1
2
+set-gnome2
+set-gnome1.4
+kerns-gprof-config
+autom4te.cache
Makefile
bacula
btraceback
+Patched 1.32f-3
+
+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,
- 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
@$(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);
- Release Notes for Bacula 1.32
+ Release Notes for Bacula 1.32f-3
- 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-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.
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.
/* 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
-
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)
/* 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
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)
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)
[
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>
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
]
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
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
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
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/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 \
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 ],
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
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
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
# 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.
--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
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
GNOME_DIR=src/gnome-console
+ gnome_version="version 1.4"
fi
fi
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)
# -------------------------------------------
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
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
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
+#
+# 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;
+
+
+
+
+
+
+
+
+
# ------------------------------------------------
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
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
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
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
"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" ;;
"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" ;;
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
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
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
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
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
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.
- 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.
- 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
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
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.
> > 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
- 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.
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
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.
- 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.
- 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
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.
-
-
======================================================
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
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, ...)
- *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
Include {
Compression = GZIP;
Signature = MD5
- Match = /*.?*/ # matches all files.
+ Wild = /*.?*/ # matches all files.
File = /
}
}
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 = /
}
- 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
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.
+
--- /dev/null
+#! /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
--- /dev/null
+Makefile
+bacula-dir
+bacula-fd
+bacula-sd
--- /dev/null
+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
# 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@
# 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@
# 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@
+# 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 >= 2.0
+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.
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 >= 2.0
+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.
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
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
# 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 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 \
--with-scriptdir=/etc/bacula \
--enable-smartalloc \
--enable-gnome \
+ --enable-static-fd \
%if %{mysql}
--with-mysql \
%else
--with-subsys-dir=/var/lock/subsys
make
+cd src/filed
+strip static-bacula-fd
+cd ../../
+
%install
cwd=${PWD}
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
# 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
%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
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
%else
-%files sqlite-%{rh_version}
+%files sqlite
%defattr(-,root,root)
%attr(0754,root,root) /etc/bacula/bacula
%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
# create the 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
%endif
-%files client-%{rh_version}
+%files client
%defattr(-,root,root)
%attr(0754,root,root) /etc/bacula/fd
%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 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
#
# 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@
#
@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
@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
@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
--- /dev/null
+#
+# 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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
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
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
}
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
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
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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
config.h
testprogs
host.h
+perlgui
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
#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
#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
$(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
*
* 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;
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 */
-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)
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
#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**
* 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;
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;
#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)
#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 */
/* 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 */
};
* 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;
#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 */
/* ***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
/* 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;
/* 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;
*/
/* 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 */
};
* 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;
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;
/* 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 */
/* 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 */
/* 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 */
};
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:
--- /dev/null
+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
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,
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)
);
return 0;
}
+#ifdef HAVE_TREAD_SAFE_MYSQL
my_thread_init();
+#endif
mdb->connected = TRUE;
V(mutex);
{
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) {
/* 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 */
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);
*/
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;
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);
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
db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
{
SQL_ROW row;
- uint32_t JobId;
db_lock(mdb);
/* 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);
}
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 */
}
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;
* 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;
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;
{
SQL_ROW row;
int numrows;
+ char *order;
db_lock(mdb);
if (item == -1) { /* find oldest volume */
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);
*/
/* 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);
* 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);
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);
* "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);
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)) {
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);
* 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
*/
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;
}
} 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);
}
}
} 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 {
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;
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
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
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) {
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);
}
--- /dev/null
+<?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>
--- /dev/null
+<?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>
btraceback.gdb
startit
stopit
+dird.conf
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 \
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 \
}
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);
}
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);
{
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;
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 {
/* 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 */
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);
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 */
#
# 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
}
/* Forward referenced functions */
static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
+void print_bsr(UAContext *ua, RBSR *bsr);
/*
* 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;
}
/*
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);
}
}
{
if (bsr) {
free_findex(bsr->fi);
- free_bsr(bsr->next);
if (bsr->VolParams) {
free(bsr->VolParams);
}
+ free_bsr(bsr->next);
free(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)) {
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++) {
}
/*
- * 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;
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;
/*
* 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) {
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 {
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
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);
/*
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) {
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);
{"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},
{"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},
{"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}
};
{"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}
};
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) {
}
if (type < 0) { /* no recursion */
type = - type;
- recurse = 0;
+ recurse = false;
}
switch (type) {
case R_DIRECTOR:
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);
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));
}
} 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);
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) {
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);
}
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);
}
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 */
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 */
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 */
};
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 */
};
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;
}
}
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) {
} 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);
} 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);
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;
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;
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;
/*
- * 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)
{
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
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);
}
}
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) {
}
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");
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;
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;
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);
}
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)) {
}
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);
}
{
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;
jcr->messages = job->messages;
if (jcr->RestoreBootstrap) {
free(jcr->RestoreBootstrap);
+ jcr->RestoreBootstrap = NULL;
}
/* This can be overridden by Console program */
if (job->RestoreBootstrap) {
break;
case JT_RESTORE:
case JT_ADMIN:
- jcr->JobLevel = L_FULL;
+ jcr->JobLevel = L_NONE;
break;
default:
break;
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;
/*
* 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);
" 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);
}
}
+ /*
+ * 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",
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);
}
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 {
}
}
}
+ 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;
}
* 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
/* 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;
}
/* 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);
/* 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, ...);
}
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));
/*
* The following code is kept temporarily for compatibility.
* It is the predecessor to the Bootstrap file.
+ * DEPRECATED
*/
if (!jcr->RestoreBootstrap) {
/*
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:
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"),
s_weekly,
s_monthly,
s_hourly,
- s_wpos, /* 1st, 2nd, ...*/
+ s_wom, /* 1st, 2nd, ...*/
+ s_woy, /* week of year w00 - w53 */
};
struct s_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'},
*/
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);
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 */
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;
}
}
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;
}
}
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;
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();
*/
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);
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);
"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};
/* 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' "
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,"
"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 =
"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' "
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 */
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);
{ 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")},
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
static int update_volume(UAContext *ua)
{
MEDIA_DBR mr;
+ POOL_DBR pr;
POOLMEM *query;
char ed1[30];
bool done = false;
N_("MaxVolFiles"), /* 4 */
N_("MaxVolBytes"), /* 5 */
N_("Recycle"), /* 6 */
+ N_("Pool"), /* 7 */
NULL };
for (int i=0; kw[i]; i++) {
case 6:
update_volrecycle(ua, ua->argv[j], &mr);
break;
+ case 7:
+ update_volpool(ua, ua->argv[j], &mr);
}
done = true;
}
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 */
case 7: /* Slot */
int slot;
- POOL_DBR pr;
memset(&pr, 0, sizeof(POOL_DBR));
pr.PoolId = mr.PoolId;
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;
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:
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);
case 1:
delete_pool(ua);
break;
+ case 2:
+ delete_job(ua);
+ return 1;
default:
bsendmsg(ua, _("Nothing done.\n"));
break;
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
*/
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);
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[] = {
/* 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);
/* 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);
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) {
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) {
}
}
}
- 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]));
}
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.
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);
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 */
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 a delete list */
db_sql_query(ua->db, query, file_delete_handler, (void *)&del);
for (i=0; i < del.num_ids; i++) {
* 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);
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);
/* 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;
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;
}
if (!open_db(ua)) {
- free_rx(&rx);
- return 0;
+ goto bail_out;
}
/* Ensure there is at least one Restore Job */
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;
}
/*
*/
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) {
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) {
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;
}
memset(&cr, 0, sizeof(cr));
if (!get_client_dbr(ua, &cr)) {
- free_rx(rx);
return 0;
}
bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
{
char *p;
char date[MAX_TIME_LENGTH];
+ bool have_date = false;
JobId_t JobId;
JOB_DBR jr;
bool done = false;
"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 };
"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"));
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;
}
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;
}
}
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;
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;
}
}
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];
}
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;
}
}
* 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));
}
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)) {
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)) {
CLIENT_DBR cr;
char fileset_name[MAX_NAME_LENGTH];
char ed1[50];
+ int i;
/* Create temp tables */
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;
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;
/* 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));
}
return stat;
}
+
/* Return next JobId from comma separated list */
static int next_jobid_from_list(char **p, uint32_t *JobId)
{
}
/*
- * 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;
}
}
if (name_list->name) {
free(name_list->name);
+ name_list->name = NULL;
}
name_list->max_ids = 0;
name_list->num_ids = 0;
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"));
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"
* 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;
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;
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;
}
return 1;
}
job_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 1: /* JobId */
if (jid) {
return 1;
}
jid = ua->argv[i];
- found = True;
+ found = true;
break;
case 2: /* client */
if (client_name) {
return 1;
}
client_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 3: /* fileset */
if (fileset_name) {
return 1;
}
fileset_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 4: /* level */
if (level_name) {
return 1;
}
level_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 5: /* storage */
if (store_name) {
return 1;
}
store_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 6: /* pool */
if (pool_name) {
return 1;
}
pool_name = ua->argv[i];
- found = True;
+ found = true;
break;
case 7: /* where */
if (where) {
return 1;
}
where = ua->argv[i];
- found = True;
+ found = true;
break;
case 8: /* bootstrap */
if (bootstrap) {
return 1;
}
bootstrap = ua->argv[i];
- found = True;
+ found = true;
break;
case 9: /* replace */
if (replace) {
return 1;
}
replace = ua->argv[i];
- found = True;
+ found = true;
break;
case 10: /* When */
if (when) {
return 1;
}
when = ua->argv[i];
- found = True;
+ found = true;
break;
case 11: /* Priority */
if (Priority) {
}
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;
}
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);
}
}
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\
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) {
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 */
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:
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:
}
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);
}
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;
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++) {
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;
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],
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;
}
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;
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);
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");
}
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;
}
}
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);
}
}
/*
- * 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();
+}
/*
*
* 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
*
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);
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))
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;
}
* 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
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;
}
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];
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);
}
+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;
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;
}
*/
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"
}
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;
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);
}
/*
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);
} 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.
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;
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;
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:
}
stat = wait_for_job_termination(jcr);
-
verify_cleanup(jcr, stat);
return 1;
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);
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\
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),
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\
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),
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\
* 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;
startit
static-bacula-fd
stopit
+filed.conf
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();
}
}
}
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;
}
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");
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;
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) {
/*
* 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;
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;
}
/*
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;
/* 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);
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),
if (jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
free_pool_memory(jcr->RestoreBootstrap);
+ jcr->RestoreBootstrap = NULL;
}
if (jcr->last_fname) {
free_pool_memory(jcr->last_fname);
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) {
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);
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;
}
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 */
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 */
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");
}
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);
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;
}
}
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;
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;
}
}
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;
}
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;
#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
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);
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);
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
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
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 {
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);
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);
}
+/*
+ * 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>
{
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);
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");
}
unlock_jcr_chain();
Dmsg0(200, "End bac_status jcr loop.\n");
- strcpy(buf, termstat);
+ bstrncpy(buf, termstat, sizeof(buf));
return buf;
}
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);
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,
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"),
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"),
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
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).
MA 02111-1307, USA.
*/
-
if (is_bopen(ofd)) {
bclose(ofd);
}
+ pm_strcpy(&attr->ofname, "*none*");
return 1;
}
if (is_bopen(ofd)) {
bclose(ofd);
}
+ pm_strcpy(&attr->ofname, "*none*");
return 1;
}
/*
stat = 0;
}
}
+ pm_strcpy(&attr->ofname, "*none*");
umask(old_mask);
return stat;
}
{
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;
}
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));
} 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));
* 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));
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);
#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));
}
}
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));
}
*(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 {
&& 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);
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+
+/* 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);
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * Main configuration file parser for Bacula User Agent
+ * some parts may be split into separate files such as
+ * the schedule configuration (sch_config.c).
+ *
+ * Note, the configuration file parser consists of three parts
+ *
+ * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ * 2. The generic config scanner in lib/parse_config.c and
+ * lib/parse_config.h.
+ * These files contain the parser code, some utility
+ * routines, and the common store routines (name, int,
+ * string).
+ *
+ * 3. The daemon specific file, which contains the Resource
+ * definitions as well as any specific store routines
+ * for the resource records.
+ *
+ * Kern Sibbald, January MM, September MM
+ *
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+#
+# 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"
+}
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+ }
+}
+
--- /dev/null
+/*
+ * 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);
+
--- /dev/null
+#
+# Bacula User Agent (or Console) Configuration File
+#
+
+Director {
+ Name = rufus-dir
+ DIRport = 8101
+ address = rufus
+ Password = UA_password
+}
#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 */
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 */
* 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;
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 */
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
+ Kern Sibbald, June MMIII
+
*/
/*
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.
#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)))
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) {
}
}
+#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;
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;
}
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;
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
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);
}
/*
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 */
#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 */
/*
* 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;
/*
* 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;
* 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)
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)
{
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()
/* 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. */
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);
/* =========================================================== */
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;
{
#ifndef HAVE_CYGWIN
int i;
- int cpid;
+ pid_t cpid;
mode_t oldmask;
/*
* Become a daemon.
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
if (head == NULL) { /* if empty list, */
head = item; /* item is head as well */
}
+ num_items++;
}
/*
if (tail == NULL) { /* if empty list, */
tail = item; /* item is tail too */
}
+ num_items++;
}
void dlist::insert_before(void *item, void *where)
if (head == where) {
head = item;
}
+ num_items++;
}
void dlist::insert_after(void *item, void *where)
if (tail == where) {
tail = item;
}
+ num_items++;
}
xitem = ilink->prev;
((dlink *)((char *)xitem+loffset))->next = ilink->next;
}
+ num_items--;
}
void * dlist::next(void *item)
}
-/* Destroy the list and its contents */
+/* Destroy the list contents */
void dlist::destroy()
{
for (void *n=head; n; ) {
free(n);
n = ni;
}
+ num_items = 0;
}
void *head;
void *tail;
int loffset;
+ int num_items;
public:
dlist(void *item, void *link);
void init(void *item, void *link);
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();
{
head = tail = NULL;
loffset = (char *)link - (char *)item;
+ num_items = 0;
}
/* Constructor */
{
return head == NULL;
}
+
+inline int dlist::size()
+{
+ return num_items;
+}
+
inline void * dlist::operator new(size_t)
{
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
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;
{
/* 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);
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");
JCR *jcr;
int len;
+ if (!Job) {
+ return NULL;
+ }
P(mutex);
len = strlen(Job);
for (jcr = jobs; jcr; jcr=jcr->next) {
{
JCR *jcr;
+ if (!Job) {
+ return NULL;
+ }
P(mutex);
for (jcr = jobs; jcr; jcr=jcr->next) {
if (strcmp(jcr->Job, Job) == 0) {
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++) {
fclose(trace_fd);
trace_fd = NULL;
}
+ term_last_jobs_list();
}
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:
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;
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;
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;
}
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;
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;
#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);
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);
/* 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);
* 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;
}
/*
* 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 */
/* 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;
if (already_dead) {
_exit(1);
}
+ Dmsg1(200, "sig=%d\n", sig);
/* Ignore certain signals */
if (sig == SIGCHLD || sig == SIGUSR2) {
return;
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");
}
#endif
- exit_handler(1);
+ exit_handler(sig);
}
/*
#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.
*/
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);
}
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);
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;
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;
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;
}
/*
- * 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,
{
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 {
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;
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 */
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;
}
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) {
return;
}
+#ifdef SLOW_WAY
+/* Moved to tree.h to eliminate subroutine call */
TREE_NODE *first_tree_node(TREE_ROOT *root)
{
return root->first;
{
return node->next;
}
+#endif
void print_tree(char *path, TREE_NODE *tree)
root = new_tree();
root->fname = tree_alloc(root, 1);
*root->fname = 0;
+ root->fname_len = 0;
FillDirectoryTree("/home/kern/bacula/k", root, NULL);
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;
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;
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 */
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
/* 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++) {
/*
* Concatenate a string (str) onto a pool memory buffer pm
+ * Returns: length of concatenated string
*/
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)
{
*/
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);
}
/*
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;
* %n = Unadorned Job name
* %t = Job type (Backup, ...)
* %r = Recipients
+ * %v = Volume name
*
* omsg = edited output message
* imsg = input string containing edit codes (%x)
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;
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);
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"),
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"),
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"),
stopit
changer.out
mtx-changer
+stored.conf
*/
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++;
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 */
}
/*
}
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:
/*
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);
} /* 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));
P(dev->mutex);
unblock_device(dev);
V(dev->mutex);
- return stat;
+ return vol_ok;
}
/*
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);
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
*
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;
}
} 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;
}
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;
}
}
{
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);
} 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 */
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;
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;
}
}
Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
bnet_strerror(ds));
- ok = FALSE;
+ ok = false;
break;
}
}
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);
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) {
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;
}
}
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;
}
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);
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);
* 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));
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;
}
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 */
}
/*
# AutomaticMount = yes; # when device opened, read it
# AlwaysOpen = yes;
# RemovableMedia = yes;
+# RandomAccess = no;
#}
#
# AutomaticMount = yes; # when device opened, read it
# AlwaysOpen = Yes;
# RemovableMedia = yes;
+# RandomAccess = no;
#}
#
"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);
}
/* 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;}
{
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);
}
/* 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;}
* 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);
}
}
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') {
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;
}
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;
}
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;
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) {
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);
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);
}
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);
#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));
/*
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 {
ssize_t stat;
int looping;
uint32_t BlockNumber;
- int retry = 0;
+ int retry;
if (dev_state(dev, ST_EOT)) {
return 0;
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);
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;
}
/* 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;
}
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 */
/* 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;}
"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);
}
}
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);
}
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);
/* 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;}
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;
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;
* 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) {
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);
}
}
- 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);
/* 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();
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);
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;
*/
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;
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");
}
/*
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));
}
}
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"));
*/
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");
}
}
*/
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");
}
}
*/
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 ? "" : "!");
}
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"));
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");
"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 */
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.
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;
}
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:
"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"
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"));
}
/* 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");
}
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\
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);
/*
#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);
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.
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 */
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);
}
/*
* 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;
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"));
}
/*
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",
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;
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;
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.
}
printf("\n");
weofcmd();
- weofcmd();
+ if (dev_cap(dev, CAP_TWOEOF)) {
+ weofcmd();
+ }
rewindcmd();
scan_blocks();
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);
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;
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);
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");
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"},
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)
{
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);
{
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"
/* 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;}
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;
+}
while (p >= jcr->dev_name && *p != '/')
p--;
if (*p == '/') {
- strcpy(jcr->VolumeName, p+1);
+ pm_strcpy(&jcr->VolumeName, p+1);
*p = 0;
}
}
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;
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;
#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
}
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
* 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 */
int
fsf_dev(DEVICE *dev, int num)
{
+ struct mtget mt_stat;
struct mtop mt_com;
int stat = 0;
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");
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");
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 */
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;
}
{
/* 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);
}
#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))
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 */
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 */
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 {
}
/*
- * 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 {
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 */
}
} 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);
}
} 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);
BSOCK *fd = jcr->file_bsock;
POOLMEM *fname = get_pool_memory(PM_FNAME);
FILE *bs;
+ int stat = 0;
if (jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
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;
-
+ }
}
*/
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;
/*
* 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);
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.
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;
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"),
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) {
}
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);
}
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)
/*
* 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;
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)) {
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
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;
if (!match_stream(bsr, bsr->stream, rec, 1)) {
goto no_match;
}
- bsr->found++;
return 1;
no_match:
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;
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;
}
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) {
#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"),
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);
/*
* 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);
* 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;
}
/*
* 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.
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));
/* 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;
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));
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 {
/*
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 */
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 */
}
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);
*/
void release_volume(JCR *jcr, DEVICE *dev)
{
-
if (jcr->WroteVol) {
Jmsg0(jcr, M_ERROR, 0, "Hey!!!!! WroteVol non-zero !!!!!\n");
}
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) &&
}
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);
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);
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,
#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
block = new_block(dev);
recs = new dlist(rec, &rec->link);
+ position_to_first_file(jcr, dev);
for ( ; ok && !done; ) {
if (job_canceled(jcr)) {
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
*/
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
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);
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
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);
/*
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");
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; ) {
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)
{
*
* 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
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 */
};
/* 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);
/*
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) {
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
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);
}
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) {
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;
{
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)); ) {
{"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},
{"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},
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);
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 */
" - 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);
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();
}
}
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;
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); )
/* */
#undef VERSION
-#define VERSION "1.32"
+#define VERSION "1.32f-3"
#define VSTRING "1"
-#define BDATE "26 Sep 2003"
-#define LSMDATE "26Sep03"
+#define BDATE "12 Jan 2004"
+#define LSMDATE "12Jan04"
/* Debug flags */
#undef DEBUG
+++ /dev/null
-build
-bin
-test.out
-weird-files
-diff
-tmp
-working
+++ /dev/null
- 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>
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/bin/sh
-#
-# Run all root tests
-#
-tests/dev-test-root
-tests/etc-test-root
-tests/lib-test-root
-cat test.out
-scripts/cleanup
+++ /dev/null
-#!/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
+++ /dev/null
-#!/bin/sh
-#
-# Run all tests
-#
-./all-non-root-tests
-./all-root-tests
-cat test.out
-scripts/cleanup
+++ /dev/null
-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
+++ /dev/null
-#
-# Default Bacula Director Configuration file
-#
-# The only thing that MUST be changed is to add one or more
-# file or directory names in the Include directive of the
-# FileSet resource.
-#
-# For Bacula release 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
-}
+++ /dev/null
-#
-# 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
-}
+++ /dev/null
-#
-# 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
-}
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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$$
+++ /dev/null
-dev/ptmx
-dev/pts
-dev/rd/c5d2
-dev/rd
-dev/shm
+++ /dev/null
-etc/mail/statistics
+++ /dev/null
-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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#
-# Default Bacula Director Configuration file
-#
-# The only thing that MUST be changed is to add one or more
-# file or directory names in the Include directive of the
-# FileSet resource.
-#
-# For Bacula release 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
-}
+++ /dev/null
-#
-# 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
-}
+++ /dev/null
-#
-# 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
-}
+++ /dev/null
-#
-# Bacula User Agent (or Console) Configuration File
-#
-
-Director {
- Name = @hostname@-dir
- DIRport = 8101
- address = @hostname@
- Password = "pNvX1WiXnwv2C/F7E52LGvw6rKjbbPvu2kyuPa9pVaL3"
-}
+++ /dev/null
-#
-# 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
-}
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/bin/sh
-echo " " >test.out
-rm -f bin/working/*
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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