From fc92af306f2cd876b24b4858a15d05b18f525b6e Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Tue, 14 Feb 2006 14:11:10 +0000 Subject: [PATCH] - Add disk-changer to scripts directory + configure/Makefile - Eliminate PoolId from jcr -- it is in jcr->jr.PoolId - Implement store_bit scanner to replace store_yesno. Mostly done. - Implement new store_bool that stores in a bool. - Add true/false to yes/no conf directives. - Make first cut at changing appropriate store_yesno to store_bool. - Complete implementation of Pool storage devices. - Move starting clones to job.c - Move create_restore_bootstrap_file() to job.c - Make copy_storage() more general to be able to handle Pool storage. - Cleanup a lot of migration code for manual running, including using Pool storage. - Move getting a scratch Volume into a subroutine. - Make all places a Volume that is added to a pool to respect max vols. - Fix bug in autochanger recycle code (improper edit 64 bit). - Fix segfault in restore command when no value specified. - Start adding code to handle multiple MediaTypes in restore. - Eliminate race condition in getting Volume name for two drive autochanger. - More debug code in autochanger. - Add storage keyword to bootstrap file, add parsing. - Move slot in bsr file into Volume record as there will be a different slot for each Volume. - Create reserve.h git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2784 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/autoconf/configure.in | 1 + bacula/configure | 3 +- bacula/kernstodo | 13 +- bacula/kes-1.39 | 53 ++++++ bacula/scripts/.cvsignore | 1 + bacula/scripts/Makefile.in | 8 +- bacula/scripts/disk-changer.in | 211 ++++++++++++++++++++++ bacula/scripts/mtx-changer.in | 91 ++++++---- bacula/src/cats/sql_find.c | 7 +- bacula/src/console/console_conf.c | 8 +- bacula/src/dird/autoprune.c | 4 +- bacula/src/dird/backup.c | 33 +--- bacula/src/dird/catreq.c | 2 +- bacula/src/dird/dird.c | 15 +- bacula/src/dird/dird_conf.c | 76 ++++---- bacula/src/dird/dird_conf.h | 78 ++++---- bacula/src/dird/job.c | 105 ++++++++--- bacula/src/dird/jobq.c | 2 +- bacula/src/dird/mac.c | 130 +++++++++----- bacula/src/dird/newvol.c | 2 +- bacula/src/dird/next_vol.c | 115 +++++++----- bacula/src/dird/protos.h | 5 +- bacula/src/dird/recycle.c | 2 +- bacula/src/dird/ua_cmds.c | 2 +- bacula/src/dird/ua_label.c | 4 + bacula/src/dird/ua_output.c | 5 +- bacula/src/dird/ua_purge.c | 13 +- bacula/src/dird/ua_restore.c | 21 +++ bacula/src/dird/ua_status.c | 2 +- bacula/src/dird/ua_update.c | 3 +- bacula/src/dird/verify.c | 27 +-- bacula/src/filed/filed_conf.c | 16 +- bacula/src/gnome2-console/console_conf.c | 10 +- bacula/src/jcr.h | 1 - bacula/src/lib/parse_conf.c | 28 ++- bacula/src/lib/parse_conf.h | 53 +++--- bacula/src/stored/acquire.c | 217 ++++++++++++----------- bacula/src/stored/askdir.c | 12 +- bacula/src/stored/autochanger.c | 34 +++- bacula/src/stored/bsr.h | 21 +-- bacula/src/stored/dev.c | 35 ++-- bacula/src/stored/dircmd.c | 4 +- bacula/src/stored/job.c | 9 + bacula/src/stored/mount.c | 11 +- bacula/src/stored/parse_bsr.c | 41 ++++- bacula/src/stored/protos.h | 3 +- bacula/src/stored/reserve.c | 69 +++---- bacula/src/stored/reserve.h | 60 +++++++ bacula/src/stored/status.c | 2 +- bacula/src/stored/stored.c | 4 +- bacula/src/stored/stored.h | 1 + bacula/src/stored/stored_conf.c | 60 +++---- bacula/src/stored/wait.c | 4 +- bacula/src/tray-monitor/tray_conf.c | 72 ++++---- bacula/src/version.h | 4 +- bacula/src/wx-console/console_conf.c | 8 +- 56 files changed, 1198 insertions(+), 623 deletions(-) create mode 100644 bacula/scripts/disk-changer.in create mode 100644 bacula/src/stored/reserve.h diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index 44a88459e3..984b356e95 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -1932,6 +1932,7 @@ AC_OUTPUT([autoconf/Make.common \ scripts/bacula.desktop.gnome2.xsu \ scripts/gnome-console.console_apps \ scripts/mtx-changer \ + scripts/disk-changer \ scripts/dvd-handler \ scripts/bacula-tray-monitor.desktop \ scripts/logwatch/Makefile \ diff --git a/bacula/configure b/bacula/configure index 9d85ea7ab1..6adc9896de 100755 --- a/bacula/configure +++ b/bacula/configure @@ -29834,7 +29834,7 @@ if test "x${subsysdir}" = "x${sbindir}" ; then exit 1 fi - ac_config_files="$ac_config_files autoconf/Make.common Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/bconsole scripts/gconsole scripts/bacula scripts/devel_bacula scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/bacula.desktop.gnome1.consolehelper scripts/bacula.desktop.gnome2.consolehelper scripts/bacula.desktop.gnome1.xsu scripts/bacula.desktop.gnome2.xsu scripts/gnome-console.console_apps scripts/mtx-changer scripts/dvd-handler scripts/bacula-tray-monitor.desktop scripts/logwatch/Makefile scripts/logwatch/logfile.bacula.conf src/Makefile src/host.h src/console/Makefile src/console/bconsole.conf src/gnome2-console/Makefile src/gnome2-console/gnome-console.conf src/wx-console/Makefile src/wx-console/wx-console.conf src/tray-monitor/Makefile src/tray-monitor/tray-monitor.conf src/dird/Makefile src/dird/bacula-dir.conf src/lib/Makefile src/stored/Makefile src/stored/bacula-sd.conf src/filed/Makefile src/filed/bacula-fd.conf src/filed/win32/Makefile src/cats/Makefile src/cats/make_catalog_backup src/cats/delete_catalog_backup src/cats/create_postgresql_database src/cats/update_postgresql_tables src/cats/make_postgresql_tables src/cats/grant_postgresql_privileges src/cats/drop_postgresql_tables src/cats/drop_postgresql_database src/cats/create_mysql_database src/cats/update_mysql_tables src/cats/make_mysql_tables src/cats/grant_mysql_privileges src/cats/drop_mysql_tables src/cats/drop_mysql_database src/cats/create_sqlite_database src/cats/update_sqlite_tables src/cats/make_sqlite_tables src/cats/grant_sqlite_privileges src/cats/drop_sqlite_tables src/cats/drop_sqlite_database src/cats/create_sqlite3_database src/cats/update_sqlite3_tables src/cats/make_sqlite3_tables src/cats/grant_sqlite3_privileges src/cats/drop_sqlite3_tables src/cats/drop_sqlite3_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/update_bdb_tables src/cats/make_bdb_tables src/cats/grant_bdb_privileges src/cats/drop_bdb_tables src/cats/drop_bdb_database src/cats/create_bacula_database src/cats/update_bacula_tables src/cats/grant_bacula_privileges src/cats/make_bacula_tables src/cats/drop_bacula_tables src/cats/drop_bacula_database src/findlib/Makefile src/pygtk-console/Makefile src/tools/Makefile src/win32/winbacula.nsi src/win32/baculafd/bacula-fd.conf src/win32/Makefile src/win32/console/bconsole.conf src/win32/wx-console/wx-console.conf src/win32/pebuilder/Makefile po/Makefile.in $PFILES" + ac_config_files="$ac_config_files autoconf/Make.common Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/bconsole scripts/gconsole scripts/bacula scripts/devel_bacula scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/bacula.desktop.gnome1.consolehelper scripts/bacula.desktop.gnome2.consolehelper scripts/bacula.desktop.gnome1.xsu scripts/bacula.desktop.gnome2.xsu scripts/gnome-console.console_apps scripts/mtx-changer scripts/disk-changer scripts/dvd-handler scripts/bacula-tray-monitor.desktop scripts/logwatch/Makefile scripts/logwatch/logfile.bacula.conf src/Makefile src/host.h src/console/Makefile src/console/bconsole.conf src/gnome2-console/Makefile src/gnome2-console/gnome-console.conf src/wx-console/Makefile src/wx-console/wx-console.conf src/tray-monitor/Makefile src/tray-monitor/tray-monitor.conf src/dird/Makefile src/dird/bacula-dir.conf src/lib/Makefile src/stored/Makefile src/stored/bacula-sd.conf src/filed/Makefile src/filed/bacula-fd.conf src/filed/win32/Makefile src/cats/Makefile src/cats/make_catalog_backup src/cats/delete_catalog_backup src/cats/create_postgresql_database src/cats/update_postgresql_tables src/cats/make_postgresql_tables src/cats/grant_postgresql_privileges src/cats/drop_postgresql_tables src/cats/drop_postgresql_database src/cats/create_mysql_database src/cats/update_mysql_tables src/cats/make_mysql_tables src/cats/grant_mysql_privileges src/cats/drop_mysql_tables src/cats/drop_mysql_database src/cats/create_sqlite_database src/cats/update_sqlite_tables src/cats/make_sqlite_tables src/cats/grant_sqlite_privileges src/cats/drop_sqlite_tables src/cats/drop_sqlite_database src/cats/create_sqlite3_database src/cats/update_sqlite3_tables src/cats/make_sqlite3_tables src/cats/grant_sqlite3_privileges src/cats/drop_sqlite3_tables src/cats/drop_sqlite3_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/update_bdb_tables src/cats/make_bdb_tables src/cats/grant_bdb_privileges src/cats/drop_bdb_tables src/cats/drop_bdb_database src/cats/create_bacula_database src/cats/update_bacula_tables src/cats/grant_bacula_privileges src/cats/make_bacula_tables src/cats/drop_bacula_tables src/cats/drop_bacula_database src/findlib/Makefile src/pygtk-console/Makefile src/tools/Makefile src/win32/winbacula.nsi src/win32/baculafd/bacula-fd.conf src/win32/Makefile src/win32/console/bconsole.conf src/win32/wx-console/wx-console.conf src/win32/pebuilder/Makefile po/Makefile.in $PFILES" ac_config_commands="$ac_config_commands default" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -30398,6 +30398,7 @@ do "scripts/bacula.desktop.gnome2.xsu" ) CONFIG_FILES="$CONFIG_FILES scripts/bacula.desktop.gnome2.xsu" ;; "scripts/gnome-console.console_apps" ) CONFIG_FILES="$CONFIG_FILES scripts/gnome-console.console_apps" ;; "scripts/mtx-changer" ) CONFIG_FILES="$CONFIG_FILES scripts/mtx-changer" ;; + "scripts/disk-changer" ) CONFIG_FILES="$CONFIG_FILES scripts/disk-changer" ;; "scripts/dvd-handler" ) CONFIG_FILES="$CONFIG_FILES scripts/dvd-handler" ;; "scripts/bacula-tray-monitor.desktop" ) CONFIG_FILES="$CONFIG_FILES scripts/bacula-tray-monitor.desktop" ;; "scripts/logwatch/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/logwatch/Makefile" ;; diff --git a/bacula/kernstodo b/bacula/kernstodo index a857ee2233..df9fc31983 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 11 January 2006 + 08 February 2006 Major development: Project Developer @@ -15,14 +15,13 @@ Document: - %d and %v only valid on Director, not for ClientRunBefore/After. Priority: -- Implement a way to disable a drive (so you can use the second - drive of an autochanger, and the first one will not be used or - even defined). - Implement code that makes the Dir aware that a drive is an autochanger (so the user doesn't need to use the Autochanger = yes directive). For 1.39: +- Detect resource deadlock in Migrate when same job wants to read + and write the same device. - Make hardlink code at line 240 of find_one.c use binary search. - Queue warning/error messages during restore so that they are reported at the end of the report rather than being @@ -1276,3 +1275,9 @@ Block Position: 0 integers. - Implement status that shows why a job is being held in reserve, or rather why none of the drives are suitable. +- Implement a way to disable a drive (so you can use the second + drive of an autochanger, and the first one will not be used or + even defined). +- Make sure Maximum Volumes is respected in Pools when adding + Volumes (e.g. when pulling a Scratch volume). + diff --git a/bacula/kes-1.39 b/bacula/kes-1.39 index 6cb67deade..9e3c3d8711 100644 --- a/bacula/kes-1.39 +++ b/bacula/kes-1.39 @@ -4,8 +4,61 @@ General: Changes to 1.39.5 +14Feb06 +- Add disk-changer to scripts directory + configure/Makefile +- Eliminate PoolId from jcr -- it is in jcr->jr.PoolId +- Implement store_bit scanner to replace store_yesno. Mostly done. +- Implement new store_bool that stores in a bool. +- Add true/false to yes/no conf directives. +- Make first cut at changing appropriate store_yesno to store_bool. +- Complete implementation of Pool storage devices. +- Move starting clones to job.c +- Move create_restore_bootstrap_file() to job.c +- Make copy_storage() more general to be able to handle + Pool storage. +- Cleanup a lot of migration code for manual running, including + using Pool storage. +- Move getting a scratch Volume into a subroutine. +- Make all places a Volume that is added to a pool to + respect max vols. +- Fix bug in autochanger recycle code (improper edit 64 bit). +- Fix segfault in restore command when no value specified. +- Start adding code to handle multiple MediaTypes in restore. +- Eliminate race condition in getting Volume name for + two drive autochanger. +- More debug code in autochanger. +- Add storage keyword to bootstrap file, add parsing. +- Move slot in bsr file into Volume record as there will be + a different slot for each Volume. +- Create reserve.h +07Feb06 +- Implement Pool storage overrides. 06Feb06 - Implement first cut of Migration. +- Implement mysql_use_result() from patch by Karl Hakimian. + This reduces significantly the memory consumption during + the restore tree building, and hence runs faster too. +- Implement StorageId patch supplied by user (reggie) in bug + #536. This should permit Bacula to work correctly with two + autochangers. +- Implement Job listing variations suggested by a user. +- Move updating bootstrap code in backup.c to subroutine + update_bootstrap_file(). +- Add new job status elapsed time and bytes written user + friendly job report output patch sent by a user. +- Implement a storage list in Pools. +- Separate out setup_job() code from run_job(). +- Get migration working -- lots of changes in mac.c in both + DIR and SD. +- Apply patch from user (Eric Bollinger I think) that fixes a + DIR crash when no arguments are supplied to a dot command. +- Fix typo (strcpy->strcmp) in ua_prune.c as reported by Martin. +- Fix command arg name->volume in label command of gnome-console. +- Fix SD acquire.c to release correct DCR by explicitly testing + on the dcr address rather than trying to "devine" if it is a read + or write dcr. This failed in error conditions when the device was + not fully setup. + 30Jan06 - Apply user supplied patch for more readable rate output in job report. diff --git a/bacula/scripts/.cvsignore b/bacula/scripts/.cvsignore index f1c514e9e1..e39d44a262 100644 --- a/bacula/scripts/.cvsignore +++ b/bacula/scripts/.cvsignore @@ -1,3 +1,4 @@ +disk-changer bacula-tray-monitor.desktop bacula-tray-monior.desktop .xvpics diff --git a/bacula/scripts/Makefile.in b/bacula/scripts/Makefile.in index d440b3c48a..1bf17739fc 100755 --- a/bacula/scripts/Makefile.in +++ b/bacula/scripts/Makefile.in @@ -43,6 +43,11 @@ install: installdirs $(MV) -f ${DESTDIR}${scriptdir}/mtx-changer ${DESTDIR}${scriptdir}/mtx-changer.old; \ fi $(INSTALL_SCRIPT) mtx-changer $(DESTDIR)$(scriptdir)/mtx-changer + @if test -f ${DESTDIR}${scriptdir}/disk-changer; then \ + echo " ==> Saving existing disk-changer to disk-changer.old"; \ + $(MV) -f ${DESTDIR}${scriptdir}/disk-changer ${DESTDIR}${scriptdir}/disk-changer.old; \ + fi + $(INSTALL_SCRIPT) disk-changer $(DESTDIR)$(scriptdir)/disk-changer @if test -f ${DESTDIR}${scriptdir}/dvd-handler; then \ echo " ==> Saving existing dvd-handler to dvd-handler.old"; \ $(MV) -f ${DESTDIR}${scriptdir}/dvd-handler ${DESTDIR}${scriptdir}/dvd-handler.old; \ @@ -66,6 +71,7 @@ uninstall: (cd $(DESTDIR)$(scriptdir); $(RMF) bacula) (cd $(DESTDIR)$(scriptdir); $(RMF) fd) (cd $(DESTDIR)$(scriptdir); $(RMF) mtx-changer) + (cd $(DESTDIR)$(scriptdir); $(RMF) disk-changer) (cd $(DESTDIR)$(scriptdir); $(RMF) dvd-handler) (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.gdb) (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.dbx) @@ -76,7 +82,7 @@ Makefile: Makefile.in cd $(topdir) \ && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status chmod 755 startmysql stopmysql bacula startit stopit btraceback - chmod 755 mtx-changer dvd-handler bconsole gconsole + chmod 755 disk-changer mtx-changer dvd-handler bconsole gconsole Makefiles: $(SHELL) config.status diff --git a/bacula/scripts/disk-changer.in b/bacula/scripts/disk-changer.in new file mode 100644 index 0000000000..7181c60f2d --- /dev/null +++ b/bacula/scripts/disk-changer.in @@ -0,0 +1,211 @@ +#!/bin/sh +# +# Bacula interface to virtual autoloader using disk storage +# +# $Id$ +# +# If you set in your Device resource +# +# Changer Command = "path-to-this-script/disk-changer" %c %o %S %a %d +# you will have the following input to this script: +# +# So Bacula will always call with all the following arguments, even though +# in come cases, not all are used. +# +# disk-changer "changer-device" "command" "slot" "archive-device" "drive-index" +# $1 $2 $3 $4 $5 +# +# By default the autochanger has 10 Volumes and 1 Drive. +# +# Note: For this script to work, you *must" specify +# Device Type = File +# in each of the Devices associated with your AutoChanger resource. +# +# changer-device is the name of a file that overrides the default +# volumes and drives. It may have: +# maxslot=n where n is one based (default 10) +# maxdrive=m where m is zero based (default 1 -- i.e. 2 drives) +# +# This code can also simulate barcodes. You simply put +# a list of the slots and barcodes in the "base" directory/barcodes. +# See below for the base directory definition. Example of a +# barcodes file: +# /var/bacula/barcodes +# 1:Vol001 +# 2:Vol002 +# ... +# +# archive-device is the name of the base directory where you want the +# Volumes stored appended with /drive0 for the first drive; /drive1 +# for the second drive, ... For example, you might use +# /var/bacula/drive0 Note: you must not have a trailing slash, and +# the string (e.g. /drive0) must be unique, and it must not match +# any other part of the directory name. These restrictions could be +# easily removed by any clever script jockey. +# +# Full example: disk-changer /var/bacula/conf load 1 /var/bacula/drive0 0 +# +# The Volumes will be created with names slot1, slot2, slot3, ... maxslot in the +# base directory. In the above example the base directory is /var/bacula. +# However, as with tapes, their Bacula Volume names will be stored inside the +# Volume label. In addition to the Volumes (e.g. /var/bacula/slot1, +# /var/bacula/slot3, ...) this script will create a /var/bacula/loadedn +# file to keep track of what Slot is loaded. You should not change this file. +# +# + +wd=@working_dir@ + +# +# log whats done +# +# to turn on logging, uncomment the following line +#touch $wd/disk-changer.log +# +dbgfile="$wd/disk-changer.log" +debug() { + if test -e $dbgfile; then + echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile + fi +} + + +# +# Create a temporary file +# +make_temp_file() { + TMPFILE=`mktemp -t mtx.XXXXXXXXXX` + if test x${TMPFILE} = x; then + TMPFILE="$wd/disk-changer.$$" + if test -f ${TMPFILE}; then + echo "Temp file security problem on: ${TMPFILE}" + exit 1 + fi + fi +} + +# check parameter count on commandline +# +check_parm_count() { + pCount=$1 + pCountNeed=$2 + if test $pCount -lt $pCountNeed; then + echo "usage: disk-changer ctl-device command [slot archive-device drive-index]" + echo " Insufficient number of arguments arguments given." + if test $pCount -lt 2; then + echo " Mimimum usage is first two arguments ..." + else + echo " Command expected $pCountNeed arguments" + fi + exit 1 + fi +} + +# +# Strip off the final name in order to get the Directory ($dir) +# that we are dealing with. +# +get_dir() { + bn=`basename $device` + dir=`echo "$device" | sed -e s%/$bn%%g -` +} + + +# Setup arguments +ctl=$1 +cmd="$2" +slot=$3 +device=$4 +drive=$5 + +# set defaults +maxdrive=1 +maxslot=10 + +# Pull in conf file +if [ -f $ctl ]; then + . $ctl +fi + + +# Check for special cases where only 2 arguments are needed, +# all others are a minimum of 5 +# +case $2 in + list) + check_parm_count $# 2 + ;; + slots) + check_parm_count $# 2 + ;; + *) + check_parm_count $# 5 + if [ $drive -gt $maxdrive ]; then + echo "Drive ($drive) out of range (0-$maxdrive)" + exit 1 + fi + if [ $slot -gt $maxslot ]; then + echo "Slot ($slot) out of range (1-$maxslot)" + exit 1 + fi + ;; +esac + + + +debug "Parms: $ctl $cmd $slot $device $drive" + +case $cmd in + unload) + debug "Doing disk -f $ctl unload $slot $device $drive" + get_dir + echo "0" >$dir/loaded${drive} + unlink $device 2>/dev/null >/dev/null + rm -f $device + ;; + + load) + debug "Doing disk $ctl load $slot $device $drive" + get_dir + echo "0" >$dir/loaded${drive} + unlink $device 2>/dev/null >/dev/null + rm -f $device + ln -s $dir/slot${slot} $device + rtn=$? + if [ $rtn -eq 0 ]; then + echo $slot >$dir/loaded${drive} + fi + exit $rtn + ;; + + list) + debug "Doing disk -f $ctl -- to list volumes" + get_dir + if [ -f $dir/barcodes ]; then + cat $dir/barcodes + else + i=1 + while [ $i -le $maxslot ]; do + echo "$i:" + i=`expr $i + 1` + done + fi + exit 0 + ;; + + loaded) + debug "Doing disk -f $ctl $drive -- to find what is loaded" + get_dir + if [ -f $dir/loaded${drive} ]; then + cat $dir/loaded${drive} + else + echo "0" + fi + exit + ;; + + slots) + debug "Doing disk -f $ctl -- to get count of slots" + echo $maxslot + ;; +esac diff --git a/bacula/scripts/mtx-changer.in b/bacula/scripts/mtx-changer.in index 217981ba29..41498ef89e 100644 --- a/bacula/scripts/mtx-changer.in +++ b/bacula/scripts/mtx-changer.in @@ -11,7 +11,7 @@ # # So Bacula will always call with all the following arguments, even though # in come cases, not all are used. - +# # mtx-changer "changer-device" "command" "slot" "archive-device" "drive-index" # $1 $2 $3 $4 $5 # @@ -36,6 +36,20 @@ MTX=@MTX@ +# +# log whats done +# +# to turn on logging, uncomment the following line +#touch @working_dir@/mtx.log +# +dbgfile="@working_dir@/mtx.log" +debug() { + if test -e $dbgfile; then + echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile + fi +} + + # # Create a temporary file # @@ -65,19 +79,44 @@ wait_for_drive() { if mt -f $1 status | grep ONLINE >/dev/null 2>&1; then break fi -# echo "Device $1 - not ready, retrying..." + debug "Device $1 - not ready, retrying..." sleep 1 i=`expr $i + 1` done } +# check parameter count on commandline +# +check_parm_count() { + pCount=$1 + pCountNeed=$2 + if test $pCount -lt $pCountNeed; then + echo "usage: mtx-changer ctl-device command [slot archive-device drive-index]" + echo " Insufficient number of arguments arguments given." + if test $pCount -lt 2; then + echo " Mimimum usage is first two arguments ..." + else + echo " Command expected $pCountNeed arguments" + fi + exit 1 + fi +} + +# Check for special cases where only 2 arguments are needed, +# all others are a minimum of 5 +# +case $2 in + list) + check_parm_count $# 2 + ;; + slots) + check_parm_count $# 2 + ;; + *) + check_parm_count $# 5 + ;; +esac -if test $# -lt 2 ; then - echo "usage: mtx-changer ctl-device command slot archive-device drive" - echo " Insufficient number of arguments arguments given." - echo " Mimimum usage is first two arguments ..." - exit 1 -fi # Setup arguments ctl=$1 @@ -86,36 +125,20 @@ slot=$3 device=$4 drive=$5 - -# -# Check for special cases where only 2 arguments are needed, -# all others are a minimum of 3 -case $cmd in - list) - ;; - slots) - ;; - *) - if test $# -lt 5; then - echo "usage: mtx-changer ctl-device command slot archive-device drive" - echo " Insufficient number of arguments arguments given." - exit 1 - fi - ;; -esac - +debug "Parms: $ctl $cmd $slot $device $drive" case $cmd in unload) -# echo "Doing mtx -f $ctl unload $slot $drive" + debug "Doing mtx -f $ctl unload $slot $drive" # # enable the following line if you need to eject the cartridge # mt -f $device offline +# sleep 10 ${MTX} -f $ctl unload $slot $drive ;; load) -# echo "Doing mtx -f $ctl load $slot $drive" + debug "Doing mtx -f $ctl load $slot $drive" ${MTX} -f $ctl load $slot $drive rtn=$? # @@ -127,13 +150,15 @@ case $cmd in ;; list) -# echo "Doing mtx -f $ctl -- to list volumes" + debug "Doing mtx -f $ctl -- to list volumes" make_temp_file +# Enable the following if you are using barcodes and need an inventory +# $(MTX) -f $ctl inventory ${MTX} -f $ctl status >${TMPFILE} rtn=$? cat ${TMPFILE} | grep " *Storage Element [0-9]*:.*Full" | awk "{print \$3 \$4}" | sed "s/Full *\(:VolumeTag=\)*//" cat ${TMPFILE} | grep "^Data Transfer Element [0-9]*:Full (Storage Element [0-9]" | awk '{printf "%s:%s\n",$7,$10}' - rm -f ${TMPFILE} 2>&1 >/dev/null + rm -f ${TMPFILE} >/dev/null 2>&1 # # If you have a VXA PacketLoader and the above does not work, try # turning it off and enabling the following line. @@ -142,18 +167,18 @@ case $cmd in ;; loaded) -# echo "Doing mtx -f $ctl $drive -- to find what is loaded" + debug "Doing mtx -f $ctl $drive -- to find what is loaded" make_temp_file ${MTX} -f $ctl status >${TMPFILE} rtn=$? cat ${TMPFILE} | grep "^Data Transfer Element $drive:Full" | awk "{print \$7}" cat ${TMPFILE} | grep "^Data Transfer Element $drive:Empty" | awk "{print 0}" - rm -f ${TMPFILE} 2>&1 >/dev/null + rm -f ${TMPFILE} >/dev/null 2>&1 exit $rtn ;; slots) -# echo "Doing mtx -f $ctl -- to get count of slots" + debug "Doing mtx -f $ctl -- to get count of slots" ${MTX} -f $ctl status | grep " *Storage Changer" | awk "{print \$5}" ;; esac diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index a875d44528..048de8fd42 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -105,7 +105,7 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) jr->JobType, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2)); } else { - Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->JobLevel); + Mmsg1(mdb->errmsg, _("Unknown level=%d\n"), jr->JobLevel); goto bail_out; } } else { @@ -199,6 +199,7 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) /* Find last full */ db_lock(mdb); + Dmsg2(100, "JobLevel=%d JobType=%d\n", jr->JobLevel, jr->JobType); if (jr->JobLevel == L_VERIFY_CATALOG) { Mmsg(mdb->cmd, "SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND " @@ -208,7 +209,7 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) edit_int64(jr->ClientId, ed1)); } else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || jr->JobLevel == L_VERIFY_DISK_TO_CATALOG || - jr->JobType == JT_MIGRATE) { + jr->JobType == JT_BACKUP) { if (Name) { Mmsg(mdb->cmd, "SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND " @@ -220,7 +221,7 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) edit_int64(jr->ClientId, ed1)); } } else { - Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->JobLevel); + Mmsg1(&mdb->errmsg, _("Unknown Job level=%d\n"), jr->JobLevel); db_unlock(mdb); return false; } diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c index 0ef206407a..10dae2d305 100644 --- a/bacula/src/console/console_conf.c +++ b/bacula/src/console/console_conf.c @@ -76,8 +76,8 @@ static RES_ITEM cons_items[] = { {"rcfile", store_dir, ITEM(res_cons.rc_file), 0, 0, 0}, {"historyfile", store_dir, ITEM(res_cons.hist_file), 0, 0, 0}, {"password", store_password, ITEM(res_cons.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_yesno, ITEM(res_cons.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_cons.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(res_cons.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_cons.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_cons.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_cons.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_cons.tls_certfile), 0, 0, 0}, @@ -93,8 +93,8 @@ static RES_ITEM dir_items[] = { {"dirport", store_int, ITEM(res_dir.DIRport), 0, ITEM_DEFAULT, 9101}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, diff --git a/bacula/src/dird/autoprune.c b/bacula/src/dird/autoprune.c index bf054db8eb..e0214080d9 100644 --- a/bacula/src/dird/autoprune.c +++ b/bacula/src/dird/autoprune.c @@ -101,7 +101,7 @@ int prune_volumes(JCR *jcr) db_lock(jcr->db); /* Get the List of all media ids in the current Pool */ - if (!db_get_media_ids(jcr, jcr->db, jcr->PoolId, &num_ids, &ids)) { + if (!db_get_media_ids(jcr, jcr->db, jcr->jr.PoolId, &num_ids, &ids)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); goto bail_out; } @@ -114,7 +114,7 @@ int prune_volumes(JCR *jcr) continue; } /* Prune only Volumes from current Pool */ - if (jcr->PoolId != mr.PoolId) { + if (jcr->jr.PoolId != mr.PoolId) { continue; } /* Prune only Volumes with status "Full", or "Used" */ diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index f8107485b7..496e14d6d8 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -97,35 +97,18 @@ bool do_backup_init(JCR *jcr) } } } - jcr->PoolId = pr.PoolId; jcr->jr.PoolId = pr.PoolId; - /* - * Fire off any clone jobs (run directives) - */ - Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds); - if (!jcr->cloned && jcr->job->run_cmds) { - char *runcmd; - JOB *job = jcr->job; - POOLMEM *cmd = get_pool_memory(PM_FNAME); - UAContext *ua = new_ua_context(jcr); - ua->batch = true; - foreach_alist(runcmd, job->run_cmds) { - cmd = edit_job_codes(jcr, cmd, runcmd, ""); - Mmsg(ua->cmd, "run %s cloned=yes", cmd); - Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd); - parse_ua_args(ua); /* parse command */ - int stat = run_cmd(ua, ua->cmd); - if (stat == 0) { - Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n")); - } else { - Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat); - } - } - free_ua_context(ua); - free_pool_memory(cmd); + /* If pool storage specified, use it instead of job storage */ + copy_storage(jcr, jcr->pool->storage); + + if (!jcr->storage) { + Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n")); + return false; } + create_clones(jcr); /* run any clone jobs */ + return true; } diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 62e4400077..e599bd95f2 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -160,7 +160,7 @@ void catalog_request(JCR *jcr, BSOCK *bs) * Pool matches, and it is either Append or Recycle * and Media Type matches and Pool allows any volume. */ - if (mr.PoolId != jcr->PoolId) { + if (mr.PoolId != jcr->jr.PoolId) { reason = _("not in Pool"); } else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) { reason = _("not correct MediaType"); diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 63a3b1ea8a..617400c8a2 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -559,6 +559,7 @@ static int check_resources() for (i=0; job_items[i].name; i++) { char **def_svalue, **svalue; /* string value */ int *def_ivalue, *ivalue; /* integer value */ + bool *def_bvalue, *bvalue; /* bool value */ int64_t *def_lvalue, *lvalue; /* 64 bit values */ uint32_t offset; @@ -608,9 +609,9 @@ static int check_resources() } /* * Handle integer fields - * Note, our store_yesno does not handle bitmaped fields + * Note, our store_bit does not handle bitmaped fields */ - } else if (job_items[i].handler == store_yesno || + } else if (job_items[i].handler == store_bit || job_items[i].handler == store_pint || job_items[i].handler == store_jobtype || job_items[i].handler == store_level || @@ -634,6 +635,16 @@ static int check_resources() lvalue = (int64_t *)((char *)job + offset); *lvalue = *def_lvalue; set_bit(i, job->hdr.item_present); + /* + * Handle bool fields + */ + } else if (job_items[i].handler == store_bool) { + def_bvalue = (bool *)((char *)(job->jobdefs) + offset); + Dmsg5(400, "Job \"%s\", field \"%s\" def_bvalue=%d item %d offset=%u\n", + job->hdr.name, job_items[i].name, *def_bvalue, i, offset); + bvalue = (bool *)((char *)job + offset); + *bvalue = *def_bvalue; + set_bit(i, job->hdr.item_present); } } } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 38de435a16..0ebace8e60 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -97,9 +97,9 @@ static RES_ITEM dir_items[] = { {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, - {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0}, + {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, @@ -127,9 +127,9 @@ static RES_ITEM con_items[] = { {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0}, {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0}, {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0}, - {"tlsenable", store_yesno, ITEM(res_con.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_con.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_yesno, ITEM(res_con.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0}, + {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true}, {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0}, @@ -157,10 +157,10 @@ static RES_ITEM cli_items[] = { {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0}, {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60}, {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180}, - {"autoprune", store_yesno, ITEM(res_client.AutoPrune), 1, ITEM_DEFAULT, 1}, + {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true}, {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, - {"tlsenable", store_yesno, ITEM(res_client.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_client.tls_require), 1, 0, 0}, + {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0}, @@ -182,12 +182,12 @@ static RES_ITEM store_items[] = { {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0}, {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0}, {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0}, - {"autochanger", store_yesno, ITEM(res_store.autochanger), 1, ITEM_DEFAULT, 0}, - {"enabled", store_yesno, ITEM(res_store.enabled), 1, ITEM_DEFAULT, 1}, + {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0}, + {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true}, {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */ - {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, 0, 0}, + {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0}, @@ -213,7 +213,7 @@ static RES_ITEM cat_items[] = { {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0}, {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0}, /* Turned off for the moment */ - {"multipleconnections", store_yesno, ITEM(res_cat.mult_db_connections), 0, 0, 0}, + {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -228,7 +228,7 @@ RES_ITEM job_items[] = { {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0}, {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0}, {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0}, - {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, ITEM_REQUIRED, 0}, + {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0}, {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0}, {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0}, {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0}, @@ -255,26 +255,26 @@ RES_ITEM job_items[] = { {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0}, {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0}, {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0}, - {"prefixlinks", store_yesno, ITEM(res_job.PrefixLinks), 1, ITEM_DEFAULT, 0}, - {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0}, - {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0}, - {"prunevolumes",store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0}, - {"enabled", store_yesno, ITEM(res_job.enabled), 1, ITEM_DEFAULT, 1}, - {"spoolattributes",store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0}, - {"spooldata", store_yesno, ITEM(res_job.spool_data), 1, ITEM_DEFAULT, 0}, - {"rerunfailedlevels", store_yesno, ITEM(res_job.rerun_failed_levels), 1, ITEM_DEFAULT, 0}, - {"prefermountedvolumes", store_yesno, ITEM(res_job.PreferMountedVolumes), 1, ITEM_DEFAULT, 1}, + {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false}, + {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false}, + {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false}, + {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false}, + {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true}, + {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false}, + {"spooldata", store_bit, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false}, + {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false}, + {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true}, {"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}, {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, - {"rescheduleonerror", store_yesno, ITEM(res_job.RescheduleOnError), 1, ITEM_DEFAULT, 0}, + {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false}, {"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}, - {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0}, + {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -287,8 +287,8 @@ static RES_ITEM fs_items[] = { {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0}, {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0}, {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0}, - {"ignorefilesetchanges", store_yesno, ITEM(res_fs.ignore_fs_changes), 1, ITEM_DEFAULT, 0}, - {"enablevss", store_yesno, ITEM(res_fs.enable_vss), 1, ITEM_DEFAULT, 0}, + {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false}, + {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -314,18 +314,18 @@ static RES_ITEM pool_items[] = { {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0}, {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0}, {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0}, - {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0}, - {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1}, - {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once),1, 0, 0}, - {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0}, - {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0}, - {"recyclecurrentvolume", store_yesno, ITEM(res_pool.recycle_current_volume), 1, 0, 0}, + {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0}, + {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true}, + {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0}, + {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0}, + {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0}, + {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0}, {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0}, {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0}, {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0}, {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0}, - {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, ITEM_DEFAULT, 1}, - {"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1}, + {"acceptanyvolume", store_bool, ITEM(res_pool.accept_any_volume), 0, ITEM_DEFAULT, true}, + {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true}, {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365}, {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0}, {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0}, @@ -333,8 +333,8 @@ static RES_ITEM pool_items[] = { {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0}, {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0}, {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0}, - {"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1}, - {"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1}, + {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true}, + {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true}, {NULL, NULL, NULL, 0, 0, 0} }; diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 45b48eb51c..6886983ee4 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -102,9 +102,6 @@ public: uint32_t MaxConcurrentJobs; /* Max concurrent jobs for whole director */ utime_t FDConnectTimeout; /* timeout for connect in seconds */ utime_t SDConnectTimeout; /* timeout in seconds */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ - int tls_verify_peer; /* TLS Verify Client Certificate */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Server Certificate File */ @@ -112,6 +109,9 @@ public: char *tls_dhfile; /* TLS Diffie-Hellman Parameters */ alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool tls_verify_peer; /* TLS Verify Client Certificate */ }; /* @@ -168,9 +168,6 @@ public: RES hdr; char *password; /* UA server password */ alist *ACL_lists[Num_ACL]; /* pointers to ACLs */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ - int tls_verify_peer; /* TLS Verify Client Certificate */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Server Certificate File */ @@ -178,6 +175,9 @@ public: char *tls_dhfile; /* TLS Diffie-Hellman Parameters */ alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool tls_verify_peer; /* TLS Verify Client Certificate */ }; @@ -189,7 +189,7 @@ class CAT { public: RES hdr; - int db_port; /* Port -- not yet implemented */ + int db_port; /* Port */ char *db_address; /* host name for remote access */ char *db_socket; /* Socket for local access */ char *db_password; @@ -208,7 +208,6 @@ public: RES hdr; int FDport; /* Where File daemon listens */ - int AutoPrune; /* Do automatic pruning? */ utime_t FileRetention; /* file retention period in seconds */ utime_t JobRetention; /* job retention period in seconds */ char *address; @@ -216,13 +215,14 @@ public: CAT *catalog; /* Catalog resource */ uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Client Certificate File */ char *tls_keyfile; /* TLS Client Key File */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool AutoPrune; /* Do automatic pruning? */ }; /* @@ -239,19 +239,19 @@ public: char *password; char *media_type; alist *device; /* Alternate devices for this Storage */ - int autochanger; /* set if autochanger */ - int drives; /* number of drives in autochanger */ uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Client Certificate File */ char *tls_keyfile; /* TLS Client Key File */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool enabled; /* Set if device is enabled */ + bool autochanger; /* set if autochanger */ int64_t StorageId; /* Set from Storage DB record */ - int enabled; /* Set if device is enabled */ + int drives; /* number of drives in autochanger */ /* Methods */ char *dev_name() const; @@ -296,21 +296,21 @@ public: utime_t DiffMaxWaitTime; /* Max Differential job wait time */ utime_t IncMaxWaitTime; /* Max Incremental job wait time */ utime_t MaxStartDelay; /* max start delay in seconds */ - int PrefixLinks; /* prefix soft links with Where path */ - int PruneJobs; /* Force pruning of Jobs */ - int PruneFiles; /* Force pruning of Files */ - int PruneVolumes; /* Force pruning of Volumes */ - int SpoolAttributes; /* Set to spool attributes in SD */ - int spool_data; /* Set to spool data in SD */ - int rerun_failed_levels; /* Upgrade to rerun failed levels */ - int PreferMountedVolumes; /* Prefer vols mounted rather than new one */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - 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 */ - int write_part_after_job; /* Set to write part after job in SD */ - int enabled; /* Set if job enabled */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + int RescheduleTimes; /* Number of times to reschedule job */ + bool RescheduleOnError; /* Set to reschedule on error */ + bool PrefixLinks; /* prefix soft links with Where path */ + bool PruneJobs; /* Force pruning of Jobs */ + bool PruneFiles; /* Force pruning of Files */ + bool PruneVolumes; /* Force pruning of Volumes */ + bool SpoolAttributes; /* Set to spool attributes in SD */ + bool spool_data; /* Set to spool data in SD */ + bool rerun_failed_levels; /* Upgrade to rerun failed levels */ + bool PreferMountedVolumes; /* Prefer vols mounted rather than new one */ + bool write_part_after_job; /* Set to write part after job in SD */ + bool enabled; /* Set if job enabled */ MSGS *messages; /* How and where to send messages */ SCHED *schedule; /* When -- Automatic schedule */ @@ -373,8 +373,8 @@ public: bool have_MD5; /* set if MD5 initialized */ struct MD5Context md5c; /* MD5 of include/exclude */ char MD5[30]; /* base 64 representation of MD5 */ - int ignore_fs_changes; /* Don't force Full if FS changed */ - int enable_vss; /* Enable Volume Shadow Copy */ + bool ignore_fs_changes; /* Don't force Full if FS changed */ + bool enable_vss; /* Enable Volume Shadow Copy */ }; @@ -416,13 +416,6 @@ public: char *label_format; /* Label format string */ char *cleaning_prefix; /* Cleaning label prefix */ int LabelType; /* Bacula/ANSI/IBM label type */ - int use_catalog; /* maintain catalog for media */ - int catalog_files; /* maintain file entries in catalog */ - int use_volume_once; /* write on volume only once */ - int accept_any_volume; /* accept any volume */ - int purge_oldest_volume; /* purge oldest volume */ - int recycle_oldest_volume; /* attempt to recycle oldest volume */ - int recycle_current_volume; /* attempt recycle of current volume */ uint32_t max_volumes; /* max number of volumes */ utime_t VolRetention; /* volume retention period in seconds */ utime_t VolUseDuration; /* duration volume can be used */ @@ -434,8 +427,15 @@ public: uint32_t MigrationLowBytes; /* When migration stops */ POOL *NextPool; /* Next pool for migration */ alist *storage; /* Where is device -- list of Storage to be used */ - int AutoPrune; /* default for pool auto prune */ - int Recycle; /* default for media recycle yes/no */ + bool use_catalog; /* maintain catalog for media */ + bool catalog_files; /* maintain file entries in catalog */ + bool use_volume_once; /* write on volume only once */ + bool accept_any_volume; /* accept any volume */ + bool purge_oldest_volume; /* purge oldest volume */ + bool recycle_oldest_volume; /* attempt to recycle oldest volume */ + bool recycle_current_volume; /* attempt recycle of current volume */ + bool AutoPrune; /* default for pool auto prune */ + bool Recycle; /* default for media recycle yes/no */ }; diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 2c9829e31f..f23976861c 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -406,7 +406,7 @@ bool cancel_job(UAContext *ua, JCR *jcr) /* Cancel Storage daemon */ if (jcr->store_bsock) { if (!ua->jcr->storage) { - copy_storage(ua->jcr, jcr); + copy_storage(ua->jcr, jcr->storage); } else { set_storage(ua->jcr, jcr->store); } @@ -828,7 +828,6 @@ void dird_free_jcr(JCR *jcr) */ void set_jcr_defaults(JCR *jcr, JOB *job) { - STORE *st; jcr->job = job; jcr->JobType = job->JobType; switch (jcr->JobType) { @@ -842,18 +841,7 @@ void set_jcr_defaults(JCR *jcr, JOB *job) } jcr->JobPriority = job->Priority; /* Copy storage definitions -- deleted in dir_free_jcr above */ - if (job->storage) { - if (jcr->storage) { - delete jcr->storage; - } - jcr->storage = New(alist(10, not_owned_by_alist)); - foreach_alist(st, job->storage) { - jcr->storage->append(st); - } - } - if (jcr->storage) { - jcr->store = (STORE *)jcr->storage->first(); - } + copy_storage(jcr, job->storage); jcr->client = job->client; if (!jcr->client_name) { jcr->client_name = get_pool_memory(PM_NAME); @@ -897,28 +885,28 @@ void set_jcr_defaults(JCR *jcr, JOB *job) } } -/* - * copy the storage definitions from an old JCR to a new one + +/* + * Copy the storage definitions from an alist to the JCR */ -void copy_storage(JCR *new_jcr, JCR *old_jcr) +void copy_storage(JCR *jcr, alist *storage) { - if (old_jcr->storage) { + if (storage) { STORE *st; - if (old_jcr->storage) { - delete old_jcr->storage; + if (jcr->storage) { + delete jcr->storage; } - new_jcr->storage = New(alist(10, not_owned_by_alist)); - foreach_alist(st, old_jcr->storage) { - new_jcr->storage->append(st); + jcr->storage = New(alist(10, not_owned_by_alist)); + foreach_alist(st, storage) { + jcr->storage->append(st); } - } - if (old_jcr->store) { - new_jcr->store = old_jcr->store; - } else if (new_jcr->storage) { - new_jcr->store = (STORE *)new_jcr->storage->first(); + } + if (jcr->storage) { + jcr->store = (STORE *)jcr->storage->first(); } } + /* Set storage override */ void set_storage(JCR *jcr, STORE *store) { @@ -933,3 +921,64 @@ void set_storage(JCR *jcr, STORE *store) /* Store not in list, so add it */ jcr->storage->prepend(store); } + +void create_clones(JCR *jcr) +{ + /* + * Fire off any clone jobs (run directives) + */ + Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds); + if (!jcr->cloned && jcr->job->run_cmds) { + char *runcmd; + JOB *job = jcr->job; + POOLMEM *cmd = get_pool_memory(PM_FNAME); + UAContext *ua = new_ua_context(jcr); + ua->batch = true; + foreach_alist(runcmd, job->run_cmds) { + cmd = edit_job_codes(jcr, cmd, runcmd, ""); + Mmsg(ua->cmd, "run %s cloned=yes", cmd); + Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd); + parse_ua_args(ua); /* parse command */ + int stat = run_cmd(ua, ua->cmd); + if (stat == 0) { + Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n")); + } else { + Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat); + } + } + free_ua_context(ua); + free_pool_memory(cmd); + } +} + +bool create_restore_bootstrap_file(JCR *jcr) +{ + RESTORE_CTX rx; + UAContext *ua; + memset(&rx, 0, sizeof(rx)); + rx.bsr = new_bsr(); + rx.JobIds = ""; + rx.bsr->JobId = jcr->target_jr.JobId; + ua = new_ua_context(jcr); + complete_bsr(ua, rx.bsr); + rx.bsr->fi = new_findex(); + rx.bsr->fi->findex = 1; + rx.bsr->fi->findex2 = jcr->target_jr.JobFiles; + jcr->ExpectedFiles = write_bsr_file(ua, rx); + if (jcr->ExpectedFiles == 0) { + free_ua_context(ua); + free_bsr(rx.bsr); + return false; + } + if (jcr->RestoreBootstrap) { + free(jcr->RestoreBootstrap); + } + POOLMEM *fname = get_pool_memory(PM_MESSAGE); + make_unique_restore_filename(ua, &fname); + jcr->RestoreBootstrap = bstrdup(fname); + free_ua_context(ua); + free_bsr(rx.bsr); + free_pool_memory(fname); + jcr->needs_sd = true; + return true; +} diff --git a/bacula/src/dird/jobq.c b/bacula/src/dird/jobq.c index 7c0d86485f..6ec9a5de51 100755 --- a/bacula/src/dird/jobq.c +++ b/bacula/src/dird/jobq.c @@ -509,7 +509,7 @@ void *jobq_server(void *arg) njcr->reschedule_count = jcr->reschedule_count; njcr->JobLevel = jcr->JobLevel; njcr->JobStatus = jcr->JobStatus; - copy_storage(njcr, jcr); + copy_storage(njcr, jcr->storage); njcr->messages = jcr->messages; Dmsg0(2300, "Call to run new job\n"); V(jq->mutex); diff --git a/bacula/src/dird/mac.c b/bacula/src/dird/mac.c index 81c4003a43..aeaeca655a 100644 --- a/bacula/src/dird/mac.c +++ b/bacula/src/dird/mac.c @@ -42,11 +42,7 @@ static char OKbootstrap[] = "3000 OK bootstrap\n"; bool do_mac_init(JCR *jcr) { POOL_DBR pr; - JOB_DBR jr; - JobId_t input_jobid; char *Name; - RESTORE_CTX rx; - UAContext *ua; const char *Type; switch(jcr->JobType) { @@ -71,18 +67,17 @@ bool do_mac_init(JCR *jcr) /* * Find JobId of last job that ran. */ - memcpy(&jr, &jcr->jr, sizeof(jr)); Name = jcr->job->migration_job->hdr.name; Dmsg1(100, "find last jobid for: %s\n", NPRT(Name)); - if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) { - Jmsg(jcr, M_FATAL, 0, _( - _("Unable to find JobId of previous Job for this client.\n"))); + jcr->target_jr.JobType = JT_BACKUP; + if (!db_find_last_jobid(jcr, jcr->db, Name, &jcr->target_jr)) { + Jmsg(jcr, M_FATAL, 0, + _("Previous job \"%s\" not found. ERR=%s\n"), Name, + db_strerror(jcr->db)); return false; } - input_jobid = jr.JobId; - Dmsg1(100, "Last jobid=%d\n", input_jobid); + Dmsg1(100, "Last jobid=%d\n", jcr->target_jr.JobId); - jcr->target_jr.JobId = input_jobid; if (!db_get_job_record(jcr, jcr->db, &jcr->target_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), db_strerror(jcr->db)); @@ -90,7 +85,7 @@ bool do_mac_init(JCR *jcr) } if (jcr->target_jr.JobStatus != 'T') { Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"), - input_jobid, jcr->target_jr.JobStatus); + jcr->target_jr.JobId, jcr->target_jr.JobStatus); return false; } Jmsg(jcr, M_INFO, 0, _("%s using JobId=%d Job=%s\n"), @@ -130,35 +125,19 @@ bool do_mac_init(JCR *jcr) Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name); } } - jcr->PoolId = pr.PoolId; /****FIXME**** this can go away */ jcr->jr.PoolId = pr.PoolId; - memset(&rx, 0, sizeof(rx)); - rx.bsr = new_bsr(); - rx.JobIds = ""; - rx.bsr->JobId = jcr->target_jr.JobId; - ua = new_ua_context(jcr); - complete_bsr(ua, rx.bsr); - rx.bsr->fi = new_findex(); - rx.bsr->fi->findex = 1; - rx.bsr->fi->findex2 = jcr->target_jr.JobFiles; - jcr->ExpectedFiles = write_bsr_file(ua, rx); - if (jcr->ExpectedFiles == 0) { - free_ua_context(ua); - free_bsr(rx.bsr); + /* If pool storage specified, use it instead of job storage */ + copy_storage(jcr, jcr->pool->storage); + + if (!jcr->storage) { + Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n")); return false; } - if (jcr->RestoreBootstrap) { - free(jcr->RestoreBootstrap); + + if (!create_restore_bootstrap_file(jcr)) { + return false; } - POOLMEM *fname = get_pool_memory(PM_MESSAGE); - make_unique_restore_filename(ua, &fname); - jcr->RestoreBootstrap = bstrdup(fname); - free_ua_context(ua); - free_bsr(rx.bsr); - free_pool_memory(fname); - - jcr->needs_sd = true; return true; } @@ -170,6 +149,8 @@ bool do_mac_init(JCR *jcr) */ bool do_mac(JCR *jcr) { + POOL_DBR pr; + POOL *pool; const char *Type; char ed1[100]; BSOCK *sd; @@ -209,15 +190,66 @@ bool do_mac(JCR *jcr) } tjcr = jcr->target_jcr = new_jcr(sizeof(JCR), dird_free_jcr); + memcpy(&tjcr->target_jr, &jcr->target_jr, sizeof(tjcr->target_jr)); set_jcr_defaults(tjcr, tjob); if (!setup_job(tjcr)) { return false; } - tjcr->PoolId = jcr->PoolId; + /* Set output PoolId and FileSetId. */ tjcr->jr.PoolId = jcr->jr.PoolId; tjcr->jr.FileSetId = jcr->jr.FileSetId; + /* + * Get the PoolId used with the original job. Then + * find the pool name from the database record. + */ + memset(&pr, 0, sizeof(pr)); + pr.PoolId = tjcr->target_jr.PoolId; + if (!db_get_pool_record(jcr, jcr->db, &pr)) { + char ed1[50]; + Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"), + edit_int64(pr.PoolId, ed1), db_strerror(jcr->db)); + return false; + } + /* Get the pool resource corresponding to the original job */ + pool = (POOL *)GetResWithName(R_POOL, pr.Name); + if (!pool) { + Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name); + return false; + } + + /* If pool storage specified, use it for restore */ + copy_storage(tjcr, pool->storage); + + /* If the original backup pool has a NextPool, make sure a + * record exists in the database. + */ + if (pool->NextPool) { + memset(&pr, 0, sizeof(pr)); + bstrncpy(pr.Name, pool->NextPool->hdr.name, sizeof(pr.Name)); + + while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */ + /* Try to create the pool */ + if (create_pool(jcr, jcr->db, pool->NextPool, POOL_OP_CREATE) < 0) { + Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. %s"), pr.Name, + db_strerror(jcr->db)); + return false; + } else { + Jmsg(jcr, M_INFO, 0, _("Pool \"%s\" created in database.\n"), pr.Name); + } + } + /* + * put the "NextPool" resource pointer in our jcr so that we + * can pull the Storage reference from it. + */ + tjcr->pool = jcr->pool = pool->NextPool; + tjcr->jr.PoolId = jcr->jr.PoolId = pr.PoolId; + } + + /* If pool storage specified, use it instead of job storage for backup */ + copy_storage(jcr, jcr->pool->storage); + /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"), Type, edit_uint64(jcr->JobId, ed1), jcr->Job); @@ -255,6 +287,9 @@ bool do_mac(JCR *jcr) /* * Now start a job with the Storage daemon */ + Dmsg2(000, "Read store=%s, write store=%s\n", + ((STORE *)tjcr->storage->first())->hdr.name, + ((STORE *)jcr->storage->first())->hdr.name); if (!start_storage_daemon_job(jcr, tjcr->storage, jcr->storage)) { return false; } @@ -299,7 +334,7 @@ bool do_mac(JCR *jcr) void mac_cleanup(JCR *jcr, int TermCode) { char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH]; - char ec1[30], ec2[30], ec3[30]; + char ec1[30], ec2[30], ec3[30], ec4[30], elapsed[50]; char term_code[100], sd_term_msg[100]; const char *term_msg; int msg_type; @@ -426,8 +461,9 @@ void mac_cleanup(JCR *jcr, int TermCode) // bmicrosleep(15, 0); /* for debugging SIGHUP */ Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n" -" Migration JobId: %u\n" -" Backup JobId: %u\n" +" Old Backup JobId: %u\n" +" New Backup JobId: %u\n" +" JobId: %u\n" " Job: %s\n" " Backup Level: %s%s\n" " Client: %s\n" @@ -435,8 +471,10 @@ void mac_cleanup(JCR *jcr, int TermCode) " Pool: \"%s\"\n" " Start time: %s\n" " End time: %s\n" +" Elapsed time: %s\n" +" Priority: %d\n" " SD Files Written: %s\n" -" SD Bytes Written: %s\n" +" SD Bytes Written: %s (%sB)\n" " Rate: %.1f KB/s\n" " Volume name(s): %s\n" " Volume Session Id: %d\n" @@ -448,8 +486,9 @@ void mac_cleanup(JCR *jcr, int TermCode) VERSION, LSMDATE, edt, - jcr->jr.JobId, + jcr->target_jr.JobId, tjcr->jr.JobId, + jcr->jr.JobId, jcr->jr.Job, level_to_str(jcr->JobLevel), jcr->since, jcr->client->hdr.name, @@ -457,8 +496,11 @@ void mac_cleanup(JCR *jcr, int TermCode) jcr->pool->hdr.name, sdt, edt, + edit_utime(RunTime, elapsed, sizeof(elapsed)), + jcr->JobPriority, edit_uint64_with_commas(jcr->SDJobFiles, ec2), edit_uint64_with_commas(jcr->SDJobBytes, ec3), + edit_uint64_with_suffix(jcr->jr.JobBytes, ec4), (float)kbps, tjcr->VolumeName, jcr->VolSessionId, @@ -469,5 +511,7 @@ void mac_cleanup(JCR *jcr, int TermCode) term_code); Dmsg1(100, "Leave mac_cleanup() target_jcr=0x%x\n", jcr->target_jcr); - free_jcr(jcr->target_jcr); + if (jcr->target_jcr) { + free_jcr(jcr->target_jcr); + } } diff --git a/bacula/src/dird/newvol.c b/bacula/src/dird/newvol.c index b10447272d..354c5ddec2 100644 --- a/bacula/src/dird/newvol.c +++ b/bacula/src/dird/newvol.c @@ -13,7 +13,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2000-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/bacula/src/dird/next_vol.c b/bacula/src/dird/next_vol.c index d04e55e9b4..e2bcfe616d 100644 --- a/bacula/src/dird/next_vol.c +++ b/bacula/src/dird/next_vol.c @@ -9,7 +9,7 @@ * Version $Id$ */ /* - Copyright (C) 2001-2005 Kern Sibbald + Copyright (C) 2001-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,6 +26,9 @@ #include "bacula.h" #include "dird.h" +static bool get_scratch_volume(JCR *jcr, MEDIA_DBR *mr, bool InChanger); + + /* * Items needed: * mr.PoolId must be set @@ -43,7 +46,7 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int index, bool create) STORE *store = jcr->store; bstrncpy(mr->MediaType, store->media_type, sizeof(mr->MediaType)); - Dmsg2(100, "CatReq FindMedia: Id=%d, MediaType=%s\n", (int)mr->PoolId, mr->MediaType); + Dmsg2(100, "CatReq FindMedia: PoolId=%d, MediaType=%s\n", (int)mr->PoolId, mr->MediaType); /* * If we are using an Autochanger, restrict Volume * search to the Autochanger on the first pass @@ -87,48 +90,10 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int index, bool create) } if (!ok) { - MEDIA_DBR smr; - POOL_DBR pr; - POOLMEM *query; - char ed1[50], ed2[50]; /* * 5. Try pulling a volume from the Scratch pool */ - memset(&pr, 0, sizeof(pr)); - bstrncpy(pr.Name, "Scratch", sizeof(pr.Name)); - if (db_get_pool_record(jcr, jcr->db, &pr)) { - memset(&smr, 0, sizeof(smr)); - smr.PoolId = pr.PoolId; - bstrncpy(smr.VolStatus, "Append", sizeof(smr.VolStatus)); /* want only appendable volumes */ - bstrncpy(smr.MediaType, mr->MediaType, sizeof(smr.MediaType)); - if (db_find_next_volume(jcr, jcr->db, 1, InChanger, &smr)) { - query = get_pool_memory(PM_MESSAGE); - db_lock(jcr->db); - Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s", - edit_int64(mr->PoolId, ed1), - edit_int64(smr.MediaId, ed2)); - ok = db_sql_query(jcr->db, query, NULL, NULL); - db_unlock(jcr->db); - Jmsg(jcr, M_INFO, 0, _("Using Volume \"%s\" from 'Scratch' pool.\n"), - smr.VolumeName); - /* Set new Pool Id in smr record, then copy it to mr */ - smr.PoolId = mr->PoolId; - memcpy(mr, &smr, sizeof(MEDIA_DBR)); - memset(&pr, 0, sizeof(pr)); - bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name)); - /* Set default parameters from current pool */ - if (db_get_pool_record(jcr, jcr->db, &pr)) { - set_pool_dbr_defaults_in_media_dbr(mr, &pr); - if (!db_update_media_record(jcr, jcr->db, mr)) { - Jmsg(jcr, M_WARNING, 0, _("Unable to update Volume record: ERR=%s"), - db_strerror(jcr->db)); - } - } else { - Jmsg(jcr, M_WARNING, 0, _("Unable to get Pool record: ERR=%s"), - db_strerror(jcr->db)); - } - } - } + ok = get_scratch_volume(jcr, mr, InChanger); } if (!ok && create) { @@ -333,3 +298,71 @@ void check_if_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, const char **r } } } + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static bool get_scratch_volume(JCR *jcr, MEDIA_DBR *mr, bool InChanger) +{ + MEDIA_DBR smr; + POOL_DBR spr, pr; + bool ok = false; + char ed1[50], ed2[50]; + + /* Only one thread at a time can pull from the scratch pool */ + P(mutex); + /* + * Get pool record where the Scratch Volume will go + */ + memset(&pr, 0, sizeof(pr)); + bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name)); + if (!db_get_pool_record(jcr, jcr->db, &pr)) { + Jmsg(jcr, M_WARNING, 0, _("Unable to get Pool record: ERR=%s"), + db_strerror(jcr->db)); + goto bail_out; + } + if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) { + Jmsg(jcr, M_WARNING, 0, _("Unable to use Scratch Volume, Pool full MaxVols=%d\n"), + pr.MaxVols); + goto bail_out; + } + /* + * Get Pool record for Scratch Pool + */ + memset(&spr, 0, sizeof(spr)); + bstrncpy(spr.Name, "Scratch", sizeof(spr.Name)); + if (db_get_pool_record(jcr, jcr->db, &spr)) { + memset(&smr, 0, sizeof(smr)); + smr.PoolId = spr.PoolId; + bstrncpy(smr.VolStatus, "Append", sizeof(smr.VolStatus)); /* want only appendable volumes */ + bstrncpy(smr.MediaType, mr->MediaType, sizeof(smr.MediaType)); + if (db_find_next_volume(jcr, jcr->db, 1, InChanger, &smr)) { + POOL_MEM query(PM_MESSAGE); + db_lock(jcr->db); + Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s", + edit_int64(mr->PoolId, ed1), + edit_int64(smr.MediaId, ed2)); + ok = db_sql_query(jcr->db, query.c_str(), NULL, NULL); + db_unlock(jcr->db); + if (!ok) { + Jmsg(jcr, M_WARNING, 0, _("Failed to move Scratch Volume. ERR=%s\n"), + db_strerror(jcr->db)); + goto bail_out; + } + Jmsg(jcr, M_INFO, 0, _("Using Volume \"%s\" from 'Scratch' pool.\n"), + smr.VolumeName); + /* Set new Pool Id in smr record, then copy it to mr */ + smr.PoolId = mr->PoolId; + memcpy(mr, &smr, sizeof(MEDIA_DBR)); + /* Set default parameters from current pool */ + set_pool_dbr_defaults_in_media_dbr(mr, &pr); + if (!db_update_media_record(jcr, jcr->db, mr)) { + Jmsg(jcr, M_WARNING, 0, _("Unable to update Volume record: ERR=%s"), + db_strerror(jcr->db)); + ok = false; + } + } + } +bail_out: + V(mutex); + return ok; +} diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index ef34968eb3..15ce08bbbd 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -97,9 +97,11 @@ extern bool get_or_create_fileset_record(JCR *jcr); extern JobId_t run_job(JCR *jcr); extern bool cancel_job(UAContext *ua, JCR *jcr); extern void init_jcr_job_record(JCR *jcr); -extern void copy_storage(JCR *new_jcr, JCR *old_jcr); +extern void copy_storage(JCR *jcr, alist *storage); extern void set_storage(JCR *jcr, STORE *store); extern bool setup_job(JCR *jcr); +extern void create_clones(JCR *jcr); +extern bool create_restore_bootstrap_file(JCR *jcr); /* mac.c */ extern bool do_mac(JCR *jcr); @@ -152,6 +154,7 @@ enum e_pool_op { }; int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op); void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr); +void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op); /* ua_input.c */ int get_cmd(UAContext *ua, const char *prompt); diff --git a/bacula/src/dird/recycle.c b/bacula/src/dird/recycle.c index 20d5b5db3d..11241990ff 100644 --- a/bacula/src/dird/recycle.c +++ b/bacula/src/dird/recycle.c @@ -78,7 +78,7 @@ int recycle_oldest_purged_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr) if (InChanger) { char changer[100]; bsnprintf(changer, sizeof(changer), "AND InChanger=1 AND StorageId=%s", - mr->StorageId); + edit_uint64(mr->StorageId, ed1)); Mmsg(query, select, edit_int64(mr->PoolId, ed1), mr->MediaType, changer); } else { Mmsg(query, select, edit_int64(mr->PoolId, ed1), mr->MediaType, ""); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index df9593c377..6ab82d7ff2 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -222,7 +222,7 @@ static int add_cmd(UAContext *ua, const char *cmd) pr.MaxVols, pr.PoolType); while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) { - bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols); + bsendmsg(ua, _("Pool already has maximum volumes=%d\n"), pr.MaxVols); for (;;) { if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) { return 1; diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c index dce647bbb8..f94121061a 100644 --- a/bacula/src/dird/ua_label.c +++ b/bacula/src/dird/ua_label.c @@ -544,6 +544,10 @@ static void label_from_barcodes(UAContext *ua, int drive) bsendmsg(ua, "%s", db_strerror(ua->db)); } } else { /* create the media record */ + if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) { + bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols); + goto bail_out; + } set_pool_dbr_defaults_in_media_dbr(&mr, &pr); bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus)); mr.MediaType[0] = 0; diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index 9a94681b0c..c3f1ac1883 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -463,12 +463,12 @@ static bool list_nextvol(UAContext *ua, int ndays) if (!complete_jcr_for_job(jcr, job, pool)) { return false; } - mr.PoolId = jcr->PoolId; + mr.PoolId = jcr->jr.PoolId; if (run->storage) { jcr->store = run->storage; } memset(&pr, 0, sizeof(pr)); - pr.PoolId = jcr->PoolId; + pr.PoolId = jcr->jr.PoolId; if (! db_get_pool_record(ua->jcr, ua->db, &pr)) { strcpy(pr.Name, "*UnknownPool*"); } @@ -626,7 +626,6 @@ int complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool) Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name); } } - jcr->PoolId = pr.PoolId; jcr->jr.PoolId = pr.PoolId; return 1; } diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index 49f6aa9f29..5a2d1189ff 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -267,7 +267,7 @@ int purgecmd(UAContext *ua, const char *cmd) static int purge_files_from_client(UAContext *ua, CLIENT *client) { struct s_file_del_ctx del; - char *query = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *query = get_pool_memory(PM_MESSAGE); int i; CLIENT_DBR cr; char ed1[50]; @@ -340,13 +340,12 @@ bail_out: * is older than the retention period, we unconditionally delete * it and all File records for that Job. This is simple enough that no * temporary tables are needed. We simply make an in memory list of - * the JobIds meeting the prune conditions, then delete the Job, - * Files, and JobMedia records in that list. + * the JobIds then delete the Job, Files, and JobMedia records in that list. */ static int purge_jobs_from_client(UAContext *ua, CLIENT *client) { struct s_job_del_ctx del; - char *query = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *query = get_pool_memory(PM_MESSAGE); int i; CLIENT_DBR cr; char ed1[50]; @@ -426,10 +425,10 @@ bail_out: void purge_files_from_job(UAContext *ua, JOB_DBR *jr) { - char *query = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *query = get_pool_memory(PM_MESSAGE); char ed1[50]; - edit_int64(jr->JobId,ed1); + edit_int64(jr->JobId, ed1); Mmsg(query, "DELETE FROM File WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); @@ -448,7 +447,7 @@ void purge_files_from_volume(UAContext *ua, MEDIA_DBR *mr ) */ int purge_jobs_from_volume(UAContext *ua, MEDIA_DBR *mr) { - char *query = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *query = get_pool_memory(PM_MESSAGE); struct s_count_ctx cnt; struct s_file_del_ctx del; int i, stat = 0; diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 57c5d9a734..5db990706f 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -249,6 +249,15 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) return 1; } +static bool has_value(UAContext *ua, int i) +{ + if (!ua->argv[i]) { + bsendmsg(ua, _("Missing value for keyword: %s\n"), ua->argk[i]); + return false; + } + return true; +} + /* * The first step in the restore process is for the user to * select a list of JobIds from which he will subsequently @@ -321,6 +330,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) /* Found keyword in kw[] list, process it */ switch (j) { case 0: /* jobid */ + if (!has_value(ua, i)) { + return 0; + } if (*rx->JobIds != 0) { pm_strcat(rx->JobIds, ","); } @@ -332,6 +344,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) have_date = true; break; case 2: /* before */ + if (!has_value(ua, i)) { + return 0; + } if (str_to_utime(ua->argv[i]) == 0) { bsendmsg(ua, _("Improper date format: %s\n"), ua->argv[i]); return 0; @@ -341,6 +356,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) break; case 3: /* file */ case 4: /* dir */ + if (!has_value(ua, i)) { + return 0; + } if (!have_date) { bstrutime(date, sizeof(date), time(NULL)); } @@ -365,6 +383,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) done = true; break; case 6: /* pool specified */ + if (!has_value(ua, i)) { + return 0; + } rx->pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]); if (!rx->pool) { bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]); diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 95e3abb740..84138f31b0 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -379,7 +379,7 @@ static void prt_runtime(UAContext *ua, sched_pkt *sp) close_db = true; /* new db opened, remember to close it */ } if (ok) { - mr.PoolId = jcr->PoolId; + mr.PoolId = jcr->jr.PoolId; ok = find_next_volume_for_append(jcr, &mr, 1, false/*no create*/); } if (!ok) { diff --git a/bacula/src/dird/ua_update.c b/bacula/src/dird/ua_update.c index 22e3e3a098..c02ab2bca4 100644 --- a/bacula/src/dird/ua_update.c +++ b/bacula/src/dird/ua_update.c @@ -29,7 +29,6 @@ extern char *list_pool; /* in sql_cmds.c */ /* Imported functions */ -void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op); void update_slots(UAContext *ua); @@ -515,7 +514,7 @@ static int update_volume(UAContext *ua) } Slot = ua->pint32_val; if (pr.MaxVols > 0 && Slot > (int)pr.MaxVols) { - bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"), + bsendmsg(ua, _("Invalid slot, it must be between 0 and MaxVols=%d\n"), pr.MaxVols); break; } diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 97be8d8095..45b0246a58 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -126,34 +126,9 @@ bool do_verify_init(JCR *jcr) * File daemon but not used). */ if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { - RESTORE_CTX rx; - UAContext *ua; - memset(&rx, 0, sizeof(rx)); - rx.bsr = new_bsr(); - rx.JobIds = ""; - rx.bsr->JobId = jcr->target_jr.JobId; - ua = new_ua_context(jcr); - complete_bsr(ua, rx.bsr); - rx.bsr->fi = new_findex(); - rx.bsr->fi->findex = 1; - rx.bsr->fi->findex2 = jcr->target_jr.JobFiles; - jcr->ExpectedFiles = write_bsr_file(ua, rx); - if (jcr->ExpectedFiles == 0) { - free_ua_context(ua); - free_bsr(rx.bsr); + if (!create_restore_bootstrap_file(jcr)) { return false; } - if (jcr->RestoreBootstrap) { - free(jcr->RestoreBootstrap); - } - POOLMEM *fname = get_pool_memory(PM_MESSAGE); - make_unique_restore_filename(ua, &fname); - jcr->RestoreBootstrap = bstrdup(fname); - free_ua_context(ua); - free_bsr(rx.bsr); - free_pool_memory(fname); - jcr->needs_sd = true; - } else { jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ } diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 515b7944d2..f01b862d24 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -89,13 +89,13 @@ static RES_ITEM cli_items[] = { {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0}, {"sdconnecttimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, {"maximumnetworkbuffersize", store_pint, ITEM(res_client.max_network_buffer_size), 0, 0, 0}, - {"pkisignatures", store_yesno, ITEM(res_client.pki_sign), 1, ITEM_DEFAULT, 0}, - {"pkiencryption", store_yesno, ITEM(res_client.pki_encrypt), 1, ITEM_DEFAULT, 0}, + {"pkisignatures", store_bit, ITEM(res_client.pki_sign), 1, ITEM_DEFAULT, 0}, + {"pkiencryption", store_bit, ITEM(res_client.pki_encrypt), 1, ITEM_DEFAULT, 0}, {"pkikeypair", store_dir, ITEM(res_client.pki_keypair_file), 0, 0, 0}, {"pkisigner", store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0}, {"pkimasterkey", store_alist_str, ITEM(res_client.pki_master_key_files), 0, 0, 0}, - {"tlsenable", store_yesno, ITEM(res_client.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_client.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(res_client.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_client.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0}, @@ -109,10 +109,10 @@ static RES_ITEM dir_items[] = { {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, - {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, - {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"monitor", store_bit, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, + {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, + {"tlsverifypeer", store_bit, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, diff --git a/bacula/src/gnome2-console/console_conf.c b/bacula/src/gnome2-console/console_conf.c index ac4ad05fce..fa9561ff65 100644 --- a/bacula/src/gnome2-console/console_conf.c +++ b/bacula/src/gnome2-console/console_conf.c @@ -69,8 +69,8 @@ static RES_ITEM dir_items[] = { {"dirport", store_int, ITEM(dir_res.DIRport), 0, ITEM_DEFAULT, 9101}, {"address", store_str, ITEM(dir_res.address), 0, ITEM_REQUIRED, 0}, {"password", store_password, ITEM(dir_res.password), 0, 0, 0}, - {"tlsenable", store_yesno, ITEM(dir_res.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(dir_res.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(dir_res.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(dir_res.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(dir_res.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(dir_res.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(dir_res.tls_certfile), 0, 0, 0}, @@ -82,8 +82,8 @@ static RES_ITEM con_items[] = { {"name", store_name, ITEM(con_res.hdr.name), 0, ITEM_REQUIRED, 0}, {"description", store_str, ITEM(con_res.hdr.desc), 0, 0, 0}, {"password", store_password, ITEM(con_res.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_yesno, ITEM(con_res.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(con_res.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(con_res.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(con_res.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(con_res.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(con_res.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(con_res.tls_certfile), 0, 0, 0}, @@ -95,7 +95,7 @@ static RES_ITEM con_font_items[] = { {"name", store_name, ITEM(con_font.hdr.name), 0, ITEM_REQUIRED, 0}, {"description", store_str, ITEM(con_font.hdr.desc), 0, 0, 0}, {"font", store_str, ITEM(con_font.fontface), 0, 0, 0}, - {"requiressl", store_yesno, ITEM(con_font.require_ssl), 1, ITEM_DEFAULT, 0}, + {"requiressl", store_bit, ITEM(con_font.require_ssl), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 5d5c761a7c..a0e51aaaf2 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -185,7 +185,6 @@ public: volatile int FDJobStatus; /* File daemon Job Status */ uint32_t ExpectedFiles; /* Expected restore files */ uint32_t MediaId; /* DB record IDs associated with this job */ - uint32_t PoolId; /* Pool record id */ FileId_t FileId; /* Last file id inserted */ uint32_t FileIndex; /* Last FileIndex processed */ POOLMEM *fname; /* name to put into catalog */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index aaa75baf1f..1e8b2be9ed 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -191,8 +191,10 @@ void init_resource(int type, RES_ITEM *items, int pass) (items[i].flags & ITEM_DEFAULT) ? "yes" : "no", items[i].default_value); if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) { - if (items[i].handler == store_yesno) { + if (items[i].handler == store_bit) { *(int *)(items[i].value) |= items[i].code; + } else if (items[i].handler == store_bool) { + *(bool *)(items[i].value) = items[i].default_value; } else if (items[i].handler == store_pint || items[i].handler == store_int) { *(int *)(items[i].value) = items[i].default_value; @@ -688,20 +690,36 @@ void store_time(LEX *lc, RES_ITEM *item, int index, int pass) /* Store a yes/no in a bit field */ -void store_yesno(LEX *lc, RES_ITEM *item, int index, int pass) +void store_bit(LEX *lc, RES_ITEM *item, int index, int pass) { lex_get_token(lc, T_NAME); - if (strcasecmp(lc->str, "yes") == 0) { + if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) { *(int *)(item->value) |= item->code; - } else if (strcasecmp(lc->str, "no") == 0) { + } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) { *(int *)(item->value) &= ~(item->code); } else { - scan_err3(lc, _("Expect a %s or %s, got: %s"), "YES", "NO", lc->str); /* YES and NO must not be translated */ + scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */ } scan_to_eol(lc); set_bit(index, res_all.hdr.item_present); } +/* Store a bool in a bit field */ +void store_bool(LEX *lc, RES_ITEM *item, int index, int pass) +{ + lex_get_token(lc, T_NAME); + if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) { + *(bool *)(item->value) = true; + } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) { + *(bool *)(item->value) = false; + } else { + scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */ + } + scan_to_eol(lc); + set_bit(index, res_all.hdr.item_present); +} + + /* * Store Tape Label Type (Bacula, ANSI, IBM) * diff --git a/bacula/src/lib/parse_conf.h b/bacula/src/lib/parse_conf.h index af81738e57..754a009cc7 100644 --- a/bacula/src/lib/parse_conf.h +++ b/bacula/src/lib/parse_conf.h @@ -21,7 +21,7 @@ */ -struct RES_ITEM; /* Declare forward referenced structure */ +struct RES_ITEM; /* Declare forward referenced structure */ typedef void (MSG_RES_HANDLER)(LEX *lc, RES_ITEM *item, int index, int pass); /* This is the structure that defines @@ -30,29 +30,29 @@ typedef void (MSG_RES_HANDLER)(LEX *lc, RES_ITEM *item, int index, int pass); * tables. */ struct RES_ITEM { - const char *name; /* Resource name i.e. Director, ... */ - MSG_RES_HANDLER *handler; /* Routine storing the resource item */ - void **value; /* Where to store the item */ - int code; /* item code/additional info */ - int flags; /* flags: default, required, ... */ - int default_value; /* default value */ + const char *name; /* Resource name i.e. Director, ... */ + MSG_RES_HANDLER *handler; /* Routine storing the resource item */ + void **value; /* Where to store the item */ + int code; /* item code/additional info */ + int flags; /* flags: default, required, ... */ + int default_value; /* default value */ }; /* For storing name_addr items in res_items table */ #define ITEM(x) ((void **)&res_all.x) -#define MAX_RES_ITEMS 70 /* maximum resource items per RES */ +#define MAX_RES_ITEMS 70 /* maximum resource items per RES */ /* This is the universal header that is * at the beginning of every resource * record. */ struct RES { - RES *next; /* pointer to next resource of this type */ - char *name; /* resource name */ - char *desc; /* resource description */ - int rcode; /* resource id or type */ - int refcnt; /* reference count for releasing */ + RES *next; /* pointer to next resource of this type */ + char *name; /* resource name */ + char *desc; /* resource description */ + int rcode; /* resource id or type */ + int refcnt; /* reference count for releasing */ char item_present[MAX_RES_ITEMS]; /* set if item is present in conf file */ }; @@ -63,25 +63,25 @@ struct RES { * resources that are available to this daemon. */ struct RES_TABLE { - const char *name; /* resource name */ - RES_ITEM *items; /* list of resource keywords */ - int rcode; /* code if needed */ + const char *name; /* resource name */ + RES_ITEM *items; /* list of resource keywords */ + int rcode; /* code if needed */ }; /* Common Resource definitions */ -#define MAX_RES_NAME_LENGTH MAX_NAME_LENGTH-1 /* maximum resource name length */ +#define MAX_RES_NAME_LENGTH MAX_NAME_LENGTH-1 /* maximum resource name length */ -#define ITEM_REQUIRED 0x1 /* item required */ -#define ITEM_DEFAULT 0x2 /* default supplied */ +#define ITEM_REQUIRED 0x1 /* item required */ +#define ITEM_DEFAULT 0x2 /* default supplied */ #define ITEM_NO_EQUALS 0x4 /* Don't scan = after name */ /* Message Resource */ struct MSGS { - RES hdr; - char *mail_cmd; /* mail command */ - char *operator_cmd; /* Operator command */ - DEST *dest_chain; /* chain of destinations */ + RES hdr; + char *mail_cmd; /* mail command */ + char *operator_cmd; /* Operator command */ + DEST *dest_chain; /* chain of destinations */ char send_msg[nbytes_for_bits(M_MAX+1)]; /* bit array of types */ }; @@ -97,7 +97,7 @@ union CURES { /* Configuration routines */ int parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error = NULL); -void free_config_resources(void); +void free_config_resources(void); RES **save_config_resources(void); RES **new_res_head(); @@ -119,7 +119,7 @@ const char *res_to_str(int rcode); #ifdef the_old_way #define foreach_res(var, type) \ - for((var)=NULL; (((void *)(var))=GetNextRes((type), (RES *)var));) + for((var)=NULL; (((void *)(var))=GetNextRes((type), (RES *)var));) #endif @@ -135,7 +135,8 @@ void store_int(LEX *lc, RES_ITEM *item, int index, int pass); void store_pint(LEX *lc, RES_ITEM *item, int index, int pass); void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass); void store_int64(LEX *lc, RES_ITEM *item, int index, int pass); -void store_yesno(LEX *lc, RES_ITEM *item, int index, int pass); +void store_bit(LEX *lc, RES_ITEM *item, int index, int pass); +void store_bool(LEX *lc, RES_ITEM *item, int index, int pass); void store_time(LEX *lc, RES_ITEM *item, int index, int pass); void store_size(LEX *lc, RES_ITEM *item, int index, int pass); void store_defs(LEX *lc, RES_ITEM *item, int index, int pass); diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 7977f5468b..0d779b9855 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -23,101 +23,6 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ -/* - * Create a new Device Control Record and attach - * it to the device (if this is a real job). - */ -DCR *new_dcr(JCR *jcr, DEVICE *dev) -{ - DCR *dcr = (DCR *)malloc(sizeof(DCR)); - memset(dcr, 0, sizeof(DCR)); - dcr->jcr = jcr; - if (dev) { - dcr->dev = dev; - dcr->device = dev->device; - dcr->block = new_block(dev); - dcr->rec = new_record(); - dcr->max_job_spool_size = dev->device->max_job_spool_size; - /* Attach this dcr only if dev is initialized */ - if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { - dev->attached_dcrs->append(dcr); /* attach dcr to device */ -// jcr->dcrs->append(dcr); /* put dcr in list for Job */ - } - } - dcr->spool_fd = -1; - return dcr; -} - -/* - * Search the dcrs list for the given dcr. If it is found, - * as it should be, then remove it. Also zap the jcr pointer - * to the dcr if it is the same one. - */ -#ifdef needed -static void remove_dcr_from_dcrs(DCR *dcr) -{ - JCR *jcr = dcr->jcr; - if (jcr->dcrs) { - int i = 0; - DCR *ldcr; - int num = jcr->dcrs->size(); - for (i=0; i < num; i++) { - ldcr = (DCR *)jcr->dcrs->get(i); - if (ldcr == dcr) { - jcr->dcrs->remove(i); - if (jcr->dcr == dcr) { - jcr->dcr = NULL; - } - } - } - } -} -#endif - -/* - * Free up all aspects of the given dcr -- i.e. dechain it, - * release allocated memory, zap pointers, ... - */ -void free_dcr(DCR *dcr) -{ - JCR *jcr = dcr->jcr; - DEVICE *dev = dcr->dev; - - if (dcr->reserved_device) { - lock_device(dev); - dev->reserved_device--; - /* If we set read mode in reserving, remove it */ - if (dev->can_read()) { - dev->clear_read(); - } - Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device); - dcr->reserved_device = false; - if (dev->num_writers < 0) { - Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers); - dev->num_writers = 0; - } - unlock_device(dev); - } - - /* Detach this dcr only if the dev is initialized */ - if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { - dev->attached_dcrs->remove(dcr); /* detach dcr from device */ -// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ - } - if (dcr->block) { - free_block(dcr->block); - } - if (dcr->rec) { - free_record(dcr->rec); - } - if (dcr->jcr) { - dcr->jcr->dcr = NULL; - } - free_unused_volume(dcr); /* free unused vols attached to this dcr */ - free(dcr); - pthread_cond_broadcast(&dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); -} /********************************************************************* * Acquire device for reading. @@ -162,6 +67,16 @@ DCR *acquire_device_for_read(DCR *dcr) goto get_out; /* should not happen */ } bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); + dcr->VolCatInfo.Slot = vol->Slot; + Dmsg4(100, "===== Vol=%s MT=%s Slt=%d Dev-MT=%s\n", dcr->VolumeName, + dcr->media_type, vol->Slot, dev->device->media_type); + + if (strcmp(dcr->media_type, dev->device->media_type) != 0) { + Dmsg2(000, "Wrong MT have=%s want=%s\n", dev->device->media_type, + dcr->media_type); + Dmsg1(000, "New storage=%s\n", vol->storage); + } init_device_wait_timers(dcr); @@ -274,6 +189,13 @@ default_path: dcr->VolumeName, dev->print_name()); get_out: + P(dev->mutex); + if (dcr->reserved_device) { + dev->reserved_device--; + Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); + dcr->reserved_device = false; + } + V(dev->mutex); dev->unblock(); if (!vol_ok) { dcr = NULL; @@ -396,7 +318,7 @@ DCR *acquire_device_for_append(DCR *dcr) P(dev->mutex); if (dcr->reserved_device) { dev->reserved_device--; - Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device); + Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); dcr->reserved_device = false; } V(dev->mutex); @@ -410,7 +332,7 @@ get_out: P(dev->mutex); if (dcr->reserved_device) { dev->reserved_device--; - Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device); + Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); dcr->reserved_device = false; } V(dev->mutex); @@ -418,6 +340,7 @@ get_out: return NULL; } + /* * This job is done, so release the device. From a Unix standpoint, * the device remains open. @@ -430,12 +353,12 @@ bool release_device(DCR *dcr) bool ok = true; lock_device(dev); - Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk"); + Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk"); /* if device is reserved, job never started, so release the reserve here */ if (dcr->reserved_device) { dev->reserved_device--; - Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device); + Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); dcr->reserved_device = false; } @@ -522,3 +445,99 @@ bool release_device(DCR *dcr) free_dcr(dcr); return ok; } + +/* + * Create a new Device Control Record and attach + * it to the device (if this is a real job). + */ +DCR *new_dcr(JCR *jcr, DEVICE *dev) +{ + DCR *dcr = (DCR *)malloc(sizeof(DCR)); + memset(dcr, 0, sizeof(DCR)); + dcr->jcr = jcr; + if (dev) { + dcr->dev = dev; + dcr->device = dev->device; + dcr->block = new_block(dev); + dcr->rec = new_record(); + dcr->max_job_spool_size = dev->device->max_job_spool_size; + /* Attach this dcr only if dev is initialized */ + if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { + dev->attached_dcrs->append(dcr); /* attach dcr to device */ +// jcr->dcrs->append(dcr); /* put dcr in list for Job */ + } + } + dcr->spool_fd = -1; + return dcr; +} + +/* + * Search the dcrs list for the given dcr. If it is found, + * as it should be, then remove it. Also zap the jcr pointer + * to the dcr if it is the same one. + */ +#ifdef needed +static void remove_dcr_from_dcrs(DCR *dcr) +{ + JCR *jcr = dcr->jcr; + if (jcr->dcrs) { + int i = 0; + DCR *ldcr; + int num = jcr->dcrs->size(); + for (i=0; i < num; i++) { + ldcr = (DCR *)jcr->dcrs->get(i); + if (ldcr == dcr) { + jcr->dcrs->remove(i); + if (jcr->dcr == dcr) { + jcr->dcr = NULL; + } + } + } + } +} +#endif + +/* + * Free up all aspects of the given dcr -- i.e. dechain it, + * release allocated memory, zap pointers, ... + */ +void free_dcr(DCR *dcr) +{ + JCR *jcr = dcr->jcr; + DEVICE *dev = dcr->dev; + + if (dcr->reserved_device) { + lock_device(dev); + dev->reserved_device--; + Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); + dcr->reserved_device = false; + /* If we set read mode in reserving, remove it */ + if (dev->can_read()) { + dev->clear_read(); + } + if (dev->num_writers < 0) { + Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers); + dev->num_writers = 0; + } + unlock_device(dev); + } + + /* Detach this dcr only if the dev is initialized */ + if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { + dev->attached_dcrs->remove(dcr); /* detach dcr from device */ +// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ + } + if (dcr->block) { + free_block(dcr->block); + } + if (dcr->rec) { + free_record(dcr->rec); + } + if (dcr->jcr) { + dcr->jcr->dcr = NULL; + } + free_unused_volume(dcr); /* free unused vols attached to this dcr */ + free(dcr); + pthread_cond_broadcast(&dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); +} diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 93984bcc98..16557abd98 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -213,6 +213,8 @@ bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) return ok; } + + /* * Get info on the next appendable volume in the Director's database * Returns: true on success @@ -226,6 +228,10 @@ bool dir_find_next_appendable_volume(DCR *dcr) JCR *jcr = dcr->jcr; BSOCK *dir = jcr->dir_bsock; bool found = false; + /* This mutex should keep different devices from getting the + * same Volume. + */ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; Dmsg0(200, "dir_find_next_appendable_volume\n"); /* @@ -233,6 +239,7 @@ bool dir_find_next_appendable_volume(DCR *dcr) * the most available could already be mounted on another * drive, so we continue looking for a not in use Volume. */ + P(mutex); for (int vol_index=1; vol_index < 20; vol_index++) { bash_spaces(dcr->media_type); bash_spaces(dcr->pool_name); @@ -251,15 +258,18 @@ bool dir_find_next_appendable_volume(DCR *dcr) } } else { Dmsg0(200, "No volume info, return false\n"); - return false; + found = false; + break; } } if (found) { Dmsg0(400, "dir_find_next_appendable_volume return true\n"); new_volume(dcr, dcr->VolumeName); /* reserve volume */ + V(mutex); return true; } dcr->VolumeName[0] = 0; + V(mutex); return false; } diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index 821c856c2c..e135852474 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -105,6 +105,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) POOLMEM *changer; if (!dev->is_autochanger()) { + Dmsg0(200, "======== NOT AUTOCHANGER ======\n"); return 0; } slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0; @@ -112,7 +113,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) * Handle autoloaders here. If we cannot autoload it, we * will return 0 so that the sysop will be asked to load it. */ - if (writing && dev->is_autochanger() && slot <= 0) { + if (writing && slot <= 0) { if (dir) { return 0; /* For user, bail out right now */ } @@ -155,6 +156,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load"); dev->close(); + Dmsg1(200, "Run program=%s\n", changer); status = run_program(changer, timeout, NULL); if (status == 0) { Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"), @@ -218,8 +220,9 @@ int get_autochanger_loaded_slot(DCR *dcr) drive); changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded"); *results = 0; + Dmsg1(200, "Run program=%s\n", changer); status = run_program(changer, timeout, results); - Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results); + Dmsg3(200, "run_prog: %s stat=%d result=%s\n", changer, status, results); if (status == 0) { loaded = str_to_int32(results); if (loaded > 0) { @@ -300,6 +303,7 @@ bool unload_autochanger(DCR *dcr, int loaded) changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "unload"); dev->close(); + Dmsg1(200, "Run program=%s\n", changer); int stat = run_program(changer, timeout, NULL); dcr->VolCatInfo.Slot = slot; if (stat != 0) { @@ -331,6 +335,7 @@ static bool unload_other_drive(DCR *dcr, int slot) AUTOCHANGER *changer = dcr->dev->device->changer_res; DEVRES *device; bool found = false; + bool first = true; if (!changer) { return false; @@ -349,12 +354,24 @@ static bool unload_other_drive(DCR *dcr, int slot) if (!found) { return true; } + + /* The Volume we want is on another device. */ + + for (int i=0; i < 3; i++) { + if (dev->is_busy()) { + wait_for_device(dcr->jcr, first); + first = false; + continue; + } + break; + } + P(dev->mutex); if (dev->is_busy()) { - Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"), + Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"), dcr->VolumeName, dev->print_name()); - Dmsg2(200, "Volume %s is in use by device %s\n", + Dmsg2(200, "Volume \"%s\" is in use by device %s\n", dcr->VolumeName, dev->print_name()); - + V(dev->mutex); return false; } @@ -367,14 +384,16 @@ static bool unload_other_drive(DCR *dcr, int slot) Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n", slot, dev->drive_index); - save_slot = dcr->VolCatInfo.Slot; save_dev = dcr->dev; dcr->dev = dev; + save_slot = dcr->VolCatInfo.Slot; dcr->VolCatInfo.Slot = slot; changer_cmd = edit_device_codes(dcr, changer_cmd, dcr->device->changer_command, "unload"); - Dmsg1(200, "Run program=%s\n", changer_cmd); dev->close(); + Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), + dev->reserved_device); + Dmsg1(200, "Run program=%s\n", changer_cmd); int stat = run_program(changer_cmd, timeout, NULL); dcr->VolCatInfo.Slot = save_slot; dcr->dev = save_dev; @@ -392,6 +411,7 @@ static bool unload_other_drive(DCR *dcr, int slot) Dmsg0(200, "Slot unloaded\n"); } unlock_changer(dcr); + V(dev->mutex); free_pool_memory(changer_cmd); return ok; } diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h index 9d18ea0b90..9f43a84707 100644 --- a/bacula/src/stored/bsr.h +++ b/bacula/src/stored/bsr.h @@ -7,22 +7,17 @@ * */ /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2002-2006 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as amended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -38,6 +33,7 @@ struct VOL_LIST { VOL_LIST *next; char VolumeName[MAX_NAME_LENGTH]; char MediaType[MAX_NAME_LENGTH]; + char storage[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ int Slot; uint32_t start_file; }; @@ -56,6 +52,8 @@ struct BSR_VOLUME { BSR_VOLUME *next; char VolumeName[MAX_NAME_LENGTH]; char MediaType[MAX_NAME_LENGTH]; + char storage[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ + int32_t Slot; /* Slot */ }; struct BSR_CLIENT { @@ -133,7 +131,6 @@ struct BSR { bool use_fast_rejection; /* set if fast rejection can be used */ bool use_positioning; /* set if we can position the archive */ BSR_VOLUME *volume; - int32_t Slot; /* Slot */ uint32_t count; /* count of files to restore this bsr */ uint32_t found; /* count of restored files this bsr */ BSR_VOLFILE *volfile; diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 6fadf6c981..820bd43dd1 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -321,7 +321,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) int nonblocking = O_NONBLOCK; Dmsg0(29, "open dev: device is tape\n"); - if (is_tape() && is_autochanger()) { + if (is_autochanger()) { get_autochanger_loaded_slot(dcr); } @@ -407,22 +407,33 @@ void DEVICE::open_file_device(DCR *dcr, int omode) { POOL_MEM archive_name(PM_FNAME); + if (is_autochanger()) { + get_autochanger_loaded_slot(dcr); + } + /* * Handle opening of File Archive (not a tape) */ - if (VolCatInfo.VolCatName[0] == 0) { - Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"), - print_name()); - clear_opened(); - return; - } - pm_strcpy(archive_name, dev_name); - if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') { - pm_strcat(archive_name, "/"); + /* + * If this is a virtual autochanger (i.e. changer_res != NULL) + * we simply use the deviced name, assuming it has been + * appropriately setup by the "autochanger". + */ + if (!device->changer_res) { + if (VolCatInfo.VolCatName[0] == 0) { + Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"), + print_name()); + clear_opened(); + return; + } + + if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') { + pm_strcat(archive_name, "/"); + } + pm_strcat(archive_name, VolCatInfo.VolCatName); } - pm_strcat(archive_name, VolCatInfo.VolCatName); mount(1); /* do mount if required */ @@ -1801,7 +1812,7 @@ bool DEVICE::do_mount(int mount, int dotimeout) edit_mount_codes(ocmd, icmd); - Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted()); + Dmsg2(000, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted()); if (dotimeout) { /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */ diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index e6d4b289ed..5c6817972a 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -192,7 +192,7 @@ void *handle_connection_request(void *arg) if ((bnet_stat = bnet_recv(bs)) <= 0) { break; /* connection terminated */ } - Dmsg1(199, "msg); + Dmsg1(199, "msg); /* Ensure that device initialization is complete */ while (!init_done) { bmicrosleep(1, 0); @@ -873,7 +873,7 @@ static bool changer_cmd(JCR *jcr) if (dcr) { dev = dcr->dev; P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev->is_tape()) { + if (!dev->device->changer_res) { bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), dev->print_name()); /* Under certain "safe" conditions, we can steal the lock */ diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index c00c7d37ea..4809fc7286 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -347,5 +347,14 @@ void stored_free_jcr(JCR *jcr) free_dcr(jcr->read_dcr); jcr->read_dcr = NULL; } + if (jcr->dirstore) { + DIRSTORE *store; + foreach_alist(store, jcr->dirstore) { + delete store->device; + delete store; + } + delete jcr->dirstore; + jcr->dirstore = NULL; + } return; } diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index d88181a9c2..9387bc3612 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -57,7 +57,8 @@ bool mount_next_write_volume(DCR *dcr, bool release) DEV_BLOCK *block = dcr->block; int mode; - Dmsg1(150, "Enter mount_next_volume(release=%d)\n", release); + Dmsg2(150, "Enter mount_next_volume(release=%d) dev=%s\n", release, + dev->print_name()); init_device_wait_timers(dcr); @@ -164,9 +165,9 @@ mount_next_vol: mode = OPEN_READ_WRITE; } while (dev->open(dcr, mode) < 0) { - Dmsg0(000, "open_device failed\n"); + Dmsg0(150, "open_device failed\n"); if (dev->is_file() && dev->is_removable()) { - Dmsg0(000, "call scan_dir_for_vol\n"); + Dmsg0(150, "call scan_dir_for_vol\n"); if (dev->scan_dir_for_volume(dcr)) { break; /* got a valid volume */ } @@ -394,7 +395,9 @@ read_volume: empty_block(block); /* we used it for reading so set for write */ } dev->set_append(); - Dmsg0(150, "set APPEND, normal return from read_dev_for_append\n"); + Dmsg1(150, "set APPEND, normal return from mount_next_write_volume. dev=%s\n", + dev->print_name()); + return true; } diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index f5076ee584..c6eec08a18 100755 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -7,7 +7,7 @@ */ /* - Copyright (C) 2002-2005 Kern Sibbald + Copyright (C) 2002-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -29,6 +29,7 @@ typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr); static BSR *store_vol(LEX *lc, BSR *bsr); static BSR *store_mediatype(LEX *lc, BSR *bsr); +static BSR *store_storage(LEX *lc, BSR *bsr); static BSR *store_client(LEX *lc, BSR *bsr); static BSR *store_job(LEX *lc, BSR *bsr); static BSR *store_jobid(LEX *lc, BSR *bsr); @@ -73,6 +74,7 @@ struct kw_items items[] = { {"volblock", store_volblock}, {"stream", store_stream}, {"slot", store_slot}, + {"storage", store_storage}, {NULL, NULL} }; @@ -268,6 +270,28 @@ static BSR *store_mediatype(LEX *lc, BSR *bsr) return bsr; } +/* Shove the Storage name in each Volume in the current bsr */ +static BSR *store_storage(LEX *lc, BSR *bsr) +{ + int token; + + token = lex_get_token(lc, T_STRING); + if (token == T_ERROR) { + return NULL; + } + if (!bsr->volume) { + Emsg1(M_ERROR,0, _("Storage %s in bsr at inappropriate place.\n"), + lc->str); + return bsr; + } + BSR_VOLUME *bv; + for (bv=bsr->volume; bv; bv=bv->next) { + bstrncpy(bv->storage, lc->str, sizeof(bv->storage)); + } + return bsr; +} + + static BSR *store_client(LEX *lc, BSR *bsr) { @@ -603,7 +627,12 @@ static BSR *store_slot(LEX *lc, BSR *bsr) if (token == T_ERROR) { return NULL; } - bsr->Slot = lc->pint32_val; + if (!bsr->volume) { + Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"), + lc->pint32_val); + return bsr; + } + bsr->volume->Slot = lc->pint32_val; scan_to_eol(lc); return bsr; } @@ -677,6 +706,9 @@ void dump_volume(BSR_VOLUME *volume) { if (volume) { Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName); + Pmsg1(-1, _(" MediaType : %s\n"), volume->MediaType); + Pmsg1(-1, _(" Storage : %s\n"), volume->storage); + Pmsg1(-1, _(" Slot : %d\n"), volume->Slot); dump_volume(volume->next); } } @@ -730,9 +762,6 @@ void dump_bsr(BSR *bsr, bool recurse) dump_jobid(bsr->JobId); dump_job(bsr->job); dump_findex(bsr->FileIndex); - if (bsr->Slot) { - Pmsg1(-1, _("Slot : %u\n"), bsr->Slot); - } if (bsr->count) { Pmsg1(-1, _("count : %u\n"), bsr->count); Pmsg1(-1, _("found : %u\n"), bsr->found); @@ -875,6 +904,8 @@ void create_restore_volume_list(JCR *jcr) vol = new_restore_volume(); bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName)); bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType)); + bstrncpy(vol->storage, bsrvol->storage, sizeof(vol->storage)); + vol->Slot = bsrvol->Slot; vol->start_file = sfile; if (add_restore_volume(jcr, vol)) { jcr->NumVolumes++; diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 384cfb7ef7..9c8d3b4791 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -215,11 +215,12 @@ VOLRES *new_volume(DCR *dcr, const char *VolumeName); VOLRES *find_volume(const char *VolumeName); bool free_volume(DEVICE *dev); void free_unused_volume(DCR *dcr); -void create_volume_list(); +void init_volume_list(); void free_volume_list(); void list_volumes(BSOCK *user); bool is_volume_in_use(DCR *dcr); void send_drive_reserve_messages(JCR *jcr, BSOCK *user); +bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx); /* From spool.c */ diff --git a/bacula/src/stored/reserve.c b/bacula/src/stored/reserve.c index 25a030c9eb..362eccac70 100644 --- a/bacula/src/stored/reserve.c +++ b/bacula/src/stored/reserve.c @@ -26,43 +26,6 @@ #include "bacula.h" #include "stored.h" -/* - * Use Device command from Director - * He tells is what Device Name to use, the Media Type, - * the Pool Name, and the Pool Type. - * - * Ensure that the device exists and is opened, then store - * the media and pool info in the JCR. This class is used - * only temporarily in this file. - */ -class DIRSTORE { -public: - alist *device; - bool append; - char name[MAX_NAME_LENGTH]; - char media_type[MAX_NAME_LENGTH]; - char pool_name[MAX_NAME_LENGTH]; - char pool_type[MAX_NAME_LENGTH]; -}; - -/* Reserve context */ -class RCTX { -public: - JCR *jcr; - char *device_name; - DIRSTORE *store; - DEVRES *device; - DEVICE *low_use_drive; /* Low use drive candidate */ - int num_writers; /* for selecting low use drive */ - bool try_low_use_drive; /* see if low use drive available */ - bool any_drive; /* Accept any drive if set */ - bool PreferMountedVols; /* Prefer volumes already mounted */ - bool exact_match; /* Want exact volume */ - bool have_volume; /* Have DIR suggested vol name */ - bool suitable_device; /* at least one device is suitable */ - bool autochanger_only; /* look at autochangers only */ - char VolumeName[MAX_NAME_LENGTH]; /* Vol name suggested by DIR */ -}; static dlist *vol_list = NULL; static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER; @@ -75,8 +38,8 @@ static int reserve_device(RCTX &rctx); static bool reserve_device_for_read(DCR *dcr); static bool reserve_device_for_append(DCR *dcr, RCTX &rctx); static bool use_storage_cmd(JCR *jcr); -bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx); static void queue_reserve_message(JCR *jcr); +static void release_msgs(JCR *jcr); /* Requests from the Director daemon */ static char use_storage[] = "use storage=%127s media_type=%127s " @@ -246,7 +209,7 @@ void list_volumes(BSOCK *user) } /* Create the Volume list */ -void create_volume_list() +void init_volume_list() { VOLRES *dummy = NULL; if (vol_list == NULL) { @@ -483,11 +446,15 @@ static bool use_storage_cmd(JCR *jcr) } all_done: - foreach_alist(store, jcr->dirstore) { - delete store->device; - delete store; - } - delete jcr->dirstore; + release_msgs(jcr); + return ok; +} + +static void release_msgs(JCR *jcr) +{ + alist *msgs = jcr->reserve_msgs; + char *msg; + P(search_lock); while ((msg = (char *)msgs->pop())) { free(msg); @@ -495,10 +462,8 @@ all_done: delete msgs; jcr->reserve_msgs = NULL; V(search_lock); - return ok; } - /* * Search for a device suitable for this job. */ @@ -527,7 +492,7 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) ok = true; break; } else if (stat == 0) { /* device busy */ - Dmsg1(100, "Suitable busy device found=%s\n", device_name); + Dmsg1(100, "Suitable device found=%s, not used: busy\n", device_name); } else { /* otherwise error */ Dmsg0(100, "No suitable device found.\n"); @@ -567,10 +532,10 @@ static int search_res_for_device(RCTX &rctx) } POOL_MEM dev_name; if (rctx.store->append == SD_APPEND) { - Dmsg2(100, "Device %s reserved=%d.\n", rctx.device_name, + Dmsg2(100, "Device %s reserved=%d for append.\n", rctx.device->hdr.name, rctx.jcr->dcr->dev->reserved_device); } else { - Dmsg2(100, "Device %s reserved=%d.\n", rctx.device_name, + Dmsg2(100, "Device %s reserved=%d for read.\n", rctx.device->hdr.name, rctx.jcr->read_dcr->dev->reserved_device); } pm_strcpy(dev_name, rctx.device->hdr.name); @@ -617,6 +582,8 @@ static int reserve_device(RCTX &rctx) const int name_len = MAX_NAME_LENGTH; /* Make sure MediaType is OK */ + Dmsg2(100, "MediaType device=%s request=%s\n", + rctx.device->media_type, rctx.store->media_type); if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) { return -1; } @@ -724,6 +691,10 @@ static bool reserve_device_for_read(DCR *dcr) dev->clear_append(); dev->set_read(); ok = true; + dev->reserved_device++; + Dmsg3(100, "Inc reserve=%d dev=%s %p\n", dev->reserved_device, + dev->print_name(), dev); + dcr->reserved_device = true; bail_out: V(dev->mutex); diff --git a/bacula/src/stored/reserve.h b/bacula/src/stored/reserve.h new file mode 100644 index 0000000000..78e35c897b --- /dev/null +++ b/bacula/src/stored/reserve.h @@ -0,0 +1,60 @@ +/* + * Definitions for reservation system. + * + * Kern Sibbald, February MMVI + * + * Version $Id$ + */ + +/* + Copyright (C) 2006 Kern Sibbald + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as amended with additional clauses defined in the + file LICENSE in the main source directory. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. + + */ + +/* + * Use Device command from Director + * The DIR tells us what Device Name to use, the Media Type, + * the Pool Name, and the Pool Type. + * + * Ensure that the device exists and is opened, then store + * the media and pool info in the JCR. This class is used + * only temporarily in this file. + */ +class DIRSTORE { +public: + alist *device; + bool append; + char name[MAX_NAME_LENGTH]; + char media_type[MAX_NAME_LENGTH]; + char pool_name[MAX_NAME_LENGTH]; + char pool_type[MAX_NAME_LENGTH]; +}; + +/* Reserve context */ +class RCTX { +public: + JCR *jcr; + char *device_name; + DIRSTORE *store; + DEVRES *device; + DEVICE *low_use_drive; /* Low use drive candidate */ + int num_writers; /* for selecting low use drive */ + bool try_low_use_drive; /* see if low use drive available */ + bool any_drive; /* Accept any drive if set */ + bool PreferMountedVols; /* Prefer volumes already mounted */ + bool exact_match; /* Want exact volume */ + bool have_volume; /* Have DIR suggested vol name */ + bool suitable_device; /* at least one device is suitable */ + bool autochanger_only; /* look at autochangers only */ + char VolumeName[MAX_NAME_LENGTH]; /* Vol name suggested by DIR */ +}; diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 596bbafc14..eff170455e 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -155,7 +155,7 @@ bool status_cmd(JCR *jcr) } else { if (dev) { - bnet_fsend(user, _("Device %s is not open or does not exist.\n"), dev->print_name()); + bnet_fsend(user, _("Device %s is not open.\n"), dev->print_name()); } else { bnet_fsend(user, _("Device \"%s\" is not open or does not exist.\n"), device->hdr.name); } diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index cc561a12df..095a9ab2f4 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -10,7 +10,7 @@ * */ /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2000-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -228,7 +228,7 @@ int main (int argc, char *argv[]) /* * Start the device allocation thread */ - create_volume_list(); /* do before device_init */ + init_volume_list(); /* do before device_init */ if (pthread_create(&thid, NULL, device_initialization, NULL) != 0) { Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), strerror(errno)); } diff --git a/bacula/src/stored/stored.h b/bacula/src/stored/stored.h index c75a523adc..f55aa44404 100644 --- a/bacula/src/stored/stored.h +++ b/bacula/src/stored/stored.h @@ -40,6 +40,7 @@ #include "stored_conf.h" #include "bsr.h" #include "jcr.h" +#include "reserve.h" #include "protos.h" #ifdef HAVE_LIBZ #include /* compression headers */ diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index f6f2e8ed3d..99e5652fe0 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -61,9 +61,9 @@ static RES_ITEM store_items[] = { {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0}, {"maximumconcurrentjobs", store_pint, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 10}, {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0}, - {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_yesno, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"tlsenable", store_bit, ITEM(res_store.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_store.tls_require), 1, 0, 0}, + {"tlsverifypeer", store_bit, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1}, {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0}, @@ -79,10 +79,10 @@ static RES_ITEM dir_items[] = { {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0}, {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, - {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, - {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"monitor", store_bit, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, + {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, + {"tlsverifypeer", store_bit, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, @@ -99,28 +99,28 @@ static RES_ITEM dev_items[] = { {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0}, {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0}, {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0}, - {"hardwareendoffile", store_yesno, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1}, - {"hardwareendofmedium", store_yesno, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1}, - {"backwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1}, - {"backwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1}, - {"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, 0}, - {"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}, - {"labelmedia", store_yesno, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0}, - {"alwaysopen", store_yesno, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1}, - {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0}, - {"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0}, - {"blockpositioning", store_yesno, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1}, - {"usemtiocget", store_yesno, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1}, - {"checklabels", store_yesno, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0}, - {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0}, - {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0}, - {"autoselect", store_yesno, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1}, + {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1}, + {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1}, + {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1}, + {"backwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1}, + {"bsfateom", store_bit, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0}, + {"twoeof", store_bit, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0}, + {"forwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1}, + {"forwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1}, + {"fastforwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1}, + {"removablemedia", store_bit, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1}, + {"randomaccess", store_bit, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0}, + {"automaticmount", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0}, + {"labelmedia", store_bit, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0}, + {"alwaysopen", store_bit, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1}, + {"autochanger", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0}, + {"closeonpoll", store_bit, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0}, + {"blockpositioning", store_bit, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1}, + {"usemtiocget", store_bit, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1}, + {"checklabels", store_bit, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0}, + {"requiresmount", store_bit, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0}, + {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0}, + {"autoselect", store_bit, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1}, {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0}, {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0}, @@ -160,7 +160,7 @@ static RES_ITEM changer_items[] = { }; -// {"mountanonymousvolumes", store_yesno, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0}, +// {"mountanonymousvolumes", store_bit, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0}, /* Message resource */ diff --git a/bacula/src/stored/wait.c b/bacula/src/stored/wait.c index 0e39ba5c60..8555561818 100644 --- a/bacula/src/stored/wait.c +++ b/bacula/src/stored/wait.c @@ -9,7 +9,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2000-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -190,7 +190,7 @@ bool wait_for_device(JCR *jcr, bool first) struct timespec timeout; int stat = 0; bool ok = true; - const int wait_time = 10 * 60; /* wait 10 minutes */ + const int wait_time = 5 * 60; /* wait 5 minutes */ Dmsg0(100, "Enter wait_for_device\n"); P(device_release_mutex); diff --git a/bacula/src/tray-monitor/tray_conf.c b/bacula/src/tray-monitor/tray_conf.c index 7614c2052a..18cfdf04f4 100644 --- a/bacula/src/tray-monitor/tray_conf.c +++ b/bacula/src/tray-monitor/tray_conf.c @@ -8,14 +8,14 @@ * 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). +* 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. +* definitions as well as any specific store routines +* for the resource records. * * Nicolas Boichat, August MMIV * @@ -69,12 +69,12 @@ int res_all_size = sizeof(res_all); /* * Monitor Resource * -* name handler value code flags default_value +* name handler value code flags default_value */ static RES_ITEM mon_items[] = { {"name", store_name, ITEM(res_monitor.hdr.name), 0, ITEM_REQUIRED, 0}, {"description", store_str, ITEM(res_monitor.hdr.desc), 0, 0, 0}, - {"requiressl", store_yesno, ITEM(res_monitor.require_ssl), 1, ITEM_DEFAULT, 0}, + {"requiressl", store_bit, ITEM(res_monitor.require_ssl), 1, ITEM_DEFAULT, 0}, {"password", store_password, ITEM(res_monitor.password), 0, ITEM_REQUIRED, 0}, {"refreshinterval", store_time,ITEM(res_monitor.RefreshInterval), 0, ITEM_DEFAULT, 5}, {"fdconnecttimeout", store_time,ITEM(res_monitor.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, @@ -88,14 +88,14 @@ static RES_ITEM dir_items[] = { {"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, 0, 0}, - {"enablessl", store_yesno, ITEM(res_dir.enable_ssl), 1, ITEM_DEFAULT, 0}, + {"enablessl", store_bit, ITEM(res_dir.enable_ssl), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; /* * Client or File daemon resource * -* name handler value code flags default_value +* name handler value code flags default_value */ static RES_ITEM cli_items[] = { @@ -104,13 +104,13 @@ static RES_ITEM cli_items[] = { {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0}, {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102}, {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0}, - {"enablessl", store_yesno, ITEM(res_client.enable_ssl), 1, ITEM_DEFAULT, 0}, + {"enablessl", store_bit, ITEM(res_client.enable_ssl), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; /* Storage daemon resource * -* name handler value code flags default_value +* name handler value code flags default_value */ static RES_ITEM store_items[] = { {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -120,7 +120,7 @@ static RES_ITEM store_items[] = { {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0}, {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0}, {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0}, - {"enablessl", store_yesno, ITEM(res_store.enable_ssl), 1, ITEM_DEFAULT, 0}, + {"enablessl", store_bit, ITEM(res_store.enable_ssl), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -131,7 +131,7 @@ static RES_ITEM store_items[] = { * NOTE!!! keep it in the same order as the R_codes * or eliminate all resources[rindex].name * -* name items rcode res_head +* name items rcode res_head */ RES_TABLE resources[] = { {"monitor", mon_items, R_MONITOR}, @@ -152,7 +152,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm sendit(sock, _("No %s resource defined\n"), res_to_str(type)); return; } - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = false; } @@ -194,7 +194,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm */ void free_resource(RES *sres, int type) { - RES *nres; /* next resource if linked */ + RES *nres; /* next resource if linked */ URES *res = (URES *)sres; if (res == NULL) @@ -258,14 +258,14 @@ void save_resource(int type, RES_ITEM *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_monitor.hdr.item_present)) { - Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"), - items[i].name, resources[rindex]); - } + if (!bit_is_set(i, res_all.res_monitor.hdr.item_present)) { + Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"), + items[i].name, resources[rindex]); + } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { - Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]); + Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]); } } @@ -282,22 +282,22 @@ void save_resource(int type, RES_ITEM *items, int pass) case R_CLIENT: case R_STORAGE: case R_DIRECTOR: - break; + break; default: - Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type); - error = 1; - break; + Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type); + error = 1; + break; } /* Note, the resource name was already saved during pass 1, * so here, we can just release it. */ if (res_all.res_monitor.hdr.name) { - free(res_all.res_monitor.hdr.name); - res_all.res_monitor.hdr.name = NULL; + free(res_all.res_monitor.hdr.name); + res_all.res_monitor.hdr.name = NULL; } if (res_all.res_monitor.hdr.desc) { - free(res_all.res_monitor.hdr.desc); - res_all.res_monitor.hdr.desc = NULL; + free(res_all.res_monitor.hdr.desc); + res_all.res_monitor.hdr.desc = NULL; } return; } @@ -330,21 +330,21 @@ void save_resource(int type, RES_ITEM *items, int pass) memcpy(res, &res_all, size); if (!res_head[rindex]) { res_head[rindex] = (RES *)res; /* store first entry */ - Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type), - res->res_monitor.hdr.name, rindex); + Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type), + res->res_monitor.hdr.name, rindex); } else { RES *next; /* Add new res to end of chain */ for (next=res_head[rindex]; next->next; next=next->next) { if (strcmp(next->name, res->res_monitor.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_monitor.hdr.name); + Emsg2(M_ERROR_TERM, 0, + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + resources[rindex].name, res->res_monitor.hdr.name); } } next->next = (RES *)res; - Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type), - res->res_monitor.hdr.name, rindex, pass); + Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type), + res->res_monitor.hdr.name, rindex, pass); } } } diff --git a/bacula/src/version.h b/bacula/src/version.h index 0bc3be13e7..1b91bd96f7 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "1.39.5" -#define BDATE "06 February 2006" -#define LSMDATE "06Feb06" +#define BDATE "14 February 2006" +#define LSMDATE "14Feb06" /* Debug flags */ #undef DEBUG diff --git a/bacula/src/wx-console/console_conf.c b/bacula/src/wx-console/console_conf.c index c13abcac29..b6c05f7151 100644 --- a/bacula/src/wx-console/console_conf.c +++ b/bacula/src/wx-console/console_conf.c @@ -81,8 +81,8 @@ static RES_ITEM cons_items[] = { {"rcfile", store_dir, ITEM(res_cons.rc_file), 0, 0, 0}, {"historyfile", store_dir, ITEM(res_cons.hist_file), 0, 0, 0}, {"password", store_password, ITEM(res_cons.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_yesno, ITEM(res_cons.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_cons.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(res_cons.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_cons.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_cons.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_cons.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_cons.tls_certfile), 0, 0, 0}, @@ -98,8 +98,8 @@ static RES_ITEM dir_items[] = { {"dirport", store_int, ITEM(res_dir.DIRport), 0, ITEM_DEFAULT, 9101}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0}, + {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, + {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, -- 2.39.5