]> git.sur5r.net Git - bacula/bacula/commitdiff
This commit was manufactured by cvs2svn to create tag Release-1.32f-4
author(no author) <(no author)@91ce42f0-d328-0410-95d8-f526ca767f89>
Tue, 27 Jan 2004 21:15:50 +0000 (21:15 +0000)
committer(no author) <(no author)@91ce42f0-d328-0410-95d8-f526ca767f89>
Tue, 27 Jan 2004 21:15:50 +0000 (21:15 +0000)
'Release-1.32f-4'.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/tags/Release-1.32f-4@1023 91ce42f0-d328-0410-95d8-f526ca767f89

229 files changed:
bacula/.cvsignore
bacula/ChangeLog
bacula/CheckList
bacula/Makefile.in
bacula/ReleaseNotes
bacula/autoconf/acconfig.h
bacula/autoconf/aclocal.m4
bacula/autoconf/config.h.in
bacula/autoconf/configure.in
bacula/configure
bacula/kernstodo
bacula/platforms/debian/bacula-director [new file with mode: 0644]
bacula/platforms/freebsd/.cvsignore [new file with mode: 0644]
bacula/platforms/freebsd/pthreads-fix.txt [new file with mode: 0644]
bacula/platforms/redhat/bacula-dir.in
bacula/platforms/redhat/bacula-fd.in
bacula/platforms/redhat/bacula-sd.in
bacula/platforms/redhat/bacula.spec.in
bacula/platforms/solaris/Makefile.in
bacula/platforms/suse/Makefile.in [new file with mode: 0644]
bacula/platforms/suse/bacula-dir.in [new file with mode: 0755]
bacula/platforms/suse/bacula-fd.in [new file with mode: 0755]
bacula/platforms/suse/bacula-sd.in [new file with mode: 0755]
bacula/scripts/bacula.in
bacula/scripts/set-gnome1.4 [new file with mode: 0755]
bacula/scripts/set-gnome2 [new file with mode: 0755]
bacula/src/.cvsignore
bacula/src/Makefile.in
bacula/src/baconfig.h
bacula/src/bc_types.h
bacula/src/cats/Makefile.in
bacula/src/cats/bdb_find.c
bacula/src/cats/bdb_get.c
bacula/src/cats/cats.h
bacula/src/cats/create_sqlite_database.in.patch [new file with mode: 0644]
bacula/src/cats/make_catalog_backup.in
bacula/src/cats/make_catalog_backup.in.patch [new file with mode: 0644]
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/mysql.c
bacula/src/cats/protos.h
bacula/src/cats/sql_delete.c
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/cats/sql_list.c
bacula/src/cats/sql_update.c
bacula/src/cats/update_bacula_tables.in [new file with mode: 0755]
bacula/src/cats/update_mysql_tables.in [new file with mode: 0755]
bacula/src/cats/update_sqlite_tables.in [new file with mode: 0755]
bacula/src/console/Makefile.in
bacula/src/console/console.c
bacula/src/console2.glade [new file with mode: 0644]
bacula/src/console2.gladep [new file with mode: 0644]
bacula/src/dird/.cvsignore
bacula/src/dird/Makefile.in
bacula/src/dird/authenticate.c
bacula/src/dird/backup.c
bacula/src/dird/bacula-dir.conf.in
bacula/src/dird/bsr.c
bacula/src/dird/catreq.c
bacula/src/dird/dird.c
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/fd_cmds.c
bacula/src/dird/getmsg.c
bacula/src/dird/inc_conf.c
bacula/src/dird/job.c
bacula/src/dird/msgchan.c
bacula/src/dird/next_vol.c
bacula/src/dird/protos.h
bacula/src/dird/restore.c
bacula/src/dird/run_conf.c
bacula/src/dird/scheduler.c
bacula/src/dird/sql_cmds.c
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_input.c
bacula/src/dird/ua_label.c
bacula/src/dird/ua_output.c
bacula/src/dird/ua_prune.c
bacula/src/dird/ua_restore.c
bacula/src/dird/ua_run.c
bacula/src/dird/ua_select.c
bacula/src/dird/ua_status.c
bacula/src/dird/ua_tree.c
bacula/src/dird/verify.c
bacula/src/filed/.cvsignore
bacula/src/filed/filed.c
bacula/src/filed/job.c
bacula/src/filed/restore.c
bacula/src/filed/status.c
bacula/src/filed/verify.c
bacula/src/filed/win32/bin/README.txt
bacula/src/filed/win32/bin/chown.exe
bacula/src/filed/win32/bin/cygwin1.dll
bacula/src/filed/win32/bin/cygz.dll
bacula/src/filed/win32/bin/mount.exe
bacula/src/filed/win32/bin/sh.exe
bacula/src/filed/win32/bin/umount.exe
bacula/src/findlib/attribs.c
bacula/src/findlib/bfile.c
bacula/src/findlib/create_file.c
bacula/src/findlib/makepath.c
bacula/src/gnome2-console/.cvsignore
bacula/src/gnome2-console/Makefile.in [new file with mode: 0644]
bacula/src/gnome2-console/authenticate.c [new file with mode: 0644]
bacula/src/gnome2-console/callbacks.c [new file with mode: 0644]
bacula/src/gnome2-console/callbacks.h [new file with mode: 0644]
bacula/src/gnome2-console/console.c [new file with mode: 0644]
bacula/src/gnome2-console/console.h [new file with mode: 0644]
bacula/src/gnome2-console/console_conf.c [new file with mode: 0644]
bacula/src/gnome2-console/console_conf.h [new file with mode: 0644]
bacula/src/gnome2-console/gnome-console.conf.in [new file with mode: 0644]
bacula/src/gnome2-console/interface.c [new file with mode: 0644]
bacula/src/gnome2-console/interface.h [new file with mode: 0644]
bacula/src/gnome2-console/support.c [new file with mode: 0644]
bacula/src/gnome2-console/support.h [new file with mode: 0644]
bacula/src/gnome2-console/test-gnome-console.conf [new file with mode: 0644]
bacula/src/jcr.h
bacula/src/lib/alist.h
bacula/src/lib/bits.h
bacula/src/lib/bnet.c
bacula/src/lib/bpipe.c
bacula/src/lib/bsock.h
bacula/src/lib/bsys.c
bacula/src/lib/btime.c
bacula/src/lib/btime.h
bacula/src/lib/cram-md5.c
bacula/src/lib/daemon.c
bacula/src/lib/dlist.c
bacula/src/lib/dlist.h
bacula/src/lib/jcr.c
bacula/src/lib/message.c
bacula/src/lib/parse_conf.c
bacula/src/lib/protos.h
bacula/src/lib/scan.c
bacula/src/lib/serial.c
bacula/src/lib/signal.c
bacula/src/lib/tree.c
bacula/src/lib/tree.h
bacula/src/lib/util.c
bacula/src/lib/var.c
bacula/src/lib/watchdog.c
bacula/src/stored/.cvsignore
bacula/src/stored/acquire.c
bacula/src/stored/append.c
bacula/src/stored/askdir.c
bacula/src/stored/autochanger.c
bacula/src/stored/bacula-sd.conf.in
bacula/src/stored/bcopy.c
bacula/src/stored/bextract.c
bacula/src/stored/block.c
bacula/src/stored/block.h
bacula/src/stored/bls.c
bacula/src/stored/bscan.c
bacula/src/stored/btape.c
bacula/src/stored/butil.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/device.c
bacula/src/stored/dircmd.c
bacula/src/stored/fd_cmds.c
bacula/src/stored/job.c
bacula/src/stored/label.c
bacula/src/stored/match_bsr.c
bacula/src/stored/mount.c
bacula/src/stored/parse_bsr.c
bacula/src/stored/protos.h
bacula/src/stored/read_record.c
bacula/src/stored/record.h
bacula/src/stored/status.c
bacula/src/stored/stored.c
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/tools/testfind.c
bacula/src/tools/testls.c
bacula/src/version.h
regress/.cvsignore [deleted file]
regress/README [deleted file]
regress/all-non-root-tape-tests [deleted file]
regress/all-non-root-tests [deleted file]
regress/all-root-tests [deleted file]
regress/all-tape-and-file-tests [deleted file]
regress/all-tests [deleted file]
regress/scripts/.cvsignore [deleted file]
regress/scripts/bacula-dir-tape.conf.in [deleted file]
regress/scripts/bacula-sd-tape.conf.in [deleted file]
regress/scripts/bacula-sd.conf.in [deleted file]
regress/scripts/cleanup [deleted file]
regress/scripts/cleanup-tape.in [deleted file]
regress/scripts/copy-confs [deleted file]
regress/scripts/copy-tape-confs [deleted file]
regress/scripts/copy-test-confs [deleted file]
regress/scripts/copy-testa-confs [deleted file]
regress/scripts/do_sed [deleted file]
regress/scripts/exclude-dev-test [deleted file]
regress/scripts/exclude-etc-test [deleted file]
regress/scripts/exclude-lib-test [deleted file]
regress/scripts/regress-config [deleted file]
regress/scripts/setup [deleted file]
regress/scripts/test-bacula-dir.conf.in [deleted file]
regress/scripts/test-bacula-fd.conf.in [deleted file]
regress/scripts/test-bacula-sd.conf.in [deleted file]
regress/scripts/test-console.conf.in [deleted file]
regress/scripts/testa-bacula-dir.conf.in [deleted file]
regress/tests/backup-bacula-tape [deleted file]
regress/tests/backup-bacula-test [deleted file]
regress/tests/bextract-test [deleted file]
regress/tests/bscan-test [deleted file]
regress/tests/bsr-opt-test [deleted file]
regress/tests/compressed-test [deleted file]
regress/tests/concurrent-jobs-test [deleted file]
regress/tests/dev-test-root [deleted file]
regress/tests/etc-test-root [deleted file]
regress/tests/four-concurrent-jobs-test [deleted file]
regress/tests/lib-test-root [deleted file]
regress/tests/recycle-test [deleted file]
regress/tests/restore-by-file-test [deleted file]
regress/tests/six-vol-test [deleted file]
regress/tests/small-file-size-tape [deleted file]
regress/tests/span-vol-test [deleted file]
regress/tests/sparse-compressed-test [deleted file]
regress/tests/sparse-test [deleted file]
regress/tests/test0 [deleted file]
regress/tests/two-jobs-test [deleted file]
regress/tests/two-vol-test [deleted file]
regress/tests/two-volume-tape [deleted file]
regress/tests/verify-vol-test [deleted file]
regress/tests/weird-files-test [deleted file]
regress/tests/weird-files2-test [deleted file]
regress/weird-files.tar.gz [deleted file]

index e87bcd24e3564d805aab53b9d1f72dd0d222886e..62866bd26b05beb8068527b6524a078710068683 100644 (file)
@@ -1,5 +1,9 @@
 1
 2
+set-gnome2
+set-gnome1.4
+kerns-gprof-config
+autom4te.cache
 Makefile
 bacula
 btraceback
index bf5d6580de491e24779101f929749fbf74b2f93a..d371c66bd62e7cda12399c23643c93e5ee49401c 100644 (file)
@@ -1,4 +1,305 @@
 
+Patched 1.32f-4
+
+2004-01-27 Version 1.32f-4 26Jan04 Release
+- Fix crash in restore if bad pool specified on command line and    
+  the pool prompt is canceled.
+- Remove some potentially bad ASSERTS in bnet.c
+- Add Scott's cats/create_sqlite_database.in.patch file
+- Add Scott's new spec file.
+
+2004-01-12 Version 1.32f-3 12Jan04 Release
+- Modify findlib/makepath.c to create all parent directories with full 
+  permissions. This should solve the access problems on restoring files 
+  on Win32 systems.
+- Modify restore to report **** Restore Error **** if any error
+  are found.  I.e.  a file could not be created.
+- Change a few errors into warnings -- e.g.  if permissions could
+  not be set, but the file is actually restored.
+
+2004-01-12 Version 1.32f-2 06Jan04 Release
+- This release has two patches applied:
+   1.32f-1-weekofmonth.patch
+   1.32f-2-eom-nextvol.patch
+- Fix an incorrect calcualtion of the week of the month reported
+  by Volker Sauer -- patch 1.
+- Fix bug reported by Phil (could not duplicate here) where at the end
+  of a Volume, Bacula wanted a new Volume and got into a loop requesting
+  it, then gave up -- Patch 2.
+- Modify selection of next Volume to select most currently appended Volume,
+  or if none oldest recycled Volume (problem reported by Lars) -- Patch 2.
+- Added new spec file from Scott.
+
+2003-12-31 Version 1.32f 31Dec03 Release
+- Note, this change affects only the Win32 FD.
+- Fixed Win32 FD crash due to missing argument in status command. It
+  always crashed if there was a job that had previously run.  Thanks to
+  Christopher Hull for finding and diagnosing this problem.
+
+2003-12-24 Version 1.32e 26Dec03 Release
+26Dec03
+- Fixed static configuration of gnome console reported by Alan Brown.
+24Dec03
+- Made restore use the base FileSet name instead of modifications of the FileSet.
+- Fix "restore" to always look at storage keyword and to use get_storage_resource()
+- Fix seg fault in restore if no client found/specified.
+- Made JobBytes print in 14 columns instead of 12 in status reports.
+- Install static-gnome-console if built.
+- Set max changer wait from 2 mins to 5 to avoid timout while tapes load.
+23Dec03
+- Added additional error messages to smtp. 
+21Dec03
+- Back ported the following items from 1.33:
+- Added suse platform directory and configure code. Must be tweaked for
+  SuSe.
+- Added debian platform directory.
+- Fixed fd.in (thanks Dan) to configure subsystem directory.
+- Back ported fix to Week of Month from 1.33
+- Back ported new Week of Year code from 1.33
+- Add JobId to Running jobs and Terminated Jobs status list.
+- Fixed "Phil's" bug where after doing a restore from a tape, if the next
+  operation was an append to the same tape, the number of files on the
+  tape and in the catalog got out of sync.
+- Fixed bug in Terminated Jobs status list that repeated the same job.
+
+2003-12-09 Version 1.32e 08Dec03 Release
+24Nov03
+- Sort FileSet selection list by CreateTime.
+- Add "lsmark", and "estimate" to tree routines.
+- Doing a mark or unmark now prints how many entries were changed.
+- Add command argument parsing to btape.c
+- Enhance EOT to print file:block on message.
+- Add repeat counts on btape bsf, fsf, bsr, fsr, and weof commands.
+- Enhance btape's fill command to be much clearer and more reliable.
+- Add state file to btape so that unfill command can be done any time
+  after a fill command.
+- Use reposition_dev() to position for read back of last block.
+22Nov03
+- Cleaned up the btape "fill" command to compare the last block written
+  and read rather than just printing them.
+21Nov03
+- Implement btape test for autochanger.
+- Implement btape test for Fast Forward Space File.
+- Moved up to cygwin 1.5.5-1
+20Nov03
+- Ensure that Volumes are selected from oldest LastWritten data/time.
+- A couple of bug fixes ensuring the proper ordering of volumes.
+19Nov03
+- Return oldest LastWritten for find_next_volume.
+- Enhance SD status if debug_level > 1 to show details of dev status.
+18Nov03
+- Create update_bacula_tables, ... scripts and modify configure and Makefiles
+  Not used in 1.32e
+- Eliminate is_num() and use is_an_integer().
+- Start daemons at level 90 rather than 20 so that MySQL will already
+  be started.
+15Nov03
+- In the bacula start/stop script, ordered the stop: FD SD Dir to
+  give the SD the best chances of updating the catalog before dying.
+- Fixed the signal handler to pass the signal to the exit_handler() 
+  previously it passed 1.
+- Modified SD so that on normal shutdown, it walks through all jcrs and
+  cancels them so that the Volume status will be updated in the catalog.
+- Found and fixed a bug where ST_LABEL was not set in append mode
+  (when a different tape was accepted other than the original one
+  proposed by the DIR.
+12Nov03
+- Change getdomainname() prototype for Darwin.
+- Add gethost_strerror() to create correct error message for
+  gethostbyname().
+- After doing a kill() of a stalled connection in watchdog, turn off
+  the timer to prevent an infinite loop.
+- Allow Bacula to rewrite the label on a disk volume.
+11Nov03
+- Add L_NONE for Admin and Restore jobs and update level_to_str()
+- Fix segfault from double free of RestoreBootstrap in job.c
+10Nov03
+- Check if volume has expired when doing an update media for the SD
+07Nov03
+- Fix bug reported by Lars where an incorrect Volume name was printed
+  by the "status dir" command.
+06Nov03
+- Pretty up a few error messages printed by smtp.
+- Make btime_t int64_t so that one can do arithmetic.
+- Implement since as utime (64 bit UTC). 
+- Compute clock diff between Dir and FD, and adjust since time.
+- Apply SQL fix from Nic Bellamy (thanks).
+- Apply John's zlib #ifdefing fix.
+05Nov03
+- Add Dan's with-sd-user, ... to configure.in.
+- Add Dan's userid and group modifications to bacula.in
+- Lots of documentation updates.
+- Make console print "Enter a period to cancel a command" when starting.
+- Fix the "list nextvol" command so that it doesn't try to close the
+  database twice, giving a segfault.
+- Make dir_ask_sysop_to_mount_next_volume() return immediately if a slot is
+  specified.
+- Correct some of the messages in testfind.c (pointed out by Dan -- thanks).
+- Alias fd to client, sd to storage.
+- Changed order of Console commands so that short commands such as q (quit) 
+  are more logical.
+
+2003-11-03 Version 1.32d 02Nov03 Release
+02Nov03
+- Mainly a bug fix release.
+- Do a clean of both Gnome directories.
+- Require that FileSet id match when finding an Incremental
+  previous job. This was already the case for a Full.
+- Print message if no status returned from FD.
+- Correct "Do not forget to mount the drive" message. Test was
+  backward.
+- "status dir" stopped scanning the run records on the first
+  one that matched giving an incomplete listing.
+- Edit commas in Bytes on "estimate" command output.
+
+2003-10-30 Version 1.32c 30Oct03 Release
+29Oct03
+- Add %v to job edit codes. It edits in the VolumeName(s).
+- Add code to ensure that fds 0,1, and 2 are defined by dup'ing them
+  to /dev/null if necessary.  Mostly for Windows that does not have them.
+- Error check dir_create_jobmedia_record() 2 places in acquire.c
+26Oct03
+- More doc fixes.
+- Make message buffer longer for a status message that was    
+  truncated.        
+- Put termination on varargs calls in gnome2-console.
+- Scroll only if text sent and not for status update.
+- Add all possible Status codes the jobstatus_to_ascii()
+25Oct03
+- Add new spec file and cats patch from Scott.
+- Optimize tree.c a bit -- turn off debug code, keep node fname
+  length for fast rejection, add some statistics, allocate
+  in 100K and 1Meg chunks, use bool, uint16_t and uint8_t to
+  reduce node packet size.
+24Oct03
+- Eliminate ua_retention.c that was not used.
+- Improve error message when closing brace missing in conf file.
+- More doc updates.
+- Eliminate Don't forget to mount if it is a disk file.
+- Fix Gnome2 scrolling and blank screen problems.
+- Eliminate multiple JobIds in restore selection list.
+- Fix non-portable varargs code in var.c
+- Make doc fixes/changes suggested by Dan Languille
+23Oct03
+- Document new features.
+- Implement mod of Verify Job at the run prompt.
+- Correct SQL table definitions so that MySQL and SQLite
+  have all the values in the same position.
+- Correct a typo in configure.in when configuring GNOME.
+- In doing a "status dir" make it loop over all the run
+  commands in the Schedule rather than doing on the first one.
+- Close all unused file descriptors in bpipe.c otherwise if
+  a daemon is started, it will keep our TCP/IP port open.
+22Oct03
+- Print block read error (checksum, I/O, BB01, ...) once then
+  the number found at the end of the reading.
+- Implement RunAfterFailedJob
+- Change db_find_job_start_time() to require a Full save before
+  running an Incremental or Differential job.
+- Remove has_volume_expired from code that updates vol info
+21Oct03
+- Implement "delete job"
+20Oct03
+- More documentation, add Marc Brueckner's tips to manual.
+- Tweak gnome2-console scroll window.
+- Turn off some debug info.
+18Oct03
+- Modify Verify to accept VerifyJob = xx, where the last backup job
+  of job xxx will be verified.
+- Add changing the Pool name for a Volume to "update volume"
+- Write most of the code for Verify Disk to Catalog.
+- Recreate the src/gnome2-console directory.
+- Change all the text handling code to the Gnome 2.0 way.
+- Correct the way verify filenames are returned to the Director so
+  that directories are in canonical form (i.e. trailing /).
+- Handle casting bug in glade-2 by sed'ing support.c in gnome2-console.
+
+2003-10-15 Version 1.32b 14Oct03 Release
+14Oct03
+- Modify configure so that if threaded MySQL client library
+  is not present, Bacula will link with the non-threaded 
+  version.
+- Updates to the Web pages and to the manual.
+- Remove trademark symbol from title. Phil pointed out that it
+  does not display correctly in a title.
+11Oct03
+- Implement restore by file before date. 
+- Change restore arguments a bit so that you can feed it
+  multiple jobid= specifications or multiple file= specifications.
+- Pass restore with run option on to run_cmd.
+- Make run-cmd not prompt if it has a "run" on the command line.
+10Oct03
+- When pruning, select only old orphanned jobs to delete so that
+  the current job is not pruned too.
+09Oct03
+- Corrected return status for bsf_dev and bsr_dev in block.c and btape.c
+- dev.c used incorrect ruturn status for bsf_dev in the BSF at EOM
+  code. This caused all appends on FreeBSD to fail.
+- Turn on fast block rejection code.
+08Oct03
+- Optimize file index searches by adding a count to the bootstrap.
+- Write single files/blocks to bootstrap without the second part.
+- Add current Volume status to the cannot use this Volume message.
+- Zero the rx->bsr in ua_restore when freeing so it doesn't get
+  freed twice.
+- Lots of testing on the restore
+- I noticed that SD and FD bootstrap files were not always
+  deleted, so delete them as soon as possible.
+- Restore by file (or by selecting files) created some
+  horrible looking bsr files that defeated the forward
+  spacing code, so fix write_findex to work right.
+- Add zlib_strerror() routine in filed/restore in case
+  of zlib errors.
+- In filed/restore.c make sure all error returns cleanup
+  and close the open file descriptor.
+- Make sure to set *non* over filename in attr packet
+  after file is found, so error messages that print the
+  filename don't print an old, incorrect name.
+- Allow bclose() to be called after closing the file.
+- Fix a number of unclear help messages, ... reported by
+  Phil in btape.
+- Retweak stored/read_record.c so that it does forward
+  spacing at the beginning of every tape, not just the
+  first one.
+- Print repositioning message if verbose is set.
+
+2003-10-01 Version 1.32a 03Oct03 Release
+04Oct03
+- Combine the code in ua_output and ua_status that searches
+  the run records.
+03Oct03
+- Fixed "list nextvol" to search for the correct pool in the
+  Schedule Run records.
+- Correct an error in is_block_zero. It found a false
+  match if the first 1016 bytes of a 32K buffer and     
+  the last 248 bytes are zero.  Broke the sparse option.
+01Oct03
+- More documentation.
+- Test if multiple mail addresses works. Yes.
+- Add debug Jmsg() to trigger if the file I/O packet is
+  not closed in the FD, i.e file descriptor leaks.
+- When error occurs reading label in mount.c, start from
+  the very top so that the retry count is in effect.
+- Zap the mode in soft links in testls.c for regression
+  testing.
+
+2003-10-01 Version 1.32 30Sep03 Release
+28Sep03
+- Enhance manual faq, regression ...
+- Make FreeBSD read sizes always be a multiple of 512. Needed
+  to read raw disks.
+- Make FreeBSD accept block AND character devices for raw
+  disk reads.  On FreeBSD there are no block devices.
+27Sep03
+- Fix printing of EndTime on job report after rescheduling.
+- Fix jobq.c error returns to clean up before returning.
+- Make Cleaning tape aware of "unlabeled" volumes.
+- If a job is rescheduled, ensure that old job is
+  removed from SD's jcr queue -- i.e. it is still waiting
+  for FD connection.
+- Test rescheduling code.
+- Change ./configure to detect Cygwin enviornments.
+
 2003-09-26 Version 1.32 26Sep03 Beta
 - Add regression and GUI-interface chapters to the manual.
 - Fix "label" of a volume that is already in the catalog,
index ff26ed374ba20c6aadb3de2120a4ffdce661ef98..ccc71d7e7994056ee376ff530cd007242ff67cf3 100644 (file)
@@ -8,7 +8,7 @@
 - Update ChangeLog (add release date)
 - Do a cvs commit
 - Do a cvs -q export -D now -d bacula-1.nn bacula
-- Build new bacula-1.nn to ensure everything is committed
+- Run the regression tests on the new bacula
 - Write ReleaseNotes
 - If everything is good
 - cd bacula/k
index 87c3a4da94fc47aa79b09c57c467d624aa904dd6..65b008f80c610d44caf9587d89658527b7ca0a67 100755 (executable)
@@ -149,6 +149,7 @@ distclean:
        @$(RMF) -r doc/techlogs/2002/CVS doc/techlogs/2001/CVS doc/techlogs/1.27/CVS
        @$(RMF) -r examples/CVS intl/CVS scripts/CVS
        @$(RMF) -r po/CVS src/immortal/CVS rescue/freebsd/CVS rescue/solaris/CVS
+       @$(RMF) -r CVS src/gnome-console/CVS src/tconsole/CVS
 
 distdirs:
        mkdir ../$(VERNAME);
index 668426ebe3254564edec5eedb90c54ffdbd66e8d..ec4ed00a795c88cd3fd628ecc554ac61c3752945 100644 (file)
@@ -1,9 +1,150 @@
 
-          Release Notes for Bacula 1.32
+          Release Notes for Bacula 1.32f-4
 
-  Bacula code: Total files = 259 Total lines = 77,702 (*.h *.c *.in)
+  Bacula code: Total files = 262 Total lines = 80,352 (*.h *.c *.in)
 
-Major Changes this Release:
+2004-01-27 Version 1.32f-4 26Jan04 Release
+- Fix crash in restore if bad pool specified on command line and    
+  the pool prompt is canceled.
+- Remove some potentially bad ASSERTS in bnet.c
+- Add Scott's cats/create_sqlite_database.in.patch file
+- Add Scott's new spec file.
+
+2004-01-12 Version 1.32f-3 12Jan04 Release
+- Modify findlib/makepath.c to create all parent directories with full 
+  permissions. This should solve the access problems on restoring files 
+  on Win32 systems.
+- Modify restore to report **** Restore Error **** if any error
+  are found.  I.e.  a file could not be created.
+- Change a few errors into warnings -- e.g.  if permissions could
+  not be set, but the file is actually restored.
+
+Release 1.32f-2:
+- This release has two patches applied:
+   1.32f-1-weekofmonth.patch
+   1.32f-2-eom-nextvol.patch
+- Fix an incorrect calcualtion of the week of the month reported
+  by Volker Sauer -- patch 1.
+- Fix bug reported by Phil (could not duplicate here) where at the end
+  of a Volume, Bacula wanted a new Volume and got into a loop requesting
+  it, then gave up -- Patch 2.
+- Modify selection of next Volume to select most currently appended Volume,
+  or if none oldest recycled Volume (problem reported by Lars) -- Patch 2.
+- Added new spec file from Scott.
+
+Changes since 1.32e:
+- Note, this change affects only the Win32 FD.
+- Fixed Win32 FD crash due to missing argument in status command. It
+  always crashed if there was a job that had previously run.  Thanks to
+  Christopher Hull for finding and diagnosing this problem.
+
+Most Significant Changes since 1.32e-08Dec03
+- Added additional error messages to smtp. 
+- Added suse platform directory and configure code. Must be tweaked for
+  SuSe.
+- Added debian platform directory.
+- Fixed fd.in (thanks Dan) to configure subsystem directory.
+- Back ported fix to Week of Month from 1.33
+- Add JobId to Running jobs and Terminated Jobs status list.
+- Fixed "Phil's" bug where after doing a restore from a tape, if the next
+  operation was an append to the same tape, the number of files on the
+  tape and in the catalog got out of sync.
+- Fixed bug in Terminated Jobs status list that repeated the same job.
+
+Most Significant Changes since 1.32d
+- All 1.32d patches applied.
+- Fixed seg fault in restore of multiple simultaneous jobs to 
+  a single Volume.
+- Fixed thread race problem in multiple simultaneous jobs to
+  a single Volume where the volume lable is not in the first 
+  tape block, so the tape is not recognized.
+- Enhance "fill" command of btape -- simpler output. Use -v to
+  cause last block to be dumped after write and after re-read.
+- Added an autochanger test to the btape "test" command. It is 
+  automatically invoked if the autochanger is properly configured.  It
+  is still a bit primitive but covers the essential of testing
+  the mtx-changer script with your autochanger.
+- Added forward space file test to btape "test" command.
+- New version 1.5.5-1 Cygwin.
+- Select the oldest LastWritten volume during recycling.
+- Modify SD to update the catalog database when it is shutdown,
+  even if the job is canceled.
+- The console program will run all commands it finds in ~/.bconsolerc
+  at startup.
+- Add Dan Langille's changes to the bacula start/stop script that
+  permit dropping root permissions just after startup.
+- The "mark" command in the restore command now provides feedback 
+  on how many files were marked.
+
+Other Changes since 1.32d:
+- Fixed getdomainname() prototype on Darwin.
+- Fixed an SQL typo (missing space) in "list volumes jobid=xxx"
+- Fixed crash with "list job"
+- Fixed crash with ' entered as a filename to be restored (any
+  name causing an SQL error would cause the crash).
+- Fixed | syntax in FileSet Include.
+- Corrected crash in restore in some weird cases where the bootstrap 
+  file defined in the resource.
+- Fixed a crash when storage daemon did not accept unknown Device.   
+- Fixed a rare crash in list nextvol
+- Fixed a compile error if zlib does not exist.
+- Finally got the Gnome console running correctly under Gnome 2.x
+- Print human readable message on error by gethostbyname().
+- Fixed a time conversion problem in tape label.
+- A number of enhancements to btape (more work to be done).
+- Updates to Solaris system installation files.
+- New bacula.spec.in from Scott Barninger -- including a rescue rpm.
+- Slightly different listing and list sorting, more important fields 
+  are first.
+                  
+                                                                                        
+Items to note:  !!!!!
+- All daemons should be compatible with all other 1.32x versions,       
+  you can mix and match (hopefully).
+
+
+Change in previous releases:
+Most Significant Changes since 1.32c
+- Mainly a bug fix release.
+- Do a clean of both Gnome directories.
+- Require that FileSet id match when finding an Incremental
+  previous job. This was already the case for a Full.
+- Print message if no status returned from FD.
+- Correct "Do not forget to mount the drive" message. Test was
+  backward.
+- "status dir" stopped scanning the run records on the first
+  one that matched giving an incomplete listing.
+- Edit commas in Bytes on "estimate" command output.
+
+Most Significant Changes since 1.32b
+- Implemented a RunAfterFailedJob record in the Job resource.
+- Implemented "delete job" command in the Console.
+- Gnome 2.0 console compiles and works. 
+- Implemented VerifyJob record in the Job resource
+  that tells Verify which job to verify (JobId not required) 
+- First cut Verify Disk to Catalog
+- Fix "status dir" to examine all run commands in Schedule.
+- Close unused file descriptors in bpipe.c
+- There is now a patch for FreeBSD 4.8 pthreads that
+  fixes the problems of data loss at the end of a tape.
+  Please see:
+  <bacula-source>/platforms/freebsd/pthreads-fix.txt
+- Fixed (I think) the elusive Windows "packet too big" bug.
+- Added %v to RunBefore/After editing codes. It edits in
+  a list of Volumes used for the job (not tested).
+
+Most Significant Changes since 1.32a:
+- Improve forward space file/block during restore, many
+  optimizations.
+- Fix a Bacula bug that did not allow appending to a tape    
+  on FreeBSD systems.
+- Fix pruning so that it will not prune the current job.
+- Modify configure to use non-threaded MySQL client lib if
+  the threaded version is not present.
+- Implement restore by file before date.
+- When pruning don't prune the current job.
+
+Major Changes 1.32a Release:
 - Implemented forward space file/block whenever possible 
   during restore. Restoring a small number of files is now  
   much faster.
@@ -22,9 +163,14 @@ Major Changes this Release:
   be used is also added to the "status dir" output.
 - Lots of fixes with variable expansion and counter variables
 - Implemented a new Include/Exclude syntax.
+- While writing a tape, an end of file mark will be written
+  every 1Gb. This makes restores faster. If you want to
+  change this use "Maximum File Size" in the SD Device
+  resource.
 
 
-Other Changes this Release:
+Other Changes 1.32a Release:
+- Fixed sparse file bug.
 - A warning message is sent when a job starts that will be
   blocked because the user did an "unmount".
 - Block checksum errors if any are printed in the job report.
index a6fe066c74eee2c788cc0f4c3769333869a116f6..e9cef42055dd2798dbf4493faded6c55962d72db 100644 (file)
@@ -23,6 +23,9 @@
 /* Define if you want to use MySQL */
 #undef HAVE_MYSQL
 
+/* Defined if MySQL thread safe library is present */
+#undef HAVE_THREAD_SAFE_MYSQL
+
 /* Define if you want to use embedded MySQL */
 #undef HAVE_EMBEDDED_MYSQL
 
 #undef HAVE_OLD_SOCKOPT
  
 #undef HAVE_BIGENDIAN
-
index 8f0aab87b2002f13c8cdc3382119cfe188028045..1294fb138109bd7cd71ad58b8aab847a9b0e8ef1 100644 (file)
@@ -390,7 +390,12 @@ Which DBMS do you want to use (please select only one):
                 fi
         fi
     SQL_INCLUDE=-I$MYSQL_INCDIR
+    if test -f $MYSQL_LIBDIR/libmysqlclient_r.a; then
     SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz"
+       AC_DEFINE(HAVE_THREAD_SAFE_MYSQL)
+    else
+       SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient -lz"
+    fi
     SQL_BINDIR=$MYSQL_BINDIR
 
     AC_DEFINE(HAVE_MYSQL)
index 13c47a86365786bc9887511b6ad3ab516d1d3af7..db3f80dc3cca8d4d9711d3f9f8f1fc039dfb36a5 100644 (file)
@@ -24,6 +24,9 @@
 /* Define if you want to use MySQL */
 #undef HAVE_MYSQL
 
+/* Defined if MySQL thread safe library is present */
+#undef HAVE_THREAD_SAFE_MYSQL
+
 /* Define if you want to use embedded MySQL */
 #undef HAVE_EMBEDDED_MYSQL
 
  
 #undef HAVE_BIGENDIAN
 
-
 /* Define to 1 if the `closedir' function returns void instead of `int'. */
 #undef CLOSEDIR_VOID
 
index f00fbe38a9d59b36d972d9590356a651bc52454c..d47e0d82d474d0c1c7d29b3203a9a9bbc9be2ea5 100644 (file)
@@ -172,18 +172,20 @@ if test x$support_gnome = xyes; then
   pkg=$?
   if test $pkg = 0; then
      GNOME_INCLUDEDIR=`pkg-config --cflags-only-I libgnomeui-2.0`
-     GNOMEUI_LIBS=`pkg-config --libs-only-other libgnomeui-2.0`
+     GNOMEUI_LIBS=`pkg-config --libs-only-l libgnomeui-2.0`
      GNOME_LIBDIR=`pkg-config --libs libgnomeui-2.0`
      GNOME_LIBS=`pkg-config --libs-only-l libgnomeui-2.0`
      AC_SUBST(GNOME_INCLUDEDIR)
      AC_SUBST(GNOMEUI_LIBS)
      AC_SUBST(GNOME_LIBDIR)
      AC_SUBST(GNOME_LIBS)
-     GNOME_DIR=src/gnome-console
+     GNOME_DIR=src/gnome2-console
+     gnome_version="version 2.x"
   else
-dnl 1.4 stuff
+dnl do 1.4 stuff
     GNOME_INIT
     GNOME_DIR=src/gnome-console
+    gnome_version="version 1.4"
   fi
 fi
 AC_SUBST(GNOME_DIR)
@@ -272,10 +274,13 @@ AC_ARG_ENABLE(static-cons,
    fi])
 
 STATIC_CONS=
+STATIC_GNOME_CONS=
 if test x$support_static_cons = xyes; then
    STATIC_CONS="static-console"
+   STATIC_GNOME_CONS="static-gnome-console"
 fi
 AC_SUBST(STATIC_CONS)
+AC_SUBST(STATIC_GNOME_CONS)
 
 # -------------------------------------------
 # client_only  (default off)
@@ -505,7 +510,7 @@ AC_ARG_WITH(tcp-wrappers,
   [
     if test "x$withval" != "xno" ; then
        saved_LIBS="$LIBS"
-       LIBS="$LIBS -lwrap -lnsl"
+       LIBS="$saved_LIBS -lwrap"
        AC_MSG_CHECKING(for libwrap)
        AC_TRY_LINK(
          [ #include <tcpd.h>
@@ -517,8 +522,21 @@ AC_ARG_WITH(tcp-wrappers,
            AC_MSG_RESULT(yes)
            AC_DEFINE(HAVE_LIBWRAP)
            TCPW_MSG="yes" 
-         ],
-         [AC_MSG_ERROR([*** libwrap missing]) ]
+         ], [
+           LIBS="$saved_LIBS -lwrap -lnsl"
+           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
   ]
@@ -728,7 +746,78 @@ AC_SUBST(fd_password)
 AC_SUBST(sd_password)
 
 
+#
+# Handle users and groups for each daemon
+#
+dir_user=
+AC_ARG_WITH(dir_user,
+    [  --with-dir-user=USER             specify user for Director daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            dir_user=$withval
+       fi
+    ]
+)
 
+dir_group=
+AC_ARG_WITH(dir_group,
+    [  --with-dir-group=GROUP           specify group for Director daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            dir_group=$withval
+       fi
+    ]
+)
+
+sd_user=
+AC_ARG_WITH(sd_user,
+    [  --with-sd-user=USER              specify user for Storage daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            sd_user=$withval
+       fi
+    ]
+)
+
+sd_group=
+AC_ARG_WITH(sd_group,
+    [  --with-sd-group=GROUP            specify group for Storage daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            sd_group=$withval
+       fi
+    ]
+)
+
+fd_user=
+AC_ARG_WITH(fd_user,
+    [  --with-fd-user=USER              specify user for File daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            fd_user=$withval
+       fi
+    ]
+)
+
+fd_group=
+AC_ARG_WITH(fd_group,
+    [  --with-fd-group=GROUP            specify group for File daemon],
+    [
+       if test "x$withval" != "x" ; then       
+            fd_group=$withval
+       fi
+    ]
+)
+
+
+
+
+AC_SUBST(dir_user)
+AC_SUBST(dir_group)
+AC_SUBST(sd_user)
+AC_SUBST(sd_group)
+AC_SUBST(fd_user)
+AC_SUBST(fd_group)
 
 # ------------------------------------------------
 # Bacula check for various SQL database engines
@@ -1346,6 +1435,11 @@ suse)
        TAPEDRIVE="/dev/nst0"
        PSCMD="ps -e -o pid,command"
        hostname=`hostname -s`
+       PFILES="${PFILES} \
+           platforms/suse/Makefile \
+           platforms/suse/bacula-fd \
+           platforms/suse/bacula-sd \
+           platforms/suse/bacula-dir"
   ;;
 suse5)
        DISTNAME=suse
@@ -1353,6 +1447,11 @@ suse5)
        TAPEDRIVE="/dev/nst0"
        PSCMD="ps -e -o pid,command"
        hostname=`hostname -s`
+       PFILES="${PFILES} \
+           platforms/suse/Makefile \
+           platforms/suse/bacula-fd \
+           platforms/suse/bacula-sd \
+           platforms/suse/bacula-dir"
   ;;
 unknown)
        DISTVER=unknown
@@ -1420,6 +1519,8 @@ AC_OUTPUT([autoconf/Make.common \
           src/console/console.conf \
           src/gnome-console/Makefile \
           src/gnome-console/gnome-console.conf \
+          src/gnome2-console/Makefile \
+          src/gnome2-console/gnome-console.conf \
           src/tconsole/Makefile \
           src/dird/Makefile \
           src/dird/bacula-dir.conf \
@@ -1432,14 +1533,14 @@ AC_OUTPUT([autoconf/Make.common \
           src/cats/Makefile \
           src/cats/make_catalog_backup \
           src/cats/delete_catalog_backup \
-          src/cats/alter_mysql_tables \
           src/cats/make_mysql_tables \
           src/cats/drop_mysql_tables \
+          src/cats/update_mysql_tables \
           src/cats/create_mysql_database \
           src/cats/grant_mysql_privileges \
-          src/cats/alter_sqlite_tables \
           src/cats/make_sqlite_tables \
           src/cats/drop_sqlite_tables \
+          src/cats/update_sqlite_tables \
           src/cats/create_sqlite_database \
           src/cats/sqlite \
           src/cats/mysql \
@@ -1448,6 +1549,7 @@ AC_OUTPUT([autoconf/Make.common \
           src/cats/drop_bdb_tables \
           src/cats/make_bacula_tables \
           src/cats/drop_bacula_tables \
+          src/cats/update_bacula_tables \
           src/findlib/Makefile \
           src/tools/Makefile \
           $PFILES ],  
@@ -1462,12 +1564,13 @@ 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/make_catalog_backup src/cats/delete_catalog_backup
-chmod 755 src/cats/alter_mysql_tables
 chmod 755 src/cats/grant_mysql_privileges
 chmod 755 src/cats/make_sqlite_tables src/cats/drop_sqlite_tables 
+chmod 755 src/cats/update_sqlite_tables
 chmod 755 src/cats/make_bacula_tables src/cats/drop_bacula_tables 
+chmod 755 src/cats/update_mysql_tables
+chmod 755 src/cats/update_bacula_tables src/cats/update_mysql_tables
 chmod 755 src/cats/create_sqlite_database
-chmod 755 src/cats/alter_sqlite_tables
 chmod 755 src/cats/sqlite
 chmod 755 src/cats/make_bdb_tables src/cats/drop_bdb_tables 
 chmod 755 src/cats/create_bdb_database
@@ -1529,9 +1632,18 @@ Configuration on `date`:
   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}
+
+  Director Port:             ${dir_port}
+  File daemon Port:          ${fd_port}
+  Storage daemon Port:       ${sd_port}
+
+  Director User:           ${dir_user}
+  Director Group:          ${dir_group}
+  Storage Daemon User:     ${dir_user}
+  Storage DaemonGroup:     ${dir_group}
+  File Daemon User:        ${dir_user}
+  File Daemon Group:       ${dir_group}
+
   SQL binaries Directory      ${SQL_BINDIR}
 
   Large file support:        $largefile_support
@@ -1539,7 +1651,7 @@ Configuration on `date`:
   TCP Wrappers support:       ${TCPW_MSG}
   ZLIB support:              ${have_zlib}
   enable-smartalloc:         ${support_smartalloc} 
-  enable-gnome:              ${support_gnome}
+  enable-gnome:              ${support_gnome} ${gnome_version}
   client-only:               ${build_client_only}
 
   " > config.out
index 89b636774c14396cedcef9590c5faeb24029650b..4d6eb606dd404acec56f22c3c3b273e4399e59e5 100755 (executable)
@@ -308,7 +308,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS BUILD_DIR TRUEPRG FALSEPRG build build_cpu build_vendor build_os host host_cpu host_vendor host_os VERSION DATE LSMDATE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA RANLIB ac_ct_RANLIB MV RM CP SED AWK ECHO CMP TBL AR OPENSSL MTX PKGCONFIG ARFLAGS MAKE_SHELL LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS HAVE_SUN_OS_TRUE HAVE_SUN_OS_FALSE HAVE_OSF1_OS_TRUE HAVE_OSF1_OS_FALSE HAVE_AIX_OS_TRUE HAVE_AIX_OS_FALSE HAVE_HPUX_OS_TRUE HAVE_HPUX_OS_FALSE HAVE_LINUX_OS_TRUE HAVE_LINUX_OS_FALSE HAVE_FREEBSD_OS_TRUE HAVE_FREEBSD_OS_FALSE HAVE_NETBSD_OS_TRUE HAVE_NETBSD_OS_FALSE HAVE_OPENBSD_OS_TRUE HAVE_OPENBSD_OS_FALSE HAVE_BSDI_OS_TRUE HAVE_BSDI_OS_FALSE HAVE_SGI_OS_TRUE HAVE_SGI_OS_FALSE HAVE_IRIX_OS_TRUE HAVE_IRIX_OS_FALSE HAVE_DARWIN_OS_TRUE HAVE_DARWIN_OS_FALSE INSIDE_GNOME_COMMON_TRUE INSIDE_GNOME_COMMON_FALSE MSGFMT GNOME_INCLUDEDIR GNOMEUI_LIBS GNOME_LIBDIR GNOME_LIBS GNOMEGNORBA_LIBS GTKXMHTML_LIBS ZVT_LIBS GNOME_CONFIG ORBIT_CONFIG ORBIT_IDL HAVE_ORBIT_TRUE HAVE_ORBIT_FALSE ORBIT_CFLAGS ORBIT_LIBS HAVE_GNORBA_TRUE HAVE_GNORBA_FALSE GNORBA_CFLAGS GNORBA_LIBS GNOME_APPLETS_LIBS GNOME_DOCKLETS_LIBS GNOME_CAPPLET_LIBS GNOME_DIR TTOOL_LDFLAGS STATIC_FD STATIC_SD STATIC_DIR STATIC_CONS ALL_DIRS CONS_INC CONS_LIBS CONS_LDFLAGS READLINE_SRC working_dir scriptdir dump_email job_email smtp_host piddir subsysdir baseport dir_port fd_port sd_port dir_password fd_password sd_password SQL_LFLAGS SQL_INCLUDE SQL_BINDIR cats DB_NAME GETCONF ac_ct_GETCONF X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS LIBOBJS ALLOCA FDLIBS DEBUG DINCLUDE DLIB DB_LIBS WCFLAGS WLDFLAGS OBJLIST hostname TAPEDRIVE PSCMD WIN32 DISTNAME DISTVER LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS BUILD_DIR TRUEPRG FALSEPRG build build_cpu build_vendor build_os host host_cpu host_vendor host_os VERSION DATE LSMDATE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA RANLIB ac_ct_RANLIB MV RM CP SED AWK ECHO CMP TBL AR OPENSSL MTX PKGCONFIG ARFLAGS MAKE_SHELL LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS HAVE_SUN_OS_TRUE HAVE_SUN_OS_FALSE HAVE_OSF1_OS_TRUE HAVE_OSF1_OS_FALSE HAVE_AIX_OS_TRUE HAVE_AIX_OS_FALSE HAVE_HPUX_OS_TRUE HAVE_HPUX_OS_FALSE HAVE_LINUX_OS_TRUE HAVE_LINUX_OS_FALSE HAVE_FREEBSD_OS_TRUE HAVE_FREEBSD_OS_FALSE HAVE_NETBSD_OS_TRUE HAVE_NETBSD_OS_FALSE HAVE_OPENBSD_OS_TRUE HAVE_OPENBSD_OS_FALSE HAVE_BSDI_OS_TRUE HAVE_BSDI_OS_FALSE HAVE_SGI_OS_TRUE HAVE_SGI_OS_FALSE HAVE_IRIX_OS_TRUE HAVE_IRIX_OS_FALSE HAVE_DARWIN_OS_TRUE HAVE_DARWIN_OS_FALSE INSIDE_GNOME_COMMON_TRUE INSIDE_GNOME_COMMON_FALSE MSGFMT GNOME_INCLUDEDIR GNOMEUI_LIBS GNOME_LIBDIR GNOME_LIBS GNOMEGNORBA_LIBS GTKXMHTML_LIBS ZVT_LIBS GNOME_CONFIG ORBIT_CONFIG ORBIT_IDL HAVE_ORBIT_TRUE HAVE_ORBIT_FALSE ORBIT_CFLAGS ORBIT_LIBS HAVE_GNORBA_TRUE HAVE_GNORBA_FALSE GNORBA_CFLAGS GNORBA_LIBS GNOME_APPLETS_LIBS GNOME_DOCKLETS_LIBS GNOME_CAPPLET_LIBS GNOME_DIR TTOOL_LDFLAGS STATIC_FD STATIC_SD STATIC_DIR STATIC_CONS STATIC_GNOME_CONS ALL_DIRS CONS_INC CONS_LIBS CONS_LDFLAGS READLINE_SRC working_dir scriptdir dump_email job_email smtp_host piddir subsysdir baseport dir_port fd_port sd_port dir_password fd_password sd_password dir_user dir_group sd_user sd_group fd_user fd_group SQL_LFLAGS SQL_INCLUDE SQL_BINDIR cats DB_NAME GETCONF ac_ct_GETCONF X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS LIBOBJS ALLOCA FDLIBS DEBUG DINCLUDE DLIB DB_LIBS WCFLAGS WLDFLAGS OBJLIST hostname TAPEDRIVE PSCMD WIN32 DISTNAME DISTVER LTLIBOBJS'
 ac_subst_files='MCOMMON'
 
 # Initialize some variables set by options.
@@ -886,6 +886,12 @@ Optional Packages:
   --with-dir-password=PASSWORD   specify Director's password
   --with-fd-password=PASSWORD    specify Client's password
   --with-sd-password=PASSWORD    specify Storage daemon's password
+  --with-dir-user=USER          specify user for Director daemon
+  --with-dir-group=GROUP                specify group for Director daemon
+  --with-sd-user=USER           specify user for Storage daemon
+  --with-sd-group=GROUP                 specify group for Storage daemon
+  --with-fd-user=USER           specify user for File daemon
+  --with-fd-group=GROUP                 specify group for File daemon
 
 Which DBMS do you want to use (please select only one):
   --with-mysql=DIR      Include MySQL support.  DIR is the MySQL base
@@ -4341,14 +4347,15 @@ if test x$support_gnome = xyes; then
   pkg=$?
   if test $pkg = 0; then
      GNOME_INCLUDEDIR=`pkg-config --cflags-only-I libgnomeui-2.0`
-     GNOMEUI_LIBS=`pkg-config --libs-only-other libgnomeui-2.0`
+     GNOMEUI_LIBS=`pkg-config --libs-only-l libgnomeui-2.0`
      GNOME_LIBDIR=`pkg-config --libs libgnomeui-2.0`
      GNOME_LIBS=`pkg-config --libs-only-l libgnomeui-2.0`
 
 
 
 
-     GNOME_DIR=src/gnome-console
+     GNOME_DIR=src/gnome2-console
+     gnome_version="version 2.x"
   else
 
 
@@ -4690,6 +4697,7 @@ echo "${ECHO_T}unknown library" >&6
 
 
     GNOME_DIR=src/gnome-console
+    gnome_version="version 1.4"
   fi
 fi
 
@@ -4793,11 +4801,14 @@ if test "${enable_static_cons+set}" = set; then
 fi;
 
 STATIC_CONS=
+STATIC_GNOME_CONS=
 if test x$support_static_cons = xyes; then
    STATIC_CONS="static-console"
+   STATIC_GNOME_CONS="static-gnome-console"
 fi
 
 
+
 # -------------------------------------------
 # client_only  (default off)
 # -------------------------------------------
@@ -6326,7 +6337,7 @@ if test "${with_tcp_wrappers+set}" = set; then
 
     if test "x$withval" != "xno" ; then
        saved_LIBS="$LIBS"
-       LIBS="$LIBS -lwrap -lnsl"
+       LIBS="$saved_LIBS -lwrap"
        echo "$as_me:$LINENO: checking for libwrap" >&5
 echo $ECHO_N "checking for libwrap... $ECHO_C" >&6
        cat >conftest.$ac_ext <<_ACEOF
@@ -6369,6 +6380,52 @@ _ACEOF
 
            TCPW_MSG="yes"
 
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+           LIBS="$saved_LIBS -lwrap -lnsl"
+           cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <tcpd.h>
+                int deny_severity = 0;
+                int allow_severity = 0;
+                struct request_info *req;
+int
+main ()
+{
+ hosts_access(req);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+                echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+                cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBWRAP 1
+_ACEOF
+
+                TCPW_MSG="yes"
+
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
@@ -6377,6 +6434,9 @@ sed 's/^/| /' conftest.$ac_ext >&5
 echo "$as_me: error: *** libwrap missing" >&2;}
    { (exit 1); exit 1; }; }
 
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+
 fi
 rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
     fi
@@ -6624,6 +6684,95 @@ fi
 
 
 
+#
+# Handle users and groups for each daemon
+#
+dir_user=
+
+# Check whether --with-dir_user or --without-dir_user was given.
+if test "${with_dir_user+set}" = set; then
+  withval="$with_dir_user"
+
+       if test "x$withval" != "x" ; then
+            dir_user=$withval
+       fi
+
+
+fi;
+
+dir_group=
+
+# Check whether --with-dir_group or --without-dir_group was given.
+if test "${with_dir_group+set}" = set; then
+  withval="$with_dir_group"
+
+       if test "x$withval" != "x" ; then
+            dir_group=$withval
+       fi
+
+
+fi;
+
+sd_user=
+
+# Check whether --with-sd_user or --without-sd_user was given.
+if test "${with_sd_user+set}" = set; then
+  withval="$with_sd_user"
+
+       if test "x$withval" != "x" ; then
+            sd_user=$withval
+       fi
+
+
+fi;
+
+sd_group=
+
+# Check whether --with-sd_group or --without-sd_group was given.
+if test "${with_sd_group+set}" = set; then
+  withval="$with_sd_group"
+
+       if test "x$withval" != "x" ; then
+            sd_group=$withval
+       fi
+
+
+fi;
+
+fd_user=
+
+# Check whether --with-fd_user or --without-fd_user was given.
+if test "${with_fd_user+set}" = set; then
+  withval="$with_fd_user"
+
+       if test "x$withval" != "x" ; then
+            fd_user=$withval
+       fi
+
+
+fi;
+
+fd_group=
+
+# Check whether --with-fd_group or --without-fd_group was given.
+if test "${with_fd_group+set}" = set; then
+  withval="$with_fd_group"
+
+       if test "x$withval" != "x" ; then
+            fd_group=$withval
+       fi
+
+
+fi;
+
+
+
+
+
+
+
+
+
 
 
 # ------------------------------------------------
@@ -6685,7 +6834,15 @@ echo "$as_me: error: Invalid MySQL directory $withval - unable to find mysql.h u
                 fi
         fi
     SQL_INCLUDE=-I$MYSQL_INCDIR
+    if test -f $MYSQL_LIBDIR/libmysqlclient_r.a; then
     SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz"
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE_THREAD_SAFE_MYSQL 1
+_ACEOF
+
+    else
+       SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient -lz"
+    fi
     SQL_BINDIR=$MYSQL_BINDIR
 
     cat >>confdefs.h <<\_ACEOF
@@ -17373,6 +17530,11 @@ suse)
        TAPEDRIVE="/dev/nst0"
        PSCMD="ps -e -o pid,command"
        hostname=`hostname -s`
+       PFILES="${PFILES} \
+           platforms/suse/Makefile \
+           platforms/suse/bacula-fd \
+           platforms/suse/bacula-sd \
+           platforms/suse/bacula-dir"
   ;;
 suse5)
        DISTNAME=suse
@@ -17380,6 +17542,11 @@ suse5)
        TAPEDRIVE="/dev/nst0"
        PSCMD="ps -e -o pid,command"
        hostname=`hostname -s`
+       PFILES="${PFILES} \
+           platforms/suse/Makefile \
+           platforms/suse/bacula-fd \
+           platforms/suse/bacula-sd \
+           platforms/suse/bacula-dir"
   ;;
 unknown)
        DISTVER=unknown
@@ -17424,7 +17591,7 @@ if test "x${subsysdir}" = "x${sbindir}" ; then
    exit 1
 fi
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    ac_config_files="$ac_config_files autoconf/Make.common Makefile rescue/Makefile rescue/linux/Makefile rescue/freebsd/Makefile rescue/solaris/Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/console scripts/gconsole scripts/bacula scripts/fd scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/mtx-changer doc/Makefile src/Makefile src/host.h src/console/Makefile src/console/console.conf src/gnome-console/Makefile src/gnome-console/gnome-console.conf src/tconsole/Makefile 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_catalog_backup src/cats/delete_catalog_backup src/cats/alter_mysql_tables src/cats/make_mysql_tables src/cats/drop_mysql_tables src/cats/create_mysql_database src/cats/grant_mysql_privileges src/cats/alter_sqlite_tables src/cats/make_sqlite_tables src/cats/drop_sqlite_tables src/cats/create_sqlite_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/make_bdb_tables src/cats/drop_bdb_tables src/cats/make_bacula_tables src/cats/drop_bacula_tables src/findlib/Makefile src/tools/Makefile $PFILES"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  ac_config_files="$ac_config_files autoconf/Make.common Makefile rescue/Makefile rescue/linux/Makefile rescue/freebsd/Makefile rescue/solaris/Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/console scripts/gconsole scripts/bacula scripts/fd scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/mtx-changer doc/Makefile src/Makefile src/host.h src/console/Makefile src/console/console.conf src/gnome-console/Makefile src/gnome-console/gnome-console.conf src/gnome2-console/Makefile src/gnome2-console/gnome-console.conf src/tconsole/Makefile 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_catalog_backup src/cats/delete_catalog_backup src/cats/make_mysql_tables src/cats/drop_mysql_tables src/cats/update_mysql_tables src/cats/create_mysql_database src/cats/grant_mysql_privileges src/cats/make_sqlite_tables src/cats/drop_sqlite_tables src/cats/update_sqlite_tables src/cats/create_sqlite_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/make_bdb_tables src/cats/drop_bdb_tables src/cats/make_bacula_tables src/cats/drop_bacula_tables src/cats/update_bacula_tables src/findlib/Makefile src/tools/Makefile $PFILES"
           ac_config_commands="$ac_config_commands default"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -17980,6 +18147,8 @@ do
   "src/console/console.conf" ) CONFIG_FILES="$CONFIG_FILES src/console/console.conf" ;;
   "src/gnome-console/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/gnome-console/Makefile" ;;
   "src/gnome-console/gnome-console.conf" ) CONFIG_FILES="$CONFIG_FILES src/gnome-console/gnome-console.conf" ;;
+  "src/gnome2-console/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/gnome2-console/Makefile" ;;
+  "src/gnome2-console/gnome-console.conf" ) CONFIG_FILES="$CONFIG_FILES src/gnome2-console/gnome-console.conf" ;;
   "src/tconsole/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tconsole/Makefile" ;;
   "src/dird/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/dird/Makefile" ;;
   "src/dird/bacula-dir.conf" ) CONFIG_FILES="$CONFIG_FILES src/dird/bacula-dir.conf" ;;
   "src/cats/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/cats/Makefile" ;;
   "src/cats/make_catalog_backup" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_catalog_backup" ;;
   "src/cats/delete_catalog_backup" ) CONFIG_FILES="$CONFIG_FILES src/cats/delete_catalog_backup" ;;
-  "src/cats/alter_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/alter_mysql_tables" ;;
   "src/cats/make_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_mysql_tables" ;;
   "src/cats/drop_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_mysql_tables" ;;
+  "src/cats/update_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_mysql_tables" ;;
   "src/cats/create_mysql_database" ) CONFIG_FILES="$CONFIG_FILES src/cats/create_mysql_database" ;;
   "src/cats/grant_mysql_privileges" ) CONFIG_FILES="$CONFIG_FILES src/cats/grant_mysql_privileges" ;;
-  "src/cats/alter_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/alter_sqlite_tables" ;;
   "src/cats/make_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_sqlite_tables" ;;
   "src/cats/drop_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_sqlite_tables" ;;
+  "src/cats/update_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_sqlite_tables" ;;
   "src/cats/create_sqlite_database" ) CONFIG_FILES="$CONFIG_FILES src/cats/create_sqlite_database" ;;
   "src/cats/sqlite" ) CONFIG_FILES="$CONFIG_FILES src/cats/sqlite" ;;
   "src/cats/mysql" ) CONFIG_FILES="$CONFIG_FILES src/cats/mysql" ;;
@@ -18008,6 +18177,7 @@ do
   "src/cats/drop_bdb_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_bdb_tables" ;;
   "src/cats/make_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_bacula_tables" ;;
   "src/cats/drop_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_bacula_tables" ;;
+  "src/cats/update_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_bacula_tables" ;;
   "src/findlib/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/findlib/Makefile" ;;
   "src/tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tools/Makefile" ;;
   "$PFILES" ) CONFIG_FILES="$CONFIG_FILES $PFILES" ;;
@@ -18201,6 +18371,7 @@ s,@STATIC_FD@,$STATIC_FD,;t t
 s,@STATIC_SD@,$STATIC_SD,;t t
 s,@STATIC_DIR@,$STATIC_DIR,;t t
 s,@STATIC_CONS@,$STATIC_CONS,;t t
+s,@STATIC_GNOME_CONS@,$STATIC_GNOME_CONS,;t t
 s,@ALL_DIRS@,$ALL_DIRS,;t t
 s,@CONS_INC@,$CONS_INC,;t t
 s,@CONS_LIBS@,$CONS_LIBS,;t t
@@ -18220,6 +18391,12 @@ s,@sd_port@,$sd_port,;t t
 s,@dir_password@,$dir_password,;t t
 s,@fd_password@,$fd_password,;t t
 s,@sd_password@,$sd_password,;t t
+s,@dir_user@,$dir_user,;t t
+s,@dir_group@,$dir_group,;t t
+s,@sd_user@,$sd_user,;t t
+s,@sd_group@,$sd_group,;t t
+s,@fd_user@,$fd_user,;t t
+s,@fd_group@,$fd_group,;t t
 s,@SQL_LFLAGS@,$SQL_LFLAGS,;t t
 s,@SQL_INCLUDE@,$SQL_INCLUDE,;t t
 s,@SQL_BINDIR@,$SQL_BINDIR,;t t
@@ -18777,12 +18954,13 @@ 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/make_catalog_backup src/cats/delete_catalog_backup
-chmod 755 src/cats/alter_mysql_tables
 chmod 755 src/cats/grant_mysql_privileges
 chmod 755 src/cats/make_sqlite_tables src/cats/drop_sqlite_tables
+chmod 755 src/cats/update_sqlite_tables
 chmod 755 src/cats/make_bacula_tables src/cats/drop_bacula_tables
+chmod 755 src/cats/update_mysql_tables
+chmod 755 src/cats/update_bacula_tables src/cats/update_mysql_tables
 chmod 755 src/cats/create_sqlite_database
-chmod 755 src/cats/alter_sqlite_tables
 chmod 755 src/cats/sqlite
 chmod 755 src/cats/make_bdb_tables src/cats/drop_bdb_tables
 chmod 755 src/cats/create_bdb_database
@@ -18844,9 +19022,18 @@ Configuration on `date`:
   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}
+
+  Director Port:             ${dir_port}
+  File daemon Port:          ${fd_port}
+  Storage daemon Port:       ${sd_port}
+
+  Director User:           ${dir_user}
+  Director Group:          ${dir_group}
+  Storage Daemon User:     ${dir_user}
+  Storage DaemonGroup:     ${dir_group}
+  File Daemon User:        ${dir_user}
+  File Daemon Group:       ${dir_group}
+
   SQL binaries Directory      ${SQL_BINDIR}
 
   Large file support:        $largefile_support
@@ -18854,7 +19041,7 @@ Configuration on `date`:
   TCP Wrappers support:       ${TCPW_MSG}
   ZLIB support:              ${have_zlib}
   enable-smartalloc:         ${support_smartalloc}
-  enable-gnome:              ${support_gnome}
+  enable-gnome:              ${support_gnome} ${gnome_version}
   client-only:               ${build_client_only}
 
   " > config.out
index 3edeac324b4d87d525265641e86b7639744ac7b3..61badcf7654f0b1b5746696b6da4047ee17350d0 100644 (file)
@@ -1,5 +1,5 @@
                  Kern's ToDo List
-                26 September 2003 
+                07 December 2003  
 
 Documentation to do: (any release a little bit at a time)
 - Document running a test version.
@@ -11,55 +11,287 @@ Documentation to do: (any release a little bit at a time)
 - VXA drives have a "cleaning required"
   indicator, but Exabyte recommends preventive cleaning after every 75
   hours of operation.
+  From Phil:
+    In this context, it should be noted that Exabyte has a command-line
+    vxatool utility available for free download.  (The current version is
+    vxatool-3.72.) It can get diagnostic info, read, write and erase tapes,
+    test the drive, unload tapes, change drive settings, flash new firmware,
+    etc.
+    Of particular interest in this context is that vxatool <device> -i will
+    report, among other details, the time since last cleaning in tape motion
+    minutes.  This information can be retrieved (and settings changed, for
+    that matter) through the generic-SCSI device even when Bacula has the
+    regular tape device locked.  (Needless to say, I don't recommend
+    changing tape settings while a job is running.)
 - Lookup HP cleaning recommendations.
 - Lookup HP tape replacement recommendations (see trouble shooting autochanger)
+- Create a man page for each binary (Debian package requirement).
           
 Testing to do: (painful)
 - that ALL console command line options work and are always implemented
 - blocksize recognition code.
 - Test if rewind at end of tape waits for tape to rewind.
 - Test cancel at EOM.       
-- Test not zeroing Autochanger slot when it is wrong.
-- Figure out how to use ssh or stunnel to protect Bacula communications.
-- Test connect timeouts.
 
-For 1.32 Testing/Documentation:
-- Document new records in Director. SDAddress SDDeviceName, SDPassword.
+For 1.33 Testing/Documentation:
+- Document new alias records in Director. SDAddress SDDeviceName, SDPassword.
   FDPassword, FDAddress, DBAddress, DBPort, DBPassword.
-- Document that it is safe to use the drive when the lights stop flashing.
 - Document new Include/Exclude ...
-- Document all the status codes JobLevel, JobType, JobStatus.
 - Add test of exclusion, test multiple Include {} statements.
 - Add counter variable test.
-                
-For 1.32:
-- Add GUI interface to manual
-- Document that Volume pruning can delete last Full backup and
-  hence you will not have a valid backup.
-- Clarify the fact that having the Bacula cygwin1.dll loaded
-  is not the same as having cygwin installed.
-- Fix sparse file handeling so that it always reads a multiple
-  of 512. Currently, it subtracts 8 bytes (for faddr).
-- Separate Dir heartbeat in FD from the SD heartbeat.
+- Document ln -sf /usr/lib/libncurses.so /usr/lib/libtermcap.so
+  and install the esound-dev  package for compiling Console on SuSE.
+- Add an example of using a FIFO in dirdconf.wml 
+- Add an item to the FAQ about running jobs in different timezones.
+- Add some examples of job editing codes.
 
+- Document Dan's new --with-dir-user, ... options.
+- Figure out how to use ssh or stunnel to protect Bacula communications.
+  Add Dan's work to manual
+                
 For 1.33
+- Add a .list all files in the restore tree (probably also a list all files)
+  Do both a long and short form.
+- Add a Media record flag that indicates that the Volume does disk
+  addressing.
+- Implement VolAddr, which is used when Volume is addressed like a disk,
+  and form it from VolFile and VolBlock.
+- Make multiple restore jobs for multiple media types specifying 
+  the proper storage type.
+- Implement MediaType keyword in bsr?   
+- Fix fast block rejection (stored/read_record.c:118). It passes a null
+  pointer (rec) to try_repositioning().
+- See if a restore job can add a file to the tape (prohibit this).
+- Look at extracting Win data from BackupRead.
+- Having dashes in filenames apparently creates problems for restore
+  by filename.
+- Add data compare on write/read in btape "test". 
+- Implement RestoreJobRetention? Maybe better "JobRetention" in a Job,
+  which would take precidence over the Catalog "JobRetention".
+- Implement Label Format in Add and Label console commands.
+- Possibly up network buffers to 65K. Put on variable.
+- Put email tape request delays on one or more variables. User wants
+  to cancel the job after a certain time interval.  Maximum Mount Wait?
+  Job, Client, Device, Pool, or Volume?
+  Is it possible to make this a directive which is *optional* in multiple
+  resources, like Level? If so, I think I'd make it an optional directive
+  in Job, Client, and Pool, with precedence such that Job overrides Client
+  which in turn overrides Pool.
+- Fix Ctl-C crashing the Console (readline?).
+- Finish work on conio.c
+
+
+After 1.33:
+- Look at adding SQL server and Exchange support for Windows. 
+- Restore: Enter Filename: 'C:/Documents and Settings/Comercial/My
+  Documents/MOP/formulário de registro BELAS ARTES.doc' causes Bacula to
+  crash.
+- Each DVD-RAM disk would be a volume, just like each tape is 
+  a volume. It's a 4.7GB media with random access, but there's nothing about 
+  it that I can see that makes it so different than a tape from  bacula's 
+  perspective. Why couldn't I back up to a bare floppy as a volume (ignoring 
+  the media capacity?)
+- Make dev->file and dev->block_num signed integers so that -1 can
+  be an invalid value which happens with BSR.
+- Create VolAddr for disk files in place of VolFile and VolBlock. This
+  is needed to properly specify ranges.
+- Print bsmtp output to job report so that problems will be seen.
+- Pass the number of files to be restored to the FD for reporting 
+- Add progress of files/bytes to SD and FD.
+- Don't continue Restore if no files selected.
+- Print warning message if FileId > 4 billion
+- do a "messages" before the first prompt in Console
+- Add a date and time stamp at the beginning of every line in the 
+  Job report (Volker Sauer).
+- Client does not show busy during Estimate command.
+- Implement Console mtx commands.
+- Look at 2Gb limit for SQLite.
+- Implement 3 Pools for a Job:
+   Job {
+   Â  Name = ...
+   Â  Full Backup Pool = xxx
+   Â  Incremental Backup Pool = yyy
+   Â  Differential Backup Pool = zzz
+   }
+- Add a default DB password to MySQL.  
+  GRANT all privileges ON bacula.* TO bacula@localhost IDENTIFIED BY 
+     'bacula_password';
+  FLUSH PRIVILEGES;
+- Define week of year for scheduler.  W01, W02, ...
+  Week 01 of a year is per definition the first week that has the
+  Thursday in this year, which is equivalent to the week that contains the
+  fourth day of January.  In other words, the first week of a new year is
+  the week that has the majority of its days in the new year.  Week 01
+  might also contain days from the previous year and the week before week
+  01 of a year is the last week (52 or 53) of the previous year even if it
+  contains days from the new year.  A week starts with Monday (day 1) and
+  ends with Sunday (day 7).  For example, the first week of the year 1997
+  lasts from 1996-12-30 to 1997-01-05 and can be written in standard
+  notation as
+
+    1997-W01 or 1997W01
+
+  The week notation can also be extended by a number indicating the day
+  of the week.  For example, the day 1996-12-31, which is the Tuesday (day
+  2) of the first week of 1997, can also be written as
+
+    1997-W01-2 or 1997W012
+
+- Implement a Mount Command and an Unmount Command where
+  the users could specify a system command to be performed
+  to do the mount, after which Bacula could attempt to
+  read the device. This is for Removeable media such as a CDROM.
+  - Most likely, this mount command would be invoked explicitly
+  by the user using the current Console "mount" and "unmount" 
+  commands -- the Storage Daemon would do the right thing 
+  depending on the exact nature of the device.
+  - As with tape drives, when Bacula wanted a new removable
+  disk mounted, it would unmount the old one, and send a message
+  to the user, who would then use "mount" as described above 
+  once he had actually inserted the disk.
+- Implement dump/print label to UA
+- Implement disk spooling. Two parts: 1. Spool to disk then
+  immediately to tape to speed up tape operations. 2. Spool to
+  disk only when the tape is full, then when a tape is hung move
+  it to tape.
+- Scratch Pool where the volumes can be re-assigned to any Pool.
+- bextract is sending everything to the log file ****FIXME****
+- Add Progress command that periodically reports the progress of
+  a job or all jobs.
+- Restrict characters permitted in a Resource name, and don't permit
+  duplicate names.
+- Allow multiple Storage specifications (or multiple names on
+  a single Storage specification) in the Job record. Thus a job 
+  can be backed up to a number of storage devices.
+- Implement some way for the File daemon to contact the Director 
+  to start a job or pass its DHCP obtained IP number.
+- Implement multiple Consoles.
+- Implement a query tape prompt/replace feature for a console
+- From Johan?
+    Two jobs ready to go, first one blocked waiting for media
+    Cancel 2nd job ("waiting execution" one)
+    Cancel blocked job
+    boom - segfault*
+- Copy console @ code to gnome2-console
+- Make AES the only encryption algorithm see 
+  http://csrc.nist.gov/CryptoToolkit/aes/).  It's
+  an officially adopted standard, has survived peer
+  review, and provides keys up to 256 bits.
+- Add ctl-c to console to stop current command and discard buffered
+  output.
+- Estimate to Tibs never returns.
+- Think about how space could be freed up on a tape -- perhaps this
+  is a Merge or Compact feature that is needed.
+- Modify FileSet, did not upgrade the current Increment job, but
+  waited for the next job to be upgraded.
+- Take a careful look at SetACL http://setacl.sourceforge.net     
+- Implement a where command for the tree telling where a file
+  is located.
+- Take a careful look at Level for the estimate command, maybe make
+  it a command line option.
+- Add Volume name to "I cannot write on this volume because"
+- Make restore job check if all the files are actually restored.
+- Make tree walk routines like cd, ls, ... more user friendly
+  by handling spaces better.
+- Write your PID file and chown root:wheel before drop.
+- Make sure there is no symlink in a file before creating a
+  file (attack).
+- Look at mktemp or mkstemp(3).
+    mktemp and mkstemp create files with predictable names too.  That's
+    not the vulnerability.  The vulnerability is in creating files without
+    using the O_EXCL flag, which means "only create this file if it doesn't
+    exist, including if the file is a dangling symlink."
+
+    It is *NOT* enough to do the equivalent of
+
+      if doesn't exist $filename
+       then create $filename
+
+    because between the test and the create another process could have
+    gotten the CPU and created the file.  You must use atomic functions
+    (those that don't get interrupted by other processes) and O_EXCL is
+    the only way for this particular example.
+- Automatically create pools, but instead of looking for what
+  in in Job records, walk through the pool resources.
+- Check and double check tree code, why does it take so long?
+- Add device name to "Current Volume not acceptable because ..."
+- Make sure that Bacula rechecks the tape after the 20 min wait.
+- Set IO_NOWAIT on Bacula TCP/IP packets.
+- Try doing a raw partition backup and restore by mounting a
+  Windows partition.
+- Report CVS problems to SourceForge.
+- Implement .consolerc for Console
+- From Lars Köllers:
+    Yes, it would allow to highly automatic the request for new tapes. If a 
+    tape is empty, bacula reads the barcodes (native or simulated), and if 
+    an unused tape is found, it runs the label command with all the 
+    necessary parameters.
+
+    By the way can bacula automatically "move" an empty/purged volume say 
+    in the "short" pool to the "long" pool if this pool runs out of volume 
+    space?
+- Either restrict the characters in a name, or fix the problem 
+  emailing with names containing / (smtp command line breaks).
+- Eliminate orphaned jobs: dbcheck, normal pruning, delete job command.
+  Hm.  Well, there are the remaining orphaned job records:
+
+     |   105 | Llioness Save  | 0000-00-00 00:00:00 | B    | D     |        0 |             0 | f         |
+     |   110 | Llioness Save  | 0000-00-00 00:00:00 | B    | I     |        0 |             0 | f         |
+     |   115 | Llioness Save  | 2003-09-10 02:22:03 | B    | I     |        0 |             0 | A         |
+     |   128 | Catalog Save   | 2003-09-11 03:53:32 | B    | I     |        0 |             0 | C         |
+     |   131 | Catalog Save   | 0000-00-00 00:00:00 | B    | I     |        0 |             0 | f         |
+
+     As you can see, three of the five are failures.  I already deleted the
+     one restore and one other failure using the by-client option.  Deciding
+     what is an orphaned job is a tricky problem though, I agree.  All these
+     records have or had 0 files/ 0 bytes, except for the restore.  With no
+     files, of course, I don't know of the job ever actually becomes
+     associated with a Volume.
+
+     (I'm not sure if this is documented anywhere -- what are the meanings of
+     all the possible JobStatus codes?)
+
+     Looking at my database, it appears to me as though all the "orphaned"
+     jobs fit into one of two categories:
+
+     1)  The Job record has a StartTime but no EndTime, and the job is not
+     Â Â Â  currently running;
+     or
+     2)  The Job record has an EndTime, indicating that it completed, but
+     Â Â Â  it has no associated JobMedia record.
+
+
+     This does suggest an approach.  If failed jobs (or jobs that, for some
+     other reason, write no files) are associated with a volume via a
+     JobMedia record, then they should be purged when the associated volume
+     is purged.  I see two ways to handle jobs that are NOT associated with a
+     specific volume:
+
+     1)  purge them automatically whenever any volume is manually purged;
+     or
+     2)  add an option to the purge command to manually purge all jobs with
+     Â Â Â  no associated volume.
+
+     I think Restore jobs also fall into category 2 above ....  so one might
+     want to make that "The Job record has an EndTime,, but no associated
+     JobMedia record, and is not a Restore job."  
+- make "btape /tmp" work.
+- Make sure a rescheduled job is properly reported by status.
+- Walk through the Pool records rather than the Job records
+  in dird.c to create/update pools.
+- What to do about "list files job=xxx".
+- Implement scan: for every slot it finds, zero the slot of
+  Volume other volume having that slot.
 - When job rescheduled, status gives is waiting for Client Rufus 
   to connect to Storage File. Dir needs to inform SD that job
   is rescheduled.
 - Fix get_storage_from_media_type (ua_restore) to use command line     
   storage=
-- Enhance "update slots" to include a "scan" feature
-  scan 1; scan 1-5; scan 1,2,4 ...  to update the catalog 
-- Allow a slot or range of slots on the label barcodes command.
 - Don't print "Warning: Wrong Volume mounted ..." if mounting second volume.
 - Make Dmsg look at global before calling subroutine.
 - Enable trace output at runtime for Win32
-- Make sure that Volumes are recycled based on "Least recently used"
-  rather than lowest MediaId.
 - Available volumes for autochangers (see patrick@baanboard.com 3 Sep 03 
   and 4 Sep) scan slots.
-- Upgrade to cygwin 1.5
-- Get MySQL 3.23.58
 - Get and test MySQL 4.0
 - Do a complete audit of all pthreads_mutex, cond, ... to ensure that
   any that are dynamically initialized are destroyed when no longer used.
@@ -71,7 +303,7 @@ For 1.33
 - Use system dependent calls to get more precise info on tape errors.
 - Add heartbeat from FD to SD if hb interval expires.
 - Suppress read error on blank tape when doing a label.
-- Can we dynamically change FileSets.
+- Can we dynamically change FileSets?
 - If pool specified to label command and Label Format is specified,
   automatically generate the Volume name.
 - Take a careful look a the Basic recycling algorithm.  When Bacula
@@ -101,9 +333,6 @@ For 1.33
   time as the user walks through the tree).
 - Possibly use the hash code if the user selects all for a restore command.
 - Orphaned Dir buffer at parse_conf.c:373 =>  store_dir
-- Implement some way for the File daemon to contact the Director 
-  to start a job or pass its DHCP obtained IP number.
-- Implement multiple Consoles.
 - Add Console usr permissions.
 - Fix "restore all" to bypass building the tree.
 - Fix restore to list errors if Invalid block found, and if # files
@@ -114,12 +343,9 @@ For 1.33
   be sure this works with admin jobs so that the user can get
   prompted to insert the correct tape.  Possibly some way to say to
   run the job but don't save the files.
-- Add JobName= to VerifyToCatalog so that all verifies can be done at the end.
 - Implement FileOptions (see end of this document)
 - Make things like list where a file is saved case independent for
   Windows.
-- Edit the Client/Storage name into authentication failure messages.
-- Implement job in VerifyToCatalog
 - Implement migrate
 - Implement a PostgreSQL driver.
 - Bacula needs to propagate SD errors.
@@ -131,7 +357,6 @@ For 1.33
   > > prod4-sd: End of medium on Volume "REU007" Bytes=16,303,521,933 
 
 - Use autochanger to handle multiple devices.
-- Fix packet too big problem.
 - Add SuSE install doc to list.
 - Check and rechedk "Invalid block number"
 - Make bextract release the drive properly between tapes 
@@ -146,16 +371,10 @@ For 1.33
 - Something is not right in last block of fill command.
 - Implement a Recycle command
 - Add FileSet to command line arguments for restore.
-- Allow multiple Storage specifications (or multiple names on
-  a single Storage specification) in the Job record. Thus a job 
-  can be backed up to a number of storage devices.
 - Add client name to cram-md5 challenge so Director can immediately
   verify if it is the correct client.
-- Implement ClientRunBeforeJob and ClientRunAfterJob.
 - Add JobLevel in FD status (but make sure it is defined).
 - Audit all UA commands to ensure that we always prompt where possible.
-- Restrict characters permitted in a Resource name, and don't permit
-  duplicate names.
 - Check Jmsg in bnet, may not work, must dup bsock.
 - Suppress Job Name in Jmsg for console
 - Create Pools that are referenced in a Run statement at startup if possible.
@@ -181,12 +400,7 @@ For 1.33
   all Differential and Incremental jobs obsoleted by that Full backup.
   This would let people minimize the number of tapes they're keeping on
   hand without having to master the art of retention times.
-- Implement new serialize subroutines
-   send(socket, "string", &Vol, "uint32", &i, NULL)
-- Scratch Pool where the volumes can be re-assigned to any Pool.
 - Implement a M_SECURITY message class.
-- Implement forward spacing block/file: position_device(bsr) --
-  just before read_block_from_device();
 - When doing a Backup send all attributes back to the Director, who
   would then figure out what files have been deleted.
 - Currently in mount.c:236 the SD simply creates a Volume. It should have
@@ -201,11 +415,6 @@ For 1.33
   low level routines by accessing it and using Jmsg().
 - Cancel waiting for Client connect in SD if FD goes away.
 
-- Add Progress command that periodically reports the progress of
-  a job or all jobs.
-- One block was orphaned in the SD probably after cancel.
-
-
 - Examine Bare Metal restore problem (a FD crash exists somewhere ...).
 - Implement timeout in response() when it should come quickly.
 - Implement console @echo command.
@@ -220,30 +429,12 @@ For 1.33
 - Implement restore "current system", but take all files without
   doing selection tree -- so that jobs without File records can
   be restored.
-- Implement disk spooling. Two parts: 1. Spool to disk then
-  immediately to tape to speed up tape operations. 2. Spool to
-  disk only when the tape is full, then when a tape is hung move
-  it to tape.
 - Implement a relocatable bacula.spec 
-- Implement dump/print label to UA
 - Add prefixlinks to where or not where absolute links to FD.
 - Issue message to mount a new tape before the rewind.
 - Simplified client job initiation for portables.
 - If SD cannot open a drive, make it periodically retry.
-- Implement LabelTemplate (at least first cut).
 - Add more of the config info to the tape label.
-- Implement a Mount Command and an Unmount Command where
-  the users could specify a system command to be performed
-  to do the mount, after which Bacula could attempt to
-  read the device. This is for Removeable media such as a CDROM.
-  - Most likely, this mount command would be invoked explicitly
-  by the user using the current Console "mount" and "unmount" 
-  commands -- the Storage Daemon would do the right thing 
-  depending on the exact nature of the device.
-  - As with tape drives, when Bacula wanted a new removable
-  disk mounted, it would unmount the old one, and send a message
-  to the user, who would then use "mount" as described above 
-  once he had actually inserted the disk.
 
 - If tape is marked read-only, then try opening it read-only rather than
   failing, and remember that it cannot be written.
@@ -295,7 +486,6 @@ For 1.33
 - Compare tape to Client files (attributes, or attributes and data) 
 - Make all database Ids 64 bit.
 - Write an applet for Linux.
-- Implement new inter-daemon communications protocol.
 - Allow console commands to detach or run in background.
 - Fix status delay on storage daemon during rewind.
 - Add SD message variables to control operator wait time
@@ -468,193 +658,6 @@ Migration triggered by:
   Highwater mark (keep total size)
   Lowwater mark
   
-Projects:
-            Bacula Projects Roadmap 
-               17 August 2002
-           last update 8 May 2003
-
-Item 1:   Multiple simultaneous Jobs. (done)
-Done -- Restore part needs better implementation to work correctly
-        Also, it needs considerable testing
-
-  What:   Permit multiple simultaneous jobs in Bacula.
-
-  Why:    An enterprise level solution needs to go fast without the
-          need for the system administrator to carefully tweak
-          timing.  Based on the benchmarks, during a full
-          backup, NetWorker typically hit 10 times the bandwidth to
-          the tape compared to Bacula--largely. This is probably due to
-          running parallel jobs and multi-threaded filling of buffers
-          and writing them to tape.  This should also make things work
-          better when you have a mix of fast and slow machines backing
-          up at the same time.
-
-  Notes:  Bacula was designed to run multiple simultaneous jobs. Thus
-          implementing this is a matter of some small cleanups and
-          careful testing.
-
-
-Item 2:   Make the Storage daemon use intermediate file storage to buffer data.
-Deferred -- not necessary yet -- possibly implement with Migration.
-
-  What:   If data is coming into the SD too fast, buffer it to 
-          disk if the user has configured this option.
-
-  Why:    This would be nice, especially if it more or less falls out
-          when implementing (1) above.  If not, it probably should not
-          be given a high priority because fundamentally the backup time
-          is limited by the tape bandwidth.  Even though you may finish a
-          client job quicker by spilling to disk, you still have to
-          eventually get it onto tape.  If intermediate disk buffering
-          allows us to improve write bandwidth to tape, it may make
-          sense.
-
-  Notes:  Whether or not this is implemented will depend upon performance
-          testing after item 1 is implemented.
-
-
-Item 3:   Write the bscan program -- also write a bcopy program.
-Done
-
-  What:   Write a program that reads a Bacula tape and puts all the 
-          appropriate data into the catalog. This allows recovery
-          from a tape that is no longer in the database, or it allows
-          re-creation of a database if lost.
-
-  Why:    This is a fundamental robustness and disaster recovery tool
-          which will increase the comfort level of a sysadmin
-          considering adopting Bacula.
-
-  Notes:  A skeleton of this program already exists, but much work
-          needs to be done. Implementing this will also make apparent
-          any deficiencies in the current Bacula tape format.
-
-
-Item 4:   Implement Base jobs.
-
-  What:   A base job is sort of like a Full save except that you 
-          will want the FileSet to contain only files that are unlikely
-          to change in the future (i.e. a snapshot of most of your
-          system after installing it). After the base job has been run,
-          when you are doing a Full save, you can specify to exclude
-          all files saved by the base job that have not been modified.
-
-  Why:    This is something none of the competition does, as far as we know
-          (except BackupPC, which is a Perl program that saves to disk
-          only).  It is big win for the user, it makes Bacula stand out
-          as offering a unique optimization that immediately saves time
-          and money.
-
-  Notes:  Big savings in tape usage. Will require more resources because
-          the e. DIR must send FD a list of files/attribs, and the FD must
-          search the list and compare it for each file to be saved.
-
-
-Item 5:   Implement Label templates
-Done 
-
-  What:   This is a mechanism whereby Bacula can automatically create
-          a tape label for new tapes according to a detailed specification
-          provided by the user.
-
-  Why:    It is a major convenience item for folks who use automated label
-          creation.
-
-  Notes:  Bacula already has a working form of automatic tape label
-          creation, but it is very crude. The design for the complete
-          tape labeling project is already documented in the manual.
-
-
-Item 6:   Write a regression script.
-Done --   Continue to expand its testing.
-
-  What:   This is an automatic script that runs and tests as many features
-          of Bacula as possible. The output is compared to previous
-          versions of Bacula and any differences are reported.
-
-  Why:    This is an enormous help in preventing introduction of new
-          errors in parts of the program that already work correctly.
-
-  Notes:  This probably should be ranked higher, it's something the typical
-          user doesn't see.  Depending on how it's implemented, it may
-          make sense to defer it until the archival tape format and
-          user interface mature.
-
-
-Item 7:   GUI for interactive restore
-Item 8:   GUI for interactive backup
-
-  What:   The current interactive restore is implemented with a tty
-          interface. It would be much nicer to be able to "see" the
-          list of files backed up in typical GUI tree format.
-          The same mechanism could also be used for creating 
-          ad-hoc backup FileSets (item 8).
-
-  Why:    Ease of use -- especially for the end user.
-
-  Notes:  Rather than implementing in Gtk, we probably should go directly
-          for a Browser implementation, even if doing so meant the
-          capability wouldn't be available until much later.  Not only
-          is there the question of Windows sites, most
-          Solaris/HP/IRIX, etc,  shops can't currently run Gtk programs
-          without installing lots of stuff admins are very wary about.
-          Real sysadmins will always use the command line anyway, and
-          the user who's doing an interactive restore or backup of his
-          own files will in most cases be on a Windows machine running
-          Exploder.
-
-
-Item 9:   Add SSL to daemon communications.
-
-  What:   This provides for secure communications between the daemons.
-
-  Why:    This would allow doing backup across the Internet without
-          privacy concerns (or with much less concern).
-
-  Notes:  The vast majority of near term potential users will be backing up
-          a single site over a LAN and, correctly or not, they probably
-          won't be concerned with security, at least not enough to go to
-          the trouble to set up keys, etc. to screw things down.  We suspect
-          that many users genuinely interested in multi-site backup
-          already run some form of VPN software in their internetwork
-          connections, and are willing to delegate security to that layer.
-
-
-Item 10:  Define definitive tape format.
-Done (version 1.27)
-
-  What:   Define that definitive tape format that will not change 
-          for the next millennium.
-
-  Why:    Stability, security.
-
-  Notes:  See notes for item 11 below.
-
-
-Item 11:  New daemon communication protocol.
-
-  What:   The current daemon to daemon protocol is basically an ASCII
-          printf() and sending the buffer. On the receiving end, the
-          buffer is sscanf()ed to unpack it. The new scheme would
-          be a binary format that allows quick packing and unpacking
-          of any data type with named fields.
-
-  Why:    Using binary packing would be faster. Named fields will permit
-          error checking to ensure that what is sent is what the 
-          receiver really wants.
-
-  Notes:  These are internal improvements in the interest of the
-          long-term stability and evolution of the program.  On the one
-          hand, the sooner they're done, the less code we have to rip
-          up when the time comes to install them.  On the other hand, they
-          don't bring an immediately perceptible benefit to potential
-          users.  Item 10 and possibly item 11 should be deferred until Bacula
-          is well established with a growing user community more or
-          less happy with the feature set.  At that time, it will make a
-          good "next generation" upgrade in the interest of data
-          immortality.
-
-
 
 
 ======================================================
@@ -662,11 +665,16 @@ Item 11:  New daemon communication protocol.
 It is somewhat like a Full save becomes an incremental since
 the Base job (or jobs) plus other non-base files.
 Need:
-- New BaseFile table that contains:
-    JobId, BaseJobId, FileId (from Base).
+- A Base backup is same as Full backup, just different type.
+- New BaseFiles table that contains:
+    BaseId - index
+    BaseJobId - Base JobId referenced for this FileId (needed ???)
+    JobId - JobId currently running
+    FileId - File not backed up, exists in Base Job
+    FileIndex - FileIndex from Base Job.
   i.e. for each base file that exists but is not saved because
   it has not changed, the File daemon sends the JobId, BaseId,
-  and FileId back to the Director who creates the DB entry.
+  FileId, FileIndex back to the Director who creates the DB entry.
 - To initiate a Base save, the Director sends the FD 
   the FileId, and full filename for each file in the Base.
 - When the FD finds a Base file, he requests the Director to
@@ -760,6 +768,9 @@ Options records:
   asterisk preceding the name indicates a feature not currently
   implemented.
 
+    - Regexp "xxx"            - Match regular expression
+    - Wild "xxx"              - Do a wild card match
+
   For Backup Jobs:
     - Compression= (GZIP, ...)
     - Signature=   (MD5, SHA1, ...)
@@ -771,6 +782,9 @@ Options records:
     - *Reader=    (filename)  - external read (backup) program
     - *Plugin=    (filename)  - read/write plugin module
 
+    - Include=    (yes/no)    - Include the file matched no additional
+                                patterns are applied.
+
   For Verify Jobs:
     - verify=     (ipnougsamc5) - verify options
 
@@ -808,7 +822,7 @@ Example:
       Include {
         Compression = GZIP;
         Signature = MD5
-        Match = /*.?*/                # matches all files.
+        Wild  = /*.?*/                # matches all files.
         File = /
       }
     }
@@ -826,13 +840,13 @@ Example:
         Options {
           Signature = MD5
           # Note multiple Matches are ORed
-          Match = /*.gz/   # matches .gz files */
-          Match = /*.Z/    # matches .Z files */
+          Wild  = "*.gz"   # matches .gz files
+          Wild  = "*.Z"    # matches .Z files
         }
         Options {
           Compression = GZIP
           Signature = MD5
-          Match = /*.?*/   # matches all files
+          Wild  = "*.?*"   # matches all files
         }
         File = /
       }
@@ -848,7 +862,7 @@ Questions:
   - Is it necessary to provide some means of ANDing regular expressions
     and negation?  (not currently planned)
 
-    e.g.  Match = /*.gz/ && !/big.gz/
+    e.g.  Wild  = /*.gz/ && !/big.gz/
 
   - I see that Networker has a "null" module which, if specified, does not 
     backup the file, but does make an record of the file in the catalog
@@ -884,76 +898,71 @@ Need:
 
 
 Done: (see kernsdone for more)
-- Implement new alist in FileSet scanning.
-- bls should continue reading even if it finds Win32 data on the tape.
-  The error should be Warning rather the Error.
-- Add user configurable timeout for connecting to SD.
-- Unsaved Flag in Job record (use JobMissingFiles).
-- Base Flag in Job record.
-- Configure mtx-changer to have correct path to mtx.
-- Add all command line arguments to "update", e.g. slot=nn volStatus=append, ...
-- Make some way so that if a machine is skipped because it is not up 
-  that Bacula will continue retrying for a specified period of time --
-  periodically.
-- Implement all command line args on run.
-- Implement command line "restore" args.
-- Implement "restore current select=no"
-- Restore file modified before date
-- Restore -- do nothing but show what would happen
-- Add estimate to Console commands
-- Use read_record.c in SD code.
-- Fix read_record to handle multiple sessions.
-- Tip from Steve Allam
-  mt -f /dev/nst0 defblksize 0
-- Document "status" in the console.
-- Document driving console from shell script.
-- Write JobMedia records with max file size is reached on tape.
-- Handle the case of multiple JobMedia records pending (i.e. the
-  thread is slow and multiple situations requiring a JobMedia
-  record occur).
-- Do performance analysis on the restore tree routines.
-- Fix maximum file size (block.c) to generate JobMedia records.
-- Make the default file size 1GB on the tape.
-- Implement forward spacing between files.
-- Add Machine type (Linux/Windows) to Status report for daemons. 
-  Look at src/host.h
-- Use repositioning at the beginning of the tape.                   
-- Do full check the command line args in update (e.g. VolStatus ...).
-- Specify list of files to restore
+
+=== after 1.32c
+- John's Full save failed with 1.32c FD and 1.31 Dir no FD status,
+  and no error message.
+- Add fd and st as Console keywords.
+- Recycling volume with a Slot requires an operator intervention:
+    rufus-dir: Start Backup JobId 18, Job=kernsave.2003-11-01_21.23.52
+    rufus-dir: Pruned 1 Job on Volume Vol01 from catalog.
+    rufus-dir: There are no Jobs associated with Volume Vol01. Marking it purged.
+    rufus-dir: Recycled volume "Vol01"
+    rufus-sd: Please mount Volume "Vol01" on Storage Device "DDS-4" for Job kernsave.2003-11-01_21.23.52
+    Use "mount" command to release Job.
+- Implement Dan's bacula script (email of 26 Oct).
+- Add JobName= to VerifyToCatalog so that all verifies can be done at the end.
+- Edit the Client/Storage name into authentication failure messages.
+- Fix packet too big problem. This is most likely a Windows TCP stack 
+  problem.
 - Implement ClientRunBeforeJob and ClientRunAfterJob.
-- Make | and < work on FD side.
-- Check to see if "blocked" is set during restore.
-- Figure out what is interrupting sql command in console.
-- Make new job print warning User Unmounted Tape.
-- Test recycling and purging (code changed in db_find_next_volume and
-  in recycle.c).
-- Document SDConnectTimeout (in FD).
-- Add restore by filename test.
-- Document restore by files.
-- Make variable expansion work correctly.
-- Implement List Volume Job=xxx  or List scheduled volumes or Status Director 
-- Copy static programs into install directory.
-- Think about changing Storage resource Device record to be
-  SDDeviceName.
-- Add RunBeforeJob and RunAfterJob to the Client program.
-- Need return status on read_cb() from read_records(). Need multiple
-  records -- one per Job, maybe a JCR or some other structure with
-  a block and a record.
-- LabelFormat on tape volume apparently creates the db record but 
-  never actually labels the volume.
-- Recycling a volume when two jobs are using it is going to break. Fixed.
-- Document list nextvol and new format status dir.
-- Client files in Win32 with Unix eol conventions doesn't work.
-- Either fix or document that fill command in btape can be
-  compressed enormously by the hardware - a 36GB tape wrote 750GB!
-- Add multiple character duration qualifiers.
-- Require some modifer.
-- Restrict characters permitted in a Resource name, and don't permit
-  duplicate names.
-- Figure out some way to ignore or get past checksum errors in
-  reading.
-- The SD spooling file gets created even if it is not used.
-- Look at Cleaning tape in ua_label.c for media create/update 
-- Add regression testing to the manual
-- End time: in job output of rescheduled job is time of first run.
-- Document list nextvol and status output.
+- Implement forward spacing block/file: position_device(bsr) --
+  just before read_block_from_device();
+=== for 1.33
+- Change console to bconsole.
+- Change smtp to bsmtp.
+- Fix time difference problem between Bacula and Client
+  so that everything is in GMT.
+- Fix TimeZone problem!
+- Mount a tape that is not right for the job (wrong # files on tape)
+  Bacula asks for another tape, fix problems with first tape and
+  say "mount". All works OK, but status shows:
+   Device /dev/nst0 open but no Bacula volume is mounted.
+       Total Bytes=1,153,820,213 Blocks=17,888 Bytes/block=64,502
+       Positioned at File=9 Block=3,951
+   Full Backup job Rufus.2003-10-26_16.45.31 using Volume "DLT-24Oct03" on device /dev/nst0
+       Files=21,003 Bytes=253,954,408 Bytes/sec=2,919,016
+       FDReadSeqNo=192,134 in_msg=129830 out_msg=5 fd=7
+- Upgrade to cygwin 1.5
+- Optimize fsf not to read.
+- Use ioctl() fsf if it exists. Figure out where we are from
+  the mt_status command. Use slow fsf only if other does not work.
+- Enhance "update slots" to include a "scan" feature
+  scan 1; scan 1-5; scan 1,2,4 ...  to update the catalog 
+- Allow a slot or range of slots on the label barcodes command.
+- Finish implementation of Verify=DiskToCatalog
+- Make sure that Volumes are recycled based on "Least recently used"
+  rather than lowest MediaId.
+- Add flag to write only one EOF mark on the tape.
+- Implement autochanger testing in btape "test" command.
+- Implement lmark to list everyfile marked.
+- Make mark/unmark report how many files marked/unmarked.
+- Keep last 5 or 10 completed jobs and show them in a similar list.
+- Make a Running Jobs: output similar to current Scheduled Jobs:
+- Change "create_media_record in bscan to use Archive instead of Full.
+- Have some way to estimate the restore size or have it printed.
+- Volume problems occurs if you have valid volume, written, then it is
+  truncated. You get 12-Nov-2003 11:48 rufus-sd: kernsave.2003-11-12_11.48.09 Warning: mount.c:228 Volume on /tmp is not a Bacula labeled Volume, because:
+     block.c:640 Read zero bytes on device /tmp.
+- Make sure that 64 bit I/O packets are used on Cygwin.
+- Add to supported autochangers 
+  OS  Â Â Â Â Â Â Â Â Â Â Â Â : FreeBSD-4.9
+  Auto-Changer    : QUALSTAR TLS-4210
+  Â  Manufufactur  : Qualstar
+  Â  Tapes         : 12 (AIT1: 36GB, AIT2: 50GB all uncompressed)
+  Â  Drives        : 2xAIT2 (installed in the Qualstar: SONY SDX-500C AIT2)
+- Document estimate command in tree.
+- Document lsmark command in tree.
+- Setup a standard job that builds a bootstrap file and saves
+  it with the catalog database.
+
diff --git a/bacula/platforms/debian/bacula-director b/bacula/platforms/debian/bacula-director
new file mode 100644 (file)
index 0000000..4d40a11
--- /dev/null
@@ -0,0 +1,59 @@
+#! /bin/sh
+# bacula-director     SysV init script for Bacula-FD.
+#
+#       Written by Miquel van Smoorenburg <miquels@cistron.nl>.
+#       Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+#       Customized for Bacula by Jose Luis Tallon <jltallon@adv-solutions.net>
+#    Modified RJM 2-12-03 to fix errors with pidfile name
+#
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/bacula-dir
+NAME="bacula-dir"
+PORT=9101
+DESC="Bacula Director"
+ARGS="-c /etc/bacula/bacula-dir.conf -u bacula -g bacula"
+
+test -f $DAEMON || exit 0
+
+set -e
+
+if [ -n "`getent services bacula-dir`" ]; then
+        PORT=`getent services bacula-dir | awk '{ gsub("/tcp","",$2); print $2; }'`
+fi
+PIDFILE=/var/run/bacula/$NAME.$PORT.pid
+
+case "$1" in
+  start)
+       if [ -f /etc/bacula/do_not_run ]; then
+               echo "Not starting $DESC: disabled via /etc/bacula/do_not_run"
+               exit 0
+       fi
+
+       echo -n "Starting $DESC: "
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $ARGS
+       echo "$NAME."
+       ;;
+
+  stop)
+       echo -n "Stopping $DESC: "
+       start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE --exec $DAEMON
+       echo "$NAME."
+       ;;
+
+  restart|force-reload)
+       echo -n "Restarting $DESC: "
+       start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON
+       sleep 1
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $ARGS
+       echo "$NAME."
+       ;;
+  *)
+       N=/etc/init.d/$NAME
+       # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+       echo "Usage: $N {start|stop|restart|force-reload}" >&2
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/bacula/platforms/freebsd/.cvsignore b/bacula/platforms/freebsd/.cvsignore
new file mode 100644 (file)
index 0000000..babb54e
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+bacula-dir
+bacula-fd
+bacula-sd
diff --git a/bacula/platforms/freebsd/pthreads-fix.txt b/bacula/platforms/freebsd/pthreads-fix.txt
new file mode 100644 (file)
index 0000000..d4fa099
--- /dev/null
@@ -0,0 +1,193 @@
+From bacula-users-admin@lists.sourceforge.net Mon Oct 20 23:44:13 2003
+Return-Path: <bacula-users-admin@lists.sourceforge.net>
+Received: from sc8-sf-list2.sourceforge.net (lists.sourceforge.net
+       [66.35.250.206]) by matou.sibbald.com (8.11.6/8.11.6) with ESMTP id
+       h9KLiDY13657 for <kern@sibbald.com>; Mon, 20 Oct 2003 23:44:13 +0200
+Received: from sc8-sf-list1-b.sourceforge.net ([10.3.1.13]
+       helo=sc8-sf-list1.sourceforge.net) by sc8-sf-list2.sourceforge.net with
+       esmtp (Exim 3.31-VA-mm2 #1 (Debian)) id 1ABhpS-00013k-00; Mon, 20 Oct 2003
+       14:44:42 -0700
+Received: from sc8-sf-mx1-b.sourceforge.net ([10.3.1.11]
+       helo=sc8-sf-mx1.sourceforge.net) by sc8-sf-list1.sourceforge.net with esmtp
+        (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) id
+       1ABhnp-0007qu-00 for <bacula-users@lists.sourceforge.net>; Mon, 20 Oct 2003
+       14:43:01 -0700
+Received: from bast.unixathome.org ([66.11.174.150] ident=postfix) by
+       sc8-sf-mx1.sourceforge.net with esmtp (Exim 4.22) id 1ABfiR-0002Iv-Q8 for
+       bacula-users@lists.sourceforge.net; Mon, 20 Oct 2003 12:29:19 -0700
+Received: from wocker (wocker.unixathome.org [192.168.0.99]) by
+       bast.unixathome.org (Postfix) with ESMTP id 258913F53 for
+       <bacula-users@lists.sourceforge.net>; Mon, 20 Oct 2003 15:25:33 -0400 (EDT)
+From: "Dan Langille" <dan@langille.org>
+To: bacula-users@lists.sourceforge.net
+MIME-Version: 1.0
+Message-ID: <3F93FF4E.14552.13ACB682@localhost>
+Priority: normal
+X-mailer: Pegasus Mail for Windows (v4.02a)
+Content-type: text/plain; charset=US-ASCII
+Content-description: Mail message body
+X-Spam-Score: 0.0 (/)
+X-Spam-Report: 0.0/5.0 Spam Filtering performed by sourceforge.net. See
+       http://spamassassin.org/tag/ for more details. Report problems to
+       https://sf.net/tracker/?func=add&group_id=1&atid=200001
+Subject: [Bacula-users] FreeBSD - large backups to tape
+Sender: bacula-users-admin@lists.sourceforge.net
+Errors-To: bacula-users-admin@lists.sourceforge.net
+X-BeenThere: bacula-users@lists.sourceforge.net
+X-Mailman-Version: 2.0.9-sf.net
+Precedence: bulk
+List-Help: <mailto:bacula-users-request@lists.sourceforge.net?subject=help>
+List-Post: <mailto:bacula-users@lists.sourceforge.net>
+List-Subscribe:
+       <https://lists.sourceforge.net/lists/listinfo/bacula-users>,
+       <mailto:bacula-users-request@lists.sourceforge.net?subject=subscribe>
+List-Id: Bacula user's email list for support and discussions
+       <bacula-users.lists.sourceforge.net>
+List-Unsubscribe:
+       <https://lists.sourceforge.net/lists/listinfo/bacula-users>,
+       <mailto:bacula-users-request@lists.sourceforge.net?subject=unsubscribe>
+List-Archive:
+       <http://sourceforge.net/mailarchive/forum.php?forum=bacula-users>
+Date: Mon, 20 Oct 2003 15:29:18 -0400
+Content-Transfer-Encoding: 8bit
+
+Kern and I have been working on a FreeBSD/Bacula problem.  
+He's asked me to post this to the list.  The problem was within the
+FreeBSD pthreads library.  A solution has been found.
+
+PROBLEM DESCRIPTION:
+
+The FreeBSD pthreads library does not properly handle End Of Tape.
+This problem will be fixed in FreeBSD 4.9.  The bug results in more
+data being written to the tape than could be read.  Any backup which
+involved more than one tape would be incomplete.
+
+DEMONSTRATION:
+
+To demonstrate the problem, tapetest.c can be obtained from 
+http://www.freebsd.org/cgi/query-pr.cgi?pr=56274
+
+This tests without pthreads:
+
+ *  If you build this program with:
+ *
+ *  c++ -g -O2 -Wall -c tapetest.c
+ *  c++ -g -O2 -Wall tapetest.o -o tapetest
+ *
+ *  Procedure for testing tape
+ *  ./tapetest /dev/your-tape-device
+ *  rewind
+ *  rawfill
+ *  rewind
+ *  scan
+ *
+ *  The output will be something like:
+ *
+ * ========
+ *  Rewound /dev/nsa0
+ *  *Begin writing blocks of 64512 bytes.
+ *  ++++++++++++++++++++ ...
+ *  Write failed.  Last block written=17294. stat=0 ERR=Unknown 
+error: 0
+ *  weof_dev
+ *  Wrote EOF to /dev/nsa0
+ *  *Rewound /dev/nsa0
+ *  *Starting scan at file 0
+ *  17294 blocks of 64512 bytes in file 0
+ *  End of File mark.
+ *  End of File mark.
+ *  End of tape
+ *  Total files=1, blocks=17294, bytes = 1115670528
+ * ========
+ *
+ *  which is correct. Notice that the return status is
+ *  0, while in the example below, which fails, the return
+ *  status is -1.
+
+This tests with pthreads:
+
+ *  If you build this program with:
+ *
+ *  c++ -g -O2 -Wall -pthread -c tapetest.c
+ *  c++ -g -O2 -Wall -pthread tapetest.o -o tapetest
+ *    Note, we simply added -pthread compared to the
+ *    previous example.
+ *
+ *  Procedure for testing tape
+ *  ./tapetest /dev/your-tape-device
+ *  rewind
+ *  rawfill
+ *  rewind
+ *  scan
+ *
+ *  The output will be something like:
+ *
+ * ========
+ *    Rewound /dev/nsa0
+ *    *Begin writing blocks of 64512 bytes.
+ *    +++++++++++++++++++++++++++++ ...
+ *    Write failed.  Last block written=17926. stat=-1 ERR=No space left on device
+ *    weof_dev
+ *    Wrote EOF to /dev/nsa0
+ *    *Rewound /dev/nsa0
+ *    *Starting scan at file 0
+ *    17913 blocks of 64512 bytes in file 0
+ *    End of File mark.
+ *    End of File mark.
+ *    End of tape
+ *    Total files=1, blocks=17913, bytes = 1155603456
+ * ========
+ *
+ * which is incroorect because it wrote 17,926 blocks but read
+ * back only 17,913 blocks
+
+If you get the same number of blocks written and read WHEN using 
+pthreads, then you've been correctly patched.
+
+SOLUTION:
+
+For FreeBSD prior to 4.9, you have two choices to ensure proper
+backups.  These instructions assume you are familiar with patching
+FreeBSD and already have the FreeBSD source code installed on your
+machine.  
+
+1 - cvsup and build your system to FreeBSD 4.8-STABLE
+
+2 - Apply this patch.
+
+http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc_r/uthread/uthread_write.c.diff?r1=1.16.2.6&r2=1.16.2.7
+
+To apply the patch, follow these instructions as root.  
+
+fetch -o pthread.diff http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc_r/uthread/uthread_write.c.diff?r1=1.16.2.6\&r2=1.16.2.7
+
+cd /usr/src/lib/libc_r/uthread/
+patch < /path/to/pthread.diff
+cd ..
+make all install
+
+I recommend restarting Bacula.
+
+
+TESTING:
+
+I suggest running tapetest on your patched system and then
+conducting a backup which spans two tapes.  Restore the data
+and compare to the original.  If not identical, please let us know.
+
+Thanks
+
+-- 
+Dan Langille : http://www.langille.org/
+
+
+
+-------------------------------------------------------
+This SF.net email is sponsored by OSDN developer relations
+Here's your chance to show off your extensive product knowledge
+We want to know what you know. Tell us and you have a chance to win $100
+http://www.zoomerang.com/survey.zgi?HRPT1X3RYQNC5V4MLNSV3E54
+_______________________________________________
+Bacula-users mailing list
+Bacula-users@lists.sourceforge.net
+https://lists.sourceforge.net/lists/listinfo/bacula-users
index d568cdb9993601e05178347728debcded757e060..05fec1b7126a93012f9c2606d8e43b0240857a1b 100755 (executable)
@@ -3,7 +3,7 @@
 # bacula       This shell script takes care of starting and stopping
 #             the bacula Director daemon
 #
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
 # description: It comes by night and sucks the vital essence from your computers.
 #
 #  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
index 19f04f028b35d82bf480378100d82adefa260bcb..8b725bc72222400b1b37247312b51562810e3a46 100755 (executable)
@@ -3,7 +3,7 @@
 # bacula       This shell script takes care of starting and stopping
 #             the bacula File daemon.
 #
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
 # description: It comes by night and sucks the vital essence from your computers.
 #
 #  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
index a4bfdd4f5a47a7964286014c23ea26d0562a2be5..e58287625d338a806b1b1cdbae54ca4786577f9b 100755 (executable)
@@ -3,7 +3,7 @@
 # bacula       This shell script takes care of starting and stopping
 #             the bacula Storage daemon.
 #
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
 # description: It comes by night and sucks the vital essence from your computers.
 #
 #  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
index f69b37527ff9a45c52572b6fbabeac72f1beaeb9..8160b3f5be48534e204a14cb52b27ff3bd85ac1b 100644 (file)
@@ -1,60 +1,70 @@
+# Platform Build Configuration
 
+# basic defines for every build
 %define depkgs ../depkgs
+%define depkgs_version 24Jul03
+%define tomsrtbt tomsrtbt-2.0.103
 
-# 
-# You must build the package with at least one define
-#  e.g.  rpmbuild -ba --define "build_rh7 1" bacula.spec
-#
-# If you want the MySQL version, use:
-#        rpmbuild -ba --define "build_mysql 1" --define "build_rh7 1" bacula.spec
-#
-
+# platform defines - set one below or define the build_xxx on the command line
+# RedHat builds
 %define rh7 0
 %{?build_rh7:%define rh7 1}
-
 %define rh8 0
 %{?build_rh8:%define rh8 1}
-
 %define rh9 0
 %{?build_rh9:%define rh9 1}
-
+# Fedora Core 1 build
+%define fc1 0
+%{?build_fc1:%define fc1 1}
+# Whitebox Enterprise build
+%define wb3 0
+%{?build_wb3:%define wb3 1}
+
+# database defines
+# set mysql for MySQL support, leave unset for sqlite support
 %define mysql 0
 %{?build_mysql:%define mysql 1}
 
-
-%if %{rh7}
-%define rh_version rh7
-%endif
-%if %{rh8}
-%define rh_version rh8
-%endif
-%if %{rh9}
-%define rh_version rh9
-%endif
-
 Summary: Bacula - The Network Backup Solution
 Name: bacula
 Version: @VERSION@
 Release: 1
 Group: System Environment/Daemons
 Copyright: GPL v2
-Source: http://www.prdownloads.sourceforge.net/bacula/%{name}-%{version}.tar.gz
+Source0:http://www.prdownloads.sourceforge.net/bacula/%{name}-%{version}.tar.gz
+Source1:http://www.prdownloads.sourceforge.net/bacula/depkgs-%{depkgs_version}.tar.gz
+Source2:http://www.tux.org/pub/distributions/tinylinux/tomsrtbt/%{tomsrtbt}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-root
 URL: http://www.bacula.org/
 Vendor: The Bacula Team
 Distribution: The Bacula Team
 Packager: D. Scott Barninger <barninger@fairfieldcomputers.com>
-Requires: gnome-libs >= 1.4
-Requires: readline
+BuildRequires: readline-devel, atk-devel, ncurses-devel, pango-devel
+BuildRequires: libstdc++-devel, libtermcap-devel, libxml2-devel, zlib-devel
+%if %{rh7}
+BuildRequires: gtk+-devel >= 1.2
 BuildRequires: gnome-libs-devel >= 1.4
-BuildRequires: readline-devel
+BuildRequires: glibc-devel >= 2.2
+BuildRequires: ORBit-devel
+BuildRequires: bonobo-devel
+BuildRequires: GConf-devel
+%else
+BuildRequires: gtk2-devel >= 2.0
+BuildRequires: libgnomeui-devel >= 2.0
+BuildRequires: glibc-devel >= 2.3
+BuildRequires: ORBit2-devel
+BuildRequires: libart_lgpl-devel >= 2.0
+BuildRequires: libbonobo-devel >= 2.0
+BuildRequires: libbonoboui-devel >= 2.0
+BuildRequires: bonobo-activation-devel
+BuildRequires: GConf2-devel
+BuildRequires: linc-devel
+%endif
+
 %if %{mysql}
-Requires: mysql >= 3.23
-Requires: mysql-server >= 3.23
 BuildRequires: mysql-devel >= 3.23
 %endif
 
-
 %description
 Bacula - It comes by night and sucks the vital essence from your computers.
 
@@ -67,18 +77,44 @@ features that make it easy to find and recover lost or damaged files.
 Bacula source code has been released under the GPL version 2 license.
 
 %if %{mysql}
-%package mysql-%{rh_version}
+%package mysql
 %else
-%package sqlite-%{rh_version}
+%package sqlite
 %endif
 
 Summary: Bacula - The Network Backup Solution
 Group: System Environment/Daemons
+Provides: bacula-dir, bacula-sd, bacula-fd
+Requires: readline, perl, atk, ncurses, pango, libstdc++
+Requires: libtermcap, libxml2, zlib
+%if %{rh7}
+Requires: gtk+ >= 1.2
+Requires: gnome-libs >= 1.4
+Requires: glibc >= 2.2
+Requires: ORBit
+Requires: bonobo
+Requires: GConf
+%else
+Requires: gtk2 >= 2.0
+Requires: libgnomeui >= 2.0
+Requires: glibc >= 2.3
+Requires: ORBit2
+Requires: libart_lgpl >= 2.0
+Requires: libbonobo >= 2.0
+Requires: libbonoboui >= 2.0
+Requires: bonobo-activation
+Requires: GConf2
+Requires: linc
+%endif
+%if %{mysql}
+Requires: mysql >= 3.23
+Requires: mysql-server >= 3.23
+%endif
 
 %if %{mysql}
-%description mysql-%{rh_version}
+%description mysql
 %else
-%description sqlite-%{rh_version}
+%description sqlite
 %endif
 
 Bacula - It comes by night and sucks the vital essence from your computers.
@@ -97,10 +133,22 @@ This build requires MySQL to be installed separately as the catalog database.
 This build incorporates sqlite as the catalog database, statically compiled.
 %endif
 
-%package client-%{rh_version}
+%package client
 Summary: Bacula - The Network Backup Solution
 Group: System Environment/Daemons
-%description client-%{rh_version}
+Provides: bacula-fd
+Requires: readline, perl, libstdc++, zlib
+%if %{rh7}
+Requires: gtk+ >= 1.2
+Requires: gnome-libs >= 1.4
+Requires: glibc >= 2.2
+%else
+Requires: gtk2 >= 2.0
+Requires: libgnomeui >= 2.0
+Requires: glibc >= 2.3
+%endif
+
+%description client
 Bacula - It comes by night and sucks the vital essence from your computers.
 
 Bacula is a set of computer programs that permit you (or the system 
@@ -113,10 +161,35 @@ Bacula source code has been released under the GPL version 2 license.
 
 This is the File daemon (Client) only package.
 
+%package rescue
+
+Summary: Bacula - The Network Backup Solution
+Group: System Environment/Daemons
+Requires: coreutils, util-linux, libc5, bacula-fd
+
+%description rescue
+Bacula - It comes by night and sucks the vital essence from your computers.
+
+Bacula is a set of computer programs that permit you (or the system 
+administrator) to manage backup, recovery, and verification of computer 
+data across a network of computers of different kinds. In technical terms, 
+it is a network client/server based backup program. Bacula is relatively 
+easy to use and efficient, while offering many advanced storage management 
+features that make it easy to find and recover lost or damaged files. 
+Bacula source code has been released under the GPL version 2 license.
+
+This package installs scripts for disaster recovery and builds rescue 
+floppy disks for bare metal recovery. This package includes tomsrtbt
+(http://www.toms.net/rb/, by Tom Oehser, Tom@Toms.NET) to provide a tool
+to build a boot floppy disk.
+
+You need to have the bacula-sqlite, bacula-mysql or bacula-client package for 
+your platform installed and configured before installing this package.
 
 %prep
 
-%setup
+%setup -b 1
+%setup -b 2
 
 %build
 
@@ -131,6 +204,12 @@ cd ${cwd}
 # patch the make_sqlite_tables script for installation bindir
 patch src/cats/make_sqlite_tables.in src/cats/make_sqlite_tables.in.patch
 
+# patch the create_sqlite_database script for installation bindir
+patch src/cats/create_sqlite_database.in src/cats/create_sqlite_database.in.patch
+
+# patch the make_catalog_backup script for installation bindir
+patch src/cats/make_catalog_backup.in src/cats/make_catalog_backup.in.patch
+
 %configure \
         --prefix=/usr \
         --sbindir=/usr/sbin \
@@ -138,6 +217,7 @@ patch src/cats/make_sqlite_tables.in src/cats/make_sqlite_tables.in.patch
         --with-scriptdir=/etc/bacula \
         --enable-smartalloc \
         --enable-gnome \
+          --enable-static-fd \
 %if %{mysql}
         --with-mysql \
 %else
@@ -148,6 +228,10 @@ patch src/cats/make_sqlite_tables.in src/cats/make_sqlite_tables.in.patch
         --with-subsys-dir=/var/lock/subsys
 make
 
+cd src/filed
+strip static-bacula-fd
+cd ../../
+
 %install
  
 cwd=${PWD}
@@ -156,6 +240,8 @@ mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
 mkdir -p $RPM_BUILD_ROOT/usr/share/pixmaps
 mkdir -p $RPM_BUILD_ROOT/usr/share/gnome/apps/System
 mkdir -p $RPM_BUILD_ROOT/usr/share/applications
+mkdir -p $RPM_BUILD_ROOT/etc/bacula/rescue
+mkdir -p $RPM_BUILD_ROOT/etc/bacula/rescue/tomsrtbt
 
 %if ! %{mysql}
 mkdir -p $RPM_BUILD_ROOT/usr/lib/sqlite
@@ -206,12 +292,30 @@ cp ../depkgs/sqlite/libsqlite.a $RPM_BUILD_ROOT/usr/lib/sqlite/libsqlite.a
 # install the logrotate file
 cp scripts/logrotate $RPM_BUILD_ROOT/etc/logrotate.d/bacula
 
+# install the rescue stuff
+# these are the rescue scripts
+cp rescue/linux/backup.etc.list $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/format_floppy $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/getdiskinfo $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/make_rescue_disk $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/restore_bacula $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/restore_etc $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/run_grub $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/run_lilo $RPM_BUILD_ROOT/etc/bacula/rescue/
+cp rescue/linux/sfdisk.bz2 $RPM_BUILD_ROOT/etc/bacula/rescue/
+
+# this is the static file daemon
+cp src/filed/static-bacula-fd $RPM_BUILD_ROOT/etc/bacula/rescue/bacula-fd
+
+# this is the tom's root boot disk
+cp ../%{tomsrtbt}/* $RPM_BUILD_ROOT/etc/bacula/rescue/tomsrtbt/
+
 %clean
 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
 
 %if %{mysql}
 
-%files mysql-%{rh_version}
+%files mysql
 %defattr(-,root,root)
 
 %attr(0754,root,root) /etc/bacula/bacula
@@ -250,7 +354,7 @@ cp scripts/logrotate $RPM_BUILD_ROOT/etc/logrotate.d/bacula
 
 %attr(0750,root,root) /usr/sbin/*
 
-%post mysql-%{rh_version}
+%post mysql
 # delete then add our links
 /sbin/chkconfig --del bacula-dir
 /sbin/chkconfig --del bacula-fd
@@ -271,7 +375,7 @@ echo "Creating MySQL bacula database..."
 echo "Creating bacula tables..."
 /etc/bacula/make_mysql_tables
 
-%preun mysql-%{rh_version}
+%preun mysql
 # delete our links
 /sbin/chkconfig --del bacula-dir
 /sbin/chkconfig --del bacula-fd
@@ -279,7 +383,7 @@ echo "Creating bacula tables..."
 
 %else
 
-%files sqlite-%{rh_version}
+%files sqlite
 %defattr(-,root,root)
 
 %attr(0754,root,root) /etc/bacula/bacula
@@ -318,7 +422,7 @@ echo "Creating bacula tables..."
 %attr(0750,root,root) /usr/sbin/*
 %attr(0750,root,root) /usr/lib/sqlite/sqlite
 
-%post sqlite-%{rh_version}
+%post sqlite
 # delete then add our links
 /sbin/chkconfig --del bacula-dir
 /sbin/chkconfig --del bacula-fd
@@ -330,10 +434,13 @@ echo "Creating bacula tables..."
 # add execute permission for console
 chmod 0755 /usr/sbin/gnome-console
 
-# create the tables
+# create the database and tables
+echo "Creating SQLite database..."
+/etc/bacula/create_sqlite_database
+echo "Creating the SQLite tables..."
 /etc/bacula/make_sqlite_tables
 
-%preun sqlite-%{rh_version}
+%preun sqlite
 # delete our links
 /sbin/chkconfig --del bacula-dir
 /sbin/chkconfig --del bacula-fd
@@ -341,7 +448,7 @@ chmod 0755 /usr/sbin/gnome-console
 
 %endif
 
-%files client-%{rh_version}
+%files client
 %defattr(-,root,root)
 
 %attr(0754,root,root) /etc/bacula/fd
@@ -359,16 +466,86 @@ chmod 0755 /usr/sbin/gnome-console
 %attr(0750,root,root) /usr/sbin/smtp
 
 
-%post client-%{rh_version}
+%post client
 # delete then add our links
 /sbin/chkconfig --del bacula-fd
 /sbin/chkconfig --add bacula-fd
 
-%preun client-%{rh_version}
+%preun client
 # delete our links
 /sbin/chkconfig --del bacula-fd
 
+%files rescue
+%defattr(-,root,root)
+%attr(0644,root,root) /etc/bacula/rescue/backup.etc.list
+%attr(0754,root,root) /etc/bacula/rescue/format_floppy
+%attr(0754,root,root) /etc/bacula/rescue/getdiskinfo
+%attr(0754,root,root) /etc/bacula/rescue/make_rescue_disk
+%attr(0754,root,root) /etc/bacula/rescue/restore_bacula
+%attr(0754,root,root) /etc/bacula/rescue/restore_etc
+%attr(0754,root,root) /etc/bacula/rescue/run_grub
+%attr(0754,root,root) /etc/bacula/rescue/run_lilo
+%attr(0644,root,root) /etc/bacula/rescue/sfdisk.bz2
+%attr(0754,root,root) /etc/bacula/rescue/bacula-fd
+/etc/bacula/rescue/tomsrtbt/*
+
+%post rescue
+# link our current installed conf file to the rescue directory
+ln -s /etc/bacula-fd.conf /etc/bacula/rescue/bacula-fd.conf
+
+echo
+echo "Ready to create the rescue files for this system."
+echo "Press <enter> to continue..."
+read A
+echo
+
+# run getdiskinfo
+echo "Running getdiskinfo..."
+cd /etc/bacula/rescue
+./getdiskinfo
+
+echo
+echo "Finished."
+echo "To create a boot disk run \"./install.s\" from the /etc/bacula/rescue/tomsrtbt/"
+echo "directory. To make the bacula rescue disk run"
+echo "\"./make_rescue_disk --copy-static-bacula --copy-etc-files\" "
+echo "from the /etc/bacula/rescue directory. To recreate the rescue"
+echo "information for this system run ./getdiskinfo again."
+echo
+
+%preun rescue
+# remove the files created after the initial rpm installation
+rm -f /etc/bacula/rescue/bacula-fd.conf
+rm -f /etc/bacula/rescue/partition.*
+rm -f /etc/bacula/rescue/format.*
+rm -f /etc/bacula/rescue/mount_drives
+rm -f /etc/bacula/rescue/start_network
+rm -f /etc/bacula/rescue/sfdisk
+rm -rf /etc/bacula/rescue/diskinfo/*
+
 %changelog
+* Sat Jan 24 2004 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- added patch for create_sqlite_database to fix the installed bindir
+- added execute of create_sqlite_database to post of sqlite package
+* Sat Jan 10 2004 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- added virtual package Provides bacula-dir, bacula-sd, bacula-fd
+- added bacula-fd as Requires for rescue package
+- added build tag for Fedora Core 1
+- cleaned up dependancies for all builds
+* Thu Jan 1 2004 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- removed rh_version from package names
+- added platform build configuration section to beginning of file
+* Tue Nov 25 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- removed make_static_bacula script from rescue package install
+* Sun Nov 23 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- Added define at top of file for depkgs version
+- Added rescue sub-package
+- Moved requires statements into proper sub-package locations
+* Mon Oct 27 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- Corrected Requires for Gnome 1.4/2.0 builds
+* Fri Oct 24 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
+- Added separate Source declaration for depkgs
+- added patch for make_catalog_backup script
 * Mon May 11 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
 - Misc changes to mysql/sqlite build and rh7/8 menu differences
 - Added rh_version to sub-package names
index 7cf9123a32bb1650d031644aac6fad41675b91a6..8d39622226adea5505452eefece36f9b56fb4ba7 100644 (file)
@@ -4,6 +4,9 @@
 #
 #  15 November 2001 -- Kern Sibbald
 #
+#  03 November 2003 corrections to the paths made by
+#      Kenneth ragnor at virtualsd dot net
+#
 #  for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
 #
 
@@ -32,7 +35,7 @@ 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
+       @$(INSTALL_PROGRAM) -m 744 bacula-sd /etc/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
@@ -43,7 +46,7 @@ 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
+       @$(INSTALL_PROGRAM) -m 744 bacula-dir /etc/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
@@ -58,20 +61,20 @@ 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
+       @rm -f /etc/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
+       @rm -f /etc/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
+       @rm -f /etc/init.d/bacula-dir
 
 clean:
        @rm -f bacula-sd bacula-fd bacula-dir
diff --git a/bacula/platforms/suse/Makefile.in b/bacula/platforms/suse/Makefile.in
new file mode 100644 (file)
index 0000000..a2dcad9
--- /dev/null
@@ -0,0 +1,81 @@
+# 
+# This file is used as the template to create the
+# Makefile for the SuSe specific installation.
+#
+#
+#  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 x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-fd; then \
+          /sbin/chkconfig --del bacula-fd; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-fd $(DESTDIR)/etc/rc.d/init.d/bacula-fd
+       # set symlinks for script at startup and shutdown
+       @if test x$(DESTDIR) = x ; then \
+          /sbin/chkconfig --add bacula-fd; \
+       fi
+
+
+install-autostart-sd:
+       @if test x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-sd; then \
+           /sbin/chkconfig --del bacula-sd; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-sd  $(DESTDIR)/etc/rc.d/init.d/bacula-sd
+       # set symlinks for script at startup and shutdown
+       @if test x$(DESTDIR) = x ; then \
+          /sbin/chkconfig --add bacula-sd; \
+       fi
+
+
+install-autostart-dir:
+       @if test x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-dir; then \
+           /sbin/chkconfig --del bacula-dir; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-dir  $(DESTDIR)/etc/rc.d/init.d/bacula-dir
+       # set symlinks for script at startup and shutdown
+       @if test x$(DESTDIR) = x ; then \
+          /sbin/chkconfig --add bacula-dir; \
+       fi
+
+
+uninstall: uninstall-autostart
+
+uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir
+
+uninstall-autostart-fd:
+       @if test x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-fd; then \
+           /sbin/chkconfig --del bacula-fd; \
+       fi
+       @rm -f  $(DESTDIR)/etc/rc.d/init.d/bacula-fd
+
+
+uninstall-autostart-sd:
+       @if test x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-sd; then \
+           /sbin/chkconfig --del bacula-sd; \
+       fi
+       @rm -f  $(DESTDIR)/etc/rc.d/init.d/bacula-sd
+
+uninstall-autostart-dir:
+       @if test x$(DESTDIR) = x -a  -f /etc/rc.d/init.d/bacula-dir; then \
+           /sbin/chkconfig --del bacula-dir; \
+       fi
+       @rm -f  $(DESTDIR)/etc/rc.d/init.d/bacula-dir
+
+clean:
+       @rm -f 1 2 3
+
+distclean: clean
+       @rm -f Makefile bacula-*.spec bacula.*.spec bacula.spec
+       @rm -f bacula-sd bacula-fd bacula-dir
+       @rm -rf CVS
diff --git a/bacula/platforms/suse/bacula-dir.in b/bacula/platforms/suse/bacula-dir.in
new file mode 100755 (executable)
index 0000000..05fec1b
--- /dev/null
@@ -0,0 +1,44 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Director daemon
+#
+# chkconfig: 2345 90 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+# Source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+case "$1" in
+    start)
+       echo -n "Starting the Bacula Director: "
+       daemon @sbindir@/bacula-dir $2 -c @sysconfdir@/bacula-dir.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-dir
+       ;;
+    stop)
+       echo -n "Stopping the Director daemon: "
+       killproc @sbindir@/bacula-dir
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-dir
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    status)
+       status @sbindir@/bacula-dir
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/suse/bacula-fd.in b/bacula/platforms/suse/bacula-fd.in
new file mode 100755 (executable)
index 0000000..8b725bc
--- /dev/null
@@ -0,0 +1,43 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula File daemon.
+#
+# chkconfig: 2345 90 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+# Source function library
+. /etc/rc.d/init.d/functions
+
+case "$1" in
+    start)
+       echo -n "Starting the Bacula File daemon: "
+       daemon @sbindir@/bacula-fd $2 -c @sysconfdir@/bacula-fd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-fd
+       ;;
+    stop)
+       echo -n "Stopping the Bacula File daemon: "
+       killproc @sbindir@/bacula-fd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-fd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    status)
+       status @sbindir@/bacula-fd
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/suse/bacula-sd.in b/bacula/platforms/suse/bacula-sd.in
new file mode 100755 (executable)
index 0000000..e582876
--- /dev/null
@@ -0,0 +1,43 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Storage daemon.
+#
+# chkconfig: 2345 90 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
index f530ba66a376804064e08d6688111b240ddbeb85..1fbd1a98eef87a7f0033588034b5b18f75320bc2 100755 (executable)
 
 PSCMD="@PSCMD@"
 
+BACBIN=@sbindir@
+BACCFG=@sysconfdir@
+PIDDIR=@piddir@
+SUBSYSDIR=@subsysdir@
+
+DIR_PORT=9101
+FD_PORT=9102
+SD_PORT=9103
+
+DIR_USER=@dir_user@
+DIR_GROUP=@dir_group@
+FD_USER=@fd_user@
+FD_GROUP=@fd_group@
+SD_USER=@sd_user@
+SD_GROUP=@sd_group@
+
 # A function to stop a program.
 killproc() {
     RC=0
@@ -69,7 +85,7 @@ killproc() {
     fi
     # Remove pid file if any.
     if [ "$notset" = "1" ]; then
-       rm -f @piddir@/$base.$2.pid
+       rm -f ${PIDDIR}/$base.$2.pid
     fi
     return $RC
 }
@@ -87,8 +103,8 @@ pidofproc() {
     base=`basename $1`
 
     # First try PID file
-    if [ -f @piddir@/$base.$2.pid ] ; then
-       pid=`head -1 @piddir@/$base.$2.pid`
+    if [ -f ${PIDDIR}/$base.$2.pid ] ; then
+       pid=`head -1 ${PIDDIR}/$base.$2.pid`
        if [ "$pid" != "" ] ; then
            echo $pid
            return 0
@@ -138,15 +154,15 @@ status() {
    fi
 
     # Next try the PID files
-    if [ -f @piddir@/$base.$2.pid ] ; then
-       pid=`head -1 @piddir@/$base.$2.pid`
+    if [ -f ${PIDDIR}/$base.$2.pid ] ; then
+       pid=`head -1 ${PIDDIR}/$base.$2.pid`
        if [ "$pid" != "" ] ; then
            echo "$base dead but pid file exists"
            return 1
        fi
     fi
     # See if the subsys lock exists
-    if [ -f @subsysdir@/$base ] ; then
+    if [ -f ${SUBSYSDIR}/$base ] ; then
        echo "$base dead but subsys locked"
        return 2
     fi
@@ -165,33 +181,81 @@ failure() {
 
 case "$1" in
     start)
-       echo "Starting the Storage daemon"
-       @sbindir@/bacula-sd $2 -v -c @sysconfdir@/bacula-sd.conf
-       echo "Starting the File daemon"
-       @sbindir@/bacula-fd $2 -v -c @sysconfdir@/bacula-fd.conf
-       sleep 2
-       echo "Starting the Director daemon"
-       @sbindir@/bacula-dir $2 -v -c @sysconfdir@/bacula-dir.conf
+       [ -x ${BACBIN}/bacula-sd ] && {
+         echo "Starting the Storage daemon"
+         OPTIONS=''
+         if [ "${SD_USER}" != '' ]; then
+            OPTIONS="${OPTIONS} -u ${SD_USER}"
+         fi
+
+         if [ "${SD_GROUP}" != '' ]; then
+            OPTIONS="${OPTIONS} -g ${SD_GROUP}"
+         fi
+
+         ${BACBIN}/bacula-sd $2 ${OPTIONS} -v -c ${BACCFG}/bacula-sd.conf
+       }
+
+       [ -x ${BACBIN}/bacula-fd ] && {
+         echo "Starting the File daemon"
+         OPTIONS=''
+         if [ "${FD_USER}" != '' ]; then
+            OPTIONS="${OPTIONS} -u ${FD_USER}"
+         fi
+
+         if [ "${FD_GROUP}" != '' ]; then
+            OPTIONS="${OPTIONS} -g ${FD_GROUP}"
+         fi
+
+         ${BACBIN}/bacula-fd $2 ${OPTIONS} -v -c ${BACCFG}/bacula-fd.conf
+       }
+
+       [ -x ${BACBIN}/bacula-dir ] && { 
+          sleep 2
+          echo "Starting the Director daemon"
+         OPTIONS=''
+         if [ "${DIR_USER}" != '' ]; then
+            OPTIONS="${OPTIONS} -u ${DIR_USER}"
+         fi
+
+         if [ "${DIR_GROUP}" != '' ]; then
+            OPTIONS="${OPTIONS} -g ${DIR_GROUP}"
+         fi
+
+         ${BACBIN}/bacula-dir $2 ${OPTIONS} -v -c ${BACCFG}/bacula-dir.conf
+       }
        ;;
+
     stop)
-       echo "Stopping the File daemon"
-       killproc @sbindir@/bacula-fd @fd_port@
-       echo "Stopping the Storage daemon"
-       killproc @sbindir@/bacula-sd @sd_port@
-       echo "Stopping the Director daemon"
-       killproc @sbindir@/bacula-dir @dir_port@
+       # Stop the FD first so that SD will fail jobs and update catalog
+       [ -x ${BACBIN}/bacula-fd ] && {
+         echo "Stopping the File daemon"
+         killproc ${BACBIN}/bacula-fd ${FD_PORT}
+       }
+
+       [ -x ${BACBIN}/bacula-sd ] && {
+         echo "Stopping the Storage daemon"
+         killproc ${BACBIN}/bacula-sd ${SD_PORT}
+       }
+
+       [ -x ${BACBIN}/bacula-dir ] && {
+         echo "Stopping the Director daemon"
+         killproc ${BACBIN}/bacula-dir ${DIR_PORT}
+       }
        echo
        ;;
+
     restart)
        $0 stop
        sleep 5
        $0 start
        ;;
+
     status)
-       status @sbindir@/bacula-sd @sd_port@
-       status @sbindir@/bacula-fd @fd_port@
-       status @sbindir@/bacula-dir @dir_port@
+       [ -x ${BACBIN}/bacula-sd  ] && status ${BACBIN}/bacula-sd  ${SD_PORT}
+       [ -x ${BACBIN}/bacula-fd  ] && status ${BACBIN}/bacula-fd  ${FD_PORT}
+       [ -x ${BACBIN}/bacula-dir ] && status ${BACBIN}/bacula-dir ${DIR_PORT}
        ;;
+
     *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
diff --git a/bacula/scripts/set-gnome1.4 b/bacula/scripts/set-gnome1.4
new file mode 100755 (executable)
index 0000000..d76e5a2
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# Simple script to change the package configuration to 
+#   Gnome 1.4 level.
+#
+MUID=`/usr/bin/id -u`
+if [ $MUID != 0 ] ; then
+   echo " "
+   echo "You must be root to run this script."
+   echo " "
+   exit 1
+fi
+cd /usr/lib/pkgconfig
+if test  -f libgnomeui-2.0.pc.orig ; then
+   rm -f libgnomeui-2.0.pc
+else
+   mv libgnomeui-2.0.pc libgnomeui-2.0.pc.orig
+fi
diff --git a/bacula/scripts/set-gnome2 b/bacula/scripts/set-gnome2
new file mode 100755 (executable)
index 0000000..414499d
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# Simple script to set the Gnome package level
+#   to Gnome 2.0
+#
+MUID=`/usr/bin/id -u`
+if [ $MUID != 0 ] ; then
+   echo " "
+   echo "You must be root to run this script."
+   echo " "
+   exit 1
+fi
+cd /usr/lib/pkgconfig
+if test -f libgnomeui-2.0.pc.orig ; then
+   cp -fp libgnomeui-2.0.pc.orig libgnomeui-2.0.pc
+fi
index 018076a9bea1ee4bca9813f885762ef6c1221013..a9c61f762d0a9e958a41436a5b89b36b88fe9448 100644 (file)
@@ -5,3 +5,4 @@ Makefile
 config.h
 testprogs
 host.h
+perlgui
index 1f32ee5812781a17ad744858f42a1e2e5d3bacd5..8b67e61486fb7dd16e7fcd2eedceb01c43edf7be 100644 (file)
@@ -40,6 +40,8 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
 
 clean:
        @$(RMF) core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+       (cd gnome-console; $(MAKE) clean)
+       (cd gnome2-console; $(MAKE) clean)
 
 realclean: clean
        @$(RMF) tags
index 123f0128efc49300669d5fa3db2bec3d00f4cfb5..b9c6cd9719aa991451e76117d4f956ca2cb13ca0 100644 (file)
@@ -434,7 +434,7 @@ extern int thr_setconcurrency(int);
 
 #ifdef HAVE_DARWIN_OS
 /* Apparently someone forgot to wrap getdomainname as a C function */
-extern "C" int getdomainname(char *name, size_t len);
+extern "C" int getdomainname(char *name, int len);
 
 /* Darwin lib fnmatch() doesn't work, so use our own */
 #undef HAVE_FNMATCH
index a8a4a4bed0b4c25aa28c1e798d154a13e99bd845..a27c3270dfee06b1f0f03341a6ae50ad320caf44 100644 (file)
@@ -181,7 +181,7 @@ typedef float             float32_t;
 #define uintmax_t u_intmax_t
 
 /* Bacula time -- Unix time with microseconds */
-#define btime_t uint64_t
+#define btime_t int64_t
 /* Unix time (time_t) widened to 64 bits */
 #define utime_t int64_t
 
index e4ee4d48afc21b52d091c5b1fd655b0bf478d3fe..a50533f63564f72f12a1c874983088f4cb04deda 100644 (file)
@@ -65,7 +65,9 @@ realclean: clean
        $(RMF) create_bdb_database drop_bdb_tables make_dbd_tables
        $(RMF) make_catalog_backup delete_catalog_backup
        $(RMF) alter_mysql_tables alter_sqlite_tables create_sqlite_database
+       $(RMF) update_mysql_tables update_sqlite_tables 
        $(RMF) drop_bacula_tables drop_sqlite_tables make_bacula_tables
+       $(RMF) update_bacula_tables
        $(RMF) drop_bdb_tables make_bdb_tables mysql
 
 distclean: realclean
index 852694647433da4b411bd2f684892caacceab741..c184ec45c3718ab144cf9217e7299abf62d2418b 100644 (file)
@@ -141,10 +141,13 @@ StartTime=%100s", &JobId, Name, cType, cLevel, StartTime) == 5) {
  *
  * Find a Volume for a given PoolId, MediaType, and VolStatus
  *
+ *   Note! this does not correctly implement InChanger.          
+ *
  * Returns: 0 on failure
  *         numrows on success
- */
-int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
+ */    
+int
+db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr) 
 {
    MEDIA_DBR omr;
    int stat = 0;
@@ -176,7 +179,9 @@ int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
    return stat;                
 }
 
-int db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { return 0; }
+int
+db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr)
+{ return 0; }
 
 
 #endif /* HAVE_BACULA_DB */
index e152c227ba3416c0ff016666a6ae60fe8cac2aea..cbabc7a3aa66f2b7f1fc5cfe104e55c831c1a929 100644 (file)
@@ -492,7 +492,7 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
 
 
 
-int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fdbr) 
+int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
 { return 0; }
 
 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, uint32_t JobId, VOL_PARAMS **VolParams)
index f4746db3c8c4da074dffd8fde03ebddb1842d244..2cacbcdaa462a7e66631807fe2171fb31cc4e3da 100644 (file)
@@ -57,70 +57,70 @@ struct sqlite {
    char dummy;
 };
 
-#define IS_NUM(x)            ((x) == 1)
-#define IS_NOT_NULL(x)       ((x) == 1)
+#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 */
+   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
+ *                    S Q L I T E
  */
 typedef struct s_db {
-   BQUEUE bq;                        /* queue control */
-   brwlock_t lock;                   /* transaction lock */
+   BQUEUE bq;                         /* queue control */
+   brwlock_t lock;                    /* transaction lock */
    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 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_address;                 /* host name address */
-   char *db_socket;                  /* socket for local access */
+   char *db_address;                  /* host name address */
+   char *db_socket;                   /* socket for local access */
    char *db_password;
-   int db_port;                      /* port for host name address */
+   int  db_port;                      /* port for host name address */
    int connected;
-   char *sqlite_errmsg;              /* error message returned by sqlite */
-   POOLMEM *errmsg;                  /* nicely edited error message */
-   POOLMEM *cmd;                     /* SQL command string */
-   POOLMEM *cached_path;             /* cached path name */
-   int cached_path_len;              /* length of cached path */
-   uint32_t cached_path_id;          /* cached path id */
-   int transaction;                  /* transaction started */
-   int changes;                      /* changes during transaction */
-   POOLMEM *fname;                   /* Filename only */
-   POOLMEM *path;                    /* Path only */
-   POOLMEM *esc_name;                /* Escaped file/path name */
-   int fnl;                          /* file name length */
-   int pnl;                          /* path name length */
+   char *sqlite_errmsg;               /* error message returned by sqlite */
+   POOLMEM *errmsg;                   /* nicely edited error message */
+   POOLMEM *cmd;                      /* SQL command string */
+   POOLMEM *cached_path;              /* cached path name */
+   int cached_path_len;               /* length of cached path */
+   uint32_t cached_path_id;           /* cached path id */
+   int transaction;                   /* transaction started */
+   int changes;                       /* changes during transaction */
+   POOLMEM *fname;                    /* Filename only */
+   POOLMEM *path;                     /* Path only */
+   POOLMEM *esc_name;                 /* Escaped file/path name */
+   int fnl;                           /* file name length */
+   int pnl;                           /* path name length */
 } B_DB;
 
 
 /* 
  * "Generic" names for easier conversion   
  *
- *                   S Q L I T E
+ *                    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_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
@@ -129,7 +129,7 @@ typedef struct s_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**   
+#define SQL_ROW               char**   
 
 
 
@@ -151,11 +151,11 @@ extern void my_sqlite_free_table(B_DB *mdb);
  * used inside sql.c and associated database interface
  * subroutines.
  *
- *                    M Y S Q L
+ *                     M Y S Q L
  */
 typedef struct s_db {
-   BQUEUE bq;                        /* queue control */
-   brwlock_t lock;                   /* transaction lock */
+   BQUEUE bq;                         /* queue control */
+   brwlock_t lock;                    /* transaction lock */
    MYSQL mysql;
    MYSQL *db;
    MYSQL_RES *result;
@@ -164,22 +164,22 @@ typedef struct s_db {
    char *db_name;
    char *db_user;
    char *db_password;
-   char *db_address;                 /* host address */
-   char *db_socket;                  /* socket for local access */
-   int db_port;                      /* port of host address */
-   int have_insert_id;               /* do have insert_id() */
+   char *db_address;                  /* host address */
+   char *db_socket;                   /* socket for local access */
+   int db_port;                       /* port of host address */
+   int have_insert_id;                /* do have insert_id() */
    int connected;
-   POOLMEM *errmsg;                  /* nicely edited error message */
-   POOLMEM *cmd;                     /* SQL command string */
+   POOLMEM *errmsg;                   /* nicely edited error message */
+   POOLMEM *cmd;                      /* SQL command string */
    POOLMEM *cached_path;
-   int cached_path_len;              /* length of cached path */
+   int cached_path_len;               /* length of cached path */
    uint32_t cached_path_id;
-   int changes;                      /* changes made to db */
-   POOLMEM *fname;                   /* Filename only */
-   POOLMEM *path;                    /* Path only */
-   POOLMEM *esc_name;                /* Escaped file/path name */
-   int fnl;                          /* file name length */
-   int pnl;                          /* path name length */
+   int changes;                       /* changes made to db */
+   POOLMEM *fname;                    /* Filename only */
+   POOLMEM *path;                     /* Path only */
+   POOLMEM *esc_name;                 /* Escaped file/path name */
+   int fnl;                           /* file name length */
+   int pnl;                           /* path name length */
 } B_DB;
 
 
@@ -188,7 +188,7 @@ typedef struct s_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_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)
@@ -197,8 +197,8 @@ typedef struct s_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
+#define SQL_ROW               MYSQL_ROW
+#define SQL_FIELD             MYSQL_FIELD
 
 #else  /* USE BACULA DB routines */
 
@@ -207,17 +207,17 @@ typedef struct s_db {
 /* Change this each time there is some incompatible
  * file format change!!!!
  */
-#define BDB_VERSION 12               /* file version number */
+#define BDB_VERSION 12                /* 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 */
+   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 */
 };
 
 
@@ -225,23 +225,23 @@ struct s_control {
  *  Bacula internal DB
  */
 typedef struct s_db {
-   BQUEUE bq;                        /* queue control */
-/* pthread_mutex_t mutex;  */        /* single thread lock */
-   brwlock_t lock;                   /* transaction 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 */
-   POOLMEM *errmsg;                  /* nicely edited error message */
-   POOLMEM *cmd;                     /* Command string */
+   BQUEUE bq;                         /* queue control */
+/* pthread_mutex_t mutex;  */         /* single thread lock */
+   brwlock_t lock;                    /* transaction 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 */
+   POOLMEM *errmsg;                   /* nicely edited error message */
+   POOLMEM *cmd;                      /* Command string */
    POOLMEM *cached_path;
-   int cached_path_len;              /* length of cached path */
+   int cached_path_len;               /* length of cached path */
    uint32_t cached_path_id;
 } B_DB;
 
@@ -255,12 +255,12 @@ typedef struct s_db {
 #define DELETE_DB(jcr, db, cmd) DeleteDB(__FILE__, __LINE__, jcr, db, cmd)
 
 
-#else   /* not __SQL_C */
+#else    /* not __SQL_C */
 
 /* This is a "dummy" definition for use outside of sql.c
  */
-typedef struct s_db {    
-   int dummy;                        /* for SunOS compiler */
+typedef struct s_db {     
+   int dummy;                         /* for SunOS compiler */
 } B_DB;  
 
 #endif /*  __SQL_C */
@@ -269,7 +269,7 @@ extern uint32_t bacula_db_version;
 
 /* ***FIXME*** FileId_t should be uint64_t */
 typedef uint32_t FileId_t;
-typedef uint32_t DBId_t;             /* general DB id type */
+typedef uint32_t DBId_t;              /* general DB id type */
 typedef uint32_t JobId_t;
       
 #define faddr_t long
@@ -283,18 +283,18 @@ typedef uint32_t JobId_t;
 /* Job record */
 struct JOB_DBR {
    JobId_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 */
-   utime_t JobTDate;                 /* Backup time/date in seconds */
+   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 */
+   utime_t JobTDate;                  /* Backup time/date in seconds */
    uint32_t VolSessionId;
    uint32_t VolSessionTime;
    uint32_t JobFiles;
@@ -305,8 +305,8 @@ struct JOB_DBR {
    /* 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 FirstIndex;               /* First index this Volume */
+   uint32_t LastIndex;                /* Last index this Volume */
    uint32_t StartFile;
    uint32_t EndFile;
    uint32_t StartBlock;
@@ -324,28 +324,28 @@ struct JOB_DBR {
  */
 /* JobMedia record */
 struct JOBMEDIA_DBR {
-   uint32_t JobMediaId;              /* record id */
-   JobId_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 */
+   uint32_t JobMediaId;               /* record id */
+   JobId_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 */
 };
 
 
 /* Volume Parameter structure */
 struct VOL_PARAMS {
    char VolumeName[MAX_NAME_LENGTH];  /* Volume name */
-   uint32_t VolIndex;                /* Volume seqence no. */ 
-   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 */
+   uint32_t VolIndex;                 /* Volume seqence no. */ 
+   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 */
 };
 
 
@@ -354,9 +354,9 @@ struct VOL_PARAMS {
  *  records (e.g. pathname, filename, fileattributes).
  */
 struct ATTR_DBR {
-   char *fname;                      /* full path & filename */
-   char *link;                       /* link if any */
-   char *attr;                       /* attributes statp */
+   char *fname;                       /* full path & filename */
+   char *link;                        /* link if any */
+   char *attr;                        /* attributes statp */
    uint32_t FileIndex;
    uint32_t Stream;
    JobId_t  JobId;
@@ -378,26 +378,26 @@ struct FILE_DBR {
    char LStat[256];
 /*   int Status; */
    char SIG[50];
-   int SigType;                      /* NO_SIG/MD5_SIG/SHA1_SIG */
+   int SigType;                       /* NO_SIG/MD5_SIG/SHA1_SIG */
 };
 
 /* Pool record -- same format as database */
 struct POOL_DBR {
    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 */
-   int AutoPrune;                    /* set to prune automatically */
-   int Recycle;                      /* default Vol recycle flag */
-   utime_t  VolRetention;            /* retention period in seconds */
-   utime_t  VolUseDuration;          /* time in secs volume can be used */
-   uint32_t MaxVolJobs;              /* Max Jobs on Volume */
-   uint32_t MaxVolFiles;             /* Max files on Volume */
-   uint64_t MaxVolBytes;             /* Max bytes on Volume */
-   char PoolType[MAX_NAME_LENGTH];            
+   char Name[MAX_NAME_LENGTH];        /* Pool name */
+   uint32_t NumVols;                  /* total number of volumes */
+   uint32_t MaxVols;                  /* max allowed volumes */
+   int32_t UseOnce;                   /* set to use once only */
+   int32_t UseCatalog;                /* set to use catalog */
+   int32_t AcceptAnyVolume;           /* set to accept any volume sequence */
+   int32_t AutoPrune;                 /* set to prune automatically */
+   int32_t Recycle;                   /* default Vol recycle flag */
+   utime_t  VolRetention;             /* retention period in seconds */
+   utime_t  VolUseDuration;           /* time in secs volume can be used */
+   uint32_t MaxVolJobs;               /* Max Jobs on Volume */
+   uint32_t MaxVolFiles;              /* Max files on Volume */
+   uint64_t MaxVolBytes;              /* Max bytes on Volume */
+   char PoolType[MAX_NAME_LENGTH];             
    char LabelFormat[MAX_NAME_LENGTH];
    /* Extra stuff not in DB */
    faddr_t rec_addr;
@@ -405,34 +405,37 @@ struct POOL_DBR {
 
 /* Media record -- same as the database */
 struct MEDIA_DBR {
-   uint32_t MediaId;                 /* Unique volume id */
+   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 labeled */
-   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 MaxVolBytes;             /* Max bytes to write to Volume */
-   uint64_t VolCapacityBytes;        /* capacity estimate */
-   utime_t  VolRetention;            /* Volume retention in seconds */
-   utime_t  VolUseDuration;          /* time in secs volume can be used */
-   uint32_t MaxVolJobs;              /* Max Jobs on Volume */
-   uint32_t MaxVolFiles;             /* Max files on Volume */
-   int     Recycle;                  /* recycle yes/no */
-   int32_t  Slot;                    /* slot in changer */
-   char VolStatus[20];               /* Volume status */
+   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 labeled */
+   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 MaxVolBytes;              /* Max bytes to write to Volume */
+   uint64_t VolCapacityBytes;         /* capacity estimate */
+   utime_t  VolRetention;             /* Volume retention in seconds */
+   utime_t  VolUseDuration;           /* time in secs volume can be used */
+   uint32_t MaxVolJobs;               /* Max Jobs on Volume */
+   uint32_t MaxVolFiles;              /* Max files on Volume */
+   int32_t  Recycle;                  /* recycle yes/no */
+   int32_t  Slot;                     /* slot in changer */
+   int32_t  Drive;                    /* drive in changer */
+   int32_t  InChanger;                /* Volume currently in changer */
+   int32_t  MediaAddressing;          /* Type of media addressing file/tape */
+   char VolStatus[20];                /* Volume status */
    /* Extra stuff not in DB */
-   faddr_t rec_addr;                 /* found record address */
+   faddr_t rec_addr;                  /* found record address */
    /* Since the database returns times as strings, this is how we pass
-    *  them back.
+    *   them back.
     */
    char    cFirstWritten[MAX_TIME_LENGTH];  /* FirstWritten returned from DB */
    char    cLastWritten[MAX_TIME_LENGTH];  /* LastWritten returned from DB */
@@ -441,12 +444,12 @@ struct MEDIA_DBR {
 
 /* Client record -- same as the database */
 struct CLIENT_DBR {
-   uint32_t ClientId;                /* Unique Client id */
+   uint32_t ClientId;                 /* Unique Client id */
    int AutoPrune;
    utime_t FileRetention;
    utime_t JobRetention;
-   char Name[MAX_NAME_LENGTH];       /* Client name */
-   char Uname[256];                  /* Uname for client */
+   char Name[MAX_NAME_LENGTH];        /* Client name */
+   char Uname[256];                   /* Uname for client */
 };
 
 /* Counter record as in database */
@@ -461,16 +464,16 @@ struct COUNTER_DBR {
 
 /* FileSet record -- same as the database */
 struct FILESET_DBR {
-   uint32_t FileSetId;               /* Unique FileSet id */
+   uint32_t FileSetId;                /* Unique FileSet id */
    char FileSet[MAX_NAME_LENGTH];     /* FileSet name */
-   char MD5[50];                     /* MD5 signature of include/exclude */
-   time_t CreateTime;                /* date created */
+   char MD5[50];                      /* MD5 signature of include/exclude */
+   time_t CreateTime;                 /* date created */
    /*
     * This is where we return CreateTime
     */
    char cCreateTime[MAX_TIME_LENGTH]; /* CreateTime as returned from DB */
    /* Not in DB but returned by db_create_fileset() */
-   bool created;                     /* set when record newly created */
+   bool created;                      /* set when record newly created */
 };
 
 
diff --git a/bacula/src/cats/create_sqlite_database.in.patch b/bacula/src/cats/create_sqlite_database.in.patch
new file mode 100644 (file)
index 0000000..85d2dcb
--- /dev/null
@@ -0,0 +1,4 @@
+5c5
+< bindir=@SQL_BINDIR@
+---
+> bindir=/usr/lib/sqlite
index 94115576b2e12ea8f2c4c4a4f81cbc6eb8e0c4a5..fe9c774fc3b9b311e4bf21d5837fcf488ba8fd93 100755 (executable)
@@ -6,9 +6,9 @@
 cd @working_dir@
 rm -f bacula.sql
 if test xsqlite = x@DB_NAME@ ; then
-echo ".dump" | @SQL_BINDIR@/sqlite bacula.db >bacula.sql
+  echo ".dump" | @SQL_BINDIR@/sqlite bacula.db >bacula.sql
 else
-@SQL_BINDIR@/mysqldump $* -f --opt bacula >bacula.sql
+  @SQL_BINDIR@/mysqldump $* -f --opt bacula >bacula.sql
 fi
 #
 #  To read back a MySQL database use: 
diff --git a/bacula/src/cats/make_catalog_backup.in.patch b/bacula/src/cats/make_catalog_backup.in.patch
new file mode 100644 (file)
index 0000000..14d3adc
--- /dev/null
@@ -0,0 +1,16 @@
+9c9
+<   echo ".dump" | @SQL_BINDIR@/sqlite bacula.db >bacula.sql
+---
+>   echo ".dump" | /usr/lib/sqlite/sqlite bacula.db >bacula.sql
+11c11
+<   @SQL_BINDIR@/mysqldump $* -f --opt bacula >bacula.sql
+---
+>   /usr/bin/mysqldump $* -f --opt bacula >bacula.sql
+16c16
+< #     rm -f @SQL_BINDIR@/../var/bacula/*
+---
+> #     rm -f /var/lib/mysql/bacula/*
+22c22
+< #     sqlite bacula.db <bacula.sql
+---
+> #     /usr/lib/sqlite/sqlite bacula.db <bacula.sql
index 1ce0d6aadcab7d5c15fdce62bb6a4701ab40647a..d84dad313f77c276a4a4e4ef2ae4f16526c1ab0a 100644 (file)
@@ -105,7 +105,6 @@ CREATE TABLE Media (
    VolBytes BIGINT UNSIGNED NOT NULL,
    VolErrors INTEGER UNSIGNED NOT NULL,
    VolWrites INTEGER UNSIGNED NOT NULL,
-   MaxVolBytes BIGINT UNSIGNED NOT NULL,
    VolCapacityBytes BIGINT UNSIGNED NOT NULL,
    VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Purged',
     'Read-Only', 'Disabled', 'Error', 'Busy', 'Used', 'Cleaning') NOT NULL,
@@ -114,6 +113,7 @@ CREATE TABLE Media (
    VolUseDuration BIGINT UNSIGNED NOT NULL,
    MaxVolJobs INTEGER UNSIGNED NOT NULL,
    MaxVolFiles INTEGER UNSIGNED NOT NULL,
+   MaxVolBytes BIGINT UNSIGNED NOT NULL,
    PRIMARY KEY(MediaId),
    INDEX (PoolId)
    );
index 3b474819b01bbaa64d42cea38fb1b209c09855d1..719aab5cd8db50da25287b4ff8fc3d15c673d2ac 100644 (file)
@@ -176,7 +176,9 @@ It is probably not running or your password is incorrect.\n"),
       return 0;
    }
 
+#ifdef HAVE_TREAD_SAFE_MYSQL
    my_thread_init();
+#endif
 
    mdb->connected = TRUE;
    V(mutex);
@@ -188,7 +190,9 @@ db_close_database(JCR *jcr, B_DB *mdb)
 {
    P(mutex);
    mdb->ref_count--;
+#ifdef HAVE_TREAD_SAFE_MYSQL
    my_thread_end();
+#endif
    if (mdb->ref_count == 0) {
       qdchain(&mdb->bq);
       if (mdb->connected && mdb->db) {
index 6ce3efee0c588981be381fd0f4ca8390277e5466..ab233e474a7f4f8556af7ba2f65c71374635a086 100644 (file)
@@ -61,7 +61,7 @@ int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
 
 /* find.c */
 int db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
-int db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
+int db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr);
 int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, MEDIA_DBR *mr);
 
 /* get.c */
@@ -69,7 +69,7 @@ int db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr);
 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr);
 int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr);
 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **VolumeNames);
-int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fdbr);
+int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr);
 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr);
 int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
 int db_get_num_media_records(JCR *jcr, B_DB *mdb);
index 45de5dc65cd995d97ed756c9bc940b526db7dd2d..5a0790804eac4300af2942b081d00a9ee4a4e011 100644 (file)
@@ -153,7 +153,7 @@ static int delete_handler(void *ctx, int num_fields, char **row)
  */
 static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
 {
-   char *query = (char *)get_pool_memory(PM_MESSAGE);
+   POOLMEM *query = get_pool_memory(PM_MESSAGE);
    struct s_del_ctx del;
    int i;
 
@@ -173,11 +173,11 @@ static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
 
    for (i=0; i < del.num_ids; i++) {
       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
-      Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM Job WHERE JobId=%u", del.JobId[i]);
       db_sql_query(mdb, query, NULL, (void *)NULL);
-      Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM File WHERE JobId=%u", del.JobId[i]);
       db_sql_query(mdb, query, NULL, (void *)NULL);
-      Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%d", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%u", del.JobId[i]);
       db_sql_query(mdb, query, NULL, (void *)NULL);
    }
    free(del.JobId);
index c0379235f8473ebeeda85bb2391deaada203f49a..815136e76e0b5a02b3c2208db93d80d203a66b4d 100644 (file)
@@ -53,8 +53,10 @@ extern void print_result(B_DB *mdb);
 extern int QueryDB(char *file, int line, JCR *jcr, B_DB *db, char *select_cmd);
 
 /*
- * Find job start time. Used to find last full save
- * for Incremental and Differential saves.
+ * Find job start time if JobId specified, otherwise
+ * find last full save for Incremental and Differential saves.
+ *
+ *  StartTime is returned in stime
  *     
  * Returns: 0 on failure
  *         1 on success, jr is unchanged, but stime is set
@@ -63,7 +65,6 @@ int
 db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
 {
    SQL_ROW row;
-   uint32_t JobId;
 
    db_lock(mdb);
 
@@ -71,26 +72,23 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
    /* 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 "
+"SELECT StartTime FROM Job WHERE JobStatus='T' AND Type='%c' AND "
 "Level='%c' AND Name='%s' AND ClientId=%u AND FileSetId=%u "
 "ORDER BY StartTime DESC LIMIT 1",
           jr->Type, L_FULL, jr->Name, jr->ClientId, jr->FileSetId);
+
+      if (jr->Level == L_DIFFERENTIAL) {
+        /* SQL cmd for Differential backup already edited above */
+
       /* 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 IN ('%c','%c','%c') AND Name='%s' AND ClientId=%u "
-"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);
-        db_unlock(mdb);
-        return 0;
-      }
-      Dmsg1(100, "Submitting: %s\n", mdb->cmd);
+        /* 
+         * For an Incremental job, we must first ensure
+         *  that a Full backup was done (cmd edited above)
+         *  then we do a second look to find the most recent
+         *  backup
+         */
       if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
          Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"), 
            sql_strerror(mdb), mdb->cmd);
@@ -99,18 +97,27 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
       }
       if ((row = sql_fetch_row(mdb)) == NULL) {
         sql_free_result(mdb);
-         Mmsg(&mdb->errmsg, _("No prior Job record found.\n"));
+            Mmsg(&mdb->errmsg, _("No prior Full backup Job record found.\n"));
         db_unlock(mdb);
         return 0;
       }
-      JobId = atoi(row[0]);
       sql_free_result(mdb);
+        /* Now edit SQL command for Incremental Job */
+        Mmsg(&mdb->cmd, 
+"SELECT StartTime FROM Job WHERE JobStatus='T' AND Type='%c' AND "
+"Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%u "
+"AND FileSetId=%u ORDER BY StartTime DESC LIMIT 1",
+          jr->Type, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name,
+           jr->ClientId, jr->FileSetId);
    } else {
-      JobId = jr->JobId;             /* search for particular id */
+         Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->Level);
+        db_unlock(mdb);
+        return 0;
    }
-
+   } else {
    Dmsg1(100, "Submitting: %s\n", mdb->cmd);
-   Mmsg(&mdb->cmd, "SELECT StartTime FROM Job WHERE Job.JobId=%u", JobId);
+      Mmsg(&mdb->cmd, "SELECT StartTime FROM Job WHERE Job.JobId=%u", jr->JobId);
+   }
 
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
       pm_strcpy(stime, "");                   /* set EOS */
@@ -121,7 +128,7 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
    }
 
    if ((row = sql_fetch_row(mdb)) == NULL) {
-      Mmsg2(&mdb->errmsg, _("No Job found for JobId=%u: ERR=%s\n"), JobId, sql_strerror(mdb));
+      Mmsg1(&mdb->errmsg, _("No Job record found: ERR=%s\n"), sql_strerror(mdb));
       sql_free_result(mdb);
       db_unlock(mdb);
       return 0;
@@ -144,7 +151,7 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
  *         0 on failure
  */
 int
-db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
+db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr)
 {
    SQL_ROW row;
 
@@ -152,20 +159,27 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
    db_lock(mdb);
    if (jr->Level == L_VERIFY_CATALOG) {
       Mmsg(&mdb->cmd, 
-"SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND Name='%s' AND "
+"SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND "
+" JobStatus='T' AND Name='%s' AND "
 "ClientId=%u ORDER BY StartTime DESC LIMIT 1",
           L_VERIFY_INIT, jr->Name, jr->ClientId);
-   } else if (jr->Level == L_VERIFY_VOLUME_TO_CATALOG) {
+   } else if (jr->Level == L_VERIFY_VOLUME_TO_CATALOG ||
+             jr->Level == L_VERIFY_DISK_TO_CATALOG) {
+      if (Name) {
+        Mmsg(&mdb->cmd,
+"SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND "
+"Name='%s' ORDER BY StartTime DESC LIMIT 1", Name);
+      } else {
       Mmsg(&mdb->cmd, 
-"SELECT JobId FROM Job WHERE Type='B' AND "
-"ClientId=%u ORDER BY StartTime DESC LIMIT 1", 
-          jr->ClientId);
+"SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND "
+"ClientId=%u ORDER BY StartTime DESC LIMIT 1", jr->ClientId);
+      }
    } else {
       Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->Level);
       db_unlock(mdb);
       return 0;
    }
-
+   Dmsg1(100, "Query: %s\n", mdb->cmd);
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
       db_unlock(mdb);
       return 0;
@@ -204,6 +218,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
 {
    SQL_ROW row;
    int numrows;
+   char *order;
 
    db_lock(mdb);
    if (item == -1) {      /* find oldest volume */
@@ -218,12 +233,19 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
      item = 1;
    } else {
       /* Find next available volume */
+      if (strcmp(mr->VolStatus, "Recycled") == 0 ||
+          strcmp(mr->VolStatus, "Purged") == 0) {
+         order = "ORDER BY LastWritten ASC,MediaId";  /* take oldest */
+      } else {
+         order = "ORDER BY LastWritten DESC,MediaId";   /* take most recently written */
+      }  
       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
-"VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
-"VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-"FirstWritten,LastWritten,VolStatus "
-"FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
-"ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); 
+          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
+          "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
+          "FirstWritten,LastWritten,VolStatus "
+          "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
+          "%s LIMIT 1",
+         mr->PoolId, mr->MediaType, mr->VolStatus, order);
    }
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
       db_unlock(mdb);
index 7ff3a44fe6bc409b9a0995c257e3a4f60e77ea2d..29d28c8cac93198055f135a3504b23a9fbe45fb6 100644 (file)
@@ -48,7 +48,7 @@
  */
 
 /* Forward referenced functions */
-static int db_get_file_record(JCR *jcr, B_DB *mdb, FILE_DBR *fdbr);
+static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
 static int db_get_path_record(JCR *jcr, B_DB *mdb);
 
@@ -67,10 +67,10 @@ extern void split_path_and_filename(JCR *jcr, B_DB *mdb, char *fname);
  *  Returns: 0 on failure
  *          1 on success with the File record in FILE_DBR
  */
-int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fdbr)
+int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
 {
    int stat;
-   Dmsg1(20, "Enter get_file_from_catalog fname=%s \n", fname);
+   Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
 
    db_lock(mdb);
    split_path_and_filename(jcr, mdb, fname);
@@ -79,7 +79,7 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fd
 
    fdbr->PathId = db_get_path_record(jcr, mdb);
 
-   stat = db_get_file_record(jcr, mdb, fdbr);
+   stat = db_get_file_record(jcr, mdb, jr, fdbr);
 
    db_unlock(mdb);
 
@@ -99,15 +99,23 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fd
  *    "normal" if a new file is found during Verify.
  */
 static
-int db_get_file_record(JCR *jcr, B_DB *mdb, FILE_DBR *fdbr)
+int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
 {
    SQL_ROW row;
    int stat = 0;
 
+   if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
    Mmsg(&mdb->cmd, 
-"SELECT FileId, LStat, MD5 from File where File.JobId=%u and File.PathId=%u and \
-File.FilenameId=%u", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
-
+"SELECT FileId, LStat, MD5 FROM File,Job WHERE "
+"File.JobId=Job.JobId AND File.PathId=%u AND "
+"File.FilenameId=%u AND Job.Type='B' AND Job.JobSTATUS='T' AND "
+"ClientId=%u ORDER BY StartTime DESC LIMIT 1",
+      fdbr->PathId, fdbr->FilenameId, jr->ClientId);
+   } else {
+      Mmsg(&mdb->cmd, 
+"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%u AND File.PathId=%u AND "
+"File.FilenameId=%u", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
+   }
    Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
       fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
       
@@ -254,15 +262,15 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
 
    db_lock(mdb);
    if (jr->JobId == 0) {
-      Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
-PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
-Type,Level \
-FROM Job WHERE Job='%s'", jr->Job);
+      Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
+"PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
+"Type,Level,ClientId "
+"FROM Job WHERE Job='%s'", jr->Job);
     } else {
-      Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
-PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
-Type,Level \
-FROM Job WHERE JobId=%u", jr->JobId);
+      Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
+"PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
+"Type,Level,ClientId "
+"FROM Job WHERE JobId=%u", jr->JobId);
     }
 
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
@@ -288,6 +296,7 @@ FROM Job WHERE JobId=%u", jr->JobId);
    jr->JobStatus = (int)*row[9];
    jr->Type = (int)*row[10];
    jr->Level = (int)*row[11];
+   jr->ClientId = str_to_uint64(row[12]);
    sql_free_result(mdb);
 
    db_unlock(mdb);
@@ -299,7 +308,8 @@ FROM Job WHERE JobId=%u", jr->JobId);
  *  Returns: 0 on error or no Volumes found
  *          number of volumes on success
  *             Volumes are concatenated in VolumeNames
- *             separated by a vertical bar (|).
+ *             separated by a vertical bar (|) in the order
+ *             that they were written.
  *
  *  Returns: number of volumes on success
  */
@@ -311,8 +321,9 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **Volum
 
    db_lock(mdb);
    Mmsg(&mdb->cmd, 
-"SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%u "
-"AND JobMedia.MediaId=Media.MediaId GROUP BY VolumeName", JobId);
+        "SELECT VolumeName,JobMedia.VolIndex FROM JobMedia,Media WHERE "
+        "JobMedia.JobId=%u AND JobMedia.MediaId=Media.MediaId "
+        "GROUP BY VolumeName ORDER BY JobMedia.VolIndex",  JobId);
 
    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
    *VolumeNames[0] = 0;
index 9ebd839f8017dab3d78acb6ac9713e750d88fd0e..8637c5c7b4cfa1dee6ff5f1e4ae65a3ddf05d5bd 100644 (file)
@@ -151,12 +151,12 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
       }
    } else {
       if (mdbr->VolumeName[0] != 0) {
-         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,MediaType,VolStatus,"
-            "VolBytes,LastWritten,VolRetention,Recycle,Slot "
+         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,"
+            "VolBytes,VolFiles,VolRetention,Recycle,Slot,MediaType,LastWritten "
             "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName);
       } else {
-         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,MediaType,VolStatus,"
-            "VolBytes,LastWritten,VolRetention,Recycle,Slot "
+         Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,"
+            "VolBytes,VolFiles,VolRetention,Recycle,Slot,MediaType,LastWritten "
             "FROM Media WHERE Media.PoolId=%u ORDER BY MediaId", mdbr->PoolId);
       }
    }
@@ -190,7 +190,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
 
    } else {
       if (JobId > 0) {                  /* do by JobId */
-         Mmsg(&mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex"
+         Mmsg(&mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
             "AND JobMedia.JobId=%u", JobId);
       } else {
index 510c21bab2f1959ab6378c15f8767c410fe45aa9..4acb2b8f59f69ff2a147fc753b527020061204d2 100644 (file)
@@ -103,9 +103,10 @@ db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
    JobTDate = (btime_t)stime;
 
    db_lock(mdb);
-   Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime='%s', \
-ClientId=%u, JobTDate=%s WHERE JobId=%u",
+   Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime='%s',"
+"ClientId=%u, JobTDate=%s WHERE JobId=%u",
       (char)(jr->Level), dt, jr->ClientId, edit_uint64(JobTDate, ed1), jr->JobId);
+
    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
    db_unlock(mdb);
    mdb->changes = 0;
diff --git a/bacula/src/cats/update_bacula_tables.in b/bacula/src/cats/update_bacula_tables.in
new file mode 100755 (executable)
index 0000000..a1b1984
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# This routine alters the appropriately configured
+#  Bacula tables for either MySQL or SQLite
+#
+if test xsqlite = x@DB_NAME@ ; then
+  echo "Altering SQLite tables"
+  . ./update_sqlite_tables
+fi
+if test xmysql = x@DB_NAME@ ; then
+  echo "Altering MySQL tables"
+  . ./update_mysql_tables
+fi
diff --git a/bacula/src/cats/update_mysql_tables.in b/bacula/src/cats/update_mysql_tables.in
new file mode 100755 (executable)
index 0000000..9da912d
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# Shell script to update MySQL tables from version 1.32 to 1.33
+#
+echo " "
+echo "Depending on the size of your database,"
+echo "this script may take several minutes to run."
+echo " "
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql $* -f <<END-OF-DATA
+USE bacula;
+
+ALTER TABLE Media ADD COLUMN Drive INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE Media ADD COLUMN InChanger TINYINT NOT NULL DEFAULT 0;
+
+ALTER TABLE Pool ADD COLUMN Enabled TINYINT DEFAULT 1;
+ALTER TABLE Pool ADD COLUMN ScratchPoolId INTEGER UNSIGNED DEFAULT 0 REFERENCES Pool;
+ALTER TABLE Pool ADD COLUMN RecyclePoolId INTEGER UNSIGNED DEFAULT 0 REFERENCES Pool;
+
+DROP TABLE BaseFiles;
+
+
+CREATE TABLE BaseFiles (
+   BaseId INTEGER UNSIGNED AUTO_INCREMENT,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   FileId INTEGER UNSIGNED NOT NULL REFERENCES File,
+   FileIndex INTEGER UNSIGNED,
+   PRIMARY KEY(BaseId)
+   );
+
+DROP TABLE UnsavedFiles;
+
+CREATE TABLE UnsavedFiles (
+   UnsavedId INTEGER UNSIGNED AUTO_INCREMENT,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
+   FilenameId INTEGER UNSIGNED NOT NULL REFERENCES Filename,
+   PRIMARY KEY (UnsavedId)
+   );
+
+DROP TABLE BaseFiles;
+
+CREATE TABLE BaseFiles (
+   BaseId INTEGER UNSIGNED AUTO_INCREMENT,
+   BaseJobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   FileId INTEGER UNSIGNED NOT NULL REFERENCES File,
+   FileIndex INTEGER UNSIGNED,
+   PRIMARY KEY(BaseId)
+   );
+
+UPDATE Version SET VersionId=7;
+
+END-OF-DATA
+then
+   echo "Update of Bacula MySQL tables succeeded."
+else
+   echo "Update of Bacula MySQL tables failed."
+fi
+exit 0
diff --git a/bacula/src/cats/update_sqlite_tables.in b/bacula/src/cats/update_sqlite_tables.in
new file mode 100755 (executable)
index 0000000..bb83b4f
--- /dev/null
@@ -0,0 +1,207 @@
+#!/bin/sh
+#
+# shell script to update SQLite from version 1.32 to 1.33
+#
+echo " "
+echo "Depending on the size of your database,"
+echo "this script may take several minutes to run."
+echo " "
+
+bindir=@SQL_BINDIR@
+cd @working_dir@
+
+$bindir/sqlite $* bacula.db <<END-OF-DATA
+
+BEGIN TRANSACTION;
+CREATE TEMPORARY TABLE Media_backup (
+   MediaId INTEGER UNSIGNED AUTOINCREMENT,
+   VolumeName VARCHAR(128) NOT NULL,
+   Slot INTEGER DEFAULT 0,
+   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,
+   VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
+   VolStatus VARCHAR(20) NOT NULL,
+   Recycle TINYINT DEFAULT 0,
+   VolRetention BIGINT UNSIGNED DEFAULT 0,
+   VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+   MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+   MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+   MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+   Drive INTEGER DEFAULT 0,
+   InChanger TINYINT DEFAULT 0,
+   PRIMARY KEY(MediaId)
+   );
+
+INSERT INTO Media_backup SELECT 
+   MediaId, VolumeName, Slot, PoolId,
+   MediaType, FirstWritten, LastWritten,
+   LabelDate, VolJobs, VolFiles, VolBlocks,
+   VolMounts, VolBytes, VolErrors, VolWrites,
+   VolCapacityBytes, VolStatus, Recycle,
+   VolRetention, VolUseDuration, MaxVolJobs,
+   MaxVolFiles, MaxVolBytes, 0, 0
+   FROM Media;
+
+
+DROP TABLE Media;
+
+CREATE TABLE Media (
+   MediaId INTEGER UNSIGNED AUTOINCREMENT,
+   VolumeName VARCHAR(128) NOT NULL,
+   Slot INTEGER DEFAULT 0,
+   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,
+   VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
+   VolStatus VARCHAR(20) NOT NULL,
+   Recycle TINYINT DEFAULT 0,
+   VolRetention BIGINT UNSIGNED DEFAULT 0,
+   VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+   MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+   MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+   MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+   Drive INTEGER DEFAULT 0,
+   InChanger TINYINT DEFAULT 0,
+   PRIMARY KEY(MediaId)
+   );
+
+INSERT INTO Media (
+   MediaId, VolumeName, Slot, PoolId,
+   MediaType, FirstWritten, LastWritten,
+   LabelDate, VolJobs, VolFiles, VolBlocks,
+   VolMounts, VolBytes, VolErrors, VolWrites,
+   VolCapacityBytes, VolStatus, Recycle,
+   VolRetention, VolUseDuration, MaxVolJobs,
+   MaxVolFiles, MaxVolBytes, Drive, InChanger)
+   SELECT * FROM Media_backup;
+
+DROP TABLE Media_backup;
+
+CREATE INDEX inx8 ON Media (PoolId);
+
+CREATE TABLE Pool_backup (
+   PoolId INTEGER UNSIGNED AUTOINCREMENT,
+   Name VARCHAR(128) NOT NULL,
+   NumVols INTEGER UNSIGNED DEFAULT 0,
+   MaxVols INTEGER UNSIGNED DEFAULT 0,
+   UseOnce TINYINT DEFAULT 0,
+   UseCatalog TINYINT DEFAULT 1,
+   AcceptAnyVolume TINYINT DEFAULT 0,
+   VolRetention BIGINT UNSIGNED DEFAULT 0,
+   VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+   MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+   MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+   MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+   AutoPrune TINYINT DEFAULT 0,
+   Recycle TINYINT DEFAULT 0,
+   PoolType VARCHAR(20) NOT NULL,
+   LabelFormat VARCHAR(128) NOT NULL,
+   Enabled TINYINT DEFAULT 1,
+   ScratchPoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
+   RecyclePoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
+   UNIQUE (Name),
+   PRIMARY KEY (PoolId)
+   );
+
+INSERT INTO Pool_backup SELECT
+   PoolId,
+   Name,
+   NumVols,
+   MaxVols,
+   UseOnce,
+   UseCatalog,
+   AcceptAnyVolume,
+   VolRetention,
+   VolUseDuration,
+   MaxVolJobs,
+   MaxVolFiles,
+   MaxVolBytes,
+   AutoPrune,
+   Recycle,
+   PoolType,
+   LabelFormat, 1, 0, 0
+   FROM Pool;
+
+DROP TABLE Pool;
+
+CREATE TABLE Pool (
+   PoolId INTEGER UNSIGNED AUTOINCREMENT,
+   Name VARCHAR(128) NOT NULL,
+   NumVols INTEGER UNSIGNED DEFAULT 0,
+   MaxVols INTEGER UNSIGNED DEFAULT 0,
+   UseOnce TINYINT DEFAULT 0,
+   UseCatalog TINYINT DEFAULT 1,
+   AcceptAnyVolume TINYINT DEFAULT 0,
+   VolRetention BIGINT UNSIGNED DEFAULT 0,
+   VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+   MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+   MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+   MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+   AutoPrune TINYINT DEFAULT 0,
+   Recycle TINYINT DEFAULT 0,
+   PoolType VARCHAR(20) NOT NULL,
+   LabelFormat VARCHAR(128) NOT NULL,
+   Enabled TINYINT DEFAULT 1,
+   ScratchPoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
+   RecyclePoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
+   UNIQUE (Name),
+   PRIMARY KEY (PoolId)
+   );
+
+INSERT INTO Pool (
+   PoolId,
+   Name,
+   NumVols,
+   MaxVols,
+   UseOnce,
+   UseCatalog,
+   AcceptAnyVolume,
+   VolRetention,
+   VolUseDuration,
+   MaxVolJobs,
+   MaxVolFiles,
+   MaxVolBytes,
+   AutoPrune,
+   Recycle,
+   PoolType,
+   LabelFormat, Enabled, ScratchPoolId, RecyclePoolId)
+   SELECT * FROM Pool_backup;
+
+DROP TABLE Pool_backup;
+
+
+DROP TABLE BaseFiles;
+
+CREATE TABLE BaseFiles (
+   BaseId INTEGER UNSIGNED AUTOINCREMENT,
+   BaseJobId INTEGER UNSIGNED REFERENCES Job NOT NULL,
+   JobId INTEGER UNSIGNED REFERENCES Job NOT NULL,
+   FileId INTEGER UNSIGNED REFERENCES File NOT NULL,
+   FileIndex INTEGER UNSIGNED,
+   PRIMARY KEY(BaseId)
+   );
+
+COMMIT;
+
+UPDATE Version SET VersionId=7;
+
+END-OF-DATA
index d5b91b721652cffb0ccda8635b9136e81ef670ab..9f9d3d73642867822d84d044819d720bcea67c39 100644 (file)
@@ -59,7 +59,7 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
 
 clean:
        @$(RMF) console core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
-       @$(RMF) static-console
+       @$(RMF) static-console gmon.out
 
 realclean: clean
        @$(RMF) tags console.conf
index f518bd2ced1063dbb20788025fa516260bed5f36..79544a66a76cd5876bca9b9c1800d8afcdeab182 100644 (file)
@@ -377,6 +377,20 @@ try_again:
 
    Dmsg0(40, "Opened connection with Director daemon\n");
 
+   sendit(_("Enter a period to cancel a command.\n"));
+
+   char *env = getenv("HOME");
+   if (env) {
+      FILE *fd;
+      pm_strcpy(&UA_sock->msg, env);
+      pm_strcat(&UA_sock->msg, "/.bconsolerc");
+      fd = fopen(UA_sock->msg, "r");
+      if (fd) {
+       read_and_process_input(fd, UA_sock);
+       fclose(fd);
+      }
+   }
+
    read_and_process_input(stdin, UA_sock);
 
    if (UA_sock) {
@@ -423,9 +437,8 @@ get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
    if (!line) {
       exit(1);
    }
-   strcpy(sock->msg, line);
-   strip_trailing_junk(sock->msg);
-   sock->msglen = strlen(sock->msg);
+   strip_trailing_junk(line);
+   sock->msglen = pm_strcpy(&sock->msg, line);
    if (sock->msglen) {
       add_history(sock->msg);
    }
diff --git a/bacula/src/console2.glade b/bacula/src/console2.glade
new file mode 100644 (file)
index 0000000..2c26194
--- /dev/null
@@ -0,0 +1,3080 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="app1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Bacula Console</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_CENTER</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <signal name="delete_event" handler="on_app1_delete_event"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox6">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkHandleBox" id="handlebox1">
+         <property name="border_width">1</property>
+         <property name="visible">True</property>
+         <property name="shadow_type">GTK_SHADOW_OUT</property>
+         <property name="handle_position">GTK_POS_LEFT</property>
+         <property name="snap_edge">GTK_POS_TOP</property>
+
+         <child>
+           <widget class="GtkMenuBar" id="menubar1">
+             <property name="visible">True</property>
+
+             <child>
+               <widget class="GtkMenuItem" id="file1">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">_File</property>
+                 <property name="use_underline">True</property>
+
+                 <child>
+                   <widget class="GtkMenu" id="file1_menu">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkMenuItem" id="connect1">
+                         <property name="visible">True</property>
+                         <property name="tooltip" translatable="yes">Connect to Director</property>
+                         <property name="label" translatable="yes">_Connect</property>
+                         <property name="use_underline">True</property>
+                         <signal name="activate" handler="on_connect_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkMenuItem" id="disconnect1">
+                         <property name="visible">True</property>
+                         <property name="tooltip" translatable="yes">Disconnect from Director</property>
+                         <property name="label" translatable="yes">_Disconnect</property>
+                         <property name="use_underline">True</property>
+                         <signal name="activate" handler="on_disconnect_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkMenuItem" id="menuitem4">
+                         <property name="visible">True</property>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="exit1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-quit</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Exit</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_exit_activate"/>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkMenuItem" id="edit1">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">_Edit</property>
+                 <property name="use_underline">True</property>
+
+                 <child>
+                   <widget class="GtkMenu" id="edit1_menu">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="cut1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-cut</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Cut</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_cut1_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="copy1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-copy</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Copy</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_copy1_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="paste1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-paste</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Paste</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_paste1_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="clear1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-clear</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Clear</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_clear1_activate"/>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkMenuItem" id="separator1">
+                         <property name="visible">True</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkMenuItem" id="item1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Display Messages</property>
+                 <property name="label" translatable="yes">_View</property>
+                 <property name="use_underline">True</property>
+
+                 <child>
+                   <widget class="GtkMenu" id="item1_menu">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkMenuItem" id="msgs">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">_Display Messages</property>
+                         <property name="use_underline">True</property>
+                         <signal name="activate" handler="on_msgs_activate"/>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkMenuItem" id="settings1">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">_Settings</property>
+                 <property name="use_underline">True</property>
+
+                 <child>
+                   <widget class="GtkMenu" id="settings1_menu">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="preferences1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gtk-preferences</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">Preferences</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_preferences1_activate"/>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkMenuItem" id="help1">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">_Help</property>
+                 <property name="use_underline">True</property>
+
+                 <child>
+                   <widget class="GtkMenu" id="help1_menu">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkImageMenuItem" id="about1">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">gnome-stock-about</property>
+                         <property name="use_underline">True</property>
+                         <accessibility>
+                           <atkproperty name="AtkObject::accessible_name" translatable="yes">About</atkproperty>
+                         </accessibility>
+                         <signal name="activate" handler="on_about_activate"/>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHandleBox" id="handlebox2">
+         <property name="border_width">1</property>
+         <property name="visible">True</property>
+         <property name="shadow_type">GTK_SHADOW_OUT</property>
+         <property name="handle_position">GTK_POS_LEFT</property>
+         <property name="snap_edge">GTK_POS_TOP</property>
+
+         <child>
+           <widget class="GtkToolbar" id="toolbar2">
+             <property name="border_width">1</property>
+             <property name="visible">True</property>
+             <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+             <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+             <property name="tooltips">True</property>
+
+             <child>
+               <widget class="button" id="connect_button1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Connect to Director</property>
+                 <property name="label" translatable="yes">Connect</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_pixmap">gtk-new</property>
+                 <signal name="clicked" handler="on_connect_button_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="button" id="run_button1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Run a Job</property>
+                 <property name="label" translatable="yes">Run</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_pixmap">gtk-execute</property>
+                 <signal name="clicked" handler="on_run_button_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="button" id="msgs_button">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Display Messages</property>
+                 <property name="label" translatable="yes">Msgs</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_pixmap">gtk-find</property>
+                 <signal name="clicked" handler="on_msgs_button_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="button" id="restore_button">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Restore</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_pixmap">gtk-revert-to-saved</property>
+                 <signal name="clicked" handler="on_restore_button_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="button" id="label_button">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Label</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_pixmap">gtk-save-as</property>
+                 <signal name="clicked" handler="on_label_button_clicked"/>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkVBox" id="vbox7">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkScrolledWindow" id="scroll1">
+             <property name="visible">True</property>
+             <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="shadow_type">GTK_SHADOW_IN</property>
+             <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+             <child>
+               <widget class="GtkTextView" id="text1">
+                 <property name="visible">True</property>
+                 <property name="editable">False</property>
+                 <property name="justification">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap_mode">GTK_WRAP_WORD</property>
+                 <property name="cursor_visible">True</property>
+                 <property name="pixels_above_lines">0</property>
+                 <property name="pixels_below_lines">0</property>
+                 <property name="pixels_inside_wrap">0</property>
+                 <property name="left_margin">0</property>
+                 <property name="right_margin">0</property>
+                 <property name="indent">0</property>
+                 <property name="text" translatable="yes"></property>
+               </widget>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox18">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label38">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes"> Command: </property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkEntry" id="entry1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Enter Commands Here</property>
+                 <property name="can_default">True</property>
+                 <property name="has_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="has_focus">True</property>
+                 <property name="editable">True</property>
+                 <property name="visibility">True</property>
+                 <property name="max_length">150</property>
+                 <property name="text" translatable="yes"></property>
+                 <property name="has_frame">True</property>
+                 <property name="invisible_char" translatable="yes">*</property>
+                 <property name="activates_default">False</property>
+                 <signal name="key_press_event" handler="on_entry1_key_press_event"/>
+                 <signal name="key_release_event" handler="on_entry1_key_release_event"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox19">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkFrame" id="frame1">
+                 <property name="visible">True</property>
+                 <property name="label_xalign">0</property>
+                 <property name="label_yalign">0.5</property>
+                 <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label39">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes"> Status: </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkFrame" id="frame2">
+                 <property name="visible">True</property>
+                 <property name="label_xalign">0</property>
+                 <property name="label_yalign">0.5</property>
+                 <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="status1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes"></property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="about1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">About Bacula Console</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox5">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area5">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkHBox" id="hbox20">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label44">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes"></property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="about_button">
+                 <property name="border_width">1</property>
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-ok</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_about_button_clicked"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkVBox" id="vbox8">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkVBox" id="vbox9">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="about_head">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Bacula Console 1.32c (24 Oct 03)
+</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHSeparator" id="hseparator1">
+                 <property name="visible">True</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="copyright">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Copyright (c) 1999 - 2002, Kern Sibbald and John Walker</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.1</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="authors">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Authors: Kern Sibbald and John Walker</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.0400001</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="theme">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">It comes by night and sucks the essence from your computers</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.15</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="SelectDirectorDialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Select Director</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox6">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area2">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkHBox" id="hbox21">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkButton" id="button11">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-ok</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_select_director_OK_clicked"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="label46">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">         </property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">2</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="button13">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-cancel</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_select_director_cancel_clicked"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkVBox" id="vbox10">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkLabel" id="label48">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes"></property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.48</property>
+             <property name="yalign">0.46</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkLabel" id="label47">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">Select Director</property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkCombo" id="combo1">
+             <property name="border_width">6</property>
+             <property name="visible">True</property>
+             <property name="value_in_list">False</property>
+             <property name="allow_empty">True</property>
+             <property name="case_sensitive">False</property>
+             <property name="enable_arrow_keys">True</property>
+             <property name="enable_arrows_always">False</property>
+
+             <child internal-child="entry">
+               <widget class="GtkEntry" id="dirselect">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="editable">True</property>
+                 <property name="visibility">True</property>
+                 <property name="max_length">0</property>
+                 <property name="text" translatable="yes"></property>
+                 <property name="has_frame">True</property>
+                 <property name="invisible_char" translatable="yes">*</property>
+                 <property name="activates_default">False</property>
+               </widget>
+             </child>
+
+             <child internal-child="list">
+               <widget class="GtkList" id="convertwidget3">
+                 <property name="visible">True</property>
+                 <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                 <child>
+                   <widget class="GtkListItem" id="convertwidget4">
+                     <property name="visible">True</property>
+
+                     <child>
+                       <widget class="GtkLabel" id="convertwidget5">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes"></property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">False</property>
+                         <property name="justify">GTK_JUSTIFY_LEFT</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="RunDialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Run a Job</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox7">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area6">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkHButtonBox" id="hbuttonbox1">
+             <property name="visible">True</property>
+             <property name="layout_style">GTK_BUTTONBOX_END</property>
+             <property name="spacing">8</property>
+
+             <child>
+               <widget class="GtkButton" id="run_ok">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-ok</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_run_ok_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="run_cancel">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-cancel</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_run_cancel_clicked"/>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkVBox" id="vbox11">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkVBox" id="vbox12">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label62">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Run a Job</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">9</property>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox28">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkHBox" id="hbox29">
+                     <property name="visible">True</property>
+                     <property name="homogeneous">False</property>
+                     <property name="spacing">0</property>
+
+                     <child>
+                       <widget class="GtkLabel" id="label63">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">Job:</property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">False</property>
+                         <property name="justify">GTK_JUSTIFY_RIGHT</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkCombo" id="combo_job">
+                         <property name="visible">True</property>
+                         <property name="value_in_list">True</property>
+                         <property name="allow_empty">False</property>
+                         <property name="case_sensitive">False</property>
+                         <property name="enable_arrow_keys">True</property>
+                         <property name="enable_arrows_always">False</property>
+
+                         <child internal-child="entry">
+                           <widget class="GtkEntry" id="entry_job">
+                             <property name="visible">True</property>
+                             <property name="can_focus">True</property>
+                             <property name="editable">False</property>
+                             <property name="visibility">True</property>
+                             <property name="max_length">0</property>
+                             <property name="text" translatable="yes"></property>
+                             <property name="has_frame">True</property>
+                             <property name="invisible_char" translatable="yes">*</property>
+                             <property name="activates_default">False</property>
+                             <signal name="changed" handler="on_entry_job_changed"/>
+                           </widget>
+                         </child>
+
+                         <child internal-child="list">
+                           <widget class="GtkList" id="convertwidget6">
+                             <property name="visible">True</property>
+                             <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                             <child>
+                               <widget class="GtkListItem" id="convertwidget7">
+                                 <property name="visible">True</property>
+
+                                 <child>
+                                   <widget class="GtkLabel" id="convertwidget8">
+                                     <property name="visible">True</property>
+                                     <property name="label" translatable="yes"></property>
+                                     <property name="use_underline">False</property>
+                                     <property name="use_markup">False</property>
+                                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                     <property name="wrap">False</property>
+                                     <property name="selectable">False</property>
+                                     <property name="xalign">0</property>
+                                     <property name="yalign">0.5</property>
+                                     <property name="xpad">0</property>
+                                     <property name="ypad">0</property>
+                                   </widget>
+                                 </child>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                       <packing>
+                         <property name="padding">1</property>
+                         <property name="expand">True</property>
+                         <property name="fill">True</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkLabel" id="label64">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">   Type:</property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">False</property>
+                         <property name="justify">GTK_JUSTIFY_CENTER</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkCombo" id="combo_type">
+                         <property name="visible">True</property>
+                         <property name="value_in_list">True</property>
+                         <property name="allow_empty">False</property>
+                         <property name="case_sensitive">False</property>
+                         <property name="enable_arrow_keys">True</property>
+                         <property name="enable_arrows_always">False</property>
+
+                         <child internal-child="entry">
+                           <widget class="GtkEntry" id="entry_type">
+                             <property name="visible">True</property>
+                             <property name="can_focus">True</property>
+                             <property name="editable">False</property>
+                             <property name="visibility">True</property>
+                             <property name="max_length">0</property>
+                             <property name="text" translatable="yes"></property>
+                             <property name="has_frame">True</property>
+                             <property name="invisible_char" translatable="yes">*</property>
+                             <property name="activates_default">False</property>
+                           </widget>
+                         </child>
+
+                         <child internal-child="list">
+                           <widget class="GtkList" id="convertwidget9">
+                             <property name="visible">True</property>
+                             <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                             <child>
+                               <widget class="GtkListItem" id="convertwidget10">
+                                 <property name="visible">True</property>
+
+                                 <child>
+                                   <widget class="GtkLabel" id="convertwidget11">
+                                     <property name="visible">True</property>
+                                     <property name="label" translatable="yes"></property>
+                                     <property name="use_underline">False</property>
+                                     <property name="use_markup">False</property>
+                                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                     <property name="wrap">False</property>
+                                     <property name="selectable">False</property>
+                                     <property name="xalign">0</property>
+                                     <property name="yalign">0.5</property>
+                                     <property name="xpad">0</property>
+                                     <property name="ypad">0</property>
+                                   </widget>
+                                 </child>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                       <packing>
+                         <property name="padding">6</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label65">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes"> </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">30</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox30">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label66">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Client:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_RIGHT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo_client">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_client">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget12">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget13">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget14">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">1</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label67">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes"> </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">123</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox31">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label68">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">FileSet: </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_RIGHT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo_fileset">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_fileset">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget15">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget16">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget17">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkButton" id="view_fileset_button">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">  View FileSet  </property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <signal name="clicked" handler="on_view_fileset_clicked"/>
+                   </widget>
+                   <packing>
+                     <property name="padding">10</property>
+                     <property name="expand">False</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label69">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">  </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">65</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox32">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label70">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Level:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_RIGHT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo_level">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_level">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget18">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget19">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget20">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget21">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget22">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label71">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">             </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">100</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox33">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label72">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Pool:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo_pool">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_pool">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget23">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget24">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget25">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget26">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget27">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label73">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">   </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">120</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox39">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label96">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Storage:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo-storage">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_storage">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget28">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget29">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget30">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget31">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget32">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label97">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">   </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">120</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox40">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label98">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Messages:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCombo" id="combo_messages">
+                     <property name="visible">True</property>
+                     <property name="value_in_list">True</property>
+                     <property name="allow_empty">False</property>
+                     <property name="case_sensitive">False</property>
+                     <property name="enable_arrow_keys">True</property>
+                     <property name="enable_arrows_always">False</property>
+
+                     <child internal-child="entry">
+                       <widget class="GtkEntry" id="entry_messages">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="editable">False</property>
+                         <property name="visibility">True</property>
+                         <property name="max_length">0</property>
+                         <property name="text" translatable="yes"></property>
+                         <property name="has_frame">True</property>
+                         <property name="invisible_char" translatable="yes">*</property>
+                         <property name="activates_default">False</property>
+                       </widget>
+                     </child>
+
+                     <child internal-child="list">
+                       <widget class="GtkList" id="convertwidget33">
+                         <property name="visible">True</property>
+                         <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                         <child>
+                           <widget class="GtkListItem" id="convertwidget34">
+                             <property name="visible">True</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="convertwidget35">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes"></property>
+                                 <property name="use_underline">False</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                               </widget>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label99">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">   </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">120</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkHBox" id="hbox34">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label77">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Where: </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkEntry" id="entry_where">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">True</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label78">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">   </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">120</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">2</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox41">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label100">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">When:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkEntry" id="entry_when">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="editable">True</property>
+                 <property name="visibility">True</property>
+                 <property name="max_length">0</property>
+                 <property name="text" translatable="yes"></property>
+                 <property name="has_frame">True</property>
+                 <property name="invisible_char" translatable="yes">*</property>
+                 <property name="activates_default">False</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="label101">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">   </property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">120</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkLabel" id="label84">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">   </property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkWindow" id="restore_files">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Restore File Selection</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+
+  <child>
+    <widget class="GtkVBox" id="vbox13">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkScrolledWindow" id="scrolledwindow4">
+         <property name="visible">True</property>
+         <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+         <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+         <property name="shadow_type">GTK_SHADOW_IN</property>
+         <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+         <child>
+           <widget class="GtkTreeView" id="ctree2">
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="headers_visible">True</property>
+             <property name="rules_hint">False</property>
+             <property name="reorderable">False</property>
+             <property name="enable_search">True</property>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHBox" id="hbox38">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkLabel" id="label88">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes"> cwd:</property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkEntry" id="entry25">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Enter Commands Here</property>
+             <property name="can_default">True</property>
+             <property name="has_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="has_focus">True</property>
+             <property name="editable">True</property>
+             <property name="visibility">True</property>
+             <property name="max_length">0</property>
+             <property name="text" translatable="yes"></property>
+             <property name="has_frame">True</property>
+             <property name="invisible_char" translatable="yes">*</property>
+             <property name="activates_default">False</property>
+             <signal name="key_press_event" handler="on_entry1_key_press_event"/>
+             <signal name="key_release_event" handler="on_entry1_key_release_event"/>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHBox" id="hbox44">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkLabel" id="label105">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes"> </property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_FILL</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">59</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="restore_file">
+             <property name="border_width">9</property>
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="label">gtk-ok</property>
+             <property name="use_stock">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_restore_file_clicked"/>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="restore_dialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Restore Files</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox8">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area7">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkHButtonBox" id="hbuttonbox2">
+             <property name="visible">True</property>
+             <property name="layout_style">GTK_BUTTONBOX_END</property>
+             <property name="spacing">8</property>
+
+             <child>
+               <widget class="GtkButton" id="restore_ok">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-ok</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_restore_ok_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="restore_cancel">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-cancel</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_restore_cancel_clicked"/>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHBox" id="hbox42">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkFrame" id="frame3">
+             <property name="border_width">8</property>
+             <property name="visible">True</property>
+             <property name="label_xalign">0</property>
+             <property name="label_yalign">0.5</property>
+             <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+             <child>
+               <widget class="GtkHBox" id="hbox43">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">0</property>
+
+                 <child>
+                   <widget class="GtkLabel" id="label102">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">         </property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_CENTER</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                     <property name="pack_type">GTK_PACK_END</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkVBox" id="vbox15">
+                     <property name="visible">True</property>
+                     <property name="homogeneous">False</property>
+                     <property name="spacing">0</property>
+
+                     <child>
+                       <widget class="GtkLabel" id="label103">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes"></property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">False</property>
+                         <property name="justify">GTK_JUSTIFY_CENTER</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">2</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkRadioButton" id="rb_most_recent">
+                         <property name="border_width">3</property>
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="label" translatable="yes">Select most recent backup</property>
+                         <property name="use_underline">True</property>
+                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                         <property name="active">True</property>
+                         <property name="inconsistent">False</property>
+                         <property name="draw_indicator">True</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkRadioButton" id="rb_jobs">
+                         <property name="border_width">5</property>
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="label" translatable="yes">Select list of Jobs</property>
+                         <property name="use_underline">True</property>
+                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                         <property name="active">False</property>
+                         <property name="inconsistent">False</property>
+                         <property name="draw_indicator">True</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkRadioButton" id="rb_file">
+                         <property name="border_width">4</property>
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="label" translatable="yes">Find a specific file</property>
+                         <property name="use_underline">True</property>
+                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                         <property name="active">False</property>
+                         <property name="inconsistent">False</property>
+                         <property name="draw_indicator">True</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkLabel" id="label104">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes"></property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">False</property>
+                         <property name="justify">GTK_JUSTIFY_CENTER</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">False</property>
+                         <property name="fill">False</property>
+                       </packing>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="label106">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Select by:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="type">label_item</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVBox" id="vbox14">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <placeholder/>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="apply_button">
+                 <property name="border_width">50</property>
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-apply</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_apply_button_clicked"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <placeholder/>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="label_dialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Label a Volume</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox9">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area8">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkHButtonBox" id="hbuttonbox3">
+             <property name="visible">True</property>
+             <property name="layout_style">GTK_BUTTONBOX_END</property>
+             <property name="spacing">8</property>
+
+             <child>
+               <widget class="GtkButton" id="label_ok">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-ok</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_label_ok_clicked"/>
+               </widget>
+             </child>
+
+             <child>
+               <widget class="GtkButton" id="label_cancel">
+                 <property name="visible">True</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label">gtk-cancel</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <signal name="clicked" handler="on_label_cancel_clicked"/>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkVBox" id="vbox16">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkLabel" id="label106">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">Label a Volume</property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">9</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox45">
+             <property name="border_width">5</property>
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label107">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Storage:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_CENTER</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.15</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkCombo" id="label_combo_storage">
+                 <property name="visible">True</property>
+                 <property name="value_in_list">True</property>
+                 <property name="allow_empty">False</property>
+                 <property name="case_sensitive">False</property>
+                 <property name="enable_arrow_keys">True</property>
+                 <property name="enable_arrows_always">False</property>
+
+                 <child internal-child="entry">
+                   <widget class="GtkEntry" id="entry26">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">False</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                   </widget>
+                 </child>
+
+                 <child internal-child="list">
+                   <widget class="GtkList" id="convertwidget38">
+                     <property name="visible">True</property>
+                     <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                     <child>
+                       <widget class="GtkListItem" id="convertwidget39">
+                         <property name="visible">True</property>
+
+                         <child>
+                           <widget class="GtkLabel" id="convertwidget40">
+                             <property name="visible">True</property>
+                             <property name="label" translatable="yes"></property>
+                             <property name="use_underline">False</property>
+                             <property name="use_markup">False</property>
+                             <property name="justify">GTK_JUSTIFY_LEFT</property>
+                             <property name="wrap">False</property>
+                             <property name="selectable">False</property>
+                             <property name="xalign">0</property>
+                             <property name="yalign">0.5</property>
+                             <property name="xpad">0</property>
+                             <property name="ypad">0</property>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkListItem" id="convertwidget41">
+                         <property name="visible">True</property>
+
+                         <child>
+                           <widget class="GtkLabel" id="convertwidget42">
+                             <property name="visible">True</property>
+                             <property name="label" translatable="yes"></property>
+                             <property name="use_underline">False</property>
+                             <property name="use_markup">False</property>
+                             <property name="justify">GTK_JUSTIFY_LEFT</property>
+                             <property name="wrap">False</property>
+                             <property name="selectable">False</property>
+                             <property name="xalign">0</property>
+                             <property name="yalign">0.5</property>
+                             <property name="xpad">0</property>
+                             <property name="ypad">0</property>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">15</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <placeholder/>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox46">
+             <property name="border_width">5</property>
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label109">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Pool:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.12</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkCombo" id="label_combo_pool">
+                 <property name="visible">True</property>
+                 <property name="value_in_list">True</property>
+                 <property name="allow_empty">False</property>
+                 <property name="case_sensitive">False</property>
+                 <property name="enable_arrow_keys">True</property>
+                 <property name="enable_arrows_always">False</property>
+
+                 <child internal-child="entry">
+                   <widget class="GtkEntry" id="entry27">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">False</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                   </widget>
+                 </child>
+
+                 <child internal-child="list">
+                   <widget class="GtkList" id="convertwidget43">
+                     <property name="visible">True</property>
+                     <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+
+                     <child>
+                       <widget class="GtkListItem" id="convertwidget44">
+                         <property name="visible">True</property>
+
+                         <child>
+                           <widget class="GtkLabel" id="convertwidget45">
+                             <property name="visible">True</property>
+                             <property name="label" translatable="yes"></property>
+                             <property name="use_underline">False</property>
+                             <property name="use_markup">False</property>
+                             <property name="justify">GTK_JUSTIFY_LEFT</property>
+                             <property name="wrap">False</property>
+                             <property name="selectable">False</property>
+                             <property name="xalign">0</property>
+                             <property name="yalign">0.5</property>
+                             <property name="xpad">0</property>
+                             <property name="ypad">0</property>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkListItem" id="convertwidget46">
+                         <property name="visible">True</property>
+
+                         <child>
+                           <widget class="GtkLabel" id="convertwidget47">
+                             <property name="visible">True</property>
+                             <property name="label" translatable="yes"></property>
+                             <property name="use_underline">False</property>
+                             <property name="use_markup">False</property>
+                             <property name="justify">GTK_JUSTIFY_LEFT</property>
+                             <property name="wrap">False</property>
+                             <property name="selectable">False</property>
+                             <property name="xalign">0</property>
+                             <property name="yalign">0.5</property>
+                             <property name="xpad">0</property>
+                             <property name="ypad">0</property>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">14</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <placeholder/>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox47">
+             <property name="border_width">5</property>
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="label111">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Volume Name:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.17</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkEntry" id="label_entry_volume">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="editable">True</property>
+                 <property name="visibility">True</property>
+                 <property name="max_length">0</property>
+                 <property name="text" translatable="yes"></property>
+                 <property name="has_frame">True</property>
+                 <property name="invisible_char" translatable="yes">*</property>
+                 <property name="activates_default">False</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <placeholder/>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkHBox" id="hbox48">
+             <property name="border_width">5</property>
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkLabel" id="slot1">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Slot:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.09</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkSpinButton" id="label_slot">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="climb_rate">1</property>
+                 <property name="digits">0</property>
+                 <property name="numeric">True</property>
+                 <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+                 <property name="snap_to_ticks">False</property>
+                 <property name="wrap">False</property>
+                 <property name="adjustment">0 0 10000 1 10 10</property>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <placeholder/>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkLabel" id="label113">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">   </property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/bacula/src/console2.gladep b/bacula/src/console2.gladep
new file mode 100644 (file)
index 0000000..8e701cb
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+  <name>console</name>
+  <program_name>gnome-console</program_name>
+  <source_directory>gnome2-console</source_directory>
+</glade-project>
index e5ca4c1c7b0e2f094be3cfd07cea5c6af5529867..fb6ff2128cf971094257e8a212b97e40f6c2de6a 100644 (file)
@@ -8,3 +8,4 @@ btraceback
 btraceback.gdb
 startit
 stopit
+dird.conf
index 299cf2c663b4423d7e34561068893eb45443ba9a..851d93d3365472ecd0a63d8ee4b20eb60d5aeddf 100644 (file)
@@ -30,7 +30,7 @@ SVRSRCS = dird.c admin.c authenticate.c \
          recycle.c restore.c run_conf.c \
          scheduler.c sql_cmds.c \
          ua_cmds.c ua_dotcmds.c \
-         ua_query.c ua_retention.c \
+         ua_query.c \
          ua_input.c ua_label.c ua_output.c ua_prune.c \
          ua_purge.c ua_restore.c ua_run.c \
          ua_select.c ua_server.c \
@@ -43,7 +43,7 @@ SVROBJS = dird.o admin.o authenticate.o \
          recycle.o restore.o run_conf.o \
          scheduler.o sql_cmds.o \
          ua_cmds.o ua_dotcmds.o \
-         ua_query.o ua_retention.o \
+         ua_query.o \
          ua_input.o ua_label.o ua_output.o ua_prune.o \
          ua_purge.o ua_restore.o ua_run.o \
          ua_select.o ua_server.o \
index b41ca667c683600eb13a84e54c28d5675eece5be..9ec6d81bf1b3e12a2ac4b6af2cd6f91335bddcb9 100644 (file)
@@ -69,7 +69,7 @@ int authenticate_storage_daemon(JCR *jcr)
    }
    if (!cram_md5_get_auth(sd, jcr->store->password, ssl_need) || 
        !cram_md5_auth(sd, jcr->store->password, ssl_need)) {
-      Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords not the same.\n"));
+      Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords or names not the same.\n"));
       return 0;
    }
    Dmsg1(116, ">stored: %s", sd->msg);
@@ -106,7 +106,7 @@ int authenticate_file_daemon(JCR *jcr)
    }
    if (!cram_md5_get_auth(fd, jcr->client->password, ssl_need) || 
        !cram_md5_auth(fd, jcr->client->password, ssl_need)) {
-      Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords not the same.\n"));
+      Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords or names not the same.\n"));
       return 0;
    }
    Dmsg1(116, ">filed: %s", fd->msg);
index 8d547b406563bc8c47e94c32d38ad4487c8aa1c9..2480afbcee82e2d5880feb7885ee3e3d111ca3a1 100644 (file)
@@ -228,7 +228,7 @@ int wait_for_job_termination(JCR *jcr)
 {
    int32_t n = 0;
    BSOCK *fd = jcr->file_bsock;
-   int fd_ok = FALSE;
+   bool fd_ok = false;
    uint32_t JobFiles, Errors;
    uint64_t ReadBytes, JobBytes;
 
@@ -237,7 +237,7 @@ int wait_for_job_termination(JCR *jcr)
    while ((n = bget_dirmsg(fd)) >= 0) {
       if (!fd_ok && sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
          &ReadBytes, &JobBytes, &Errors) == 5) {
-        fd_ok = TRUE;
+        fd_ok = true;
         set_jcr_job_status(jcr, jcr->FDJobStatus);
          Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus);
       } else {
@@ -257,15 +257,18 @@ int wait_for_job_termination(JCR *jcr)
    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/Errors */
    wait_for_storage_daemon_termination(jcr);
 
+
    /* Return values from FD */
    if (fd_ok) {
       jcr->JobFiles = JobFiles;
       jcr->Errors = Errors;
       jcr->ReadBytes = ReadBytes;
       jcr->JobBytes = JobBytes;
+   } else {
+      Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
    }
 
-// Dmsg4(000, "fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", fd_ok, jcr->FDJobStatus,
+// Dmsg4(100, "fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", fd_ok, jcr->FDJobStatus,
 //   jcr->JobStatus, jcr->SDJobStatus);
 
    /* Return the first error status we find Dir, FD, or SD */
@@ -295,7 +298,7 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr
    double kbps, compression;
    utime_t RunTime;
 
-   Dmsg0(100, "Enter backup_cleanup()\n");
+   Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
    memset(&mr, 0, sizeof(mr));
    set_jcr_job_status(jcr, TermCode);
 
@@ -337,8 +340,12 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr
         VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
                    &VolParams);
         if (VolCount == 0) {
-            Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters. ERR=%s\n"),
-                db_strerror(jcr->db));
+            Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to "      
+                 "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db));
+            if (jcr->SDJobFiles != 0) {
+               set_jcr_job_status(jcr, JS_ErrorTerminated);
+            }
+
         }
         for (int i=0; i < VolCount; i++) {
            /* Write the record */
index be3f7e3626921a12f634064dfb3f2c21559d54c6..9c00dfbdb4b009ef4497becd9f4e286264b1a771 100644 (file)
@@ -185,7 +185,7 @@ Messages {
 #
 # WARNING! the following will create a file that you must cycle from
 #          time to time as it will grow indefinitely. However, it will
-#          also keep all your messages if the scroll off the console.
+#          also keep all your messages if they scroll off the console.
 #
   append = "@working_dir@/log" = all, !skipped
 }
index ae8ddf2a7e27830a24c0b2ff5983bd6fbba6aae8..9457c12bac1cb957387e46fd7379c77d170926ad 100644 (file)
@@ -35,6 +35,7 @@
 
 /* Forward referenced functions */
 static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
+void print_bsr(UAContext *ua, RBSR *bsr);
 
 
 /*
@@ -62,21 +63,31 @@ static void free_findex(RBSR_FINDEX *fi)
  *  range regardless of volume. The FirstIndex and LastIndex
  *  passed in here are for the current volume, so when 
  *  writing out the fi, constrain them to those values.
+ *
+ * We are called here once for each JobMedia record
+ *  for each Volume.
  */
-static void write_findex(UAContext *ua, RBSR_FINDEX *fi, 
+static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi, 
              int32_t FirstIndex, int32_t LastIndex, FILE *fd) 
 {
-   if (fi) {
+   uint32_t count = 0;
+   for ( ; fi; fi=fi->next) {
       int32_t findex, findex2;
+      if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
+         (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
+         (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
       findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
       findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
       if (findex == findex2) {
          fprintf(fd, "FileIndex=%d\n", findex);
+           count++;
       } else {
          fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
+           count += findex2 - findex + 1;
+      }
       }
-      write_findex(ua, fi->next, FirstIndex, LastIndex, fd);
    }
+   return count;
 }
 
 /*
@@ -101,13 +112,15 @@ static bool is_volume_selected(RBSR_FINDEX *fi,
 
 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
 {
-   if (fi) {
+   bsendmsg(ua, "fi=0x%x\n", (unsigned)fi);
+   for ( ; fi; fi=fi->next) {
       if (fi->findex == fi->findex2) {
          bsendmsg(ua, "FileIndex=%d\n", fi->findex);
+//       Dmsg1(100, "FileIndex=%d\n", fi->findex);
       } else {
          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
+//       Dmsg2(100, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
       }
-      print_findex(ua, fi->next);
    }
 }
 
@@ -124,10 +137,10 @@ void free_bsr(RBSR *bsr)
 {
    if (bsr) {
       free_findex(bsr->fi);
-      free_bsr(bsr->next);
       if (bsr->VolParams) {
         free(bsr->VolParams);
       }
+      free_bsr(bsr->next);
       free(bsr);
    }
 }
@@ -210,6 +223,11 @@ int write_bsr_file(UAContext *ua, RBSR *bsr)
 static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
 {
    if (bsr) {
+      uint32_t count;
+      /*
+       * For a given volume, loop over all the JobMedia records.
+       *   VolCount is the number of JobMedia records.
+       */
       for (int i=0; i < bsr->VolCount; i++) {
         if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
              bsr->VolParams[i].LastIndex)) {
@@ -219,21 +237,32 @@ static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
+        if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
+            fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
+        } else {
          fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
                 bsr->VolParams[i].EndFile);
+        }
+        if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
+            fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartBlock);
+        } else {
          fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
                 bsr->VolParams[i].EndBlock);
-
-//       Dmsg2(000, "bsr VolParam FI=%u LI=%u\n",
+        }
+//       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
 //         bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
-        write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
+
+        count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
            bsr->VolParams[i].LastIndex, fd);
+        if (count) {
+            fprintf(fd, "Count=%u\n", count);
+        }
       }
       write_bsr(ua, bsr->next, fd);
    }
 }
 
-static void print_bsr(UAContext *ua, RBSR *bsr)
+void print_bsr(UAContext *ua, RBSR *bsr)
 {
    if (bsr) {
       for (int i=0; i < bsr->VolCount; i++) {
@@ -296,7 +325,7 @@ void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
    }
 
    /* 
-    * At this point, bsr points to bsr containing JobId,
+    * At this point, bsr points to bsr containing this JobId,
     *  and we are sure that there is at least one fi record.
     */
    lfi = fi = bsr->fi;
@@ -318,6 +347,10 @@ void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
       if (findex == (fi->findex2 + 1)) {  /* extend up */
         RBSR_FINDEX *nfi;     
         fi->findex2 = findex;
+        /*
+         * If the following record contains one higher, merge its
+         *   file index by extending it up.
+         */
         if (fi->next && ((findex+1) == fi->next->findex)) { 
            nfi = fi->next;
            fi->findex2 = nfi->findex2;
index 05f7f1e8841f92caae7fc5c5e52a25a9423f3940..91feaff4bb0f000b8fd699249e9248bea55dab6f 100644 (file)
@@ -145,8 +145,10 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
 
               /* 
                * Now try recycling if necessary
+               *   reason set non-NULL if we cannot use it
+               *   We also check for Volume being expired.
                */
-              is_volume_valid_or_recyclable(jcr, &mr, &reason);
+              check_if_volume_valid_or_recyclable(jcr, &mr, &reason);
            }
         }
         if (reason == NULL) {
@@ -164,7 +166,8 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
             Dmsg2(100, "Vol Info for %s: %s", jcr->Job, bs->msg);
         } else { 
            /* Not suitable volume */
-            bnet_fsend(bs, "1998 Volume \"%s\" %s.\n", mr.VolumeName, reason);
+            bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName, 
+              mr.VolStatus, reason);
         }
 
       } else {
@@ -216,14 +219,6 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
       mr.Slot = sdmr.Slot;
 
-      /*     
-       * Apply expiration periods and limits, if not a label request,
-       *   and ignore status because if !label we won't use it.
-       */
-      if (!label) {
-        has_volume_expired(jcr, &mr);
-      }
-
       Dmsg2(200, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
       /*
        * Write the modified record to the DB
@@ -237,6 +232,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
          bnet_fsend(bs, "1992 Update Media error\n");
          Dmsg0(190, "send error\n");
       }
+      has_volume_expired(jcr, &mr);   /* if expired, change Media record */
       db_unlock(jcr->db);
 
    /*
index eb0a4758ecf612b5e77c7990d39522f240010132..b4130421222ccb25418d89b9b262928c47c2d9b4 100644 (file)
@@ -97,7 +97,6 @@ int main (int argc, char *argv[])
    textdomain("bacula-dir");
    init_msg(NULL, NULL);             /* initialize message handler */
    daemon_start_time = time(NULL);
-   memset(&last_job, 0, sizeof(last_job));
 
    while ((ch = getopt(argc, argv, "c:d:fg:r:stu:v?")) != -1) {
       switch (ch) {
@@ -241,7 +240,7 @@ static void terminate_dird(int sig)
    delete_pid_file(director->pid_directory, "bacula-dir",  
                   director->DIRport);
    stop_watchdog();
-   signal(SIGCHLD, SIG_IGN);          /* don't worry about children now */
+// signal(SIGCHLD, SIG_IGN);          /* don't worry about children now */
    term_scheduler();
    if (runjob) {
       free(runjob);
index 47c9f98581eafa706c18c68aeb837bfea747fa4c..687ab5523cff266e39c1d0f34d40db61e04b8f6e 100644 (file)
@@ -203,6 +203,7 @@ static struct res_items job_items[] = {
    {"pool",     store_res,     ITEM(res_job.pool),     R_POOL, 0, 0},
    {"client",   store_res,     ITEM(res_job.client),   R_CLIENT, 0, 0},
    {"fileset",  store_res,     ITEM(res_job.fileset),  R_FILESET, 0, 0},
+   {"verifyjob",  store_res,   ITEM(res_job.verify_job), R_JOB, 0, 0},
    {"where",    store_dir,     ITEM(res_job.RestoreWhere), 0, 0, 0},
    {"replace",  store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
    {"bootstrap",store_dir,     ITEM(res_job.RestoreBootstrap), 0, 0, 0},
@@ -214,6 +215,7 @@ static struct res_items job_items[] = {
    {"prunevolumes", store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0},
    {"runbeforejob", store_str,  ITEM(res_job.RunBeforeJob), 0, 0, 0},
    {"runafterjob",  store_str,  ITEM(res_job.RunAfterJob),  0, 0, 0},
+   {"runafterfailedjob",  store_str,  ITEM(res_job.RunAfterFailedJob),  0, 0, 0},
    {"clientrunbeforejob", store_str,  ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
    {"clientrunafterjob",  store_str,  ITEM(res_job.ClientRunAfterJob),  0, 0, 0},
    {"spoolattributes", store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0},
@@ -223,6 +225,7 @@ static struct res_items job_items[] = {
    {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
    {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
    {"priority",   store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
+   {"jobretention",  store_time,  ITEM(res_job.JobRetention),  0, 0, 0},
    {NULL, NULL, NULL, 0, 0, 0} 
 };
 
@@ -345,7 +348,10 @@ struct s_jl joblevels[] = {
    {"Catalog",       L_VERIFY_CATALOG,  JT_VERIFY},
    {"InitCatalog",   L_VERIFY_INIT,     JT_VERIFY},
    {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG,   JT_VERIFY},
+   {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG,   JT_VERIFY},
    {"Data",          L_VERIFY_DATA,     JT_VERIFY},
+   {" ",             L_NONE,            JT_ADMIN},
+   {" ",             L_NONE,            JT_RESTORE},
    {NULL,           0}
 };
 
@@ -410,7 +416,7 @@ char *level_to_str(int level)
 void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
 {
    URES *res = (URES *)reshdr;
-   int recurse = 1;
+   bool recurse = true;
    char ed1[100], ed2[100];
 
    if (res == NULL) {
@@ -419,7 +425,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
    }
    if (type < 0) {                   /* no recursion */
       type = - type;
-      recurse = 0;
+      recurse = false;
    }
    switch (type) {
    case R_DIRECTOR:
@@ -483,7 +489,8 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
         res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user));
       break;
    case R_JOB:
-      sendit(sock, "Job: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n", 
+      sendit(sock, "%s: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n", 
+         type == R_JOB ? "Job" : "JobDefs",
         res->res_job.hdr.name, res->res_job.JobType, 
         level_to_str(res->res_job.level), res->res_job.Priority,
         res->res_job.MaxConcurrentJobs);
@@ -514,6 +521,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
       if (res->res_job.RunAfterJob) {
          sendit(sock, "  --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob));
       }
+      if (res->res_job.RunAfterFailedJob) {
+         sendit(sock, "  --> RunAfterFailed=%s\n", NPRT(res->res_job.RunAfterFailedJob));
+      }
       if (res->res_job.WriteBootstrap) {
          sendit(sock, "  --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap));
       }
@@ -527,6 +537,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
       } else {
          sendit(sock, "!!! No Pool resource\n");
       }
+      if (res->res_job.verify_job) {
+         sendit(sock, "  --> ");
+        dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
+      }
+      break;
       if (res->res_job.messages) {
          sendit(sock, "  --> ");
         dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
@@ -565,43 +580,52 @@ next_run:
               bstrncat(buf, num, sizeof(buf));
            }
         }
-         strcat(buf, "\n");
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-         strcpy(buf, "      mday=");
+         bstrncpy(buf, "      mday=", sizeof(buf));
         for (i=0; i<31; i++) {
            if (bit_is_set(i, run->mday)) {
                sprintf(num, "%d ", i+1);
-              strcat(buf, num);
+              bstrncat(buf, num, sizeof(buf));
            }
         }
-         strcat(buf, "\n");
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-         strcpy(buf, "      month=");
+         bstrncpy(buf, "      month=", sizeof(buf));
         for (i=0; i<12; i++) {
            if (bit_is_set(i, run->month)) {
                sprintf(num, "%d ", i+1);
-              strcat(buf, num);
+              bstrncat(buf, num, sizeof(buf));
            }
         }
-         strcat(buf, "\n");
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-         strcpy(buf, "      wday=");
+         bstrncpy(buf, "      wday=", sizeof(buf));
         for (i=0; i<7; i++) {
            if (bit_is_set(i, run->wday)) {
                sprintf(num, "%d ", i+1);
-              strcat(buf, num);
+              bstrncat(buf, num, sizeof(buf));
            }
         }
-         strcat(buf, "\n");
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-         strcpy(buf, "      wpos=");
+         bstrncpy(buf, "      wom=", sizeof(buf));
         for (i=0; i<5; i++) {
-           if (bit_is_set(i, run->wpos)) {
+           if (bit_is_set(i, run->wom)) {
                sprintf(num, "%d ", i+1);
-              strcat(buf, num);
+              bstrncat(buf, num, sizeof(buf));
            }
         }
-         strcat(buf, "\n");
+         bstrncat(buf, "\n", sizeof(buf));
+        sendit(sock, buf);
+         bstrncpy(buf, "      woy=", sizeof(buf));
+        for (i=0; i<54; i++) {
+           if (bit_is_set(i, run->woy)) {
+               sprintf(num, "%d ", i);
+              bstrncat(buf, num, sizeof(buf));
+           }
+        }
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
          sendit(sock, "      mins=%d\n", run->minute);
         if (run->pool) {
@@ -830,6 +854,9 @@ void free_resource(int type)
       if (res->res_job.RunAfterJob) {
         free(res->res_job.RunAfterJob);
       }
+      if (res->res_job.RunAfterFailedJob) {
+        free(res->res_job.RunAfterFailedJob);
+      }
       if (res->res_job.ClientRunBeforeJob) {
         free(res->res_job.ClientRunBeforeJob);
       }
@@ -916,15 +943,17 @@ void save_resource(int type, struct res_items *items, int pass)
         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_ERROR_TERM, 0, "Cannot find Job resource %s\n", res_all.res_dir.hdr.name);
+        if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
+            Emsg1(M_ERROR_TERM, 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.fileset  = res_all.res_job.fileset;
-        res->res_job.storage  = res_all.res_job.storage;
-        res->res_job.pool     = res_all.res_job.pool;
+        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.fileset    = res_all.res_job.fileset;
+        res->res_job.storage    = res_all.res_job.storage;
+        res->res_job.pool       = res_all.res_job.pool;
+        res->res_job.verify_job = res_all.res_job.verify_job;
         if (res->res_job.JobType == 0) {
             Emsg1(M_ERROR_TERM, 0, "Job Type not defined for Job resource %s\n", res_all.res_dir.hdr.name);
         }
index 5c4aad6b66570ad8d41efdc3c7fd71fbccffdf5c..5fe488885ea94529b6179f345c4a5be032f3e559 100644 (file)
@@ -185,6 +185,7 @@ struct JOB {
    char *RestoreBootstrap;            /* Bootstrap file */
    char *RunBeforeJob;                /* Run program before Job */
    char *RunAfterJob;                 /* Run program after Job */
+   char *RunAfterFailedJob;           /* Run program after Job that errs */
    char *ClientRunBeforeJob;          /* Run client program before Job */
    char *ClientRunAfterJob;           /* Run client program after Job */
    char *WriteBootstrap;              /* Where to write bootstrap Job updates */
@@ -200,6 +201,7 @@ struct JOB {
    int RescheduleOnError;             /* Set to reschedule on error */
    int RescheduleTimes;               /* Number of times to reschedule job */
    utime_t RescheduleInterval;        /* Reschedule interval */
+   utime_t JobRetention;              /* job retention period in seconds */
   
    MSGS      *messages;               /* How and where to send messages */
    SCHED     *schedule;               /* When -- Automatic schedule */
@@ -207,6 +209,7 @@ struct JOB {
    FILESET   *fileset;                /* What to backup -- Fileset */
    STORE     *storage;                /* Where is device -- Storage daemon */
    POOL      *pool;                   /* Where is media -- Media Pool */
+   JOB       *verify_job;             /* Job name to verify */
    uint32_t NumConcurrentJobs;        /* number of concurrent jobs running */
 };
 
@@ -345,5 +348,6 @@ struct RUN {
    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 */
-   char wpos[nbytes_for_bits(5)];     /* week position */
+   char wom[nbytes_for_bits(5)];      /* week of month */
+   char woy[nbytes_for_bits(54)];     /* week of year */
 };
index 4d7f1e25b970dfe32d556b46c425a37155bc62ff..5fbfaf54eeef11e5a8ba81c82125092e7155dd13 100644 (file)
@@ -155,7 +155,7 @@ void get_level_since_time(JCR *jcr, char *since, int since_len)
          bstrncpy(since, ", since=", since_len);
         bstrncat(since, jcr->stime, since_len);
       }
-      Dmsg1(115, "Last start time = %s\n", jcr->stime);
+      Dmsg1(100, "Last start time = %s\n", jcr->stime);
       break;
    }
 }
@@ -236,6 +236,7 @@ static int send_list(JCR *jcr, int list)
         p = (char *)ie->name_list.get(j);
         switch (*p) {
          case '|':
+           p++;                      /* skip over the | */
             fd->msg = edit_job_codes(jcr, fd->msg, p, "");
             bpipe = open_bpipe(fd->msg, 0, "r");
            if (!bpipe) {
@@ -250,6 +251,7 @@ static int send_list(JCR *jcr, int list)
            } else {
                bstrncpy(buf, "0 ", sizeof(buf));
            }
+            Dmsg1(100, "Opts=%s\n", buf);
            optlen = strlen(buf);
            while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) {
                fd->msglen = Mmsg(&fd->msg, "%s", buf);
@@ -279,6 +281,7 @@ static int send_list(JCR *jcr, int list)
            } else {
                bstrncpy(buf, "0 ", sizeof(buf));
            }
+            Dmsg1(100, "Opts=%s\n", buf);
            optlen = strlen(buf);
            while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) {
                fd->msglen = Mmsg(&fd->msg, "%s", buf);
@@ -293,15 +296,15 @@ static int send_list(JCR *jcr, int list)
             p++;                      /* skip over \ */
            /* Note, fall through wanted */
         default:
+            Dmsg2(100, "numopts=%d opts=%s\n", ie->num_opts, NPRT(ie->opts_list[0]->opts));
            if (ie->num_opts) {
               pm_strcpy(&fd->msg, ie->opts_list[0]->opts);
                pm_strcat(&fd->msg, " ");
            } else {
                pm_strcpy(&fd->msg, "0 ");
            }
-           pm_strcat(&fd->msg, p);
+           fd->msglen = pm_strcat(&fd->msg, p);
             Dmsg1(100, "Inc/Exc name=%s\n", fd->msg);
-           fd->msglen = strlen(fd->msg);
            if (!bnet_send(fd)) {
                Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
               goto bail_out;
index b2309f37091e4b5e511430ad9bf2390b83fcf78c..a4d71bc4c7c829d914e1a80dfb60176621164a3a 100644 (file)
@@ -95,7 +95,8 @@ int bget_dirmsg(BSOCK *bs)
            bnet_fsend(bs, OK_msg); /* send response */
            break;
         case BNET_HEARTBEAT:
-       /*   Dmsg0(000, "Got heartbeat.\n"); */
+//         encode_time(time(NULL), Job);
+//          Dmsg1(100, "%s got heartbeat.\n", Job);
            break;
         case BNET_HB_RESPONSE:
            break;
@@ -104,6 +105,10 @@ int bget_dirmsg(BSOCK *bs)
             bnet_fsend(bs, "Status OK\n");
            bnet_sig(bs, BNET_EOD);
            break;
+       case BNET_BTIME:             /* send Bacula time */
+          char ed1[50];
+            bnet_fsend(bs, "btime %s\n", edit_uint64(get_current_btime(),ed1));
+           break;
         default:
             Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
            return n;
index bacd5bbead282d35aeaadcc806b85ff6f5934889..1e9c69c694451b354e64a99860d1c538b6ebc747 100644 (file)
@@ -151,8 +151,9 @@ static struct s_fs_opt FS_options[] = {
 
 
 /* 
- * Scan for old Include options (keyword=option) is converted into one or
- *  two characters. Verifyopts=xxxx is Vxxxx:
+ * Scan for right hand side of Include options (keyword=option) is 
+ *    converted into one or two characters. Verifyopts=xxxx is Vxxxx:
+ *    Whatever is found is concatenated to the opts string.
  */
 static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
 {
@@ -167,6 +168,7 @@ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
       bstrncat(opts, "V", optlen);         /* indicate Verify */
       bstrncat(opts, lc->str, optlen);
       bstrncat(opts, ":", optlen);         /* terminate it */
+      Dmsg3(100, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
 
    /*
     * Standard keyword options for Include/Exclude 
@@ -185,7 +187,7 @@ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen)
          scan_err1(lc, "Expected a FileSet option keyword, got:%s:", lc->str);
       } else { /* add option */
         bstrncat(opts, option, optlen);
-         Dmsg3(200, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
+         Dmsg3(100, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen);
       }
    }
 
@@ -238,6 +240,7 @@ void store_inc(LEX *lc, struct res_items *item, int index, int pass)
       if ((token=lex_get_token(lc, T_ALL)) != T_EQUALS) {
          scan_err1(lc, _("expected an = following keyword, got: %s"), lc->str);
       } else {
+        /* Scan right hand side of option */
         scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
       }
       if (token == T_BOB) {
@@ -258,7 +261,7 @@ void store_inc(LEX *lc, struct res_items *item, int index, int pass)
       }
       setup_current_opts();
       bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
-      Dmsg1(200, "incexe opts=%s\n", res_incexe.current_opts->opts);
+      Dmsg2(100, "old pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
 
       /* Create incexe structure */
       Dmsg0(200, "Create INCEXE structure\n");
@@ -472,7 +475,9 @@ static void store_fname(LEX *lc, struct res_items *item, int index, int pass)
    scan_to_eol(lc);
 }
 
-
+/*
+ * New style options come here
+ */
 static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
 {
    int i;
@@ -481,6 +486,7 @@ static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
 
    inc_opts[0] = 0;
    keyword = INC_KW_NONE;
+   /* Look up the keyword */
    for (i=0; FS_option_kw[i].name; i++) {
       if (strcasecmp(item->name, FS_option_kw[i].name) == 0) {
         keyword = FS_option_kw[i].token;
@@ -490,14 +496,13 @@ static void store_opts(LEX *lc, struct res_items *item, int index, int pass)
    if (keyword == INC_KW_NONE) {
       scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
    }
-   Dmsg2(200, "keyword=%d %s\n", keyword, FS_option_kw[keyword].name);
+   /* Now scan for the value */
    scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
-
    if (pass == 1) {
       setup_current_opts();
-      bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
+      bstrncpy(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS);
+      Dmsg2(100, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts);
    }
-
    scan_to_eol(lc);
 }
 
index 597edcfafb23d214c17d0eec187cc22dcdf3945c..e84a6422ccb1ee96e5cdbe9c52ed962f7ac3f6a4 100644 (file)
@@ -206,13 +206,18 @@ static void *job_thread(void *arg)
             Pmsg1(0, "Unimplemented job type: %d\n", jcr->JobType);
            break;
         }
-        if (jcr->job->RunAfterJob) {
+        if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
+            (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
            POOLMEM *after = get_pool_memory(PM_FNAME);
            int status;
            BPIPE *bpipe;
            char line[MAXSTRING];
            
-            after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
+           if (jcr->JobStatus == JS_Terminated) {
+               after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
+           } else {
+               after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
+           }
             bpipe = open_bpipe(after, 0, "r");
            free_pool_memory(after);
            while (fgets(line, sizeof(line), bpipe->rfd)) {
@@ -220,8 +225,13 @@ static void *job_thread(void *arg)
            }
            status = close_bpipe(bpipe);
            if (status != 0) {
-               Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"),
-                 status);
+              if (jcr->JobStatus == JS_Terminated) {
+                  Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"),
+                      status);
+              } else {
+                  Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob returned non-zero status=%d\n"),
+                      status);
+              }
               set_jcr_job_status(jcr, JS_FatalError);
               update_job_end_record(jcr);
            }
@@ -397,7 +407,15 @@ void set_jcr_defaults(JCR *jcr, JOB *job)
 {
    jcr->job = job;
    jcr->JobType = job->JobType;
-   jcr->JobLevel = job->level;
+   switch (jcr->JobType) {
+   case JT_ADMIN:
+   case JT_RESTORE:
+      jcr->JobLevel = L_NONE;
+      break;
+   default:
+      jcr->JobLevel = job->level;
+      break;
+   }
    jcr->JobPriority = job->Priority;
    jcr->store = job->storage;
    jcr->client = job->client;
@@ -411,6 +429,7 @@ void set_jcr_defaults(JCR *jcr, JOB *job)
    jcr->messages = job->messages; 
    if (jcr->RestoreBootstrap) {
       free(jcr->RestoreBootstrap);
+      jcr->RestoreBootstrap = NULL;
    }
    /* This can be overridden by Console program */
    if (job->RestoreBootstrap) {
@@ -427,7 +446,7 @@ void set_jcr_defaults(JCR *jcr, JOB *job)
         break;
       case JT_RESTORE:
       case JT_ADMIN:
-        jcr->JobLevel = L_FULL;
+        jcr->JobLevel = L_NONE;
         break;
       default:
         break;
index 304cfd53365d9cf4f563d744160ba3d0db884bb2..1f3d42bb9c7772b9a42008579cfda1e4aac114c9 100644 (file)
@@ -95,7 +95,6 @@ int start_storage_daemon_job(JCR *jcr)
    BSOCK *sd;
    char auth_key[100];
    POOLMEM *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;
@@ -136,24 +135,18 @@ int start_storage_daemon_job(JCR *jcr)
    /*
     * 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 = get_memory(device_name_len);
-   pool_name = get_memory(pool_name_len);
-   pool_type = get_memory(pool_type_len);
-   media_type = 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);
+   device_name = get_pool_memory(PM_NAME);
+   pool_name = get_pool_memory(PM_NAME);
+   pool_type = get_pool_memory(PM_NAME);
+   media_type = get_pool_memory(PM_NAME);
+   pm_strcpy(&device_name, storage->dev_name);
+   pm_strcpy(&media_type, storage->media_type);
+   pm_strcpy(&pool_type, jcr->pool->pool_type);
+   pm_strcpy(&pool_name, jcr->pool->hdr.name);
    bash_spaces(device_name);
    bash_spaces(media_type);
    bash_spaces(pool_type);
    bash_spaces(pool_name);
-   sd->msg = 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(110, ">stored: %s", sd->msg);
    status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY);
@@ -163,7 +156,6 @@ int start_storage_daemon_job(JCR *jcr)
          "     Storage daemon didn't accept Device \"%s\" because:\n     %s"),
         device_name, pool_type/* sd->msg */);
    }
-         
    free_memory(device_name);
    free_memory(media_type);
    free_memory(pool_name);
index 043fd1ac93ad646d07b9e53c5630432b3853a7bf..a27a0ad865b9f9e76df73a20dfd78928c49be2c7 100644 (file)
@@ -69,6 +69,9 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create)
            }
         }
 
+        /* 
+          * Don't do a purge if called from a command i.e. create == 0.
+         */ 
         if (!ok && (jcr->pool->purge_oldest_volume ||
                     jcr->pool->recycle_oldest_volume)) {
             Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
@@ -81,10 +84,10 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create)
                Dmsg0(400, "Try purge.\n");
               /* Try to purge oldest volume */
               ua = new_ua_context(jcr);
-              if (jcr->pool->purge_oldest_volume) {
+              if (jcr->pool->purge_oldest_volume && create) {
                   Jmsg(jcr, M_INFO, 0, _("Purging oldest volume \"%s\"\n"), mr->VolumeName);
                  ok = purge_jobs_from_volume(ua, mr);
-              } else {
+              } else if (jcr->pool->recycle_oldest_volume) {
                   Jmsg(jcr, M_INFO, 0, _("Pruning oldest volume \"%s\"\n"), mr->VolumeName);
                  ok = prune_volume(ua, mr);
               }
@@ -100,11 +103,6 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create)
       if (ok) {
         /* If we can use the volume, check if it is expired */
         if (has_volume_expired(jcr, mr)) {
-           /* Need to update media */
-           if (!db_update_media_record(jcr, jcr->db, mr)) {
-               Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"),
-                   mr->VolumeName, db_strerror(jcr->db));
-           }           
            if (retry++ < 200) {            /* sanity check */
               continue;                    /* try again from the top */
            } else {
@@ -172,6 +170,13 @@ bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr)
         }
       }
    }
+   if (expired) {
+      /* Need to update media */
+      if (!db_update_media_record(jcr, jcr->db, mr)) {
+         Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"),
+             mr->VolumeName, db_strerror(jcr->db));
+      }          
+   }  
    return expired;
 }
 
@@ -181,39 +186,44 @@ bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr)
  *  Returns: on failure - reason = NULL
  *          on success - reason - pointer to reason
  */
-bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason)
+void check_if_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason)
 {
    int ok;
 
    *reason = NULL;
 
    /*  Check if a duration or limit has expired */
-   has_volume_expired(jcr, mr);
+   if (has_volume_expired(jcr, mr)) {
+      *reason = "volume has expired";
+      /* Keep going because we may be able to recycle volume */
+   }
 
    /*
     * Now see if we can use the volume as is
     */
    if (strcmp(mr->VolStatus, "Append") == 0 ||
        strcmp(mr->VolStatus, "Recycle") == 0) {
-      return true;
+      *reason = NULL;
+      return;
    }
                                                                                        
    /*
-    * Check if the Volume is alreay marked for recycling
+    * Check if the Volume is already marked for recycling
     */
    if (strcmp(mr->VolStatus, "Purged") == 0) {
       if (recycle_volume(jcr, mr)) {
          Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
-        return true;
+        *reason = NULL;
+        return;
       } else {
          /* In principle this shouldn't happen */
-         *reason = "recycling of current volume failed";
-        return false;
+         *reason = "and recycling of current volume failed";
+        return;
       }
    }
                                                                                        
    /* At this point, the volume is not valid for writing */
-   *reason = "not Append, Purged or Recycle";
+   *reason = "but should be Append, Purged or Recycle";
                                                                                        
    /*
     * What we're trying to do here is see if the current volume is
@@ -239,15 +249,14 @@ bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason)
         /* If fully purged, recycle current volume */
         if (recycle_volume(jcr, mr)) {
             Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
-           return true;               /* Good volume */
+           *reason = NULL;
         } else {
-            *reason = "not Append, Purged or Recycle (recycling of the "
+            *reason = "but should be Append, Purged or Recycle (recycling of the "
                "current volume failed)";
         }
       } else {
-         *reason = "not Append, Purged or Recycle (cannot automatically "
+         *reason = "but should be Append, Purged or Recycle (cannot automatically "
             "recycle current volume, as it still contains unpruned data)";
       }
    }
-   return *reason ? false : true;
 }
index a4b48609dec3bebc46cb4fb83b121f3f49063c0a..38878c7f7b6eb4664dbae37de356f024287c127a 100644 (file)
@@ -102,7 +102,7 @@ extern void wait_for_storage_daemon_termination(JCR *jcr);
 /* next_vol.c */
 int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create);
 bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr);
-bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason);
+void check_if_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason);
 
 /* newvol.c */
 int newVolume(JCR *jcr, MEDIA_DBR *mr);
@@ -132,6 +132,7 @@ int is_volume_name_legal(UAContext *ua, char *name);
 /* ua_output.c */
 void prtit(void *ctx, char *msg);
 int complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool);
+RUN *find_next_run(RUN *run, JOB *job, time_t &runtime);
 
 /* ua_server.c */
 void bsendmsg(void *sock, char *fmt, ...);
index b40a5dc09c2c39197b03d8763d323683b4d12262..21ad8c0a2b9877f63a53cb3425ad85f7173681aa 100644 (file)
@@ -73,7 +73,7 @@ int do_restore(JCR *jcr)
    }
 
    memset(&rjr, 0, sizeof(rjr));
-   jcr->jr.Level = 'F';            /* Full restore */
+   jcr->jr.Level = L_FULL;        /* Full restore */
    jcr->jr.StartTime = jcr->start_time;
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
@@ -88,6 +88,7 @@ int do_restore(JCR *jcr)
    /* 
     * The following code is kept temporarily for compatibility.
     * It is the predecessor to the Bootstrap file.
+    *  DEPRECATED
     */
    if (!jcr->RestoreBootstrap) {
       /*
@@ -286,14 +287,18 @@ static void restore_cleanup(JCR *jcr, int TermCode)
       msg_type = M_ERROR;         /* Generate error message */
       if (jcr->store_bsock) {
         bnet_sig(jcr->store_bsock, BNET_TERMINATE);
-        pthread_cancel(jcr->SD_msg_chan);
+        if (jcr->SD_msg_chan) {
+           pthread_cancel(jcr->SD_msg_chan);
+        }
       }
       break;
    case JS_Canceled:
       term_msg = _("Restore Canceled");
       if (jcr->store_bsock) {
         bnet_sig(jcr->store_bsock, BNET_TERMINATE);
-        pthread_cancel(jcr->SD_msg_chan);
+        if (jcr->SD_msg_chan) {
+           pthread_cancel(jcr->SD_msg_chan);
+        }
       }
       break;
    default:
@@ -324,7 +329,7 @@ End time:               %s\n\
 Files Restored:         %s\n\
 Bytes Restored:         %s\n\
 Rate:                   %.1f KB/s\n\
-Non-fatal FD Errors:    %d\n\
+FD Errors:              %d\n\
 FD termination status:  %s\n\
 SD termination status:  %s\n\
 Termination:            %s\n\n"),
index d08d9e315b17833c150b0aa9e14ab8d11399e85c..66fafec301403240ae131b9a79fc454203cf3395 100644 (file)
@@ -47,7 +47,8 @@ enum e_state {
    s_weekly,
    s_monthly,
    s_hourly,
-   s_wpos,                           /* 1st, 2nd, ...*/
+   s_wom,                          /* 1st, 2nd, ...*/
+   s_woy,                          /* week of year w00 - w53 */
 };  
 
 struct s_keyw {
@@ -105,59 +106,48 @@ static struct s_keyw keyw[] = {
   {N_("monthly"),    s_monthly, 0},
   {N_("hourly"),     s_hourly,  0},
 
-  {N_("1st"),        s_wpos,    0},
-  {N_("2nd"),        s_wpos,    1},
-  {N_("3rd"),        s_wpos,    2},
-  {N_("4th"),        s_wpos,    3},
-  {N_("5th"),        s_wpos,    4},
-
-  {N_("first"),      s_wpos,    0},
-  {N_("second"),     s_wpos,    1},
-  {N_("third"),      s_wpos,    2},
-  {N_("fourth"),     s_wpos,    3},
-  {N_("fifth"),      s_wpos,    4},
+  {N_("1st"),        s_wom,     0},
+  {N_("2nd"),        s_wom,     1},
+  {N_("3rd"),        s_wom,     2},
+  {N_("4th"),        s_wom,     3},
+  {N_("5th"),        s_wom,     4},
+
+  {N_("first"),      s_wom,     0},
+  {N_("second"),     s_wom,     1},
+  {N_("third"),      s_wom,     2},
+  {N_("fourth"),     s_wom,     3},
+  {N_("fifth"),      s_wom,     4},
   {NULL,        s_none,    0}
 };
 
-static int have_hour, have_mday, have_wday, have_month, have_wpos;
-static int have_at;
+static bool have_hour, have_mday, have_wday, have_month, have_wom;
+static bool have_at, have_woy;
 static RUN lrun;
 
 static void clear_defaults()
 {
-   have_hour = have_mday = have_wday = have_month = have_wpos = TRUE;
+   have_hour = have_mday = have_wday = have_month = have_wom = have_woy = true;
    clear_bit(0,lrun.hour);
    clear_bits(0, 30, lrun.mday);
    clear_bits(0, 6, lrun.wday);
    clear_bits(0, 11, lrun.month);
-   clear_bits(0, 4, lrun.wpos);
+   clear_bits(0, 4, lrun.wom);
+   clear_bits(0, 53, lrun.woy);
 }
 
 static void set_defaults()
 {
-   have_hour = have_mday = have_wday = have_month = have_wpos = FALSE;
-   have_at = FALSE;
+   have_hour = have_mday = have_wday = have_month = have_wom = have_woy = 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);
-   set_bits(0, 4, lrun.wpos);
+   set_bits(0, 4, lrun.wom);
+   set_bits(0, 53, lrun.woy);
 }
 
 
-/* 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;
-}
-
 /* Keywords (RHS) permitted in Run records */
 static struct s_kw RunFields[] = {
    {"pool",     'P'},
@@ -183,7 +173,8 @@ static struct s_kw RunFields[] = {
  */
 void store_run(LEX *lc, struct res_items *item, int index, int pass)
 {
-   int i, j, found;
+   int i, j;
+   bool found;
    int token, state, state2 = 0, code = 0, code2 = 0;
    int options = lc->options;
    RUN **run = (RUN **)(item->value);  
@@ -198,12 +189,12 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass)
    memset(&lrun, 0, sizeof(RUN));
 
    /* scan for Job level "full", "incremental", ... */
-   for (found=TRUE; found; ) {
-      found = FALSE;
+   for (found=true; found; ) {
+      found = false;
       token = lex_get_token(lc, T_NAME);
       for (i=0; RunFields[i].name; i++) {
         if (strcasecmp(lc->str, RunFields[i].name) == 0) {
-           found = TRUE;
+           found = true;
            if (lex_get_token(lc, T_ALL) != T_EQUALS) {
                scan_err1(lc, "Expected an equals, got: %s", lc->str);
               /* NOT REACHED */ 
@@ -281,7 +272,7 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass)
         if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
            lrun.level = joblevels[j].level;
            lrun.job_type = joblevels[j].job_type;
-           found = TRUE;
+           found = true;
            break;
         }
       }
@@ -298,243 +289,284 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass)
    for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
       int len, pm = 0;
       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)"));
-           }
+      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_NAME:                /* this handles drop through from keyword */
+      case T_UNQUOTED_STRING:
+         if (strchr(lc->str, (int)'-')) {
+           state = s_range;
            break;
-        case T_NAME:                 /* this handles drop through from keyword */
-        case T_UNQUOTED_STRING:
-            if (strchr(lc->str, (int)'-')) {
-              state = s_range;
-              break;
+        }
+         if (strchr(lc->str, (int)':')) {
+           state = s_time;
+           break;
+        }
+         if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
+            is_an_integer(lc->str+1)) {
+           code = atoi(lc->str+1);
+           if (code < 0 || code > 53) {
+               scan_err0(lc, _("Week number out of range (0-53)"));
            }
-            if (strchr(lc->str, (int)':')) {
-              state = s_time;
+           state = s_woy;            /* week of year */
+           break;
+        }
+        /* everything else must be a keyword */
+        for (i=0; keyw[i].name; i++) {
+           if (strcasecmp(lc->str, keyw[i].name) == 0) {
+              state = keyw[i].state;
+              code   = keyw[i].code;
+              i = 0;
               break;
            }
-           /* everything else must be a keyword */
-           for (i=0; keyw[i].name; i++) {
-              if (strcasecmp(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);
-              /* NOT REACHED */
-           }
-           break;
-        case T_COMMA:
-           continue;
-        default:
-            scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
+        }
+        if (i != 0) {
+            scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
            /* NOT REACHED */
-           break;
+        }
+        break;
+      case T_COMMA:
+        continue;
+      default:
+         scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
+        /* NOT REACHED */
+        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;
+      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_wom:                 /* Week of month 1st, ... */
+        if (!have_wom) {
+           clear_bits(0, 4, lrun.wom);
+           have_wom = true;
+        }
+        set_bit(code, lrun.wom);
+        break;
+      case s_woy:
+        if (!have_woy) {
+           clear_bits(0, 53, lrun.woy);
+           have_woy = true;
+        }
+        set_bit(code, lrun.woy);
+        break;
+      case s_time:                /* time */
+        if (!have_at) {
+            scan_err0(lc, _("Time must be preceded by keyword AT."));
+           /* NOT REACHED */
+        }
+        if (!have_hour) {
+           clear_bit(0, lrun.hour);
+        }
+         p = strchr(lc->str, ':');
+        if (!p)  {
+            scan_err0(lc, _("Time logic error.\n"));
+           /* NOT REACHED */
+        }
+        *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."));
+              /* NOT REACHED */
            }
-           set_bit(code, lrun.mday);
-           break;
-        case s_month:                /* month of year */
-           if (!have_month) {
-              clear_bits(0, 11, lrun.month);
-              have_month = TRUE;
+        } 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."));
+           /* NOT REACHED */
+        }
+        set_bit(code, lrun.hour);
+        lrun.minute = code2;
+        have_hour = true;
+        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_an_integer(lc->str) && is_an_integer(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."));
            }
-           set_bit(code, lrun.month);
-           break;
-        case s_wday:                 /* week day */
-           if (!have_wday) {
-              clear_bits(0, 6, lrun.wday);
+           if (!have_mday) {
               clear_bits(0, 30, lrun.mday);
-              have_wday = TRUE;
+              clear_bits(0, 6, lrun.wday);
+              have_mday = true;
            }
-           set_bit(code, lrun.wday);
-           break;
-        case s_wpos:                 /* Week position 1st, ... */
-           if (!have_wpos) {
-              clear_bits(0, 4, lrun.wpos);
-              have_wpos = TRUE;
+           if (code < code2) {
+              set_bits(code, code2, lrun.mday);
+           } else {
+              set_bits(code, 30, lrun.mday);
+              set_bits(0, code2, lrun.mday);
            }
-           set_bit(code, lrun.wpos);
            break;
-        case s_time:                 /* time */
-           if (!have_at) {
-               scan_err0(lc, _("Time must be preceded by keyword AT."));
-              /* NOT REACHED */
-           }
-           if (!have_hour) {
-              clear_bit(0, lrun.hour);
+        }
+        /* Check for week of year range */
+        if (strlen(lc->str) == 3 && strlen(p) == 3 &&
+             (lc->str[0] == 'w' || lc->str[0] == 'W') &&
+             (p[0] == 'w' || p[0] == 'W') &&
+            is_an_integer(lc->str+1) && is_an_integer(p+1)) {
+           code = atoi(lc->str+1);
+           code2 = atoi(p+1);
+           if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
+               scan_err0(lc, _("Week number out of range (0-53)"));
            }
-            p = strchr(lc->str, ':');
-           if (!p)  {
-               scan_err0(lc, _("Time logic error.\n"));
-              /* NOT REACHED */
+           if (!have_woy) {
+              clear_bits(0, 53, lrun.woy);
+              have_woy = true;
            }
-           *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."));
-                 /* NOT REACHED */
-              }
+           if (code < code2) {
+              set_bits(code, code2, lrun.woy);
            } else {
-              pm = 0;
+              set_bits(code, 53, lrun.woy);
+              set_bits(0, code2, lrun.woy);
            }
-           code2 = atoi(p);
-           if (pm) {
-              code += 12;
-           }
-           if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
-               scan_err0(lc, _("Bad time specification."));
-              /* NOT REACHED */
-           }
-           set_bit(code, lrun.hour);
-           lrun.minute = code2;
-           have_hour = TRUE;
-           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);
-              }
+        }
+        /* 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 && state != s_wom)) {
+            scan_err0(lc, _("Invalid month, week or position day range"));
+           /* NOT REACHED */
+        }
 
-           /* 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;
-              }
+        /* 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 != s_month && state != s_wday && state != s_wpos)) {
-               scan_err0(lc, _("Invalid month, week or position day range"));
-              /* NOT REACHED */
+        }
+        if (i != 0 || state != state2 || code == code2) {
+            scan_err0(lc, _("Invalid month, weekday or position range"));
+           /* NOT REACHED */
+        }
+        if (state == s_wday) {
+           if (!have_wday) {
+              clear_bits(0, 6, lrun.wday);
+              clear_bits(0, 30, lrun.mday);
+              have_wday = true;
            }
-
-           /* 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 (code < code2) {
+              set_bits(code, code2, lrun.wday);
+           } else {
+              set_bits(code, 6, lrun.wday);
+              set_bits(0, code2, lrun.wday);
            }
-           if (i != 0 || state != state2 || code == code2) {
-               scan_err0(lc, _("Invalid month, weekday or position range"));
-              /* NOT REACHED */
+        } else if (state == s_month) {
+           if (!have_month) {
+              clear_bits(0, 30, lrun.month);
+              have_month = true;
            }
-           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 if (state == 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);
-              }
+           if (code < code2) {
+              set_bits(code, code2, lrun.month);
            } else {
-              /* Must be position */
-              if (!have_wpos) {
-                 clear_bits(0, 4, lrun.wpos);
-                 have_wpos = TRUE;
-              }
-              if (code < code2) {
-                 set_bits(code, code2, lrun.wpos);
-              } else {
-                 set_bits(code, 4, lrun.wpos);
-                 set_bits(0, code2, lrun.wpos);
-              }
-           }                      
-           break;
-        case s_hourly:
-           clear_defaults();
-           set_bits(0, 23, lrun.hour);
-           set_bits(0, 30, lrun.mday);
-           set_bits(0, 11, lrun.month);
-           set_bits(0, 4, lrun.wpos);
-           break;
-        case s_weekly:
-           clear_defaults();
-           set_bit(0, lrun.wday);
-           set_bits(0, 11, lrun.month);
-           set_bits(0, 4, lrun.wpos);
-           break;
-        case s_daily:
-           clear_defaults();
-           set_bits(0, 30, lrun.mday);
-           set_bits(0, 11, lrun.month);
-           set_bits(0, 4,  lrun.wpos);
-           break;
-        case s_monthly:
-           clear_defaults();
-           set_bits(0, 11, lrun.month);
-           set_bits(0, 4,  lrun.wpos);
-           break;
-        default:
-            scan_err0(lc, _("Unexpected run state\n"));
-           /* NOT REACHED */
-           break;
+              /* this is a bit odd, but we accept it anyway */
+              set_bits(code, 30, lrun.month);
+              set_bits(0, code2, lrun.month);
+           }
+        } else {
+           /* Must be position */
+           if (!have_wom) {
+              clear_bits(0, 4, lrun.wom);
+              have_wom = true;
+           }
+           if (code < code2) {
+              set_bits(code, code2, lrun.wom);
+           } else {
+              set_bits(code, 4, lrun.wom);
+              set_bits(0, code2, lrun.wom);
+           }
+        }                      
+        break;
+      case s_hourly:
+        clear_defaults();
+        set_bits(0, 23, lrun.hour);
+        set_bits(0, 30, lrun.mday);
+        set_bits(0, 11, lrun.month);
+        set_bits(0, 4, lrun.wom);
+        set_bits(0, 53, lrun.woy);
+        break;
+      case s_weekly:
+        clear_defaults();
+        set_bit(0, lrun.wday);
+        set_bits(0, 11, lrun.month);
+        set_bits(0, 4, lrun.wom);
+        set_bits(0, 53, lrun.woy);
+        break;
+      case s_daily:
+        clear_defaults();
+        set_bits(0, 30, lrun.mday);
+        set_bits(0, 11, lrun.month);
+        set_bits(0, 4,  lrun.wom);
+        set_bits(0, 53, lrun.woy);
+        break;
+      case s_monthly:
+        clear_defaults();
+        set_bits(0, 11, lrun.month);
+        set_bits(0, 4,  lrun.wom);
+        set_bits(0, 53, lrun.woy);
+        break;
+      default:
+         scan_err0(lc, _("Unexpected run state\n"));
+        /* NOT REACHED */
+        break;
       }
    }
 
index 5633fb3294da4e9445060eb61f00ad9f39c8a410..ebb63ddec337a0b3db2fd9bc78adba6045687edb 100644 (file)
@@ -189,7 +189,7 @@ static void find_runs()
    JOB *job;
    SCHED *sched;
    struct tm tm;
-   int hour, next_hour, minute, mday, wday, month, wpos;
+   int hour, next_hour, minute, mday, wday, month, wom, woy;
 
    Dmsg0(200, "enter find_runs()\n");
    num_runjobs = 0;
@@ -205,7 +205,8 @@ static void find_runs()
    mday = tm.tm_mday - 1;
    wday = tm.tm_wday;
    month = tm.tm_mon;
-   wpos = (tm.tm_mday - 1) / 7; 
+   wom = mday / 7;
+   woy = tm_woy(now);                    /* get week of year */
 
    /* Loop through all jobs */
    LockRes();
@@ -221,7 +222,9 @@ static void find_runs()
          */
         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) && bit_is_set(wpos, run->wpos)) {
+            bit_is_set(month, run->month) && 
+            bit_is_set(wom, run->wom) &&  
+            bit_is_set(woy, run->woy)) {
 
            /* find time (time_t) job is to be run */
            localtime_r(&now, &tm);
@@ -234,7 +237,7 @@ static void find_runs()
            if (bit_is_set(next_hour, run->hour)) {
               tm.tm_hour++;
               if (tm.tm_hour > 23) {
-                 tm.tm_hour = 0;
+                 continue;           /* next day */
               }
               runtime = mktime(&tm);
               add_job(job, run, now, runtime);
index ce8e774cc78db61e430eb8e2348227363b1d7475..610aa8a9d1735f0b41d4870db5eaea67b6fecfe6 100644 (file)
@@ -57,17 +57,30 @@ char *drop_deltabs[] = {
    "DROP INDEX DelInx1",
    NULL};
 
+
 /* List of SQL commands to create temp table and indicies  */
 char *create_deltabs[] = {
    "CREATE TABLE DelCandidates ("
+#ifdef HAVE_MYSQL
       "JobId INTEGER UNSIGNED NOT NULL, "
       "PurgedFiles TINYINT, "
       "FileSetId INTEGER UNSIGNED, "
       "JobFiles INTEGER UNSIGNED, "
-#ifdef HAVE_MYSQL
       "JobStatus BINARY(1))",
 #else
+#ifdef HAVE_POSTGRESQL
+      "JobId INTEGER NOT NULL, "
+      "PurgedFiles SMALLINT, "
+      "FileSetId INTEGER, "
+      "JobFiles INTEGER, "
+      "JobStatus char(1))",
+#else
+      "JobId INTEGER UNSIGNED NOT NULL, "
+      "PurgedFiles TINYINT, "
+      "FileSetId INTEGER UNSIGNED, "
+      "JobFiles INTEGER UNSIGNED, "
       "JobStatus CHAR)",
+#endif
 #endif
    "CREATE INDEX DelInx1 ON DelCandidates (JobId)",
    NULL};
@@ -85,12 +98,14 @@ char *insert_delcand =
 /* Select Jobs from the DelCandidates table that have a
  * more recent backup -- i.e. are not the only backup.
  * This is the list of Jobs to delete for a Backup Job.
+ * At the same time, we select "orphanned" jobs
+ * (i.e. no files, ...) for deletion.
  */
 char *select_backup_del =
    "SELECT DelCandidates.JobId "
    "FROM Job,DelCandidates "
-   "WHERE (DelCandidates.JobFiles=0) OR "
-   "(DelCandidates.JobStatus!='T') OR "
+   "WHERE (JobTDate<%s AND ((DelCandidates.JobFiles=0) OR "
+   "(DelCandidates.JobStatus!='T'))) OR "
    "(Job.JobTDate>%s "
    "AND Job.ClientId=%u "
    "AND Job.Type='B' "
@@ -171,7 +186,20 @@ char *uar_del_temp  = "DROP TABLE temp";
 char *uar_del_temp1 = "DROP TABLE temp1";
 
 char *uar_create_temp = 
-   "CREATE TABLE temp (JobId INTEGER UNSIGNED NOT NULL,"
+   "CREATE TABLE temp ("
+#ifdef HAVE_POSTGRESQL
+   "JobId INTEGER NOT NULL,"
+   "JobTDate BIGINT,"
+   "ClientId INTEGER,"
+   "Level CHAR,"
+   "JobFiles INTEGER,"
+   "StartTime TEXT,"
+   "VolumeName TEXT,"
+   "StartFile INTEGER,"
+   "VolSessionId INTEGER,"
+   "VolSessionTime INTEGER)";
+#else
+   "JobId INTEGER UNSIGNED NOT NULL,"
    "JobTDate BIGINT UNSIGNED,"
    "ClientId INTEGER UNSIGNED,"
    "Level CHAR,"
@@ -181,20 +209,28 @@ char *uar_create_temp =
    "StartFile INTEGER UNSIGNED,"
    "VolSessionId INTEGER UNSIGNED,"
    "VolSessionTime INTEGER UNSIGNED)";
+#endif
 
 char *uar_create_temp1 = 
-   "CREATE TABLE temp1 (JobId INTEGER UNSIGNED NOT NULL,"
+   "CREATE TABLE temp1 ("
+#ifdef HAVE_POSTGRESQL
+   "JobId INTEGER NOT NULL,"
+   "JobTDate BIGINT)";
+#else
+   "JobId INTEGER UNSIGNED NOT NULL,"
    "JobTDate BIGINT UNSIGNED)";
+#endif
 
 char *uar_last_full =
    "INSERT INTO temp1 SELECT Job.JobId,JobTdate "
-   "FROM Client,Job,JobMedia,Media WHERE Client.ClientId=%u "
+   "FROM Client,Job,JobMedia,Media,FileSet WHERE Client.ClientId=%u "
    "AND Job.ClientId=%u "
    "AND Job.StartTime<'%s' "
    "AND Level='F' AND JobStatus='T' "
    "AND JobMedia.JobId=Job.JobId "
    "AND JobMedia.MediaId=Media.MediaId "
-   "AND Job.FileSetId=%u "
+   "AND Job.FileSetId=FileSet.FileSetId "
+   "AND FileSet.FileSet='%s' "
    "ORDER BY Job.JobTDate DESC LIMIT 1";
 
 char *uar_full = 
@@ -210,39 +246,42 @@ char *uar_inc_dec =
    "INSERT INTO temp SELECT Job.JobId,Job.JobTDate,Job.ClientId,"
    "Job.Level,Job.JobFiles,Job.StartTime,Media.VolumeName,JobMedia.StartFile,"
    "Job.VolSessionId,Job.VolSessionTime "
-   "FROM Job,JobMedia,Media "
-   "WHERE Job.JobTDate>%s AND Job.StartTime < '%s' "
+   "FROM Job,JobMedia,Media,FileSet "
+   "WHERE Job.JobTDate>%s AND Job.StartTime<'%s' "
    "AND Job.ClientId=%u "
    "AND JobMedia.JobId=Job.JobId "
    "AND JobMedia.MediaId=Media.MediaId "
    "AND Job.Level IN ('I', 'D') AND JobStatus='T' "
-   "AND Job.FileSetId=%u "
-   "GROUP BY Job.JobId";
+   "AND Job.FileSetId=FileSet.FileSetId "
+   "AND FileSet.FileSet='%s' ";
 
 char *uar_list_temp = 
    "SELECT JobId,Level,JobFiles,StartTime,VolumeName,StartFile,"
-   "VolSessionId,VolSessionTime FROM temp";
+   "VolSessionId,VolSessionTime FROM temp "
+   "ORDER BY StartTime ASC";
+
 
 char *uar_sel_jobid_temp = "SELECT JobId FROM temp";
 
 char *uar_sel_all_temp1 = "SELECT * FROM temp1";
 
-/* Select filesets for this Client */
+/* Select FileSet names for this Client */
 char *uar_sel_fileset = 
-   "SELECT FileSet.FileSetId,FileSet.FileSet,FileSet.CreateTime FROM Job,"
+   "SELECT DISTINCT FileSet.FileSet FROM Job,"
    "Client,FileSet WHERE Job.FileSetId=FileSet.FileSetId "
    "AND Job.ClientId=%u AND Client.ClientId=%u "
-   "GROUP BY FileSet.FileSetId ORDER BY FileSet.FileSetId";
+   "ORDER BY FileSet.FileSet";
 
 /* Find MediaType used by this Job */
 char *uar_mediatype =
    "SELECT MediaType FROM JobMedia,Media WHERE JobMedia.JobId=%u "
    "AND JobMedia.MediaId=Media.MediaId";
 
-/* Find JobId, FileIndex for a given path/file */
+/* Find JobId, FileIndex for a given path/file and date */
 char *uar_jobid_fileindex = 
    "SELECT Job.JobId, File.FileIndex FROM Job,File,Path,Filename,Client "
    "WHERE Job.JobId=File.JobId "
+   "AND Job.StartTime<'%s' "
    "AND Path.Path='%s' "
    "AND Filename.Name='%s' "
    "AND Client.Name='%s' "
index 7acb0d12161b10f20675e2c27c4143f3a2317004..bc3c3b47b79af73791ad28a8af608ba02d50d1eb 100644 (file)
@@ -50,11 +50,11 @@ 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 run_cmd(UAContext *ua, char *cmd);
 extern int retentioncmd(UAContext *ua, char *cmd);
 extern int prunecmd(UAContext *ua, char *cmd);
 extern int purgecmd(UAContext *ua, char *cmd);
-extern int restorecmd(UAContext *ua, char *cmd);
+extern int restore_cmd(UAContext *ua, char *cmd);
 extern int label_cmd(UAContext *ua, char *cmd);
 extern int relabel_cmd(UAContext *ua, char *cmd);
 extern int update_slots(UAContext *ua);  /* ua_label.c */
@@ -75,6 +75,7 @@ static int update_volume(UAContext *ua);
 static int update_pool(UAContext *ua);
 static int delete_volume(UAContext *ua);
 static int delete_pool(UAContext *ua);
+static int delete_job(UAContext *ua);
 static int mount_cmd(UAContext *ua, char *cmd);
 static int release_cmd(UAContext *ua, char *cmd);
 static int update_cmd(UAContext *ua, char *cmd);
@@ -94,23 +95,23 @@ static struct cmdstruct commands[] = {
  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing")},
  { N_("exit"),       quit_cmd,      _("exit = quit")},
  { N_("help"),       help_cmd,      _("print this command")},
+ { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files jobid=<nn>]; from catalog")},
  { N_("label"),      label_cmd,     _("label a tape")},
- { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
  { N_("llist"),      llist_cmd,     _("full or long list like list command")},
  { N_("messages"),   messagescmd,   _("messages")},
  { N_("mount"),      mount_cmd,     _("mount <storage-name>")},
  { N_("prune"),      prunecmd,      _("prune expired records from catalog")},
  { N_("purge"),      purgecmd,      _("purge records from catalog")},
- { N_("query"),      querycmd,      _("query catalog")},
  { N_("quit"),       quit_cmd,      _("quit")},
+ { N_("query"),      querycmd,      _("query catalog")},
+ { N_("restore"),    restore_cmd,   _("restore files")},
  { N_("relabel"),    relabel_cmd,   _("relabel a tape")},
  { N_("release"),    release_cmd,   _("release <storage-name>")},
- { N_("restore"),    restorecmd,    _("restore files")},
- { N_("run"),        runcmd,        _("run <job-name>")},
+ { N_("run"),        run_cmd,       _("run <job-name>")},
+ { N_("status"),     status_cmd,    _("status [storage | client]=<name>")},
  { N_("setdebug"),   setdebug_cmd,  _("sets debug level")},
  { N_("show"),       show_cmd,      _("show (resource records) [jobs | pools | ... | all]")},
  { N_("sqlquery"),   sqlquerycmd,   _("use SQL to query catalog")}, 
- { N_("status"),     status_cmd,    _("status [storage | client]=<name>")},
  { N_("time"),       time_cmd,      _("print current time")},
  { N_("unmount"),    unmount_cmd,   _("unmount <storage-name>")},
  { N_("update"),     update_cmd,    _("update Volume or Pool")},
@@ -799,6 +800,26 @@ static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
    free_pool_memory(query);
 }
 
+/* Modify the Pool in which this Volume is located */
+static void update_volpool(UAContext *ua, char *val, MEDIA_DBR *mr)
+{
+   POOL_DBR pr;
+   POOLMEM *query;
+   memset(&pr, 0, sizeof(pr));
+   bstrncpy(pr.Name, val, sizeof(pr.Name));
+   if (!get_pool_dbr(ua, &pr)) {
+      return;
+   }
+   query = get_pool_memory(PM_MESSAGE);
+   Mmsg(&query, "UPDATE Media SET PoolId=%u WHERE MediaId=%u", pr.PoolId, mr->MediaId);
+   if (!db_sql_query(ua->db, query, NULL, NULL)) {  
+      bsendmsg(ua, "%s", db_strerror(ua->db));
+   } else {      
+      bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
+   }
+   free_pool_memory(query);
+}
+
 /*
  * Update a media record -- allows you to change the
  *  Volume status. E.g. if you want Bacula to stop
@@ -808,6 +829,7 @@ static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
 static int update_volume(UAContext *ua)
 {
    MEDIA_DBR mr;
+   POOL_DBR pr;
    POOLMEM *query;
    char ed1[30];
    bool done = false;
@@ -819,6 +841,7 @@ static int update_volume(UAContext *ua)
       N_("MaxVolFiles"),              /* 4 */
       N_("MaxVolBytes"),              /* 5 */
       N_("Recycle"),                  /* 6 */
+      N_("Pool"),                     /* 7 */
       NULL };
 
    for (int i=0; kw[i]; i++) {
@@ -849,6 +872,8 @@ static int update_volume(UAContext *ua)
         case 6:
            update_volrecycle(ua, ua->argv[j], &mr);
            break;
+        case 7:
+           update_volpool(ua, ua->argv[j], &mr);
         }
         done = true;
       }
@@ -869,6 +894,7 @@ static int update_volume(UAContext *ua)
       add_prompt(ua, _("Recycle Flag"));
       add_prompt(ua, _("Slot"));
       add_prompt(ua, _("Volume Files"));
+      add_prompt(ua, _("Pool"));
       add_prompt(ua, _("Done"));
       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
       case 0:                        /* Volume Status */
@@ -944,7 +970,6 @@ static int update_volume(UAContext *ua)
 
       case 7:                        /* Slot */
         int slot;
-        POOL_DBR pr;
 
         memset(&pr, 0, sizeof(POOL_DBR));
         pr.PoolId = mr.PoolId;
@@ -999,6 +1024,19 @@ static int update_volume(UAContext *ua)
         free_pool_memory(query);
         break;
 
+      case 9:                         /* Volume's Pool */
+        memset(&pr, 0, sizeof(POOL_DBR));
+        pr.PoolId = mr.PoolId;
+        if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
+            bsendmsg(ua, "%s", db_strerror(ua->db));
+           return 0;
+        }
+         bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
+         if (!get_cmd(ua, _("Enter new Pool name: "))) {
+           return 0;
+        }
+        update_volpool(ua, ua->cmd, &mr);
+        return 1;
       default:                       /* Done or error */
          bsendmsg(ua, "Selection done.\n");
         return 1;
@@ -1414,15 +1452,13 @@ static int delete_cmd(UAContext *ua, char *cmd)
    static char *keywords[] = {
       N_("volume"),
       N_("pool"),
+      N_("job"),
       NULL};
 
    if (!open_db(ua)) {
       return 1;
    }
 
-   bsendmsg(ua, _(
-"In general it is not a good idea to delete either a\n"
-"Pool or a Volume since they may contain data.\n\n"));
      
    switch (find_arg_keyword(ua, keywords)) {
    case 0:
@@ -1431,9 +1467,17 @@ static int delete_cmd(UAContext *ua, char *cmd)
    case 1:
       delete_pool(ua);
       return 1;
+   case 2:
+      delete_job(ua);
+      return 1;
    default:
       break;
    }
+
+   bsendmsg(ua, _(
+"In general it is not a good idea to delete either a\n"
+"Pool or a Volume since they may contain data.\n\n"));
+
    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
    case 0:
       delete_volume(ua);
@@ -1441,6 +1485,9 @@ static int delete_cmd(UAContext *ua, char *cmd)
    case 1:
       delete_pool(ua);
       break;
+   case 2:
+      delete_job(ua);
+      return 1;
    default:
       bsendmsg(ua, _("Nothing done.\n"));
       break;
@@ -1448,6 +1495,30 @@ static int delete_cmd(UAContext *ua, char *cmd)
    return 1;
 }
 
+static int delete_job(UAContext *ua)
+{
+   POOLMEM *query = get_pool_memory(PM_MESSAGE);
+   JobId_t JobId;
+
+   int i = find_arg_with_value(ua, "jobid");
+   if (i >= 0) {
+      JobId = str_to_int64(ua->argv[i]);
+   } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
+      return 0;
+   } else {
+      JobId = ua->pint32_val; 
+   }
+   Mmsg(&query, "DELETE FROM Job WHERE JobId=%u", JobId);
+   db_sql_query(ua->db, query, NULL, (void *)NULL);
+   Mmsg(&query, "DELETE FROM File WHERE JobId=%u", JobId);
+   db_sql_query(ua->db, query, NULL, (void *)NULL);
+   Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%u", JobId);
+   db_sql_query(ua->db, query, NULL, (void *)NULL);
+   free_pool_memory(query);
+   bsendmsg(ua, _("Job %u and associated records deleted from the catalog.\n"), JobId);
+   return 1;
+}
+
 /*
  * Delete media records from database -- dangerous 
  */
index c0f3ea74ed55aff70bacc4e911a8bb09f8e0ad48..39c4e33ebff8582d8e82da27b91d9ab737cb3900 100644 (file)
@@ -55,8 +55,7 @@ int get_cmd(UAContext *ua, char *prompt)
       if (is_bnet_stop(sock)) {
         return 0;                    /* error or terminate */
       }
-      ua->cmd = check_pool_memory_size(ua->cmd, sock->msglen+1);
-      bstrncpy(ua->cmd, sock->msg, sock->msglen+1);
+      pm_strcpy(&ua->cmd, sock->msg);
       strip_trailing_junk(ua->cmd);
       if (strcmp(ua->cmd, ".messages") == 0) {
         qmessagescmd(ua, ua->cmd);
index 028c5e74b7314f2f7dd1a52aa26d6a931f5c99ad..ecbf8aa38f0e3566fdf0427a9d28cf75fd814823 100644 (file)
@@ -148,8 +148,8 @@ static int do_label(UAContext *ua, char *cmd, int relabel)
    char dev_name[MAX_NAME_LENGTH];
    MEDIA_DBR mr, omr;
    POOL_DBR pr;
+   bool print_reminder = true;
    int ok = FALSE;
-   int mounted = FALSE;
    int i;
    bool media_record_exists = false;
    static char *barcode_keyword[] = {
@@ -284,12 +284,17 @@ checkName:
            /* Here we can get
             *  3001 OK mount. Device=xxx      or
             *  3001 Mounted Volume vvvv
+            *  3906 is cannot mount non-tape
+            * So for those, no need to print a reminder
             */
-            mounted = strncmp(sd->msg, "3001 ", 5) == 0;
+            if (strncmp(sd->msg, "3001 ", 5) == 0 ||
+                strncmp(sd->msg, "3906 ", 5) == 0) {
+              print_reminder = false;
         }
       }
    }
-   if (!mounted) {
+   }
+   if (print_reminder) {
       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
    }
    bnet_sig(sd, BNET_TERMINATE);
index b79001982e9d941adf14c83b8e4156f3263521f0..52cd33cd877c40d821e943d7fdb5cf4bd0a41d5c 100644 (file)
@@ -304,7 +304,7 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
       /* List MEDIA or VOLUMES */
       } else if (strcasecmp(ua->argk[i], _("media")) == 0 ||
                  strcasecmp(ua->argk[i], _("volumes")) == 0) {
-        int done = FALSE;
+        bool done = false;
         for (j=i+1; j<ua->argc; j++) {
             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
               bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
@@ -320,7 +320,7 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
            n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
             bsendmsg(ua, _("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
            free_pool_memory(VolumeName);
-           done = TRUE;
+           done = true;
         }
         /* if no job or jobid keyword found, then we list all media */
         if (!done) {
@@ -372,6 +372,11 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
                  strcasecmp(ua->argk[i], _("nextvolume")) == 0) {
         JOB *job;
         JCR *jcr = ua->jcr;
+        POOL *pool;
+        RUN *run;
+        time_t runtime;
+        bool found = false;
+
          i = find_arg_with_value(ua, "job");
         if (i <= 0) {
            if ((job = select_job_resource(ua)) == NULL) {
@@ -386,21 +391,37 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
               }
            }
         }
-        if (!complete_jcr_for_job(jcr, job, NULL)) {
-           return 1;
-        }
+        for (run=NULL; (run = find_next_run(run, job, runtime)); ) {
+           pool = run ? run->pool : NULL;
+           if (!complete_jcr_for_job(jcr, job, pool)) {
+              return 1;
+           }
           
-        if (!find_next_volume_for_append(jcr, &mr, 0)) {
-            bsendmsg(ua, "Could not find next Volume\n");
+           if (!find_next_volume_for_append(jcr, &mr, 0)) {
+               bsendmsg(ua, _("Could not find next Volume.\n"));
+              if (jcr->db) {
+                 db_close_database(jcr, jcr->db);
+                 jcr->db = NULL;
+              }
+              return 1;
+           } else {
+               bsendmsg(ua, _("The next Volume to be used by Job \"%s\" will be %s\n"), 
+                 job->hdr.name, mr.VolumeName);
+              found = true;
+           }
+           if (jcr->db) {
+              db_close_database(jcr, jcr->db);
+              jcr->db = NULL;
+           }
+        }
+        if (jcr->db) {
            db_close_database(jcr, jcr->db);
            jcr->db = NULL;
-           return 1;
-        } else {
-            bsendmsg(ua, "The next Volume to be used by Job \"%s\" will be %s\n", 
-              job->hdr.name, mr.VolumeName);
         }
-        db_close_database(jcr, jcr->db);
-        jcr->db = NULL;
+        if (!found) {
+            bsendmsg(ua, _("Could not find next Volume.\n"));
+        }
+        return 1;
       } else {
          bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
       }
@@ -408,6 +429,101 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
    return 1;
 }
 
+/* 
+ * For a given job, we examine all his run records
+ *  to see if it is scheduled today or tomorrow.
+ */
+RUN *find_next_run(RUN *run, JOB *job, time_t &runtime)
+{
+   time_t now, tomorrow;
+   SCHED *sched;
+   struct tm tm;
+   int mday, wday, month, wom, tmday, twday, tmonth, twom, i, hour;
+   int woy, twoy;
+   int tod, tom;
+
+   Dmsg0(200, "enter find_runs()\n");
+
+   sched = job->schedule;
+   if (sched == NULL) {           /* scheduled? */
+      return NULL;                /* no nothing to report */
+   }
+   /* Break down current time into components */ 
+   now = time(NULL);
+   localtime_r(&now, &tm);
+   mday = tm.tm_mday - 1;
+   wday = tm.tm_wday;
+   month = tm.tm_mon;
+   wom = mday / 7;
+   woy = tm_woy(now);
+
+   /* Break down tomorrow into components */
+   tomorrow = now + 60 * 60 * 24;
+   localtime_r(&tomorrow, &tm);
+   tmday = tm.tm_mday - 1;
+   twday = tm.tm_wday;
+   tmonth = tm.tm_mon;
+   twom  = tmday / 7;
+   twoy  = tm_woy(tomorrow);
+
+   if (run == NULL) {
+      run = sched->run;
+   } else {
+      run = run->next;
+   }
+   for ( ; 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) && bit_is_set(wom, run->wom) &&
+            bit_is_set(woy, run->woy);
+
+      tom = (bit_is_set(tmday, run->mday) || bit_is_set(twday, run->wday)) &&
+            bit_is_set(tmonth, run->month) && bit_is_set(twom, run->wom) &&
+            bit_is_set(twoy, run->woy);
+
+      Dmsg2(200, "tod=%d tom=%d\n", tod, tom);
+      if (tod) {                  /* Jobs scheduled today (next 24 hours) */
+        /* 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) {
+                 return run;         /* found it, return run resource */
+              }
+           }
+        }
+      }
+
+//    Dmsg2(200, "runtime=%d now=%d\n", runtime, now);
+      if (tom) {               /* look at jobs scheduled tomorrow */
+        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) {
+           return run;               /* found it, return run resource */
+        }
+      }
+   } /* end for loop over runs */ 
+   /* Nothing found */
+   return NULL;
+}
 /* 
  * Fill in the remaining fields of the jcr as if it
  *  is going to run the job.
@@ -438,8 +554,10 @@ int complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
       if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
          Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, 
            db_strerror(jcr->db));
-        db_close_database(jcr, jcr->db);
-        jcr->db = NULL;
+        if (jcr->db) {
+           db_close_database(jcr, jcr->db);
+           jcr->db = NULL;
+        }
         return 0;
       } else {
          Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
@@ -538,11 +656,12 @@ again:
    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
    va_end(arg_ptr);
    if (len < 0 || len >= maxlen) {
-      msg = realloc_pool_memory(msg, maxlen + 200);
+      msg = realloc_pool_memory(msg, maxlen + maxlen/2);
       goto again;
    }
 
    if (bs) {
+      bs->msg = msg;
       bs->msglen = len;
       bnet_send(bs);
    } else {                          /* No UA, send to Job */
index cd6684a3f1e4a546f73500ded3a325ad17b382f3..2278405d8007e1169ba40b7bb68b577e3a7674a1 100644 (file)
@@ -270,7 +270,7 @@ int prune_files(UAContext *ua, CLIENT *client)
 
    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
 
-   /* Now process same set but making delete list */
+   /* Now process same set but making delete list */
    db_sql_query(ua->db, query, file_delete_handler, (void *)&del);
 
    for (i=0; i < del.num_ids; i++) {
@@ -286,7 +286,7 @@ int prune_files(UAContext *ua, CLIENT *client)
        * Now mark Job as having files purged. This is necessary to
        * avoid having too many Jobs to process in future prunings. If
        * we don't do this, the number of JobId's in our in memory list
-       * will grow very large.
+       * could grow very large.
        */
       Mmsg(&query, upd_Purged, del.JobId[i]);
       db_sql_query(ua->db, query, NULL, (void *)NULL);
@@ -415,7 +415,7 @@ int prune_jobs(UAContext *ua, CLIENT *client, int JobType)
    switch (JobType) {
    case JT_ADMIN:
    case JT_BACKUP:
-      Mmsg(&query, select_backup_del, ed1, cr.ClientId);
+      Mmsg(&query, select_backup_del, ed1, ed1, cr.ClientId);
       break;
    case JT_RESTORE:
       Mmsg(&query, select_restore_del, ed1, cr.ClientId);
index c195a50ef4a1199de5931e609fc618f37f274861..36733d0ab2bf6968794de1f106cd19be4bd7f6f8 100644 (file)
@@ -38,7 +38,8 @@
 
 
 /* Imported functions */
-extern int runcmd(UAContext *ua, char *cmd);
+extern int run_cmd(UAContext *ua, char *cmd);
+extern void print_bsr(UAContext *ua, RBSR *bsr);
 
 /* Imported variables */
 extern char *uar_list_jobs,    *uar_file,        *uar_sel_files;
@@ -100,15 +101,17 @@ static void build_directory_tree(UAContext *ua, RESTORE_CTX *rx);
 static void free_rx(RESTORE_CTX *rx);
 static void split_path_and_filename(RESTORE_CTX *rx, char *fname);
 static int jobid_fileindex_handler(void *ctx, int num_fields, char **row);
-static int insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file);
-static void insert_one_file(UAContext *ua, RESTORE_CTX *rx);
+static int insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file,
+                                       char *date);
+static void insert_one_file(UAContext *ua, RESTORE_CTX *rx, char *date);
 static int get_client_name(UAContext *ua, RESTORE_CTX *rx);
+static int get_date(UAContext *ua, char *date, int date_len);
 
 /*
  *   Restore files
  *
  */
-int restorecmd(UAContext *ua, char *cmd)
+int restore_cmd(UAContext *ua, char *cmd)
 {
    RESTORE_CTX rx;                   /* restore context */
    JOB *job = NULL;
@@ -128,8 +131,7 @@ int restorecmd(UAContext *ua, char *cmd)
    }
 
    if (!open_db(ua)) {
-      free_rx(&rx);
-      return 0;
+      goto bail_out;
    }
 
    /* Ensure there is at least one Restore Job */
@@ -147,8 +149,7 @@ int restorecmd(UAContext *ua, char *cmd)
       bsendmsg(ua, _(
          "No Restore Job Resource found. You must create at least\n"
          "one before running this command.\n"));
-      free_rx(&rx);
-      return 0;
+      goto bail_out;
    }
 
    /* 
@@ -159,29 +160,25 @@ int restorecmd(UAContext *ua, char *cmd)
     */
    switch (user_select_jobids_or_files(ua, &rx)) {
    case 0:
-      free_rx(&rx);
-      return 0;                      /* error */
+      goto bail_out;
    case 1:                           /* select by jobid */
       build_directory_tree(ua, &rx);
       break;
-   case 2:
+   case 2:                           /* select by filename, no tree needed */
       break;
    }
 
    if (rx.bsr->JobId) {
       if (!complete_bsr(ua, rx.bsr)) {  /* find Vol, SessId, SessTime from JobIds */
          bsendmsg(ua, _("Unable to construct a valid BSR. Cannot continue.\n"));
-        free_rx(&rx);
-        return 0;
+        goto bail_out;
       }
-//    print_bsr(ua, rx.bsr);
       write_bsr_file(ua, rx.bsr);
-      bsendmsg(ua, _("\n%u file%s selected to restore.\n\n"), rx.selected_files,
+      bsendmsg(ua, _("\n%u file%s selected to be restored.\n\n"), rx.selected_files,
          rx.selected_files==1?"":"s");
    } else {
-      bsendmsg(ua, _("No files selected to restore.\n"));
-      free_rx(&rx);
-      return 0;
+      bsendmsg(ua, _("No files selected to be restored.\n"));
+      goto bail_out;
    }
 
    if (rx.restore_jobs == 1) {
@@ -190,12 +187,14 @@ int restorecmd(UAContext *ua, char *cmd)
       job = select_restore_job_resource(ua);
    }
    if (!job) {
-      bsendmsg(ua, _("No Restore Job resource found!\n"));
-      free_rx(&rx);
-      return 0;
+      goto bail_out;
    }
 
    get_client_name(ua, &rx);
+   if (!rx.ClientName) {
+      bsendmsg(ua, _("No Restore Job resource found!\n"));
+      goto bail_out;
+   }
 
    /* Build run command */
    if (rx.where) {
@@ -210,19 +209,27 @@ int restorecmd(UAContext *ua, char *cmd)
           job->hdr.name, rx.ClientName, rx.store?rx.store->hdr.name:"",
          working_directory);
    }
-   
+   if (find_arg(ua, _("run")) >= 0) {
+      pm_strcat(&ua->cmd, " run");    /* pass it on to the run command */
+   }
    Dmsg1(400, "Submitting: %s\n", ua->cmd);
    parse_ua_args(ua);
-   runcmd(ua, ua->cmd);
+   run_cmd(ua, ua->cmd);
 
    bsendmsg(ua, _("Restore command done.\n"));
    free_rx(&rx);
    return 1;
+
+bail_out:
+   free_rx(&rx);
+   return 0;
+
 }
 
 static void free_rx(RESTORE_CTX *rx) 
 {
    free_bsr(rx->bsr);
+   rx->bsr = NULL;
    if (rx->JobIds) {
       free_pool_memory(rx->JobIds);
       rx->JobIds = NULL;
@@ -255,7 +262,6 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx)
       }
       memset(&cr, 0, sizeof(cr));
       if (!get_client_dbr(ua, &cr)) {
-        free_rx(rx);
         return 0;
       }
       bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
@@ -272,6 +278,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
 {
    char *p;
    char date[MAX_TIME_LENGTH];
+   bool have_date = false;
    JobId_t JobId;
    JOB_DBR jr;
    bool done = false;
@@ -284,6 +291,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       "Select the most recent backup for a client",
       "Select backup for a client before a specified time",
       "Enter a list of files to restore",
+      "Enter a list of files to restore before a specified time",
       "Cancel",
       NULL };
 
@@ -292,24 +300,26 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       "current",   /* 1 */
       "before",    /* 2 */
       "file",      /* 3 */
+      "select",    /* 4 */
       NULL
    };
 
+   *rx->JobIds = 0;
    switch (find_arg_keyword(ua, kw)) {
    case 0:                           /* jobid */
-      i = find_arg_with_value(ua, _("jobid"));
-      if (i < 0) {
-        return 0;
+      for ( ;; ) {
+         i = find_arg_with_value(ua, _("jobid"));
+        if (i < 0) {
+           break;
+        }
+        pm_strcpy(&rx->JobIds, ua->argv[i]);
+         ua->argk[i][0] = 0;          /* "consume" jobid= */
       }
-      pm_strcpy(&rx->JobIds, ua->argv[i]);
       done = true;
       break;
    case 1:                           /* current */
       bstrutime(date, sizeof(date), time(NULL));
-      if (!select_backups_before_date(ua, rx, date)) {
-        return 0;
-      }
-      done = true;
+      have_date = true;
       break;
    case 2:                           /* before */
       i = find_arg_with_value(ua, _("before"));
@@ -321,12 +331,12 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
         return 0;
       }
       bstrncpy(date, ua->argv[i], sizeof(date));
-      if (!select_backups_before_date(ua, rx, date)) {
-        return 0;
-      }
-      done = true;
+      have_date = true;
       break;
    case 3:                           /* file */
+      if (!have_date) {
+        bstrutime(date, sizeof(date), time(NULL));
+      }
       if (!get_client_name(ua, rx)) {
         return 0;
       }
@@ -336,12 +346,21 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
            break;
         }
         pm_strcpy(&ua->cmd, ua->argv[i]);
-        insert_one_file(ua, rx);
-        ua->argk[i][0] = 0;
+        insert_one_file(ua, rx, date);
+         ua->argk[i][0] = 0;          /* "consume" the file= */
       }
       /* Check MediaType and select storage that corresponds */
       get_storage_from_mediatype(ua, &rx->name_list, rx);
       return 2;
+   case 4:                           /* select */
+      if (!have_date) {
+        bstrutime(date, sizeof(date), time(NULL));
+      }
+      if (!select_backups_before_date(ua, rx, date)) {
+        return 0;
+      }
+      done = true;
+      break;
    default:
       break;
    }
@@ -402,26 +421,44 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
         }
         break;
       case 5:                        /* select backup at specified time */
-         bsendmsg(ua, _("The restored files will the most current backup\n"
-                        "BEFORE the date you specify below.\n\n"));
+        if (!get_date(ua, date, sizeof(date))) {
+           return 0;
+        }
+        if (!select_backups_before_date(ua, rx, date)) {
+           return 0;
+        }
+        break;
+      case 6:                        /* Enter files */
+        bstrutime(date, sizeof(date), time(NULL));
+        if (!get_client_name(ua, rx)) {
+           return 0;
+        }
+         bsendmsg(ua, _("Enter file names, or < to enter a filename\n"      
+                        "containg a list of file names, and terminate\n"
+                        "them with a blank line.\n"));
         for ( ;; ) {
-            if (!get_cmd(ua, _("Enter date as YYYY-MM-DD HH:MM:SS :"))) {
+            if (!get_cmd(ua, _("Enter filename: "))) {
               return 0;
            }
-           if (str_to_utime(ua->cmd) != 0) {
+           len = strlen(ua->cmd);
+           if (len == 0) {
               break;
            }
-            bsendmsg(ua, _("Improper date format.\n"));
-        }              
-        bstrncpy(date, ua->cmd, sizeof(date));
-        if (!select_backups_before_date(ua, rx, date)) {
+           insert_one_file(ua, rx, date);
+        }
+        /* Check MediaType and select storage that corresponds */
+        get_storage_from_mediatype(ua, &rx->name_list, rx);
+        return 2;
+       case 7:                       /* enter files backed up before specified time */
+        if (!get_date(ua, date, sizeof(date))) {
            return 0;
         }
-        break;
-      case 6:                        /* Enter files */
         if (!get_client_name(ua, rx)) {
            return 0;
         }
+         bsendmsg(ua, _("Enter file names, or < to enter a filename\n"      
+                        "containg a list of file names, and terminate\n"
+                        "them with a blank line.\n"));
         for ( ;; ) {
             if (!get_cmd(ua, _("Enter filename: "))) {
               return 0;
@@ -430,13 +467,14 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
            if (len == 0) {
               break;
            }
-           insert_one_file(ua, rx);
+           insert_one_file(ua, rx, date);
         }
         /* Check MediaType and select storage that corresponds */
         get_storage_from_mediatype(ua, &rx->name_list, rx);
         return 2;
+
       
-      case 7:                        /* Cancel or quit */
+      case 8:                        /* Cancel or quit */
         return 0;
       }
    }
@@ -473,7 +511,24 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
    return 1;
 }
 
-static void insert_one_file(UAContext *ua, RESTORE_CTX *rx)
+static int get_date(UAContext *ua, char *date, int date_len)
+{
+   bsendmsg(ua, _("The restored files will the most current backup\n"
+                  "BEFORE the date you specify below.\n\n"));
+   for ( ;; ) {
+      if (!get_cmd(ua, _("Enter date as YYYY-MM-DD HH:MM:SS :"))) {
+        return 0;
+      }
+      if (str_to_utime(ua->cmd) != 0) {
+        break;
+      }
+      bsendmsg(ua, _("Improper date format.\n"));
+   }             
+   bstrncpy(date, ua->cmd, date_len);
+   return 1;
+}
+
+static void insert_one_file(UAContext *ua, RESTORE_CTX *rx, char *date)
 {
    FILE *ffd;
    char file[5000];
@@ -490,14 +545,14 @@ static void insert_one_file(UAContext *ua, RESTORE_CTX *rx)
       }
       while (fgets(file, sizeof(file), ffd)) {
         line++;
-        if (!insert_file_into_findex_list(ua, rx, file)) {
+        if (!insert_file_into_findex_list(ua, rx, file, date)) {
             bsendmsg(ua, _("Error occurred on line %d of %s\n"), line, p);
         }
       }
       fclose(ffd);
       break;
    default:
-      insert_file_into_findex_list(ua, rx, ua->cmd);
+      insert_file_into_findex_list(ua, rx, ua->cmd, date);
       break;
    }
 }
@@ -507,12 +562,14 @@ static void insert_one_file(UAContext *ua, RESTORE_CTX *rx)
  *   lookup the most recent backup in the catalog to get the JobId
  *   and FileIndex, then insert them into the findex list.
  */
-static int insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file)
+static int insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file, 
+                                       char *date)
 {
    strip_trailing_junk(file);
    split_path_and_filename(rx, file);
-   Mmsg(&rx->query, uar_jobid_fileindex, rx->path, rx->fname, rx->ClientName);
+   Mmsg(&rx->query, uar_jobid_fileindex, date, rx->path, rx->fname, rx->ClientName);
    rx->found = false;
+   /* Find and insert jobid and File Index */
    if (!db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx)) {
       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), 
         rx->query, db_strerror(ua->db));
@@ -523,7 +580,7 @@ static int insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *fi
    }
    rx->selected_files++;
    /*
-    * Find the FileSets for this JobId and add to the name_list
+    * Find the MediaTypes for this JobId and add to the name_list
     */
    Mmsg(&rx->query, uar_mediatype, rx->JobId);
    if (!db_sql_query(ua->db, rx->query, unique_name_list_handler, (void *)&rx->name_list)) {
@@ -620,7 +677,7 @@ static void build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
          bsendmsg(ua, "%s", db_strerror(ua->db));
       }
       /*
-       * Find the FileSets for this JobId and add to the name_list
+       * Find the MediaTypes for this JobId and add to the name_list
        */
       Mmsg(&rx->query, uar_mediatype, JobId);
       if (!db_sql_query(ua->db, rx->query, unique_name_list_handler, (void *)&rx->name_list)) {
@@ -666,6 +723,7 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date
    CLIENT_DBR cr;
    char fileset_name[MAX_NAME_LENGTH];
    char ed1[50];
+   int i;
 
 
    /* Create temp tables */
@@ -687,27 +745,40 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date
    bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
 
    /*
-    * Select FileSet 
+    * Get FileSet 
     */
-   Mmsg(&rx->query, uar_sel_fileset, cr.ClientId, cr.ClientId);
-   start_prompt(ua, _("The defined FileSet resources are:\n"));
-   if (!db_sql_query(ua->db, rx->query, fileset_handler, (void *)ua)) {
-      bsendmsg(ua, "%s\n", db_strerror(ua->db));
+   memset(&fsr, 0, sizeof(fsr));
+   i = find_arg_with_value(ua, "FileSet"); 
+   if (i >= 0) {
+      bstrncpy(fsr.FileSet, ua->argv[i], sizeof(fsr.FileSet));
+      if (!db_get_fileset_record(ua->jcr, ua->db, &fsr)) {
+         bsendmsg(ua, _("Error getting FileSet \"%s\": ERR=%s\n"), fsr.FileSet, 
+           db_strerror(ua->db));
+        i = -1;
+      }
    }
-   if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), 
+   if (i < 0) {                      /* fileset not found */
+      Mmsg(&rx->query, uar_sel_fileset, cr.ClientId, cr.ClientId);
+      start_prompt(ua, _("The defined FileSet resources are:\n"));
+      if (!db_sql_query(ua->db, rx->query, fileset_handler, (void *)ua)) {
+         bsendmsg(ua, "%s\n", db_strerror(ua->db));
+      }
+      if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), 
                 fileset_name, sizeof(fileset_name)) < 0) {
-      goto bail_out;
-   }
-   fsr.FileSetId = atoi(fileset_name); /* Id is first part of name */
-   if (!db_get_fileset_record(ua->jcr, ua->db, &fsr)) {
-      bsendmsg(ua, _("Error getting FileSet record: %s\n"), db_strerror(ua->db));
-      bsendmsg(ua, _("This probably means you modified the FileSet.\n"
+        goto bail_out;
+      }
+
+      bstrncpy(fsr.FileSet, fileset_name, sizeof(fsr.FileSet));
+      if (!db_get_fileset_record(ua->jcr, ua->db, &fsr)) {
+         bsendmsg(ua, _("Error getting FileSet record: %s\n"), db_strerror(ua->db));
+         bsendmsg(ua, _("This probably means you modified the FileSet.\n"
                      "Continuing anyway.\n"));
+      }
    }
 
 
    /* Find JobId of last Full backup for this client, fileset */
-   Mmsg(&rx->query, uar_last_full, cr.ClientId, cr.ClientId, date, fsr.FileSetId);
+   Mmsg(&rx->query, uar_last_full, cr.ClientId, cr.ClientId, date, fsr.FileSet);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
       goto bail_out;
@@ -718,7 +789,7 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
       goto bail_out;
    }
-   /* Note, this is needed as I don't seem to get the callback
+   /* Note, this is needed because I don't seem to get the callback
     * from the call just above.
     */
    rx->JobTDate = 0;
@@ -732,7 +803,7 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date
 
    /* Now find all Incremental/Decremental Jobs after Full save */
    Mmsg(&rx->query, uar_inc_dec, edit_uint64(rx->JobTDate, ed1), date,
-       cr.ClientId, fsr.FileSetId);
+       cr.ClientId, fsr.FileSet);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
    }
@@ -759,6 +830,7 @@ bail_out:
    return stat;
 }
 
+
 /* Return next JobId from comma separated list */
 static int next_jobid_from_list(char **p, uint32_t *JobId)
 {
@@ -826,14 +898,15 @@ static int last_full_handler(void *ctx, int num_fields, char **row)
 }
 
 /*
- * Callback handler build fileset prompt list
+ * Callback handler build FileSet name prompt list
  */
 static int fileset_handler(void *ctx, int num_fields, char **row)
 {
-   char prompt[MAX_NAME_LENGTH+200];
 
-   snprintf(prompt, sizeof(prompt), "%s  %s  %s", row[0], row[1], row[2]);
-   add_prompt((UAContext *)ctx, prompt);
+   /* row[0] = FileSet (name) */
+   if (row[0]) {
+      add_prompt((UAContext *)ctx, row[0]);
+   }
    return 0;
 }
 
@@ -891,6 +964,7 @@ static void free_name_list(NAME_LIST *name_list)
    }
    if (name_list->name) {
       free(name_list->name);
+      name_list->name = NULL;
    }
    name_list->max_ids = 0;
    name_list->num_ids = 0;
@@ -898,9 +972,6 @@ static void free_name_list(NAME_LIST *name_list)
 
 static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, RESTORE_CTX *rx)
 {
-   char name[MAX_NAME_LENGTH];
-   STORE *store = NULL;
-
    if (name_list->num_ids > 1) {
       bsendmsg(ua, _("Warning, the JobIds that you selected refer to more than one MediaType.\n"
          "Restore is not possible. The MediaTypes used are:\n"));
@@ -915,16 +986,8 @@ static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, REST
       return;
    }
 
-   start_prompt(ua, _("The defined Storage resources are:\n"));
-   LockRes();
-   while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
-      if (strcmp(store->media_type, name_list->name[0]) == 0) {
-        add_prompt(ua, store->hdr.name);
-      }
-   }
-   UnlockRes();
-   do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name));
-   rx->store = (STORE *)GetResWithName(R_STORAGE, name);
+   rx->store = get_storage_resource(ua, false /* don't use default */);
+
    if (!rx->store) {
       bsendmsg(ua, _("\nWarning. Unable to find Storage resource for\n"
          "MediaType %s, needed by the Jobs you selected.\n"
index 9a4a559dce2ef671ab54774c901de0202409900d..be20b7dbc3cf610a59dbcb37104b68423888093b 100644 (file)
@@ -44,15 +44,17 @@ extern struct s_kw ReplaceOptions[];
  *     run <job-name> jobid=nn
  *
  */
-int runcmd(UAContext *ua, char *cmd)
+int run_cmd(UAContext *ua, char *cmd)
 {
    JCR *jcr;
    char *job_name, *level_name, *jid, *store_name, *pool_name;
    char *where, *fileset_name, *client_name, *bootstrap, *replace;
-   char *when;
+   char *when, *verify_job_name;
    int Priority = 0;
-   int i, j, found, opt;
+   int i, j, opt;
+   bool found;
    JOB *job = NULL;
+   JOB *verify_job = NULL;
    STORE *store = NULL;
    CLIENT *client = NULL;
    FILESET *fileset = NULL;
@@ -71,9 +73,12 @@ int runcmd(UAContext *ua, char *cmd)
       N_("when"),
       N_("priority"),
       N_("yes"),          /* 12 -- if you change this change YES_POS too */
+      N_("run"),          /* 13 -- if you change this change RUN_POS too */
+      N_("verifyjob"),
       NULL};
 
 #define YES_POS 12
+#define RUN_POS 13
 
    if (!open_db(ua)) {
       return 1;
@@ -90,14 +95,15 @@ int runcmd(UAContext *ua, char *cmd)
    fileset_name = NULL;
    bootstrap = NULL;
    replace = NULL;
+   verify_job_name = NULL;
 
    for (i=1; i<ua->argc; i++) {
-      found = False;
+      found = false;
       Dmsg2(200, "Doing arg %d = %s\n", i, ua->argk[i]);
       for (j=0; !found && kw[j]; j++) {
         if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
-           /* Note, yes has no value, so do not err */
-           if (!ua->argv[i] && j != YES_POS /*yes*/) {
+           /* Note, yes and run have no value, so do not err */
+           if (!ua->argv[i] && (j != YES_POS /*yes*/ && j != RUN_POS)) {  
                bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
               return 1;
            }
@@ -109,7 +115,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               job_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 1: /* JobId */
               if (jid) {
@@ -117,7 +123,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               jid = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 2: /* client */
               if (client_name) {
@@ -125,7 +131,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               client_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 3: /* fileset */
               if (fileset_name) {
@@ -133,7 +139,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               fileset_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 4: /* level */
               if (level_name) {
@@ -141,7 +147,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               level_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 5: /* storage */
               if (store_name) {
@@ -149,7 +155,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               store_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 6: /* pool */
               if (pool_name) {
@@ -157,7 +163,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               pool_name = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 7: /* where */
               if (where) {
@@ -165,7 +171,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               where = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 8: /* bootstrap */
               if (bootstrap) {
@@ -173,7 +179,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               bootstrap = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 9: /* replace */
               if (replace) {
@@ -181,7 +187,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               replace = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 10: /* When */
               if (when) {
@@ -189,7 +195,7 @@ int runcmd(UAContext *ua, char *cmd)
                  return 1;
               }
               when = ua->argv[i];
-              found = True;
+              found = true;
               break;
            case 11:  /* Priority */
               if (Priority) {
@@ -203,8 +209,18 @@ int runcmd(UAContext *ua, char *cmd)
               }
               break;
            case 12: /* yes */
-              found = True;
+           case 13: /* run */
+              found = true;
               break;
+           case 14: /* Verify Job */
+              if (verify_job_name) {
+                  bsendmsg(ua, _("Verify Job specified twice.\n"));
+                 return 1;
+              }
+              verify_job_name = ua->argv[i];
+              found = true;
+              break;
+
            default:
               break;
            }
@@ -270,6 +286,9 @@ int runcmd(UAContext *ua, char *cmd)
    } else {
       pool = job->pool;            /* use default */
    }
+   if (!pool) {
+      return 1;
+   }
 
    if (client_name) {
       client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
@@ -297,6 +316,15 @@ int runcmd(UAContext *ua, char *cmd)
       return 1;
    }
 
+   if (verify_job_name) {
+      verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
+      if (!verify_job) {
+         bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
+        verify_job = select_job_resource(ua);
+      }
+   } else {
+      verify_job = job->verify_job;
+   }
 
    /* Create JCR to run job */
    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
@@ -396,6 +424,32 @@ Priority: %d\n"),
            }
         }
         level_name = NULL;
+        if (jcr->JobType == JT_BACKUP) {
+            bsendmsg(ua, _("Run %s job\n\
+JobName:  %s\n\
+FileSet:  %s\n\
+Level:    %s\n\
+Client:   %s\n\
+Storage:  %s\n\
+Pool:     %s\n\
+When:     %s\n\
+Priority: %d\n"),
+                 _("Backup"),
+                job->hdr.name,
+                jcr->fileset->hdr.name,
+                level_to_str(jcr->JobLevel),
+                jcr->client->hdr.name,
+                jcr->store->hdr.name,
+                NPRT(jcr->pool->hdr.name), 
+                bstrutime(dt, sizeof(dt), jcr->sched_time),
+                jcr->JobPriority);
+        } else {  /* JT_VERIFY */
+           char *Name;
+           if (jcr->job->verify_job) {
+              Name = jcr->job->verify_job->hdr.name;
+           } else {
+               Name = "";
+           }
          bsendmsg(ua, _("Run %s job\n\
 JobName:  %s\n\
 FileSet:  %s\n\
@@ -403,17 +457,20 @@ Level:    %s\n\
 Client:   %s\n\
 Storage:  %s\n\
 Pool:     %s\n\
+Verify Job:  %s\n\
 When:     %s\n\
 Priority: %d\n"),
-                 jcr->JobType==JT_BACKUP?_("Backup"):_("Verify"),
+                 _("Verify"),
                 job->hdr.name,
                 jcr->fileset->hdr.name,
                 level_to_str(jcr->JobLevel),
                 jcr->client->hdr.name,
                 jcr->store->hdr.name,
                 NPRT(jcr->pool->hdr.name), 
+                Name,            
                 bstrutime(dt, sizeof(dt), jcr->sched_time),
                 jcr->JobPriority);
+        }
         break;
       case JT_RESTORE:
         if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
@@ -513,6 +570,9 @@ Priority:   %d\n"),
       if (jcr->JobType == JT_BACKUP ||
          jcr->JobType == JT_VERIFY) {
          add_prompt(ua, _("Pool"));          /* 7 */
+        if (jcr->JobType == JT_VERIFY) {
+            add_prompt(ua, _("Verify Job"));  /* 8 */
+        }
       } else if (jcr->JobType == JT_RESTORE) {
          add_prompt(ua, _("Bootstrap"));     /* 7 */
          add_prompt(ua, _("Where"));         /* 8 */
@@ -554,6 +614,7 @@ Priority:   %d\n"),
             add_prompt(ua, _("Initialize Catalog"));
             add_prompt(ua, _("Verify Catalog"));
             add_prompt(ua, _("Verify Volume to Catalog"));
+            add_prompt(ua, _("Verify Disk to Catalog"));
             add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
             switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
            case 0:
@@ -566,6 +627,9 @@ Priority:   %d\n"),
               jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
               break;
            case 3:
+              jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
+              break;
+           case 4:
               jcr->JobLevel = L_VERIFY_DATA;
               break;
            default:
@@ -636,6 +700,7 @@ Priority:   %d\n"),
         }
         goto try_again;
       case 7:
+        /* Pool or Bootstrap depending on JobType */
         if (jcr->JobType == JT_BACKUP ||
             jcr->JobType == JT_VERIFY) {      /* Pool */
            pool = select_pool_resource(ua);
@@ -668,6 +733,16 @@ Priority:   %d\n"),
         }
         goto try_again;
       case 8:
+        /* Verify Job */
+        if (jcr->JobType == JT_VERIFY) {
+           JOB *job = select_job_resource(ua);
+           if (job) {
+              jcr->job->verify_job = job;
+           } else {
+              jcr->job->verify_job = NULL;
+           }
+           goto try_again;
+        }
         /* Where */
          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
            break;
index f3afec0d056e8f8e5e52c4aa40c3bd20b6e2b3ed..98d2528c4ad7bda69687cb5e93426bc1c87217fc 100644 (file)
@@ -84,6 +84,12 @@ int find_arg_keyword(UAContext *ua, char **list)
    return -1;
 }
 
+/* 
+ * Given one keyword, find the first one that
+ *   is in the argument list.
+ * Returns: argk index (always gt 0)
+ *         -1 if not found
+ */
 int find_arg(UAContext *ua, char *keyword)
 {
    for (int i=1; i<ua->argc; i++) {
@@ -272,7 +278,8 @@ CLIENT *get_client_resource(UAContext *ua)
    int i;
    
    for (i=1; i<ua->argc; i++) {
-      if (strcasecmp(ua->argk[i], _("client")) == 0 && ua->argv[i]) {
+      if ((strcasecmp(ua->argk[i], _("client")) == 0 ||
+           strcasecmp(ua->argk[i], _("fd")) == 0) && ua->argv[i]) {
         client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
         if (client) {
            return client;
@@ -305,7 +312,8 @@ int get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
       bsendmsg(ua, _("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
    }
    for (i=1; i<ua->argc; i++) {
-      if (strcasecmp(ua->argk[i], _("client")) == 0 && ua->argv[i]) {
+      if ((strcasecmp(ua->argk[i], _("client")) == 0 ||               
+           strcasecmp(ua->argk[i], _("fd")) == 0) && ua->argv[i]) {
         bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
         if (!db_get_client_record(ua->jcr, ua->db, cr)) {
             bsendmsg(ua, _("Could not find Client %s: ERR=%s"), ua->argv[i],
@@ -341,7 +349,7 @@ int select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
       return 0;
    }
    if (num_clients <= 0) {
-      bsendmsg(ua, _("No clients defined. Run a job to create one.\n"));
+      bsendmsg(ua, _("No clients defined. You must run a job before using this command.\n"));
       return 0;
    }
      
@@ -730,22 +738,24 @@ STORE *get_storage_resource(UAContext *ua, int use_default)
 
    for (i=1; i<ua->argc; i++) {
       if (use_default && !ua->argv[i]) {
+        /* Ignore scan and barcode(s) keywords */
+         if (strncasecmp("scan", ua->argk[i], 4) == 0 ||
+             strncasecmp("barcode", ua->argk[i], 7) == 0) {
+           continue;
+        }
         /* Default argument is storage */
         if (store_name) {
             bsendmsg(ua, _("Storage name given twice.\n"));
            return NULL;
         }
-        /* Ignore barcode(s) keywords */
-         if (strncasecmp("barcode", ua->argk[i], 7) == 0) {
-           continue;
-        }
         store_name = ua->argk[i];
          if (*store_name == '?') {
            *store_name = 0;
            break;
         }
       } else {
-         if (strcasecmp(ua->argk[i], _("storage")) == 0) {
+         if (strcasecmp(ua->argk[i], _("storage")) == 0 ||
+             strcasecmp(ua->argk[i], _("sd")) == 0) {
            store_name = ua->argv[i];
            break;
 
index 44ca5bac40e3e3e7b288f1a5e1bc726e23ab3074..06a96bbbe289f531a83024811b955c604d7806bd 100644 (file)
@@ -34,7 +34,9 @@ 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 list_scheduled_jobs(UAContext *ua);
+static void list_running_jobs(UAContext *ua);
+static void list_terminated_jobs(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);
@@ -190,133 +192,28 @@ static void do_all_status(UAContext *ua, char *cmd)
 
 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;
+   char dt[MAX_TIME_LENGTH];
 
    bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
            HOST_OS, DISTNAME, DISTVER);
    bstrftime(dt, sizeof(dt), daemon_start_time);
+   strcpy(dt+7, dt+9);    /* cut century */
    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[30];
-
-      bstrftime(dt, sizeof(dt), last_job.end_time);
-      bsendmsg(ua, _("Last Job %s finished at %s\n"), last_job.Job, dt);
-      jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
-          
-      bsendmsg(ua, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
-          edit_uint64_with_commas(last_job.JobFiles, b1),
-          edit_uint64_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_Canceled:
-         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;
-      case JS_WaitStoreRes:
-         msg = _("is waiting on max Storage jobs");
-        break;
-      case JS_WaitClientRes:
-         msg = _("is waiting on max Client jobs");
-        break;
-      case JS_WaitJobRes:
-         msg = _("is waiting on max Job jobs");
-        break;
-      case JS_WaitPriority:
-         msg = _("is waiting for higher priority jobs to finish");
-        break;
-      case JS_WaitMaxJobs:
-         msg = _("is waiting on max total jobs");
-        break;
-      case JS_WaitStartTime:
-         msg = _("is waiting for its start time");
-        break;
-
-
-      default:
-        msg = (char *) get_pool_memory(PM_FNAME);
-         Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
-        pool_mem = TRUE;
-        break;
-      }
-      /* 
-       * Now report Storage daemon status code 
-       */
-      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);
+   /*
+    * List scheduled Jobs
+    */
+   list_scheduled_jobs(ua);
+
+   /* 
+    * List running jobs
+    */
+   list_running_jobs(ua);
+
+   /* 
+    * List terminated jobs
+    */
+   list_terminated_jobs(ua);
    bsendmsg(ua, "====\n");
 }
 
@@ -398,6 +295,7 @@ static void prt_runhdr(UAContext *ua)
 static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL *pool)
 {
    char dt[MAX_TIME_LENGTH];      
+   char *level_ptr;
    bool ok = false;
    bool close_db = false;
    JCR *jcr = ua->jcr;
@@ -417,9 +315,18 @@ static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL
       }
    }
    bstrftime(dt, sizeof(dt), runtime);
+   strcpy(dt+7, dt+9);    /* cut century */
+   switch (job->JobType) {
+   case JT_ADMIN:
+   case JT_RESTORE:
+      level_ptr = " ";
+      break;
+   default:
+      level_ptr = level_to_str(level);
+      break;
+   }
    bsendmsg(ua, _("%-14s %-8s %-18s %-18s %s\n"), 
-      level_to_str(level), job_type_to_str(job->JobType), dt, job->hdr.name,
-      mr.VolumeName);
+      level_ptr, job_type_to_str(job->JobType), dt, job->hdr.name, mr.VolumeName);
    if (close_db) {
       db_close_database(jcr, jcr->db);
    }
@@ -428,109 +335,269 @@ static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL
 }
 
 /*         
- * Find all jobs to be run this hour
- * and the next hour.
+ * Find all jobs to be run in roughly the
+ *  next 24 hours.
  */
-static void print_jobs_scheduled(UAContext *ua)
+static void list_scheduled_jobs(UAContext *ua)
 {
-   time_t now, runtime, tomorrow;
+   time_t runtime;
    RUN *run;
    JOB *job;
-   SCHED *sched;
-   struct tm tm;
-   int mday, wday, month, wpos, tmday, twday, tmonth, twpos, i, hour;
-   int tod, tom;
-   int found;
-   int hdr_printed = FALSE;
-   int level;
+   int level, num_jobs = 0;
+   bool hdr_printed = false;
 
    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;
-   wpos = (tm.tm_mday - 1) / 7;
-
-   tomorrow = now + 60 * 60 * 24;
-   localtime_r(&tomorrow, &tm);
-   tmday = tm.tm_mday - 1;
-   twday = tm.tm_wday;
-   tmonth = tm.tm_mon;
-   twpos  = (tm.tm_mday - 1) / 7;
-
    /* Loop through all jobs */
    LockRes();
    for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
-      level = job->level;   
-      sched = job->schedule;
-      if (sched == NULL) {           /* scheduled? */
-        continue;                    /* no, skip this job */
-      }
-      for (run=sched->run; run; run=run->next) {
+      for (run=NULL; (run = find_next_run(run, job, runtime)); ) {
+        level = job->level;   
         if (run->level) {
            level = run->level;
         }
-        /* 
-         * 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) && bit_is_set(wpos, run->wpos);
-
-        tom = (bit_is_set(tmday, run->mday) || bit_is_set(twday, run->wday)) &&
-               bit_is_set(tmonth, run->month) && bit_is_set(wpos, run->wpos);
-
-         Dmsg2(200, "tod=%d tom=%d\n", tod, tom);
-        found = FALSE;
-        if (tod) {                   /* Jobs scheduled today (next 24 hours) */
-           /* 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) {
-                    if (!hdr_printed) {
-                       hdr_printed = TRUE;
-                       prt_runhdr(ua);
-                    }
-                    prt_runtime(ua, job, level, runtime, run->pool);
-                    found = TRUE;
-                    break;
-                 }
-              }
-           }
+        if (!hdr_printed) {
+           prt_runhdr(ua);
+           hdr_printed = true;
         }
+        prt_runtime(ua, job, level, runtime, run->pool);
+        num_jobs++;
+      }
 
-//       Dmsg2(200, "runtime=%d now=%d\n", runtime, now);
-        if (!found && tom) {            /* look at jobs scheduled tomorrow */
-           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) {
-              if (!hdr_printed) {
-                 hdr_printed = TRUE;
-                 prt_runhdr(ua);
-              }
-              prt_runtime(ua, job, level, runtime, run->pool);
-           }
-        }
-      } /* end for loop over runs */ 
    } /* end for loop over resources */
    UnlockRes();
+   if (num_jobs == 0) {
+      bsendmsg(ua, _("No Scheduled Jobs.\n"));
+   } else {
+      bsendmsg(ua, "\n");
+   }
    Dmsg0(200, "Leave find_runs()\n");
 }
+
+static void list_running_jobs(UAContext *ua)
+{
+   JCR *jcr;
+   int njobs = 0;
+   char *msg;
+   char dt[MAX_TIME_LENGTH];
+   char level[10];
+   bool pool_mem = false;
+
+   lock_jcr_chain();
+   for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+      if (jcr->JobId == 0) {     /* this is us */
+        /* this is a console or other control job. We only show console
+         * jobs in the status output.
+         */
+        if (jcr->JobType == JT_CONSOLE) {
+           bstrftime(dt, sizeof(dt), jcr->start_time);
+           strcpy(dt+7, dt+9);  /* cut century */
+            bsendmsg(ua, _("Console connected at %s\n"), dt);
+        }
+        njobs--;
+      }
+      free_locked_jcr(jcr);
+   }
+   if (njobs == 0) {
+      unlock_jcr_chain();
+      bsendmsg(ua, _("No Running Jobs.\n"));
+      return;
+   }
+   njobs = 0;
+   bsendmsg(ua, _("\nRunning Jobs:\n"));
+   bsendmsg(ua, _("Level JobId  Job                        Status\n"));
+   bsendmsg(ua, _("====================================================================\n"));
+   for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+      if (jcr->JobId == 0) {     /* this is us */
+        njobs--;
+        free_locked_jcr(jcr);
+        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_Error:
+         msg = _("has errors");
+        break;
+      case JS_FatalError:
+         msg = _("has a fatal error");
+        break;
+      case JS_Differences:
+         msg = _("has verify differences");
+        break;
+      case JS_Canceled:
+         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;
+      case JS_WaitStoreRes:
+         msg = _("is waiting on max Storage jobs");
+        break;
+      case JS_WaitClientRes:
+         msg = _("is waiting on max Client jobs");
+        break;
+      case JS_WaitJobRes:
+         msg = _("is waiting on max Job jobs");
+        break;
+      case JS_WaitMaxJobs:
+         msg = _("is waiting on max total jobs");
+        break;
+      case JS_WaitStartTime:
+         msg = _("is waiting for its start time");
+        break;
+      case JS_WaitPriority:
+         msg = _("is waiting for higher priority jobs to finish");
+        break;
+
+      default:
+        msg = (char *) get_pool_memory(PM_FNAME);
+         Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
+        pool_mem = true;
+        break;
+      }
+      /* 
+       * Now report Storage daemon status code 
+       */
+      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;
+      }
+      switch (jcr->JobType) {
+      case JT_ADMIN:
+      case JT_RESTORE:
+         bstrncpy(level, "    ", sizeof(level));
+        break;
+      default:
+        bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level));
+        level[4] = 0;
+        break;
+      }
+
+      bsendmsg(ua, _("%-4s %6d  %-20s %s\n"), 
+        level, 
+        jcr->JobId,
+        jcr->Job,
+        msg);
+
+      if (pool_mem) {
+        free_pool_memory(msg);
+        pool_mem = false;
+      }
+      free_locked_jcr(jcr);
+   }
+   unlock_jcr_chain();
+
+   bsendmsg(ua, "\n");
+}
+
+static void list_terminated_jobs(UAContext *ua)
+{
+   char dt[MAX_TIME_LENGTH], b1[30], b2[30];
+   char level[10];
+
+   if (last_jobs->empty()) {
+      bsendmsg(ua, _("No Terminated Jobs.\n"));
+      return;
+   }
+   lock_last_jobs_list();
+   struct s_last_job *je;
+   bsendmsg(ua, _("\nTerminated Jobs:\n"));
+   bsendmsg(ua, _(" JobId  Level   Files          Bytes Status   Finished        Name \n"));
+   bsendmsg(ua, _("======================================================================\n"));
+   for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) {
+      char JobName[MAX_NAME_LENGTH];
+      char *termstat;
+
+      bstrftime(dt, sizeof(dt), je->end_time);
+      strcpy(dt+7, dt+9);     /* cut century */
+      switch (je->JobType) {
+      case JT_ADMIN:
+      case JT_RESTORE:
+         bstrncpy(level, "    ", sizeof(level));
+        break;
+      default:
+        bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
+        level[4] = 0;
+        break;
+      }
+      switch (je->JobStatus) {
+      case JS_Created:
+         termstat = "Created";
+        break;
+      case JS_FatalError:
+      case JS_ErrorTerminated:
+         termstat = "Error";
+        break;
+      case JS_Differences:
+         termstat = "Diffs";
+        break;
+      case JS_Canceled:
+         termstat = "Cancel";
+        break;
+      case JS_Terminated:
+         termstat = "OK";
+        break;
+      default:
+         termstat = "Other";
+        break;
+      }
+      bstrncpy(JobName, je->Job, sizeof(JobName));
+      /* There are three periods after the Job name */
+      char *p;
+      for (int i=0; i<3; i++) {
+         if ((p=strrchr(JobName, '.')) != NULL) {
+           *p = 0;
+        }
+      }
+      bsendmsg(ua, _("%6d  %-4s %8s %14s %-7s  %-8s %s\n"), 
+        je->JobId,
+        level, 
+        edit_uint64_with_commas(je->JobFiles, b1),
+        edit_uint64_with_commas(je->JobBytes, b2), 
+        termstat,
+        dt, JobName);
+   }
+   bsendmsg(ua, "\n");
+   unlock_last_jobs_list();
+}
index 29db4a832dd91ebddf45b2ea66909b2f23dbd3d5..0a87e265ecf157caf80296d624a91477aee1beaa 100644 (file)
@@ -1,7 +1,8 @@
 /*
  *
  *   Bacula Director -- User Agent Database File tree for Restore
- *     command.
+ *     command. This file interacts with the user implementing the
+ *     UA tree commands.
  *
  *     Kern Sibbald, July MMII
  *
@@ -40,7 +41,9 @@ static int markcmd(UAContext *ua, TREE_CTX *tree);
 static int countcmd(UAContext *ua, TREE_CTX *tree);
 static int findcmd(UAContext *ua, TREE_CTX *tree);
 static int lscmd(UAContext *ua, TREE_CTX *tree);
+static int lsmark(UAContext *ua, TREE_CTX *tree);
 static int dircmd(UAContext *ua, TREE_CTX *tree);
+static int estimatecmd(UAContext *ua, TREE_CTX *tree);
 static int helpcmd(UAContext *ua, TREE_CTX *tree);
 static int cdcmd(UAContext *ua, TREE_CTX *tree);
 static int pwdcmd(UAContext *ua, TREE_CTX *tree);
@@ -50,17 +53,19 @@ static int quitcmd(UAContext *ua, TREE_CTX *tree);
 
 struct cmdstruct { char *key; int (*func)(UAContext *ua, TREE_CTX *tree); char *help; }; 
 static struct cmdstruct commands[] = {
- { N_("mark"),       markcmd,      _("mark file for restoration")},
- { N_("unmark"),     unmarkcmd,    _("unmark file for restoration")},
  { N_("cd"),         cdcmd,        _("change current directory")},
- { N_("pwd"),        pwdcmd,       _("print current working directory")},
- { N_("ls"),         lscmd,        _("list current directory")},    
- { N_("dir"),        dircmd,       _("list current directory")},    
  { N_("count"),      countcmd,     _("count marked files")},
- { N_("find"),       findcmd,      _("find files")},
+ { N_("dir"),        dircmd,       _("list current directory")},    
  { N_("done"),       quitcmd,      _("leave file selection mode")},
+ { N_("estimate"),   estimatecmd,  _("estimate restore size")},
  { N_("exit"),       quitcmd,      _("exit = done")},
+ { N_("find"),       findcmd,      _("find files")},
  { N_("help"),       helpcmd,      _("print help")},
+ { N_("lsmark"),     lsmark,       _("list the marked files")},    
+ { N_("ls"),         lscmd,        _("list current directory")},    
+ { N_("mark"),       markcmd,      _("mark file to be restored")},
+ { N_("pwd"),        pwdcmd,       _("print current working directory")},
+ { N_("unmark"),     unmarkcmd,    _("unmark file to be restored")},
  { N_("?"),          helpcmd,      _("print help")},    
             };
 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
@@ -163,7 +168,7 @@ int insert_tree_handler(void *ctx, int num_fields, char **row)
    new_node->FileIndex = atoi(row[2]);
    new_node->JobId = atoi(row[3]);
    new_node->type = type;
-   new_node->extract = 1;            /* extract all by default */
+   new_node->extract = true;         /* extract all by default */
    tree->cnt++;
    return 0;
 }
@@ -174,19 +179,23 @@ int insert_tree_handler(void *ctx, int num_fields, char **row)
  *  down the tree setting all children if the 
  *  node is a directory.
  */
-static void set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, int value)
+static int set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, bool extract)
 {
    TREE_NODE *n;
    FILE_DBR fdbr;
    struct stat statp;
+   int count = 0;
 
-   node->extract = value;
+   node->extract = extract;
+   if (node->type != TN_NEWDIR) {
+      count++;
+   }
    /* For a non-file (i.e. directory), we see all the children */
    if (node->type != TN_FILE) {
       for (n=node->child; n; n=n->sibling) {
-        set_extract(ua, n, tree, value);
+        count += set_extract(ua, n, tree, extract);
       }
-   } else if (value) {
+   } else if (extract) {
       char cwd[2000];
       /* Ordinary file, we get the full path, look up the
        * attributes, decode them, and if we are hard linked to
@@ -195,57 +204,65 @@ static void set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, int valu
       tree_getpath(node, cwd, sizeof(cwd));
       fdbr.FileId = 0;
       fdbr.JobId = node->JobId;
-      if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) {
+      if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
         int32_t LinkFI;
         decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
         /*
          * If we point to a hard linked file, traverse the tree to
-         * find that file, and mark it for restoration as well. It
+         * find that file, and mark it to be restored as well. It
          * must have the Link we just obtained and the same JobId.
          */
         if (LinkFI) {
            for (n=first_tree_node(tree->root); n; n=next_tree_node(n)) {
               if (n->FileIndex == LinkFI && n->JobId == node->JobId) {
-                 n->extract = 1;
+                 n->extract = true;
                  break;
               }
            }
         }
       }
    }
+   return count;
 }
 
 static int markcmd(UAContext *ua, TREE_CTX *tree)
 {
    TREE_NODE *node;
+   int count = 0;
 
-   if (ua->argc < 2)
-      return 1;
-   if (!tree->node->child) {    
+   if (ua->argc < 2 || !tree->node->child) {
+      bsendmsg(ua, _("No files marked.\n"));
       return 1;
    }
-   for (node = tree->node->child; node; node=node->sibling) {
-      if (fnmatch(ua->argk[1], node->fname, 0) == 0) {
-        set_extract(ua, node, tree, 1);
+   for (int i=1; i < ua->argc; i++) {
+      for (node = tree->node->child; node; node=node->sibling) {
+        if (fnmatch(ua->argk[i], node->fname, 0) == 0) {
+           count += set_extract(ua, node, tree, true);
+        }
       }
    }
+   if (count == 0) {
+      bsendmsg(ua, _("No files marked.\n"));
+   } else {
+      bsendmsg(ua, _("%d file%s marked.\n"), count, count==0?"":"s");
+   }
    return 1;
 }
 
 static int countcmd(UAContext *ua, TREE_CTX *tree)
 {
-   int total, extract;
+   int total, num_extract;
 
-   total = extract = 0;
+   total = num_extract = 0;
    for (TREE_NODE *node=first_tree_node(tree->root); node; node=next_tree_node(node)) {
       if (node->type != TN_NEWDIR) {
         total++;
         if (node->extract) {
-           extract++;
+           num_extract++;
         }
       }
    }
-   bsendmsg(ua, "%d total files. %d marked for restoration.\n", total, extract);
+   bsendmsg(ua, "%d total files. %d marked to be restored.\n", total, num_extract);
    return 1;
 }
 
@@ -287,13 +304,34 @@ static int lscmd(UAContext *ua, TREE_CTX *tree)
    return 1;
 }
 
+/*
+ * Ls command that lists only the marked files
+ */
+static int lsmark(UAContext *ua, TREE_CTX *tree)
+{
+   TREE_NODE *node;
+
+   if (!tree->node->child) {    
+      return 1;
+   }
+   for (node = tree->node->child; node; node=node->sibling) {
+      if (ua->argc == 1 || fnmatch(ua->argk[1], node->fname, 0) == 0 &&
+         node->extract) {
+         bsendmsg(ua, "%s%s%s\n", node->extract?"*":"", node->fname,
+            (node->type==TN_DIR||node->type==TN_NEWDIR)?"/":"");
+      }
+   }
+   return 1;
+}
+
+
 extern char *getuser(uid_t uid);
 extern char *getgroup(gid_t gid);
 
 /*
  * This is actually the long form used for "dir"
  */
-static void ls_output(char *buf, char *fname, int extract, struct stat *statp)
+static void ls_output(char *buf, char *fname, bool extract, struct stat *statp)
 {
    char *p, *f;
    char ec1[30];
@@ -338,7 +376,7 @@ static int dircmd(UAContext *ua, TREE_CTX *tree)
         tree_getpath(node, cwd, sizeof(cwd));
         fdbr.FileId = 0;
         fdbr.JobId = node->JobId;
-        if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) {
+        if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
            int32_t LinkFI;
            decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
            ls_output(buf, cwd, node->extract, &statp);
@@ -354,6 +392,45 @@ static int dircmd(UAContext *ua, TREE_CTX *tree)
 }
 
 
+static int estimatecmd(UAContext *ua, TREE_CTX *tree)
+{
+   int total, num_extract;
+   uint64_t total_bytes = 0;
+   FILE_DBR fdbr;
+   struct stat statp;
+   char cwd[1100];
+   char ec1[50];
+
+   total = num_extract = 0;
+   for (TREE_NODE *node=first_tree_node(tree->root); node; node=next_tree_node(node)) {
+      if (node->type != TN_NEWDIR) {
+        total++;
+        /* If regular file, get size */
+        if (node->extract && node->type == TN_FILE) {
+           num_extract++;
+           tree_getpath(node, cwd, sizeof(cwd));
+           fdbr.FileId = 0;
+           fdbr.JobId = node->JobId;
+           if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
+              int32_t LinkFI;
+              decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
+              if (S_ISREG(statp.st_mode) && statp.st_size > 0) {
+                 total_bytes += statp.st_size;
+              }
+           }
+        /* Directory, count only */
+        } else if (node->extract) {
+           num_extract++;
+        }
+      }
+   }
+   bsendmsg(ua, "%d total files; %d marked to be restored; %s bytes.\n", 
+           total, num_extract, edit_uint64_with_commas(total_bytes, ec1));
+   return 1;
+}
+
+
+
 static int helpcmd(UAContext *ua, TREE_CTX *tree) 
 {
    unsigned int i;
@@ -413,17 +490,24 @@ static int pwdcmd(UAContext *ua, TREE_CTX *tree)
 static int unmarkcmd(UAContext *ua, TREE_CTX *tree)
 {
    TREE_NODE *node;
+   int count = 0;
 
-   if (ua->argc < 2)
-      return 1;
-   if (!tree->node->child) {    
+   if (ua->argc < 2 || !tree->node->child) {    
+      bsendmsg(ua, _("No files unmarked.\n"));
       return 1;
    }
-   for (node = tree->node->child; node; node=node->sibling) {
-      if (fnmatch(ua->argk[1], node->fname, 0) == 0) {
-        set_extract(ua, node, tree, 0);
+   for (int i=1; i < ua->argc; i++) {
+      for (node = tree->node->child; node; node=node->sibling) {
+        if (fnmatch(ua->argk[i], node->fname, 0) == 0) {
+           count += set_extract(ua, node, tree, false);
+        }
       }
    }
+   if (count == 0) {
+      bsendmsg(ua, _("No files unmarked.\n"));
+   } else {
+      bsendmsg(ua, _("%d file%s unmarked.\n"), count, count==0?"":"s");
+   }
    return 1;
 }
 
index 40faac1e41f1669c9af3e6688d8be073dc42ad7d..5fc210e2b0cb690f4b16e4964d5a69f8161ebb5d 100644 (file)
@@ -64,26 +64,41 @@ static int missing_handler(void *ctx, int num_fields, char **row);
  */
 int do_verify(JCR *jcr) 
 {
-   char *level;
+   char *level, *Name;
    BSOCK   *fd;
-   JOB_DBR jr;
-   JobId_t JobId = 0;
+   JOB_DBR jr, verify_jr;
+   JobId_t verify_jobid = 0;
    int stat;
 
+   memset(&verify_jr, 0, sizeof(verify_jr));
+   if (!jcr->verify_jr) {
+      jcr->verify_jr = &verify_jr;
+   }
    if (!get_or_create_client_record(jcr)) {
       goto bail_out;
    }
 
    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.
+   /*
+    * Find JobId of last job that ran. E.g. 
+    *  for VERIFY_CATALOG we want the JobId of the last INIT.
+    *  for VERIFY_VOLUME_TO_CATALOG, we want the JobId of the 
+    *      last backup Job.
     */
    if (jcr->JobLevel == L_VERIFY_CATALOG || 
-       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
+       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
+       jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
       memcpy(&jr, &jcr->jr, sizeof(jr));
-      if (!db_find_last_jobid(jcr, jcr->db, &jr)) {
+      if (jcr->job->verify_job &&
+         (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
+          jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG)) {
+        Name = jcr->job->verify_job->hdr.name;
+      } else {
+        Name = NULL;
+      }
+      Dmsg1(100, "find last jobid for: %s\n", NPRT(Name));
+      if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) {
         if (jcr->JobLevel == L_VERIFY_CATALOG) {
            Jmsg(jcr, M_FATAL, 0, _(
                  "Unable to find JobId of previous InitCatalog Job.\n"
@@ -95,8 +110,8 @@ int do_verify(JCR *jcr)
         }   
         goto bail_out;
       }
-      JobId = jr.JobId;
-      Dmsg1(20, "Last full id=%d\n", JobId);
+      verify_jobid = jr.JobId;
+      Dmsg1(100, "Last full jobid=%d\n", verify_jobid);
    } 
 
    jcr->jr.JobId = jcr->JobId;
@@ -111,28 +126,30 @@ int do_verify(JCR *jcr)
       jcr->fname = get_pool_memory(PM_FNAME);
    }
 
-   jcr->jr.JobId = JobId;      /* save target JobId */
-
    /* Print Job Start message */
    Jmsg(jcr, M_INFO, 0, _("Start Verify JobId %d Job=%s\n"),
       jcr->JobId, jcr->Job);
 
+   /*
+    * Now get the job record for the previous backup that interests
+    *  us. We use the verify_jobid that we found above.
+    */
    if (jcr->JobLevel == L_VERIFY_CATALOG || 
-       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
-      memset(&jr, 0, sizeof(jr));
-      jr.JobId = JobId;
-      if (!db_get_job_record(jcr, jcr->db, &jr)) {
+       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
+       jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
+      verify_jr.JobId = verify_jobid;
+      if (!db_get_job_record(jcr, jcr->db, &verify_jr)) {
          Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), 
              db_strerror(jcr->db));
         goto bail_out;
       }
-      if (jr.JobStatus != 'T') {
+      if (verify_jr.JobStatus != 'T') {
          Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"),
-           JobId, jr.JobStatus);
+           verify_jobid, verify_jr.JobStatus);
         goto bail_out;
       }
       Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"),
-        JobId, jr.Job); 
+        verify_jr.JobId, verify_jr.Job); 
    }
 
    /* 
@@ -144,12 +161,12 @@ int do_verify(JCR *jcr)
    if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
       RBSR *bsr = new_bsr();
       UAContext *ua;
-      bsr->JobId = jr.JobId;
+      bsr->JobId = verify_jr.JobId;
       ua = new_ua_context(jcr);
       complete_bsr(ua, bsr);
       bsr->fi = new_findex();
       bsr->fi->findex = 1;
-      bsr->fi->findex2 = jr.JobFiles;
+      bsr->fi->findex2 = verify_jr.JobFiles;
       if (!write_bsr_file(ua, bsr)) {
         free_ua_context(ua);
         free_bsr(bsr);
@@ -188,6 +205,12 @@ int do_verify(JCR *jcr)
    } else {
       jcr->sd_auth_key = bstrdup("dummy");    /* dummy Storage daemon key */
    }
+
+   if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG && jcr->job->verify_job) {
+      jcr->fileset = jcr->job->verify_job->fileset;
+   }
+   Dmsg2(100, "ClientId=%u JobLevel=%c\n", verify_jr.ClientId, jcr->JobLevel);
+
    /*
     * OK, now connect to the File daemon
     *  and ask him for the files.
@@ -200,6 +223,7 @@ int do_verify(JCR *jcr)
    set_jcr_job_status(jcr, JS_Running);
    fd = jcr->file_bsock;
 
+
    Dmsg0(30, ">filed: Send include list\n");
    if (!send_include_list(jcr)) {
       goto bail_out;
@@ -262,6 +286,9 @@ int do_verify(JCR *jcr)
    case L_VERIFY_DATA:
       level = "data";
       break;
+   case L_VERIFY_DISK_TO_CATALOG:
+      level="disk_to_catalog";
+      break;
    default:
       Jmsg1(jcr, M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->JobLevel);
       goto bail_out;
@@ -290,12 +317,19 @@ int do_verify(JCR *jcr)
       Dmsg0(10, "Verify level=catalog\n");
       jcr->sd_msg_thread_done = true;  /* no SD msg thread, so it is done */
       jcr->SDJobStatus = JS_Terminated;
-      get_attributes_and_compare_to_catalog(jcr, JobId);
+      get_attributes_and_compare_to_catalog(jcr, verify_jobid);
       break;
 
    case L_VERIFY_VOLUME_TO_CATALOG:
       Dmsg0(10, "Verify level=volume\n");
-      get_attributes_and_compare_to_catalog(jcr, JobId);
+      get_attributes_and_compare_to_catalog(jcr, verify_jobid);
+      break;
+
+   case L_VERIFY_DISK_TO_CATALOG:
+      Dmsg0(10, "Verify level=disk_to_catalog\n");
+      jcr->sd_msg_thread_done = true;  /* no SD msg thread, so it is done */
+      jcr->SDJobStatus = JS_Terminated;
+      get_attributes_and_compare_to_catalog(jcr, verify_jobid);
       break;
 
    case L_VERIFY_INIT:
@@ -312,7 +346,6 @@ int do_verify(JCR *jcr)
    }
 
    stat = wait_for_job_termination(jcr);
-
    verify_cleanup(jcr, stat);
    return 1;
 
@@ -333,8 +366,9 @@ static void verify_cleanup(JCR *jcr, int TermCode)
    char *term_msg;
    int msg_type;
    JobId_t JobId;
+   char *Name;
 
-// Dmsg1(000, "Enter verify_cleanup() TermCod=%d\n", TermCode);
+// Dmsg1(100, "Enter verify_cleanup() TermCod=%d\n", TermCode);
 
    JobId = jcr->jr.JobId;
    set_jcr_job_status(jcr, TermCode);
@@ -358,21 +392,29 @@ static void verify_cleanup(JCR *jcr, int TermCode)
       break;
    default:
       term_msg = term_code;
-      sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
+      bsnprintf(term_code, sizeof(term_code), 
+                _("Inappropriate term code: %d %c\n"), TermCode, TermCode);
       break;
    }
    bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
    bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
+   if (jcr->job->verify_job) {
+      Name = jcr->job->verify_job->hdr.name;
+   } else {
+      Name = "";
+   }
 
    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
    if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
-       jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
+      jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
       Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\
 JobId:                  %d\n\
 Job:                    %s\n\
 FileSet:                %s\n\
 Verify Level:           %s\n\
 Client:                 %s\n\
+Verify JobId:           %d\n\
+Verify Job:             %s\n\
 Start time:             %s\n\
 End time:               %s\n\
 Files Examined:         %s\n\
@@ -386,6 +428,8 @@ Termination:            %s\n\n"),
         jcr->fileset->hdr.name,
         level_to_str(jcr->JobLevel),
         jcr->client->hdr.name,
+        jcr->verify_jr->JobId,
+        Name,
         sdt,
         edt,
         edit_uint64_with_commas(jcr->JobFiles, ec1),
@@ -400,6 +444,8 @@ Job:                    %s\n\
 FileSet:                %s\n\
 Verify Level:           %s\n\
 Client:                 %s\n\
+Verify JobId:           %d\n\
+Verify Job:             %s\n\
 Start time:             %s\n\
 End time:               %s\n\
 Files Examined:         %s\n\
@@ -412,6 +458,8 @@ Termination:            %s\n\n"),
         jcr->fileset->hdr.name,
         level_to_str(jcr->JobLevel),
         jcr->client->hdr.name,
+        jcr->verify_jr->JobId,
+        Name,
         sdt,
         edt,
         edit_uint64_with_commas(jcr->JobFiles, ec1),
@@ -465,7 +513,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
 
       fname = check_pool_memory_size(fname, fd->msglen);
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
-      Dmsg1(400, "Atts+SIG=%s\n", fd->msg);
+      Dmsg1(200, "Atts+SIG=%s\n", fd->msg);
       if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream, 
            fname)) != 3) {
          Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n\
@@ -510,7 +558,8 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          * Find equivalent record in the database 
          */
         fdbr.FileId = 0;
-        if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname, &fdbr)) {
+        if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname, 
+             jcr->verify_jr, &fdbr)) {
             Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
             Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname);
            stat = JS_Differences;
index f97f16974f82bad78c1affae2a04da2a15b156e6..9edec269560cbd90ebcbbed7c91b636d7a70c32e 100644 (file)
@@ -7,3 +7,4 @@ host.h
 startit
 static-bacula-fd
 stopit
+filed.conf
index 4ad2c704d25120d04c8bb966b358f3410462a2af..aa8dbe07bef51fda265f104efa9936502e179e22 100644 (file)
@@ -99,54 +99,52 @@ int main (int argc, char *argv[])
    init_msg(NULL, NULL);
    daemon_start_time = time(NULL);
 
-   memset(&last_job, 0, sizeof(last_job));
-
    while ((ch = getopt(argc, argv, "c:d:fg:istu:v?")) != -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 'g':                    /* set group */
-           gid = optarg;
-           break;
-
-         case 'i':
-           inetd_request = TRUE;
-           break;
-         case 's':
-           no_signals = TRUE;
-           break;
-
-         case 't':
-           test_config = TRUE;
-           break;
-
-         case 'u':                    /* set userid */
-           uid = optarg;
-           break;
-
-         case 'v':                    /* verbose */
-           verbose++;
-           break;
-
-         case '?':
-        default:
-           usage();
+      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 'g':                    /* set group */
+        gid = optarg;
+        break;
+
+      case 'i':
+        inetd_request = TRUE;
+        break;
+      case 's':
+        no_signals = TRUE;
+        break;
+
+      case 't':
+        test_config = TRUE;
+        break;
+
+      case 'u':                    /* set userid */
+        uid = optarg;
+        break;
+
+      case 'v':                    /* verbose */
+        verbose++;
+        break;
+
+      case '?':
+      default:
+        usage();
 
       }  
    }
index e79f6142bde2ba7147177c446da2af736a9a2830..23796405bd665c26cbdc1c76ed5b69c4b1bcf59c 100644 (file)
@@ -307,7 +307,7 @@ static int estimate_cmd(JCR *jcr)
    }
    make_estimate(jcr);
    bnet_fsend(dir, OKest, jcr->num_files_examined, 
-      edit_uint64(jcr->JobBytes, ed2));
+      edit_uint64_with_commas(jcr->JobBytes, ed2));
    bnet_sig(dir, BNET_EOD);
    return 1;
 }
@@ -436,6 +436,7 @@ static void add_fname_to_list(JCR *jcr, char *fname, int list)
 
    switch (*p) {
    case '|':
+      p++;                           /* skip over | */
       fn = get_pool_memory(PM_FNAME);
       fn = edit_job_codes(jcr, fn, p, "");
       bpipe = open_bpipe(fn, 0, "r");
@@ -590,7 +591,7 @@ static int bootstrap_cmd(JCR *jcr)
 static int level_cmd(JCR *jcr)
 {
    BSOCK *dir = jcr->dir_bsock;
-   POOLMEM *level;
+   POOLMEM *level, *buf = NULL;
    struct tm tm;
    time_t mtime;
    int mtime_only;
@@ -598,10 +599,7 @@ static int level_cmd(JCR *jcr)
    level = get_memory(dir->msglen+1);
    Dmsg1(110, "level_cmd: %s", dir->msg);
    if (sscanf(dir->msg, "level = %s ", level) != 1) {
-      pm_strcpy(&jcr->errmsg, dir->msg);
-      Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
-      free_memory(level);
-      return 0;
+      goto bail_out;
    }
    /* Base backup requested? */
    if (strcmp(level, "base") == 0) {
@@ -612,16 +610,14 @@ static int level_cmd(JCR *jcr)
    /* 
     * Backup requested since <date> <time>
     *  This form is also used for incremental and differential
+    *  This code is deprecated.  See since_utime for new code.
     */
    } else if (strcmp(level, "since") == 0) {
       jcr->JobLevel = L_SINCE;
       if (sscanf(dir->msg, "level = since %d-%d-%d %d:%d:%d mtime_only=%d", 
                 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
                 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &mtime_only) != 7) {
-        pm_strcpy(&jcr->errmsg, dir->msg);
-         Jmsg1(jcr, M_FATAL, 0, _("Bad scan of date/time: %s\n"), jcr->errmsg);
-        free_memory(level);
-        return 0;
+        goto bail_out;
       }
       tm.tm_year -= 1900;
       tm.tm_mon  -= 1;
@@ -632,13 +628,75 @@ static int level_cmd(JCR *jcr)
       jcr->incremental = 1;          /* set incremental or decremental backup */
       jcr->mtime = mtime;            /* set since time */
       jcr->mtime_only = mtime_only;   /* and what to compare */
+   /*
+    * We get his UTC since time, then sync the clocks and correct it
+    *  to agree with our clock.
+    */
+   } else if (strcmp(level, "since_utime") == 0) {
+      buf = get_memory(dir->msglen+1);
+      utime_t since_time, adj;
+      btime_t his_time, bt_start, rt=0, bt_adj=0;
+      jcr->JobLevel = L_SINCE;
+      if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d", 
+                buf, &mtime_only) != 2) { 
+        goto bail_out;
+      }
+      since_time = str_to_uint64(buf); /* this is the since time */
+      char ed1[50], ed2[50];
+      /* 
+       * Sync clocks by polling him for the time. We take       
+       *   10 samples of his time throwing out the first two.
+       */
+      for (int i=0; i<10; i++) {
+        bt_start = get_current_btime();
+        bnet_sig(dir, BNET_BTIME);   /* poll for time */
+        if (bnet_recv(dir) <= 0) {   /* get response */
+           goto bail_out;
+        }
+         if (sscanf(dir->msg, "btime %s", buf) != 1) {
+           goto bail_out;
+        }
+        if (i < 2) {                 /* toss first two results */
+           continue;
+        }
+        his_time = str_to_uint64(buf);
+        rt = get_current_btime() - bt_start; /* compute round trip time */
+        bt_adj -= his_time - bt_start - rt/2;
+         Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
+      }
+
+      bt_adj = bt_adj / 8;           /* compute average time */
+      Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
+      adj = btime_to_utime(bt_adj);
+      since_time += adj;             /* adjust for clock difference */
+      if (adj != 0) {
+         Jmsg(jcr, M_INFO, 0, _("Since time adjusted by %d seconds.\n"), adj);
+      }
+      bnet_sig(dir, BNET_EOD);
+
+      Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
+      jcr->incremental = 1;          /* set incremental or decremental backup */
+      jcr->mtime = since_time;       /* set since time */
+      jcr->mtime_only = mtime_only;   /* and what to compare */
    } else {
       Jmsg1(jcr, M_FATAL, 0, "Unknown backup level: %s\n", level);
       free_memory(level);
       return 0;
    }
    free_memory(level);
+   if (buf) {
+      free_memory(buf);
+   }
    return bnet_fsend(dir, OKlevel);
+
+bail_out:
+   pm_strcpy(&jcr->errmsg, dir->msg);
+   Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
+   free_memory(level);
+   if (buf) {
+      free_memory(buf);
+   }
+   return 0;
 }
 
 /*
@@ -843,6 +901,8 @@ static int verify_cmd(JCR *jcr)
       jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
    } else if (strcasecmp(level, "data") == 0){
       jcr->JobLevel = L_VERIFY_DATA;
+   } else if (strcasecmp(level, "disk_to_catalog") == 0) {
+      jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
    } else {   
       bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
       return 0;   
@@ -875,6 +935,9 @@ static int verify_cmd(JCR *jcr)
       /* Inform Storage daemon that we are done */
       bnet_sig(sd, BNET_TERMINATE);
 
+      break;
+   case L_VERIFY_DISK_TO_CATALOG:
+      do_verify(jcr);
       break;
    default:
       bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
@@ -972,6 +1035,9 @@ static int restore_cmd(JCR *jcr)
 
 bail_out:
 
+   if (jcr->Errors) {
+      set_jcr_job_status(jcr, JS_ErrorTerminated);
+   }
    /* Send termination status back to Dir */
    bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles, 
       edit_uint64(jcr->ReadBytes, ed1), 
@@ -1049,6 +1115,7 @@ static void filed_free_jcr(JCR *jcr)
    if (jcr->RestoreBootstrap) {
       unlink(jcr->RestoreBootstrap);
       free_pool_memory(jcr->RestoreBootstrap);
+      jcr->RestoreBootstrap = NULL;
    }
    if (jcr->last_fname) {
       free_pool_memory(jcr->last_fname);
@@ -1096,6 +1163,7 @@ static int send_bootstrap_file(JCR *jcr)
    char buf[2000];
    BSOCK *sd = jcr->store_bsock;
    char *bootstrap = "bootstrap\n";
+   int stat = 0;
 
    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
    if (!jcr->RestoreBootstrap) {
@@ -1106,7 +1174,7 @@ static int send_bootstrap_file(JCR *jcr)
       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), 
         jcr->RestoreBootstrap, strerror(errno));
       set_jcr_job_status(jcr, JS_ErrorTerminated);
-      return 0;
+      goto bail_out;
    }
    pm_strcpy(&sd->msg, bootstrap);  
    sd->msglen = strlen(sd->msg);
@@ -1119,7 +1187,16 @@ static int send_bootstrap_file(JCR *jcr)
    fclose(bs);
    if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
-      return 0;
+      goto bail_out;
    }
-   return 1;
+   stat = 1;
+
+bail_out:
+   if (jcr->RestoreBootstrap) {
+      unlink(jcr->RestoreBootstrap);
+      free_pool_memory(jcr->RestoreBootstrap);
+      jcr->RestoreBootstrap = NULL;
+   }
+
+   return stat;
 }
index 068306b060330a26d2dd2600516fe1e114c4247f..eb4afe2686505c58dd66bf101d8377e1a246603c 100644 (file)
@@ -33,6 +33,9 @@
 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
 
 /* Forward referenced functions */
+#ifdef HAVE_LIBZ
+static char *zlib_strerror(int stat);
+#endif
 
 #define RETRY 10                     /* retry wait time */
 
@@ -47,7 +50,7 @@ void do_restore(JCR *jcr)
    uint32_t size;
    uint32_t VolSessionId, VolSessionTime;
    int32_t file_index;
-   int extract = FALSE;
+   bool extract = false;
    BFILE bfd;
    int stat;
    uint32_t total = 0;               /* Job total but only 32 bits for debug */
@@ -125,7 +128,7 @@ void do_restore(JCR *jcr)
                Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open\n"));
            }
            set_attributes(jcr, attr, &bfd);
-           extract = FALSE;
+           extract = false;
             Dmsg0(30, "Stop extracting.\n");
         }
 
@@ -157,14 +160,14 @@ void do_restore(JCR *jcr)
         jcr->num_files_examined++;
 
          Dmsg1(30, "Outfile=%s\n", attr->ofname);
-        extract = FALSE;
+        extract = false;
         stat = create_file(jcr, attr, &bfd, jcr->replace);
         switch (stat) {
         case CF_ERROR:
         case CF_SKIP:
            break;
         case CF_EXTRACT:
-           extract = TRUE;
+           extract = true;
            P(jcr->mutex);
            pm_strcpy(&jcr->last_fname, attr->ofname);
            V(jcr->mutex);
@@ -206,7 +209,8 @@ void do_restore(JCR *jcr)
                  if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
                      Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
                         edit_uint64(fileAddr, ec1), attr->ofname, berror(&bfd));
-                    extract = FALSE;
+                    extract = false;
+                    bclose(&bfd);
                     continue;
                  }
               }
@@ -218,7 +222,8 @@ void do_restore(JCR *jcr)
            if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) {
                Dmsg0(0, "===Write error===\n");
                Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: ERR=%s\n"), attr->ofname, berror(&bfd));
-              extract = FALSE;
+              extract = false;
+              bclose(&bfd);
               continue;
            } 
            total += wsize;
@@ -250,7 +255,8 @@ void do_restore(JCR *jcr)
                  if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
                      Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
                         edit_uint64(fileAddr, ec1), attr->ofname, berror(&bfd));
-                    extract = FALSE;
+                    extract = false;
+                    bclose(&bfd);
                     continue;
                  }
               }
@@ -262,8 +268,10 @@ void do_restore(JCR *jcr)
             Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
            if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len, 
                  (const Byte *)wbuf, (uLong)wsize)) != Z_OK) {
-               Jmsg(jcr, M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
-              extract = FALSE;
+               Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"), 
+                 attr->ofname, zlib_strerror(stat));
+              extract = false;
+              bclose(&bfd);
               continue;
            }
 
@@ -271,7 +279,8 @@ void do_restore(JCR *jcr)
            if ((uLong)bwrite(&bfd, jcr->compress_buf, compress_len) != compress_len) {
                Dmsg0(0, "===Write error===\n");
                Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), attr->ofname, berror(&bfd));
-              extract = FALSE;
+              extract = false;
+              bclose(&bfd);
               continue;
            }
            total += compress_len;
@@ -282,7 +291,8 @@ void do_restore(JCR *jcr)
 #else
         if (extract) {
             Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
-           extract = FALSE;
+           extract = false;
+           bclose(&bfd);
            continue;
         }
 #endif
@@ -308,7 +318,7 @@ void do_restore(JCR *jcr)
                Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
            }
            set_attributes(jcr, attr, &bfd);
-           extract = FALSE;
+           extract = false;
         }
          Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
@@ -333,6 +343,7 @@ ok_out:
       free(jcr->compress_buf);
       jcr->compress_buf = NULL;
    }
+   bclose(&bfd);
    free_attr(attr);
    Dmsg2(10, "End Do Restore. Files=%d Bytes=%" lld "\n", jcr->JobFiles,
       jcr->JobBytes);
@@ -341,3 +352,31 @@ ok_out:
         non_support_data, non_support_attr);
    }
 }         
+
+#ifdef HAVE_LIBZ
+/*
+ * Convert ZLIB error code into an ASCII message
+ */
+static char *zlib_strerror(int stat)
+{
+   if (stat >= 0) {
+      return "None";
+   }
+   switch (stat) {
+   case Z_ERRNO:
+      return "Zlib errno";
+   case Z_STREAM_ERROR:
+      return "Zlib stream error";
+   case Z_DATA_ERROR:
+      return "Zlib data error";
+   case Z_MEM_ERROR:
+      return "Zlib memory error";
+   case Z_BUF_ERROR:
+      return "Zlib buffer error";
+   case Z_VERSION_ERROR:
+      return "Zlib version error";
+   default:
+      return "*none*";
+   }
+}
+#endif
index c1c6ce18783737fa69b19fa0f49e089156ebd985..90ebead8f7c92e1bdd7c7d727237ed0291e1527b 100755 (executable)
@@ -33,6 +33,12 @@ extern char my_name[];
 extern struct s_last_job last_job;
 extern time_t daemon_start_time;
 
+/* Forward referenced functions */
+static void  list_terminated_jobs(void sendit(char *msg, int len, void *sarg), void *arg);
+static void bsock_sendit(char *msg, int len, void *arg);
+static char *level_to_str(int level);
+
+
 #ifdef HAVE_CYGWIN
 static int privs = 0;
 #endif
@@ -53,44 +59,56 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg)
    len = Mmsg(&msg, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
              HOST_OS, DISTNAME, DISTVER);
    sendit(msg, len, arg);
-   bstrftime(dt, sizeof(dt), daemon_start_time);
+   bstrftime_nc(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);
 #ifdef HAVE_CYGWIN
-   if (!privs) {
-      privs = enable_backup_privileges(NULL, 1);
+   if (debug_level > 0) {
+      if (!privs) {
+        privs = enable_backup_privileges(NULL, 1);
+      }
+      len = Mmsg(&msg, 
+         _("Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs,
+         p_OpenProcessToken?"":"!",
+         p_AdjustTokenPrivileges?"":"!",
+         p_LookupPrivilegeValue?"":"!",
+         p_GetFileAttributesEx?"":"!",
+         p_BackupRead?"":"!",
+         p_BackupWrite?"":"!",
+         p_SetProcessShutdownParameters?"":"!");
+      sendit(msg, len, arg);
    }
-   len = Mmsg(&msg, 
-      _("Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs,
-      p_OpenProcessToken?"":"!",
-      p_AdjustTokenPrivileges?"":"!",
-      p_LookupPrivilegeValue?"":"!",
-      p_GetFileAttributesEx?"":"!",
-      p_BackupRead?"":"!",
-      p_BackupWrite?"":"!",
-      p_SetProcessShutdownParameters?"":"!");
-   sendit(msg, len, arg);
 #endif
 
-   if (last_job.NumJobs > 0) {
+   list_terminated_jobs(sendit, arg);
+
+#ifdef xxx
       char termstat[30];
+      struct s_last_job *je;
+      lock_last_jobs_list();
+      for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) {
+        bstrftime_nc(dt, sizeof(dt), je->end_time);
+         len = Mmsg(&msg, _("Last Job %s finished at %s\n"), je->Job, dt);
+        sendit(msg, len, arg);
 
-      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);
+        jobstatus_to_ascii(je->JobStatus, termstat, sizeof(termstat));
+         len = Mmsg(&msg, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
+             edit_uint64_with_commas(je->JobFiles, b1),
+             edit_uint64_with_commas(je->JobBytes, b2),
+             termstat);
+        sendit(msg, len, arg);
+      }
+      unlock_last_jobs_list();
+#endif
 
-      jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
-      len = Mmsg(&msg, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
-          edit_uint64_with_commas(last_job.JobFiles, b1),
-          edit_uint64_with_commas(last_job.JobBytes, b2),
-          termstat);
-      sendit(msg, len, arg);
-   }
+   /*
+    * List running jobs  
+    */
    Dmsg0(200, "Begin status jcr loop.\n");
    lock_jcr_chain();
    for (njcr=NULL; (njcr=get_next_jcr(njcr)); ) {
-      bstrftime(dt, sizeof(dt), njcr->start_time);
+      bstrftime_nc(dt, sizeof(dt), njcr->start_time);
       if (njcr->JobId == 0) {
          len = Mmsg(&msg, _("Director connected at: %s\n"), dt);
       } else {
@@ -145,13 +163,93 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg)
    free_pool_memory(msg);
 }
 
+static void  list_terminated_jobs(void sendit(char *msg, int len, void *sarg), void *arg) 
+{
+   char dt[MAX_TIME_LENGTH], b1[30], b2[30];
+   char level[10];
+   struct s_last_job *je;
+   char *msg;
+
+   if (last_job.NumJobs == 0) {
+      msg = _("No Terminated Jobs.\n"); 
+      sendit(msg, strlen(msg), arg);
+      return;
+   }
+   lock_last_jobs_list();
+   sendit("\n", 1, arg);               /* send separately */
+   msg =  _("Terminated Jobs:\n"); 
+   sendit(msg, strlen(msg), arg);
+   msg =  _(" JobId  Level   Files          Bytes Status   Finished        Name \n");
+   sendit(msg, strlen(msg), arg);
+   msg = _("======================================================================\n"); 
+   sendit(msg, strlen(msg), arg);
+   for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) {
+      char JobName[MAX_NAME_LENGTH];
+      char *termstat;
+      char buf[1000];
+
+      bstrftime_nc(dt, sizeof(dt), je->end_time);
+      switch (je->JobType) {
+      case JT_ADMIN:
+      case JT_RESTORE:
+         bstrncpy(level, "    ", sizeof(level));
+        break;
+      default:
+        bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
+        level[4] = 0;
+        break;
+      }
+      switch (je->JobStatus) {
+      case JS_Created:
+         termstat = "Created";
+        break;
+      case JS_FatalError:
+      case JS_ErrorTerminated:
+         termstat = "Error";
+        break;
+      case JS_Differences:
+         termstat = "Diffs";
+        break;
+      case JS_Canceled:
+         termstat = "Cancel";
+        break;
+      case JS_Terminated:
+         termstat = "OK";
+        break;
+      default:
+         termstat = "Other";
+        break;
+      }
+      bstrncpy(JobName, je->Job, sizeof(JobName));
+      /* There are three periods after the Job name */
+      char *p;
+      for (int i=0; i<3; i++) {
+         if ((p=strrchr(JobName, '.')) != NULL) {
+           *p = 0;
+        }
+      }
+      bsnprintf(buf, sizeof(buf), _("%6d  %-4s %8s %14s %-7s  %-8s %s\n"), 
+        je->JobId,
+        level, 
+        edit_uint64_with_commas(je->JobFiles, b1),
+        edit_uint64_with_commas(je->JobBytes, b2), 
+        termstat,
+        dt, JobName);
+      sendit(buf, strlen(buf), arg);
+   }
+   sendit("\n", 1, arg);
+   unlock_last_jobs_list();
+}
+
+
 /*
- * Send to Director 
+ * Send to bsock (Director or Console)
  */
-static void sendit(char *msg, int len, void *arg)
+static void bsock_sendit(char *msg, int len, void *arg)
 {
    BSOCK *user = (BSOCK *)arg;
 
+   user->msg = check_pool_memory_size(user->msg, len+1);
    memcpy(user->msg, msg, len+1);
    user->msglen = len+1;
    bnet_send(user);
@@ -165,7 +263,7 @@ int status_cmd(JCR *jcr)
    BSOCK *user = jcr->dir_bsock;
 
    bnet_fsend(user, "\n");
-   do_status(sendit, (void *)user);
+   do_status(bsock_sendit, (void *)user);
    bnet_fsend(user, "====\n");
 
    bnet_sig(user, BNET_EOD);
@@ -173,6 +271,54 @@ int status_cmd(JCR *jcr)
 }
 
 
+/*
+ * Convert Job Level into a string
+ */
+static char *level_to_str(int level) 
+{
+   char *str;
+
+   switch (level) {
+   case L_BASE:
+      str = _("Base");
+   case L_FULL:
+      str = _("Full");
+      break;
+   case L_INCREMENTAL:
+      str = _("Incremental");
+      break;
+   case L_DIFFERENTIAL:
+      str = _("Differential");
+      break;
+   case L_SINCE:
+      str = _("Since");
+      break;
+   case L_VERIFY_CATALOG:
+      str = _("Verify Catalog");
+      break;
+   case L_VERIFY_INIT:
+      str = _("Init Catalog");
+      break;
+   case L_VERIFY_VOLUME_TO_CATALOG:
+      str = _("Volume to Catalog");
+      break;
+   case L_VERIFY_DISK_TO_CATALOG:
+      str = _("Disk to Catalog");
+      break;
+   case L_VERIFY_DATA:
+      str = _("Data");
+      break;
+   case L_NONE:
+      str = " ";
+      break;
+   default:
+      str = _("Unknown Job Level");
+      break;
+   }
+   return str;
+}
+
+
 #ifdef HAVE_CYGWIN
 #include <windows.h>
 
@@ -191,7 +337,7 @@ static void win32_sendit(char *msg, int len, void *marg)
 {
    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
 
-   if (len > 0) {
+   if (len > 0 && msg[len-1] == '\n') {
       msg[len-1] = 0;                /* eliminate newline */
    }
    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
@@ -219,12 +365,16 @@ char *bac_status(int stat)
    bacstat = 0;
    if (last_job.NumJobs > 0) {
       switch (last_job.JobStatus) {
-       case JS_ErrorTerminated:
-           bacstat = -1;
-            termstat = _("Last Job Erred");
-           break;
-       default:
-           break;
+      case JS_Canceled:
+        bacstat = -1;
+         termstat = _("Last Job Canceled");
+        break;
+      case JS_ErrorTerminated:
+        bacstat = -1;
+         termstat = _("Last Job Failed");
+        break;
+      default:
+        break;
       }
    }
    Dmsg0(200, "Begin bac_status jcr loop.\n");
@@ -240,7 +390,7 @@ char *bac_status(int stat)
    }
    unlock_jcr_chain();
    Dmsg0(200, "End bac_status jcr loop.\n");
-   strcpy(buf, termstat);
+   bstrncpy(buf, termstat, sizeof(buf));
    return buf;
 }
 
index bd5ac212e0b86536c1d753eb5fdecc4140e8260e..cf414d63209cf79402e7cc62bd8b6e00c1cfef65 100644 (file)
@@ -119,7 +119,7 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt)
       return 1;
    case FT_DIRNOCHG:
    case FT_NOCHG:
-      Jmsg(jcr, M_INFO, -1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
+      Jmsg(jcr, M_SKIPPED, -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);
@@ -178,6 +178,11 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt)
       stat = bnet_fsend(dir, "%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 if (ff_pkt->type == FT_DIR) {
+      /* Here link is the canonical filename (i.e. with trailing slash) */
+      stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
+                   STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link, 
+                   0, attribs, 0, 0);
    } else {
       stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
                    STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 
@@ -192,13 +197,14 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt)
       return 0;
    }
 
-   /* If file opened, compute MD5 */
+   /* If file opened, compute MD5 or SHA1 hash */
    if (is_bopen(&bfd)  && ff_pkt->flags & FO_MD5) {
       char MD5buf[40];               /* 24 should do */
       MD5Init(&md5c);
       while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) {
         MD5Update(&md5c, ((unsigned char *) jcr->big_buf), n);
         jcr->JobBytes += n;
+        jcr->ReadBytes += n;
       }
       if (n < 0) {
          Jmsg(jcr, M_ERROR, -1, _("Error reading file %s: ERR=%s\n"), 
@@ -218,6 +224,7 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt)
       while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) {
         SHA1Update(&sha1c, ((unsigned char *) jcr->big_buf), n);
         jcr->JobBytes += n;
+        jcr->ReadBytes += n;
       }
       if (n < 0) {
          Jmsg(jcr, M_ERROR, -1, _("Error reading file %s: ERR=%s\n"), 
index 08ab12edd8d6b3f7626c0545c8e69c492de0eda8..cefbf6b158b8b6347a64c6fbf688912a1ff3677e 100644 (file)
@@ -3,7 +3,7 @@
 
 
 This is the binary distribution of Bacula for Win32
-systems (Win95, Win98, WinMe, WinNT, and Win2000).
+systems (Win95, Win98, WinMe, WinXP, WinNT, and Win2000).
 
 INSTALLATION
 
@@ -13,7 +13,7 @@ To install it, please UnZip (or detar) the distribution
 file into your root directory on drive c:\  then follow
 the instructions in the online manual viewable by any
 Internet Browser (Netscape, Microsoft Internet Explorer).
-See  http://www.bacula.net/htm-manual
+See  http://www.bacula.org/rel-manual/index.html
 or get the source release
 
 Bacula (tm) is released under the GPL license (given below).
@@ -41,4 +41,3 @@ cygwin can be found at http://www.cygwin.com
    MA 02111-1307, USA.
 
  */
-
index cc88a8bcdb32909c43d26d63575a1ca37430c64a..8403c8e4a8c003bc3942371e28fe093c081d97e1 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/chown.exe and b/bacula/src/filed/win32/bin/chown.exe differ
index 5dff1432827885a0fc556389ff431a6cc2b7ca18..78210c9523fae98003e0e563eca3087e450e2348 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/cygwin1.dll and b/bacula/src/filed/win32/bin/cygwin1.dll differ
index 6672c9e83aed9dd807a84da9a050e3b215dd8f1b..08386eac7bd7e3689eee5c61b0b82f34a48e07fa 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/cygz.dll and b/bacula/src/filed/win32/bin/cygz.dll differ
index bc46d6feabf67bf671796b8b2f6e6b6aeb5e0634..beda551a8845d2b5482fd4c083ade7ee227f2f66 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/mount.exe and b/bacula/src/filed/win32/bin/mount.exe differ
index 5f736fd9dc01f97a2a0f3c4f77684e16334cfcc8..34ffc0e5918cb0ca07ed20e25f9d0fb02af8fc5c 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/sh.exe and b/bacula/src/filed/win32/bin/sh.exe differ
index eef24c7bce932f9ce7f6d11c3aeeac143d83490a..cb6b25112d2afc178b50a3f9ed828ca6352d5b40 100755 (executable)
Binary files a/bacula/src/filed/win32/bin/umount.exe and b/bacula/src/filed/win32/bin/umount.exe differ
index 27d92542624ebda39026ee08800cee9853a41d46..f0d65be64cebafa9eb498af37b99a9763de1e6e9 100755 (executable)
@@ -241,6 +241,7 @@ int set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
       if (is_bopen(ofd)) {
         bclose(ofd); 
       }
+      pm_strcpy(&attr->ofname, "*none*");
       return 1;
    }
 
@@ -249,6 +250,7 @@ int set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
       if (is_bopen(ofd)) {
         bclose(ofd); 
       }
+      pm_strcpy(&attr->ofname, "*none*");
       return 1;
    }
    /*
@@ -307,6 +309,7 @@ int set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
         stat = 0;
       }
    }
+   pm_strcpy(&attr->ofname, "*none*");
    umask(old_mask);
    return stat;
 }
index 3f2c9539006b6efd9c3f0a355ceec923db7094ae..2ade59f41fb7f7737b6fbae8a92b667a1400e9e8 100644 (file)
@@ -477,14 +477,21 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
 {
    bfd->fid = open(fname, flags, mode);
    bfd->berrno = errno;
+   Dmsg1(50, "Open file %d\n", bfd->fid);
    return bfd->fid;
 }
 
 int bclose(BFILE *bfd)
 { 
-   int stat = close(bfd->fid);
+   int stat;  
+   Dmsg1(50, "Close file %d\n", bfd->fid);
+   if (bfd->fid == -1) {
+      return 0;
+   }
+   stat = close(bfd->fid);
    bfd->berrno = errno;
    bfd->fid = -1;
+
    return stat;
 }
 
index 2900f998d9c0eee9a01cac18062cb9d7438a4344..766120df91609dea4be2a6347c58609c9b6a9501 100644 (file)
@@ -170,6 +170,9 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
            mode |= O_CTG;               /* set contiguous bit if needed */
         }
          Dmsg1(50, "Create file: %s\n", attr->ofname);
+        if (is_bopen(bfd)) {
+            Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid);
+        }
         if ((bopen(bfd, attr->ofname, mode, S_IRUSR | S_IWUSR)) < 0) {
             Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), 
                  attr->ofname, berror(bfd));
@@ -205,6 +208,9 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
            } else {
               tid = NULL;
            }
+           if (is_bopen(bfd)) {
+               Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid);
+           }
            if ((bopen(bfd, attr->ofname, mode, 0)) < 0) {
                Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), 
                     attr->ofname, berror(bfd));
@@ -248,6 +254,9 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
        *   and saved.
        */
       if (!is_portable_backup(bfd)) {
+        if (is_bopen(bfd)) {
+            Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid);
+        }
         if ((bopen(bfd, attr->ofname, O_WRONLY|O_BINARY, 0)) < 0) {
             Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), 
                  attr->ofname, berror(bfd));
index 6404d3a9c18edf0365a3942c2c7f1cce35399dc9..03c9b07fafa48ec1285a303974bac6a6806e6cf7 100644 (file)
@@ -200,6 +200,12 @@ make_path(
         re_protect = 0;
       }
 
+#ifdef HAVE_CYGWIN
+      /* Because of silly Win32 security, we allow everything */
+      tmp_mode = S_IRWXUGO;
+      re_protect = 0;
+#endif
+
       /* If we can record the current working directory, we may be able
         to do the chdir optimization.  */
       cwd.do_chdir = !save_cwd(&cwd);
@@ -312,7 +318,7 @@ make_path(
 #endif
              )
            {
-              Jmsg(jcr, M_ERROR, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
+              Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
                     quote(dirpath), strerror(errno));
            }
       }
@@ -326,7 +332,7 @@ make_path(
          Dmsg1(300, "Final chmod mode=%o\n", mode);
       }
       if ((mode & ~S_IRWXUGO) && chmod(basename_dir, mode)) {
-          Jmsg(jcr, M_ERROR, 0, _("Cannot change permissions of %s: ERR=%s\n"), 
+          Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), 
             quote(dirpath), strerror(errno));
       }
 
@@ -341,8 +347,8 @@ make_path(
           *(p->dirname_end) = '\0';
           Dmsg2(300, "Reset parent mode=%o dir=%s\n", parent_mode, dirpath);
          if (chmod(dirpath, parent_mode)) {
-              Jmsg(jcr, M_ERROR, 0, _("Cannot change permissions of %s: ERR=%s\n"),
-                    quote (dirpath), strerror(errno));
+              Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"),
+                    quote(dirpath), strerror(errno));
          }
       }
   } else {
@@ -369,11 +375,11 @@ make_path(
              && errno != EPERM
 #endif
              ) {
-              Jmsg(jcr, M_ERROR, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
+              Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
                     quote(dirpath), strerror(errno));
            }
          if (chmod(dirpath, mode)) {
-              Jmsg(jcr, M_ERROR, 0, _("Cannot change permissions of %s: ERR=%s\n"),
+              Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"),
                                 quote(dirpath), strerror(errno));
          }
           Dmsg2(300, "pathexists chmod mode=%o dir=%s\n", mode, dirpath);
index b8893fbd692ea91b5ec96c0ab2f0fedf78d36f49..37844ba1f1a9792667fc0c3333f01d77fc2fd8e8 100644 (file)
@@ -5,3 +5,4 @@ gnome-console.conf
 1
 2
 3
+main.c
diff --git a/bacula/src/gnome2-console/Makefile.in b/bacula/src/gnome2-console/Makefile.in
new file mode 100644 (file)
index 0000000..07afa08
--- /dev/null
@@ -0,0 +1,125 @@
+#
+#   Version $Id$
+#
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/gnome2-console
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+GNOME_INCLUDEDIR = @GNOME_INCLUDEDIR@
+GNOMEUI_LIBS = @GNOMEUI_LIBS@
+GNOME_LIBDIR = @GNOME_LIBDIR@
+GNOME_LIBS = @GNOME_LIBS@
+
+
+#
+CONSSRCS = console.c console_conf.c authenticate.c support.c interface.c callbacks.c
+CONSOBJS = console.o console_conf.o authenticate.o support.o interface.o callbacks.o
+
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+#CONS_INC=@CONS_INC@ $(GNOME_INCLUDEDIR)
+#CONS_LIBS=@CONS_LIBS@ $(GNOME_LIBS)
+#CONS_LDFLAGS=@CONS_LDFLAGS@ $(GNOME_LIBDIR) $(GNOMEUI_LIBS)
+
+CONS_INC=$(GNOME_INCLUDEDIR)
+CONS_LIBS=$(GNOME_LIBS)
+CONS_LDFLAGS=$(GNOME_LIBDIR) $(GNOMEUI_LIBS)
+
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) $(CONS_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile gnome-console @STATIC_GNOME_CONS@
+       @echo "==== Make of gnome-console is good ===="
+       @echo " "
+
+support.o:   support.c
+       rm -f support.c.orig
+       mv support.c support.c.orig
+       sed "s%parent = g_object_get_data%parent = \(GtkWidget \*\)g_object_get_data%" support.c.orig >support.c
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) $(CONS_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+
+gnome-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
+
+static-console: static-gnome-console
+
+static-gnome-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 
+       strip $@
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       @$(RMF) gnome-console core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+       @$(RMF) static-gnome-console gmon.out
+
+realclean: clean
+       @$(RMF) tags
+       @$(RM) -rf .deps gnome-console.conf
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile; $(RMF) -r CVS)
+
+install: all
+       $(INSTALL_SCRIPT) gnome-console $(DESTDIR)$(sbindir)/gnome-console
+       @srcconf=gnome-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_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) gnome-console)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) gnome-console.conf gnome-console.conf.new)
+
+
+
+# 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) $(GNOME_INCLUDEDIR) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/gnome2-console/authenticate.c b/bacula/src/gnome2-console/authenticate.c
new file mode 100644 (file)
index 0000000..3fe7a2f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *
+ *   Bacula UA authentication. Provides authentication with
+ *     the Director.
+ *
+ *     Kern Sibbald, June MMI
+ *
+ *     Version $Id$
+ *
+ *    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.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;
+   int ssl_need = BNET_SSL_NONE;
+
+   /* 
+    * Send my name to the Director then do authentication
+    */
+   bnet_fsend(dir, hello, "UserAgent");
+
+   if (!cram_md5_get_auth(dir, director->password, ssl_need) || 
+       !cram_md5_auth(dir, director->password, ssl_need)) {
+      printf(_("%s: Director authorization problem.\n"), my_name);
+      set_text(_("Director authorization problem.\n"), -1);
+      return 0;
+   }
+
+   Dmsg1(6, ">dird: %s", dir->msg);
+   if (bnet_recv(dir) <= 0) {
+      set_textf(_("Bad response to Hello command: ERR=%s\n"),
+        bnet_strerror(dir));
+      printf(_("%s: Bad response to Hello command: ERR=%s\n"),
+        my_name, bnet_strerror(dir));
+      set_text(_("The Director is probably not running.\n"), -1);
+      return 0;
+   }
+   Dmsg1(10, "<dird: %s", dir->msg);
+   if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
+      set_text(_("Director rejected Hello command\n"), -1);
+      return 0;
+   } else {
+      set_text(dir->msg, dir->msglen);
+   }
+   return 1;
+}
diff --git a/bacula/src/gnome2-console/callbacks.c b/bacula/src/gnome2-console/callbacks.c
new file mode 100644 (file)
index 0000000..2d2f654
--- /dev/null
@@ -0,0 +1,504 @@
+/* 
+ *    Version $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "bacula.h"
+#include "console.h"
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#define KEY_Enter 65293
+#define KEY_Up   65362
+#define KEY_Down  65364
+#define KEY_Left  65361
+#define KEY_Right 65363
+
+gboolean
+on_app1_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+   gtk_main_quit();
+   return FALSE;
+}
+
+void
+on_connect_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+   if (connect_to_director(user_data)) {
+      start_director_reader(user_data);
+   }
+}
+
+
+void
+on_disconnect_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+   if (disconnect_from_director(user_data)) {
+      stop_director_reader(user_data);
+   }
+}
+
+
+void
+on_exit_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+   gtk_main_quit();
+}
+
+
+void
+on_cut1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+
+}
+
+
+void
+on_copy1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+
+}
+
+
+void
+on_paste1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+
+}
+
+
+void
+on_clear1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+
+}
+
+
+void
+on_properties1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+
+}
+
+
+void
+on_preferences1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+}
+
+
+void
+on_about_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+   gtk_widget_show(about1);
+   gtk_main();
+}
+
+
+void
+on_connect_button_clicked(GtkButton *button, gpointer user_data)
+{
+   if (connect_to_director(user_data)) {
+      start_director_reader(user_data);
+   }
+}
+
+/* Define max length of history and how many to delete when it gets there.  
+ * If you make HIST_DEL > HIST_MAX, you shoot yourself in the foot. 
+ */
+#define HIST_MAX 2500
+#define HIST_DEL  500
+
+static GList *hist = NULL;
+static GList *hc = NULL;
+static int hist_len = 0;
+
+static void add_to_history(gchar *ecmd)
+{
+   int len = strlen(ecmd);
+
+   if (len > 0) {
+      hist = g_list_append(hist, bstrdup(ecmd));
+      hist_len++;
+   }
+   if (hist_len >= HIST_MAX) {
+      int i;
+      GList *hp;
+      for (i=0; i<HIST_DEL; i++) {
+        hp = g_list_next(hist);
+        free(hp->data);
+        hist = g_list_remove(hist, hp->data);
+      }
+      hist_len -= HIST_DEL;
+   }
+   hc = NULL;            
+}
+
+/*
+ * Note, apparently there is a bug in GNOME where some of the
+ *  key press events are lost -- at least it loses every other
+ *  up arrow!
+ */
+gboolean
+on_entry1_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+   if (event->keyval == KEY_Enter) {
+      char *ecmd = (char *)gtk_entry_get_text((GtkEntry *)entry1);
+      set_text(ecmd, strlen(ecmd));
+      set_text("\n", 1);
+      add_to_history(ecmd);
+      write_director(ecmd);
+      gtk_entry_set_text((GtkEntry *)entry1, "");
+   } else if (event->keyval == KEY_Up) {
+      if (!hc) {
+        hc = g_list_last(hist);
+      } else {
+        hc = g_list_previous(hc);
+      }
+      if (!hc) {
+        hc = g_list_first(hist);
+      }
+      gtk_entry_set_text((GtkEntry *)entry1, (gchar *)hc->data);
+   } else if (event->keyval == KEY_Down) {
+      if (!hc) {
+        hc = g_list_first(hist);
+      } else {
+        hc = g_list_next(hc);
+      }
+      if (!hc) {
+        hc = g_list_last(hist);
+      }
+      gtk_entry_set_text((GtkEntry *)entry1, (gchar *)hc->data);
+   }
+// gtk_entry_set_position((GtkEntry *)entry1, -1);
+// gtk_window_set_focus((GtkWindow *)app1, entry1);
+   return FALSE;
+}
+
+
+void
+on_app1_show(GtkWidget *widget, gpointer user_data)
+{
+}
+
+
+
+void
+on_msgs_button_clicked(GtkButton *button, gpointer user_data)
+{
+   write_director("messages");
+}
+
+void
+on_msgs_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+   write_director("messages");
+}
+
+void
+on_about_button_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(about1);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+void
+on_select_director_OK_clicked(GtkButton *button, gpointer user_data)
+{
+   reply = OK;
+   gtk_widget_hide(dir_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+
+void
+on_select_director_cancel_clicked(GtkButton *button, gpointer user_data)
+{
+   reply = CANCEL;
+   gtk_widget_hide(dir_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+/*
+ * Compare list string items
+ */
+static gint compare_func(const void *data1, const void *data2)
+{
+   return strcmp((const char *)data1, (const char *)data2);
+}
+
+static GList *find_combo_list(char *name)
+{
+   if (strcmp(name, "job") == 0) {
+      return job_list;
+   }
+   if (strcmp(name, "pool") == 0) {
+      return pool_list;
+   }
+   if (strcmp(name, "client") == 0) {
+      return client_list;
+   }
+   if (strcmp(name, "storage") == 0) {
+      return storage_list;
+   }
+   if (strcmp(name, "fileset") == 0) {
+      return fileset_list;
+   }
+   if (strcmp(name, "messages") == 0) {
+      return messages_list;
+   }
+   if (strcmp(name, "type") == 0) {
+      return type_list;
+   }
+   if (strcmp(name, "level") == 0) {
+      return level_list;
+   }
+   return NULL;
+}
+
+/*
+ * Set correct default values in the Run dialog box
+ */
+static void set_run_defaults()
+{
+   GtkWidget *combo, *entry;
+   char *job, *def;
+   GList *item, *list;
+   char cmd[1000];
+   int pos;
+
+   stop_director_reader(NULL);
+
+   combo = lookup_widget(run_dialog, "combo_job");
+   job = (char *)gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
+   bsnprintf(cmd, sizeof(cmd), ".defaults job=\"%s\"", job);
+   write_director(cmd);
+   while (bnet_recv(UA_sock) > 0) {
+      def = strchr(UA_sock->msg, '=');
+      if (!def) {
+        continue;
+      }
+      *def++ = 0;
+      if (strcmp(UA_sock->msg, "job") == 0 ||
+          strcmp(UA_sock->msg, "when") == 0) {
+        continue;
+      }
+      /* Where is an entry box */
+      if (strcmp(UA_sock->msg, "where") == 0) {
+         entry = lookup_widget(run_dialog, "entry_where");
+        gtk_entry_set_text(GTK_ENTRY(entry), def);
+        continue;
+      }
+
+      /* Now handle combo boxes */
+      list = find_combo_list(UA_sock->msg);
+      if (!list) {
+        continue;
+      }
+      item = g_list_find_custom(list, def, compare_func);
+      bsnprintf(cmd, sizeof(cmd), "combo_%s", UA_sock->msg);
+      combo = lookup_widget(run_dialog, cmd);
+      if (!combo) {
+        continue;
+      }
+      pos = g_list_position(list, item);
+      gtk_list_select_item(GTK_LIST(GTK_COMBO(combo)->list), pos);
+   }
+   start_director_reader(NULL);
+}
+
+void
+on_entry_job_changed(GtkEditable *editable, gpointer user_data)
+{
+   set_run_defaults();
+}
+
+
+void
+on_run_button_clicked(GtkButton *button, gpointer user_data)
+{
+   char dt[50];
+   GtkWidget *entry;
+
+   bstrutime(dt, sizeof(dt), time(NULL));
+   entry = lookup_widget(run_dialog, "entry_when");
+   gtk_entry_set_text(GTK_ENTRY(entry), dt);
+   set_run_defaults();
+   gtk_widget_show(run_dialog);
+   gtk_main();
+}
+
+
+static char *get_combo_text(GtkWidget *dialog, char *combo_name)
+{
+   GtkWidget *combo;
+   combo = lookup_widget(dialog, combo_name);
+   if (!combo) {
+      return NULL;
+   }
+   return (char *)gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
+}
+
+static char *get_entry_text(GtkWidget *dialog, char *entry_name)
+{
+   GtkWidget *entry;
+   entry = lookup_widget(dialog, entry_name);
+   if (!entry) {
+      return NULL;
+   }
+   return (char *)gtk_entry_get_text(GTK_ENTRY(entry));
+}
+
+static char *get_spin_text(GtkWidget *dialog, char *spin_name)
+{
+   GtkSpinButton *spin;
+   spin = (GtkSpinButton *)lookup_widget(dialog, spin_name);
+   if (!spin) {
+      return NULL;
+   }
+   return (char *)gtk_entry_get_text(GTK_ENTRY(&spin->entry));
+}
+
+
+
+
+void
+on_run_ok_clicked(GtkButton *button, gpointer user_data)
+{
+   char *job, *fileset, *level, *client, *pool, *when, *where, *storage;
+
+   gtk_widget_hide(run_dialog);
+   gtk_main_quit();
+
+   job     = get_combo_text(run_dialog, "combo_job");
+   fileset = get_combo_text(run_dialog, "combo_fileset");
+   client  = get_combo_text(run_dialog, "combo_client");
+   pool    = get_combo_text(run_dialog, "combo_pool");
+   storage = get_combo_text(run_dialog, "combo_storage");
+   level   = get_combo_text(run_dialog, "combo_level");
+
+   when    = get_entry_text(run_dialog, "entry_when");
+   where   = get_entry_text(run_dialog, "entry_where");
+
+   if (!job || !fileset || !client || !pool || !storage ||
+       !level || !when || !where) {
+      set_status_ready();
+      return;
+   }
+      
+   bsnprintf(cmd, sizeof(cmd), 
+             "run job=\"%s\" fileset=\"%s\" level=%s client=\"%s\" pool=\"%s\" "
+             "when=\"%s\" where=\"%s\" storage=\"%s\"", 
+            job, fileset, level, client, pool, when, where, storage);
+   write_director(cmd);
+   write_director("yes");
+   return;
+}
+
+
+void
+on_run_cancel_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(run_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+gboolean
+on_entry1_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+  return FALSE;
+}
+
+void
+on_restore_button_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_show(restore_dialog);
+   gtk_main();
+}
+
+void
+on_view_fileset_clicked(GtkButton *button, gpointer user_data)
+{
+}
+
+void
+on_restore_ok_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(restore_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+
+void
+on_restore_cancel_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(restore_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
+
+void
+on_apply_button_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_show(restore_files);
+   gtk_main();
+}
+
+void
+on_restore_file_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(restore_files);
+   gtk_main_quit();
+}
+
+void
+on_label_button_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_show(label_dialog);
+   gtk_main();
+}
+
+void
+on_label_ok_clicked(GtkButton *button, gpointer user_data)
+{
+   char *pool, *volume, *storage, *slot;
+
+   gtk_widget_hide(label_dialog);
+   gtk_main_quit();
+
+   pool    = get_combo_text(label_dialog, "label_combo_pool");
+   storage = get_combo_text(label_dialog, "label_combo_storage");
+
+   volume  = get_entry_text(label_dialog, "label_entry_volume");
+
+   slot    = get_spin_text(label_dialog, "label_slot");
+
+   if (!pool || !storage || !volume || !(*volume)) {
+      set_status_ready();
+      return;
+   }
+      
+   bsnprintf(cmd, sizeof(cmd), 
+             "label name=\"%s\" pool=\"%s\" storage=\"%s\" slot=%s", 
+            volume, pool, storage, slot);
+   write_director(cmd);
+}
+
+
+void
+on_label_cancel_clicked(GtkButton *button, gpointer user_data)
+{
+   gtk_widget_hide(label_dialog);
+   gtk_main_quit();
+   set_status_ready();
+}
diff --git a/bacula/src/gnome2-console/callbacks.h b/bacula/src/gnome2-console/callbacks.h
new file mode 100644 (file)
index 0000000..184ba9c
--- /dev/null
@@ -0,0 +1,240 @@
+
+/*   Version $Id$  */
+
+gboolean
+on_app1_delete_event                   (GtkWidget       *widget,
+                                        GdkEvent        *event,
+                                        gpointer         user_data);
+
+void
+on_new_file1_activate                  (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_open1_activate                      (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_save1_activate                      (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_save_as1_activate                   (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_exit1_activate                      (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_cut1_activate                       (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_copy1_activate                      (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_paste1_activate                     (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_clear1_activate                     (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_properties1_activate                (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_preferences1_activate               (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_about1_activate                     (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_about1_clicked                      (GnomeDialog     *gnomedialog,
+                                        gint             arg1,
+                                        gpointer         user_data);
+
+gboolean
+on_entry1_key_press_event              (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+gboolean
+on_app1_key_press_event                (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+void
+on_select_director_clicked             (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_connect_button1_clicked             (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_app1_realize                        (GtkWidget       *widget,
+                                        gpointer         user_data);
+
+gboolean
+on_combo_entry1_key_press_event        (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+gboolean
+on_entry1_key_press_event              (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+gboolean
+on_entry1_key_press_event              (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+void
+on_app1_show                           (GtkWidget       *widget,
+                                        gpointer         user_data);
+
+void
+on_connect_button1_clicked             (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_run_button1_clicked                 (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_msgs_button_clicked                 (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_msgs_activate                       (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_run_button_clicked                  (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_disconnect_activate                 (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_about_activate                      (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_connect_button_clicked              (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_connect_activate                    (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_exit_activate                       (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_about_clicked                       (GnomeDialog     *gnomedialog,
+                                        gint             arg1,
+                                        gpointer         user_data);
+
+gboolean
+on_app2_delete_event                   (GtkWidget       *widget,
+                                        GdkEvent        *event,
+                                        gpointer         user_data);
+
+void
+on_app2_show                           (GtkWidget       *widget,
+                                        gpointer         user_data);
+
+gboolean
+on_app1_delete_event                   (GtkWidget       *widget,
+                                        GdkEvent        *event,
+                                        gpointer         user_data);
+
+void
+on_app1_show                           (GtkWidget       *widget,
+                                        gpointer         user_data);
+
+gboolean
+on_entry1_key_press_event              (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+void
+on_about_button_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_select_director_OK_clicked          (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_select_director_cancel_clicked      (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_run_ok_clicked                      (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_run_cancel_clicked                  (GtkButton       *button,
+                                        gpointer         user_data);
+
+gboolean
+on_entry1_key_release_event            (GtkWidget       *widget,
+                                        GdkEventKey     *event,
+                                        gpointer         user_data);
+
+void
+on_restore_button_clicked              (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_type_combo_selection_received       (GtkWidget       *widget,
+                                        GtkSelectionData *data,
+                                        guint            time,
+                                        gpointer         user_data);
+
+void
+on_view_fileset_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_entry_job_changed                   (GtkEditable     *editable,
+                                        gpointer         user_data);
+
+void
+on_restore_ok_clicked                  (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_restore_cancel_clicked              (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_apply_button_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_restore_file_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_label_button_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_label_ok_clicked                    (GtkButton       *button,
+                                        gpointer         user_data);
+
+void
+on_label_cancel_clicked                (GtkButton       *button,
+                                        gpointer         user_data);
diff --git a/bacula/src/gnome2-console/console.c b/bacula/src/gnome2-console/console.c
new file mode 100644 (file)
index 0000000..1fb76c0
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ *
+ *   Bacula GNOME Console interface to the Director
+ *
+ *     Kern Sibbald, March MMII
+ *     
+ *     Version $Id$
+ */
+
+/*
+   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 "console.h"
+
+#include "interface.h"
+#include "support.h"
+
+/* Imported functions */
+int authenticate_director(JCR *jcr, DIRRES *director);
+       
+/* Exported variables */
+GtkWidget *app1;            /* application window */
+GtkWidget *text1;           /* text window */
+GtkWidget *entry1;          /* entry box */
+GtkWidget *status1;         /* status bar */
+GtkWidget *combo1;          /* director combo */
+GtkWidget *scroll1;         /* main scroll bar */
+GtkWidget *run_dialog;      /* run dialog */
+GtkWidget *dir_dialog;      /* director selection dialog */
+GtkWidget *restore_dialog;   /* restore dialog */
+GtkWidget *restore_files;    /* restore files dialog */
+GtkWidget *dir_select;
+GtkWidget *about1;          /* about box */
+GtkWidget *label_dialog;
+GdkFont   *text_font = NULL;
+PangoFontDescription *font_desc;
+pthread_mutex_t cmd_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cmd_wait;
+char cmd[1000];
+int reply;
+BSOCK *UA_sock = NULL;
+GList *job_list, *client_list, *fileset_list;
+GList *messages_list, *pool_list, *storage_list;
+GList *type_list, *level_list;
+
+/* Forward referenced functions */
+static void terminate_console(int sig);
+static gint message_handler(gpointer data);
+static int initial_connect_to_director(gpointer data);
+static void set_scroll_bar_to_end(void);
+
+/* Static variables */
+static char *configfile = NULL;
+static DIRRES *dir; 
+static CONRES *con; 
+static int ndir;
+static int director_reader_running = FALSE;
+static bool at_prompt = false;
+static bool ready = false;
+static bool quit = false;
+static guint initial;
+
+#define CONFIG_FILE "./gnome-console.conf"   /* default configuration file */
+
+static void usage()
+{
+   fprintf(stderr, _(
+"\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
+"Usage: gnome-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"), HOST_OS, DISTNAME, DISTVER);
+
+   exit(1);
+}
+
+
+/*********************************************************************
+ *
+ *        Main Bacula GNOME Console -- User Interface Program
+ *
+ */
+int main(int argc, char *argv[])
+{
+   int ch, stat;
+   int no_signals = TRUE;
+   int test_config = FALSE;
+   int gargc = 1;
+   char *gargv[2] = {"gnome-console", NULL};
+
+   init_stack_dump();
+   my_name_is(argc, argv, "gnome-console");
+   init_msg(NULL, NULL);
+   working_directory  = "/tmp";
+
+   struct sigaction sigignore;
+   sigignore.sa_flags = 0;
+   sigignore.sa_handler = SIG_IGN;      
+   sigfillset(&sigignore.sa_mask);
+   sigaction(SIGPIPE, &sigignore, NULL);
+
+   if ((stat=pthread_cond_init(&cmd_wait, NULL)) != 0) {
+      Emsg1(M_ABORT, 0, _("Pthread cond init error = %s\n"),
+        strerror(stat));
+   }
+
+   gnome_init("bacula", VERSION, gargc, (char **)&gargv);
+
+   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);
+   }
+
+   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_ERROR_TERM, 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);
+   }
+
+
+   app1 = create_app1();
+   gtk_window_set_default_size(GTK_WINDOW(app1), 800, 700);
+   run_dialog = create_RunDialog();
+   label_dialog = create_label_dialog();
+   restore_dialog = create_restore_dialog();
+   restore_files  = create_restore_files();
+   about1 = create_about1();
+
+   gtk_widget_show(app1);
+
+   text1 = lookup_widget(app1, "text1");
+   entry1 = lookup_widget(app1, "entry1");
+   status1 = lookup_widget(app1, "status1");
+   scroll1 = lookup_widget(app1, "scroll1");
+
+/*
+ * Thanks to Phil Stracchino for providing the font configuration code.
+ * original default:
+   text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-koi8-r");
+ * this works for me:
+   text_font = gdk_font_load("-Bigelow & Holmes-lucida console-medium-r-semi condensed-*-12-0-100-100-m-0-iso8859-1");
+ * and, new automagic:font specification!
+ */
+
+   LockRes();
+   for (con = NULL; (con = (CONRES *)GetNextRes(R_CONSOLE, (RES *)con)); ) {
+       text_font = gdk_font_load(con->fontface);
+       if (text_font == NULL) {
+           Dmsg2(404, "Load of requested ConsoleFont \"%s\" (%s) failed!\n",
+                 con->hdr.name, con->fontface);
+       } else {
+           Dmsg2(404, "ConsoleFont \"%s\" (%s) loaded.\n",
+                 con->hdr.name, con->fontface);
+          break;
+       }          
+   }
+   UnlockRes();
+
+   if (text_font == NULL) {
+       Dmsg1(100, "Attempting to load fallback font %s\n",
+              "-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
+       text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
+   }
+   font_desc = pango_font_description_from_string("LucidaTypewriter 9");
+   gtk_widget_modify_font (app1, font_desc);
+   gtk_widget_modify_font (text1, font_desc);
+   gtk_widget_modify_font (entry1, font_desc);
+   gtk_widget_modify_font (status1, font_desc);
+   pango_font_description_free (font_desc);
+
+
+   initial = gtk_timeout_add(100, initial_connect_to_director, (gpointer)NULL);
+
+   gtk_main();
+   quit = true;
+   disconnect_from_director((gpointer)NULL);
+   return 0;
+}
+
+/*
+ * Every 5 seconds, ask the Director for our
+ *  messages.
+ */
+static gint message_handler(gpointer data)
+{
+   if (ready && UA_sock) {
+      bnet_fsend(UA_sock, ".messages");
+   }
+   return TRUE;
+}
+
+int disconnect_from_director(gpointer data)
+{
+   if (!quit)
+      set_status(_(" Not Connected"));
+   if (UA_sock) {
+      bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
+      bnet_close(UA_sock);
+      UA_sock = NULL;
+   }
+   return 1;
+}
+
+/*
+ * Called just after the main loop is started to allow
+ *  us to connect to the Director.
+ */
+static int initial_connect_to_director(gpointer data)
+{
+   gtk_timeout_remove(initial);
+   if (connect_to_director(data)) {
+      start_director_reader(data);
+   }
+   gtk_timeout_add(5000, message_handler, (gpointer)NULL);
+   return TRUE;
+}
+
+static GList *get_list(char *cmd)
+{
+   GList *options;
+   char *msg;
+
+   options = NULL;
+   write_director(cmd);
+   while (bnet_recv(UA_sock) > 0) {
+      strip_trailing_junk(UA_sock->msg);
+      msg = (char *)malloc(strlen(UA_sock->msg) + 1);
+      strcpy(msg, UA_sock->msg);
+      options = g_list_append(options, msg);
+   }
+   return options;
+   
+}
+
+static GList *get_and_fill_combo(GtkWidget *dialog, char *combo_name, char *cmd)
+{
+   GtkWidget *combo;
+   GList *options;
+
+   combo = lookup_widget(dialog, combo_name);
+   options = get_list(cmd);
+   if (combo && options) {
+      gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
+   }
+   return options;
+}
+
+static void fill_combo(GtkWidget *dialog, char *combo_name, GList *options)
+{
+   GtkWidget *combo;
+
+   combo = lookup_widget(dialog, combo_name);
+   if (combo) {
+      gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
+   }
+   return;
+}
+
+
+/*
+ * Connect to Director. If there are more than one, put up
+ * a modal dialog so that the user chooses one.
+ */
+int connect_to_director(gpointer data)
+{
+   GList *dirs = NULL;
+   GtkWidget *combo;
+   char buf[1000];
+   JCR jcr;
+
+
+   if (UA_sock) {
+      return 0;
+   }
+
+   if (ndir > 1) {
+      LockRes();
+      for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
+         sprintf(buf, "%s at %s:%d", dir->hdr.name, dir->address,
+           dir->DIRport);
+         printf("%s\n", buf);
+        dirs = g_list_append(dirs, dir->hdr.name);
+      }
+      UnlockRes();
+      dir_dialog = create_SelectDirectorDialog();
+      combo = lookup_widget(dir_dialog, "combo1");
+      dir_select = lookup_widget(dir_dialog, "dirselect");
+      gtk_combo_set_popdown_strings(GTK_COMBO(combo), dirs);   
+      printf("dialog run\n");
+      gtk_widget_show(dir_dialog);
+      gtk_main();
+
+      if (reply == OK) {
+        gchar *ecmd = gtk_editable_get_chars((GtkEditable *)dir_select, 0, -1);
+        dir = (DIRRES *)GetResWithName(R_DIRECTOR, ecmd);
+        if (ecmd) {
+           g_free(ecmd);             /* release director name string */
+        }
+      }
+      if (dirs) {
+        g_free(dirs);
+      }
+      gtk_widget_destroy(dir_dialog);
+      dir_dialog = NULL;
+   } else {
+      /* Just take the first Director */
+      LockRes();
+      dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
+      UnlockRes();
+   }
+
+   if (!dir) {
+      printf("dir is NULL\n");
+      return 0;
+   }
+
+   memset(&jcr, 0, sizeof(jcr));
+   
+   set_statusf(_(" Connecting to Director %s:%d"), dir->address,dir->DIRport);
+   set_textf(_("Connecting to Director %s:%d\n\n"), dir->address,dir->DIRport);
+
+   while (gtk_events_pending()) {     /* fully paint screen */
+      gtk_main_iteration();
+   }
+   UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, 
+                         NULL, dir->DIRport, 0);
+   if (UA_sock == NULL) {
+      return 0;
+   }
+   
+   jcr.dir_bsock = UA_sock;
+   if (!authenticate_director(&jcr, dir)) {
+      set_text(UA_sock->msg, UA_sock->msglen);
+      return 0;
+   }
+
+   set_status(" Initializing ...");
+
+   bnet_fsend(UA_sock, "autodisplay on");
+
+   /* Read and display all initial messages */
+   while (bnet_recv(UA_sock) > 0) {
+      set_text(UA_sock->msg, UA_sock->msglen);
+   }
+
+   /* Paint changes */
+   while (gtk_events_pending()) {
+      gtk_main_iteration();
+   }
+
+   /* Fill the run_dialog combo boxes */
+   job_list      = get_and_fill_combo(run_dialog, "combo_job", ".jobs");
+   client_list   = get_and_fill_combo(run_dialog, "combo_client", ".clients");
+   fileset_list  = get_and_fill_combo(run_dialog, "combo_fileset", ".filesets");
+   messages_list = get_and_fill_combo(run_dialog, "combo_messages", ".msgs");
+   pool_list     = get_and_fill_combo(run_dialog, "combo_pool", ".pools");
+   storage_list  = get_and_fill_combo(run_dialog, "combo_storage", ".storage");
+   type_list     = get_and_fill_combo(run_dialog, "combo_type", ".types");
+   level_list    = get_and_fill_combo(run_dialog, "combo_level", ".levels");
+
+   fill_combo(label_dialog, "label_combo_storage", storage_list);
+   fill_combo(label_dialog, "label_combo_pool", pool_list);
+
+   set_status(" Connected");
+   return 1;
+}
+
+void write_director(gchar *msg)
+{
+   if (UA_sock) {
+      at_prompt = false;
+      set_status(_(" Processing command ..."));
+      UA_sock->msglen = strlen(msg);
+      pm_strcpy(&UA_sock->msg, msg);
+      bnet_send(UA_sock);
+   }
+   if (strcmp(msg, ".quit") == 0 || strcmp(msg, ".exit") == 0) {
+      disconnect_from_director((gpointer)NULL);
+      gtk_main_quit();
+   }
+}
+
+void read_director(gpointer data, gint fd, GdkInputCondition condition)
+{
+   int stat;
+
+   if (!UA_sock || UA_sock->fd != fd) {
+      return;
+   }
+   stat = bnet_recv(UA_sock);
+   if (stat >= 0) {
+      if (at_prompt) {
+         set_text("\n", 1);
+        at_prompt = false;
+      }
+      set_text(UA_sock->msg, UA_sock->msglen);
+      return;
+   }
+   if (is_bnet_stop(UA_sock)) {        /* error or term request */
+      gtk_main_quit();
+      return;
+   }
+   /* Must be a signal -- either do something or ignore it */
+   if (UA_sock->msglen == BNET_PROMPT) {
+      at_prompt = true;
+      set_status(_(" At prompt waiting for input ..."));
+   }
+   if (UA_sock->msglen == BNET_EOD) {
+      set_status_ready();
+   }
+   return;
+}
+
+static gint tag;
+
+void start_director_reader(gpointer data)
+{
+
+   if (director_reader_running || !UA_sock) {
+      return;
+   }
+   director_reader_running = TRUE;
+
+   tag = gdk_input_add(UA_sock->fd, GDK_INPUT_READ, read_director, NULL);
+}
+
+void stop_director_reader(gpointer data)
+{
+   if (!director_reader_running) {
+      return;
+   }
+   gdk_input_remove(tag);
+   director_reader_running = FALSE;
+}
+
+
+
+/* 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;
+   disconnect_from_director((gpointer)NULL);
+   gtk_main_quit();
+   exit(0);
+}
+
+
+/* Buffer approx 2000 lines -- assume 60 chars/line */
+#define MAX_TEXT_CHARS  (2000 * 60)
+static int text_chars = 0;
+
+static void truncate_text_chars()
+{
+   GtkTextBuffer *textbuf;
+   GtkTextIter iter, iter2;
+   guint len;
+   int del_chars = MAX_TEXT_CHARS / 4;
+
+   textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text1));
+   len = gtk_text_buffer_get_char_count(textbuf);
+   gtk_text_buffer_get_iter_at_offset (textbuf, &iter, 0);
+   gtk_text_buffer_get_iter_at_offset (textbuf, &iter2, del_chars);
+   gtk_text_buffer_delete (textbuf, &iter, &iter2);
+   text_chars -= del_chars;
+   len = gtk_text_buffer_get_char_count(textbuf);
+   gtk_text_iter_set_offset(&iter, len);
+}
+
+void set_textf(char *fmt, ...)
+{
+   va_list arg_ptr;
+   char buf[1000];
+   int len;
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
+   va_end(arg_ptr);
+   set_text(buf, len);
+}
+
+void set_text(char *buf, int len)
+{
+   GtkTextBuffer *textbuf;
+   GtkTextIter iter;
+   guint buf_len;
+
+   textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text1));
+   buf_len = gtk_text_buffer_get_char_count(textbuf);
+   gtk_text_buffer_get_iter_at_offset(textbuf, &iter, buf_len - 1);
+   gtk_text_buffer_insert(textbuf, &iter, buf, -1);
+   text_chars += len;
+   if (text_chars > MAX_TEXT_CHARS) {
+      truncate_text_chars();
+   }
+   set_scroll_bar_to_end();
+}
+
+void set_statusf(char *fmt, ...)
+{
+   va_list arg_ptr;
+   char buf[1000];
+   int len;
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
+   va_end(arg_ptr);
+   gtk_label_set_text(GTK_LABEL(status1), buf);
+// set_scroll_bar_to_end();
+   ready = false;
+}
+
+void set_status_ready()    
+{
+   gtk_label_set_text(GTK_LABEL(status1), " Ready");
+   ready = true;
+// set_scroll_bar_to_end();
+}
+
+void set_status(char *buf)
+{
+   gtk_label_set_text(GTK_LABEL(status1), buf);
+// set_scroll_bar_to_end();
+   ready = false;
+}
+
+static void set_scroll_bar_to_end(void)
+{
+   GtkTextBuffer* textbuf = NULL;
+   GtkTextIter iter;
+   guint buf_len;
+
+   textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text1));
+   buf_len = gtk_text_buffer_get_char_count(textbuf);
+   gtk_text_buffer_get_iter_at_offset(textbuf, &iter, buf_len - 1);
+   gtk_text_iter_set_offset(&iter, buf_len);
+   gtk_text_buffer_place_cursor(textbuf, &iter);
+   gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text1),
+              gtk_text_buffer_get_mark(textbuf, "insert"), 
+             0, TRUE, 0.0, 1.0);
+}
diff --git a/bacula/src/gnome2-console/console.h b/bacula/src/gnome2-console/console.h
new file mode 100644 (file)
index 0000000..200ca32
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Bacula GNOME User Agent specific configuration and defines
+ *
+ *     Kern Sibbald, March 2002
+ *
+ *     Version $Id$
+ */
+
+#ifndef __CONSOLE_H_
+#define __CONSOLE_H_
+
+#include "console_conf.h"
+#include "jcr.h"
+/* Super kludge for GNOME 2.0 */
+#undef _
+#undef N_
+#undef textdomain
+
+#include <gnome.h>
+
+extern GtkWidget *app1;       /* application window */
+extern GtkWidget *text1;      /* text window */
+extern GtkWidget *entry1;     /* entry box */
+extern GtkWidget *combo1;     /* Directory combo */
+extern GtkWidget *dir_dialog; 
+extern GtkWidget *dir_select;
+extern GtkWidget *run_dialog;       /* run dialog */
+extern GtkWidget *label_dialog;     
+extern GtkWidget *restore_dialog;   /* restore dialog */
+extern GtkWidget *restore_files;    /* restore files dialog */
+extern GtkWidget *about1;
+extern GList *job_list, *client_list, *fileset_list;
+extern GList *messages_list, *pool_list, *storage_list;
+extern GList *type_list, *level_list;
+
+
+extern pthread_mutex_t cmd_mutex;
+extern pthread_cond_t  cmd_wait;
+extern char cmd[1000];
+extern int cmd_ready;
+extern int reply;
+extern BSOCK *UA_sock;
+
+
+
+#define OK     1
+#define CANCEL 0
+
+void set_textf(char *fmt, ...);
+void set_text(char *buf, int len);
+void set_status(char *buf);
+void set_status_ready();
+void set_statusf(char *fmt, ...);
+int connect_to_director(gpointer data);
+int disconnect_from_director(gpointer data);
+void start_director_reader(gpointer data);
+void stop_director_reader(gpointer data);
+void write_director(gchar *msg);
+void read_director(gpointer data, gint fd, GdkInputCondition condition);
+
+#endif
diff --git a/bacula/src/gnome2-console/console_conf.c b/bacula/src/gnome2-console/console_conf.c
new file mode 100644 (file)
index 0000000..725fc02
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *   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
+ *
+ *     Version $Id$
+ */
+
+/*
+   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_DEFAULT, 9101},
+   {"address",     store_str,      ITEM(res_dir.address),  0, ITEM_REQUIRED, 0},
+   {"password",    store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
+   {"enablessl", store_yesno,      ITEM(res_dir.enable_ssl), 1, ITEM_DEFAULT, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+static struct res_items con_items[] = {
+   {"name",        store_name,     ITEM(con_dir.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(con_dir.hdr.desc), 0, 0, 0},
+   {"font",        store_str,      ITEM(con_dir.fontface), 0, ITEM_REQUIRED, 0},
+   {"requiressl",  store_yesno,    ITEM(con_dir.require_ssl), 1, ITEM_DEFAULT, 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},
+   {"consolefont",   con_items,   R_CONSOLE,   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;
+      case R_CONSOLE:
+         printf("Console: name=%s font face=%s\n", 
+               reshdr->name, NPRT(res->con_dir.fontface));
+        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;
+      case R_CONSOLE:
+        if (res->con_dir.fontface) {
+           free(res->con_dir.fontface);
+        }
+        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 = 0;
+   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;
+
+        case R_CONSOLE:
+           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;
+   }
+
+   /* The following code is only executed during pass 1 */
+   switch (type) {
+      case R_DIRECTOR:
+        size = sizeof(DIRRES);
+        break;
+      case R_CONSOLE:
+        size = sizeof(CONRES);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+        error = 1;
+        break;
+   }
+   /* Common */
+   if (!error) {
+      res = (URES *)malloc(size);
+      memcpy(res, &res_all, size);
+      if (!resources[rindex].res_head) {
+        resources[rindex].res_head = (RES *)res; /* store first entry */
+      } else {
+        RES *next;
+        /* Add new res to end of chain */
+        for (next=resources[rindex].res_head; next->next; next=next->next) {
+           if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
+              Emsg2(M_ERROR_TERM, 0,
+                  _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
+                 resources[rindex].name, res->res_dir.hdr.name);
+           }
+        }
+        next->next = (RES *)res;
+         Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
+              res->res_dir.hdr.name);
+      }
+   }
+}
diff --git a/bacula/src/gnome2-console/console_conf.h b/bacula/src/gnome2-console/console_conf.h
new file mode 100644 (file)
index 0000000..b63d20c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Bacula GNOME User Agent specific configuration and defines
+ *
+ *     Kern Sibbald, March 2002
+ *
+ *     Version $Id$
+ */
+
+#ifndef __CONSOLE_CONF_H_
+#define __CONSOLE_CONF_H_
+
+/*
+ * Resource codes -- they must be sequential for indexing   
+ */
+#define R_FIRST                      1001
+
+#define R_DIRECTOR                   1001
+#define R_CONSOLE                    1002
+
+#define R_LAST                       R_CONSOLE
+
+/*
+ * 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 */
+   int enable_ssl;                   /* Use SSL */
+};
+typedef struct s_res_dir DIRRES;
+
+struct s_con_dir {
+   RES  hdr;
+   char *fontface;                   /* Console Font specification */
+   int require_ssl;                  /* Require SSL on all connections */
+};
+typedef struct s_con_dir CONRES;
+
+/* Define the Union of all the above
+ * resource structure definitions.
+ */
+union u_res {
+   struct s_res_dir    res_dir;
+   struct s_con_dir    con_dir;
+   RES hdr;
+};
+
+typedef union u_res URES;
+
+#endif
diff --git a/bacula/src/gnome2-console/gnome-console.conf.in b/bacula/src/gnome2-console/gnome-console.conf.in
new file mode 100644 (file)
index 0000000..8ca3533
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Bacula User Agent (or Console) Configuration File
+#
+
+Director {
+  Name = @hostname@-dir
+  DIRport = @dir_port@
+  address = @hostname@
+  Password = "@dir_password@"
+}
+
+ConsoleFont {
+  Name = Default
+  Font = "-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1"
+}
diff --git a/bacula/src/gnome2-console/interface.c b/bacula/src/gnome2-console/interface.c
new file mode 100644 (file)
index 0000000..d536d15
--- /dev/null
@@ -0,0 +1,1464 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <bonobo.h>
+#include <gnome.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+  g_object_set_data_full (G_OBJECT (component), name, \
+    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+  g_object_set_data (G_OBJECT (component), name, widget)
+
+static GnomeUIInfo file1_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("_Connect"),
+    N_("Connect to Director"),
+    (gpointer) on_connect_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("_Disconnect"),
+    N_("Disconnect from Director"),
+    (gpointer) on_disconnect_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_SEPARATOR,
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-quit"),
+    NULL,
+    (gpointer) on_exit_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
+static GnomeUIInfo edit1_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-cut"),
+    NULL,
+    (gpointer) on_cut1_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-copy"),
+    NULL,
+    (gpointer) on_copy1_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-paste"),
+    NULL,
+    (gpointer) on_paste1_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-clear"),
+    NULL,
+    (gpointer) on_clear1_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_SEPARATOR,
+  GNOMEUIINFO_END
+};
+
+static GnomeUIInfo item1_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("_Display Messages"),
+    NULL,
+    (gpointer) on_msgs_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
+static GnomeUIInfo settings1_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("gtk-preferences"),
+    NULL,
+    (gpointer) on_preferences1_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
+static GnomeUIInfo help1_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("gnome-stock-about"),
+    NULL,
+    (gpointer) on_about_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
+static GnomeUIInfo menubar1_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_SUBTREE, N_("_File"),
+    NULL,
+    file1_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_SUBTREE, N_("_Edit"),
+    NULL,
+    edit1_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_SUBTREE, N_("_View"),
+    N_("Display Messages"),
+    item1_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_SUBTREE, N_("_Settings"),
+    NULL,
+    settings1_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_SUBTREE, N_("_Help"),
+    NULL,
+    help1_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
+GtkWidget*
+create_app1 (void)
+{
+  GtkWidget *app1;
+  GtkWidget *vbox6;
+  GtkWidget *handlebox1;
+  GtkWidget *menubar1;
+  GtkWidget *handlebox2;
+  GtkWidget *toolbar2;
+  GtkWidget *tmp_toolbar_icon;
+  GtkWidget *connect_button1;
+  GtkWidget *run_button1;
+  GtkWidget *msgs_button;
+  GtkWidget *restore_button;
+  GtkWidget *label_button;
+  GtkWidget *vbox7;
+  GtkWidget *scroll1;
+  GtkWidget *text1;
+  GtkWidget *hbox18;
+  GtkWidget *label38;
+  GtkWidget *entry1;
+  GtkWidget *hbox19;
+  GtkWidget *frame1;
+  GtkWidget *label39;
+  GtkWidget *frame2;
+  GtkWidget *status1;
+  GtkTooltips *tooltips;
+
+  tooltips = gtk_tooltips_new ();
+
+  app1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (app1), _("Bacula Console"));
+  gtk_window_set_position (GTK_WINDOW (app1), GTK_WIN_POS_CENTER);
+
+  vbox6 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox6);
+  gtk_container_add (GTK_CONTAINER (app1), vbox6);
+
+  handlebox1 = gtk_handle_box_new ();
+  gtk_widget_show (handlebox1);
+  gtk_box_pack_start (GTK_BOX (vbox6), handlebox1, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (handlebox1), 1);
+
+  menubar1 = gtk_menu_bar_new ();
+  gtk_widget_show (menubar1);
+  gtk_container_add (GTK_CONTAINER (handlebox1), menubar1);
+  gnome_app_fill_menu (GTK_MENU_SHELL (menubar1), menubar1_uiinfo,
+                       NULL, FALSE, 0);
+
+  handlebox2 = gtk_handle_box_new ();
+  gtk_widget_show (handlebox2);
+  gtk_box_pack_start (GTK_BOX (vbox6), handlebox2, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (handlebox2), 1);
+
+  toolbar2 = gtk_toolbar_new ();
+  gtk_widget_show (toolbar2);
+  gtk_container_add (GTK_CONTAINER (handlebox2), toolbar2);
+  gtk_container_set_border_width (GTK_CONTAINER (toolbar2), 1);
+  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar2), GTK_TOOLBAR_BOTH);
+
+  tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-new", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)));
+  connect_button1 = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar2),
+                                GTK_TOOLBAR_CHILD_BUTTON,
+                                NULL,
+                                _("Connect"),
+                                _("Connect to Director"), NULL,
+                                tmp_toolbar_icon, NULL, NULL);
+  gtk_label_set_use_underline (GTK_LABEL (((GtkToolbarChild*) (g_list_last (GTK_TOOLBAR (toolbar2)->children)->data))->label), TRUE);
+  gtk_widget_show (connect_button1);
+
+  tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-execute", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)));
+  run_button1 = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar2),
+                                GTK_TOOLBAR_CHILD_BUTTON,
+                                NULL,
+                                _("Run"),
+                                _("Run a Job"), NULL,
+                                tmp_toolbar_icon, NULL, NULL);
+  gtk_label_set_use_underline (GTK_LABEL (((GtkToolbarChild*) (g_list_last (GTK_TOOLBAR (toolbar2)->children)->data))->label), TRUE);
+  gtk_widget_show (run_button1);
+
+  tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-find", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)));
+  msgs_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar2),
+                                GTK_TOOLBAR_CHILD_BUTTON,
+                                NULL,
+                                _("Msgs"),
+                                _("Display Messages"), NULL,
+                                tmp_toolbar_icon, NULL, NULL);
+  gtk_label_set_use_underline (GTK_LABEL (((GtkToolbarChild*) (g_list_last (GTK_TOOLBAR (toolbar2)->children)->data))->label), TRUE);
+  gtk_widget_show (msgs_button);
+
+  tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-revert-to-saved", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)));
+  restore_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar2),
+                                GTK_TOOLBAR_CHILD_BUTTON,
+                                NULL,
+                                _("Restore"),
+                                NULL, NULL,
+                                tmp_toolbar_icon, NULL, NULL);
+  gtk_label_set_use_underline (GTK_LABEL (((GtkToolbarChild*) (g_list_last (GTK_TOOLBAR (toolbar2)->children)->data))->label), TRUE);
+  gtk_widget_show (restore_button);
+
+  tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-save-as", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)));
+  label_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar2),
+                                GTK_TOOLBAR_CHILD_BUTTON,
+                                NULL,
+                                _("Label"),
+                                NULL, NULL,
+                                tmp_toolbar_icon, NULL, NULL);
+  gtk_label_set_use_underline (GTK_LABEL (((GtkToolbarChild*) (g_list_last (GTK_TOOLBAR (toolbar2)->children)->data))->label), TRUE);
+  gtk_widget_show (label_button);
+
+  vbox7 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox7);
+  gtk_box_pack_start (GTK_BOX (vbox6), vbox7, TRUE, TRUE, 0);
+
+  scroll1 = gtk_scrolled_window_new (NULL, NULL);
+  gtk_widget_show (scroll1);
+  gtk_box_pack_start (GTK_BOX (vbox7), scroll1, TRUE, TRUE, 0);
+  GTK_WIDGET_UNSET_FLAGS (scroll1, GTK_CAN_FOCUS);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll1), GTK_SHADOW_IN);
+
+  text1 = gtk_text_view_new ();
+  gtk_widget_show (text1);
+  gtk_container_add (GTK_CONTAINER (scroll1), text1);
+  GTK_WIDGET_UNSET_FLAGS (text1, GTK_CAN_FOCUS);
+  gtk_text_view_set_editable (GTK_TEXT_VIEW (text1), FALSE);
+  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text1), GTK_WRAP_WORD);
+
+  hbox18 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox18);
+  gtk_box_pack_start (GTK_BOX (vbox7), hbox18, FALSE, TRUE, 0);
+
+  label38 = gtk_label_new (_(" Command: "));
+  gtk_widget_show (label38);
+  gtk_box_pack_start (GTK_BOX (hbox18), label38, FALSE, TRUE, 0);
+
+  entry1 = gtk_entry_new ();
+  gtk_widget_show (entry1);
+  gtk_box_pack_start (GTK_BOX (hbox18), entry1, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (entry1, GTK_CAN_DEFAULT);
+  gtk_tooltips_set_tip (tooltips, entry1, _("Enter Commands Here"), NULL);
+  gtk_entry_set_max_length (GTK_ENTRY (entry1), 150);
+
+  hbox19 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox19);
+  gtk_box_pack_start (GTK_BOX (vbox7), hbox19, FALSE, FALSE, 0);
+
+  frame1 = gtk_frame_new (NULL);
+  gtk_widget_show (frame1);
+  gtk_box_pack_start (GTK_BOX (hbox19), frame1, FALSE, TRUE, 0);
+
+  label39 = gtk_label_new (_(" Status: "));
+  gtk_widget_show (label39);
+  gtk_container_add (GTK_CONTAINER (frame1), label39);
+
+  frame2 = gtk_frame_new (NULL);
+  gtk_widget_show (frame2);
+  gtk_box_pack_start (GTK_BOX (hbox19), frame2, TRUE, TRUE, 0);
+
+  status1 = gtk_label_new ("");
+  gtk_widget_show (status1);
+  gtk_container_add (GTK_CONTAINER (frame2), status1);
+  gtk_label_set_justify (GTK_LABEL (status1), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (status1), 0, 0.5);
+
+  g_signal_connect ((gpointer) app1, "delete_event",
+                    G_CALLBACK (on_app1_delete_event),
+                    NULL);
+  g_signal_connect ((gpointer) connect_button1, "clicked",
+                    G_CALLBACK (on_connect_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) run_button1, "clicked",
+                    G_CALLBACK (on_run_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) msgs_button, "clicked",
+                    G_CALLBACK (on_msgs_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) restore_button, "clicked",
+                    G_CALLBACK (on_restore_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) label_button, "clicked",
+                    G_CALLBACK (on_label_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) entry1, "key_press_event",
+                    G_CALLBACK (on_entry1_key_press_event),
+                    NULL);
+  g_signal_connect ((gpointer) entry1, "key_release_event",
+                    G_CALLBACK (on_entry1_key_release_event),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (app1, app1, "app1");
+  GLADE_HOOKUP_OBJECT (app1, vbox6, "vbox6");
+  GLADE_HOOKUP_OBJECT (app1, handlebox1, "handlebox1");
+  GLADE_HOOKUP_OBJECT (app1, menubar1, "menubar1");
+  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[0].widget, "file1");
+  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[0].widget, "connect1");
+  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[1].widget, "disconnect1");
+  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[2].widget, "menuitem4");
+  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[3].widget, "exit1");
+  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[1].widget, "edit1");
+  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[0].widget, "cut1");
+  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[1].widget, "copy1");
+  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[2].widget, "paste1");
+  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[3].widget, "clear1");
+  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[4].widget, "separator1");
+  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[2].widget, "item1");
+  GLADE_HOOKUP_OBJECT (app1, item1_menu_uiinfo[0].widget, "msgs");
+  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[3].widget, "settings1");
+  GLADE_HOOKUP_OBJECT (app1, settings1_menu_uiinfo[0].widget, "preferences1");
+  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[4].widget, "help1");
+  GLADE_HOOKUP_OBJECT (app1, help1_menu_uiinfo[0].widget, "about1");
+  GLADE_HOOKUP_OBJECT (app1, handlebox2, "handlebox2");
+  GLADE_HOOKUP_OBJECT (app1, toolbar2, "toolbar2");
+  GLADE_HOOKUP_OBJECT (app1, connect_button1, "connect_button1");
+  GLADE_HOOKUP_OBJECT (app1, run_button1, "run_button1");
+  GLADE_HOOKUP_OBJECT (app1, msgs_button, "msgs_button");
+  GLADE_HOOKUP_OBJECT (app1, restore_button, "restore_button");
+  GLADE_HOOKUP_OBJECT (app1, label_button, "label_button");
+  GLADE_HOOKUP_OBJECT (app1, vbox7, "vbox7");
+  GLADE_HOOKUP_OBJECT (app1, scroll1, "scroll1");
+  GLADE_HOOKUP_OBJECT (app1, text1, "text1");
+  GLADE_HOOKUP_OBJECT (app1, hbox18, "hbox18");
+  GLADE_HOOKUP_OBJECT (app1, label38, "label38");
+  GLADE_HOOKUP_OBJECT (app1, entry1, "entry1");
+  GLADE_HOOKUP_OBJECT (app1, hbox19, "hbox19");
+  GLADE_HOOKUP_OBJECT (app1, frame1, "frame1");
+  GLADE_HOOKUP_OBJECT (app1, label39, "label39");
+  GLADE_HOOKUP_OBJECT (app1, frame2, "frame2");
+  GLADE_HOOKUP_OBJECT (app1, status1, "status1");
+  GLADE_HOOKUP_OBJECT_NO_REF (app1, tooltips, "tooltips");
+
+  gtk_widget_grab_focus (entry1);
+  gtk_widget_grab_default (entry1);
+  return app1;
+}
+
+GtkWidget*
+create_about1 (void)
+{
+  GtkWidget *about1;
+  GtkWidget *dialog_vbox5;
+  GtkWidget *vbox8;
+  GtkWidget *vbox9;
+  GtkWidget *about_head;
+  GtkWidget *hseparator1;
+  GtkWidget *copyright;
+  GtkWidget *authors;
+  GtkWidget *theme;
+  GtkWidget *dialog_action_area5;
+  GtkWidget *hbox20;
+  GtkWidget *label44;
+  GtkWidget *about_button;
+
+  about1 = gtk_dialog_new ();
+  gtk_window_set_title (GTK_WINDOW (about1), _("About Bacula Console"));
+  gtk_window_set_modal (GTK_WINDOW (about1), TRUE);
+
+  dialog_vbox5 = GTK_DIALOG (about1)->vbox;
+  gtk_widget_show (dialog_vbox5);
+
+  vbox8 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox8);
+  gtk_box_pack_start (GTK_BOX (dialog_vbox5), vbox8, TRUE, TRUE, 0);
+
+  vbox9 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox9);
+  gtk_box_pack_start (GTK_BOX (vbox8), vbox9, TRUE, TRUE, 0);
+
+  about_head = gtk_label_new (_("Bacula Console 1.32c (24 Oct 03)\n"));
+  gtk_widget_show (about_head);
+  gtk_box_pack_start (GTK_BOX (vbox9), about_head, FALSE, FALSE, 0);
+
+  hseparator1 = gtk_hseparator_new ();
+  gtk_widget_show (hseparator1);
+  gtk_box_pack_start (GTK_BOX (vbox9), hseparator1, FALSE, FALSE, 0);
+
+  copyright = gtk_label_new (_("Copyright (c) 1999 - 2002, Kern Sibbald and John Walker"));
+  gtk_widget_show (copyright);
+  gtk_box_pack_start (GTK_BOX (vbox9), copyright, TRUE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (copyright), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (copyright), 0.1, 0.5);
+
+  authors = gtk_label_new (_("Authors: Kern Sibbald and John Walker"));
+  gtk_widget_show (authors);
+  gtk_box_pack_start (GTK_BOX (vbox9), authors, TRUE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (authors), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (authors), 0.0400001, 0.5);
+
+  theme = gtk_label_new (_("It comes by night and sucks the essence from your computers"));
+  gtk_widget_show (theme);
+  gtk_box_pack_start (GTK_BOX (vbox9), theme, TRUE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (theme), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (theme), 0.15, 0.5);
+
+  dialog_action_area5 = GTK_DIALOG (about1)->action_area;
+  gtk_widget_show (dialog_action_area5);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area5), GTK_BUTTONBOX_END);
+
+  hbox20 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox20);
+  gtk_container_add (GTK_CONTAINER (dialog_action_area5), hbox20);
+
+  label44 = gtk_label_new ("");
+  gtk_widget_show (label44);
+  gtk_box_pack_start (GTK_BOX (hbox20), label44, TRUE, FALSE, 0);
+
+  about_button = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (about_button);
+  gtk_box_pack_start (GTK_BOX (hbox20), about_button, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (about_button), 1);
+  GTK_WIDGET_SET_FLAGS (about_button, GTK_CAN_DEFAULT);
+
+  g_signal_connect ((gpointer) about_button, "clicked",
+                    G_CALLBACK (on_about_button_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (about1, about1, "about1");
+  GLADE_HOOKUP_OBJECT_NO_REF (about1, dialog_vbox5, "dialog_vbox5");
+  GLADE_HOOKUP_OBJECT (about1, vbox8, "vbox8");
+  GLADE_HOOKUP_OBJECT (about1, vbox9, "vbox9");
+  GLADE_HOOKUP_OBJECT (about1, about_head, "about_head");
+  GLADE_HOOKUP_OBJECT (about1, hseparator1, "hseparator1");
+  GLADE_HOOKUP_OBJECT (about1, copyright, "copyright");
+  GLADE_HOOKUP_OBJECT (about1, authors, "authors");
+  GLADE_HOOKUP_OBJECT (about1, theme, "theme");
+  GLADE_HOOKUP_OBJECT_NO_REF (about1, dialog_action_area5, "dialog_action_area5");
+  GLADE_HOOKUP_OBJECT (about1, hbox20, "hbox20");
+  GLADE_HOOKUP_OBJECT (about1, label44, "label44");
+  GLADE_HOOKUP_OBJECT (about1, about_button, "about_button");
+
+  return about1;
+}
+
+GtkWidget*
+create_SelectDirectorDialog (void)
+{
+  GtkWidget *SelectDirectorDialog;
+  GtkWidget *dialog_vbox6;
+  GtkWidget *vbox10;
+  GtkWidget *label48;
+  GtkWidget *label47;
+  GtkWidget *combo1;
+  GList *combo1_items = NULL;
+  GtkWidget *dirselect;
+  GtkWidget *dialog_action_area2;
+  GtkWidget *hbox21;
+  GtkWidget *button11;
+  GtkWidget *label46;
+  GtkWidget *button13;
+
+  SelectDirectorDialog = gtk_dialog_new ();
+  gtk_window_set_title (GTK_WINDOW (SelectDirectorDialog), _("Select Director"));
+  gtk_window_set_modal (GTK_WINDOW (SelectDirectorDialog), TRUE);
+
+  dialog_vbox6 = GTK_DIALOG (SelectDirectorDialog)->vbox;
+  gtk_widget_show (dialog_vbox6);
+
+  vbox10 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox10);
+  gtk_box_pack_start (GTK_BOX (dialog_vbox6), vbox10, TRUE, TRUE, 0);
+
+  label48 = gtk_label_new ("");
+  gtk_widget_show (label48);
+  gtk_box_pack_start (GTK_BOX (vbox10), label48, FALSE, FALSE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label48), 0.48, 0.46);
+
+  label47 = gtk_label_new (_("Select Director"));
+  gtk_widget_show (label47);
+  gtk_box_pack_start (GTK_BOX (vbox10), label47, FALSE, FALSE, 0);
+
+  combo1 = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo1)->popwin),
+                     "GladeParentKey", combo1);
+  gtk_widget_show (combo1);
+  gtk_box_pack_start (GTK_BOX (vbox10), combo1, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (combo1), 6);
+  combo1_items = g_list_append (combo1_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo1), combo1_items);
+  g_list_free (combo1_items);
+
+  dirselect = GTK_COMBO (combo1)->entry;
+  gtk_widget_show (dirselect);
+
+  dialog_action_area2 = GTK_DIALOG (SelectDirectorDialog)->action_area;
+  gtk_widget_show (dialog_action_area2);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_END);
+
+  hbox21 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox21);
+  gtk_container_add (GTK_CONTAINER (dialog_action_area2), hbox21);
+
+  button11 = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (button11);
+  gtk_box_pack_start (GTK_BOX (hbox21), button11, FALSE, FALSE, 0);
+
+  label46 = gtk_label_new (_("         "));
+  gtk_widget_show (label46);
+  gtk_box_pack_start (GTK_BOX (hbox21), label46, FALSE, FALSE, 0);
+  gtk_misc_set_padding (GTK_MISC (label46), 2, 0);
+
+  button13 = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_widget_show (button13);
+  gtk_box_pack_start (GTK_BOX (hbox21), button13, FALSE, FALSE, 0);
+
+  g_signal_connect ((gpointer) button11, "clicked",
+                    G_CALLBACK (on_select_director_OK_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) button13, "clicked",
+                    G_CALLBACK (on_select_director_cancel_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (SelectDirectorDialog, SelectDirectorDialog, "SelectDirectorDialog");
+  GLADE_HOOKUP_OBJECT_NO_REF (SelectDirectorDialog, dialog_vbox6, "dialog_vbox6");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, vbox10, "vbox10");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, label48, "label48");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, label47, "label47");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, combo1, "combo1");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, dirselect, "dirselect");
+  GLADE_HOOKUP_OBJECT_NO_REF (SelectDirectorDialog, dialog_action_area2, "dialog_action_area2");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, hbox21, "hbox21");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, button11, "button11");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, label46, "label46");
+  GLADE_HOOKUP_OBJECT (SelectDirectorDialog, button13, "button13");
+
+  return SelectDirectorDialog;
+}
+
+GtkWidget*
+create_RunDialog (void)
+{
+  GtkWidget *RunDialog;
+  GtkWidget *dialog_vbox7;
+  GtkWidget *vbox11;
+  GtkWidget *vbox12;
+  GtkWidget *label62;
+  GtkWidget *hbox28;
+  GtkWidget *hbox29;
+  GtkWidget *label63;
+  GtkWidget *combo_job;
+  GList *combo_job_items = NULL;
+  GtkWidget *entry_job;
+  GtkWidget *label64;
+  GtkWidget *combo_type;
+  GList *combo_type_items = NULL;
+  GtkWidget *entry_type;
+  GtkWidget *label65;
+  GtkWidget *hbox30;
+  GtkWidget *label66;
+  GtkWidget *combo_client;
+  GList *combo_client_items = NULL;
+  GtkWidget *entry_client;
+  GtkWidget *label67;
+  GtkWidget *hbox31;
+  GtkWidget *label68;
+  GtkWidget *combo_fileset;
+  GList *combo_fileset_items = NULL;
+  GtkWidget *entry_fileset;
+  GtkWidget *view_fileset_button;
+  GtkWidget *label69;
+  GtkWidget *hbox32;
+  GtkWidget *label70;
+  GtkWidget *combo_level;
+  GList *combo_level_items = NULL;
+  GtkWidget *entry_level;
+  GtkWidget *label71;
+  GtkWidget *hbox33;
+  GtkWidget *label72;
+  GtkWidget *combo_pool;
+  GList *combo_pool_items = NULL;
+  GtkWidget *entry_pool;
+  GtkWidget *label73;
+  GtkWidget *hbox39;
+  GtkWidget *label96;
+  GtkWidget *combo_storage;
+  GList *combo_storage_items = NULL;
+  GtkWidget *entry_storage;
+  GtkWidget *label97;
+  GtkWidget *hbox40;
+  GtkWidget *label98;
+  GtkWidget *combo_messages;
+  GList *combo_messages_items = NULL;
+  GtkWidget *entry_messages;
+  GtkWidget *label99;
+  GtkWidget *hbox34;
+  GtkWidget *label77;
+  GtkWidget *entry_where;
+  GtkWidget *label78;
+  GtkWidget *hbox41;
+  GtkWidget *label100;
+  GtkWidget *entry_when;
+  GtkWidget *label101;
+  GtkWidget *label84;
+  GtkWidget *dialog_action_area6;
+  GtkWidget *hbuttonbox1;
+  GtkWidget *run_ok;
+  GtkWidget *run_cancel;
+
+  RunDialog = gtk_dialog_new ();
+  gtk_window_set_title (GTK_WINDOW (RunDialog), _("Run a Job"));
+
+  dialog_vbox7 = GTK_DIALOG (RunDialog)->vbox;
+  gtk_widget_show (dialog_vbox7);
+
+  vbox11 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox11);
+  gtk_box_pack_start (GTK_BOX (dialog_vbox7), vbox11, TRUE, TRUE, 0);
+
+  vbox12 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox12);
+  gtk_box_pack_start (GTK_BOX (vbox11), vbox12, TRUE, TRUE, 0);
+
+  label62 = gtk_label_new (_("Run a Job"));
+  gtk_widget_show (label62);
+  gtk_box_pack_start (GTK_BOX (vbox12), label62, FALSE, FALSE, 2);
+  gtk_misc_set_padding (GTK_MISC (label62), 0, 9);
+
+  hbox28 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox28);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox28, FALSE, FALSE, 2);
+
+  hbox29 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox29);
+  gtk_box_pack_start (GTK_BOX (hbox28), hbox29, TRUE, TRUE, 0);
+
+  label63 = gtk_label_new (_("Job:"));
+  gtk_widget_show (label63);
+  gtk_box_pack_start (GTK_BOX (hbox29), label63, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label63), GTK_JUSTIFY_RIGHT);
+
+  combo_job = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_job)->popwin),
+                     "GladeParentKey", combo_job);
+  gtk_widget_show (combo_job);
+  gtk_box_pack_start (GTK_BOX (hbox29), combo_job, TRUE, TRUE, 1);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_job), TRUE, FALSE);
+  combo_job_items = g_list_append (combo_job_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_job), combo_job_items);
+  g_list_free (combo_job_items);
+
+  entry_job = GTK_COMBO (combo_job)->entry;
+  gtk_widget_show (entry_job);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_job), FALSE);
+
+  label64 = gtk_label_new (_("   Type:"));
+  gtk_widget_show (label64);
+  gtk_box_pack_start (GTK_BOX (hbox29), label64, FALSE, FALSE, 0);
+
+  combo_type = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_type)->popwin),
+                     "GladeParentKey", combo_type);
+  gtk_widget_show (combo_type);
+  gtk_box_pack_start (GTK_BOX (hbox29), combo_type, FALSE, FALSE, 6);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_type), TRUE, FALSE);
+  combo_type_items = g_list_append (combo_type_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_type), combo_type_items);
+  g_list_free (combo_type_items);
+
+  entry_type = GTK_COMBO (combo_type)->entry;
+  gtk_widget_show (entry_type);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_type), FALSE);
+
+  label65 = gtk_label_new (_(" "));
+  gtk_widget_show (label65);
+  gtk_box_pack_start (GTK_BOX (hbox28), label65, FALSE, FALSE, 30);
+
+  hbox30 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox30);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox30, TRUE, TRUE, 0);
+
+  label66 = gtk_label_new (_("Client:"));
+  gtk_widget_show (label66);
+  gtk_box_pack_start (GTK_BOX (hbox30), label66, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label66), GTK_JUSTIFY_RIGHT);
+
+  combo_client = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_client)->popwin),
+                     "GladeParentKey", combo_client);
+  gtk_widget_show (combo_client);
+  gtk_box_pack_start (GTK_BOX (hbox30), combo_client, TRUE, TRUE, 1);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_client), TRUE, FALSE);
+  combo_client_items = g_list_append (combo_client_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_client), combo_client_items);
+  g_list_free (combo_client_items);
+
+  entry_client = GTK_COMBO (combo_client)->entry;
+  gtk_widget_show (entry_client);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_client), FALSE);
+
+  label67 = gtk_label_new (_(" "));
+  gtk_widget_show (label67);
+  gtk_box_pack_start (GTK_BOX (hbox30), label67, FALSE, FALSE, 123);
+
+  hbox31 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox31);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox31, TRUE, TRUE, 2);
+
+  label68 = gtk_label_new (_("FileSet: "));
+  gtk_widget_show (label68);
+  gtk_box_pack_start (GTK_BOX (hbox31), label68, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label68), GTK_JUSTIFY_RIGHT);
+
+  combo_fileset = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_fileset)->popwin),
+                     "GladeParentKey", combo_fileset);
+  gtk_widget_show (combo_fileset);
+  gtk_box_pack_start (GTK_BOX (hbox31), combo_fileset, TRUE, TRUE, 0);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_fileset), TRUE, FALSE);
+  combo_fileset_items = g_list_append (combo_fileset_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_fileset), combo_fileset_items);
+  g_list_free (combo_fileset_items);
+
+  entry_fileset = GTK_COMBO (combo_fileset)->entry;
+  gtk_widget_show (entry_fileset);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_fileset), FALSE);
+
+  view_fileset_button = gtk_button_new_with_mnemonic (_("  View FileSet  "));
+  gtk_widget_show (view_fileset_button);
+  gtk_box_pack_start (GTK_BOX (hbox31), view_fileset_button, FALSE, TRUE, 10);
+
+  label69 = gtk_label_new (_("  "));
+  gtk_widget_show (label69);
+  gtk_box_pack_start (GTK_BOX (hbox31), label69, FALSE, FALSE, 65);
+
+  hbox32 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox32);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox32, TRUE, TRUE, 2);
+
+  label70 = gtk_label_new (_("Level:"));
+  gtk_widget_show (label70);
+  gtk_box_pack_start (GTK_BOX (hbox32), label70, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label70), GTK_JUSTIFY_RIGHT);
+
+  combo_level = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_level)->popwin),
+                     "GladeParentKey", combo_level);
+  gtk_widget_show (combo_level);
+  gtk_box_pack_start (GTK_BOX (hbox32), combo_level, TRUE, TRUE, 0);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_level), TRUE, FALSE);
+  combo_level_items = g_list_append (combo_level_items, (gpointer) "");
+  combo_level_items = g_list_append (combo_level_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_level), combo_level_items);
+  g_list_free (combo_level_items);
+
+  entry_level = GTK_COMBO (combo_level)->entry;
+  gtk_widget_show (entry_level);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_level), FALSE);
+
+  label71 = gtk_label_new (_("             "));
+  gtk_widget_show (label71);
+  gtk_box_pack_start (GTK_BOX (hbox32), label71, FALSE, FALSE, 100);
+
+  hbox33 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox33);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox33, TRUE, TRUE, 2);
+
+  label72 = gtk_label_new (_("Pool:"));
+  gtk_widget_show (label72);
+  gtk_box_pack_start (GTK_BOX (hbox33), label72, FALSE, FALSE, 0);
+
+  combo_pool = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_pool)->popwin),
+                     "GladeParentKey", combo_pool);
+  gtk_widget_show (combo_pool);
+  gtk_box_pack_start (GTK_BOX (hbox33), combo_pool, TRUE, TRUE, 0);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_pool), TRUE, FALSE);
+  combo_pool_items = g_list_append (combo_pool_items, (gpointer) "");
+  combo_pool_items = g_list_append (combo_pool_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_pool), combo_pool_items);
+  g_list_free (combo_pool_items);
+
+  entry_pool = GTK_COMBO (combo_pool)->entry;
+  gtk_widget_show (entry_pool);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_pool), FALSE);
+
+  label73 = gtk_label_new (_("   "));
+  gtk_widget_show (label73);
+  gtk_box_pack_start (GTK_BOX (hbox33), label73, FALSE, FALSE, 120);
+
+  hbox39 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox39);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox39, TRUE, TRUE, 0);
+
+  label96 = gtk_label_new (_("Storage:"));
+  gtk_widget_show (label96);
+  gtk_box_pack_start (GTK_BOX (hbox39), label96, FALSE, FALSE, 0);
+
+  combo_storage = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_storage)->popwin),
+                     "GladeParentKey", combo_storage);
+  gtk_widget_show (combo_storage);
+  gtk_box_pack_start (GTK_BOX (hbox39), combo_storage, TRUE, TRUE, 0);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_storage), TRUE, FALSE);
+  combo_storage_items = g_list_append (combo_storage_items, (gpointer) "");
+  combo_storage_items = g_list_append (combo_storage_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_storage), combo_storage_items);
+  g_list_free (combo_storage_items);
+
+  entry_storage = GTK_COMBO (combo_storage)->entry;
+  gtk_widget_show (entry_storage);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_storage), FALSE);
+
+  label97 = gtk_label_new (_("   "));
+  gtk_widget_show (label97);
+  gtk_box_pack_start (GTK_BOX (hbox39), label97, FALSE, FALSE, 120);
+
+  hbox40 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox40);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox40, TRUE, TRUE, 0);
+
+  label98 = gtk_label_new (_("Messages:"));
+  gtk_widget_show (label98);
+  gtk_box_pack_start (GTK_BOX (hbox40), label98, FALSE, FALSE, 0);
+
+  combo_messages = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (combo_messages)->popwin),
+                     "GladeParentKey", combo_messages);
+  gtk_widget_show (combo_messages);
+  gtk_box_pack_start (GTK_BOX (hbox40), combo_messages, TRUE, TRUE, 0);
+  gtk_combo_set_value_in_list (GTK_COMBO (combo_messages), TRUE, FALSE);
+  combo_messages_items = g_list_append (combo_messages_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (combo_messages), combo_messages_items);
+  g_list_free (combo_messages_items);
+
+  entry_messages = GTK_COMBO (combo_messages)->entry;
+  gtk_widget_show (entry_messages);
+  gtk_editable_set_editable (GTK_EDITABLE (entry_messages), FALSE);
+
+  label99 = gtk_label_new (_("   "));
+  gtk_widget_show (label99);
+  gtk_box_pack_start (GTK_BOX (hbox40), label99, FALSE, FALSE, 120);
+
+  hbox34 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox34);
+  gtk_box_pack_start (GTK_BOX (vbox12), hbox34, TRUE, TRUE, 2);
+
+  label77 = gtk_label_new (_("Where: "));
+  gtk_widget_show (label77);
+  gtk_box_pack_start (GTK_BOX (hbox34), label77, FALSE, FALSE, 0);
+
+  entry_where = gtk_entry_new ();
+  gtk_widget_show (entry_where);
+  gtk_box_pack_start (GTK_BOX (hbox34), entry_where, TRUE, TRUE, 0);
+
+  label78 = gtk_label_new (_("   "));
+  gtk_widget_show (label78);
+  gtk_box_pack_start (GTK_BOX (hbox34), label78, FALSE, FALSE, 120);
+
+  hbox41 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox41);
+  gtk_box_pack_start (GTK_BOX (vbox11), hbox41, TRUE, TRUE, 0);
+
+  label100 = gtk_label_new (_("When:"));
+  gtk_widget_show (label100);
+  gtk_box_pack_start (GTK_BOX (hbox41), label100, FALSE, FALSE, 0);
+
+  entry_when = gtk_entry_new ();
+  gtk_widget_show (entry_when);
+  gtk_box_pack_start (GTK_BOX (hbox41), entry_when, TRUE, TRUE, 0);
+
+  label101 = gtk_label_new (_("   "));
+  gtk_widget_show (label101);
+  gtk_box_pack_start (GTK_BOX (hbox41), label101, FALSE, FALSE, 120);
+
+  label84 = gtk_label_new (_("   "));
+  gtk_widget_show (label84);
+  gtk_box_pack_start (GTK_BOX (vbox11), label84, FALSE, FALSE, 0);
+
+  dialog_action_area6 = GTK_DIALOG (RunDialog)->action_area;
+  gtk_widget_show (dialog_action_area6);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area6), GTK_BUTTONBOX_END);
+
+  hbuttonbox1 = gtk_hbutton_box_new ();
+  gtk_widget_show (hbuttonbox1);
+  gtk_container_add (GTK_CONTAINER (dialog_action_area6), hbuttonbox1);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 8);
+
+  run_ok = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (run_ok);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox1), run_ok);
+  GTK_WIDGET_SET_FLAGS (run_ok, GTK_CAN_DEFAULT);
+
+  run_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_widget_show (run_cancel);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox1), run_cancel);
+  GTK_WIDGET_SET_FLAGS (run_cancel, GTK_CAN_DEFAULT);
+
+  g_signal_connect ((gpointer) entry_job, "changed",
+                    G_CALLBACK (on_entry_job_changed),
+                    NULL);
+  g_signal_connect ((gpointer) view_fileset_button, "clicked",
+                    G_CALLBACK (on_view_fileset_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) run_ok, "clicked",
+                    G_CALLBACK (on_run_ok_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) run_cancel, "clicked",
+                    G_CALLBACK (on_run_cancel_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (RunDialog, RunDialog, "RunDialog");
+  GLADE_HOOKUP_OBJECT_NO_REF (RunDialog, dialog_vbox7, "dialog_vbox7");
+  GLADE_HOOKUP_OBJECT (RunDialog, vbox11, "vbox11");
+  GLADE_HOOKUP_OBJECT (RunDialog, vbox12, "vbox12");
+  GLADE_HOOKUP_OBJECT (RunDialog, label62, "label62");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox28, "hbox28");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox29, "hbox29");
+  GLADE_HOOKUP_OBJECT (RunDialog, label63, "label63");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_job, "combo_job");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_job, "entry_job");
+  GLADE_HOOKUP_OBJECT (RunDialog, label64, "label64");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_type, "combo_type");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_type, "entry_type");
+  GLADE_HOOKUP_OBJECT (RunDialog, label65, "label65");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox30, "hbox30");
+  GLADE_HOOKUP_OBJECT (RunDialog, label66, "label66");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_client, "combo_client");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_client, "entry_client");
+  GLADE_HOOKUP_OBJECT (RunDialog, label67, "label67");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox31, "hbox31");
+  GLADE_HOOKUP_OBJECT (RunDialog, label68, "label68");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_fileset, "combo_fileset");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_fileset, "entry_fileset");
+  GLADE_HOOKUP_OBJECT (RunDialog, view_fileset_button, "view_fileset_button");
+  GLADE_HOOKUP_OBJECT (RunDialog, label69, "label69");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox32, "hbox32");
+  GLADE_HOOKUP_OBJECT (RunDialog, label70, "label70");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_level, "combo_level");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_level, "entry_level");
+  GLADE_HOOKUP_OBJECT (RunDialog, label71, "label71");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox33, "hbox33");
+  GLADE_HOOKUP_OBJECT (RunDialog, label72, "label72");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_pool, "combo_pool");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_pool, "entry_pool");
+  GLADE_HOOKUP_OBJECT (RunDialog, label73, "label73");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox39, "hbox39");
+  GLADE_HOOKUP_OBJECT (RunDialog, label96, "label96");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_storage, "combo_storage");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_storage, "entry_storage");
+  GLADE_HOOKUP_OBJECT (RunDialog, label97, "label97");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox40, "hbox40");
+  GLADE_HOOKUP_OBJECT (RunDialog, label98, "label98");
+  GLADE_HOOKUP_OBJECT (RunDialog, combo_messages, "combo_messages");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_messages, "entry_messages");
+  GLADE_HOOKUP_OBJECT (RunDialog, label99, "label99");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox34, "hbox34");
+  GLADE_HOOKUP_OBJECT (RunDialog, label77, "label77");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_where, "entry_where");
+  GLADE_HOOKUP_OBJECT (RunDialog, label78, "label78");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbox41, "hbox41");
+  GLADE_HOOKUP_OBJECT (RunDialog, label100, "label100");
+  GLADE_HOOKUP_OBJECT (RunDialog, entry_when, "entry_when");
+  GLADE_HOOKUP_OBJECT (RunDialog, label101, "label101");
+  GLADE_HOOKUP_OBJECT (RunDialog, label84, "label84");
+  GLADE_HOOKUP_OBJECT_NO_REF (RunDialog, dialog_action_area6, "dialog_action_area6");
+  GLADE_HOOKUP_OBJECT (RunDialog, hbuttonbox1, "hbuttonbox1");
+  GLADE_HOOKUP_OBJECT (RunDialog, run_ok, "run_ok");
+  GLADE_HOOKUP_OBJECT (RunDialog, run_cancel, "run_cancel");
+
+  return RunDialog;
+}
+
+GtkWidget*
+create_restore_files (void)
+{
+  GtkWidget *restore_files;
+  GtkWidget *vbox13;
+  GtkWidget *scrolledwindow4;
+  GtkWidget *ctree2;
+  GtkWidget *hbox38;
+  GtkWidget *label88;
+  GtkWidget *entry25;
+  GtkWidget *hbox44;
+  GtkWidget *label105;
+  GtkWidget *restore_file;
+  GtkTooltips *tooltips;
+
+  tooltips = gtk_tooltips_new ();
+
+  restore_files = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (restore_files), _("Restore File Selection"));
+  gtk_window_set_modal (GTK_WINDOW (restore_files), TRUE);
+
+  vbox13 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox13);
+  gtk_container_add (GTK_CONTAINER (restore_files), vbox13);
+
+  scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL);
+  gtk_widget_show (scrolledwindow4);
+  gtk_box_pack_start (GTK_BOX (vbox13), scrolledwindow4, TRUE, TRUE, 0);
+  GTK_WIDGET_UNSET_FLAGS (scrolledwindow4, GTK_CAN_FOCUS);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_SHADOW_IN);
+
+  ctree2 = gtk_tree_view_new ();
+  gtk_widget_show (ctree2);
+  gtk_container_add (GTK_CONTAINER (scrolledwindow4), ctree2);
+
+  hbox38 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox38);
+  gtk_box_pack_start (GTK_BOX (vbox13), hbox38, FALSE, TRUE, 0);
+
+  label88 = gtk_label_new (_(" cwd:"));
+  gtk_widget_show (label88);
+  gtk_box_pack_start (GTK_BOX (hbox38), label88, FALSE, TRUE, 0);
+
+  entry25 = gtk_entry_new ();
+  gtk_widget_show (entry25);
+  gtk_box_pack_start (GTK_BOX (hbox38), entry25, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (entry25, GTK_CAN_DEFAULT);
+  gtk_tooltips_set_tip (tooltips, entry25, _("Enter Commands Here"), NULL);
+
+  hbox44 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox44);
+  gtk_box_pack_start (GTK_BOX (vbox13), hbox44, FALSE, TRUE, 0);
+
+  label105 = gtk_label_new (_(" "));
+  gtk_widget_show (label105);
+  gtk_box_pack_start (GTK_BOX (hbox44), label105, TRUE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label105), GTK_JUSTIFY_FILL);
+  gtk_misc_set_padding (GTK_MISC (label105), 59, 0);
+
+  restore_file = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (restore_file);
+  gtk_box_pack_start (GTK_BOX (hbox44), restore_file, TRUE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (restore_file), 9);
+
+  g_signal_connect ((gpointer) entry25, "key_press_event",
+                    G_CALLBACK (on_entry1_key_press_event),
+                    NULL);
+  g_signal_connect ((gpointer) entry25, "key_release_event",
+                    G_CALLBACK (on_entry1_key_release_event),
+                    NULL);
+  g_signal_connect ((gpointer) restore_file, "clicked",
+                    G_CALLBACK (on_restore_file_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (restore_files, restore_files, "restore_files");
+  GLADE_HOOKUP_OBJECT (restore_files, vbox13, "vbox13");
+  GLADE_HOOKUP_OBJECT (restore_files, scrolledwindow4, "scrolledwindow4");
+  GLADE_HOOKUP_OBJECT (restore_files, ctree2, "ctree2");
+  GLADE_HOOKUP_OBJECT (restore_files, hbox38, "hbox38");
+  GLADE_HOOKUP_OBJECT (restore_files, label88, "label88");
+  GLADE_HOOKUP_OBJECT (restore_files, entry25, "entry25");
+  GLADE_HOOKUP_OBJECT (restore_files, hbox44, "hbox44");
+  GLADE_HOOKUP_OBJECT (restore_files, label105, "label105");
+  GLADE_HOOKUP_OBJECT (restore_files, restore_file, "restore_file");
+  GLADE_HOOKUP_OBJECT_NO_REF (restore_files, tooltips, "tooltips");
+
+  gtk_widget_grab_focus (entry25);
+  gtk_widget_grab_default (entry25);
+  return restore_files;
+}
+
+GtkWidget*
+create_restore_dialog (void)
+{
+  GtkWidget *restore_dialog;
+  GtkWidget *dialog_vbox8;
+  GtkWidget *hbox42;
+  GtkWidget *frame3;
+  GtkWidget *hbox43;
+  GtkWidget *label102;
+  GtkWidget *vbox15;
+  GtkWidget *label103;
+  GtkWidget *rb_most_recent;
+  GSList *rb_most_recent_group = NULL;
+  GtkWidget *rb_jobs;
+  GSList *rb_jobs_group = NULL;
+  GtkWidget *rb_file;
+  GSList *rb_file_group = NULL;
+  GtkWidget *label104;
+  GtkWidget *label106;
+  GtkWidget *vbox14;
+  GtkWidget *apply_button;
+  GtkWidget *dialog_action_area7;
+  GtkWidget *hbuttonbox2;
+  GtkWidget *restore_ok;
+  GtkWidget *restore_cancel;
+
+  restore_dialog = gtk_dialog_new ();
+  gtk_window_set_title (GTK_WINDOW (restore_dialog), _("Restore Files"));
+  gtk_window_set_modal (GTK_WINDOW (restore_dialog), TRUE);
+
+  dialog_vbox8 = GTK_DIALOG (restore_dialog)->vbox;
+  gtk_widget_show (dialog_vbox8);
+
+  hbox42 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox42);
+  gtk_box_pack_start (GTK_BOX (dialog_vbox8), hbox42, TRUE, TRUE, 0);
+
+  frame3 = gtk_frame_new (NULL);
+  gtk_widget_show (frame3);
+  gtk_box_pack_start (GTK_BOX (hbox42), frame3, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (frame3), 8);
+
+  hbox43 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox43);
+  gtk_container_add (GTK_CONTAINER (frame3), hbox43);
+
+  label102 = gtk_label_new (_("         "));
+  gtk_widget_show (label102);
+  gtk_box_pack_end (GTK_BOX (hbox43), label102, FALSE, FALSE, 0);
+
+  vbox15 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox15);
+  gtk_box_pack_start (GTK_BOX (hbox43), vbox15, TRUE, TRUE, 0);
+
+  label103 = gtk_label_new ("");
+  gtk_widget_show (label103);
+  gtk_box_pack_start (GTK_BOX (vbox15), label103, FALSE, FALSE, 0);
+  gtk_misc_set_padding (GTK_MISC (label103), 0, 2);
+
+  rb_most_recent = gtk_radio_button_new_with_mnemonic (NULL, _("Select most recent backup"));
+  gtk_widget_show (rb_most_recent);
+  gtk_box_pack_start (GTK_BOX (vbox15), rb_most_recent, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (rb_most_recent), 3);
+  gtk_radio_button_set_group (GTK_RADIO_BUTTON (rb_most_recent), rb_most_recent_group);
+  rb_most_recent_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (rb_most_recent));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rb_most_recent), TRUE);
+
+  rb_jobs = gtk_radio_button_new_with_mnemonic (NULL, _("Select list of Jobs"));
+  gtk_widget_show (rb_jobs);
+  gtk_box_pack_start (GTK_BOX (vbox15), rb_jobs, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (rb_jobs), 5);
+  gtk_radio_button_set_group (GTK_RADIO_BUTTON (rb_jobs), rb_jobs_group);
+  rb_jobs_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (rb_jobs));
+
+  rb_file = gtk_radio_button_new_with_mnemonic (NULL, _("Find a specific file"));
+  gtk_widget_show (rb_file);
+  gtk_box_pack_start (GTK_BOX (vbox15), rb_file, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (rb_file), 4);
+  gtk_radio_button_set_group (GTK_RADIO_BUTTON (rb_file), rb_file_group);
+  rb_file_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (rb_file));
+
+  label104 = gtk_label_new ("");
+  gtk_widget_show (label104);
+  gtk_box_pack_start (GTK_BOX (vbox15), label104, FALSE, FALSE, 0);
+
+  label106 = gtk_label_new (_("Select by:"));
+  gtk_widget_show (label106);
+  gtk_frame_set_label_widget (GTK_FRAME (frame3), label106);
+  gtk_label_set_justify (GTK_LABEL (label106), GTK_JUSTIFY_LEFT);
+
+  vbox14 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox14);
+  gtk_box_pack_start (GTK_BOX (hbox42), vbox14, FALSE, FALSE, 0);
+
+  apply_button = gtk_button_new_from_stock ("gtk-apply");
+  gtk_widget_show (apply_button);
+  gtk_box_pack_start (GTK_BOX (vbox14), apply_button, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (apply_button), 50);
+
+  dialog_action_area7 = GTK_DIALOG (restore_dialog)->action_area;
+  gtk_widget_show (dialog_action_area7);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area7), GTK_BUTTONBOX_END);
+
+  hbuttonbox2 = gtk_hbutton_box_new ();
+  gtk_widget_show (hbuttonbox2);
+  gtk_container_add (GTK_CONTAINER (dialog_action_area7), hbuttonbox2);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbuttonbox2), 8);
+
+  restore_ok = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (restore_ok);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox2), restore_ok);
+  GTK_WIDGET_SET_FLAGS (restore_ok, GTK_CAN_DEFAULT);
+
+  restore_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_widget_show (restore_cancel);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox2), restore_cancel);
+  GTK_WIDGET_SET_FLAGS (restore_cancel, GTK_CAN_DEFAULT);
+
+  g_signal_connect ((gpointer) apply_button, "clicked",
+                    G_CALLBACK (on_apply_button_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) restore_ok, "clicked",
+                    G_CALLBACK (on_restore_ok_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) restore_cancel, "clicked",
+                    G_CALLBACK (on_restore_cancel_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (restore_dialog, restore_dialog, "restore_dialog");
+  GLADE_HOOKUP_OBJECT_NO_REF (restore_dialog, dialog_vbox8, "dialog_vbox8");
+  GLADE_HOOKUP_OBJECT (restore_dialog, hbox42, "hbox42");
+  GLADE_HOOKUP_OBJECT (restore_dialog, frame3, "frame3");
+  GLADE_HOOKUP_OBJECT (restore_dialog, hbox43, "hbox43");
+  GLADE_HOOKUP_OBJECT (restore_dialog, label102, "label102");
+  GLADE_HOOKUP_OBJECT (restore_dialog, vbox15, "vbox15");
+  GLADE_HOOKUP_OBJECT (restore_dialog, label103, "label103");
+  GLADE_HOOKUP_OBJECT (restore_dialog, rb_most_recent, "rb_most_recent");
+  GLADE_HOOKUP_OBJECT (restore_dialog, rb_jobs, "rb_jobs");
+  GLADE_HOOKUP_OBJECT (restore_dialog, rb_file, "rb_file");
+  GLADE_HOOKUP_OBJECT (restore_dialog, label104, "label104");
+  GLADE_HOOKUP_OBJECT (restore_dialog, label106, "label106");
+  GLADE_HOOKUP_OBJECT (restore_dialog, vbox14, "vbox14");
+  GLADE_HOOKUP_OBJECT (restore_dialog, apply_button, "apply_button");
+  GLADE_HOOKUP_OBJECT_NO_REF (restore_dialog, dialog_action_area7, "dialog_action_area7");
+  GLADE_HOOKUP_OBJECT (restore_dialog, hbuttonbox2, "hbuttonbox2");
+  GLADE_HOOKUP_OBJECT (restore_dialog, restore_ok, "restore_ok");
+  GLADE_HOOKUP_OBJECT (restore_dialog, restore_cancel, "restore_cancel");
+
+  return restore_dialog;
+}
+
+GtkWidget*
+create_label_dialog (void)
+{
+  GtkWidget *label_dialog;
+  GtkWidget *dialog_vbox9;
+  GtkWidget *vbox16;
+  GtkWidget *label106;
+  GtkWidget *hbox45;
+  GtkWidget *label107;
+  GtkWidget *label_combo_storage;
+  GList *label_combo_storage_items = NULL;
+  GtkWidget *entry26;
+  GtkWidget *hbox46;
+  GtkWidget *label109;
+  GtkWidget *label_combo_pool;
+  GList *label_combo_pool_items = NULL;
+  GtkWidget *entry27;
+  GtkWidget *hbox47;
+  GtkWidget *label111;
+  GtkWidget *label_entry_volume;
+  GtkWidget *hbox48;
+  GtkWidget *slot1;
+  GtkObject *label_slot_adj;
+  GtkWidget *label_slot;
+  GtkWidget *label113;
+  GtkWidget *dialog_action_area8;
+  GtkWidget *hbuttonbox3;
+  GtkWidget *label_ok;
+  GtkWidget *label_cancel;
+
+  label_dialog = gtk_dialog_new ();
+  gtk_window_set_title (GTK_WINDOW (label_dialog), _("Label a Volume"));
+  gtk_window_set_modal (GTK_WINDOW (label_dialog), TRUE);
+
+  dialog_vbox9 = GTK_DIALOG (label_dialog)->vbox;
+  gtk_widget_show (dialog_vbox9);
+
+  vbox16 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox16);
+  gtk_box_pack_start (GTK_BOX (dialog_vbox9), vbox16, FALSE, TRUE, 0);
+
+  label106 = gtk_label_new (_("Label a Volume"));
+  gtk_widget_show (label106);
+  gtk_box_pack_start (GTK_BOX (vbox16), label106, FALSE, FALSE, 0);
+  gtk_misc_set_padding (GTK_MISC (label106), 0, 9);
+
+  hbox45 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox45);
+  gtk_box_pack_start (GTK_BOX (vbox16), hbox45, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox45), 5);
+
+  label107 = gtk_label_new (_("Storage:"));
+  gtk_widget_show (label107);
+  gtk_box_pack_start (GTK_BOX (hbox45), label107, TRUE, TRUE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label107), 0.15, 0.5);
+
+  label_combo_storage = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (label_combo_storage)->popwin),
+                     "GladeParentKey", label_combo_storage);
+  gtk_widget_show (label_combo_storage);
+  gtk_box_pack_start (GTK_BOX (hbox45), label_combo_storage, TRUE, TRUE, 15);
+  gtk_combo_set_value_in_list (GTK_COMBO (label_combo_storage), TRUE, FALSE);
+  label_combo_storage_items = g_list_append (label_combo_storage_items, (gpointer) "");
+  label_combo_storage_items = g_list_append (label_combo_storage_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (label_combo_storage), label_combo_storage_items);
+  g_list_free (label_combo_storage_items);
+
+  entry26 = GTK_COMBO (label_combo_storage)->entry;
+  gtk_widget_show (entry26);
+  gtk_editable_set_editable (GTK_EDITABLE (entry26), FALSE);
+
+  hbox46 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox46);
+  gtk_box_pack_start (GTK_BOX (vbox16), hbox46, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox46), 5);
+
+  label109 = gtk_label_new (_("Pool:"));
+  gtk_widget_show (label109);
+  gtk_box_pack_start (GTK_BOX (hbox46), label109, TRUE, TRUE, 0);
+  gtk_label_set_justify (GTK_LABEL (label109), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (label109), 0.12, 0.5);
+
+  label_combo_pool = gtk_combo_new ();
+  g_object_set_data (G_OBJECT (GTK_COMBO (label_combo_pool)->popwin),
+                     "GladeParentKey", label_combo_pool);
+  gtk_widget_show (label_combo_pool);
+  gtk_box_pack_start (GTK_BOX (hbox46), label_combo_pool, TRUE, TRUE, 14);
+  gtk_combo_set_value_in_list (GTK_COMBO (label_combo_pool), TRUE, FALSE);
+  label_combo_pool_items = g_list_append (label_combo_pool_items, (gpointer) "");
+  label_combo_pool_items = g_list_append (label_combo_pool_items, (gpointer) "");
+  gtk_combo_set_popdown_strings (GTK_COMBO (label_combo_pool), label_combo_pool_items);
+  g_list_free (label_combo_pool_items);
+
+  entry27 = GTK_COMBO (label_combo_pool)->entry;
+  gtk_widget_show (entry27);
+  gtk_editable_set_editable (GTK_EDITABLE (entry27), FALSE);
+
+  hbox47 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox47);
+  gtk_box_pack_start (GTK_BOX (vbox16), hbox47, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox47), 5);
+
+  label111 = gtk_label_new (_("Volume Name:"));
+  gtk_widget_show (label111);
+  gtk_box_pack_start (GTK_BOX (hbox47), label111, TRUE, TRUE, 0);
+  gtk_label_set_justify (GTK_LABEL (label111), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (label111), 0.17, 0.5);
+
+  label_entry_volume = gtk_entry_new ();
+  gtk_widget_show (label_entry_volume);
+  gtk_box_pack_start (GTK_BOX (hbox47), label_entry_volume, TRUE, TRUE, 0);
+
+  hbox48 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox48);
+  gtk_box_pack_start (GTK_BOX (vbox16), hbox48, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox48), 5);
+
+  slot1 = gtk_label_new (_("Slot:"));
+  gtk_widget_show (slot1);
+  gtk_box_pack_start (GTK_BOX (hbox48), slot1, FALSE, TRUE, 0);
+  gtk_label_set_justify (GTK_LABEL (slot1), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (slot1), 0.09, 0.5);
+
+  label_slot_adj = gtk_adjustment_new (0, 0, 10000, 1, 10, 10);
+  label_slot = gtk_spin_button_new (GTK_ADJUSTMENT (label_slot_adj), 1, 0);
+  gtk_widget_show (label_slot);
+  gtk_box_pack_start (GTK_BOX (hbox48), label_slot, TRUE, TRUE, 0);
+  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (label_slot), TRUE);
+
+  label113 = gtk_label_new (_("   "));
+  gtk_widget_show (label113);
+  gtk_box_pack_start (GTK_BOX (vbox16), label113, FALSE, FALSE, 0);
+
+  dialog_action_area8 = GTK_DIALOG (label_dialog)->action_area;
+  gtk_widget_show (dialog_action_area8);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area8), GTK_BUTTONBOX_END);
+
+  hbuttonbox3 = gtk_hbutton_box_new ();
+  gtk_widget_show (hbuttonbox3);
+  gtk_container_add (GTK_CONTAINER (dialog_action_area8), hbuttonbox3);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox3), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbuttonbox3), 8);
+
+  label_ok = gtk_button_new_from_stock ("gtk-ok");
+  gtk_widget_show (label_ok);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox3), label_ok);
+  GTK_WIDGET_SET_FLAGS (label_ok, GTK_CAN_DEFAULT);
+
+  label_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_widget_show (label_cancel);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox3), label_cancel);
+  GTK_WIDGET_SET_FLAGS (label_cancel, GTK_CAN_DEFAULT);
+
+  g_signal_connect ((gpointer) label_ok, "clicked",
+                    G_CALLBACK (on_label_ok_clicked),
+                    NULL);
+  g_signal_connect ((gpointer) label_cancel, "clicked",
+                    G_CALLBACK (on_label_cancel_clicked),
+                    NULL);
+
+  /* Store pointers to all widgets, for use by lookup_widget(). */
+  GLADE_HOOKUP_OBJECT_NO_REF (label_dialog, label_dialog, "label_dialog");
+  GLADE_HOOKUP_OBJECT_NO_REF (label_dialog, dialog_vbox9, "dialog_vbox9");
+  GLADE_HOOKUP_OBJECT (label_dialog, vbox16, "vbox16");
+  GLADE_HOOKUP_OBJECT (label_dialog, label106, "label106");
+  GLADE_HOOKUP_OBJECT (label_dialog, hbox45, "hbox45");
+  GLADE_HOOKUP_OBJECT (label_dialog, label107, "label107");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_combo_storage, "label_combo_storage");
+  GLADE_HOOKUP_OBJECT (label_dialog, entry26, "entry26");
+  GLADE_HOOKUP_OBJECT (label_dialog, hbox46, "hbox46");
+  GLADE_HOOKUP_OBJECT (label_dialog, label109, "label109");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_combo_pool, "label_combo_pool");
+  GLADE_HOOKUP_OBJECT (label_dialog, entry27, "entry27");
+  GLADE_HOOKUP_OBJECT (label_dialog, hbox47, "hbox47");
+  GLADE_HOOKUP_OBJECT (label_dialog, label111, "label111");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_entry_volume, "label_entry_volume");
+  GLADE_HOOKUP_OBJECT (label_dialog, hbox48, "hbox48");
+  GLADE_HOOKUP_OBJECT (label_dialog, slot1, "slot1");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_slot, "label_slot");
+  GLADE_HOOKUP_OBJECT (label_dialog, label113, "label113");
+  GLADE_HOOKUP_OBJECT_NO_REF (label_dialog, dialog_action_area8, "dialog_action_area8");
+  GLADE_HOOKUP_OBJECT (label_dialog, hbuttonbox3, "hbuttonbox3");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_ok, "label_ok");
+  GLADE_HOOKUP_OBJECT (label_dialog, label_cancel, "label_cancel");
+
+  return label_dialog;
+}
+
diff --git a/bacula/src/gnome2-console/interface.h b/bacula/src/gnome2-console/interface.h
new file mode 100644 (file)
index 0000000..f9853e1
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_app1 (void);
+GtkWidget* create_about1 (void);
+GtkWidget* create_SelectDirectorDialog (void);
+GtkWidget* create_RunDialog (void);
+GtkWidget* create_restore_files (void);
+GtkWidget* create_restore_dialog (void);
+GtkWidget* create_label_dialog (void);
diff --git a/bacula/src/gnome2-console/support.c b/bacula/src/gnome2-console/support.c
new file mode 100644 (file)
index 0000000..7f06554
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gnome.h>
+
+#include "support.h"
+
+GtkWidget*
+lookup_widget                          (GtkWidget       *widget,
+                                        const gchar     *widget_name)
+{
+  GtkWidget *parent, *found_widget;
+
+  for (;;)
+    {
+      if (GTK_IS_MENU (widget))
+        parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+      else
+        parent = widget->parent;
+      if (!parent)
+        parent = (GtkWidget *)g_object_get_data (G_OBJECT (widget), "GladeParentKey");
+      if (parent == NULL)
+        break;
+      widget = parent;
+    }
+
+  found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+                                                 widget_name);
+  if (!found_widget)
+    g_warning ("Widget not found: %s", widget_name);
+  return found_widget;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap                          (GtkWidget       *widget,
+                                        const gchar     *filename)
+{
+  GtkWidget *pixmap;
+  gchar *pathname;
+
+  if (!filename || !filename[0])
+      return gtk_image_new ();
+
+  pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
+                                        filename, TRUE, NULL);
+  if (!pathname)
+    {
+      g_warning (_("Couldn't find pixmap file: %s"), filename);
+      return gtk_image_new ();
+    }
+
+  pixmap = gtk_image_new_from_file (pathname);
+  g_free (pathname);
+  return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GdkPixbuf*
+create_pixbuf                          (const gchar     *filename)
+{
+  gchar *pathname = NULL;
+  GdkPixbuf *pixbuf;
+  GError *error = NULL;
+
+  if (!filename || !filename[0])
+      return NULL;
+
+  pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
+                                        filename, TRUE, NULL);
+
+  if (!pathname)
+    {
+      g_warning (_("Couldn't find pixmap file: %s"), filename);
+      return NULL;
+    }
+
+  pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
+  if (!pixbuf)
+    {
+      fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
+               pathname, error->message);
+      g_error_free (error);
+    }
+  g_free (pathname);
+  return pixbuf;
+}
+
+/* This is used to set ATK action descriptions. */
+void
+glade_set_atk_action_description       (AtkAction       *action,
+                                        const gchar     *action_name,
+                                        const gchar     *description)
+{
+  gint n_actions, i;
+
+  n_actions = atk_action_get_n_actions (action);
+  for (i = 0; i < n_actions; i++)
+    {
+      if (!strcmp (atk_action_get_name (action, i), action_name))
+        atk_action_set_description (action, i, description);
+    }
+}
+
diff --git a/bacula/src/gnome2-console/support.h b/bacula/src/gnome2-console/support.h
new file mode 100644 (file)
index 0000000..13d1746
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#include <gnome.h>
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget*  lookup_widget              (GtkWidget       *widget,
+                                        const gchar     *widget_name);
+
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps used in the interface. */
+GtkWidget*  create_pixmap              (GtkWidget       *widget,
+                                        const gchar     *filename);
+
+/* This is used to create the pixbufs used in the interface. */
+GdkPixbuf*  create_pixbuf              (const gchar     *filename);
+
+/* This is used to set ATK action descriptions. */
+void        glade_set_atk_action_description (AtkAction       *action,
+                                              const gchar     *action_name,
+                                              const gchar     *description);
+
diff --git a/bacula/src/gnome2-console/test-gnome-console.conf b/bacula/src/gnome2-console/test-gnome-console.conf
new file mode 100644 (file)
index 0000000..b2725a1
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Bacula User Agent (or Console) Configuration File
+#
+
+Director {
+  Name = rufus-dir
+  DIRport = 8101
+  address = rufus
+  Password = UA_password
+}
index e3e012b61cd80f8747cd63bf3cc9c45fde98b4d6..8a47e2e6c36acbe29f2800004c8a2c1901a5c40b 100644 (file)
 #define L_VERIFY_CATALOG         'C'  /* verify from catalog */
 #define L_VERIFY_INIT            'V'  /* verify save (init DB) */
 #define L_VERIFY_VOLUME_TO_CATALOG 'O'  /* verify Volume to catalog entries */
+#define L_VERIFY_DISK_TO_CATALOG 'd'  /* verify Disk attributes to catalog */
 #define L_VERIFY_DATA            'A'  /* verify data on volume */
 #define L_BASE                   'B'  /* Base level job */
+#define L_NONE                   ' '  /* None, for Restore and Admin */
 
 
 /* Job Types. These are stored in the DB */
@@ -154,7 +156,8 @@ struct JCR {
    POOLMEM *fname;                    /* name to put into catalog */
    int fn_printed;                    /* printed filename */
    POOLMEM *stime;                    /* start time for incremental/differential */
-   JOB_DBR jr;                        /* Job record in Database */
+   JOB_DBR jr;                        /* Job DB record for current job */
+   JOB_DBR *verify_jr;                /* Pointer to target job */
    uint32_t RestoreJobId;             /* Id specified by UA */
    POOLMEM *client_uname;             /* client uname */ 
    int replace;                       /* Replace option */
@@ -250,9 +253,11 @@ struct JCR {
  *  info on the last job run.
  */
 struct s_last_job {
+   dlink link;
    int NumJobs;
    int JobType;
    int JobStatus;
+   int JobLevel;
    uint32_t JobId;
    uint32_t VolSessionId;
    uint32_t VolSessionTime;
@@ -263,7 +268,8 @@ struct s_last_job {
    char Job[MAX_NAME_LENGTH];
 };
 
-extern struct s_last_job last_job;
+extern struct s_last_job last_job;               
+extern dlist *last_jobs;
 
 
 /* The following routines are found in lib/jcr.c */
index 03ab5e3e91e0b160f1bcedc9bf3615836b2e75ca..8b6755405b4c73eb2819a8b0722938f90e7d8619 100644 (file)
@@ -20,6 +20,8 @@
    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
    MA 02111-1307, USA.
 
+   Kern Sibbald, June MMIII
+
  */
 
 /* 
@@ -52,7 +54,7 @@ inline void * alist::operator [](int index) const {
    return items[index];
 }
 
-/*                           
+/*                            
  * This allows us to do explicit initialization,
  *   allowing us to mix C++ classes inside malloc'ed
  *   C structures. Define before called in constructor.
index b2ad6bc774767cf55ca17cde472d68d0bf866cd8..26e0a6c02c15e275c5ceb31dcca0f6ed6b6e9efc 100644 (file)
@@ -33,7 +33,7 @@
 #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)))
+#define bit_is_set(b, var) (((var)[(b)>>3] & (1<<((b)&0x7))) != 0)
 
 /* set bit */
 #define set_bit(b, var) ((var)[(b)>>3] |= (1<<((b)&0x7)))
index 0e04ffa22403280e2eeefc0c0a9d8e2382e053eb..ba0c334212acce505d2068aee7af1c365168ffe9 100644 (file)
@@ -284,7 +284,7 @@ int bnet_despool(BSOCK *bsock)
       bsock->msglen = ntohl(pktsiz);
       if (bsock->msglen > 0) {
         if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
-           bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
+           bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen + 1);
         }
         nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
         if (nbytes != (size_t)bsock->msglen) {
@@ -354,7 +354,6 @@ bnet_send(BSOCK *bsock)
 
    bsock->out_msg_no++;              /* increment message number */
    if (bsock->msglen <= 0) {         /* length only? */
-      ASSERT(msglen == bsock->msglen);
       return 1;                      /* yes, no data */
    }
 
@@ -381,7 +380,6 @@ bnet_send(BSOCK *bsock)
       }
       return 0;
    }
-   ASSERT(msglen == bsock->msglen);
    return 1;
 }
 
@@ -474,6 +472,50 @@ bnet_wait_data_intr(BSOCK *bsock, int sec)
    }
 }
 
+#ifndef NETDB_INTERNAL
+#define NETDB_INTERNAL -1      /* See errno. */
+#endif
+#ifndef NETDB_SUCCESS
+#define NETDB_SUCCESS  0       /* No problem. */
+#endif
+#ifndef HOST_NOT_FOUND
+#define HOST_NOT_FOUND 1       /* Authoritative Answer Host not found. */
+#endif
+#ifndef TRY_AGAIN
+#define TRY_AGAIN      2       /* Non-Authoritative Host not found, or SERVERFAIL. */
+#endif
+#ifndef NO_RECOVERY
+#define NO_RECOVERY    3       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
+#endif
+#ifndef NO_DATA
+#define NO_DATA        4       /* Valid name, no data record of requested type. */
+#endif
+
+extern int h_errno;            /* On error has one of the above */
+
+/*
+ * Get human readable error for gethostbyname()
+ */
+static char *gethost_strerror() 
+{
+   switch (h_errno) {
+   case NETDB_INTERNAL:
+      return strerror(errno);
+   case NETDB_SUCCESS:
+      return "No problem.";
+   case HOST_NOT_FOUND:
+      return "Authoritative answer Host not found.";
+   case TRY_AGAIN:
+      return "Non-authoritative Host not found, or ServerFail.";
+   case NO_RECOVERY:
+      return "Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.";
+   case NO_DATA:
+      return "Valid name, no data record of resquested type.";
+   default:
+      return "Unknown error.";
+   }
+}
+
 
 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -497,7 +539,7 @@ static uint32_t *bget_host_ip(JCR *jcr, char *host)
       P(ip_mutex);
       if ((hp = gethostbyname(host)) == NULL) {
          Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n", 
-              host, strerror(errno));
+              host, gethost_strerror());
         V(ip_mutex);
         return NULL;
       }
@@ -512,7 +554,7 @@ Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
         i++;
       }
       i++;
-      addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 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;
@@ -639,6 +681,9 @@ bnet_fsend(BSOCK *bs, char *fmt, ...)
    va_list arg_ptr;
    int maxlen;
 
+   if (bs->errors || bs->terminated) {
+      return 0;
+   }
    /* 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
@@ -650,10 +695,10 @@ again:
    bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
    va_end(arg_ptr);
    if (bs->msglen < 0 || bs->msglen >= maxlen) {
-      bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
+      bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
       goto again;
    }
-   return bnet_send(bs) < 0 ? 0 : 1;
+   return bnet_send(bs);
 }
 
 /* 
index a44290b75d61912f4c3a35343bbe2ff616cc6624..1501e18d2c41fd4b8333e709ebaaf5591e2c69b7 100644 (file)
@@ -92,6 +92,9 @@ BPIPE *open_bpipe(char *prog, int wait, char *mode)
         dup2(readp[1], 1);           /* dup our read to his stdout */
         dup2(readp[1], 2);           /*   and his stderr */
       }
+      for (int i=3; i<=32; i++) {     /* close any open file descriptors */
+        close(i);
+      }
       execvp(bargv[0], bargv);       /* call the program */
       exit(errno);                    /* shouldn't get here */
 
index 92aa2596c5fad3e5fe090291aa6329fc80ca5cbc..89910344b5af411f8dab1ba66cc1037fa47405c7 100644 (file)
@@ -66,6 +66,7 @@ struct BSOCK {
 #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_BTIME       -9           /* Send UTC btime */
 
 #define BNET_SETBUF_READ  1           /* Arg for bnet_set_buffer_size */
 #define BNET_SETBUF_WRITE 2           /* Arg for bnet_set_buffer_size */
index 8e66a9adf9b04ab4625728f5b6c5431639e24f6e..b421e2e2e01724594624464748c751b552323e2b 100644 (file)
@@ -108,7 +108,7 @@ void *bcalloc (size_t size1, size_t size2)
 /*
  * Implement snprintf
  */
-int bsnprintf(char *str, size_t size, const  char  *fmt,  ...) 
+int bsnprintf(char *str, int32_t size, const  char  *fmt,  ...) 
 {
 #ifdef HAVE_VSNPRINTF
    va_list   arg_ptr;
@@ -143,7 +143,7 @@ int bsnprintf(char *str, size_t size, const  char  *fmt,  ...)
 /*
  * Implement vsnprintf()
  */
-int bvsnprintf(char *str, size_t size, const char  *format, va_list ap)
+int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
 {
 #ifdef HAVE_VSNPRINTF
    int len;
index 10a2ff79251f12ea6eda347fc65c7164774d0aba..825573e2cf37fd853282ad35d90fd61b4927626f 100644 (file)
@@ -31,7 +31,7 @@
  *  it is being phased out. 
  *     
  *  Epoch is the base of Unix time in seconds (time_t, ...) 
- *     and is 1 Jan 1970 at 0:0
+ *     and is 1 Jan 1970 at 0:0 UTC
  *
  *  The major two times that should be left are:
  *     btime_t (64 bit integer in microseconds base Epoch)
@@ -53,6 +53,21 @@ char *bstrftime(char *dt, int maxlen, utime_t tim)
    return dt;
 }
 
+/* Formatted time for user display: dd-Mon-yy hh:mm  (no century) */
+char *bstrftime_nc(char *dt, int maxlen, utime_t tim)
+{
+   time_t ttime = tim;
+   struct tm tm;
+   
+   /* ***FIXME**** the format and localtime_r() should be user configurable */
+   localtime_r(&ttime, &tm);
+   /* NOTE! since the compiler complains about %y, I use %y and cut the century */
+   strftime(dt, maxlen, "%d-%b-%Y %H:%M", &tm);
+   strcpy(dt+7, dt+9);
+   return dt;
+}
+
+
 /* Unix time to standard time string yyyy-mm-dd hh:mm:ss */
 char *bstrutime(char *dt, int maxlen, utime_t tim)
 {
@@ -92,28 +107,10 @@ utime_t str_to_utime(char *str)
    return (utime_t)ttime;
 }
 
-/* Deprecated. Do not use. */
-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
-}
 
 /*
  * Bacula's time (btime_t) is an unsigned 64 bit integer that contains
- *   the number of microseconds since Epoch Time (1 Jan 1970).
+ *   the number of microseconds since Epoch Time (1 Jan 1970) UTC.
  */
 
 btime_t get_current_btime()
@@ -135,9 +132,80 @@ time_t btime_to_unix(btime_t bt)
 /* Convert btime to utime */
 utime_t btime_to_utime(btime_t bt)
 {
-   return (utime_t)bt;
+   return (utime_t)(bt/1000000);
 }
 
+/*
+ * Return the week of the month, base 0 (wpos)
+ *   given tm_mday and tm_wday. Value returned
+ *   can be from 0 to 4 => week1, ... week5
+ */
+int tm_wom(int mday, int wday)
+{
+   int fs;                      /* first sunday */
+   fs = (mday%7) - wday;
+   if (fs <= 0) {
+      fs += 7;
+   }
+   if (mday <= fs) {
+//    Dmsg2(100, "wom=0 wday=%d <= fs=%d\n", wday, fs);
+      return 0;
+   }
+   int wom = 1 + (mday - fs - 1) / 7;
+// Dmsg3(100, "wom=%d wday=%d fs=%d\n", wom, wday, fs);
+   return wom;
+}  
+
+/*
+ * Given a Unix date return the week of the year.
+ * The returned value can be 0-53.  Officially
+ * the weeks are numbered from 1 to 53 where week1
+ * is the week in which the first Thursday of the
+ * year occurs (alternatively, the week which contains
+ * the 4th of January).  We return 0, if the week of the
+ * year does not fall in the current year.
+ */
+int tm_woy(time_t stime)
+{
+   int woy, fty, tm_yday;
+   time_t time4;
+   struct tm tm;
+   memset(&tm, 0, sizeof(struct tm));
+   localtime_r(&stime, &tm);
+   tm_yday = tm.tm_yday;
+   tm.tm_mon = 0;
+   tm.tm_mday = 4;
+   time4 = mktime(&tm);
+   localtime_r(&time4, &tm);
+   fty = 1 - tm.tm_wday;
+   if (fty <= 0) {
+      fty += 7;
+   }
+   woy = tm_yday - fty + 4;
+   if (woy < 0) {
+      return 0;
+   }
+   return 1 + woy / 7;
+}
+
+/* Deprecated. Do not use. */
+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. */
index a35756947e5aceb9891cefe7dafc7e0bb02328fe..9f5b5d1986ca590d6e93c39c104057eeb9299e56 100644 (file)
@@ -3,14 +3,6 @@
 
   See btime.c for defintions.
 
-  The following is deprecated:
-    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
-
      Version $Id$
 
  */
 #define __btime_INCLUDED
 
 /* New btime definition -- use this */
-extern btime_t get_current_btime(void);
-extern time_t btime_to_unix(btime_t bt);   /* bacula time to epoch time */
-extern utime_t btime_to_utime(btime_t bt); /* bacula time to utime_t */
+btime_t get_current_btime(void);
+time_t btime_to_unix(btime_t bt);   /* bacula time to epoch time */
+utime_t btime_to_utime(btime_t bt); /* bacula time to utime_t */
+
+int tm_wom(int mday, int wday);
+int tm_woy(time_t stime);
 
-extern char *bstrftime(char *dt, int maxlen, utime_t tim);
-extern char *bstrutime(char *dt, int maxlen, utime_t tim);
-extern utime_t str_to_utime(char *str);
+char *bstrutime(char *dt, int maxlen, utime_t tim);
+char *bstrftime(char *dt, int maxlen, utime_t tim);
+char *bstrftime_nc(char *dt, int maxlen, utime_t tim);
+utime_t str_to_utime(char *str);
 
 
 /* =========================================================== */
index 948892dc24f9310906c598f66b298d4c8f648839..be1ed8db4c529b3446719b58932b7a502ef53b8a 100644 (file)
@@ -96,6 +96,7 @@ int cram_md5_get_auth(BSOCK *bs, char *password, int ssl_need)
    if (sscanf(mp_chr(bs->msg), "auth cram-md5 %s ssl=%d\n", chal, &ssl_has) != 2) {
       ssl_has = BNET_SSL_NONE;
       if (sscanf(mp_chr(bs->msg), "auth cram-md5 %s\n", chal) != 1) {
+         bnet_fsend(bs, "1999 Authorization failed.\n");
          Dmsg1(100, "Cannot scan challenge: %s\n", bs->msg);
         bmicrosleep(5, 0);
         return 0;
index b5ced0cb795e48cdd239d24a2fbdcdaa4db56120..20dc2fdf52fb733cd95b327cb39dfa22d71824eb 100644 (file)
@@ -41,7 +41,7 @@ daemon_start()
 {
 #ifndef HAVE_CYGWIN
    int i;
-   int cpid;
+   pid_t cpid;
    mode_t oldmask;
    /*
     *  Become a daemon.
@@ -57,17 +57,10 @@ daemon_start()
    setsid();
 
    /* In the PRODUCTION system, we close ALL
-    * file descriptors. It is useful
-    * for debugging to leave the STDOUT ane STDERR open.
+    * file descriptors except stdin, stdout, and stderr.
     */
-   for (i=sysconf(_SC_OPEN_MAX)-1; i >=0; i--) {
-#ifdef DEBUG
-      if (i != STDOUT_FILENO && i != STDERR_FILENO) {
-        close(i);
-      }
-#else 
+   for (i=sysconf(_SC_OPEN_MAX)-1; i > 2; i--) {
       close(i);
-#endif
    }
 
    /* Move to root directory. For debug we stay
index 15307bc3b357c98b47aff71bba1dea525cac0342..03d74717d8c1b2dcd4f8a8200bc33467c643a919 100644 (file)
@@ -48,6 +48,7 @@ void dlist::append(void *item)
    if (head == NULL) {               /* if empty list, */
       head = item;                   /* item is head as well */
    }
+   num_items++;
 }
 
 /*
@@ -64,6 +65,7 @@ void dlist::prepend(void *item)
    if (tail == NULL) {               /* if empty list, */                    
       tail = item;                   /* item is tail too */
    }
+   num_items++;
 }
 
 void dlist::insert_before(void *item, void *where)      
@@ -80,6 +82,7 @@ void dlist::insert_before(void *item, void *where)
    if (head == where) {
       head = item;
    }
+   num_items++;
 }
 
 void dlist::insert_after(void *item, void *where)      
@@ -96,6 +99,7 @@ void dlist::insert_after(void *item, void *where)
    if (tail == where) {
       tail = item;
    }
+   num_items++;
 }
 
 
@@ -122,6 +126,7 @@ void dlist::remove(void *item)
       xitem = ilink->prev;
       ((dlink *)((char *)xitem+loffset))->next = ilink->next;
    }
+   num_items--;
 }
 
 void * dlist::next(void *item)
@@ -141,7 +146,7 @@ void * dlist::prev(void *item)
 }
 
 
-/* Destroy the list and its contents */
+/* Destroy the list contents */
 void dlist::destroy()
 {
    for (void *n=head; n; ) {
@@ -149,6 +154,7 @@ void dlist::destroy()
       free(n);
       n = ni;
    }
+   num_items = 0;
 }
 
 
index 84121b1c2c38a7e517a4e867a663c0ed90b3d5ba..0b4a154789a049cc3553c47558f639f83a628ff7 100644 (file)
@@ -39,6 +39,7 @@ class dlist {
    void *head;
    void *tail;
    int loffset;
+   int num_items;
 public:
    dlist(void *item, void *link);
    void init(void *item, void *link);
@@ -48,6 +49,7 @@ public:
    void insert_after(void *item, void *where);
    void remove(void *item);
    bool empty();
+   int  size();
    void *next(void *item);
    void *prev(void *item);
    void destroy();
@@ -66,6 +68,7 @@ inline void dlist::init(void *item, void *link)
 {
    head = tail = NULL;
    loffset = (char *)link - (char *)item;
+   num_items = 0;
 }
 
 /* Constructor */
@@ -78,6 +81,12 @@ inline bool dlist::empty()
 {
    return head == NULL;
 }
+
+inline int dlist::size()
+{
+   return num_items;
+}
+
    
 inline void * dlist::operator new(size_t)
 {
index ece158bd71805d67639ced3376d50fc40aab4bae..6936b63854bcb2a0e727367be5041f360ba38e1c 100755 (executable)
 
 extern void timeout_handler(int sig);
 
-struct s_last_job last_job;          /* last job run by this daemon */
+struct s_last_job last_job;    /* last job run by this daemon */
+dlist *last_jobs;
+#define MAX_LAST_JOBS 10
 
 static JCR *jobs = NULL;             /* pointer to JCR chain */
+
+/* Mutex for locking various jcr chains while updating */
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
+void init_last_jobs_list()
+{
+   struct s_last_job *job_entry;
+   last_jobs = new dlist(job_entry,  &job_entry->link);
+   memset(&last_job, 0, sizeof(last_job));
+}
+
+void term_last_jobs_list()
+{
+   for (void *je=NULL; (je=last_jobs->next(je)); ) {
+      free(je);                    
+   }
+   delete last_jobs;
+}
+
+void lock_last_jobs_list() 
+{
+   P(mutex);
+}
+
+void unlock_last_jobs_list() 
+{
+   V(mutex);
+}
+
 /*
  * Create a Job Control Record and link it into JCR chain
  * Returns newly allocated JCR
@@ -59,9 +88,9 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
    pthread_mutex_init(&(jcr->mutex), NULL);
    jcr->JobStatus = JS_Created;       /* ready to run */
    jcr->VolumeName = get_pool_memory(PM_FNAME);
-   mp_chr(jcr->VolumeName)[0] = 0;
+   jcr->VolumeName[0] = 0;
    jcr->errmsg = get_pool_memory(PM_MESSAGE);
-   mp_chr(jcr->errmsg)[0] = 0;
+   jcr->errmsg[0] = 0;
    strcpy(jcr->Job, "*Console*");     /* default */
 
    sigtimer.sa_flags = 0;
@@ -111,23 +140,25 @@ 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;
+   case JT_BACKUP:
+   case JT_VERIFY:
+   case JT_RESTORE:
+   case JT_ADMIN:
+      last_job.NumJobs++;
+      last_job.JobType = jcr->JobType;
+      last_job.JobId = jcr->JobId;
+      last_job.VolSessionId = jcr->VolSessionId;
+      last_job.VolSessionTime = jcr->VolSessionTime;
+      bstrncpy(last_job.Job, jcr->Job, sizeof(last_job.Job));
+      last_job.JobFiles = jcr->JobFiles;
+      last_job.JobBytes = jcr->JobBytes;
+      last_job.JobStatus = jcr->JobStatus;
+      last_job.JobLevel = jcr->JobLevel;
+      last_job.start_time = jcr->start_time;
+      last_job.end_time = time(NULL);
+      break;
+   default:
+      break;
    }
    pthread_mutex_destroy(&jcr->mutex);
 
@@ -182,27 +213,39 @@ void b_free_jcr(char *file, int line, JCR *jcr)
 
 void free_jcr(JCR *jcr)
 {
+
    Dmsg1(200, "Enter free_jcr 0x%x\n", jcr);
 
 #endif
+   struct s_last_job *je;
 
    P(mutex);
    jcr->use_count--;                 /* decrement use count */
-   Dmsg2(200, "Dec jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
+   Dmsg3(200, "Dec jcr 0x%x use_count=%d jobid=%d\n", jcr, jcr->use_count, jcr->JobId);
    if (jcr->use_count > 0) {         /* if in use */
       V(mutex);
       Dmsg2(200, "jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
       return;
    }
    remove_jcr(jcr);
-   V(mutex);
 
+   Dmsg1(200, "End job=%d\n", jcr->JobId);
    if (jcr->daemon_free_jcr) {
       jcr->daemon_free_jcr(jcr);      /* call daemon free routine */
    }
+
    free_common_jcr(jcr);
 
-   P(mutex);
+   /* Keep list of last jobs, but not Console where JobId==0 */
+   if (last_job.JobId > 0) {
+      je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
+      memcpy((char *)je, (char *)&last_job, sizeof(last_job));
+      last_jobs->append(je);
+      if (last_jobs->size() > MAX_LAST_JOBS) {
+        last_jobs->remove(last_jobs->first());
+      }
+      last_job.JobId = 0;            /* zap last job */
+   }
    close_msg(NULL);                  /* flush any daemon messages */
    V(mutex);
    Dmsg0(200, "Exit free_jcr\n");
@@ -284,6 +327,9 @@ JCR *get_jcr_by_partial_name(char *Job)
    JCR *jcr;      
    int len;
 
+   if (!Job) {
+      return NULL;
+   }
    P(mutex);
    len = strlen(Job);
    for (jcr = jobs; jcr; jcr=jcr->next) {
@@ -308,6 +354,9 @@ JCR *get_jcr_by_full_name(char *Job)
 {
    JCR *jcr;      
 
+   if (!Job) {
+      return NULL;
+   }
    P(mutex);
    for (jcr = jobs; jcr; jcr=jcr->next) {
       if (strcmp(jcr->Job, Job) == 0) {
index dc7c4723ff7fc8897c6199a84035c89734ffb685..ffc431dade5e24a69bc940f56783649357f7900f 100755 (executable)
@@ -158,12 +158,33 @@ void
 init_msg(JCR *jcr, MSGS *msg)
 {
    DEST *d, *dnew, *temp_chain = NULL;
+   int i, fd;
+
+   if (jcr == NULL && msg == NULL) {
+      init_last_jobs_list();
+   }
+
+   /*
+    * Make sure we have fd's 0, 1, 2 open
+    *  If we don't do this one of our sockets may open
+    *  there and if we then use stdout, it could
+    *  send total garbage to our socket.
+    *
+    */
+   fd = open("/dev/null", O_RDONLY, 0644);
+   if (fd > 2) {
+      close(fd);
+   } else {
+      for(i=1; fd + i <= 2; i++) {
+        dup2(fd, fd+i);
+      }
+   }
+
 
    /*
     * If msg is NULL, initialize global chain for STDOUT and syslog
     */
    if (msg == NULL) {
-      int i;
       daemon_msgs = (MSGS *)malloc(sizeof(MSGS));
       memset(daemon_msgs, 0, sizeof(MSGS));
       for (i=1; i<=M_MAX; i++) {
@@ -534,6 +555,7 @@ void term_msg()
       fclose(trace_fd);
       trace_fd = NULL;
    }
+   term_last_jobs_list();
 }
 
 
@@ -667,11 +689,8 @@ void dispatch_message(JCR *jcr, int type, int level, char *msg)
             case MD_DIRECTOR:
                 Dmsg1(800, "DIRECTOR for following msg: %s", msg);
                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, msg) + 1;
-                  bnet_send(jcr->dir_bsock);
+                   bnet_fsend(jcr->dir_bsock, "Jmsg Job=%s type=%d level=%d %s", 
+                     jcr->Job, type, level, msg);
                }
                break;
             case MD_STDOUT:
@@ -1006,7 +1025,7 @@ again:
    len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
    va_end(arg_ptr);
    if (len < 0 || len >= maxlen) {
-      *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + 200);
+      *pool_buf = realloc_pool_memory(*pool_buf, maxlen + i + maxlen/2);
       goto again;
    }
    return len;
@@ -1027,7 +1046,7 @@ again:
    len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
    va_end(arg_ptr);
    if (len < 0 || len >= maxlen) {
-      *pool_buf = realloc_pool_memory(*pool_buf, maxlen + 200);
+      *pool_buf = realloc_pool_memory(*pool_buf, maxlen + maxlen/2);
       goto again;
    }
    return len;
@@ -1053,7 +1072,7 @@ again:
    len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
    va_end(arg_ptr);
    if (len < 0 || len >= maxlen) {
-      pool_buf = realloc_pool_memory(pool_buf, maxlen + i + 200);
+      pool_buf = realloc_pool_memory(pool_buf, maxlen + i + maxlen/2);
       goto again;
    }
 
index 6b612deb0a711cead969af7704a73fac5ec104af..2c3ac1b43e3c0941b811c02427d695f284453cef 100755 (executable)
@@ -284,7 +284,7 @@ static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd
         str = &lc->str[0];
       }
       for (i=0; msg_types[i].name; i++) {
-        if (strcmp(str, msg_types[i].name) == 0) {
+        if (strcasecmp(str, msg_types[i].name) == 0) {
            msg_type = msg_types[i].token;
            found = TRUE;
            break;
@@ -678,7 +678,8 @@ parse_config(char *cf)
                     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);
+                        scan_err1(lc, "Keyword \"%s\" not permitted in this resource.\n"
+                           "Perhaps you left the trailing brace off of the previous resource.", lc->str);
                        /* NOT REACHED */
                     }
                     break;
index 8f8bbf4218a667620b1211e07030cfd3a977a1b7..c04472e5b1ce3309194e213f8bfe1110446a3c38 100644 (file)
@@ -47,8 +47,8 @@ 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       bsnprintf              (char *str, int32_t size, const  char  *format, ...);
+int       bvsnprintf             (char *str, int32_t size, const char  *format, va_list ap);
 int       pool_sprintf           (char *pool_buf, char *fmt, ...);
 void      create_pid_file        (char *dir, char *progname, int port);
 int       delete_pid_file        (char *dir, char *progname, int port);
@@ -117,6 +117,13 @@ char             *edit_utime             (utime_t val, char *buf);
 int              is_a_number             (const char *num);
 int              is_an_integer           (const char *n);
 
+/* jcr.c (most definitions are in src/jcr.h) */
+void init_last_jobs_list();
+void term_last_jobs_list();
+void lock_last_jobs_list();
+void unlock_last_jobs_list();
+
+
 /* lex.c */
 LEX *     lex_close_file         (LEX *lf);
 LEX *     lex_open_file          (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error);
@@ -162,8 +169,8 @@ void             init_stack_dump          (void);
 /* scan.c */
 void             strip_trailing_junk     (char *str);
 void             strip_trailing_slashes  (char *dir);
-int              skip_spaces             (char **msg);
-int              skip_nonspaces          (char **msg);
+bool             skip_spaces             (char **msg);
+bool             skip_nonspaces          (char **msg);
 int              fstrsch                 (char *a, char *b);
 int              parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, 
                         char **argk, char **argv, int max_args);
index f435502b6cca66434b2d32198fc0f57f951b9888..34c31d2d2b674dec9a571be39c092bd9c863f30a 100644 (file)
@@ -59,17 +59,17 @@ void strip_trailing_slashes(char *dir)
  *          1 on success
  *          new address in passed parameter 
  */
-int skip_spaces(char **msg)
+bool skip_spaces(char **msg)
 {
    char *p = *msg;
    if (!p) {
-      return 0;
+      return false;
    }
-   while (*p && *p == ' ') {
+   while (*p && B_ISSPACE(*p)) {
       p++;
    }
    *msg = p;
-   return *p ? 1 : 0;
+   return *p ? true : false;
 }
 
 /*
@@ -78,18 +78,18 @@ int skip_spaces(char **msg)
  *          1 on success
  *          new address in passed parameter 
  */
-int skip_nonspaces(char **msg)
+bool skip_nonspaces(char **msg)
 {
    char *p = *msg;
 
    if (!p) {
-      return 0;
+      return false;
    }
-   while (*p && *p != ' ') {
+   while (*p && !B_ISSPACE(*p)) {
       p++;
    }
    *msg = p;
-   return *p ? 1 : 0;
+   return *p ? true : false;
 }
 
 /* folded search for string - case insensitive */
index b11e5a50a3ec28aa9622adfccd0cc477e079d40a..f82030702c319a7d969e9472ff5f216c9dd43c60 100644 (file)
@@ -242,7 +242,7 @@ uint64_t unserial_uint64(uint8_t * * const ptr)
 
 /*  unserial_btime  -- Unserialise a btime_t 64 bit integer.  */
 
-uint64_t unserial_btime(uint8_t * * const ptr)
+btime_t unserial_btime(uint8_t * * const ptr)
 {
     btime_t v;
 
index aea28d9453212b1757fbd4dfd33e1d128e829212..4561f4664cad1fb205c74f4768287b1273897d70 100644 (file)
@@ -65,6 +65,7 @@ static void signal_handler(int sig)
    if (already_dead) {
       _exit(1);
    }
+   Dmsg1(200, "sig=%d\n", sig);
    /* Ignore certain signals */
    if (sig == SIGCHLD || sig == SIGUSR2) {
       return;
@@ -138,7 +139,7 @@ static void signal_handler(int sig)
         waitpid(pid, NULL, 0);       /* wait for child to produce dump */
          fprintf(stderr, "Traceback complete, attempting cleanup ...\n");
          Dmsg0(500, "Done waitpid\n");
-        exit_handler(1);             /* clean up if possible */
+        exit_handler(sig);           /* clean up if possible */
          Dmsg0(500, "Done exit_handler\n");
       } else {
          Dmsg0(500, "Doing sleep\n");
@@ -148,7 +149,7 @@ static void signal_handler(int sig)
    }
 #endif
 
-   exit_handler(1);
+   exit_handler(sig);
 }
 
 /*
index 1927f26ba7502483646effe871f2128cae9ee450..ba3242f683ceb687f2ccf041f86c69f4527e4238 100755 (executable)
 #define MAXPATHLEN 1000
 #endif
 
+#undef Dmsg0
+#undef Dmsg1
+#undef Dmsg2
+#undef Dmsg3
+#define Dmsg0(n,f)
+#define Dmsg1(n,f,a1)
+#define Dmsg2(n,f,a1,a2)
+#define Dmsg3(n,f,a1,a2,a3)
+
 /*
  * This subroutine gets a big buffer.
  */
@@ -40,11 +49,13 @@ static void malloc_buf(TREE_ROOT *root, int size)
    struct s_mem *mem;
 
    mem = (struct s_mem *)malloc(size);
+   root->total_size += size;
+   root->blocks++;
    mem->next = root->mem;
    root->mem = mem;
    mem->mem = mem->first;
    mem->rem = (char *)mem + size - mem->mem;
-   Dmsg2(400, "malloc buf size=%d rem=%d\n", size, mem->rem);
+   Dmsg2(200, "malloc buf size=%d rem=%d\n", size, mem->rem);
 }
 
 
@@ -65,9 +76,9 @@ TREE_ROOT *new_tree(int count)
    root = (TREE_ROOT *)malloc(sizeof(TREE_ROOT));
    memset(root, 0, sizeof(TREE_ROOT));
    root->type = TN_ROOT;
-   /* Assume filename = 20 characters average length */
-   size = count * (BALIGN(sizeof(TREE_NODE)) + 20);
-   if (size > 10000000) {
+   /* Assume filename + node  = 40 characters average length */
+   size = count * (BALIGN(sizeof(TREE_NODE)) + 40);
+   if (count > 1000000 || size > 10000000) {
       size = 10000000;
    }
    Dmsg2(400, "count=%d size=%d\n", count, size);
@@ -82,15 +93,20 @@ TREE_ROOT *new_tree(int count)
 TREE_NODE *new_tree_node(TREE_ROOT *root, int type)
 {
    TREE_NODE *node;
-   int size = BALIGN(sizeof(TREE_NODE));
+   int asize = BALIGN(sizeof(TREE_NODE));
 
-   if (root->mem->rem < size) {
-      malloc_buf(root, 20000);
+   if (root->mem->rem < asize) {
+      uint32_t mb_size;
+      if (root->total_size >= 1000000) {
+        mb_size = 1000000;
+      } else {
+        mb_size = 100000;
    }
-
-   root->mem->rem -= size;
+      malloc_buf(root, mb_size);
+   }
+   root->mem->rem -= asize;
    node = (TREE_NODE *)root->mem->mem;
-   root->mem->mem += size;
+   root->mem->mem += asize;
    memset(node, 0, sizeof(TREE_NODE));
    node->type = type;
    return node;
@@ -108,7 +124,13 @@ static char *tree_alloc(TREE_ROOT *root, int size)
    int asize = BALIGN(size);
 
    if (root->mem->rem < asize) {
-      malloc_buf(root, 20000+asize);
+      uint32_t mb_size;
+      if (root->total_size >= 1000000) {
+        mb_size = 1000000;
+      } else {
+        mb_size = 100000;
+      }
+      malloc_buf(root, mb_size);
    }
    root->mem->rem -= asize;
    buf = root->mem->mem;
@@ -130,6 +152,7 @@ void free_tree(TREE_ROOT *root)
    if (root->cached_path) {
       free_pool_memory(root->cached_path);
    }
+   Dmsg2(400, "Total size=%u blocks=%d\n", root->total_size, root->blocks);
    free(root);
    return;
 }
@@ -137,7 +160,8 @@ void free_tree(TREE_ROOT *root)
 
 
 /* 
- * Insert a node in the tree
+ * Insert a node in the tree. This is the main subroutine
+ *   called when building a tree.
  *
  */
 TREE_NODE *insert_tree_node(char *path, TREE_NODE *node, 
@@ -145,14 +169,14 @@ TREE_NODE *insert_tree_node(char *path, TREE_NODE *node,
 {
    TREE_NODE *sibling;
    char *p, *q, *fname;
-   int len = strlen(path);
+   int path_len = strlen(path);
 
    Dmsg1(100, "insert_tree_node: %s\n", path);
    /*
     * If trailing slash, strip it
     */
-   if (len > 0) {
-      q = path + len - 1;
+   if (path_len > 0) {
+      q = path + path_len - 1;
       if (*q == '/') {
         *q = 0;                      /* strip trailing slash */
       } else {
@@ -167,11 +191,12 @@ TREE_NODE *insert_tree_node(char *path, TREE_NODE *node,
       if (!parent) {                 /* if no parent, we need to make one */
         *p = 0;                      /* terminate path */
          Dmsg1(100, "make_tree_path for %s\n", path);
-        if ((int)strlen(path) == root->cached_path_len &&
+        path_len = strlen(path);     /* get new length */
+        if (path_len == root->cached_path_len &&
             strcmp(path, root->cached_path) == 0) {
            parent = root->cached_parent;
         } else {
-           root->cached_path_len = strlen(path);
+           root->cached_path_len = path_len;
            pm_strcpy(&root->cached_path, path);
            parent = make_tree_path(path, root);
            root->cached_parent = parent; 
@@ -188,9 +213,11 @@ TREE_NODE *insert_tree_node(char *path, TREE_NODE *node,
       Dmsg1(100, "No / found: %s\n", path);
    }
 
+   uint16_t fname_len = strlen(fname);
    for (sibling=parent->child; sibling; sibling=sibling->sibling) {
       Dmsg2(100, "sibling->fname=%s fname=%s\n", sibling->fname, fname);
-      if (strcmp(sibling->fname, fname) == 0) {
+      if (sibling->fname_len == fname_len &&
+         strcmp(sibling->fname, fname) == 0) {
          Dmsg1(100, "make_tree_path: found parent=%s\n", parent->fname);
         if (q) {                     /* if trailing slash on entry */
             *q = '/';                 /*  restore it */
@@ -234,9 +261,11 @@ TREE_NODE *make_tree_path(char *path, TREE_ROOT *root)
       type = TN_DIR_NLS;
    }
    /* Is it already a sibling? */
+   uint16_t fname_len = strlen(fname);
    for (sibling=parent->child; sibling; sibling=sibling->sibling) {
       Dmsg2(100, "sibling->fname=%s fname=%s\n", sibling->fname, fname);
-      if (strcmp(sibling->fname, fname) == 0) {
+      if (sibling->fname_len == fname_len &&
+         strcmp(sibling->fname, fname) == 0) {
          Dmsg1(100, "make_tree_path: found parent=%s\n", parent->fname);
         return sibling;
       }
@@ -256,7 +285,8 @@ void append_tree_node(char *fname, TREE_NODE *node, TREE_ROOT *root, TREE_NODE *
    TREE_NODE *child;
 
    Dmsg1(100, "append_tree_node: %s\n", fname);
-   node->fname = tree_alloc(root, strlen(fname) + 1);
+   node->fname_len = strlen(fname);
+   node->fname = tree_alloc(root, node->fname_len + 1);
    strcpy(node->fname, fname);
    node->parent = parent;
    if (!parent->child) {
@@ -280,6 +310,8 @@ item_link:
    return;
 }
 
+#ifdef SLOW_WAY
+/* Moved to tree.h to eliminate subroutine call */
 TREE_NODE *first_tree_node(TREE_ROOT *root)
 {
    return root->first;
@@ -289,6 +321,7 @@ TREE_NODE *next_tree_node(TREE_NODE *node)
 {
    return node->next;
 }
+#endif
 
 
 void print_tree(char *path, TREE_NODE *tree)
@@ -435,6 +468,7 @@ int main(int argc, char *argv[])
     root = new_tree();
     root->fname = tree_alloc(root, 1);
     *root->fname = 0;
+    root->fname_len = 0;
 
     FillDirectoryTree("/home/kern/bacula/k", root, NULL);
 
index 2fd3386b02f61c02e3abca4c412bca8a4d24b03e..e92c567216b24996776dcd5c922427b1b244aa80 100644 (file)
@@ -31,12 +31,17 @@ struct s_mem {
    char first[1];                     /* first byte */
 };
 
+/*
+ * Keep this node as small as possible because
+ *   there is one for each file.
+ */
 struct s_tree_node {
    char *fname;                       /* file name */
    int32_t FileIndex;                 /* file index */
    uint32_t JobId;                    /* JobId */
-   short type;                        /* node type */
-   short extract;                     /* set if extracting */
+   uint16_t fname_len;                /* length of string */
+   uint8_t type;                      /* node type */
+   bool extract;                      /* set if extracting */
    struct s_tree_node *parent;
    struct s_tree_node *sibling;
    struct s_tree_node *child;
@@ -48,8 +53,9 @@ struct s_tree_root {
    char *fname;                       /* file name */
    int32_t FileIndex;                 /* file index */
    uint32_t JobId;                    /* JobId */
-   short type;                        /* node type */
-   short extract;                     /* set if extracting */
+   uint16_t fname_len;                /* length of string */
+   uint8_t type;                      /* node type */
+   bool extract;                      /* set if extracting */
    struct s_tree_node *parent;
    struct s_tree_node *sibling;
    struct s_tree_node *child;
@@ -59,6 +65,8 @@ struct s_tree_root {
    struct s_tree_node *first;         /* first entry in the tree */
    struct s_tree_node *last;          /* last entry in tree */
    struct s_mem *mem;                 /* tree memory */
+   uint32_t total_size;               /* total bytes allocated */
+   uint32_t blocks;                   /* total mallocs */
    int cached_path_len;               /* length of cached path */
    char *cached_path;                 /* cached current path */
    TREE_NODE *cached_parent;          /* cached parent for above path */
@@ -77,11 +85,17 @@ TREE_NODE *new_tree_node(TREE_ROOT *root, int type);
 TREE_NODE *insert_tree_node(char *fname, TREE_NODE *node, 
                             TREE_ROOT *root, TREE_NODE *parent);
 TREE_NODE *make_tree_path(char *path, TREE_ROOT *root);
-TREE_NODE *first_tree_node(TREE_ROOT *root);
-TREE_NODE *next_tree_node(TREE_NODE *node);
 TREE_NODE *tree_cwd(char *path, TREE_ROOT *root, TREE_NODE *node);
 TREE_NODE *tree_relcwd(char *path, TREE_ROOT *root, TREE_NODE *node);
 void append_tree_node(char *path, TREE_NODE *node, TREE_ROOT *root, TREE_NODE *parent);
 void print_tree(char *path, TREE_NODE *root);    
 void free_tree(TREE_ROOT *root);
 int tree_getpath(TREE_NODE *node, char *buf, int buf_size);
+
+#ifdef SLOW_WAY
+TREE_NODE *first_tree_node(TREE_ROOT *root);
+TREE_NODE *next_tree_node(TREE_NODE *node);
+#else
+  #define first_tree_node(r) (r)->first
+  #define next_tree_node(n)  (n)->next
+#endif
index 9c1ce536c37deb4b07bb1ecaa14686ac2ad32f10..8f91db6c67a44a3e369169963c2503ac57d7c123 100644 (file)
 /* Return true of buffer has all zero bytes */
 int is_buf_zero(char *buf, int len)
 {
-   uint64_t *ip = (uint64_t *)buf;
+   uint64_t *ip;
    char *p;
    int i, len64, done, rem;
 
+   if (buf[0] != 0) {
+      return 0;
+   }
+   ip = (uint64_t *)buf;
    /* Optimize by checking uint64_t for zero */
-   len64 = len >> sizeof(uint64_t);
+   len64 = len / sizeof(uint64_t);
    for (i=0; i < len64; i++) {
       if (ip[i] != 0) {
         return 0;
       }
    }
-   done = len64 << sizeof(uint64_t);  /* bytes already checked */
+   done = len64 * sizeof(uint64_t);  /* bytes already checked */
    p = buf + done;
    rem = len - done;
    for (i = 0; i < rem; i++) {
@@ -111,6 +115,7 @@ char *encode_time(time_t time, char *buf)
 
 /*
  * Concatenate a string (str) onto a pool memory buffer pm
+ *   Returns: length of concatenated string
  */
 int pm_strcat(POOLMEM **pm, char *str)
 {
@@ -125,6 +130,7 @@ int pm_strcat(POOLMEM **pm, char *str)
 
 /*
  * Copy a string (str) into a pool memory buffer pm
+ *   Returns: length of string copied
  */
 int pm_strcpy(POOLMEM **pm, char *str)
 {
@@ -141,32 +147,76 @@ int pm_strcpy(POOLMEM **pm, char *str)
  */
 void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
 {
-   char *termstat, jstat[2];
+   char *jobstat;
+   char buf[100];
 
    switch (JobStatus) {
-      case JS_Terminated:
-         termstat = _("OK");
-        break;
-     case JS_FatalError:
-     case JS_ErrorTerminated:
-         termstat = _("Error");
-        break;
-     case JS_Error:
-         termstat = _("Non-fatal error");
-        break;
-     case JS_Canceled:
-         termstat = _("Canceled");
-        break;
-     case JS_Differences:
-         termstat = _("Verify differences");
-        break;
-     default:
-        jstat[0] = last_job.JobStatus;
-        jstat[1] = 0;
-        termstat = jstat;
-        break;
+   case JS_Created:
+      jobstat = _("Created");
+      break;
+   case JS_Running:
+      jobstat = _("Running");
+      break;
+   case JS_Blocked:
+      jobstat = _("Blocked");
+      break;
+   case JS_Terminated:
+      jobstat = _("OK");
+      break;
+   case JS_FatalError:
+   case JS_ErrorTerminated:
+      jobstat = _("Error");
+      break;
+   case JS_Error:
+      jobstat = _("Non-fatal error");
+      break;
+   case JS_Canceled:
+      jobstat = _("Canceled");
+      break;
+   case JS_Differences:
+      jobstat = _("Verify differences");
+      break;
+   case JS_WaitFD:
+      jobstat = _("Waiting on FD");
+      break;
+   case JS_WaitSD:
+      jobstat = _("Wait on SD");
+      break;
+   case JS_WaitMedia:
+      jobstat = _("Wait for new Volume");
+      break;
+   case JS_WaitMount:
+      jobstat = _("Waiting for mount");
+      break;
+   case JS_WaitStoreRes:
+      jobstat = _("Waiting for Storage resource");
+      break;
+   case JS_WaitJobRes:
+      jobstat = _("Waiting for Job resource");
+      break;
+   case JS_WaitClientRes:
+      jobstat = _("Waiting for Client resource");
+      break;
+   case JS_WaitMaxJobs:
+      jobstat = _("Waiting on Max Jobs");
+      break;
+   case JS_WaitStartTime:
+      jobstat = _("Waiting for Start Time");
+      break;
+   case JS_WaitPriority:
+      jobstat = _("Waiting on Priority");
+      break;
+
+   default:
+      if (JobStatus == 0) {
+        buf[0] = 0;
+      } else {
+         bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
+      }
+      jobstat = buf;
+      break;
    }
-   bstrncpy(msg, termstat, maxlen);
+   bstrncpy(msg, jobstat, maxlen);
 }
 
 /*
@@ -259,9 +309,15 @@ char *job_level_to_str(int level)
    case L_VERIFY_VOLUME_TO_CATALOG:
       str = _("Verify Volume to Catalog");
       break;
+   case L_VERIFY_DISK_TO_CATALOG:
+      str = _("Verify Disk to Catalog");
+      break;
    case L_VERIFY_DATA:
       str = _("Verify Data");
       break;
+   case L_NONE:
+      str = " ";
+      break;
    default:
       str = _("Unknown Job Level");
       break;
@@ -430,6 +486,7 @@ void make_session_key(char *key, char *seed, int mode)
  *  %n = Unadorned Job name
  *  %t = Job type (Backup, ...)
  *  %r = Recipients
+ *  %v = Volume name
  *
  *  omsg = edited output message
  *  imsg = input string containing edit codes (%x)
@@ -488,6 +545,13 @@ POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to)
          case 't':
            str = job_type_to_str(jcr->JobType);
            break;
+         case 'v':
+           if (jcr->VolumeName && jcr->VolumeName[0]) {
+              str = jcr->VolumeName;
+           } else {
+               str = "";
+           }
+           break;
         default:
             add[0] = '%';
            add[1] = *p;
index 2b0bcb14004463f3e0b3e4648b00c265b9e39a3a..8022a0ab4ef1ebc22af956e10bc21a8dd98f5e7d 100644 (file)
@@ -2605,21 +2605,13 @@ var_formatv(
     const char *fmt, va_list ap)
 {
     var_rc_t rc;
-    va_list apbak;
     char *cpBuf;
-    int nBuf;
+    int nBuf = 5000;
 
     /* argument sanity checks */
     if (var == NULL || dst_ptr == NULL || fmt == NULL)
        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
 
-    /* determine formatting buffer length */
-    apbak = ap;
-    nBuf = var_mvsnprintf(NULL, 0, fmt, ap);
-    ap = apbak;
-    if (nBuf == -1)
-       return VAR_RC(VAR_ERR_FORMATTING_FAILURE);
-
     /* perform formatting */
     if ((cpBuf = (char *)malloc(nBuf+1)) == NULL)
        return VAR_RC(VAR_ERR_OUT_OF_MEMORY);
index 93ba92cee1114bfa5cc5f836ce72b42974d8306b..14fda2273b566fd3b420e4bbe555b994509f5568 100755 (executable)
@@ -133,6 +133,7 @@ static void *btimer_thread(void *arg)
         if (fd) {
            timer_start = fd->timer_start;
            if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+              fd->timer_start = 0;   /* turn off timer */
               fd->timed_out = TRUE;
               Jmsg(jcr, M_ERROR, 0, _(
 "Watchdog sending kill after %d secs to thread stalled reading Storage daemon.\n"),
@@ -144,6 +145,7 @@ static void *btimer_thread(void *arg)
         if (fd) {
            timer_start = fd->timer_start;
            if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+              fd->timer_start = 0;   /* turn off timer */
               fd->timed_out = TRUE;
               Jmsg(jcr, M_ERROR, 0, _(
 "Watchdog sending kill after %d secs to thread stalled reading File daemon.\n"),
@@ -155,6 +157,7 @@ static void *btimer_thread(void *arg)
         if (fd) {
            timer_start = fd->timer_start;
            if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+              fd->timer_start = 0;   /* turn off timer */
               fd->timed_out = TRUE;
               Jmsg(jcr, M_ERROR, 0, _(
 "Watchdog sending kill after %d secs to thread stalled reading Director.\n"),
index a3104e4eea6a16636c48efe197384edd67ccf186..6f6270578fdc330431456391701940e0467a6cdd 100644 (file)
@@ -18,3 +18,4 @@ startit
 stopit
 changer.out
 mtx-changer
+stored.conf
index 940b0171f2ee86fa8830a101f295f5aa8507f66e..59b335ea360d8cf457c7d1d926a7b06c7ea9f7c7 100644 (file)
@@ -40,30 +40,36 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  */
 int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 {
-   int stat = 0;
-   int tape_previously_mounted;
+   bool vol_ok = false;
+   bool tape_previously_mounted;
+   bool tape_initially_mounted;
    VOL_LIST *vol;
    int autochanger = 0;
    int i;
 
    if (device_is_unmounted(dev)) {
-      Jmsg(jcr, M_WARNING, 0, _("device is BLOCKED due to user unmount.\n"));
+      Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
+        dev_name(dev));
    }
    lock_device(dev);
    block_device(dev, BST_DOING_ACQUIRE);
    unlock_device(dev);
 
-   tape_previously_mounted = (dev->state & ST_READ) || (dev->state & ST_APPEND);
-
-   if (dev->state & ST_READ || dev->num_writers > 0) {
-      Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy. Job canceled.\n"), dev_name(dev));
+   if (dev_state(dev, ST_READ) || dev->num_writers > 0) {
+      Jmsg2(jcr, M_FATAL, 0, _("Device %s is busy. Job %d canceled.\n"), 
+           dev_name(dev), jcr->JobId);
       goto get_out;
    }
 
+   tape_previously_mounted = dev_state(dev, ST_READ) || 
+                            dev_state(dev, ST_APPEND) ||
+                            dev_state(dev, ST_LABEL);
+   tape_initially_mounted = tape_previously_mounted;
+
    /* Find next Volume, if any */
    vol = jcr->VolList;
    if (!vol) {
-      Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job canceled.\n"));
+      Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
       goto get_out;
    }
    jcr->CurVolume++;
@@ -74,7 +80,7 @@ int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 
    for (i=0; i<5; i++) {
       if (job_canceled(jcr)) {
-         Mmsg0(&dev->errmsg, _("Job canceled.\n"));
+         Mmsg1(&dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
         goto get_out;                /* error return */
       }
       /*
@@ -91,11 +97,15 @@ int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
         }
          Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
       }
+      /****FIXME***** do not reread label if ioctl() says we are
+       *  correctly possitioned.  Possibly have way user can turn
+       *  this optimization (to be implemented) off.
+       */
       dev->state &= ~ST_LABEL;          /* force reread of label */
       Dmsg0(200, "calling read-vol-label\n");
       switch (read_dev_volume_label(jcr, dev, block)) {
       case VOL_OK:
-        stat = 1;
+        vol_ok = true;
         break;                    /* got it */
       case VOL_IO_ERROR:
         /*
@@ -107,10 +117,16 @@ int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
         }
         goto default_path;
+      case VOL_NAME_ERROR:
+        if (tape_initially_mounted) {
+           tape_initially_mounted = false;
+           goto default_path;
+        }
+        /* Fall through */
       default:
          Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
 default_path:
-        tape_previously_mounted = 1;
+        tape_previously_mounted = true;
          Dmsg0(200, "dir_get_volume_info\n");
         if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_READ)) { 
             Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
@@ -133,13 +149,14 @@ default_path:
       } /* end switch */
       break;
    } /* end for loop */
-   if (stat == 0) {
+   if (!vol_ok) {
       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device \"%s\".\n"),
            dev_name(dev));
       goto get_out;
    }
 
-   dev->state |= ST_READ;
+   dev->state &= ~ST_APPEND;         /* clear any previous append mode */
+   dev->state |= ST_READ;            /* set reed mode */
    attach_jcr_to_device(dev, jcr);    /* attach jcr to device */
    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
       jcr->VolumeName, dev_name(dev));
@@ -148,7 +165,7 @@ get_out:
    P(dev->mutex); 
    unblock_device(dev);
    V(dev->mutex);
-   return stat;
+   return vol_ok;
 }
 
 /*
@@ -169,7 +186,8 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    DEVICE *rtn_dev = NULL;
 
    if (device_is_unmounted(dev)) {
-      Jmsg(jcr, M_WARNING, 0, _("device is BLOCKED due to user unmount.\n"));
+      Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
+        dev_name(dev));
    }
    lock_device(dev);
    block_device(dev, BST_DOING_ACQUIRE);
@@ -178,7 +196,7 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
             
 
-   if (dev->state & ST_APPEND) {
+   if (dev_state(dev, ST_APPEND)) {
       /* 
        * Device already in append mode  
        *
@@ -198,7 +216,7 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
            for ( ; d; d=d->next) {
               open_vols++;
            }
-           if (dev->state & ST_FILE && dev->max_open_vols > open_vols) {
+           if (dev_state(dev, ST_FILE) && dev->max_open_vols > open_vols) {
               d = init_dev(NULL, (DEVRES *)dev->device); /* init new device */
               d->prev = dev;                   /* chain in new device */
               d->next = dev->next;
@@ -235,7 +253,7 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
        }
    } else { 
       /* Not already in append mode, so mount the device */
-      if (dev->state & ST_READ) {
+      if (dev_state(dev, ST_READ)) {
          Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
         goto get_out;
       } 
@@ -245,8 +263,11 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 
    if (do_mount || recycle) {
       if (!mount_next_write_volume(jcr, dev, block, release)) {
-         Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
-           dev_name(dev));
+        if (!job_canceled(jcr)) {
+            /* Reduce "noise" -- don't print if job canceled */
+            Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
+              dev_name(dev));
+        }
         goto get_out;
       }
    }
@@ -279,7 +300,7 @@ int release_device(JCR *jcr, DEVICE *dev)
 {
    lock_device(dev);
    Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
-   if (dev->state & ST_READ) {
+   if (dev_state(dev, ST_READ)) {
       dev->state &= ~ST_READ;        /* clear read bit */
       if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
         offline_or_rewind_dev(dev);
@@ -290,39 +311,33 @@ int release_device(JCR *jcr, DEVICE *dev)
    } else if (dev->num_writers > 0) {
       dev->num_writers--;
       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
-      if (dev->num_writers == 0) {
-        /* If we are the only writer, write EOF after job */
-        if (dev->state & ST_LABEL) {
-            Dmsg0(100, "dir_create_jobmedia_record. Release\n");
-           dir_create_jobmedia_record(jcr);
-           if (dev_can_write(dev)) {
-              weof_dev(dev, 1);
-           }
-           dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
-           dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
-           /* Note! do volume update before close, which zaps VolCatInfo */
-            Dmsg0(200, "dir_update_vol_info. Release0\n");
-           dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
+      if (dev_state(dev, ST_LABEL)) {
+         Dmsg0(100, "dir_create_jobmedia_record. Release\n");
+        if (!dir_create_jobmedia_record(jcr)) {
+            Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+           jcr->VolCatInfo.VolCatName, jcr->Job);
         }
-
-        if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
-           offline_or_rewind_dev(dev);
-           close_dev(dev);
+        /* If no more writers, write an EOF */
+        if (!dev->num_writers && dev_can_write(dev)) {
+           weof_dev(dev, 1);
         }
-      } else if (dev->state & ST_LABEL) {
-         Dmsg0(100, "dir_create_jobmedia_record. Release\n");
-        dir_create_jobmedia_record(jcr);
-         Dmsg0(200, "dir_update_vol_info. Release1\n");
         dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
         dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
-        dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
+        /* Note! do volume update before close, which zaps VolCatInfo */
+         Dmsg0(100, "dir_update_vol_info. Release0\n");
+        dir_update_volume_info(jcr, dev, 0); /* send Volume info to Director */
+      }
+
+      if (!dev->num_writers && (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN))) {
+        offline_or_rewind_dev(dev);
+        close_dev(dev);
       }
    } else {
-      Jmsg2(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s, Volume %s not in use.\n"), 
+      Jmsg2(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s, Volume \"%s\" not in use.\n"), 
            dev_name(dev), NPRT(jcr->VolumeName));
    }
    detach_jcr_from_device(dev, jcr);
-   if (dev->prev && !(dev->state & ST_READ) && dev->num_writers == 0) {
+   if (dev->prev && !dev_state(dev, ST_READ) && !dev->num_writers) {
       P(mutex);
       unlock_device(dev);
       dev->prev->next = dev->next;    /* dechain */
index e67a8d770e2785c5b32ff015582b240e16d970ec..4b7a0c010c40077a4802a1a0d03efab817a83a9a 100644 (file)
@@ -47,7 +47,7 @@ int do_append_data(JCR *jcr)
    int32_t file_index, stream, last_file_index;
    BSOCK *ds;
    BSOCK *fd_sock = jcr->file_bsock;
-   int ok = TRUE;
+   bool ok = true;
    DEVICE *dev = jcr->device->dev;
    DEV_RECORD rec;
    DEV_BLOCK  *block;
@@ -93,7 +93,7 @@ int do_append_data(JCR *jcr)
       Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
         strerror_dev(dev));
       set_jcr_job_status(jcr, JS_ErrorTerminated);
-      ok = FALSE;
+      ok = false;
    }
 
 
@@ -131,7 +131,7 @@ int do_append_data(JCR *jcr)
         }
          Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
            bnet_strerror(ds));
-        ok = FALSE;
+        ok = false;
         break;
       }
        
@@ -152,7 +152,7 @@ int do_append_data(JCR *jcr)
       }
       if (!B_ISSPACE(*p) || !B_ISDIGIT(*(p+1))) {
          Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg);
-        ok = FALSE;
+        ok = false;
         break;
       }
       stream = (int32_t)str_to_int64(p);
@@ -162,7 +162,7 @@ int do_append_data(JCR *jcr)
       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;
+        ok = false;
         break;
       }
       if (file_index != last_file_index) {
@@ -194,7 +194,7 @@ int do_append_data(JCR *jcr)
                  dev_name(dev), strerror_dev(dev));
                Jmsg(jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
                     strerror_dev(dev));
-              ok = FALSE;
+              ok = false;
               break;
            }
         }
@@ -218,7 +218,7 @@ int do_append_data(JCR *jcr)
               if (!dir_update_file_attributes(jcr, &rec)) {
                   Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
                     bnet_strerror(jcr->dir_bsock));
-                 ok = FALSE;
+                 ok = false;
                  jcr->dir_bsock->spool = 0;
                  break;
               }
@@ -229,15 +229,10 @@ int do_append_data(JCR *jcr)
       if (is_bnet_error(ds)) {
          Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
            bnet_strerror(ds));
-        ok = FALSE;
+        ok = false;
         break;
       }
    }
-   /* 
-    *   We probably need a new flag that says "Do not attempt
-    *   to write because there is no tape".
-    */
-   Dmsg0(90, "Write_end_session_label()\n");
 
    /* Create Job status for end of session label */
    set_jcr_job_status(jcr, ok?JS_Terminated:JS_ErrorTerminated);
@@ -253,22 +248,23 @@ int do_append_data(JCR *jcr)
          Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
             strerror_dev(dev));
         set_jcr_job_status(jcr, JS_ErrorTerminated);
-        ok = FALSE;
+        ok = false;
       }
+      Dmsg0(90, "back from write_end_session_label()\n");
       /* Flush out final partial block of this session */
       if (!write_block_to_device(jcr, dev, block)) {
          Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
         set_jcr_job_status(jcr, JS_ErrorTerminated);
-        ok = FALSE;
+        ok = false;
       }
    }
 
-   Dmsg1(200, "release device JobStatus=%d\n", jcr->JobStatus);
+   Dmsg1(200, "calling release device JobStatus=%d\n", jcr->JobStatus);
    /* Release the device */
    if (!release_device(jcr, dev)) {
       Pmsg0(000, _("Error in release_device\n"));
       set_jcr_job_status(jcr, JS_ErrorTerminated);
-      ok = FALSE;
+      ok = false;
    }
 
    free_block(block);
index 762c138d4d7d026717535d4ea2dbf9174a7b3087..11949fc63944144a6befae2a8d2053bb85dabdc2 100644 (file)
@@ -148,16 +148,25 @@ int dir_find_next_appendable_volume(JCR *jcr)
  * After writing a Volume, send the updated statistics
  * back to the director.
  */
-int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int label)
+int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label)
 {
    BSOCK *dir = jcr->dir_bsock;
    time_t EndTime = time(NULL);
    char ed1[50], ed2[50];
+   VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
 
    if (vol->VolCatName[0] == 0) {
       Jmsg0(jcr, M_ERROR, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
       return 0;
    }
+   if (dev_state(dev, ST_READ)) {
+      Jmsg0(jcr, M_ERROR, 0, _("Attempt to update_volume_info in read mode!!!\n"));
+      return 0;
+   }
+   if (!dev_state(dev, ST_LABEL)) {
+      Jmsg0(jcr, M_ERROR, 0, _("Attempt to update_volume_info on non-labeled Volume!!!\n"));
+      return 0;
+   }
    /* Just labeled or relabeled the tape */
    if (label) {
       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
@@ -286,10 +295,12 @@ int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
         jstat = JS_WaitMount;
         /*
          * If we have a valid volume name and we are not
-         * removable media, return now, otherwise wait
+         * removable media, return now, or if we have a
+         * Slot for an autochanger, otherwise wait
          * for the operator to mount the media.
          */
-        if (jcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && dev_cap(dev, CAP_LABEL)) {
+        if ((jcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && dev_cap(dev, CAP_LABEL)) ||
+            (jcr->VolumeName[0] && jcr->VolCatInfo.Slot)) {
             Dmsg0(190, "Return 1 from mount without wait.\n");
            return 1;
         }
index a6a19870c99d6ffdf73302358d91e91f6a7caa7c..c2178454b8956465cc5c5127de592773ba686e6c 100644 (file)
@@ -128,14 +128,19 @@ int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir)
    return rtn_stat;
 }
 
-void invalidate_slot_in_catalog(JCR *jcr)
+/*
+ * The Volume is not in the correct slot, so mark this 
+ *   Volume as not being in the Changer.
+ */
+void invalid_slot_in_catalog(JCR *jcr, DEVICE *dev)
 {
    Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume \"%s\" not found in slot %d.\n"
 "    Setting slot to zero in catalog.\n"),
        jcr->VolCatInfo.VolCatName, jcr->VolCatInfo.Slot);
-   jcr->VolCatInfo.Slot = 0; /* invalidate slot */
-   Dmsg0(200, "update vol info in mount\n");
-   dir_update_volume_info(jcr, &jcr->VolCatInfo, 1);  /* set slot */
+// jcr->VolCatInfo.InChanger = false;
+// dev->VolCatInfo.InChanger = false;
+   Dmsg0(100, "update vol info in mount\n");
+   dir_update_volume_info(jcr, dev, 1);  /* set new status */
 }
 
 /*
index 3d6b277fced221a50e4d0093a08ee0b9a1a8b21e..3afd8ce65a6aea34200738d73eb34a39d1535497 100644 (file)
@@ -49,6 +49,7 @@ Device {
 #  AutomaticMount = yes;               # when device opened, read it
 #  AlwaysOpen = yes;
 #  RemovableMedia = yes;
+#  RandomAccess = no;
 #}
 
 #
@@ -62,6 +63,7 @@ Device {
 #  AutomaticMount = yes;               # when device opened, read it
 #  AlwaysOpen = Yes;
 #  RemovableMedia = yes;
+#  RandomAccess = no;
 #}
 
 # 
index 36a4a45ce596fa54eeb7745270d7b1638783a44d..9efa2a796503d7b98dee654daa37afe120b821fe 100644 (file)
@@ -57,11 +57,11 @@ static void usage()
 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
 "       -b bootstrap      specify a bootstrap file\n"
 "       -c <file>         specify configuration file\n"
-"       -dnn              set debug level to nn\n"
+"       -d <nn>           set debug level to nn\n"
 "       -v                verbose\n"
 "       -i                specify input Volume names (separated by |)\n"
 "       -o                specify output Volume names (separated by |)\n"
-"       -w dir            specify working directory (default /tmp)\n"
+"       -w <dir>          specify working directory (default /tmp)\n"
 "       -?                print this message\n\n"));
    exit(1);
 }
@@ -254,7 +254,7 @@ static int record_cb(JCR *in_jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec
 /* Dummies to replace askdir.c */
 int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
 int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
index 6f058b4c4a0f7ddeb8bdb660f361a258629635e6..1ac47c0700736eaea88c63f7ab05577f7f723e1f 100644 (file)
@@ -71,13 +71,13 @@ static void usage()
 {
    fprintf(stderr,
 "\nVersion: " VERSION " (" BDATE ")\n\n"
-"Usage: bextract [-d debug_level] <bacula-archive> <directory-to-store-files>\n"
+"Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
 "       -b <file>       specify a bootstrap file\n"
 "       -c <file>       specify a configuration file\n"
-"       -dnn            set debug level to nn\n"
+"       -d <nn>         set debug level to nn\n"
 "       -e <file>       exclude list\n"
 "       -i <file>       include list\n"
-"       -V              specify Volume names (separated by |)\n"
+"       -V <volumes>    specify Volume names (separated by |)\n"
 "       -?              print this message\n\n");
    exit(1);
 }
@@ -435,7 +435,7 @@ static int record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 /* Dummies to replace askdir.c */
 int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
 int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
index bdb2fab3834557dfae9dd5d6d95e6dae2c607d36..c74902de4b519e564ece3fe233cf05400bc132cc 100644 (file)
@@ -131,11 +131,11 @@ DEV_BLOCK *new_block(DEVICE *dev)
  * Only the first block checksum error was reported.
  *   If there are more, report it now.
  */
-void print_block_errors(JCR *jcr, DEV_BLOCK *block)
+void print_block_read_errors(JCR *jcr, DEV_BLOCK *block)
 {
-   if (block->checksum_errors > 1) {
-      Jmsg(jcr, M_ERROR, 0, _("%d block checksum errors ignored.\n"),
-        block->checksum_errors);
+   if (block->read_errors > 1) {
+      Jmsg(jcr, M_ERROR, 0, _("%d block read errors ignored.\n"),
+        block->read_errors);
    }
 }
 
@@ -223,7 +223,10 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) {
          Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
            BLKHDR1_ID, Id);
-        Emsg0(M_ERROR, 0, dev->errmsg);
+        if (block->read_errors == 0 || verbose >= 2) {
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        }
+        block->read_errors++;
         return 0;
       }
    } else if (Id[3] == '2') {
@@ -235,12 +238,18 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) {
          Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
            BLKHDR2_ID, Id);
-        Emsg0(M_ERROR, 0, dev->errmsg);
+        if (block->read_errors == 0 || verbose >= 2) {
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        }
+        block->read_errors++;
         return 0;
       }
    } else {
       Mmsg1(&dev->errmsg, _("Expected block-id BB01 or BB02, got %s. Buffer discarded.\n"), Id);
-      Emsg0(M_ERROR, 0, dev->errmsg);
+      if (block->read_errors == 0 || verbose >= 2) {
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+      }
+      block->read_errors++;
       return 0;
    }
 
@@ -248,7 +257,10 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    if (block_len > MAX_BLOCK_LENGTH) {
       Mmsg1(&dev->errmsg,  _("Block length %u is insane (too large), probably due to a bad archive.\n"),
         block_len);
-      Emsg0(M_ERROR, 0, dev->errmsg);
+      if (block->read_errors == 0 || verbose >= 2) {
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+      }
+      block->read_errors++;
       return 0;
    }
 
@@ -268,14 +280,13 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       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);
          Mmsg3(&dev->errmsg, _("Block checksum mismatch in block %u: calc=%x blk=%x\n"), 
            (unsigned)BlockNumber, BlockCheckSum, CheckSum);
-        if (block->checksum_errors == 0) {
+        if (block->read_errors == 0 || verbose >= 2) {
             Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
         }
-        block->checksum_errors++;
+        block->read_errors++;
+        return 0;
       }
    }
    return 1;
@@ -399,13 +410,22 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"),
            edit_uint64(max_cap, ed1),  dev->dev_name);
       block->write_failed = true;
-      weof_dev(dev, 2);              /* end the tape */
+      if (weof_dev(dev, 1) != 0) {           /* end tape */
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+      }
+      /* Don't do update after second EOF or file count will be wrong */
+      Dmsg0(100, "dir_update_volume_info\n");
+      dev->VolCatInfo.VolCatFiles = dev->file;
+      dir_update_volume_info(jcr, dev, 0);
+      if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* write eof */
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+      }
       dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
       return 0;   
    }
 
    /* Limit maximum File size on volume to user specified value */
-   if (dev->state & ST_TAPE) {
+   if (dev_state(dev, ST_TAPE)) {
       if ((dev->max_file_size > 0) && 
          (dev->file_addr+block->binbuf) >= dev->max_file_size) {
 
@@ -414,10 +434,16 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
             Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
            block->write_failed = true;
            dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
+            Dmsg0(100, "dir_update_volume_info\n");
+           dev->VolCatInfo.VolCatFiles = dev->file;
+           dir_update_volume_info(jcr, dev, 0);
            return 0;   
         }
 
         /* Do bookkeeping to handle EOF just written */
+         Dmsg0(100, "dir_update_volume_info\n");
+        dev->VolCatInfo.VolCatFiles = dev->file;
+        dir_update_volume_info(jcr, dev, 0);
         if (!dir_create_jobmedia_record(jcr)) {
              Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
                  jcr->VolCatInfo.VolCatName, jcr->Job);
@@ -431,7 +457,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
            if (mjcr->JobId == 0) {
               continue;                 /* ignore console */
            }
-           mjcr->NewFile = true;
+           mjcr->NewFile = true;     /* set reminder to do set_new_file_params */
         }
         set_new_file_parameters(jcr, dev);
       }
@@ -460,19 +486,25 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
         if (dev->dev_errno == 0) {
            dev->dev_errno = ENOSPC;        /* out of space */
         }
-         Jmsg(jcr, M_ERROR, 0, _("Write error on device %s. ERR=%s.\n"), 
-           dev->dev_name, strerror(dev->dev_errno));
+         Jmsg(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"), 
+           dev->file, dev->block_num, dev->dev_name, strerror(dev->dev_errno));
       } else {
        dev->dev_errno = ENOSPC;            /* out of space */
-         Jmsg3(jcr, M_INFO, 0, _("End of medium on device %s. Write of %u bytes got %d.\n"), 
-           dev->dev_name, wlen, stat);
+         Jmsg(jcr, M_INFO, 0, _("End of medium at %u:%u on device %s. Write of %u bytes got %d.\n"), 
+           dev->file, dev->block_num, dev->dev_name, wlen, stat);
       }  
 
       Dmsg6(100, "=== Write error. size=%u rtn=%d dev_blk=%d blk_blk=%d errno=%d: ERR=%s\n", 
         wlen, stat, dev->block_num, block->BlockNumber, dev->dev_errno, strerror(dev->dev_errno));
 
       block->write_failed = true;
-      if (weof_dev(dev, 2) != 0) {        /* end the tape */
+      if (weof_dev(dev, 1) != 0) {        /* end the tape */
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+      }
+      Dmsg0(100, "dir_update_volume_info\n");
+      dev->VolCatInfo.VolCatFiles = dev->file;
+      dir_update_volume_info(jcr, dev, 0);
+      if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* end the tape */
          Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
       }
       dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
@@ -482,19 +514,24 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 #ifdef CHECK_LAST_BLOCK
       /* 
        * If the device is a tape and it supports backspace record,
-       *   we backspace over two eof marks and over the last record,
+       *   we backspace over one or two eof marks depending on 
+       *   how many we just wrote, then over the last record,
        *   then re-read it and verify that the block number is
        *   correct.
        */
       if (dev->state & ST_TAPE && dev_cap(dev, CAP_BSR)) {
 
         /* Now back up over what we wrote and read the last block */
-        if (bsf_dev(dev, 1) != 0 || bsf_dev(dev, 1) != 0) {
+        if (!bsf_dev(dev, 1)) {
+           ok = false;
+            Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
+        }
+        if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) {
            ok = false;
             Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
         }
         /* Backspace over record */
-        if (ok && bsr_dev(dev, 1) != 0) {
+        if (ok && !bsr_dev(dev, 1)) {
            ok = false;
             Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
            /*
@@ -539,7 +576,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    block->BlockNumber++;
 
    /* Update jcr values */
-   if (dev->state & ST_TAPE) {
+   if (dev_state(dev, ST_TAPE)) {
       jcr->EndBlock = dev->EndBlock;
       jcr->EndFile  = dev->EndFile;
    } else {
@@ -585,7 +622,7 @@ int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_bloc
    ssize_t stat;
    int looping;
    uint32_t BlockNumber;
-   int retry = 0;
+   int retry;
 
    if (dev_state(dev, ST_EOT)) {
       return 0;
@@ -601,12 +638,14 @@ reread:
       block->read_len = 0;
       return 0;
    }
+   retry = 0;
    do {
       stat = read(dev->fd, block->buf, (size_t)block->buf_len);
       if (retry == 1) {
         dev->VolCatInfo.VolCatErrors++;   
       }
    } while (stat == -1 && (errno == EINTR || errno == EIO) && retry++ < 11);
+// Dmsg1(100, "read stat = %d\n", stat);
    if (stat < 0) {
       Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno));
       clrerror_dev(dev, -1);
@@ -646,7 +685,6 @@ reread:
 
    BlockNumber = block->BlockNumber + 1;
    if (!unser_block_header(jcr, dev, block)) {
-      Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
       block->read_len = 0;
       return 0;
    }
@@ -664,8 +702,8 @@ reread:
       /* Attempt to reposition to re-read the block */
       if (dev->state & ST_TAPE) {
          Dmsg0(100, "Backspace record for reread.\n");
-        if (bsr_dev(dev, 1) != 0) {
-            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        if (!bsr_dev(dev, 1)) {
+            Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev));
            block->read_len = 0;
            return 0;
         }
index 68274579352dd08578ba27978c10c8be441be9d2..1c3c304bb0f140aa0622aeb3d65c4e6812d52ec6 100644 (file)
@@ -96,10 +96,10 @@ struct DEV_BLOCK {
    uint32_t read_len;                 /* bytes read into buffer, if zero, block empty */
    uint32_t VolSessionId;             /* */
    uint32_t VolSessionTime;           /* */
+   uint32_t read_errors;              /* block errors (checksum, header, ...) */
    int      BlockVer;                 /* block version 1 or 2 */
    bool     write_failed;             /* set if write failed */
    bool     block_read;               /* set when block read */
-   int      checksum_errors;          /* count of block checksum errors */
    int32_t  FirstIndex;               /* first index this block */
    int32_t  LastIndex;                /* last index this block */
    char    *bufp;                     /* pointer into buffer */
index 6d26549f71cf091775af918eb8563672eefeb274..350d7b79110f461c3b13eff6368c88fd2e3ffcf4 100644 (file)
@@ -398,7 +398,7 @@ static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sess
 /* Dummies to replace askdir.c */
 int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
 int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
index 897ff9e66464bcb8438d78f28edd2c813765705e..d0d406c7a2582c4d230b636a2e8c854c91dc5344 100644 (file)
@@ -102,17 +102,17 @@ static void usage()
 "Usage: bscan [-d debug_level] <bacula-archive>\n"
 "       -b bootstrap      specify a bootstrap file\n"
 "       -c <file>         specify configuration file\n"
-"       -dnn              set debug level to nn\n"
+"       -d <nn>           set debug level to nn\n"
 "       -m                update media info in database\n"
-"       -n name           specify the database name (default bacula)\n"
-"       -u user           specify database user name (default bacula)\n"
-"       -p password       specify database password (default none)\n"
-"       -h host           specify database host (default NULL)\n"
+"       -n <name>         specify the database name (default bacula)\n"
+"       -u <user>         specify database user name (default bacula)\n"
+"       -p <password      specify database password (default none)\n"
+"       -h <host>         specify database host (default NULL)\n"
 "       -r                list records\n"
 "       -s                synchronize or store in database\n"
 "       -v                verbose\n"
-"       -V                specify Volume names (separated by |)\n"
-"       -w dir            specify working directory (default from conf file)\n"
+"       -V <Volumes>      specify Volume names (separated by |)\n"
+"       -w <dir>          specify working directory (default from conf file)\n"
 "       -?                print this message\n\n"));
    exit(1);
 }
@@ -575,7 +575,7 @@ static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       }
       fr.JobId = mjcr->JobId;
       fr.FileId = 0;
-      if (db_get_file_attributes_record(bjcr, db, attr->fname, &fr)) {
+      if (db_get_file_attributes_record(bjcr, db, attr->fname, NULL, &fr)) {
         if (verbose > 1) {
             Pmsg1(000, _("File record already exists for: %s\n"), attr->fname);
         }
@@ -720,7 +720,8 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
    struct date_time dt;
    struct tm tm;
 
-   bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus));
+   /* We mark Vols as Archive to keep them from being re-written */
+   bstrncpy(mr->VolStatus, "Archive", sizeof(mr->VolStatus));
    mr->VolRetention = 365 * 3600 * 24; /* 1 year */
    if (vl->VerNum >= 11) {
       mr->FirstWritten = btime_to_utime(vl->write_btime);
@@ -1111,7 +1112,7 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
 /* Dummies to replace askdir.c */
 int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
 int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
index 7b2c5642fedf6c3558b903e648f9b367de405462..e7d1426e6be407c1b74bf3a3c69a1022dd90f360 100644 (file)
@@ -46,6 +46,12 @@ char buf[100000];
 int bsize = TAPE_BSIZE;
 char VolName[MAX_NAME_LENGTH];
 
+/*
+ * If you change the format of the state file, 
+ *  increment this value
+ */ 
+static uint32_t btape_state_level = 1;
+
 DEVICE *dev = NULL;
 DEVRES *device = NULL;
 
@@ -70,14 +76,24 @@ static void scan_blocks();
 static void set_volume_name(char *VolName, int volnum);
 static void rawfill_cmd();
 static void bfill_cmd();
+static bool open_the_device();
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
+static void autochangercmd();
+static void do_unfill();
 
 
 /* Static variables */
 #define CONFIG_FILE "bacula-sd.conf"
 char *configfile;
 
+#define MAX_CMD_ARGS 30
+static POOLMEM *cmd;
+static POOLMEM *args;
+static char *argk[MAX_CMD_ARGS];
+static char *argv[MAX_CMD_ARGS];
+static int argc;
+
 static BSR *bsr = NULL;
-static char cmd[1000];
 static int signals = TRUE;
 static int ok;
 static int stop;
@@ -115,10 +131,9 @@ int get_cmd(char *prompt);
  *        Main Bacula Pool Creation Program
  *
  */
-int main(int argc, char *argv[])
+int main(int margc, char *margv[])
 {
    int ch;
-   DEV_BLOCK *block;
 
    /* Sanity checks */
    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
@@ -132,10 +147,10 @@ int main(int argc, char *argv[])
    printf("Tape block granularity is %d bytes.\n", TAPE_BSIZE);
 
    working_directory = "/tmp";
-   my_name_is(argc, argv, "btape");
+   my_name_is(margc, margv, "btape");
    init_msg(NULL, NULL);
 
-   while ((ch = getopt(argc, argv, "b:c:d:sv?")) != -1) {
+   while ((ch = getopt(margc, margv, "b:c:d:sv?")) != -1) {
       switch (ch) {
       case 'b':                    /* bootstrap file */
         bsr = parse_bsr(NULL, optarg);
@@ -171,10 +186,11 @@ int main(int argc, char *argv[])
 
       }  
    }
-   argc -= optind;
-   argv += optind;
-
+   margc -= optind;
+   margv += optind;
 
+   cmd = get_pool_memory(PM_FNAME);
+   args = get_pool_memory(PM_FNAME);
    
    if (signals) {
       init_signals(terminate_btape);
@@ -190,35 +206,25 @@ int main(int argc, char *argv[])
 
 
    /* See if we can open a device */
-   if (argc == 0) {
+   if (margc == 0) {
       Pmsg0(000, "No archive name specified.\n");
       usage();
       exit(1);
-   } else if (argc != 1) {
+   } else if (margc != 1) {
       Pmsg0(000, "Improper number of arguments specified.\n");
       usage();
       exit(1);
    }
 
-   jcr = setup_jcr("btape", argv[0], bsr, NULL);
+   jcr = setup_jcr("btape", margv[0], bsr, NULL);
    dev = setup_to_access_device(jcr, 0);     /* acquire for write */
    if (!dev) {
       exit(1);
    }
-   block = new_block(dev);
-   lock_device(dev);
-   if (!(dev->state & ST_OPENED)) {
-      Dmsg0(129, "Opening device.\n");
-      if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
-         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
-        unlock_device(dev);
-        free_block(block);
-        goto terminate;
-      }
+   dev->max_volume_size = 0;        
+   if (!open_the_device()) {
+      goto terminate;
    }
-   Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
-   unlock_device(dev);
-   free_block(block);
 
    Dmsg0(200, "Do tape commands\n");
    do_tape_cmds();
@@ -236,6 +242,14 @@ static void terminate_btape(int stat)
       free(configfile);
    }
    free_config_resources();
+   if (args) {
+      free_pool_memory(args);
+      args = NULL;
+   }
+   if (cmd) {
+      free_pool_memory(cmd);
+      cmd = NULL;
+   }
 
    if (dev) {
       term_dev(dev);
@@ -265,6 +279,28 @@ static void terminate_btape(int stat)
    exit(stat);
 }
 
+static bool open_the_device()
+{
+   DEV_BLOCK *block;
+   
+   block = new_block(dev);
+   lock_device(dev);
+   if (!(dev->state & ST_OPENED)) {
+      Dmsg1(200, "Opening device %s\n", jcr->VolumeName);
+      if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
+         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
+        unlock_device(dev);
+        free_block(block);
+        return false;
+      }
+   }
+   Dmsg1(000, "open_dev %s OK\n", dev_name(dev));
+   unlock_device(dev);
+   free_block(block);
+   return true;
+}
+
+
 void quitcmd()
 {
    quit = 1;
@@ -275,27 +311,8 @@ void quitcmd()
  */
 static void labelcmd()
 {
-   DEVRES *device;
-   int found = 0;
-
-   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) {
-      Pmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
-      return;
-   }
-
    if (VolumeName) {
-      strcpy(cmd, VolumeName);
+      pm_strcpy(&cmd, VolumeName);
    } else {
       if (!get_cmd("Enter Volume Name: ")) {
         return;
@@ -307,7 +324,7 @@ static void labelcmd()
          Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
       }
    }
-   write_volume_label_to_dev(jcr, device, cmd, "Default");
+   write_volume_label_to_dev(jcr, jcr->device, cmd, "Default");
 }
 
 /*
@@ -395,12 +412,19 @@ static void clearcmd()
 static void weofcmd()
 {
    int stat;
+   int num = 1;
+   if (argc > 1) {
+      num = atoi(argk[1]);
+   }
+   if (num <= 0) {
+      num = 1;
+   }
 
-   if ((stat = weof_dev(dev, 1)) < 0) {
+   if ((stat = weof_dev(dev, num)) < 0) {
       Pmsg2(0, "Bad status from weof %d. ERR=%s\n", stat, strerror_dev(dev));
       return;
    } else {
-      Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
+      Pmsg3(0, "Wrote %d EOF%s to %s\n", num, num==1?"":"s", dev_name(dev));
    }
 }
 
@@ -414,7 +438,7 @@ static void weofcmd()
 static void eomcmd()
 {
    if (!eod_dev(dev)) {
-      Pmsg1(0, _("Bad status from MTEOD. ERR=%s\n"), strerror_dev(dev));
+      Pmsg1(0, "%s", strerror_dev(dev));
       return;
    } else {
       Pmsg0(0, _("Moved to end of medium.\n"));
@@ -435,12 +459,18 @@ static void eodcmd()
  */
 static void bsfcmd()
 {
-   int stat;
+   int num = 1;
+   if (argc > 1) {
+      num = atoi(argk[1]);
+   }
+   if (num <= 0) {
+      num = 1;
+   }
 
-   if ((stat=bsf_dev(dev, 1)) < 0) {
-      Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror(errno));
+   if (!bsf_dev(dev, num)) {
+      Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror_dev(dev));
    } else {
-      Pmsg0(0, _("Backspaced one file.\n"));
+      Pmsg2(0, _("Backspaced %d file%s.\n"), num, num==1?"":"s");
    }
 }
 
@@ -449,12 +479,17 @@ static void bsfcmd()
  */
 static void bsrcmd()
 {
-   int stat;
-
-   if ((stat=bsr_dev(dev, 1)) < 0) {
-      Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), strerror(errno));
+   int num = 1;
+   if (argc > 1) {
+      num = atoi(argk[1]);
+   }
+   if (num <= 0) {
+      num = 1;
+   }
+   if (!bsr_dev(dev, num)) {
+      Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), strerror_dev(dev));
    } else {
-      Pmsg0(0, _("Backspaced one record.\n"));
+      Pmsg2(0, _("Backspaced %d record%s.\n"), num, num==1?"":"s");
    }
 }
 
@@ -464,7 +499,7 @@ static void bsrcmd()
  */
 static void capcmd()
 {
-   printf(_("Device capabilities:\n"));
+   printf(_("Configured device capabilities:\n"));
    printf("%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
    printf("%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
    printf("%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
@@ -568,8 +603,8 @@ static int re_read_block_test()
    }
 
    Pmsg0(-1, _("\n=== Write, backup, and re-read test ===\n\n"
-      "I'm going to write three records and two eof's\n"
-      "then backup over the eof's and re-read the last record.\n"     
+      "I'm going to write three records and an eof\n"
+      "then backup over the eof and re-read the last record.\n"     
       "Bacula does this after writing the last block on the\n"
       "tape to verify that the block was written correctly.\n"
       "It is not an *essential* feature ...\n\n")); 
@@ -612,18 +647,22 @@ static int re_read_block_test()
       Pmsg1(0, _("Wrote third record of %d bytes.\n"), rec->data_len);
    }
    weofcmd();
-   weofcmd();
-   if (bsf_dev(dev, 1) != 0) {
-      Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror(dev->dev_errno));
-      goto bail_out;
+   if (dev_cap(dev, CAP_TWOEOF)) {
+      weofcmd();
    }
-   if (bsf_dev(dev, 1) != 0) {
-      Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror(dev->dev_errno));
+   if (!bsf_dev(dev, 1)) {
+      Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
       goto bail_out;
    }
-   Pmsg0(0, "Backspaced over two EOFs OK.\n");
-   if (bsr_dev(dev, 1) != 0) {
-      Pmsg1(0, _("Backspace record failed! ERR=%s\n"), strerror(dev->dev_errno));
+   if (dev_cap(dev, CAP_TWOEOF)) {
+      if (!bsf_dev(dev, 1)) {
+         Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
+        goto bail_out;
+      }
+   }
+   Pmsg0(0, "Backspaced over EOF OK.\n");
+   if (!bsr_dev(dev, 1)) {
+      Pmsg1(0, _("Backspace record failed! ERR=%s\n"), strerror_dev(dev));
       goto bail_out;
    }
    Pmsg0(0, "Backspace record OK.\n");
@@ -674,6 +713,7 @@ static int append_test()
 "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"));
+   argc = 1;
    rewindcmd();
    wrcmd();
    weofcmd();     /* end file 0 */
@@ -712,6 +752,226 @@ static int append_test()
    return 1;
 }
 
+
+/*
+ * This test exercises the autochanger
+ */
+static int autochanger_test()
+{
+   POOLMEM *results, *changer;
+   int slot, status, loaded;
+   int timeout = 120;
+   int sleep_time = 0;
+
+   if (!dev_cap(dev, CAP_AUTOCHANGER)) {
+      return 1;
+   }
+   if (!(jcr->device && jcr->device->changer_name && jcr->device->changer_command)) {
+      Pmsg0(-1, "\nAutochanger enabled, but no name or no command device specified.\n");
+      return 1;
+   }
+
+   Pmsg0(-1, "\nTo test the autochanger you must have a blank tape in Slot 1.\n"
+             "I'm going to write on it.\n");
+   if (!get_cmd("\nDo you wish to continue with the Autochanger test? (y/n): ")) {
+      return 0;
+   }
+   if (cmd[0] != 'y' && cmd[0] != 'Y') {
+      return 0;
+   }
+
+   Pmsg0(-1, _("\n\n=== Autochanger test ===\n\n"));
+
+   results = get_pool_memory(PM_MESSAGE);
+   changer = get_pool_memory(PM_FNAME);
+
+try_again:
+   slot = 1;
+   jcr->VolCatInfo.Slot = slot;
+   /* Find out what is loaded, zero means device is unloaded */
+   Pmsg0(-1, _("3301 Issuing autochanger \"loaded\" command.\n"));
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
+                "loaded");
+   status = run_program(changer, timeout, results);
+   Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results);
+   if (status == 0) {
+      loaded = atoi(results);
+   } else {
+      Pmsg1(-1, _("3991 Bad autochanger \"load slot\" status=%d.\n"), status);
+      loaded = -1;             /* force unload */
+      goto bail_out;
+   }
+   if (loaded) {
+      Pmsg1(-1, "Slot %d loaded. I am going to unload it.\n", loaded);
+   } else {
+      Pmsg0(-1, "Nothing loaded into the drive. OK.\n");
+   }
+   Dmsg1(100, "Results from loaded query=%s\n", results);
+   if (loaded) {
+      offline_or_rewind_dev(dev);
+      /* We are going to load a new tape, so close the device */
+      force_close_dev(dev);
+      Pmsg0(-1, _("3302 Issuing autochanger \"unload\" command.\n"));
+      changer = edit_device_codes(jcr, changer, 
+                     jcr->device->changer_command, "unload");
+      status = run_program(changer, timeout, NULL);
+      Pmsg2(-1, "unload status=%s %d\n", status==0?"OK":"Bad", status);
+   }
+
+   /*
+    * Load the Slot 1
+    */
+   Pmsg1(-1, _("3303 Issuing autochanger \"load slot %d\" command.\n"), slot);
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "load");
+   Dmsg1(200, "Changer=%s\n", changer);
+   status = run_program(changer, timeout, NULL);
+   if (status == 0) {
+      Pmsg1(-1,  _("3304 Autochanger \"load slot %d\" status is OK.\n"), slot);
+   } else {
+      Pmsg1(-1,  _("3992 Bad autochanger \"load slot\" status=%d.\n"), status);
+      goto bail_out;
+   }
+
+   if (!open_the_device()) {
+      goto bail_out;
+   }
+   bmicrosleep(sleep_time, 0);
+   if (!rewind_dev(dev)) {
+      Pmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      clrerror_dev(dev, -1);
+      Pmsg0(-1, "\nThe test failed, probably because you need to put\n"
+                "a longer sleep time in the mtx-script in the load) case.\n" 
+                "Adding a 30 second sleep and trying again ...\n");
+      sleep_time += 30;
+      goto try_again;
+   } else {
+      Pmsg1(0, "Rewound %s\n", dev_name(dev));
+   }
+      
+   if ((status = weof_dev(dev, 1)) < 0) {
+      Pmsg2(0, "Bad status from weof %d. ERR=%s\n", status, strerror_dev(dev));
+      goto bail_out;
+   } else {
+      Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
+   }
+
+   if (sleep_time) {
+      Pmsg1(-1, "\nThe test worked this time. Please add:\n\n"
+                "   sleep %d\n\n"
+                "to your mtx-changer script in the load) case.\n\n",
+               sleep_time);
+   } else {
+      Pmsg0(-1, "\nThe test autochanger worked!!\n\n");
+   }
+
+   free_pool_memory(changer);
+   free_pool_memory(results);
+   return 1;
+
+
+bail_out:
+   free_pool_memory(changer);
+   free_pool_memory(results);
+   Pmsg0(-1, "You must correct this error or the Autochanger will not work.\n");
+   return -2;
+}
+
+static void autochangercmd()
+{
+   autochanger_test();
+}
+
+
+/*
+ * This test assumes that the append test has been done,
+ *   then it tests the fsf function.
+ */
+static int fsf_test()
+{
+   bool set_off = false;
+   
+   Pmsg0(-1, _("\n\n=== Forward space files test ===\n\n"
+               "This test is essential to Bacula.\n\n"
+               "I'm going to write five files then test forward spacing\n\n"));
+   argc = 1;
+   rewindcmd();
+   wrcmd();
+   weofcmd();     /* end file 0 */
+   wrcmd();
+   wrcmd();
+   weofcmd();     /* end file 1 */
+   wrcmd();
+   wrcmd();
+   wrcmd();
+   weofcmd();    /* end file 2 */
+   wrcmd();
+   wrcmd();
+   weofcmd();    /* end file 3 */
+   wrcmd();
+   weofcmd();    /* end file 4 */
+
+test_again:
+   rewindcmd();
+   Pmsg0(0, _("Now forward spacing 1 file.\n"));
+   if (!fsf_dev(dev, 1)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 1. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 1) {
+      goto bail_out;
+   }
+
+   Pmsg0(0, _("Now forward spacing 2 files.\n"));
+   if (!fsf_dev(dev, 2)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 3. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 3) {
+      goto bail_out;
+   }
+
+   rewindcmd();
+   Pmsg0(0, _("Now forward spacing 4 files.\n"));
+   if (!fsf_dev(dev, 4)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 4. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 4 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 4) {
+      goto bail_out;
+   }
+   if (set_off) {
+      Pmsg0(-1, "The test worked this time. Please add:\n\n"
+                "   Fast Forward Space File = no\n\n"
+                "to your Device resource for this drive.\n");
+   }
+   return 1;
+
+bail_out:
+   Pmsg0(-1, _("\nThe forward space file test failed.\n"));
+   if (dev_cap(dev, CAP_FASTFSF)) {
+      Pmsg0(-1, "You have Fast Forward Space File enabled.\n"
+              "I am turning it off then retring the test.\n");
+      dev->capabilities &= ~CAP_FASTFSF;
+      set_off = true;
+      goto test_again;
+   }
+   Pmsg0(-1, "You must correct this error or Bacula will not work.\n");
+   return -2;
+}
+
+
+
+
+
 /* 
  * This is a general test of Bacula's functions
  *   needed to read and write the tape.
@@ -727,12 +987,16 @@ static void testcmd()
    if (stat == -1) {                 /* first test failed */
       if (dev_cap(dev, CAP_EOM)) {
          Pmsg0(-1, "\nAppend test failed. Attempting again.\n"
-                   "Setting \"Hardware End of Medium = no\" and retrying append test.\n\n");
+                   "Setting \"Hardware End of Medium = no\n"
+                   "    and \"Fast Forward Space File = no\n"
+                   "and retrying append test.\n\n");
         dev->capabilities &= ~CAP_EOM; /* turn off eom */
+        dev->capabilities &= ~CAP_FASTFSF; /* turn off fast fsf */
         stat = append_test();
         if (stat == 1) {
             Pmsg0(-1, "\n\nIt looks like the test worked this time, please add:\n\n"
                      "    Hardware End of Medium = No\n\n"
+                     "    Fast Forward Space File = No\n"
                      "to your Device resource in the Storage conf file.\n");
            goto all_done;
         }
@@ -749,23 +1013,25 @@ static void testcmd()
            if (stat == 1) {
                Pmsg0(-1, "\n\nIt looks like the test worked this time, please add:\n\n"
                      "    Hardware End of Medium = No\n"
+                     "    Fast Forward Space File = No\n"
                      "    BSF at EOM = yes\n\n"
                      "to your Device resource in the Storage conf file.\n");
               goto all_done;
            }
         }
 
-         Pmsg0(-1, "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
-               "Unable to correct the problem. You MUST fix this\n"
-                "problem before Bacula can use your tape drive correctly\n");
-         Pmsg0(-1, "\nPerhaps running Bacula in fixed block mode will work.\n"
-               "Do so by setting:\n\n"
-               "Minimum Block Size = nnn\n"
-               "Maximum Block Size = nnn\n\n"
-               "in your Storage daemon's Device definition.\n"
-               "nnn must match your tape driver's block size.\n"
-               "This, however, is not really an ideal solution.\n");
       }
+      Pmsg0(-1, "\nAppend test failed.\n\n");
+      Pmsg0(-1, "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+            "Unable to correct the problem. You MUST fix this\n"
+             "problem before Bacula can use your tape drive correctly\n");
+      Pmsg0(-1, "\nPerhaps running Bacula in fixed block mode will work.\n"
+            "Do so by setting:\n\n"
+            "Minimum Block Size = nnn\n"
+            "Maximum Block Size = nnn\n\n"
+            "in your Storage daemon's Device definition.\n"
+            "nnn must match your tape driver's block size.\n"
+            "This, however, is not really an ideal solution.\n");
    }
 
 all_done:
@@ -780,7 +1046,7 @@ all_done:
         "End of File mark.\n"
         "1 block of 64448 bytes in file 4\n" 
         "End of File mark.\n"
-        "Total files=4, blocks=7, bytes = 451136\n"
+        "Total files=4, blocks=7, bytes = 451,136\n"
         "=== End sample correct output ===\n\n"));
 
    Pmsg0(-1, _("If the above scan output is not identical to the\n"
@@ -792,6 +1058,10 @@ all_done:
       re_read_block_test();
    }
 
+   fsf_test();                       /* do fast forward space file test */
+
+   autochanger_test();               /* do autochanger test */
+
    Pmsg0(-1, _("\n=== End Append files test ===\n"));
    
 }
@@ -799,21 +1069,35 @@ all_done:
 /* Forward space a file */
 static void fsfcmd()
 {
-   if (!fsf_dev(dev, 1)) {
+   int num = 1;
+   if (argc > 1) {
+      num = atoi(argk[1]);
+   }
+   if (num <= 0) {
+      num = 1;
+   }
+   if (!fsf_dev(dev, num)) {
       Pmsg1(0, "Bad status from fsf. ERR=%s\n", strerror_dev(dev));
       return;
    }
-   Pmsg0(0, "Forward spaced one file.\n");
+   Pmsg2(0, "Forward spaced %d file%s.\n", num, num==1?"":"s");
 }
 
 /* Forward space a record */
 static void fsrcmd()
 {
-   if (!fsr_dev(dev, 1)) {
+   int num = 1;
+   if (argc > 1) {
+      num = atoi(argk[1]);
+   }
+   if (num <= 0) {
+      num = 1;
+   }
+   if (!fsr_dev(dev, num)) {
       Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
       return;
    }
-   Pmsg0(0, "Forward spaced one record.\n");
+   Pmsg2(0, "Forward spaced %d record%s.\n", num, num==1?"":"s");
 }
 
 
@@ -1071,10 +1355,16 @@ static void fillcmd()
    DEV_RECORD rec;
    DEV_BLOCK  *block;
    char ec1[50];
+   int fd;
+   uint32_t i;
+   uint32_t min_block_size;
 
    ok = TRUE;
    stop = 0;
    vol_num = 0;
+   last_file = 0;
+   last_block_num = 0;
+   BlockNumber = 0;
 
    Pmsg0(-1, "\n\
 This command simulates Bacula writing to a tape.\n\
@@ -1110,6 +1400,10 @@ This may take a long time -- hours! ...\n\n");
    
    Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
 
+
+   /* Use fixed block size to simplify read back */
+   min_block_size = dev->min_block_size;
+   dev->min_block_size = dev->max_block_size;
    block = new_block(dev);
 
    /* 
@@ -1142,29 +1436,45 @@ This may take a long time -- hours! ...\n\n");
 #define REC_SIZE 32768
    rec.data_len = REC_SIZE;
 
+   /* 
+    * Put some random data in the record
+    */
+   fd = open("/dev/urandom", O_RDONLY);
+   if (fd) {
+      read(fd, rec.data, rec.data_len);
+      close(fd);
+   } else {
+      uint32_t *p = (uint32_t *)rec.data;
+      srandom(time(NULL));
+      for (i=0; i<rec.data_len/sizeof(uint32_t); i++) {
+        p[i] = random();
+      }
+   }
+
    /* 
     * Generate data as if from File daemon, write to device   
     */
    jcr->VolFirstIndex = 0;
    time(&jcr->run_time);             /* start counting time for rates */
-   Pmsg0(-1, "Begin writing Bacula records to first tape ...\n");
-   Pmsg1(-1, "Block num = %d\n", dev->block_num);
+   if (simple) {
+      Pmsg0(-1, "Begin writing Bacula records to tape ...\n");
+   } else {
+      Pmsg0(-1, "Begin writing Bacula records to first tape ...\n");
+   }
    for (file_index = 0; ok && !job_canceled(jcr); ) {
       rec.VolSessionId = jcr->VolSessionId;
       rec.VolSessionTime = jcr->VolSessionTime;
       rec.FileIndex = ++file_index;
       rec.Stream = STREAM_FILE_DATA;
 
-      /* 
-       * Fill the buffer with the file_index negated. Negation ensures that
-       *   more bits are turned on.
-       */
-      uint64_t *lp = (uint64_t *)rec.data;
-      for (uint32_t i=0; i < (rec.data_len-sizeof(uint64_t))/sizeof(uint64_t); i++) {
-        *lp++ = ~file_index;
+      /* Mix up the data just a bit */
+      uint32_t *lp = (uint32_t *)rec.data;
+      lp[0] += lp[13];
+      for (i=1; i < (rec.data_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) {
+        lp[i] += lp[i-1];
       }
 
-      Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
+      Dmsg4(250, "before write_rec FI=%d SessId=%d Strm=%s len=%d\n",
         rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex), 
         rec.data_len);
        
@@ -1186,11 +1496,11 @@ This may take a long time -- hours! ...\n\n");
            now = time(NULL);
            now -= jcr->run_time;
            if (now <= 0) {
-              now = 1;
+              now = 1;          /* prevent divide error */
            }
            kbs = (double)dev->VolCatInfo.VolCatBytes / (1000.0 * (double)now);
-            Pmsg4(-1, "Wrote block=%u, blk_num=%d VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
-              dev->block_num,
+            Pmsg4(-1, "Wrote blk_block=%u, dev_blk_num=%u VolBytes=%s rate=%.1f KB/s\n", 
+              block->BlockNumber, dev->block_num,
               edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
         }
         /* Every 15000 blocks (approx 1GB) write an EOF.
@@ -1238,7 +1548,21 @@ This may take a long time -- hours! ...\n\n");
          Pmsg0(-1, _("Set ok=FALSE after write_block_to_device.\n"));
         ok = FALSE;
       }
-      Pmsg0(-1, "Wrote End Of Session label.\n");
+      Pmsg0(-1, _("Wrote End Of Session label.\n"));
+   }
+
+   sprintf(buf, "%s/btape.state", working_directory);
+   fd = open(buf, O_CREAT|O_TRUNC|O_WRONLY, 0640);
+   if (fd >= 0) {
+      write(fd, &btape_state_level, sizeof(btape_state_level));
+      write(fd, &last_block_num, sizeof(last_block_num));
+      write(fd, &last_file, sizeof(last_file));
+      write(fd, last_block->buf, last_block->buf_len);
+      close(fd);
+      Pmsg0(-1, "Wrote state file.\n");
+   } else {
+      Pmsg2(-1, _("Could not create state file: %s ERR=%s\n"), buf,
+                strerror(errno));
    }
 
    /* Release the device */
@@ -1247,14 +1571,55 @@ This may take a long time -- hours! ...\n\n");
       ok = FALSE;
    }
 
-   free_block(block);
-   free_memory(rec.data);
-
-   dump_block(last_block, _("Last block written to tape.\n"));
+   if (verbose) {
+      Pmsg0(-1, "\n");
+      dump_block(last_block, _("Last block written to tape.\n"));
+   }
 
    Pmsg0(-1, _("\n\nDone filling tape. Now beginning re-read of tape ...\n"));
 
-   unfillcmd();
+   if (simple) {
+      do_unfill();
+    } else {
+       /* Multiple Volume tape */
+      dumped = 0;
+      VolBytes = 0;
+      LastBlock = 0;
+      block = new_block(dev);
+
+      dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */
+      dev->capabilities &= ~CAP_LABEL;   /* don't label anything here */
+
+      end_of_tape = 0;
+
+
+      time(&jcr->run_time);             /* start counting time for rates */
+      stop = 0;
+      file_index = 0;
+      /* Close device so user can use autochanger if desired */
+      if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
+        offline_dev(dev);
+      }
+      force_close_dev(dev);
+      get_cmd(_("Mount first tape. Press enter when ready: ")); 
+   
+      free_vol_list(jcr);
+      set_volume_name("TestVolume1", 1);
+      jcr->bsr = NULL;
+      create_vol_list(jcr);
+      close_dev(dev);
+      dev->state &= ~ST_READ;
+      if (!acquire_device_for_read(jcr, dev, block)) {
+         Pmsg1(-1, "%s", dev->errmsg);
+        goto bail_out;
+      }
+      /* Read all records and then second tape */
+      read_records(jcr, dev, record_cb, my_mount_next_read_volume);
+   }
+bail_out:
+   dev->min_block_size = min_block_size;
+   free_block(block);
+   free_memory(rec.data);
 }
 
 /*
@@ -1264,6 +1629,36 @@ This may take a long time -- hours! ...\n\n");
  *  verify that it is correct.
  */
 static void unfillcmd()
+{
+   int fd;
+
+   if (!last_block) {
+      last_block = new_block(dev);
+   }
+   sprintf(buf, "%s/btape.state", working_directory);
+   fd = open(buf, O_RDONLY);
+   if (fd >= 0) {
+      uint32_t state_level;             
+      read(fd, &state_level, sizeof(btape_state_level));
+      read(fd, &last_block_num, sizeof(last_block_num));
+      read(fd, &last_file, sizeof(last_file));
+      read(fd, last_block->buf, last_block->buf_len);
+      close(fd);
+      if (state_level != btape_state_level) {
+          Pmsg0(-1, "\nThe state file level has changed. You must redo\n"
+                  "the fill command.\n");
+         return;
+       }
+   } else {
+      Pmsg2(-1, "\nCould not find the state file: %s ERR=%s\n"
+             "You must redo the fill command.\n", buf, strerror(errno));
+      return;
+   }
+   
+   do_unfill();
+}
+
+static void do_unfill()
 {
    DEV_BLOCK *block;
 
@@ -1277,75 +1672,61 @@ static void unfillcmd()
 
    end_of_tape = 0;
 
-   if (!simple) {
-      /* Close device so user can use autochanger if desired */
-      if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
-        offline_dev(dev);
-      }
-      force_close_dev(dev);
-      get_cmd(_("Mount first tape. Press enter when ready: ")); 
-   
-      free_vol_list(jcr);
-      set_volume_name("TestVolume1", 1);
-      jcr->bsr = NULL;
-      create_vol_list(jcr);
-      close_dev(dev);
-      dev->state &= ~ST_READ;
-      if (!acquire_device_for_read(jcr, dev, block)) {
-         Pmsg1(-1, "%s", dev->errmsg);
-        return;
-      }
-   }
 
    time(&jcr->run_time);             /* start counting time for rates */
    stop = 0;
    file_index = 0;
-   if (!simple) {
-      /* Read all records and then second tape */
-      read_records(jcr, dev, record_cb, my_mount_next_read_volume);
-   } else {
-      /*
-       * Simplified test, we simply fsf to file, then read the
-       * last block and make sure it is the same as the saved block.
-       */
-      Pmsg0(000, "Rewinding tape ...\n");
-      if (!rewind_dev(dev)) {
-         Pmsg1(-1, _("Error rewinding: ERR=%s\n"), strerror_dev(dev));
-        goto bail_out;
-      }
-      if (last_file > 0) {
-         Pmsg1(000, "Forward spacing to last file=%u\n", last_file);
-        if (!fsf_dev(dev, last_file)) {
-            Pmsg1(-1, _("Error in FSF: ERR=%s\n"), strerror_dev(dev));
-           goto bail_out;
-        }
-      }
-      Pmsg1(-1, _("Forward space to file %u complete. Reading blocks ...\n"), 
-           last_file);
-      Pmsg1(-1, _("Now reading to block %u.\n"), last_block_num);
-      for (uint32_t i=0; i <= last_block_num; i++) {
-        if (!read_block_from_device(jcr, dev, block, NO_BLOCK_NUMBER_CHECK)) {
-            Pmsg1(-1, _("Error reading blocks: ERR=%s\n"), strerror_dev(dev));
-            Pmsg2(-1, _("Wanted block %u error at block %u\n"), last_block_num, i);
-           goto bail_out;
-        }
-        if (i > 0 && i % 1000 == 0) {
-            Pmsg1(-1, _("At block %u\n"), i);
+
+   /*
+    * Note, re-reading last block may have caused us to 
+    *  lose track of where we are (block number unknown).
+    */
+   rewind_dev(dev);                  /* get to a known place on tape */
+   Pmsg4(-1, _("Reposition from %u:%u to %u:%u\n"), dev->file, dev->block_num,
+        last_file, last_block_num);
+   if (!reposition_dev(dev, last_file, last_block_num)) {
+      Pmsg1(-1, "Reposition error. ERR=%s\n", strerror_dev(dev));
+   }
+   Pmsg1(-1, _("Reading block %u.\n"), last_block_num);
+   if (!read_block_from_device(jcr, dev, block, NO_BLOCK_NUMBER_CHECK)) {
+      Pmsg1(-1, _("Error reading block: ERR=%s\n"), strerror_dev(dev));
+      goto bail_out;
+   }
+   if (last_block) {
+      char *p, *q;
+      uint32_t CheckSum, block_len;
+      ser_declare;
+      p = last_block->buf;     
+      q = block->buf;
+      unser_begin(q, BLKHDR2_LENGTH);
+      unser_uint32(CheckSum);
+      unser_uint32(block_len);
+      while (q < (block->buf+block_len)) {
+        if (*p == *q) {
+           p++;
+           q++;
+           continue;
         }
+         Pmsg0(-1, "\n");
+         dump_block(last_block, _("Last block written"));
+         Pmsg0(-1, "\n");
+         dump_block(block, _("Block read back"));
+         Pmsg1(-1, "\n\nThe blocks differ at byte %u\n", p - last_block->buf);
+         Pmsg0(-1, "\n\n!!!! The last block written and the block\n"
+                   "that was read back differ. The test FAILED !!!!\n"
+                   "This must be corrected before you use Bacula\n"
+                   "to write multi-tape Volumes.!!!!\n");
+        goto bail_out;
       }
-      if (last_block) {
+      Pmsg0(-1, _("\nThe blocks are identical. Test succeeded.\n\n"));
+      if (verbose) {
          dump_block(last_block, _("Last block written"));
          dump_block(block, _("Block read back"));
-         Pmsg0(-1, _("Except for the buffer address, the contents of\n"
-                     "the above two block dumps should be the same.\n"
-                     "If not you have a problem ...\n"));
       }
    }
 
 bail_out:
    free_block(block);
-
-   Pmsg0(000, _("Done with reread of fill data.\n"));
 }
 
 /* 
@@ -1357,7 +1738,9 @@ static int record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 
    if (stop > 1 && !dumped) {        /* on second tape */
       dumped = 1;
-      dump_block(block, "First block on second tape");
+      if (verbose) {
+         dump_block(block, "First block on second tape");
+      }
       Pmsg4(-1, "Blk: FileIndex=%d: block=%u size=%d vol=%s\n", 
           rec->FileIndex, block->BlockNumber, block->block_len, dev->VolHdr.VolName);
       Pmsg6(-1, "   Rec: VId=%d VT=%d FI=%s Strm=%s len=%d state=%x\n",
@@ -1474,16 +1857,17 @@ static int flush_block(DEV_BLOCK *block, int dump)
    free_memory(this_block->buf);    
    memcpy(this_block, block, sizeof(DEV_BLOCK));
    this_block->buf = get_memory(block->buf_len);
-   memcpy(this_block->buf, block->buf, this_block->buf_len);
    this_file = dev->file;
    this_block_num = dev->block_num;
    if (!write_block_to_dev(jcr, dev, block)) {
-      Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", 
-        (unsigned)file_index, block->BlockNumber, block->block_len);
-      Pmsg2(000, "last_block_num=%u this_block_num=%d\n", last_block_num,
-        this_block_num);
-      if (dump) {
-         dump_block(block, "Block not written");
+      Pmsg3(000, "Last block at: %u:%u this_dev_block_num=%d\n", 
+                 last_file, last_block_num, this_block_num);
+      if (verbose) {
+         Pmsg3(000, "Block not written: FileIndex=%u blk_block=%u Size=%u\n", 
+           (unsigned)file_index, block->BlockNumber, block->block_len);
+        if (dump) {
+            dump_block(block, "Block not written");
+        }
       }
       if (stop == 0) {
         eot_block = block->BlockNumber;
@@ -1493,7 +1877,7 @@ static int flush_block(DEV_BLOCK *block, int dump)
       now = time(NULL);
       now -= jcr->run_time;
       if (now <= 0) {
-        now = 1;
+         now = 1;                     /* don't divide by zero */
       }
       kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
       vol_size = dev->VolCatInfo.VolCatBytes;
@@ -1516,6 +1900,8 @@ static int flush_block(DEV_BLOCK *block, int dump)
       unlock_device(dev);
       return 1;                      /* end of tape reached */
    }
+   /* Save contents after write so that the header is serialized */
+   memcpy(this_block->buf, block->buf, this_block->buf_len);
 
    /*
     * Toggle between two allocated blocks for efficiency.
@@ -1579,7 +1965,9 @@ static void qfillcmd()
    }
    printf("\n");
    weofcmd();
-   weofcmd();
+   if (dev_cap(dev, CAP_TWOEOF)) {
+      weofcmd();
+   }
    rewindcmd();
    scan_blocks();
 
@@ -1602,15 +1990,19 @@ static void rawfill_cmd()
    uint32_t block_num = 0;
    uint32_t *p;
    int my_errno;
+   uint32_t i;
 
    block = new_block(dev);
    fd = open("/dev/urandom", O_RDONLY);
    if (fd) {
       read(fd, block->buf, block->buf_len);
+      close(fd);
    } else {
-      Pmsg0(0, "Cannot open /dev/urandom.\n");
-      free_block(block);
-      return;
+      uint32_t *p = (uint32_t *)block->buf;
+      srandom(time(NULL));
+      for (i=0; i<block->buf_len/sizeof(uint32_t); i++) {
+        p[i] = random();
+      }
    }
    p = (uint32_t *)block->buf;
    Pmsg1(0, "Begin writing raw blocks of %u bytes.\n", block->buf_len);
@@ -1622,6 +2014,10 @@ static void rawfill_cmd()
             printf("+");
            fflush(stdout);
         }
+        p[0] += p[13];
+        for (i=1; i<(block->buf_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) {
+           p[i] += p[i-1];
+        }
         continue;
       }
       break;
@@ -1644,16 +2040,20 @@ static void bfill_cmd()
    uint32_t block_num = 0;
    uint32_t *p;
    int my_errno;
-   int fd;
+   int fd;   
+   uint32_t i;
 
    block = new_block(dev);
    fd = open("/dev/urandom", O_RDONLY);
    if (fd) {
       read(fd, block->buf, block->buf_len);
+      close(fd);
    } else {
-      Pmsg0(0, "Cannot open /dev/urandom.\n");
-      free_block(block);
-      return;
+      uint32_t *p = (uint32_t *)block->buf;
+      srandom(time(NULL));
+      for (i=0; i<block->buf_len/sizeof(uint32_t); i++) {
+        p[i] = random();
+      }
    }
    p = (uint32_t *)block->buf;
    Pmsg1(0, "Begin writing Bacula blocks of %u bytes.\n", block->buf_len);
@@ -1668,6 +2068,10 @@ static void bfill_cmd()
          printf("+");
         fflush(stdout);
       }
+      p[0] += p[13];
+      for (i=1; i<(block->buf_len/sizeof(uint32_t)-1); i++) {
+        p[i] += p[i-1];
+      }
    }
    my_errno = errno;
    printf("\n");
@@ -1679,6 +2083,7 @@ static void bfill_cmd()
 
 struct cmdstruct { char *key; void (*func)(); char *help; }; 
 static struct cmdstruct commands[] = {
+ {"autochanger", autochangercmd, "test autochanger"},
  {"bsf",        bsfcmd,       "backspace file"},
  {"bsr",        bsrcmd,       "backspace record"},
  {"bfill",      bfill_cmd,    "fill tape using Bacula writes"},
@@ -1713,15 +2118,16 @@ static void
 do_tape_cmds()
 {
    unsigned int i;
-   int found;
+   bool found;
 
    while (get_cmd("*")) {
       sm_check(__FILE__, __LINE__, False);
-      found = 0;
+      found = false;
+      parse_args(cmd, &args, &argc, argk, argv, MAX_CMD_ARGS);
       for (i=0; i<comsize; i++)       /* search for command */
-        if (fstrsch(cmd,  commands[i].key)) {
+        if (argc > 0 && fstrsch(argk[0],  commands[i].key)) {
            (*commands[i].func)();    /* go execute command */
-           found = 1;
+           found = true;
            break;
         }
       if (!found)
@@ -1735,6 +2141,7 @@ static void helpcmd()
 {
    unsigned int i;
    usage();
+   printf(_("Interactive commands:\n"));
    printf(_("  Command    Description\n  =======    ===========\n"));
    for (i=0; i<comsize; i++)
       printf("  %-10s %s\n", commands[i].key, commands[i].help);
@@ -1745,9 +2152,9 @@ static void usage()
 {
    fprintf(stderr, _(
 "\nVersion: " VERSION " (" BDATE ")\n\n"
-"Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
+"Usage: btape <options> <device_name>\n"
 "       -c <file>   set configuration file to file\n"
-"       -dnn        set debug level to nn\n"
+"       -d <nn>     set debug level to nn\n"
 "       -s          turn off signals\n"
 "       -t          open the default tape device\n"
 "       -?          print this message.\n"  
@@ -1790,7 +2197,7 @@ get_cmd(char *prompt)
 
 /* Dummies to replace askdir.c */
 int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
 int    dir_send_job_status(JCR *jcr) {return 1;}
@@ -1878,3 +2285,81 @@ static void set_volume_name(char *VolName, int volnum)
    pm_strcpy(&jcr->VolumeName, VolName);
    bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
 }
+
+/*
+ * Edit codes into ChangerCommand
+ *  %% = %
+ *  %a = archive device name
+ *  %c = changer device name
+ *  %f = Client's name
+ *  %j = Job name
+ *  %o = command
+ *  %s = Slot base 0
+ *  %S = Slot base 1
+ *  %v = Volume name
+ *
+ *
+ *  omsg = edited output message
+ *  imsg = input string containing edit codes (%x)
+ *  cmd = command string (load, unload, ...) 
+ *
+ */
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
+{
+   char *p;
+   const char *str;
+   char add[20];
+
+   *omsg = 0;
+   Dmsg1(400, "edit_device_codes: %s\n", imsg);
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+        switch (*++p) {
+         case '%':
+            str = "%";
+           break;
+         case 'a':
+           str = dev_name(jcr->device->dev);
+           break;
+         case 'c':
+           str = NPRT(jcr->device->changer_name);
+           break;
+         case 'o':
+           str = NPRT(cmd);
+           break;
+         case 's':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
+           str = add;
+           break;
+         case 'S':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot);
+           str = add;
+           break;
+         case 'j':                    /* Job name */
+           str = jcr->Job;
+           break;
+         case 'v':
+           str = NPRT(jcr->VolumeName);
+           break;
+         case 'f':
+           str = NPRT(jcr->client_name);
+           break;
+
+        default:
+            add[0] = '%';
+           add[1] = *p;
+           add[2] = 0;
+           str = add;
+           break;
+        }
+      } else {
+        add[0] = *p;
+        add[1] = 0;
+        str = add;
+      }
+      Dmsg1(400, "add_str %s\n", str);
+      pm_strcat(&omsg, (char *)str);
+      Dmsg1(400, "omsg=%s\n", omsg);
+   }
+   return omsg;
+}
index a23bb1646f796a553174a76754907bc6707772fb..6a1446582b6b31d99959858710861edbc4b6d25e 100644 (file)
@@ -86,7 +86,7 @@ DEVICE *setup_to_access_device(JCR *jcr, int read_access)
          while (p >= jcr->dev_name && *p != '/')
            p--;
          if (*p == '/') {
-           strcpy(jcr->VolumeName, p+1);
+           pm_strcpy(&jcr->VolumeName, p+1);
            *p = 0;
         }
       }
@@ -97,8 +97,10 @@ DEVICE *setup_to_access_device(JCR *jcr, int read_access)
           jcr->dev_name, configfile);
       return NULL;
    }
+   jcr->device = device;
    
    dev = init_dev(NULL, device);
+   jcr->device->dev = dev;
    if (!dev || !open_device(dev)) {
       Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), jcr->dev_name);
       return NULL;
@@ -209,14 +211,14 @@ JCR *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName)
    jcr->pool_type = get_pool_memory(PM_FNAME);
    strcpy(jcr->pool_type, "Backup");
    jcr->job_name = get_pool_memory(PM_FNAME);
-   strcpy(jcr->job_name, "Dummy.Job.Name");
+   pm_strcpy(&jcr->job_name, "Dummy.Job.Name");
    jcr->client_name = get_pool_memory(PM_FNAME);
-   strcpy(jcr->client_name, "Dummy.Client.Name");
-   strcpy(jcr->Job, name);
+   pm_strcpy(&jcr->client_name, "Dummy.Client.Name");
+   bstrncpy(jcr->Job, name, sizeof(jcr->Job));
    jcr->fileset_name = get_pool_memory(PM_FNAME);
-   strcpy(jcr->fileset_name, "Dummy.fileset.name");
+   pm_strcpy(&jcr->fileset_name, "Dummy.fileset.name");
    jcr->fileset_md5 = get_pool_memory(PM_FNAME);
-   strcpy(jcr->fileset_md5, "Dummy.fileset.md5");
+   pm_strcpy(&jcr->fileset_md5, "Dummy.fileset.md5");
    jcr->JobId = 1;
    jcr->JobType = JT_BACKUP;
    jcr->JobLevel = L_FULL;
index dfde94eba213e7665237b828628ee44912383371..121b989468a990247ac64d34bb1cf4a3acf29443 100644 (file)
@@ -325,7 +325,7 @@ open_dev(DEVICE *dev, char *VolName, int mode)
 #undef rewind_dev
 int _rewind_dev(char *file, int line, DEVICE *dev)
 {
-   Dmsg2(000, "rewind_dev called from %s:%d\n", file, line);
+   Dmsg2(100, "rewind_dev called from %s:%d\n", file, line);
    return rewind_dev(dev);
 }
 #endif
@@ -412,12 +412,15 @@ eod_dev(DEVICE *dev)
    }
    if (!(dev->state & ST_TAPE)) {
       pos = lseek(dev->fd, (off_t)0, SEEK_END);
-//    Dmsg1(000, "====== Seek to %lld\n", pos);
+//    Dmsg1(100, "====== Seek to %lld\n", pos);
       if (pos >= 0) {
         update_pos_dev(dev);
         dev->state |= ST_EOT;
         return 1;
       }
+      dev->dev_errno = errno;
+      Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
+            dev->dev_name, strerror(dev->dev_errno));
       return 0;
    }
 #ifdef MTEOM
@@ -465,7 +468,7 @@ eod_dev(DEVICE *dev)
     * the second EOF.
     */
    if (dev_cap(dev, CAP_BSFATEOM)) {
-      stat =  (bsf_dev(dev, 1) == 0);
+      stat =  bsf_dev(dev, 1);
       dev->file++;                   /* keep same file */
    } else {
       update_pos_dev(dev);                  /* update position */
@@ -700,6 +703,7 @@ int offline_or_rewind_dev(DEVICE *dev)
 int
 fsf_dev(DEVICE *dev, int num)
 { 
+   struct mtget mt_stat;
    struct mtop mt_com;
    int stat = 0;
 
@@ -721,13 +725,51 @@ fsf_dev(DEVICE *dev, int num)
    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_cap(dev, CAP_FSF)) {
+   /*
+    * If Fast forward space file is set, then we
+    *  use MTFSF to forward space and MTIOCGET
+    *  to get the file position. We assume that 
+    *  the SCSI driver will ensure that we do not
+    *  forward space over the end of data mark.
+    */
+   if (dev_cap(dev, CAP_FSF) && dev_cap(dev, CAP_FASTFSF)) {
+      mt_com.mt_op = MTFSF;
+      mt_com.mt_count = num;
+      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));
+         Dmsg1(200, "%s", dev->errmsg);
+        return 0;
+      } else if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+           dev->state |= ST_EOT;
+           clrerror_dev(dev, MTFSF);
+           dev->dev_errno = errno;
+            Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
+              dev->dev_name, strerror(dev->dev_errno));
+            Dmsg1(200, "%s", dev->errmsg);
+           return 0;
+      }
+      Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+      dev->file = mt_stat.mt_fileno;
+      dev->state |= ST_EOF;    /* just read EOF */
+      dev->file_addr = 0;
+      return 1;
+
+   /* 
+    * Here if CAP_FSF is set, and virtually all drives
+    *  these days support it, we read a record, then forward
+    *  space one file. Using this procedure, which is slow,
+    *  is the only way we can be sure that we don't read
+    *  two consecutive EOF marks, which means End of Data.
+    */
+   } else if (dev_cap(dev, CAP_FSF)) {
       POOLMEM *rbuf;
       int rbuf_len;
       Dmsg0(200, "FSF has cap_fsf\n");
@@ -830,12 +872,14 @@ bsf_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to bsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to bsf_dev. Archive device not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
 
    if (!(dev_state(dev, ST_TAPE))) {
+      Mmsg1(&dev->errmsg, _("Device %s cannot BSF because it is not a tape.\n"),
+        dev->dev_name);
       return 0;
    }
    Dmsg0(29, "bsf_dev\n");
@@ -1002,12 +1046,12 @@ weof_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to weof_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to weof_dev. Archive drive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
 
-   if (!(dev->state & ST_TAPE)) {
+   if (!(dev_state(dev, ST_TAPE))) {
       return 0;
    }
    dev->state &= ~(ST_EOT | ST_EOF);  /* remove EOF/EOT flags */
@@ -1021,8 +1065,10 @@ weof_dev(DEVICE *dev, int num)
       dev->file_addr = 0;
    } else {
       clrerror_dev(dev, MTWEOF);
-      Mmsg2(&dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
-        dev->dev_name, strerror(dev->dev_errno));
+      if (stat == -1) {
+         Mmsg2(&dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
+           dev->dev_name, strerror(dev->dev_errno));
+       }
    }
    return stat;
 }
@@ -1115,7 +1161,7 @@ clrerror_dev(DEVICE *dev, int func)
 {
    /* Read and clear SCSI error status */
    union mterrstat mt_errstat;
-   Pmsg2(000, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev->dev_errno,
+   Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev->dev_errno,
       strerror(dev->dev_errno));
    ioctl(dev->fd, MTIOCERRSTAT, (char *)&mt_errstat);
 }
index 797fa441b68dae7c631d65aa4c5c18cb0c70e753..3f27bd8170bd8fe7311d349cae8984a4d810be7e 100644 (file)
@@ -82,6 +82,8 @@
 #define CAP_OFFLINEUNMOUNT (1<<13)    /* Offline before unmount */
 #define CAP_STREAM         (1<<14)    /* Stream device */
 #define CAP_BSFATEOM       (1<<15)    /* Backspace file at EOM */
+#define CAP_FASTFSF        (1<<16)    /* Fast forward space file */
+#define CAP_TWOEOF         (1<<17)    /* Write two eofs for EOM */
 
 /* Test state */
 #define dev_state(dev, st_state) ((dev)->state & (st_state))
@@ -125,6 +127,8 @@ struct VOLUME_CAT_INFO {
    uint64_t VolCatRBytes;             /* Number of bytes read */
    uint32_t VolCatRecycles;           /* Number of recycles this volume */
    int32_t  Slot;                     /* Slot in changer */
+   int32_t  Drive;                    /* Changer drive */
+   bool     InChanger;                /* Set if vol in current magazine */
    uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
    uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
    uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
index 4fd675c1384d67490e031d623e56f63f5215c69a..eaacb8fcd4ed1e358e73423936df89303f289ed3 100644 (file)
@@ -106,13 +106,12 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
        return 0;
    }
 
-   strcpy(dev->VolCatInfo.VolCatStatus, "Full");
-   Dmsg2(200, "Call update_vol_info Stat=%s Vol=%s\n", 
+   bstrncpy(dev->VolCatInfo.VolCatStatus, "Full", sizeof(dev->VolCatInfo.VolCatStatus));
+   Dmsg2(100, "Call update_vol_info Stat=%s Vol=%s\n", 
       dev->VolCatInfo.VolCatStatus, dev->VolCatInfo.VolCatName);
    dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
-   /* *****FIXME**** this needs to be done elsewhere */
    dev->VolCatInfo.VolCatJobs++;             /* increment number of jobs */
-   if (!dir_update_volume_info(jcr, &dev->VolCatInfo, 0)) {    /* send Volume info to Director */
+   if (!dir_update_volume_info(jcr, dev, 0)) {   /* send Volume info to Director */
       P(dev->mutex);
       unblock_device(dev);
       return 0;                   /* device locked */
@@ -201,7 +200,7 @@ void set_new_volume_parameters(JCR *jcr, DEVICE *dev)
       Jmsg1(jcr, M_ERROR, 0, "%s", jcr->errmsg);
    }
    /* Set new start/end positions */
-   if (dev->state & ST_TAPE) {
+   if (dev_state(dev, ST_TAPE)) {
       jcr->StartBlock = dev->block_num;
       jcr->StartFile = dev->file;
    } else {
@@ -217,14 +216,14 @@ void set_new_volume_parameters(JCR *jcr, DEVICE *dev)
 }
 
 /*
- * We are now in a new file, so reset the Volume parameters
+ * We are now in a new Volume file, so reset the Volume parameters
  *  concerning this job.  The global changes were made earlier
  *  in the dev structure.
  */
 void set_new_file_parameters(JCR *jcr, DEVICE *dev) 
 {
    /* Set new start/end positions */
-   if (dev->state & ST_TAPE) {
+   if (dev_state(dev, ST_TAPE)) {
       jcr->StartBlock = dev->block_num;
       jcr->StartFile = dev->file;
    } else {
index 143ee339bb2b9a55c1c1915ecd2050319342cb76..49bf8886711c45ab0160d945f155ab369d7eea07 100644 (file)
@@ -324,10 +324,10 @@ static int do_label(JCR *jcr, int relabel)
            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
         } 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"),
+                bnet_fsend(dir, _("3911 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"),
+                bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
         } else {                     /* device not being used */
@@ -581,7 +581,7 @@ static int mount_cmd(JCR *jcr)
       }
    } else {
       pm_strcpy(&jcr->errmsg, dir->msg);
-      bnet_fsend(dir, _("3906 Error scanning mount command: %s\n"), jcr->errmsg);
+      bnet_fsend(dir, _("3909 Error scanning mount command: %s\n"), jcr->errmsg);
    }
    free_memory(dev_name);
    bnet_sig(dir, BNET_EOD);
@@ -823,7 +823,7 @@ static int autochanger_cmd(JCR *jcr)
       }
    } else {  /* error on scanf */
       pm_strcpy(&jcr->errmsg, dir->msg);
-      bnet_fsend(dir, _("3907 Error scanning autocharger list command: %s\n"),
+      bnet_fsend(dir, _("3908 Error scanning autocharger list command: %s\n"),
         jcr->errmsg);
    }
    free_memory(devname);
index e4eaf9df49d51b9602847fabd8ed9ea899a49a39..78b96b7d25e9919cb7e1ccb9dce149c928c55853 100644 (file)
@@ -317,6 +317,7 @@ static int bootstrap_cmd(JCR *jcr)
    BSOCK *fd = jcr->file_bsock;
    POOLMEM *fname = get_pool_memory(PM_FNAME);
    FILE *bs;
+   int stat = 0;
 
    if (jcr->RestoreBootstrap) {
       unlink(jcr->RestoreBootstrap);
@@ -345,15 +346,18 @@ static int bootstrap_cmd(JCR *jcr)
    if (debug_level > 20) {
       dump_bsr(jcr->bsr, true);
    }
-   return bnet_fsend(fd, OK_bootstrap);
+   stat = 1;
 
 bail_out:
    unlink(jcr->RestoreBootstrap);
    free_pool_memory(jcr->RestoreBootstrap);
    jcr->RestoreBootstrap = NULL;
+   if (stat) {
+      return bnet_fsend(fd, OK_bootstrap);
+   } else {
    bnet_fsend(fd, ERROR_bootstrap);
    return 0;
-
+   }
 }
 
 
index 8673fa4757469bcffeff5669e5e0c23168e05dcc..6c54e6d835bff105fada120bd7678bcd6df2089c 100644 (file)
@@ -103,7 +103,7 @@ int job_cmd(JCR *jcr)
     */
    ojcr = get_jcr_by_full_name(job);
    if (ojcr && !ojcr->authenticated) {
-      Dmsg2(000, "Found ojcr=0x%x Job %s\n", (unsigned)ojcr, job);
+      Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)ojcr, job);
       free_jcr(ojcr);
    }
    jcr->JobId = JobId;
@@ -142,11 +142,6 @@ int job_cmd(JCR *jcr)
    /*
     * Pass back an authorization key for the File daemon
     */
-#ifdef Old_way_not_so_good
-   gettimeofday(&tv, &tz);
-   srandom(tv.tv_usec + tv.tv_sec);
-   sprintf(auth_key, "%ld", (long)random());
-#endif
    make_session_key(auth_key, NULL, 1);
    bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
    Dmsg1(110, ">dird: %s", dir->msg);
@@ -170,7 +165,7 @@ int job_cmd(JCR *jcr)
    timeout.tv_sec = tv.tv_sec + 30 * 60;       /* wait 30 minutes */
 
 
-   Dmsg1(200, "%s waiting on job_start_wait\n", jcr->Job);
+   Dmsg1(100, "%s waiting on job_start_wait\n", jcr->Job);
    /* Wait for the File daemon to contact us to start the Job,
     *  when he does, we will be released, unless the 30 minutes
     *  expires.
@@ -187,6 +182,7 @@ int job_cmd(JCR *jcr)
    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
 
    if (jcr->authenticated && !job_canceled(jcr)) {
+      Dmsg1(100, "Running job %s\n", jcr->Job);
       run_job(jcr);                  /* Run the job */
    }
    return 0;
index c62a4e69d7fbb67fe625f17b25719c3c2bb2bb1e..a92b259ccbb19012493d46b8b288ad447e275120 100644 (file)
@@ -65,7 +65,7 @@ int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n", 
       dev_name(dev), VolName, dev->VolHdr.VolName);
 
-   if (dev->state & ST_LABEL) {       /* did we already read label? */
+   if (dev_state(dev, ST_LABEL)) {      /* did we already read label? */
       /* Compare Volume Names allow special wild card */
       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) {
          Mmsg(&jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
@@ -131,6 +131,17 @@ because:\n   %s"), dev_name(dev), strerror_dev(dev));
       return jcr->label_status = VOL_VERSION_ERROR;
    }
 
+   /* 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 */
+
    /* Compare Volume Names */
    Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolName);
    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) {
@@ -147,16 +158,6 @@ because:\n   %s"), dev_name(dev), strerror_dev(dev));
    }
    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);
    }
index ece77a6bd24165fe62b2dfb1e32cca2006ce8439..e1551703c214a76203238446fc3032091ef5f7b3 100755 (executable)
@@ -77,10 +77,16 @@ int match_bsr_block(BSR *bsr, DEV_BLOCK *block)
       return 1;                      /* cannot fast reject */
    }
 
-   if (match_block_sesstime(bsr, bsr->sesstime, block)) {
+   for ( ; bsr; bsr=bsr->next) {
+   if (!match_block_sesstime(bsr, bsr->sesstime, block)) {
+        continue;
+      }
+      if (!match_block_sessid(bsr, bsr->sessid, block)) {
+        continue;
+   }
       return 1;
    }
-   return match_block_sessid(bsr, bsr->sessid, block);
+   return 0;
 }
 
 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block)
@@ -135,7 +141,7 @@ int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *se
       /* 
        * Note, bsr->reposition is set by match_all when
        *  a bsr is done. We turn it off if a match was
-       *  found or if we cannot use poistioning
+       *  found or if we cannot use positioning
        */
       if (stat != 0 || !bsr->use_positioning) {
         bsr->reposition = false;
@@ -157,10 +163,10 @@ BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev)
 
    if (!root_bsr || !root_bsr->use_positioning || 
        !root_bsr->reposition || !dev_is_tape(dev)) {
-      Dmsg2(100, "use_pos=%d repos=%d\n", root_bsr->use_positioning,
-       root_bsr->reposition);
+      Dmsg2(100, "No nxt_bsr use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
       return NULL;
    }
+   Dmsg2(100, "use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
    root_bsr->mount_next_volume = false;
    for (bsr=root_bsr; bsr; bsr=bsr->next) {
       if (bsr->done || !match_volume(bsr, bsr->volume, &dev->VolHdr, 1)) {
@@ -231,6 +237,34 @@ static BSR *find_smallest_volfile(BSR *found_bsr, BSR *bsr)
    return return_bsr;
 }
 
+/* 
+ * Called to tell the matcher that the end of
+ *   the current file has been reached.
+ *  The bsr argument is not used, but is included
+ *    for consistency with the other match calls.
+ * 
+ * Returns: true if we should reposition
+ *       : false otherwise.
+ */
+bool match_set_eof(BSR *bsr, DEV_RECORD *rec)
+{
+   BSR *rbsr = rec->bsr;
+   Dmsg1(100, "match_set %d\n", rbsr != NULL);
+   if (!rbsr) {
+      return false;
+   }
+   rec->bsr = NULL;
+   rbsr->found++;
+   if (rbsr->count && rbsr->found >= rbsr->count) {
+      rbsr->done = true;
+      rbsr->root->reposition = true;
+      Dmsg2(100, "match_set_eof reposition count=%d found=%d\n",
+        rbsr->count, rbsr->found);
+      return true;
+   }
+   return false;
+}
+
 /* 
  * Match all the components of current record
  *   returns  1 on match
@@ -243,33 +277,54 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
    if (bsr->done) {
       goto no_match;
    }
-   if (bsr->count && bsr->count <= bsr->found) {
-      bsr->done = true;
-      bsr->root->reposition = true;
-      Dmsg0(100, "bsr done from count\n");
-      goto no_match;
-   }
    if (!match_volume(bsr, bsr->volume, volrec, 1)) {
       goto no_match;
    }
    if (!match_volfile(bsr, bsr->volfile, rec, 1)) {
+      Dmsg2(100, "Fail on file. bsr=%d rec=%d\n", bsr->volfile->efile,
+        rec->File);
       goto no_match;
    }
    if (!match_sesstime(bsr, bsr->sesstime, rec, 1)) {
+      Dmsg2(100, "Fail on sesstime. bsr=%d rec=%d\n",
+        bsr->sesstime->sesstime, rec->VolSessionTime);
       goto no_match;
    }
 
    /* NOTE!! This test MUST come after the sesstime test */
    if (!match_sessid(bsr, bsr->sessid, rec)) {
+      Dmsg2(100, "Fail on sessid. bsr=%d rec=%d\n",
+        bsr->sessid->sessid, rec->VolSessionId);
       goto no_match;
    }
 
    /* NOTE!! This test MUST come after sesstime and sessid tests */
    if (!match_findex(bsr, bsr->FileIndex, rec, 1)) {
+      Dmsg2(100, "Fail on findex. bsr=%d rec=%d\n",
+        bsr->FileIndex->findex2, rec->FileIndex);
       goto no_match;
    }
+   /*
+    * If a count was specified and we have a FileIndex, assume
+    *  it is a Bacula created bsr (or the equivalent). We
+    *  then save the bsr where the match occurred so that
+    *  after processing the record or records, we can update
+    *  the found count. I.e. rec->bsr points to the bsr that
+    *  satisfied the match.
+    */
+   if (bsr->count && bsr->FileIndex) {
+      rec->bsr = bsr;
+      return 1;                      /* this is a complete match */
+   }
+
+   /*
+    * The selections below are not used by Bacula's
+    *   restore command, and don't work because of
+    *  the rec->bsr = bsr optimization above.
+    */
    if (!match_jobid(bsr, bsr->JobId, sessrec, 1)) {
       goto no_match;
+       
    }
    if (!match_job(bsr, bsr->job, sessrec, 1)) {
       goto no_match;
@@ -286,7 +341,6 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
    if (!match_stream(bsr, bsr->stream, rec, 1)) {
       goto no_match;
    }
-   bsr->found++;
    return 1;
 
 no_match:
@@ -392,7 +446,7 @@ static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool d
    if (!(rec->state & REC_ISTAPE)) {
       return 1;                      /* All File records OK for this match */
    }
-// Dmsg3(000, "match_volfile: sfile=%d efile=%d recfile=%d\n",
+// Dmsg3(100, "match_volfile: sfile=%d efile=%d recfile=%d\n",
 //            volfile->sfile, volfile->efile, rec->File);
    if (volfile->sfile <= rec->File && volfile->efile >= rec->File) {
       return 1;
@@ -409,7 +463,8 @@ static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool d
    if (volfile->done && done) {
       bsr->done = true;
       bsr->root->reposition = true;
-      Dmsg0(100, "bsr done from volfile\n");
+      Dmsg2(100, "bsr done from volfile rec=%d volefile=%d\n", 
+        rec->File, volfile->efile);
    }
    return 0;
 }
@@ -464,6 +519,10 @@ static int match_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_RECORD *rec)
    return 0;
 }
 
+/*
+ * When reading the Volume, the Volume Findex (rec->FileIndex) always
+ *   are found in sequential order. Thus we can make optimizations.
+ */
 static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done)
 {
    if (!findex) {
index 4d45f4e384c0466f9b9871766cf0e9acf1b8de12..fa7dd67f0f40c57233f4c8a80378fb3f14cbf6b5 100644 (file)
@@ -30,7 +30,8 @@
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
-/* Forward referenced functions */
+/* Forward referenced routines */
+static void mark_volume_in_error(JCR *jcr, DEVICE *dev);
 
 
 /*
  * This routine returns a 0 only if it is REALLY
  *  impossible to get the requested Volume.
  *
- *    *****FIXME****** handle "Recycle" volume ******
  */
 int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release)
 {
-   int retry = 0, autochanger;
-   bool ask, recycle;
+   int retry = 0;
+   bool ask = false, recycle, autochanger;
+   int vol_label_status;
 
    Dmsg0(100, "Enter mount_next_volume()\n");
 
+   /* 
+    * Attempt to mount the next volume. If something non-fatal goes
+    *  wrong, we come back here to re-try (new op messages, re-read
+    *  Volume, ...)
+    */
 mount_next_vol:
    if (retry++ > 5) {
       Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), 
@@ -60,11 +66,11 @@ mount_next_vol:
       return 0;
    }
    if (job_canceled(jcr)) {
-      Jmsg(jcr, M_FATAL, 0, _("Job canceled.\n"));
+      Jmsg(jcr, M_FATAL, 0, _("Job %d canceled.\n"), jcr->JobId);
       return 0;
    }
-   autochanger = 0;
-   recycle = ask = false;
+   autochanger = false;               /* Assume no autochanger */
+   recycle = false;
    if (release) {
       Dmsg0(100, "mount_next_volume release=1\n");
       release_volume(jcr, dev);
@@ -73,10 +79,14 @@ mount_next_vol:
 
    /* 
     * Get Director's idea of what tape we should have mounted. 
+    *   in jcr->VolCatInfo
     */
-   if (!dir_find_next_appendable_volume(jcr) &&
-       !dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
-      return 0;
+   Dmsg0(100, "Before dir_find_next\n");
+   if (!dir_find_next_appendable_volume(jcr)) {
+       Dmsg0(100, "not dir_find_next\n");
+       if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+        return 0;
+       }
    }
    Dmsg2(100, "After find_next_append. Vol=%s Slot=%d\n",
         jcr->VolCatInfo.VolCatName, jcr->VolCatInfo.Slot);
@@ -94,142 +104,139 @@ mount_next_vol:
     * It assumes that the device is not already in use!
     *
     */
-
-   Dmsg0(100, "Enter ready_dev_for_append\n");
-
    dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
 
-   for ( ;; ) {
-      int vol_label_status;
-      autochanger = autoload_device(jcr, dev, 1, NULL);
-      Dmsg1(100, "autoload_dev returns %d\n", autochanger);
+   autochanger = autoload_device(jcr, dev, 1, NULL);
+   Dmsg1(100, "autoload_dev returns %d\n", autochanger);
+   /*
+    * If we autochanged to correct Volume or (we have not just
+    *  released the Volume AND we can automount) we go ahead 
+    *  and read the label. If there is no tape in the drive,
+    *  we will err, recurse and ask the operator the next time.
+    */
+   if (autochanger || (!release && dev_is_tape(dev) && dev_cap(dev, CAP_AUTOMOUNT))) {
+      ask = false;                 /* don't ask SYSOP this time */
+   }
+   Dmsg2(100, "Ask=%d autochanger=%d\n", ask, autochanger);
+   release = true;                /* release next time if we "recurse" */
 
-      /*
-       * If we autochanged to correct Volume or (we have not just
-       *   released the Volume AND we can automount) we go ahead 
-       *   and read the label. If there is no tape in the drive,
-       *   we will err, recurse and ask the operator the next time.
-       */
-      if (autochanger || (!release && dev_is_tape(dev) && dev_cap(dev, CAP_AUTOMOUNT))) {
-         ask = false;                 /* don't ask SYSOP this time */
-      }
+   if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+      Dmsg0(100, "Error return ask_sysop ...\n");
+      return 0;             /* error return */
+   }
+   Dmsg1(100, "want vol=%s\n", jcr->VolumeName);
 
-      release = 1;                    /* release next time if we "recurse" */
+   /* Open device */
+   if  (!(dev_state(dev, ST_OPENED))) {
+       int mode;
+       if (dev_cap(dev, CAP_STREAM)) {
+         mode = OPEN_WRITE_ONLY;
+       } else {
+         mode = OPEN_READ_WRITE;
+       }
+       if (open_dev(dev, jcr->VolCatInfo.VolCatName, mode) < 0) {
+          Jmsg2(jcr, M_FATAL, 0, _("Unable to open device %s. ERR=%s\n"), 
+            dev_name(dev), strerror_dev(dev));
+         return 0;
+       }
+   }
 
-ask_again:
-      if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
-         Dmsg0(100, "Error return ask_sysop ...\n");
-        return 0;              /* error return */
-      }
-      Dmsg1(100, "want vol=%s\n", jcr->VolumeName);
+   /*
+    * Now make sure we have the right tape mounted
+    */
+read_volume:
+   /* 
+    * If we are writing to a stream device, ASSUME the volume label
+    *  is correct.
+    */
+   if (dev_cap(dev, CAP_STREAM)) {
+      vol_label_status = VOL_OK;
+      create_volume_label(dev, jcr->VolumeName, "Default");
+      dev->VolHdr.LabelType = PRE_LABEL;
+   } else {
+      vol_label_status = read_dev_volume_label(jcr, dev, block);
+   }
 
-      /* Open device */
-      if  (!(dev->state & ST_OPENED)) {
-         int mode;
-         if (dev_cap(dev, CAP_STREAM)) {
-            mode = OPEN_WRITE_ONLY;
-         } else {
-            mode = OPEN_READ_WRITE;
-         }
-         if (open_dev(dev, jcr->VolCatInfo.VolCatName, mode) < 0) {
-             Jmsg2(jcr, M_FATAL, 0, _("Unable to open device %s. ERR=%s\n"), 
-               dev_name(dev), strerror_dev(dev));
-            return 0;
-         }
-      }
+   Dmsg2(100, "dirVol=%s dirStat=%s\n", jcr->VolumeName,
+      jcr->VolCatInfo.VolCatStatus);
+   /*
+    * At this point, dev->VolCatInfo has what is in the drive, if anything,
+    *         and   jcr->VolCatInfo has what the Director wants.
+    */
+   switch (vol_label_status) {
+   case VOL_OK:
+      Dmsg1(100, "Vol OK name=%s\n", jcr->VolumeName);
+      memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
+      recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
+      break;                   /* got a Volume */
+   case VOL_NAME_ERROR:
+      VOLUME_CAT_INFO VolCatInfo;
 
-      /*
-       * Now make sure we have the right tape mounted
-       */
-read_volume:
+      Dmsg1(100, "Vol NAME Error Name=%s\n", jcr->VolumeName);
       /* 
-       * If we are writing to a stream device, ASSUME the volume label
-       *  is correct.
+       * OK, we got a different volume mounted. First save the
+       *  requested Volume info (jcr) structure, then query if
+       *  this volume is really OK. If not, put back the desired
+       *  volume name and continue.
        */
-      if (dev_cap(dev, CAP_STREAM)) {
-        vol_label_status = VOL_OK;
-         create_volume_label(dev, jcr->VolumeName, "Default");
-        dev->VolHdr.LabelType = PRE_LABEL;
-      } else {
-        vol_label_status = read_dev_volume_label(jcr, dev, block);
+      memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(VolCatInfo));
+      /* Check if this is a valid Volume in the pool */
+      pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName);                        
+      if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) {
+         Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n"
+              "    Current Volume \"%s\" not acceptable because:\n"
+              "    %s"),
+            VolCatInfo.VolCatName, dev->VolHdr.VolName,
+            jcr->dir_bsock->msg);
+        /* Restore desired volume name, note device info out of sync */
+        memcpy(&jcr->VolCatInfo, &VolCatInfo, sizeof(jcr->VolCatInfo));
+        ask = true;
+        goto mount_next_vol;
       }
-      Dmsg2(100, "dirVol=%s dirStat=%s\n", jcr->VolumeName,
-        jcr->VolCatInfo.VolCatStatus);
-      /*
-       * At this point, dev->VolCatInfo has what is in the drive, if anything,
-       *         and   jcr->VolCatInfo has what the Director wants.
+      Dmsg1(100, "want new name=%s\n", jcr->VolumeName);
+      memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo));
+      recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
+      break;               /* got a Volume */
+   /*
+    * At this point, we assume we have a blank tape mounted.
+    */
+   case VOL_NO_LABEL:
+   case VOL_IO_ERROR:
+      /* 
+       * If permitted, we label the device, make sure we can do
+       *   it by checking that the VolCatBytes is zero => not labeled, 
+       *   once the Volume is labeled we don't want to label another
+       *   blank tape with the same name.  For disk, we go ahead and
+       *   label it anyway, because the OS insures that there is only
+       *   one Volume with that name.
+       * As noted above, at this point jcr->VolCatInfo has what
+       *   the Director wants and dev->VolCatInfo has info on the
+       *   previous tape (or nothing).
        */
-      switch (vol_label_status) {
-      case VOL_OK:
-         Dmsg1(100, "Vol OK name=%s\n", jcr->VolumeName);
-        memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
-         recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
-        break;                    /* got a Volume */
-      case VOL_NAME_ERROR:
-        VOLUME_CAT_INFO VolCatInfo;
-
-         Dmsg1(100, "Vol NAME Error Name=%s\n", jcr->VolumeName);
-        /* 
-         * OK, we got a different volume mounted. First save the
-         *  requested Volume info (jcr) structure, then query if
-         *  this volume is really OK. If not, put back the desired
-         *  volume name and continue.
-         */
-        memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(VolCatInfo));
-        /* Check if this is a valid Volume in the pool */
-        pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName);                         
-        if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) {
-            Mmsg(&jcr->errmsg, _("Director wanted Volume \"%s\".\n"
-                 "    Current Volume \"%s\" not acceptable because:\n"
-                 "    %s"),
-               VolCatInfo.VolCatName, dev->VolHdr.VolName,
-               jcr->dir_bsock->msg);
-           /* Restore desired volume name, note device info out of sync */
-           memcpy(&jcr->VolCatInfo, &VolCatInfo, sizeof(jcr->VolCatInfo));
-           goto mount_error;
+      if (dev_cap(dev, CAP_LABEL) && (jcr->VolCatInfo.VolCatBytes == 0 ||
+           (!dev_is_tape(dev) && strcmp(jcr->VolCatInfo.VolCatStatus, 
+                                   "Recycle") == 0))) {
+         Dmsg0(100, "Create volume label\n");
+        if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName,
+               jcr->pool_name)) {
+            Dmsg0(100, "!write_vol_label\n");
+           goto mount_next_vol;
         }
-         Dmsg1(100, "want new name=%s\n", jcr->VolumeName);
+         Dmsg0(100, "dir_update_vol_info. Set Append\n");
+         /* Copy Director's info into the device info */
         memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo));
-         recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
-        break;                /* got a Volume */
-      /*
-       * At this point, we assume we have a blank tape mounted.
-       */
-      case VOL_NO_LABEL:
-      case VOL_IO_ERROR:
-        /* 
-         * If permitted, we label the device, make sure we can do
-         *   it by checking that the VolCatBytes is zero => not labeled. 
-         * As noted above, at this point jcr->VolCatInfo has what
-         *   the Director wants and dev->VolCatInfo has info on the
-         *   previous tape (or nothing).
-         */
-        if (dev_cap(dev, CAP_LABEL) && jcr->VolCatInfo.VolCatBytes == 0) {
-            Dmsg0(100, "Create volume label\n");
-           if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName,
-                  jcr->pool_name)) {
-               Dmsg0(100, "!write_vol_label\n");
-              goto mount_next_vol;
-           }
-            Dmsg0(200, "dir_update_vol_info. Set Append\n");
-            /* Copy Director's info into the device info */
-           memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo));
-           dir_update_volume_info(jcr, &dev->VolCatInfo, 1);  /* indicate tape labeled */
-            Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
-              jcr->VolumeName, dev_name(dev));
-           goto read_volume;      /* read label we just wrote */
-        } 
-        /* NOTE! Fall-through wanted. */
-      case VOL_NO_MEDIA:
-      default:
-mount_error:
-        /* Send error message */
-         Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
-         Dmsg0(100, "Default\n");
-        ask = true;
-        goto ask_again;
-      }
-      break;
+        dir_update_volume_info(jcr, dev, 1);  /* indicate tape labeled */
+         Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
+           jcr->VolumeName, dev_name(dev));
+        goto read_volume;      /* read label we just wrote */
+      } 
+      /* NOTE! Fall-through wanted. */
+   case VOL_NO_MEDIA:
+   default:
+      /* Send error message */
+      Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
+      ask = true;
+      goto mount_next_vol;
    }
 
    /* 
@@ -240,7 +247,7 @@ mount_error:
     *  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
+    *  a second volume, the calling routine will write the label
     *  before writing the overflow block.
     *
     *  If the tape is marked as Recycle, we rewrite the label.
@@ -271,6 +278,13 @@ mount_error:
               dev_name(dev), strerror_dev(dev));
            goto mount_next_vol;
         }
+        /* 
+         * We do not return the label in the block, because if we are
+         *  running multiple simultaneous jobs, once we release the lock
+         *  some other thread may write his block over the label. So, 
+         *  we simply write it definitively now.
+         */
+#ifdef needed
         if (!rewind_dev(dev)) {
             Jmsg2(jcr, M_ERROR, 0, _("Unable to rewind device %s. ERR=%s\n"),
               dev_name(dev), strerror_dev(dev));
@@ -279,6 +293,7 @@ mount_error:
 
         /* Recreate a correct volume label and return it in the block */
         write_volume_label_to_block(jcr, dev, block);
+#endif
       }
       /* Set or reset Volume statistics */
       dev->VolCatInfo.VolCatJobs = 0;
@@ -296,9 +311,9 @@ mount_error:
         dev->VolCatInfo.VolCatWrites = 1;
         dev->VolCatInfo.VolCatReads = 1;
       }
-      Dmsg0(200, "dir_update_vol_info. Set Append\n");
+      Dmsg0(100, "dir_update_vol_info. Set Append\n");
       bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
-      dir_update_volume_info(jcr, &dev->VolCatInfo, 1);  /* indicate doing relabel */
+      dir_update_volume_info(jcr, dev, 1);  /* indicate doing relabel */
       if (recycle) {
          Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
            jcr->VolumeName, dev_name(dev));
@@ -306,6 +321,10 @@ mount_error:
          Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
            jcr->VolumeName, dev_name(dev));
       }
+      /*
+       * End writing real Volume label (from pre-labeled tape), or recycling
+       *  the volume.
+       */
 
    } else {
       /*
@@ -319,11 +338,7 @@ mount_error:
       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);
-         bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
-         Dmsg0(200, "dir_update_vol_info. Set Error.\n");
-        dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
+        mark_volume_in_error(jcr, dev);
         goto mount_next_vol;
       }
       /* *****FIXME**** we should do some checking for files too */
@@ -339,15 +354,13 @@ mount_error:
             Jmsg(jcr, M_ERROR, 0, _("I canot write on this volume because:\n\
 The number of files mismatch! Volume=%u Catalog=%u\n"), 
                 dev_file(dev), dev->VolCatInfo.VolCatFiles);
-            bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
-            Dmsg0(200, "dir_update_vol_info. Set Error.\n");
-           dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
+           mark_volume_in_error(jcr, dev);
            goto mount_next_vol;
         }
       }
       dev->VolCatInfo.VolCatMounts++;     /* Update mounts */
-      Dmsg1(200, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
-      dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
+      Dmsg1(100, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
+      dir_update_volume_info(jcr, dev, 0);
       /* Return an empty block */
       empty_block(block);            /* we used it for reading so set for write */
    }
@@ -356,7 +369,19 @@ The number of files mismatch! Volume=%u Catalog=%u\n"),
    return 1; 
 }
 
+static void mark_volume_in_error(JCR *jcr, DEVICE *dev)
+{
+   Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"),
+       jcr->VolumeName);
+   bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
+   Dmsg0(100, "dir_update_vol_info. Set Error.\n");
+   dir_update_volume_info(jcr, dev, 0);
+}
 
+/* 
+ * If we are reading, we come here at the end of the tape
+ *  and see if there are more volumes to be mounted.
+ */
 int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 {
    Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume);
@@ -383,7 +408,6 @@ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
  */
 void release_volume(JCR *jcr, DEVICE *dev)
 {
-
    if (jcr->WroteVol) {
       Jmsg0(jcr, M_ERROR, 0, "Hey!!!!! WroteVol non-zero !!!!!\n");
    }
@@ -395,7 +419,8 @@ void release_volume(JCR *jcr, DEVICE *dev)
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
    memset(&jcr->VolCatInfo, 0, sizeof(jcr->VolCatInfo));
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
-   dev->state &= ~ST_LABEL;       /* label not yet read */
+   /* Force re-read of label */
+   dev->state &= ~(ST_LABEL|ST_READ|ST_APPEND);
    jcr->VolumeName[0] = 0;
 
    if ((dev->state & ST_OPENED) && 
index 83343dcb7a19c5b1ed118572f2ab7c6c6f1863a5..7805c1c9d9685428e5f77bb8b7607b4fdc0d1372 100755 (executable)
@@ -713,9 +713,12 @@ void dump_bsr(BSR *bsr, bool recurse)
    }
    if (bsr->count) {
       Dmsg1(-1, "count       : %u\n", bsr->count);
+      Dmsg1(-1, "found       : %u\n", bsr->found);
    }
+
    Dmsg1(-1,    "done        : %s\n", bsr->done?"yes":"no");
    Dmsg1(-1,    "positioning : %d\n", bsr->use_positioning);
+   Dmsg1(-1,    "fast_reject : %d\n", bsr->use_fast_rejection);
    if (recurse && bsr->next) {
       Dmsg0(-1, "\n");
       dump_bsr(bsr->next, true);
index 8ad22626602f20375d793d796dd78c1868ef5d60..3e1d1560e5722b21d88546fa91f136546167ac5e 100644 (file)
 uint32_t new_VolSessionId();
 
 /* From acquire.c */
-DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int     acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int     release_device(JCR *jcr, DEVICE *dev);
+DEVICE  *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int      acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int      release_device(JCR *jcr, DEVICE *dev);
 
 /* From askdir.c */
 enum get_vol_info_rw {
    GET_VOL_INFO_FOR_WRITE,
    GET_VOL_INFO_FOR_READ
 };
-int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
-int    dir_find_next_appendable_volume(JCR *jcr);
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int label);
-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);
-int    dir_create_jobmedia_record(JCR *jcr);
+int     dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
+int     dir_find_next_appendable_volume(JCR *jcr);
+int     dir_update_volume_info(JCR *jcr, DEVICE *dev, int label);
+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);
+int     dir_create_jobmedia_record(JCR *jcr);
 
 /* authenticate.c */
-int    authenticate_director(JCR *jcr);
-int    authenticate_filed(JCR *jcr);
+int     authenticate_director(JCR *jcr);
+int     authenticate_filed(JCR *jcr);
 
 /* From block.c */
-void   dump_block(DEV_BLOCK *b, char *msg);
+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(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void   print_block_errors(JCR *jcr, DEV_BLOCK *block);
+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(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    print_block_read_errors(JCR *jcr, DEV_BLOCK *block);
 
 #define CHECK_BLOCK_NUMBERS    true
 #define NO_BLOCK_NUMBER_CHECK  false
-int    read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
-int    read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int     read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int     read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
 
 /* From butil.c -- utilities for SD tool programs */
-void   print_ls_output(char *fname, char *link, int type, struct stat *statp);
+void    print_ls_output(char *fname, char *link, int type, struct stat *statp);
 JCR    *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName);
 DEVICE *setup_to_access_device(JCR *jcr, int read_access);
-void   display_tape_error_status(JCR *jcr, DEVICE *dev);
+void    display_tape_error_status(JCR *jcr, DEVICE *dev);
 DEVRES *find_device_res(char *device_name, int read_access);
 
 
 /* From dev.c */
-DEVICE *init_dev(DEVICE *dev, DEVRES *device);
-int     open_dev(DEVICE *dev, char *VolName, int mode);
-void    close_dev(DEVICE *dev);
-void    force_close_dev(DEVICE *dev);
-int     truncate_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);
-void    attach_jcr_to_device(DEVICE *dev, JCR *jcr);
-void    detach_jcr_from_device(DEVICE *dev, JCR *jcr);
-JCR    *next_attached_jcr(DEVICE *dev, JCR *jcr);
-int     dev_can_write(DEVICE *dev);
-int     offline_or_rewind_dev(DEVICE *dev);
-int     reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
+DEVICE  *init_dev(DEVICE *dev, DEVRES *device);
+int      open_dev(DEVICE *dev, char *VolName, int mode);
+void     close_dev(DEVICE *dev);
+void     force_close_dev(DEVICE *dev);
+int      truncate_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);
+void     attach_jcr_to_device(DEVICE *dev, JCR *jcr);
+void     detach_jcr_from_device(DEVICE *dev, JCR *jcr);
+JCR     *next_attached_jcr(DEVICE *dev, JCR *jcr);
+int      dev_can_write(DEVICE *dev);
+int      offline_or_rewind_dev(DEVICE *dev);
+int      reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
 
 
 /* Get info about device */
-char *  dev_name(DEVICE *dev);
-char *  dev_vol_name(DEVICE *dev);
+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);
+int      dev_is_tape(DEVICE *dev);
 
 /* From device.c */
-int     open_device(DEVICE *dev);
-int     fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int      open_device(DEVICE *dev);
+int      fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 void _lock_device(char *file, int line, DEVICE *dev);
 void _unlock_device(char *file, int line, DEVICE *dev);
 void _block_device(char *file, int line, DEVICE *dev, int state);
@@ -126,64 +126,65 @@ void set_new_file_parameters(JCR *jcr, DEVICE *dev);
 int  device_is_unmounted(DEVICE *dev);
 
 /* From dircmd.c */
-void    *connection_request(void *arg); 
+void     *connection_request(void *arg); 
 
 
 /* From fd_cmds.c */
-void    run_job(JCR *jcr);
+void     run_job(JCR *jcr);
 
 /* From job.c */
-void    stored_free_jcr(JCR *jcr);
-void    connection_from_filed(void *arg);     
-void    handle_filed_connection(BSOCK *fd, char *job_name);
+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);
-void    create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
-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);
+int      read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void     create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+void     create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
+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 match_bsr.c */
-int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, 
-             SESSION_LABEL *sesrec);
-int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
-void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
-BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
+int      match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, 
+              SESSION_LABEL *sesrec);
+int      match_bsr_block(BSR *bsr, DEV_BLOCK *block);
+void     position_bsr_block(BSR *bsr, DEV_BLOCK *block);
+BSR     *find_next_bsr(BSR *root_bsr, DEVICE *dev);
+bool     match_set_eof(BSR *bsr, DEV_RECORD *rec);
 
 /* From mount.c */
-int     mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
-int     mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void    release_volume(JCR *jcr, DEVICE *dev);
+int      mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
+int      mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void     release_volume(JCR *jcr, DEVICE *dev);
 
 /* From autochanger.c */
-int     autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
-int     autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
-void    invalidate_slot_in_catalog(JCR *jcr);
+int      autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int      autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
+void     invalidate_slot_in_catalog(JCR *jcr, DEVICE *dev);
 
 
 /* From parse_bsr.c */
-extern BSR *parse_bsr(JCR *jcr, char *lf);
-void dump_bsr(BSR *bsr, bool recurse);
-extern void free_bsr(BSR *bsr);
-extern VOL_LIST *new_vol();
-extern int add_vol(JCR *jcr, VOL_LIST *vol);
-extern void free_vol_list(JCR *jcr);
-extern void create_vol_list(JCR *jcr);
+BSR     *parse_bsr(JCR *jcr, char *lf);
+void     dump_bsr(BSR *bsr, bool recurse);
+void     free_bsr(BSR *bsr);
+VOL_LIST *new_vol();
+int      add_vol(JCR *jcr, VOL_LIST *vol);
+void     free_vol_list(JCR *jcr);
+void     create_vol_list(JCR *jcr);
 
 /* From record.c */
 char   *FI_to_ascii(int fi);
 char   *stream_to_ascii(int stream, int fi);
-int    write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int    can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int    read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
+int     write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int     can_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);
+void    free_record(DEV_RECORD *rec);
 
 /* From read_record.c */
 int read_records(JCR *jcr,  DEVICE *dev, 
index 8e34737869e67a9e9e3bfeae10f9426496876a92..abcaec972277213c491035d412aa3918f3c15f69 100644 (file)
 #include "bacula.h"
 #include "stored.h"
 
+/* Forward referenced functions */
 static void handle_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
+static BSR *position_to_first_file(JCR *jcr, DEVICE *dev);
+static int try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev);
 #ifdef DEBUG
 static char *rec_state_to_str(DEV_RECORD *rec);
 #endif
@@ -52,6 +55,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
 
    block = new_block(dev);
    recs = new dlist(rec, &rec->link);
+   position_to_first_file(jcr, dev);
 
    for ( ; ok && !done; ) {
       if (job_canceled(jcr)) {
@@ -59,18 +63,13 @@ int read_records(JCR *jcr,  DEVICE *dev,
         break;
       }
       if (!read_block_from_device(jcr, dev, block, CHECK_BLOCK_NUMBERS)) {
-         Dmsg0(20, "!read_record()\n");
         if (dev_state(dev, ST_EOT)) {
            DEV_RECORD *trec = new_record();
 
-            Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
-                 block->BlockNumber, rec->remainder);
             Jmsg(jcr, M_INFO, 0, "End of Volume at file %u  on device %s, Volume \"%s\"\n", 
                 dev->file, dev_name(dev), jcr->VolumeName);
            if (!mount_cb(jcr, dev, block)) {
                Jmsg(jcr, M_INFO, 0, "End of all volumes.\n");
-               Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
-                 block->BlockNumber, rec->remainder);
               ok = FALSE;
               /*
                * Create EOT Label so that Media record may
@@ -79,13 +78,10 @@ int read_records(JCR *jcr,  DEVICE *dev,
                */
               trec->FileIndex = EOT_LABEL;
               trec->File = dev->file;
-              trec->Block = rec->Block; /* return block last read */
               ok = record_cb(jcr, dev, block, trec);
               free_record(trec);
               break;
            }
-            Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
-                 block->BlockNumber, rec->remainder);
            /*
             * We just have a new tape up, now read the label (first record)
             *  and pass it off to the callback routine, then continue
@@ -96,33 +92,17 @@ int read_records(JCR *jcr,  DEVICE *dev,
            handle_session_record(dev, trec, &sessrec);
            ok = record_cb(jcr, dev, block, trec);
            free_record(trec);
-           /*
-            * Now find and position to first file and block 
-            *   on this tape.
-            */
-           if (jcr->bsr) {
-              BSR *bsr;
-
-              jcr->bsr->reposition = true;
-              bsr = find_next_bsr(jcr->bsr, dev);
-              if (bsr) {
-                  Jmsg(jcr, M_INFO, 0, _("Forward spacing to file:block %u:%u.\n"), 
-                    bsr->volfile->sfile, bsr->volblock->sblock);
-                  Dmsg4(100, "Reposition new from (file:block) %d:%d to %d:%d\n",
-                       dev->file, dev->block_num, bsr->volfile->sfile,
-                       bsr->volblock->sblock);
-                 reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
-                  Dmsg2(100, "Now at (file:block) %d:%d\n",
-                       dev->file, dev->block_num);
-              }
-           }
+           position_to_first_file(jcr, dev);
            /* After reading label, we must read first data block */
            continue;
 
         } else if (dev_state(dev, ST_EOF)) {
+           if (verbose) {
             Jmsg(jcr, M_INFO, 0, "Got EOF at file %u  on device %s, Volume \"%s\"\n", 
                  dev->file, dev_name(dev), jcr->VolumeName);
-            Dmsg0(20, "read_record got eof. try again\n");
+           }
+            Dmsg3(100, "Got EOF at file %u  on device %s, Volume \"%s\"\n", 
+                 dev->file, dev_name(dev), jcr->VolumeName);
            continue;
         } else if (dev_state(dev, ST_SHORT)) {
             Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
@@ -134,16 +114,16 @@ int read_records(JCR *jcr,  DEVICE *dev,
            break;
         }
       }
-      Dmsg5(100, "Read block: dev=%d blk=%d VI=%u VT=%u blen=%d\n", dev->block_num, block->BlockNumber, 
-        block->VolSessionId, block->VolSessionTime, block->block_len);
+      Dmsg2(100, "New block at position=(file:block) %d:%d\n", dev->file, dev->block_num);
+#ifdef if_and_when_FAST_BLOCK_REJECTION_is_working
+      /* this does not stop when file/block are too big */
       if (!match_bsr_block(jcr->bsr, block)) {
-         Dmsg5(100, "reject Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
-           block->BlockNumber, block->block_len, block->BlockVer,
-           block->VolSessionId, block->VolSessionTime);
-        continue;
+        if (try_repositioning(jcr, rec, dev)) {
+           break;                    /* get next volume */
+        }
+        continue;                    /* skip this record */
       }
-      Dmsg4(100, "Block: %d VI=%u VT=%u blen=%d\n", block->BlockNumber, 
-        block->VolSessionId, block->VolSessionTime, block->block_len);
+#endif
 
       /*
        * Get a new record for each Job as defined by
@@ -163,21 +143,25 @@ int read_records(JCR *jcr,  DEVICE *dev,
          Dmsg2(100, "New record for SI=%d ST=%d\n",
             block->VolSessionId, block->VolSessionTime);
       } else {
+#ifdef xxx
         if (rec->Block != 0 && (rec->Block+1) != block->BlockNumber) {
             Jmsg(jcr, M_ERROR, 0, _("Invalid block number. Expected %u, got %u\n"),
                 rec->Block+1, block->BlockNumber);
         }
+#endif 
       }
       Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
            block->BlockNumber, rec->remainder);
       record = 0;
+      rec->state = 0;
+      Dmsg1(100, "Block empty %d\n", is_block_empty(rec));
       for (rec->state=0; !is_block_empty(rec); ) {
         if (!read_record_from_block(block, rec)) {
-            Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
+            Dmsg3(100, "!read-break. state=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
                  block->BlockNumber, rec->remainder);
            break;
         }
-         Dmsg5(100, "read-OK. stat=%s blk=%d rem=%d file:block=%d:%d\n", 
+         Dmsg5(100, "read-OK. state=%s blk=%d rem=%d file:block=%d:%d\n", 
                 rec_state_to_str(rec), block->BlockNumber, rec->remainder,
                 dev->file, dev->block_num);
         /*
@@ -190,10 +174,6 @@ int read_records(JCR *jcr,  DEVICE *dev,
          Dmsg6(100, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
            rec_state_to_str(rec), block->BlockNumber,
            rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
-         Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
-              FI_to_ascii(rec->FileIndex), 
-              stream_to_ascii(rec->Stream, rec->FileIndex), 
-              rec->data_len);
 
         if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
             Dmsg0(40, "Get EOM LABEL\n");
@@ -220,43 +200,40 @@ int read_records(JCR *jcr,  DEVICE *dev,
            int stat = match_bsr(jcr->bsr, rec, &dev->VolHdr, &sessrec);
            if (stat == -1) { /* no more possible matches */
               done = true;   /* all items found, stop */
+               Dmsg2(100, "All done=(file:block) %d:%d\n", dev->file, dev->block_num);
               break;
            } else if (stat == 0) {  /* no match */
-              BSR *bsr;
-              bsr = find_next_bsr(jcr->bsr, dev);
-              if (bsr == NULL && jcr->bsr->mount_next_volume) {
-                  Dmsg0(100, "Would mount next volume here\n");
-                  Dmsg2(100, "Current postion (file:block) %d:%d\n",
-                    dev->file, dev->block_num);
-                 jcr->bsr->mount_next_volume = false;
-                 dev->state |= ST_EOT;
-                 rec->Block = 0;
+               Dmsg4(100, "Clear rem=%d FI=%d before set_eof pos %d:%d\n", 
+                 rec->remainder, rec->FileIndex, dev->file, dev->block_num);
+              rec->remainder = 0;
+              rec->state &= ~REC_PARTIAL_RECORD;
+              if (try_repositioning(jcr, rec, dev)) {
                  break;
               }     
-              if (bsr) {
-                  Dmsg4(100, "Reposition from (file:block) %d:%d to %d:%d\n",
-                    dev->file, dev->block_num, bsr->volfile->sfile,
-                    bsr->volblock->sblock);
-                 reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
-                 rec->Block = 0;
-                  Dmsg2(100, "Now at (file:block) %d:%d\n",
-                    dev->file, dev->block_num);
-              }
-               Dmsg5(100, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n",
-                 record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, 
-                 rec->FileIndex);
                continue;              /* we don't want record, read next one */
            }
         }
         if (is_partial_record(rec)) {
-            Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+            Dmsg6(100, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
               rec_state_to_str(rec), block->BlockNumber,
               rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
            break;                    /* read second part of record */
         }
         ok = record_cb(jcr, dev, block, rec);
+        if (rec->Stream == STREAM_MD5_SIGNATURE || rec->Stream == STREAM_SHA1_SIGNATURE) {
+            Dmsg3(100, "Done FI=%d before set_eof pos %d:%d\n", rec->FileIndex,
+                 dev->file, dev->block_num);
+           if (match_set_eof(jcr->bsr, rec) && try_repositioning(jcr, rec, dev)) {
+               Dmsg2(100, "Break after match_set_eof pos %d:%d\n",
+                    dev->file, dev->block_num);
+              break;
+           }
+            Dmsg2(100, "After set_eof pos %d:%d\n", dev->file, dev->block_num);
+        }
       } /* end for loop over records */
+      Dmsg2(100, "After end records position=(file:block) %d:%d\n", dev->file, dev->block_num);
    } /* end for loop over blocks */
+// Dmsg2(100, "Position=(file:block) %d:%d\n", dev->file, dev->block_num);
 
    /* Walk down list and free all remaining allocated recs */
    for (rec=(DEV_RECORD *)recs->first(); rec; ) {
@@ -266,11 +243,68 @@ int read_records(JCR *jcr,  DEVICE *dev,
       rec = nrec;
    }
    delete recs;
-   print_block_errors(jcr, block);
+   print_block_read_errors(jcr, block);
    free_block(block);
    return ok;
 }
 
+/*
+ * See if we can reposition.
+ *   Returns:  1 if at end of volume
+ *            0 otherwise
+ */
+static int try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev)
+{
+   BSR *bsr;
+   bsr = find_next_bsr(jcr->bsr, dev);
+   if (bsr == NULL && jcr->bsr->mount_next_volume) {
+      Dmsg0(100, "Would mount next volume here\n");
+      Dmsg2(100, "Current postion (file:block) %d:%d\n",
+        dev->file, dev->block_num);
+      jcr->bsr->mount_next_volume = false;
+      dev->state |= ST_EOT;
+      rec->Block = 0;
+      return 1;
+   }    
+   if (bsr) {
+      if (verbose > 1) {
+         Jmsg(jcr, M_INFO, 0, "Reposition from (file:block) %d:%d to %d:%d\n",
+           dev->file, dev->block_num, bsr->volfile->sfile,
+           bsr->volblock->sblock);
+      }
+      Dmsg4(100, "Try_Reposition from (file:block) %d:%d to %d:%d\n",
+           dev->file, dev->block_num, bsr->volfile->sfile,
+           bsr->volblock->sblock);
+      reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
+      rec->Block = 0;
+   }
+   return 0;
+}
+
+/*
+ * Position to the first file on this volume
+ */
+static BSR *position_to_first_file(JCR *jcr, DEVICE *dev)
+{
+   BSR *bsr = NULL;
+   /*
+    * Now find and position to first file and block 
+    *  on this tape.
+    */
+   if (jcr->bsr) {
+      jcr->bsr->reposition = true;    /* force repositioning */
+      bsr = find_next_bsr(jcr->bsr, dev);
+      if (bsr && (bsr->volfile->sfile != 0 || bsr->volblock->sblock != 0)) {
+         Jmsg(jcr, M_INFO, 0, _("Forward spacing to file:block %u:%u.\n"), 
+           bsr->volfile->sfile, bsr->volblock->sblock);
+         Dmsg2(100, "Forward spacing to file:block %u:%u.\n", 
+           bsr->volfile->sfile, bsr->volblock->sblock);
+        reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
+      }
+   }
+   return bsr;
+}
+
 
 static void handle_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
 {
index f00207547e1d47500c600d40a5a7bdb33e56bd8a..dd3047d478af6b6e1bfa893ffd9a9cda292fc2e8 100644 (file)
@@ -77,6 +77,7 @@
  * 
  *  This is the memory structure for the record header.
  */
+struct BSR;                           /* satisfy forward reference */
 struct DEV_RECORD {
    dlink link;                        /* link for chaining in read_record.c */
    /* File and Block are always returned during reading
@@ -91,6 +92,7 @@ struct DEV_RECORD {
    uint32_t data_len;                 /* current record length */
    uint32_t remainder;                /* remaining bytes to read/write */
    uint32_t state;                    /* state bits */
+   BSR *bsr;                          /* pointer to bsr that matched */
    uint8_t  ser_buf[WRITE_RECHDR_LENGTH];   /* serialized record header goes here */
    POOLMEM *data;                     /* Record data. This MUST be a memory pool item */
 };           
index 196f31ac556c2d4923644e1b5dacf1c1913ca0fd..161628ea4f3f24506b71631b823db2de16bd8ab4 100644 (file)
@@ -44,6 +44,9 @@ extern struct s_last_job last_job;
 
 /* Forward referenced functions */
 static void send_blocked_status(JCR *jcr, DEVICE *dev);
+static void list_terminated_jobs(void *arg);
+static void sendit(char *msg, int len, void *arg);
+static char *level_to_str(int level);
 
 
 /*
@@ -61,21 +64,18 @@ int status_cmd(JCR *jcr)
    bnet_fsend(user, "\n%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
              HOST_OS, DISTNAME, DISTVER);
    bstrftime(dt, sizeof(dt), daemon_start_time);
+   strcpy(dt+7, dt+9);               /* cut century */
    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[30];
 
-      bstrftime(dt, sizeof(dt), last_job.end_time);
-      bnet_fsend(user, _("Last Job %s finished at %s\n"), last_job.Job, dt);
-
-      jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
-      bnet_fsend(user, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
-          edit_uint64_with_commas(last_job.JobFiles, b1),
-          edit_uint64_with_commas(last_job.JobBytes, b2),
-          termstat);
-   }
+   /*
+    * List terminated jobs
+    */
+   list_terminated_jobs(user);
 
+   /*
+    * List devices
+    */
    LockRes();
    for (device=NULL;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
       for (dev=device->dev; dev; dev=dev->next) {
@@ -167,7 +167,7 @@ int status_cmd(JCR *jcr)
       bnet_fsend(user, _("No jobs running.\n"));
    }
 
-#ifdef full_status
+#ifdef xfull_status
    bnet_fsend(user, "\n\n");
    dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
 #endif
@@ -204,4 +204,177 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev)
    default:
       break;
    }
+   if (debug_level > 1) {
+      bnet_fsend(user, _("Configured device capabilities:\n"));
+      bnet_fsend(user, "%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
+      bnet_fsend(user, "%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
+      bnet_fsend(user, "%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
+      bnet_fsend(user, "%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
+      bnet_fsend(user, "%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
+      bnet_fsend(user, "%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
+      bnet_fsend(user, "%sREM ", dev->capabilities & CAP_REM ? "" : "!");
+      bnet_fsend(user, "%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
+      bnet_fsend(user, "%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
+      bnet_fsend(user, "%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
+      bnet_fsend(user, "%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
+      bnet_fsend(user, "%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
+      bnet_fsend(user, "\n");
+
+      bnet_fsend(user, _("Device status:\n"));
+      bnet_fsend(user, "%sOPENED ", dev->state & ST_OPENED ? "" : "!");
+      bnet_fsend(user, "%sTAPE ", dev->state & ST_TAPE ? "" : "!");
+      bnet_fsend(user, "%sLABEL ", dev->state & ST_LABEL ? "" : "!");
+      bnet_fsend(user, "%sMALLOC ", dev->state & ST_MALLOC ? "" : "!");
+      bnet_fsend(user, "%sAPPEND ", dev->state & ST_APPEND ? "" : "!");
+      bnet_fsend(user, "%sREAD ", dev->state & ST_READ ? "" : "!");
+      bnet_fsend(user, "%sEOT ", dev->state & ST_EOT ? "" : "!");
+      bnet_fsend(user, "%sWEOT ", dev->state & ST_WEOT ? "" : "!");
+      bnet_fsend(user, "%sEOF ", dev->state & ST_EOF ? "" : "!");
+      bnet_fsend(user, "%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");
+      bnet_fsend(user, "%sSHORT ", dev->state & ST_SHORT ? "" : "!");
+      bnet_fsend(user, "\n");
+
+      bnet_fsend(user, _("Device parameters:\n"));
+      bnet_fsend(user, "Device name: %s\n", dev->dev_name);
+      bnet_fsend(user, "File=%u block=%u\n", dev->file, dev->block_num);
+      bnet_fsend(user, "Min block=%u Max block=%u\n", dev->min_block_size, dev->max_block_size);
+   }
+
+}
+
+static void list_terminated_jobs(void *arg)
+{
+   char dt[MAX_TIME_LENGTH], b1[30], b2[30];
+   char level[10];
+   struct s_last_job *je;
+   char *msg;
+
+   if (last_job.NumJobs == 0) {
+      msg = _("No Terminated Jobs.\n"); 
+      sendit(msg, strlen(msg), arg);
+      return;
+   }
+   lock_last_jobs_list();
+   msg =  _("\nTerminated Jobs:\n"); 
+   sendit(msg, strlen(msg), arg);
+   msg =  _(" JobId  Level   Files          Bytes Status   Finished        Name \n");
+   sendit(msg, strlen(msg), arg);
+   msg = _("======================================================================\n"); 
+   sendit(msg, strlen(msg), arg);
+   for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) {
+      char JobName[MAX_NAME_LENGTH];
+      char *termstat;
+      char buf[1000];
+
+      bstrftime(dt, sizeof(dt), je->end_time);
+      strcpy(dt+7, dt+9);     /* cut century */
+      switch (je->JobType) {
+      case JT_ADMIN:
+      case JT_RESTORE:
+         bstrncpy(level, "    ", sizeof(level));
+        break;
+      default:
+        bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
+        level[4] = 0;
+        break;
+      }
+      switch (je->JobStatus) {
+      case JS_Created:
+         termstat = "Created";
+        break;
+      case JS_FatalError:
+      case JS_ErrorTerminated:
+         termstat = "Error";
+        break;
+      case JS_Differences:
+         termstat = "Diffs";
+        break;
+      case JS_Canceled:
+         termstat = "Cancel";
+        break;
+      case JS_Terminated:
+         termstat = "OK";
+        break;
+      default:
+         termstat = "Other";
+        break;
+      }
+      bstrncpy(JobName, je->Job, sizeof(JobName));
+      /* There are three periods after the Job name */
+      char *p;
+      for (int i=0; i<3; i++) {
+         if ((p=strrchr(JobName, '.')) != NULL) {
+           *p = 0;
+        }
+      }
+      bsnprintf(buf, sizeof(buf), _("%6d  %-4s %8s %14s %-7s  %-8s %s\n"), 
+        je->JobId,
+        level, 
+        edit_uint64_with_commas(je->JobFiles, b1),
+        edit_uint64_with_commas(je->JobBytes, b2), 
+        termstat,
+        dt, JobName);
+      sendit(buf, strlen(buf), arg);
+   }
+   sendit("\n", 1, arg);
+   unlock_last_jobs_list();
+}
+
+/*
+ * Convert Job Level into a string
+ */
+static char *level_to_str(int level) 
+{
+   char *str;
+
+   switch (level) {
+   case L_BASE:
+      str = _("Base");
+   case L_FULL:
+      str = _("Full");
+      break;
+   case L_INCREMENTAL:
+      str = _("Incremental");
+      break;
+   case L_DIFFERENTIAL:
+      str = _("Differential");
+      break;
+   case L_SINCE:
+      str = _("Since");
+      break;
+   case L_VERIFY_CATALOG:
+      str = _("Verify Catalog");
+      break;
+   case L_VERIFY_INIT:
+      str = _("Init Catalog");
+      break;
+   case L_VERIFY_VOLUME_TO_CATALOG:
+      str = _("Volume to Catalog");
+      break;
+   case L_VERIFY_DISK_TO_CATALOG:
+      str = _("Disk to Catalog");
+      break;
+   case L_VERIFY_DATA:
+      str = _("Data");
+      break;
+   case L_NONE:
+      str = " ";
+      break;
+   default:
+      str = _("Unknown Job Level");
+      break;
+   }
+   return str;
+}
+
+/*
+ * 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);
 }
index 826b7fbd18b496758ea2ebe9d5cdb829109ee801..a83e70bd015f9ba42108b5ee220cbedf7438f847 100644 (file)
@@ -94,7 +94,6 @@ int main (int argc, char *argv[])
    textdomain("bacula-sd");
    init_msg(NULL, NULL);
    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) {
@@ -107,48 +106,48 @@ int main (int argc, char *argv[])
 
    while ((ch = getopt(argc, argv, "c:d:fg:stu:v?")) != -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 'c':                    /* configuration file */
+        if (configfile != NULL) {
+           free(configfile);
+        }
+        configfile = bstrdup(optarg);
+        break;
 
-         case 'f':                    /* run in foreground */
-           foreground = TRUE;
-           break;
+      case 'd':                    /* debug level */
+        debug_level = atoi(optarg);
+        if (debug_level <= 0) {
+           debug_level = 1; 
+        }
+        break;
 
-         case 'g':                    /* set group id */
-           gid = optarg;
-           break;
+      case 'f':                    /* run in foreground */
+        foreground = TRUE;
+        break;
 
-         case 's':                    /* no signals */
-           no_signals = TRUE;
-           break;
+      case 'g':                    /* set group id */
+        gid = optarg;
+        break;
 
-         case 't':
-           test_config = TRUE;
-           break;
+      case 's':                    /* no signals */
+        no_signals = TRUE;
+        break;
 
-         case 'u':                    /* set uid */
-           uid = optarg;
-           break;
+      case 't':
+        test_config = TRUE;
+        break;
 
-         case 'v':                    /* verbose */
-           verbose++;
-           break;
+      case 'u':                    /* set uid */
+        uid = optarg;
+        break;
 
-         case '?':
-        default:
-           usage();
+      case 'v':                    /* verbose */
+        verbose++;
+        break;
 
+      case '?':
+      default:
+        usage();
+        break;
       }  
    }
    argc -= optind;
@@ -335,16 +334,47 @@ void terminate_stored(int sig)
 {
    static int in_here = FALSE;
    DEVRES *device;
+   JCR *jcr;
 
    if (in_here) {                    /* prevent loops */
       exit(1);
    }
    in_here = TRUE;
 
+   if (sig == SIGTERM) {             /* normal shutdown request? */
+      /*
+       * This is a normal shutdown request. We wiffle through
+       *   all open jobs canceling them and trying to wake
+       *   them up so that they will report back the correct
+       *   volume status.
+       */
+      lock_jcr_chain();
+      for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+        BSOCK *fd;
+        free_locked_jcr(jcr);
+        if (jcr->JobId == 0) {
+           continue;                 /* ignore console */
+        }
+        set_jcr_job_status(jcr, JS_Canceled);
+        fd = jcr->file_bsock;  
+        if (fd) {
+           fd->timed_out = TRUE;
+            Dmsg1(100, "killing JobId=%d\n", jcr->JobId);
+           pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+           if (jcr->device && jcr->device->dev && jcr->device->dev->dev_blocked) {
+              pthread_cond_signal(&jcr->device->dev->wait_next_vol);
+           }
+           bmicrosleep(0, 50000);
+         }
+      }
+      unlock_jcr_chain();
+      bmicrosleep(0, 500000);        /* give them 1/2 sec to clean up */
+   }
+
    delete_pid_file(me->pid_directory, "bacula-sd", me->SDport);
    stop_watchdog();
 
-   Dmsg0(200, "In terminate_stored()\n");
+   Dmsg1(200, "In terminate_stored() sig=%d\n", sig);
 
    LockRes();
    for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
index 28c1d578721f35ab0af809d9117a7976b64c5e8b..972fd65344918f473d710b1af7d8a12f6d743155 100644 (file)
@@ -90,8 +90,10 @@ static struct res_items dev_items[] = {
    {"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},
    {"bsfateom",              store_yesno,  ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
+   {"twoeof",                store_yesno,  ITEM(res_dev.cap_bits), CAP_TWOEOF, 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},
+   {"fastforwardspacefile",  store_yesno,  ITEM(res_dev.cap_bits), CAP_FASTFSF, 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},
@@ -100,7 +102,7 @@ static struct res_items dev_items[] = {
    {"autochanger",           store_yesno,  ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
-   {"maximumchangerwait",    store_pint,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 2 * 60},
+   {"maximumchangerwait",    store_pint,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"maximumopenwait",       store_pint,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"maximumopenvolumes",    store_pint,   ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
    {"offlineonunmount",      store_yesno,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
@@ -147,77 +149,77 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
       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 SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
-           res->res_store.hdr.name, NPRT(res->res_store.SDaddr),
-           res->res_store.SDport, res->res_store.SDDport,
-           edit_utime(res->res_store.heartbeat_interval, buf));
-        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);
-        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, _("Warning: unknown resource type %d\n"), type);
-        break;
+   case R_DIRECTOR:
+      sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
+      break;
+   case R_STORAGE:
+      sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
+        res->res_store.hdr.name, NPRT(res->res_store.SDaddr),
+        res->res_store.SDport, res->res_store.SDDport,
+        edit_utime(res->res_store.heartbeat_interval, buf));
+      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) {
+         bstrncat(buf, "CAP_EOF ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_BSR) {
+         bstrncat(buf, "CAP_BSR ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_BSF) {
+         bstrncat(buf, "CAP_BSF ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_FSR) {
+         bstrncat(buf, "CAP_FSR ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_FSF) {
+         bstrncat(buf, "CAP_FSF ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_EOM) {
+         bstrncat(buf, "CAP_EOM ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_REM) {
+         bstrncat(buf, "CAP_REM ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_RACCESS) {
+         bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
+         bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_LABEL) {
+         bstrncat(buf, "CAP_LABEL ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_ANONVOLS) {
+         bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
+      }
+      if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
+         bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
+      }
+      bstrncat(buf, "\n", sizeof(buf));
+      sendit(sock, buf);
+      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, _("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);
index 14ac5972f5462d530a245785925cc789ea684c23..7cf81d72d8e0a936c1631d07eb7923030c832ebe 100644 (file)
@@ -75,7 +75,7 @@ struct DEVRES {
    char *device_name;                 /* Archive device name */
    char *changer_name;                /* Changer device name */
    char *changer_command;             /* Changer command  -- external program */
-   int  cap_bits;                     /* Capabilities of this device */
+   uint32_t cap_bits;                 /* Capabilities of this device */
    uint32_t max_changer_wait;         /* Changer timeout */
    uint32_t max_rewind_wait;          /* maximum secs to wait for rewind */
    uint32_t max_open_wait;            /* maximum secs to wait for open */
index b79081afbf1b149acf8170d90363cd09938dd350..8ace8a7a817824eeec151ea269c73a683861078d 100644 (file)
@@ -51,12 +51,12 @@ static void usage()
 "       -           read pattern(s) from stdin\n"
 "       -?          print this message.\n"
 "\n"
-"Patterns are file inclusion -- normally directories.\n"
+"Patterns are used for file inclusion -- normally directories.\n"
 "Debug level >= 1 prints each file found.\n"
 "Debug level >= 10 prints path/file for catalog.\n"
-"Errors always printed.\n"
-"Files/paths truncated is number with len > 255.\n"
-"Truncation is only in catalog.\n"
+"Errors are always printed.\n"
+"Files/paths truncated is the number of files/paths with len > 255.\n"
+"Truncation is only in the catalog.\n"
 "\n"));
 
    exit(1);
index 51d178023c820ae5fc76984e36d7258bb8876023..236d3b7d8f27ff302fc029e22ea958e1b2dfaeb4 100755 (executable)
@@ -71,28 +71,28 @@ main (int argc, char *const *argv)
 
    while ((ch = getopt(argc, argv, "ad:e:i:?")) != -1) {
       switch (ch) {
-         case 'a':                    /* print extended attributes *debug* */
-           attrs = 1;
-           break;
-
-         case 'd':                    /* set debug level */
-           debug_level = atoi(optarg);
-           if (debug_level <= 0) {
-              debug_level = 1; 
-           }
-           break;
+      case 'a':                       /* print extended attributes *debug* */
+        attrs = 1;
+        break;
+
+      case 'd':                       /* set debug level */
+        debug_level = atoi(optarg);
+        if (debug_level <= 0) {
+           debug_level = 1; 
+        }
+        break;
 
-         case 'e':                    /* exclude patterns */
-           exc = optarg;
-           break;
+      case 'e':                       /* exclude patterns */
+        exc = optarg;
+        break;
 
-         case 'i':                    /* include patterns */
-           inc = optarg;
-           break;
+      case 'i':                       /* include patterns */
+        inc = optarg;
+        break;
 
-         case '?':
-        default:
-           usage();
+      case '?':
+      default:
+        usage();
 
       }  
    }
@@ -200,6 +200,10 @@ static void print_ls_output(char *fname, char *link, int type, struct stat *stat
    char *p, *f;
    int n;
 
+   if (type == FT_LNK) {
+      statp->st_mtime = 0;
+      statp->st_mode |= 0777;
+   }
    p = encode_mode(statp->st_mode, buf);
    n = sprintf(p, " %2d ", (uint32_t)statp->st_nlink);
    p += n;
@@ -213,11 +217,7 @@ static void print_ls_output(char *fname, char *link, int type, struct stat *stat
       n = sprintf(p, "     ");
    }
    p += n;
-   if (type != FT_LNK) {
-      p = encode_time(statp->st_mtime, p);
-   } else {
-      p = encode_time(0, p);
-   }
+   p = encode_time(statp->st_mtime, p);
    *p++ = ' ';
    /* Copy file name */
    for (f=fname; *f && (p-buf) < (int)sizeof(buf); )
index 47e2bf31fa5c6b71bb3d8540f635469cdf86c647..623ae811d77b7c8036c5da2e04b3311389c9782f 100644 (file)
@@ -1,9 +1,9 @@
 /* */
 #undef  VERSION
-#define VERSION "1.32"
+#define VERSION "1.32f-4"
 #define VSTRING "1"
-#define BDATE   "26 Sep 2003"
-#define LSMDATE "26Sep03"
+#define BDATE   "24 Jan 2004"
+#define LSMDATE "24Jan04"
 
 /* Debug flags */
 #undef  DEBUG
diff --git a/regress/.cvsignore b/regress/.cvsignore
deleted file mode 100644 (file)
index 120006c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-build
-bin
-test.out
-weird-files
-diff
-tmp
-working
diff --git a/regress/README b/regress/README
deleted file mode 100644 (file)
index ad5056c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-     Bacula Regression
-     Kern Sibbald
-     April 2003
-
-This is Bacula's regression script directory.  At this time
-(May 2003), it is still in development, so all the tests are
-not complete.
-
-To set it up, first edit Makefile and set BACULA-SOURCE to point
-to your source.
-
-!!!!!!!!!! IMPORTANT !!!!!!!!
-Second, edit the EMAIL address in the Makefile to be your
-email address and not mine or I will get LOTS of unwanted
-email!
-
-Third, edit the DEPKGS path in the Makefile to point to the
-depkgs directory.
-
-Fourth, make sure that depkgs is pre-built if it isn't 
-already: (cd your-depkgs; make sqlite).
-
-Then do:
-
-   make setup
-
-You run the above one time.  This will copy the Bacula
-source, configure, build it, and configure all the scripts
-and conf files.  If you change your source, you will need
-to redo this command. 
-
-Then you can run any of the tests in the tests subdirectory.
-Each test whose name ends in -root requires you to be root for
-a resonable run.  Each test is totally independent of any other
-test. Aside from the required "make setup", each test is totally
-self-initalizing and should clean up after itself.
-
-Not all the tests yet report OK.  This is simply because there are
-some spurious differences that I haven't yet taken the time to
-eliminate.  The working scrips as of 24 Apr 03 are:
-
-backup-bacula-test
-sparse-test
-compressed-test
-sparse-compressed-test
-two-jobs-test
-wierd-files-test
-verify-vol-test
-
-The tests expect you to execute them from the main regress 
-directory!               
-
-You can run them individually as:
-
-   tests/two-jobs-test
-
-or all non-root tests (my normal testing under my account)
-
-  ./all-non-root-tests
-
-or all tests (I only run these before a production release):
-
-   su
-   ./all-tests
-
-
-after running the root tests, while still root, it is a good idea
-to do:
-
-   make reset
-
-this cleans up any files that may be created with root permissions.
-
-If you want to add more tests, do so by putting the shell script 
-in the tests subdirectory. Be careful when adding (or better not)
-new clients, pools, and such to the test-bacula-dir.conf.in file
-as it may invalidate a good number of tests, which respond to
-questions by answering with a number (i.e. the order of the selection
-list is known). It might be better to add your own testb-bacula...
-configuration file.  
-
-To avoid re-doing a make setup if you have made a change to the
-conf files, and you do not need a new copy of the source, you can simply do:
-
-   scripts/do-sed <your-email-address>
diff --git a/regress/all-non-root-tape-tests b/regress/all-non-root-tape-tests
deleted file mode 100755 (executable)
index 13fffb0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-#
-# Run all tape tests
-#
-tests/test0
-tests/backup-bacula-tape
-tests/small-file-size-tape
-tests/two-volume-tape
-echo " "
-echo " "
-echo "Test results"
-cat test.out
-scripts/cleanup
diff --git a/regress/all-non-root-tests b/regress/all-non-root-tests
deleted file mode 100755 (executable)
index 2b2c48d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-#
-# Run all tests
-#
-tests/test0
-tests/backup-bacula-test
-tests/verify-vol-test
-tests/sparse-test
-tests/compressed-test
-tests/sparse-compressed-test
-tests/weird-files-test
-tests/two-jobs-test
-tests/two-vol-test
-tests/six-vol-test
-tests/bscan-test
-tests/weird-files2-test
-tests/concurrent-jobs-test
-tests/four-concurrent-jobs-test
-tests/bsr-opt-test
-tests/bextract-test
-tests/recycle-test
-tests/span-vol-test
-tests/restore-by-file-test
-echo " "
-echo " "
-echo "Test results"
-cat test.out
-scripts/cleanup
diff --git a/regress/all-root-tests b/regress/all-root-tests
deleted file mode 100755 (executable)
index 9eb8995..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-#
-# Run all root tests
-#
-tests/dev-test-root
-tests/etc-test-root
-tests/lib-test-root
-cat test.out
-scripts/cleanup
diff --git a/regress/all-tape-and-file-tests b/regress/all-tape-and-file-tests
deleted file mode 100755 (executable)
index 8579344..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# Run all tests
-#
-tests/test0
-tests/backup-bacula-test
-tests/verify-vol-test
-tests/sparse-test
-tests/compressed-test
-tests/sparse-compressed-test
-tests/weird-files-test
-tests/two-jobs-test
-tests/two-vol-test
-tests/six-vol-test
-tests/bscan-test
-tests/weird-files2-test
-tests/concurrent-jobs-test
-tests/four-concurrent-jobs-test
-tests/bsr-opt-test
-tests/bextract-test
-tests/recycle-test
-tests/span-vol-test
-tests/backup-bacula-tape
-tests/small-file-size-tape
-tests/two-volume-tape
-echo " "
-echo " "
-echo "Test results"
-cat test.out
-scripts/cleanup
diff --git a/regress/all-tests b/regress/all-tests
deleted file mode 100755 (executable)
index b1b2b35..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-#
-# Run all tests
-#
-./all-non-root-tests
-./all-root-tests
-cat test.out
-scripts/cleanup
diff --git a/regress/scripts/.cvsignore b/regress/scripts/.cvsignore
deleted file mode 100644 (file)
index 0253541..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-bacula-dir.conf
-bacula-fd.conf
-bacula-sd.conf
-console.conf
-test-bacula-dir.conf
-test-bacula-fd.conf
-test-bacula-sd.conf
-test-console.conf
-testa-bacula-dir.conf
-bacula-dir-tape.conf
-bacula-sd-tape.conf
-cleanup-tape
diff --git a/regress/scripts/bacula-dir-tape.conf.in b/regress/scripts/bacula-dir-tape.conf.in
deleted file mode 100644 (file)
index da9ac34..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#
-# 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 1.30 (12 April 2003) -- redhat 7.3
-#
-#  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 = 8101                # where we listen for UA connections
-  QueryFile = "@scriptdir@/query.sql"
-  WorkingDirectory = "@working_dir@"
-  PidDirectory = "@piddir@"
-  Maximum Concurrent Jobs = 4
-  Password = "pNvX1WiXnwv2C/F7E52LGvw6rKjbbPvu2kyuPa9pVaL3"
-  Messages = Standard
-}
-
-#
-# Define the main nightly save backup job
-#   By default, this job will back up to disk in /tmp
-Job {
-  Name = "NightlySave"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = DDS-4
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-  Maximum Concurrent Jobs = 4
-}
-
-
-# Standard Restore template, to be changed by Console program
-Job {
-  Name = "RestoreFiles"
-  Type = Restore
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = DDS-4
-  Messages = Standard
-  Pool = Default
-  Where = /tmp/bacula-restores
-}
-
-
-# List of files to be backed up
-FileSet {
-  Name = "Full Set"
-  Include = signature=MD5 { 
-    </tmp/file-list
-  }
-}
-
-
-#
-# When to do the backups, full backup on first sunday of the month,
-#  differential (i.e. incremental since full) every other sunday,
-#  and incremental backups other days
-Schedule {
-  Name = "WeeklyCycle"
-  Run = Full 1st sun at 1:05
-  Run = Differential 2nd-5th sun at 1:05
-  Run = Incremental mon-sat at 1:05
-}
-
-# Client (File Services) to backup
-Client {
-  Name = @hostname@-fd
-  Address = @hostname@
-  FDPort = 8102
-  Catalog = MyCatalog
-  Password = "xevrjURYoCHhn26RaJoWbeWXEY/a3VqGKp/37tgWiuHc"          # password for FileDaemon
-  File Retention = 30d                # 30 days
-  Job Retention = 180d                # six months
-  AutoPrune = yes                     # Prune expired Jobs/Files
-  Maximum Concurrent Jobs = 4
-}
-
-# Definition of DDS tape storage device
-Storage {
-  Name = DDS-4
-  Address = @hostname@                # N.B. Use a fully qualified name here
-  SDPort = 8103
-  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"          # password for Storage daemon
-  Device = DDS-4                      # must be same as Device in Storage daemon
-  Media Type = DDS-4                  # must be same as MediaType in Storage daemon
-  AutoChanger = yes
-}
-
-
-# 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 localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
-  operatorcommand = "@sbindir@/smtp -h localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: Intervention needed for %j\" %r"
-  MailOnError = @job_email@ = all
-  operator = @job_email@ = mount
-  console = all, !skipped
-#
-# WARNING! the following will create a file that you must cycle from
-#          time to time as it will grow indefinitely. However, it will
-#          also keep all your messages if the scroll off the console.
-#
-  append = "@working_dir@/log" = all, !skipped
-}
-
-    
-# Default pool definition
-Pool {
-  Name = Default
-  Pool Type = Backup
-  Recycle = yes                       # Bacula can automatically recycle Volumes
-  AutoPrune = yes                     # Prune expired volumes
-  Volume Retention = 365d             # one year
-  Accept Any Volume = yes             # write on any volume in the pool
-}
diff --git a/regress/scripts/bacula-sd-tape.conf.in b/regress/scripts/bacula-sd-tape.conf.in
deleted file mode 100644 (file)
index f78dcb6..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Default Bacula Storage Daemon Configuration file
-#
-#  For Bacula release 1.30 (12 April 2003) -- redhat 7.3
-#
-# 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
-  SDPort = 8103                  # 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 = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-}
-
-#
-# Devices supported by this Storage daemon
-# To connect, the Director's bacula-dir.conf must have the
-#  same Name and MediaType. 
-#
-
-Device {
-  Name = DDS-4                     # 
-  Media Type = DDS-4
-  Changer Device = @autochanger@
-  Changer Command ="@scriptdir@/mtx-changer %c %o %S %a"
-  Archive Device = @tape_drive@
-  AutomaticMount = yes;               # when device opened, read it
-  AlwaysOpen = yes;
-  RemovableMedia = yes;
-# Maximum File Size = 1000000
-}
-
-# 
-# Send all messages to the Director, 
-# mount messages also are sent to the email address
-#
-Messages {
-  Name = Standard
-  director = @hostname@-dir = all
-}
diff --git a/regress/scripts/bacula-sd.conf.in b/regress/scripts/bacula-sd.conf.in
deleted file mode 100644 (file)
index 47422aa..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# Default Bacula Storage Daemon Configuration file
-#
-#  For Bacula release 1.32 (20 Sep 2003) -- redhat 9
-#
-# 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 = rufus-sd
-  SDPort = 8103                  # Director's port      
-  WorkingDirectory = "/home/kern/bacula/regress/working"
-  Pid Directory = "/home/kern/bacula/regress/working"
-}
-
-#
-# List Directors who are permitted to contact Storage daemon
-#
-Director {
-  Name = rufus-dir
-  Password = "BzlEl8haeFmnv/Lv8V6zDzUBgFFQNsUtny6VkmccQpOy"
-}
-
-#
-# Devices supported by this Storage daemon
-# To connect, the Director's bacula-dir.conf must have the
-#  same Name and MediaType. 
-#
-
-Device {
-  Name = FileStorage
-  Media Type = File
-  Archive Device = @tmpdir@
-  LabelMedia = yes;                   # lets Bacula label unlabeled media
-  Random Access = Yes;
-  AutomaticMount = yes;               # when device opened, read it
-  RemovableMedia = no;
-  AlwaysOpen = no;
-}
-
-#Device {
-#  Name = DDS-4                        # 
-#  Media Type = DDS-4
-#  Archive Device = /dev/nst0
-#  AutomaticMount = yes;               # when device opened, read it
-#  AlwaysOpen = yes;
-#  RemovableMedia = yes;
-#}
-
-#
-# A very old Exabyte with no end of media detection
-#
-#Device {
-#  Name = "Exabyte 8mm"
-#  Media Type = "8mm"
-#  Archive Device = /dev/nst0
-#  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 = rufus-dir = all
-}
diff --git a/regress/scripts/cleanup b/regress/scripts/cleanup
deleted file mode 100755 (executable)
index 8bd8365..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-#
-# Cleanup left over files -- both before and after test run
-#
-rm -rf /tmp/TestVolume001 /tmp/bacula-restores /tmp/Small*
-rm -rf tmp/original tmp/bacula-restores tmp/Small* tmp/TestVolume*
-rm -rf tmp/restored tmp/largefile tmp/bscan.bsr tmp/log*.out
-rm -rf /tmp/sed_tmp /tmp/file-list
-rm -rf tmp/build tmp/restore-list
diff --git a/regress/scripts/cleanup-tape.in b/regress/scripts/cleanup-tape.in
deleted file mode 100755 (executable)
index 64ad92f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-#
-# Cleanup left over files -- both before and after test run
-#
-rm -rf /tmp/TestVolume001 /tmp/bacula-restores /tmp/Small*
-rm -rf tmp/original tmp/bacula-restores tmp/Small* tmp/TestVolume*
-rm -rf tmp/restored tmp/largefile tmp/bscan.bsr tmp/log*.out
-
-#
-# If we have an autochanger always load tape in slot 1
-#
-if ! test x@autochanger@ = x/dev/null; then
-   drive=`bin/mtx-changer @autochanger@ loaded`
-   if ! test x$drive = x1; then
-      bin/mtx-changer @autochanger@ unload
-      bin/mtx-changer @autochanger@ load 1
-   fi
-fi
-
-mt -f @tape_drive@ rewind
-mt -f @tape_drive@ weof
diff --git a/regress/scripts/copy-confs b/regress/scripts/copy-confs
deleted file mode 100755 (executable)
index ee77a34..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-/bin/cp -f scripts/bacula-dir.conf bin/bacula-dir.conf
-/bin/cp -f scripts/bacula-sd.conf bin/bacula-sd.conf
-/bin/cp -f scripts/bacula-fd.conf bin/bacula-fd.conf
-/bin/cp -f scripts/console.conf bin/console.conf
diff --git a/regress/scripts/copy-tape-confs b/regress/scripts/copy-tape-confs
deleted file mode 100755 (executable)
index 28223b0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-/bin/cp -f scripts/bacula-dir-tape.conf bin/bacula-dir.conf
-/bin/cp -f scripts/bacula-sd-tape.conf bin/bacula-sd.conf
-/bin/cp -f scripts/test-bacula-fd.conf bin/bacula-fd.conf
-/bin/cp -f scripts/test-console.conf bin/console.conf
diff --git a/regress/scripts/copy-test-confs b/regress/scripts/copy-test-confs
deleted file mode 100755 (executable)
index 45a30a2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-/bin/cp -f scripts/test-bacula-dir.conf bin/bacula-dir.conf
-/bin/cp -f scripts/test-bacula-sd.conf bin/bacula-sd.conf
-/bin/cp -f scripts/test-bacula-fd.conf bin/bacula-fd.conf
-/bin/cp -f scripts/test-console.conf bin/console.conf
diff --git a/regress/scripts/copy-testa-confs b/regress/scripts/copy-testa-confs
deleted file mode 100755 (executable)
index 0574b9a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-/bin/cp -f scripts/testa-bacula-dir.conf bin/bacula-dir.conf
-/bin/cp -f scripts/test-bacula-sd.conf bin/bacula-sd.conf
-/bin/cp -f scripts/test-bacula-fd.conf bin/bacula-fd.conf
-/bin/cp -f scripts/test-console.conf bin/console.conf
diff --git a/regress/scripts/do_sed b/regress/scripts/do_sed
deleted file mode 100755 (executable)
index 165a204..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-#
-if test $# != 3 ; then
-   echo "First arg must be email name"
-   echo "  and the second must be a tape drive"
-   echo "  and the third must be a tape control name or /dev/null"
-   exit 1
-fi
-out="/tmp/sed_tmp"
-cwd=`pwd`
-host=`hostname | tr '.' ' ' | cut -f 1 -d ' '`
-if test x$host = x ; then
-   host=localhost 
-fi
-# Create sed command script
-echo "s%@sbindir@%${cwd}/bin%g" >${out}
-echo "s%@scriptdir@%${cwd}/bin%g" >>${out}
-echo "s%@working_dir@%${cwd}/working%g" >>${out}
-echo "s%@piddir@%${cwd}/working%g" >>${out}
-echo "s%@subsysdir@%${cwd}/working%g" >>${out}
-echo "s%@job_email@%${1}%g" >>${out}
-echo "s%@tape_drive@%${2}%g" >>${out}
-echo "s%@autochanger@%${3}%g" >>${out}
-echo "s%@tmpdir@%${cwd}/tmp%g" >>${out}
-echo "s%@hostname@%${host}%g" >>${out}
-
-# process .in files with sed script
-sed -f ${out} ${cwd}/scripts/test-bacula-dir.conf.in >${cwd}/scripts/test-bacula-dir.conf
-sed -f ${out} ${cwd}/scripts/testa-bacula-dir.conf.in >${cwd}/scripts/testa-bacula-dir.conf
-sed -f ${out} ${cwd}/scripts/test-bacula-fd.conf.in >${cwd}/scripts/test-bacula-fd.conf
-sed -f ${out} ${cwd}/scripts/test-bacula-sd.conf.in >${cwd}/scripts/test-bacula-sd.conf
-sed -f ${out} ${cwd}/scripts/test-console.conf.in >${cwd}/scripts/test-console.conf
-sed -f ${out} ${cwd}/scripts/bacula-dir-tape.conf.in >${cwd}/scripts/bacula-dir-tape.conf
-sed -f ${out} ${cwd}/scripts/bacula-sd-tape.conf.in >${cwd}/scripts/bacula-sd-tape.conf
-sed -f ${out} ${cwd}/scripts/cleanup-tape.in >${cwd}/scripts/cleanup-tape
-cp ${cwd}/bin/bacula-sd.conf /tmp/bac$$
-sed s%/tmp%${cwd}/tmp%g /tmp/bac$$ >${cwd}/bin/bacula-sd.conf
-chmod 777 ${cwd}/scripts/cleanup-tape
-
-rm -f ${out}
-rm -f /tmp/bac$$
diff --git a/regress/scripts/exclude-dev-test b/regress/scripts/exclude-dev-test
deleted file mode 100644 (file)
index 4165ea1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-dev/ptmx
-dev/pts
-dev/rd/c5d2
-dev/rd
-dev/shm
diff --git a/regress/scripts/exclude-etc-test b/regress/scripts/exclude-etc-test
deleted file mode 100644 (file)
index f59ca8d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-etc/mail/statistics
diff --git a/regress/scripts/exclude-lib-test b/regress/scripts/exclude-lib-test
deleted file mode 100644 (file)
index 5be32f4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-lib/ld-2.2.5.so
-lib/libtermcap.so.2.0.8
-lib/libc-2.2.5.so
-lib/libnsl-2.2.5.so
-lib/libnss_files-2.2.5.so
diff --git a/regress/scripts/regress-config b/regress/scripts/regress-config
deleted file mode 100755 (executable)
index e03e84b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-#
-# This is the configuration script for regression testing
-#
-
-CFLAGS="-g -O2 -Wall" \
- ./configure \
-    --sbindir=$1/bin \
-    --sysconfdir=$1/bin \
-    --with-pid-dir=$1/working \
-    --with-subsys-dir=$1/working \
-    --enable-smartalloc \
-    --disable-readline \
-    --with-sqlite=$2 \
-    --with-working-dir=$1/working \
-    --with-dump-email=$3 \
-    --with-job-email=$3 \
-    --with-baseport=8101 
-
-exit 0
diff --git a/regress/scripts/setup b/regress/scripts/setup
deleted file mode 100755 (executable)
index 48d7123..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/sh
-#
-# Script to setup running Bacula regression tests
-#
-cwd=`pwd`
-if [ $# != 3 ] ; then
-   echo "Incorrect number of arguments. Need:"
-   echo "setup bacula-src depkgs email-address"
-   echo " "
-   exit 1
-fi
-if [ ! -d $1 ] ; then
-   echo "Arg 1 must be a Bacula release directory."
-   echo " "
-   exit 1
-fi
-if [ ! -d $2 ] ; then
-   cd ..
-   cwd=`pwd`
-   echo "The regression scripts require DEPKGS as arg 2 but not found!" 
-   echo " "
-   exit 1
-fi
-rm -rf build bin
-# Copy new source
-cp -rp $1 build
-cp scripts/regress-config build
-cd build
-rm -f Makefile config.cache
-# Run Bacula configuration, make, install
-./regress-config ${cwd} $2 $3
-make
-make install
-cp src/tools/testls ../bin
-
-cd ..
-bin/bacula stop
-bin/create_sqlite_database
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-# Start and stop Bacula to ensure conf files are OK
-bin/bacula start
-bin/bacula stop
-#
-# Save Bacula default conf files for later use
-#
-cp -f bin/*.conf scripts
diff --git a/regress/scripts/test-bacula-dir.conf.in b/regress/scripts/test-bacula-dir.conf.in
deleted file mode 100644 (file)
index e584b9f..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-#
-# 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 1.30 (12 April 2003) -- redhat 7.3
-#
-#  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 = 8101                # where we listen for UA connections
-  QueryFile = "@scriptdir@/query.sql"
-  WorkingDirectory = "@working_dir@"
-  PidDirectory = "@piddir@"
-  SubSysDirectory = "@subsysdir@"
-  Maximum Concurrent Jobs = 4
-  Password = "pNvX1WiXnwv2C/F7E52LGvw6rKjbbPvu2kyuPa9pVaL3"         # Console password
-  Messages = Standard
-}
-
-#
-# Define the main nightly save backup job
-#   By default, this job will back up to disk in /tmp
-Job {
-  Name = "NightlySave"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-  Maximum Concurrent Jobs = 4
-}
-
-Job {
-  Name = "MonsterSave"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File1
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-
-Job {
-  Name = "VerifyVolume"
-  Type = Verify
-  Level = VolumeToCatalog
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-
-Job {
-  Name = "SparseTest"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="SparseSet"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-Job {
-  Name = "CompressedTest"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="CompressedSet"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Maximum Concurrent Jobs = 4
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-Job {
-  Name = "SparseCompressedTest"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="SparseCompressedSet"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-
-# Backup the catalog database (after the nightly save)
-Job {
-  Name = "BackupCatalog"
-  Type = Backup
-  Client=@hostname@-fd 
-  FileSet="Catalog"
-#  Schedule = "WeeklyCycleAfterBackup"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  # This creates an ASCII copy of the catalog
-  RunBeforeJob = "@sbindir@/make_catalog_backup -u bacula"
-  # This deletes the copy of the catalog
-  RunAfterJob  = "@sbindir@/delete_catalog_backup"
-  Write Bootstrap = "@working_dir@/BackupCatalog.bsr"
-}
-
-# Standard Restore template, to be changed by Console program
-Job {
-  Name = "RestoreFiles"
-  Type = Restore
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Where = /tmp/bacula-restores
-}
-
-
-# List of files to be backed up
-FileSet {
-  Name = "Full Set"
-  Include = signature=MD5 { 
-    </tmp/file-list
-  }
-}
-
-FileSet {
-  Name = "SparseSet"
-  Include = signature=MD5 sparse=yes { 
-    </tmp/file-list
-  }
-}
-
-FileSet {
-  Name = "CompressedSet"
-  Include = signature=MD5 compression=GZIP { 
-    </tmp/file-list
-  }
-}
-
-FileSet {
-  Name = "SparseCompressedSet"
-  Include = signature=MD5 compression=GZIP { 
-    </tmp/file-list
-  }
-}
-
-
-
-#
-# When to do the backups, full backup on first sunday of the month,
-#  differential (i.e. incremental since full) every other sunday,
-#  and incremental backups other days
-Schedule {
-  Name = "WeeklyCycle"
-  Run = Full 1st sun at 1:05
-  Run = Differential 2nd-5th sun at 1:05
-  Run = Incremental mon-sat at 1:05
-}
-
-# This schedule does the catalog. It starts after the WeeklyCycle
-Schedule {
-  Name = "WeeklyCycleAfterBackup"
-  Run = Full sun-sat at 1:10
-}
-
-# This is the backup of the catalog
-FileSet {
-  Name = "Catalog"
-  Include = signature=MD5 {
-     /home/kern/bacula/regress/bin/working/bacula.sql
-  }
-}
-
-# Client (File Services) to backup
-Client {
-  Name = @hostname@-fd
-  Address = @hostname@
-  FDPort = 8102
-  Catalog = MyCatalog
-  Password = "xevrjURYoCHhn26RaJoWbeWXEY/a3VqGKp/37tgWiuHc"          # password for FileDaemon
-  File Retention = 30d                # 30 days
-  Job Retention = 180d                # six months
-  AutoPrune = yes                     # Prune expired Jobs/Files
-  Maximum Concurrent Jobs = 4
-}
-
-# Definiton of file storage device
-Storage {
-  Name = File
-  Address = @hostname@                # N.B. Use a fully qualified name here
-  SDPort = 8103
-  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-  Device = FileStorage
-  Media Type = File
-  Maximum Concurrent Jobs = 4
-}
-
-Storage {
-  Name = File1
-  Address = @hostname@                # N.B. Use a fully qualified name here
-  SDPort = 8103
-  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-  Device = FileStorage1
-  Media Type = File1
-  Maximum Concurrent Jobs = 4
-}
-
-
-# Definition of DLT tape storage device
-#Storage {
-#  Name = DLTDrive
-#  Address = @hostname@                # N.B. Use a fully qualified name here
-#  SDPort = 8103
-#  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"          # 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@                # N.B. Use a fully qualified name here
-#  SDPort = 8103
-#  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"          # 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@                # N.B. Use a fully qualified name here
-#  SDPort = 8103
-#  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-#  Device = "Exabyte 8mm"
-#  MediaType = "8mm"
-#}
-
-
-# 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 localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
-  operatorcommand = "@sbindir@/smtp -h localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: Intervention needed for %j\" %r"
-  MailOnError = @job_email@ = all
-  operator = @job_email@ = mount
-  console = all, !skipped
-#
-# WARNING! the following will create a file that you must cycle from
-#          time to time as it will grow indefinitely. However, it will
-#          also keep all your messages if the scroll off the console.
-#
-  append = "@working_dir@/log" = all, !skipped
-}
-
-Messages {
-  Name = NoEmail
-  mailcommand = "@sbindir@/smtp -h localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
-  console = all, !skipped
-#
-# WARNING! the following will create a file that you must cycle from
-#          time to time as it will grow indefinitely. However, it will
-#          also keep all your messages if the scroll off the console.
-#
-  append = "@working_dir@/log" = all, !skipped
-}
-
-    
-# Default pool definition
-Pool {
-  Name = Default
-  Pool Type = Backup
-  Recycle = yes                       # Bacula can automatically recycle Volumes
-  AutoPrune = yes                     # Prune expired volumes
-  Volume Retention = 365d             # one year
-  Accept Any Volume = yes             # write on any volume in the pool
-}
diff --git a/regress/scripts/test-bacula-fd.conf.in b/regress/scripts/test-bacula-fd.conf.in
deleted file mode 100644 (file)
index c5554bb..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Default  Bacula File Daemon Configuration file
-#
-#  For Bacula release 1.30 (12 April 2003) -- redhat 7.3
-#
-# 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 = "xevrjURYoCHhn26RaJoWbeWXEY/a3VqGKp/37tgWiuHc"
-}
-
-#
-# "Global" File daemon configuration specifications
-#
-FileDaemon {                          # this is me
-  Name = @hostname@-fd
-  FDport = 8102                  # 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
-}
diff --git a/regress/scripts/test-bacula-sd.conf.in b/regress/scripts/test-bacula-sd.conf.in
deleted file mode 100644 (file)
index e3145d3..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# Default Bacula Storage Daemon Configuration file
-#
-#  For Bacula release 1.30 (12 April 2003) -- redhat 7.3
-#
-# 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
-  SDPort = 8103                  # 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 = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-}
-
-#
-# Devices supported by this Storage daemon
-# To connect, the Director's bacula-dir.conf must have the
-#  same Name and MediaType. 
-#
-
-Device {
-  Name = FileStorage
-  Media Type = File
-  Archive Device = @tmpdir@
-  LabelMedia = yes;                   # lets Bacula label unlabelled media
-  Random Access = Yes;
-  AutomaticMount = yes;               # when device opened, read it
-  RemovableMedia = no;
-  AlwaysOpen = no;
-}
-
-Device {
-  Name = FileStorage1
-  Media Type = File1
-  Archive Device = @tmpdir@
-  LabelMedia = yes;                   # lets Bacula label unlabelled media
-  Random Access = Yes;
-  AutomaticMount = yes;               # when device opened, read it
-  RemovableMedia = no;
-  AlwaysOpen = no;
-}
-
-
-#Device {
-#  Name = "HP DLT 80"
-#  Media Type = DLT8000
-#  Archive Device = /dev/nst0
-#  AutomaticMount = yes;               # when device opened, read it
-#  AlwaysOpen = yes;
-#  RemovableMedia = yes;
-#}
-
-#Device {
-#  Name = SDT-7000                     # 
-#  Media Type = DDS-2
-#  Archive Device = /dev/nst0
-#  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;
-#}
-
-#
-# A very old Exabyte with no end of media detection
-#
-#Device {
-#  Name = "Exabyte 8mm"
-#  Media Type = "8mm"
-#  Archive Device = /dev/nst0
-#  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
-}
diff --git a/regress/scripts/test-console.conf.in b/regress/scripts/test-console.conf.in
deleted file mode 100644 (file)
index 0fe916b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Bacula User Agent (or Console) Configuration File
-#
-
-Director {
-  Name = @hostname@-dir
-  DIRport = 8101
-  address = @hostname@
-  Password = "pNvX1WiXnwv2C/F7E52LGvw6rKjbbPvu2kyuPa9pVaL3"
-}
diff --git a/regress/scripts/testa-bacula-dir.conf.in b/regress/scripts/testa-bacula-dir.conf.in
deleted file mode 100644 (file)
index ed85af4..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#
-# TestA   Bacula Director Configuration file
-#
-#  For Bacula release 1.30 (12 April 2003) -- redhat 7.3
-#
-
-Director {                            # define myself
-  Name = @hostname@-dir
-  DIRport = 8101                # where we listen for UA connections
-  QueryFile = "@scriptdir@/query.sql"
-  WorkingDirectory = "@working_dir@"
-  PidDirectory = "@piddir@"
-  SubSysDirectory = "@subsysdir@"
-  Maximum Concurrent Jobs = 1
-  Password = "pNvX1WiXnwv2C/F7E52LGvw6rKjbbPvu2kyuPa9pVaL3"         # Console password
-  Messages = Standard
-}
-
-
-Job {
-  Name = "MultiVol"
-  Type = Backup
-  Client=@hostname@-fd 
-  Level = Full
-  FileSet="Full Set"
-  Storage = File 
-  Messages = Standard
-  Write Bootstrap = "@working_dir@/SmallVols.bsr"
-  Pool = SmallVols
-}
-
-
-Job {
-  Name = "VerifyVolume"
-  Type = Verify
-  Level = VolumeToCatalog
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Write Bootstrap = "@working_dir@/NightlySave.bsr"
-}
-
-
-
-# Standard Restore template, to be changed by Console program
-Job {
-  Name = "RestoreFiles"
-  Type = Restore
-  Client=@hostname@-fd 
-  FileSet="Full Set"
-  Storage = File
-  Messages = Standard
-  Pool = Default
-  Where = /tmp/bacula-restores
-}
-
-
-# List of files to be backed up
-FileSet {
-  Name = "Full Set"
-  Include = signature=SHA1 { 
-    </tmp/file-list
-  }
-}
-
-
-# Client (File Services) to backup
-Client {
-  Name = @hostname@-fd
-  Address = @hostname@
-  FDPort = 8102
-  Catalog = MyCatalog
-  Password = "xevrjURYoCHhn26RaJoWbeWXEY/a3VqGKp/37tgWiuHc"          # password for FileDaemon
-  File Retention = 30d                # 30 days
-  Job Retention = 180d                # six months
-  AutoPrune = yes                     # Prune expired Jobs/Files
-}
-
-# Definiton of file storage device
-Storage {
-  Name = File
-  Address = @hostname@                # N.B. Use a fully qualified name here
-  SDPort = 8103
-  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-  Device = FileStorage
-  Media Type = File
-}
-
-Storage {
-  Name = File1
-  Address = @hostname@                # N.B. Use a fully qualified name here
-  SDPort = 8103
-  Password = "ccV3lVTsQRsdIUGyab0N4sMDavui2hOBkmpBU0aQKOr9"
-  Device = FileStorage1
-  Media Type = File1
-}
-
-
-# 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 localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
-  operatorcommand = "@sbindir@/smtp -h localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: Intervention needed for %j\" %r"
-  MailOnError = @job_email@ = all
-  operator = @job_email@ = mount
-  console = all, !skipped
-
-  append = "@working_dir@/log" = all, !skipped
-}
-
-Messages {
-  Name = NoEmail
-  mailcommand = "@sbindir@/smtp -h localhost -f \"\(Bacula Regression\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
-  console = all, !skipped
-
-  append = "@working_dir@/log" = all, !skipped
-}
-
-    
-# Default pool definition
-Pool {
-  Name = Default
-  Pool Type = Backup
-  Recycle = yes                       # Bacula can automatically recycle Volumes
-  AutoPrune = yes                     # Prune expired volumes
-  Volume Retention = 365d             # one year
-  Accept Any Volume = yes             # write on any volume in the pool
-}
-
-Pool {
-  Name = SmallVols
-  Pool Type = Backup
-  Recycle = yes                       # Bacula can automatically recycle Volumes
-  AutoPrune = yes                     # Prune expired volumes
-  Volume Retention = 365d             # one year
-  Accept Any Volume = yes             # write on any volume in the pool
-  Maximum Volumes = 10
-  MaximumVolumeBytes = 10M
-  LabelFormat = Small
-}
diff --git a/regress/tests/backup-bacula-tape b/regress/tests/backup-bacula-tape
deleted file mode 100755 (executable)
index 8f669b8..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory 
-#   to a tape then restore it.
-#
-cwd=`pwd`
-bin/bacula stop  2>&1 >/dev/null
-scripts/copy-tape-confs
-scripts/cleanup-tape
-echo "${cwd}/build" >/tmp/file-list
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting Bacula tape test ==="
-echo " === Starting Bacula tape test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=DDS-4 volume=TestVolume001 slot=0
-run job=NightlySave yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Bacula tape test Bacula source failed!!! !!!!! "
-   echo "  !!!!! Bacula tape test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Bacula tape test Bacula source OK ===== "
-   echo "  ===== Bacula tape test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/backup-bacula-test b/regress/tests/backup-bacula-test
deleted file mode 100755 (executable)
index dfda3bc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-cwd=`pwd`
-scripts/copy-confs
-scripts/cleanup
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting Backup Bacula Test ==="
-echo " === Starting Backup Bacula Test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label volume=TestVolume001
-run job=Client1 yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out  
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Backup Bacula Test failed!!! !!!!! "
-   echo "  !!!!! Backup Bacula Test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Backup Bacula Test OK ===== "
-   echo "  ===== Backup Bacula Test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/bextract-test b/regress/tests/bextract-test
deleted file mode 100755 (executable)
index fc1310b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   split the archive into two volumes, then build a BSR with
-#   the restore command and use bextract to restore the files.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting bextract-test  ==="
-echo " === Starting bextract-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1 volume=TestVolume001
-label storage=File1 volume=TestVolume002
-update Volume=TestVolume001 MaxVolBytes=3000000
-run job=NightlySave storage=File1 yes
-wait
-messages
-@# 
-@# now build the bsr file
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-no
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-mkdir -p ${cwd}/tmp/bacula-restores
-bin/bextract -b working/restore.bsr -c bin/bacula-sd.conf ${cwd}/tmp ${cwd}/tmp/bacula-restores 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-diff -r build  tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! bextract-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! bextract-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== bextract-test Bacula source OK ===== "
-   echo "  ===== bextract-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/bscan-test b/regress/tests/bscan-test
deleted file mode 100755 (executable)
index aca7d1a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   split the archive into two volumes then bscan it
-#   into the catalog after the backup. It also to a limited
-#   extent tests the purge volume and delete volume commands.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting bscan-test  ==="
-echo " === Starting bscan-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1
-TestVolume001
-label storage=File1
-TestVolume002
-update Volume=TestVolume001 MaxVolBytes=3000000
-run job=NightlySave storage=File1
-yes
-wait
-messages
-@output /dev/null
-@#
-@# now purge the Volume
-@#
-purge volume=TestVolume001
-purge volume=TestVolume002
-delete volume=TestVolume001
-yes
-delete volume=TestVolume002
-yes
-messages
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-echo "volume=TestVolume001|TestVolume002" >tmp/bscan.bsr
-bin/bscan -w working -m -s -v -b tmp/bscan.bsr -c bin/bacula-sd.conf ${cwd}/tmp 2>&1 >/dev/null
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log2.out
-@# 
-@# now do a restore
-@#
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build  tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! bscan-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! bscan-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== bscan-test Bacula source OK ===== "
-   echo "  ===== bscan-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/bsr-opt-test b/regress/tests/bsr-opt-test
deleted file mode 100755 (executable)
index 381166f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   split the archive into two volumes, then restore
-#   files on only one of the volumes and ensure that
-#   the other volume is not used.  I.e. bsr optimization
-#   works.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting bsr-opt-test  ==="
-echo " === Starting bsr-opt-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1 volume=TestVolume001
-label storage=File1 volume=TestVolume002
-update Volume=TestVolume001 MaxVolBytes=3000000
-run job=NightlySave storage=File1 yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current
-unmark *
-cd ${cwd}/build/src/cats
-mark *
-ls
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep TestVolume001 working/restore.bsr
-bsrstat=$?
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build/src/cats  tmp/bacula-restores${cwd}/build/src/cats 2>&1 >/dev/null
-if [ $? != 0 -o $bsrstat != 1 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! bsr-opt-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! bsr-opt-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== bsr-opt-test Bacula source OK ===== "
-   echo "  ===== bsr-opt-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/compressed-test b/regress/tests/compressed-test
deleted file mode 100755 (executable)
index ac886b0..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory using the compressed option
-#   then restore it.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop  2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting compressed-test ==="
-echo " === Starting compressed-test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-status all
-status all
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=CompressedTest yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores
-5
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! compressed-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! compressed-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== compressed-test Bacula source OK ===== "
-   echo "  ===== compressed-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/concurrent-jobs-test b/regress/tests/concurrent-jobs-test
deleted file mode 100755 (executable)
index e02470e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-#
-# Run two jobs at the same time
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/tmp/largefile" >/tmp/file-list
-if test -c /dev/urandom ; then
-# Create 56MB file with random data
-   echo "Creating a 56MB file with random data ..."
-   dd if=/dev/urandom of=${cwd}/tmp/largefile bs=1024 count=55000
-else
-   echo "Creating a 56MB file with bacula-dir data ..."
-   dd if=bin/bacula-dir of=${cwd}/tmp/1 bs=1024 count=1000
-   cat ${cwd}/tmp/1 ${cwd}/tmp/1 ${cwd}/tmp/1 ${cwd}/tmp/1 ${cwd}/tmp/1 >${cwd}/tmp/2
-   rm -f ${cwd}/tmp/1
-   cat ${cwd}/tmp/2 ${cwd}/tmp/2 ${cwd}/tmp/2 ${cwd}/tmp/2 ${cwd}/tmp/2 >>${cwd}/tmp/3
-   rm -f ${cwd}/tmp/2
-   cat ${cwd}/tmp/3 ${cwd}/tmp/3 ${cwd}/tmp/3 ${cwd}/tmp/3 ${cwd}/tmp/3 >${cwd}/tmp/largefile
-   rm -f ${cwd}/tmp/3
-fi 
-
-echo "largefile created"
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting concurrent-jobs-test  ==="
-echo " === Starting concurrent-jobs-test  ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=CompressedTest level=Full yes
-run job=CompressedTest level=Full yes
-run job=CompressedTest level=Full yes
-run job=CompressedTest level=Full yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores
-5
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff tmp/largefile  tmp/bacula-restores${cwd}/tmp/largefile 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! concurrent-jobs-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! concurrent-jobs-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== concurrent-jobs-test Bacula source OK ===== "
-   echo "  ===== concurrent-jobs-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/dev-test-root b/regress/tests/dev-test-root
deleted file mode 100755 (executable)
index 8f21e22..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-echo " "
-echo " "
-echo " === /dev save/restore test ==="
-echo " "
-echo " "
-UID=`/usr/bin/id -u`
-if [ $UID != 0 ] ; then
-   echo " "
-   echo "You must be root to run this test."
-   echo "  ===== dev test failed!!! ===== "
-   echo "  ===== dev test failed!!! ===== " >>test.out
-   echo " "
-   exit 1
-fi
-cwd=`pwd`
-scripts/copy-test-confs
-echo "/dev" >/tmp/file-list
-rm -rf /tmp/TestVolume001 /tmp/bacula-restores
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-label storage=File
-TestVolume001
-run job=NightlySave
-yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-restore
-5
-done
-yes
-@sleep 1
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-cd /
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-etc-test dev >${cwd}/tmp/original
-cd /tmp/bacula-restores
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-etc-test dev >${cwd}/tmp/restored
-diff ${cwd}/tmp/original ${cwd}/tmp/restored 2>&1 >/dev/null
-if [ $? != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  ===== dev test failed!!! ===== "
-   echo "  ===== dev test failed!!! ===== " >>test.out
-   echo " "
-else
-   echo "  ===== dev test OK ===== "
-   echo "  ===== dev test OK ===== " >>test.out
-   cd ${cwd}
-   scripts/cleanup
-fi
diff --git a/regress/tests/etc-test-root b/regress/tests/etc-test-root
deleted file mode 100755 (executable)
index 6459026..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-echo " "
-echo " "
-echo " === /etc save/restore test ==="
-echo " "
-echo " "
-UID=`/usr/bin/id -u`
-if [ $UID != 0 ] ; then
-   echo " "
-   echo "You must be root to run this test."
-   echo "  ===== Test4 failed!!! ===== "
-   echo "  ===== Test4 failed!!! ===== " >>test.out
-   echo " "
-   exit 1
-fi
-cwd=`pwd`
-scripts/copy-test-confs
-echo "/etc" >/tmp/file-list
-rm -rf /tmp/TestVolume001 /tmp/bacula-restores
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-label storage=File
-TestVolume001
-run job=NightlySave
-yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-restore
-5
-done
-yes
-@sleep 1
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-cd /
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-etc-test etc >${cwd}/tmp/original
-cd /tmp/bacula-restores
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-etc-test etc >${cwd}/tmp/restored
-diff ${cwd}/tmp/original ${cwd}/tmp/restored 2>&1 >/dev/null
-if [ $? != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  ===== Test4 /etc failed!!! ===== "
-   echo "  ===== Test4 failed!!! ===== " >>test.out
-   echo " "
-else
-   echo "  ===== Test4 /etc OK ===== "
-   echo "  ===== Test4 OK ===== " >>test.out
-   cd ${cwd}
-   scripts/cleanup
-fi
diff --git a/regress/tests/four-concurrent-jobs-test b/regress/tests/four-concurrent-jobs-test
deleted file mode 100755 (executable)
index 0782fbd..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-#
-# Run two jobs at the same time
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting four-concurrent-jobs-test  ==="
-echo " === Starting four-concurrent-jobs-test  ===" >>working/log
-echo " "
-
-#bin/bacula start 2>&1 >/dev/null
-bin/bacula start
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1
-TestVolume001
-label storage=File1
-TestVolume002
-update Volume=TestVolume001
-6
-100000000
-@#50000000
-10
-run job=NightlySave level=Full Storage=File1
-yes
-run job=NightlySave level=Full Storage=File1
-yes
-run job=NightlySave level=Full Storage=File1
-yes
-run job=NightlySave level=Full Storage=File1
-yes
-@sleep 2
-status dir
-@sleep 5
-messages
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores
-5
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! four-concurrent-jobs-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! four-concurrent-jobs-test failed!!! !!!!! " >>test.out
-   echo " "
-   exit 1
-else
-   echo "  ===== four-concurrent-jobs-test Bacula source OK ===== "
-   echo "  ===== four-concurrent-jobs-test OK ===== " >>test.out
-   scripts/cleanup
-   exit 0
-fi
diff --git a/regress/tests/lib-test-root b/regress/tests/lib-test-root
deleted file mode 100755 (executable)
index 60320fb..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-echo " "
-echo " "
-echo " === /lib save/restore test ==="
-echo " "
-echo " "
-UID=`/usr/bin/id -u`
-if [ $UID != 0 ] ; then
-   echo " "
-   echo "You must be root to run this test."
-   echo "  ===== Test5 failed!!! ===== "
-   echo "  ===== Test5 failed!!! ===== " >>test.out
-   echo " "
-   exit 1
-fi
-cwd=`pwd`
-scripts/copy-test-confs
-echo "/lib" >/tmp/file-list
-rm -rf /tmp/TestVolume001 /tmp/bacula-restores
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-label storage=File
-TestVolume001
-run job=NightlySave
-yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-restore
-5
-done
-yes
-@sleep 1
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-cd /
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-lib-test lib >${cwd}/tmp/original
-cd /tmp/bacula-restores
-${cwd}/bin/testls -e ${cwd}/scripts/exclude-lib-test lib >${cwd}/tmp/restored
-diff ${cwd}/tmp/original ${cwd}/tmp/restored 2>&1 >/dev/null
-if [ $? != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  ===== Test5 /lib failed!!! ===== "
-   echo "  ===== Test5 failed!!! ===== " >>test.out
-   echo " "
-else
-   echo "  ===== Test5 /lib OK ===== "
-   echo "  ===== Test5 OK ===== " >>test.out
-   cd ${cwd}
-   scripts/cleanup
-fi
diff --git a/regress/tests/recycle-test b/regress/tests/recycle-test
deleted file mode 100755 (executable)
index 0745b88..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   create three volumes and do six backups causing the
-#   volumes to be recycled, and cycling through the volumes
-#   twice. Tests maxvoljobs and volretention.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting recycle-test  ==="
-echo " === Starting recycle-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-label storage=File1 volume=TestVolume001
-label storage=File1 volume=TestVolume002
-label storage=File1 volume=TestVolume003
-update Volume=TestVolume001 volretention=10s
-update Volume=TestVolume001 maxvoljobs=1
-update Volume=TestVolume002 volretention=10s
-update Volume=TestVolume002 maxvoljobs=1
-update Volume=TestVolume003 volretention=10s
-update Volume=TestVolume003 maxvoljobs=1
-list volumes
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-list volumes
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-list volumes
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-list volumes
-@sleep 10
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-list volumes
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-@output tmp/log1.out
-list volumes
-run job=NightlySave storage=File1 level=full yes
-wait
-messages
-list volumes
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build  tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! recycle-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! recycle-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== recycle-test Bacula source OK ===== "
-   echo "  ===== recycle-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/restore-by-file-test b/regress/tests/restore-by-file-test
deleted file mode 100755 (executable)
index 22d4cc7..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory using the compressed option
-#   then restore it.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/tmp/build" >/tmp/file-list
-mkdir ${cwd}/tmp/build
-cp -p ${cwd}/build/src/dird/*.c ${cwd}/tmp/build
-cd ${cwd}/tmp/build
-ls >../1
-cd ..
-sed s%\^%${cwd}/tmp/build/% 1 >restore-list
-rm -f 1
-cd ${cwd}
-bin/bacula stop  2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting restore-by-file-test ==="
-echo " === Starting restore-by-file-test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=CompressedTest yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores
-7
-<${cwd}/tmp/restore-list
-
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r tmp/build tmp/bacula-restores${cwd}/tmp/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! restore-by-file-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! restore-by-file-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== restore-by-file-test Bacula source OK ===== "
-   echo "  ===== restore-by-file-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/six-vol-test b/regress/tests/six-vol-test
deleted file mode 100755 (executable)
index 73ce4e9..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh
-#
-# Create a 60MB file with random bytes. Back it up to 6 Volumes
-#   each constrained to 10MB using the automatic labeling feature.
-#
-
-if test ! -c /dev/urandom ; then
-   echo "No random device. Test skipped.\n"
-   exit 0
-fi
-cwd=`pwd`
-scripts/copy-testa-confs
-scripts/cleanup
-echo "${cwd}/tmp/largefile" >/tmp/file-list
-# Create 56MB file with random data
-echo "Creating a 56MB file with random data ..."
-dd if=/dev/urandom of=${cwd}/tmp/largefile bs=1024 count=55000
-echo "largefile created"
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting six-vol-test  ==="
-echo " === Starting six-vol-test  ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-run job=MultiVol storage=File yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores
-5
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop  2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff tmp/largefile  tmp/bacula-restores${cwd}/tmp/largefile 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! six-vol-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! six-vol-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== six-vol-test Bacula source OK ===== "
-   echo "  ===== six-vol-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/small-file-size-tape b/regress/tests/small-file-size-tape
deleted file mode 100755 (executable)
index 743cc17..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory 
-#   to a tape where the maximum tape file size is set to 1M
-#
-cwd=`pwd`
-bin/bacula stop  2>&1 >/dev/null
-scripts/copy-tape-confs
-scripts/cleanup-tape
-echo "${cwd}/build" >/tmp/file-list
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-out="tmp/sed_tmp"
-echo "s%# Maximum File Size%  Maximum File Size%g" >${out}
-cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
-sed -f ${out} ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
-
-echo " "
-echo " "
-echo " === Starting Small File Size test ==="
-echo " === Starting Small File Size test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=DDS-4 volume=TestVolume001 slot=0
-run job=NightlySave yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Small File Size test Bacula source failed!!! !!!!! "
-   echo "  !!!!! Small File Size test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Small File Size test Bacula source OK ===== "
-   echo "  ===== Small File Size test OK ===== " >>test.out
-#  scripts/cleanup
-fi
diff --git a/regress/tests/span-vol-test b/regress/tests/span-vol-test
deleted file mode 100755 (executable)
index a73dbfb..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   split the archive into four volumes, two of which are
-#   totally full. I.e. make sure that bsr selects all tapes 
-#   including those fully spanned.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting span-vol-test  ==="
-echo " === Starting span-vol-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1 volume=TestVolume001
-label storage=File1 volume=TestVolume002
-label storage=File1 volume=TestVolume003
-label storage=File1 volume=TestVolume004
-update Volume=TestVolume001 MaxVolBytes=3000000
-update Volume=TestVolume002 MaxVolBytes=3000000
-update Volume=TestVolume003 MaxVolBytes=3000000
-run job=NightlySave storage=File1 yes
-wait
-list volumes
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build  tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! span-vol-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! span-vol-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== span-vol-test Bacula source OK ===== "
-   echo "  ===== span-vol-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/sparse-compressed-test b/regress/tests/sparse-compressed-test
deleted file mode 100755 (executable)
index 3f2fcb9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory using the Sparse option
-#   then restore it.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting sparse-compressed-test ==="
-echo " === Starting sparse-compressed-test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=SparseCompressedTest yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out   
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! sparse-compressed-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! sparse-compressed-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== sparse-compressed-test Bacula source OK ===== "
-   echo "  ===== sparse-compressed-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/sparse-test b/regress/tests/sparse-test
deleted file mode 100755 (executable)
index aaecc63..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory using the Sparse option
-#   then restore it.
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting sparse-test ==="
-echo " === Starting sparse-test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=SparseTest yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! sparse-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! sparse-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== sparse-test Bacula source OK ===== "
-   echo "  ===== sparse-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/test0 b/regress/tests/test0
deleted file mode 100755 (executable)
index 0d0edd0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-echo " " >test.out
-rm -f bin/working/*
diff --git a/regress/tests/two-jobs-test b/regress/tests/two-jobs-test
deleted file mode 100755 (executable)
index d848ce4..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory using the compressed option
-#   then backup a second time and finally restore it
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting two-jobs-test  ==="
-echo " === Starting two-jobs-test  ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-estimate job=CompressedTest listing
-estimate job=CompressedTest listing
-estimate job=CompressedTest listing
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=CompressedTest yes
-wait
-messages
-quit
-END_OF_DATA
-echo "Backup 1 done"
-touch ${cwd}/build/src/dird/*.c
-#
-# run a second job
-#
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-run job=CompressedTest
-yes
-wait
-messages
-@# 
-@# now do several restores to ensure we cleanup between jobs
-@#
-@output /dev/null
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! two-jobs-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! two-jobs-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== two-jobs-test Bacula source OK ===== "
-   echo "  ===== two-jobs-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/two-vol-test b/regress/tests/two-vol-test
deleted file mode 100755 (executable)
index 53ca3cf..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory but 
-#   split the archive into two volumes
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting two-vol-test  ==="
-echo " === Starting two-vol-test  ===" >working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File1 volume=TestVolume001
-label storage=File1 volume=TestVolume002
-update Volume=TestVolume001
-6
-3000000
-10
-run job=NightlySave storage=File1 yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build  tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! two-vol-test Bacula source failed!!! !!!!! "
-   echo "  !!!!! two-vol-test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== two-vol-test Bacula source OK ===== "
-   echo "  ===== two-vol-test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/two-volume-tape b/regress/tests/two-volume-tape
deleted file mode 100755 (executable)
index 31c7d79..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory 
-#   to two tapes where the maximum tape file size is set to 1M
-#
-cwd=`pwd`
-bin/bacula stop  2>&1 >/dev/null
-scripts/copy-tape-confs
-mtx -f /dev/sg0 unload
-mtx -f /dev/sg0 load 1
-mt -f /dev/nst0 rewind
-mt -f /dev/nst0 weof
-mtx -f /dev/sg0 unload
-mtx -f /dev/sg0 load 2
-mt -f /dev/nst0 rewind
-mt -f /dev/nst0 weof
-mtx -f /dev/sg0 unload
-echo "${cwd}/build" >/tmp/file-list
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-out="tmp/sed_tmp"
-echo "s%# Maximum File Size%  Maximum File Size%g" >${out}
-cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
-sed -f ${out} ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
-
-echo " "
-echo " "
-echo " === Starting Two Volume Tape test ==="
-echo " === Starting Two Volume Tape test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=DDS-4 volume=TestVolume001 slot=1
-label storage=DDS-4 volume=TestVolume002 slot=2
-update Volume=TestVolume001 MaxVolBytes=3000000
-run job=NightlySave yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff -r build tmp/bacula-restores${cwd}/build 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Two Volume Tape test Bacula source failed!!! !!!!! "
-   echo "  !!!!! Two Volume Tape test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Two Volume Tape test Bacula source OK ===== "
-   echo "  ===== Two Volume Tape test OK ===== " >>test.out
-#  scripts/cleanup
-fi
diff --git a/regress/tests/verify-vol-test b/regress/tests/verify-vol-test
deleted file mode 100755 (executable)
index 1e841c2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then verify the catalog.           
-#
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/build" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting verify Volume Test ==="
-echo " === Starting verify Volume Test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=NightlySave yes
-wait
-messages
-@# 
-@# now do a verify volume
-@#
-@output ${cwd}/tmp/original
-run job=VerifyVolume
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-sleep 2
-bin/bacula stop 2>&1 >/dev/null
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Verify OK" ${cwd}/tmp/original 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Verify Volume failed!!! !!!!! "
-   echo "  !!!!! Verify Volume failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Verify Volume Test OK ===== "
-   echo "  ===== Verify Volume Test OK ===== " >>test.out
-   scripts/cleanup
-fi
diff --git a/regress/tests/weird-files-test b/regress/tests/weird-files-test
deleted file mode 100755 (executable)
index 7237d40..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-if test ! -d weird-files ; then
-   echo " "
-   echo "Weird files not configured. Test not run."
-   exit 0
-fi
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-echo "${cwd}/weird-files" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting weird filenames test ==="
-echo " === Starting weird filenames test ===" >>working/log
-echo " "
-
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File
-TestVolume001
-run job=NightlySave
-yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=${cwd}/tmp/bacula-restores current all
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-${cwd}/bin/testls weird-files >${cwd}/tmp/original
-cd tmp/bacula-restores${cwd}
-${cwd}/bin/testls weird-files >${cwd}/tmp/restored
-cd ${cwd}
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff ${cwd}/tmp/original ${cwd}/tmp/restored 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Weird files test failed!!! !!!!! "
-   echo "  !!!!! Weird files test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Weird files test OK ===== "
-   echo "  ===== Weird files test OK ===== " >>test.out
-   cd ${cwd}
-   scripts/cleanup
-fi
diff --git a/regress/tests/weird-files2-test b/regress/tests/weird-files2-test
deleted file mode 100755 (executable)
index a618c4e..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/sh
-#
-# Run a simple backup of the Bacula build directory
-#   then restore it.
-#
-if test ! -d weird-files ; then
-   echo " "
-   echo "weird files not configured. Test not run."
-   exit 0
-fi
-cwd=`pwd`
-scripts/copy-test-confs
-scripts/cleanup
-rm -rf weird-files2
-cp -a weird-files weird-files2
-echo "${cwd}/weird-files2" >/tmp/file-list
-bin/bacula stop 2>&1 >/dev/null
-bin/drop_sqlite_tables
-bin/make_sqlite_tables
-
-echo " "
-echo " "
-echo " === Starting weird filenames2 test ==="
-echo " === Starting weird filenames2 test ===" >>working/log
-echo " "
-
-bin/testls weird-files2 >${cwd}/tmp/original
-bin/bacula start 2>&1 >/dev/null
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@output tmp/log1.out
-label storage=File volume=TestVolume001
-run job=NightlySave yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-#
-# Now mess up the a hard link, and a soft link
-#
-cd weird-files2
-rm -f hard-file2
-ln hard-file3 hard-file2
-rm -f soft-file2
-ln -s soft-file3 soft-file2
-cd ${cwd}
-bin/console -c bin/console.conf <<END_OF_DATA
-@output /dev/null
-messages
-@# 
-@# now do a restore
-@#
-@output tmp/log2.out
-restore where=
-5
-done
-yes
-wait
-messages
-@output
-quit
-END_OF_DATA
-bin/bacula stop 2>&1 >/dev/null
-bin/testls weird-files2 >${cwd}/tmp/restored
-grep "^Termination: *Backup OK" tmp/log1.out 2>&1 >/dev/null
-bstat=$?
-grep "^Termination: *Restore OK" tmp/log2.out 2>&1 >/dev/null
-rstat=$?
-diff ${cwd}/tmp/original ${cwd}/tmp/restored 2>&1 >/dev/null
-if [ $? != 0 -o $bstat != 0 -o $rstat != 0 ] ; then
-   echo " "
-   echo " "
-   echo "  !!!!! Weird files2 test failed!!! !!!!! "
-   echo "  !!!!! Weird files2 test failed!!! !!!!! " >>test.out
-   echo " "
-else
-   echo "  ===== Weird files2 test OK ===== "
-   echo "  ===== Weird files2 test OK ===== " >>test.out
-   cd ${cwd}
-   scripts/cleanup
-   rm -rf weird-files2
-fi
diff --git a/regress/weird-files.tar.gz b/regress/weird-files.tar.gz
deleted file mode 100644 (file)
index 0ecbe3f..0000000
Binary files a/regress/weird-files.tar.gz and /dev/null differ