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 \
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
"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" ;;
Kern's ToDo List
- 11 January 2006
+ 08 February 2006
Major development:
Project Developer
- %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
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).
+
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.
+disk-changer
bacula-tray-monitor.desktop
bacula-tray-monior.desktop
.xvpics
$(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; \
(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)
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
--- /dev/null
+#!/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
#
# 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
#
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
#
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
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=$?
#
;;
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.
;;
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
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 {
/* 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 "
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 "
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;
}
{"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},
{"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},
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;
}
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" */
}
}
}
- 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;
}
* 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");
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;
}
/*
* 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 ||
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);
}
}
}
{"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},
{"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},
{"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},
{"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},
{"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}
};
{"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},
{"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}
};
{"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}
};
{"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},
{"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}
};
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 */
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 */
};
/*
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 */
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 */
};
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;
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;
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? */
};
/*
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;
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 */
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 */
};
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 */
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 */
};
/* 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);
}
*/
void set_jcr_defaults(JCR *jcr, JOB *job)
{
- STORE *st;
jcr->job = job;
jcr->JobType = job->JobType;
switch (jcr->JobType) {
}
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);
}
}
-/*
- * 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)
{
/* 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;
+}
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);
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) {
/*
* 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));
}
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"),
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;
}
*/
bool do_mac(JCR *jcr)
{
+ POOL_DBR pr;
+ POOL *pool;
const char *Type;
char ed1[100];
BSOCK *sd;
}
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);
/*
* 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;
}
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;
// 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"
" 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"
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,
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,
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);
+ }
}
* 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
* 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
#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
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
}
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) {
}
}
}
+
+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;
+}
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);
};
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);
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, "");
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;
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;
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*");
}
Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
}
}
- jcr->PoolId = pr.PoolId;
jcr->jr.PoolId = pr.PoolId;
return 1;
}
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];
* 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];
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);
*/
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;
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
/* 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, ",");
}
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;
break;
case 3: /* file */
case 4: /* dir */
+ if (!has_value(ua, i)) {
+ return 0;
+ }
if (!have_date) {
bstrutime(date, sizeof(date), time(NULL));
}
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]);
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) {
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);
}
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;
}
* 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 */
}
{"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},
{"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},
{"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},
{"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},
{"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}
};
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 */
(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;
/* 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)
*
*/
-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
* 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 */
};
* 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 */
};
/* 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();
#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
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);
#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.
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);
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;
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);
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);
return NULL;
}
+
/*
* This job is done, so release the device. From a Unix standpoint,
* the device remains open.
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;
}
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);
+}
return ok;
}
+
+
/*
* Get info on the next appendable volume in the Director's database
* Returns: true on success
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");
/*
* 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);
}
} 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;
}
POOLMEM *changer;
if (!dev->is_autochanger()) {
+ Dmsg0(200, "======== NOT AUTOCHANGER ======\n");
return 0;
}
slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
* 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 */
}
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"),
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) {
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) {
AUTOCHANGER *changer = dcr->dev->device->changer_res;
DEVRES *device;
bool found = false;
+ bool first = true;
if (!changer) {
return false;
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;
}
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;
Dmsg0(200, "Slot unloaded\n");
}
unlock_changer(dcr);
+ V(dev->mutex);
free_pool_memory(changer_cmd);
return ok;
}
*
*/
/*
- 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.
*/
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;
};
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 {
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;
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);
}
{
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 */
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. */
if ((bnet_stat = bnet_recv(bs)) <= 0) {
break; /* connection terminated */
}
- Dmsg1(199, "<dird: %s", bs->msg);
+ Dmsg1(199, "<dird: %s\n", bs->msg);
/* Ensure that device initialization is complete */
while (!init_done) {
bmicrosleep(1, 0);
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 */
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;
}
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);
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 */
}
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;
}
*/
/*
- 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
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);
{"volblock", store_volblock},
{"stream", store_stream},
{"slot", store_slot},
+ {"storage", store_storage},
{NULL, NULL}
};
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)
{
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;
}
{
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);
}
}
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);
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++;
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 */
#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;
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 "
}
/* Create the Volume list */
-void create_volume_list()
+void init_volume_list()
{
VOLRES *dummy = NULL;
if (vol_list == NULL) {
}
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);
delete msgs;
jcr->reserve_msgs = NULL;
V(search_lock);
- return ok;
}
-
/*
* Search for a device suitable for this job.
*/
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");
}
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);
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;
}
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);
--- /dev/null
+/*
+ * 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 */
+};
} 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);
}
*
*/
/*
- 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
/*
* 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));
}
#include "stored_conf.h"
#include "bsr.h"
#include "jcr.h"
+#include "reserve.h"
#include "protos.h"
#ifdef HAVE_LIBZ
#include <zlib.h> /* compression headers */
{"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},
{"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},
{"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},
};
-// {"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 */
* 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
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);
* 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
*
/*
* 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},
{"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[] = {
{"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},
{"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}
};
* 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},
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;
}
*/
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)
*/
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]);
}
}
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;
}
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);
}
}
}
#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
{"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},
{"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},