+2003-11-xx Version 1.33 xxNov03
+18Nov03
+- Start daemons at level 90 rather than 20 so that MySQL will already
+ be started.
+- Write alter_mysql_tables.in and alter_sqlite_tables.in
+- Add Drive and InChanger to Media record.
+- Update database level to 7.
+- Add db_make_inchanger_unique() and call it when creating and updating
+ the Media record.
+- Add Drive and InChanger to database code for Media record.
+- Allow changing InChanger flag in update command.
+- First cut at allowing the user to specify slots for updating autochanger.
+- Add scan to "update slots scan".
+- Add command in SD to readlabel.
+15Nov03
+- In the bacula start/stop script, ordered the stop: FD SD Dir to
+ give the SD the best chances of updating the catalog before dying.
+- Add Drive and InChanger to MEDIA_DBR record and to Volume update
+ from the SD.
+- Reorganize the Volume info update from SD so that the Dir sends back the
+ current information in case the Volume status has changed by expiring.
+ The DIR-SD protocol is not backward compatible (must update).
+- Fixed the signal handler to pass the signal to the exit_handler()
+ previously it passed 1.
+- Modified SD so that on normal shutdown, it walks through all jcrs and
+ cancels them so that the Volume status will be updated in the catalog.
+- Found and fixed a bug where ST_LABEL was not set in append mode
+ (when a different tape was accepted other than the original one
+ proposed by the DIR.
+- Update the catalog Volume info after dev->file is incremented rather
+ than waiting for end of job.
+12Nov03
+- Change getdomainname() prototype for Darwin.
+- Add gethost_strerror() to create correct error message for
+ gethostbyname().
+- After doing a kill() of a stalled connection in watchdog, turn off
+ the timer to prevent an infinite loop.
+- Allow Bacula to rewrite the label on a disk volume.
+- Correct usage report printed by bsmtp.
+11Nov03
+- Complete changing references to bsmtp from smtp.
+- Add L_NONE for Admin and Restore jobs and update level_to_str()
+- Fix segfault from double free of RestoreBootstrap in job.c
+10Nov03
+- Change console to bconsole
+- Change console.conf to bconsole.conf
+- Change smtp to bsmtp
+- Implement .bconsolerc
+- Check if volume has expired when doing an update media for the SD
+09Nov03
+- Implement new code that assures that a non-zero Slot is unique within
+ a given Pool. When setting a non-zero Slot, the Slot of all other
+ Volumes with the same Slot is set to zero.
+07Nov03
+- Fix bug reported by Lars where an incorrect Volume name was printed
+ by the "status dir" command.
+06Nov03
+- Pretty up a few error messages printed by smtp.
+- Make btime_t int64_t so that one can do arithmetic.
+- Implement since as utime (64 bit UTC).
+- Compute clock diff between Dir and FD, and adjust since time.
+- Apply SQL fix from Nic Bellamy (thanks).
+- Apply John's zlib #ifdefing fix.
+05Nov03
+- Add Dan's with-sd-user, ... to configure.in.
+- Add Dan's userid and group modifications to bacula.in
+- Lots of documentation updates.
+- Make console print "Enter a period to cancel a command" when starting.
+- Fix the "list nextvol" command so that it doesn't try to close the
+ database twice, giving a segfault.
+- Fix (hopefully) to dircmd.c so that a mount request does a pthread_cond_signal.
+ There was one path were the signal was not sent. This should fix the bug
+ that requires you to do two "mount" commands to free a job waiting on a mount.
+- Make dir_ask_sysop_to_mount_next_volume() return immediately if a slot is
+ specified.
+- Correct some of the messages in testfind.c (pointed out by Dan -- thanks).
+- Alias fd to client, sd to storage.
+- Changed order of Console commands so that short commands such as q (quit)
+ are more logical.
+
2003-11-03 Version 1.32d 02Nov03 Release
02Nov03
- Mainly a bug fix release.
chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
chmod 755 src/cats/create_mysql_database
chmod 755 src/cats/make_catalog_backup src/cats/delete_catalog_backup
- chmod 755 src/cats/alter_mysql_tables
+ chmod 755 src/cats/update_mysql_tables
chmod 755 src/cats/create_sqlite_database
- chmod 755 src/cats/alter_sqlite_tables
+ chmod 755 src/cats/update_sqlite_tables
+ chomd 755 src/cats/update_bacula_tables
chmod 755 src/cats/create_bdb_database
chmod 755 src/cats/grant_mysql_privileges
- Release Notes for Bacula 1.32d
+ Release Notes for Bacula 1.33
Bacula code: Total files = 259 Total lines = 78,087 (*.h *.c *.in)
-Most Significant Changes since 1.32c
-- Mainly a bug fix release.
-- Do a clean of both Gnome directories.
-- Require that FileSet id match when finding an Incremental
- previous job. This was already the case for a Full.
-- Print message if no status returned from FD.
-- Correct "Do not forget to mount the drive" message. Test was
- backward.
-- "status dir" stopped scanning the run records on the first
- one that matched giving an incomplete listing.
-- Edit commas in Bytes on "estimate" command output.
+Most Significant Changes since 1.32d
+- Implement "update slots scan" that reads the volume label.
-Most Significant Changes since 1.32b
-- Implemented a RunAfterFailedJob record in the Job resource.
-- Implemented "delete job" command in the Console.
-- Gnome 2.0 console compiles and works.
-- Implemented VerifyJob record in the Job resource
- that tells Verify which job to verify (JobId not required)
-- First cut Verify Disk to Catalog
-- Fix "status dir" to examine all run commands in Schedule.
-- Close unused file descriptors in bpipe.c
-- There is now a patch for FreeBSD 4.8 pthreads that
- fixes the problems of data loss at the end of a tape.
- Please see:
- <bacula-source>/platforms/freebsd/pthreads-fix.txt
-- Fixed (I think) the elusive Windows "packet too big" bug.
-- Added %v to RunBefore/After editing codes. It edits in
- a list of Volumes used for the job (not tested).
-
-Most Significant Changes since 1.32a:
-- Improve forward space file/block during restore, many
- optimizations.
-- Fix a Bacula bug that did not allow appending to a tape
- on FreeBSD systems.
-- Fix pruning so that it will not prune the current job.
-- Modify configure to use non-threaded MySQL client lib if
- the threaded version is not present.
-- Implement restore by file before date.
-- When pruning don't prune the current job.
-
-Major Changes 1.32a Release:
-- Implemented forward space file/block whenever possible
- during restore. Restoring a small number of files is now
- much faster.
-- There is a new option to restore that allows you
- to restore files based on their Filename. You can
- also specify a file to read which contains the list.
-- Added ClientRunBeforeJob and ClientRunAfterJob.
-- Implemented Include | and < in File daemon.
-- Automatic labeling of tape Volumes should work now.
-- Recycling has been completely restructured and should work.
-- Implemented full length time interval qualifiers (e.g
- "5n is now "5 min" or "5 minutes". A modifier is now required!
-- Fixed gnome-console to compile with RH9 (Gnome 2.0)
-- Implemented "list nextvol job=xxx", which displays the
- next volume to be used by job xxx. The Volume name to
- be used is also added to the "status dir" output.
-- Lots of fixes with variable expansion and counter variables
-- Implemented a new Include/Exclude syntax.
-- While writing a tape, an end of file mark will be written
- every 1Gb. This makes restores faster. If you want to
- change this use "Maximum File Size" in the SD Device
- resource.
-
-
-Other Changes 1.32a Release:
-- Fixed sparse file bug.
-- A warning message is sent when a job starts that will be
- blocked because the user did an "unmount".
-- Block checksum errors if any are printed in the job report.
-- Implemented a single routine to read_records. It also returns
- a different record packet for each session. This means
- that multiple simultaneous jobs should work.
-- Added SDConnectTimeout to FD.
-- Lots of doc enhancements
-- Fixed a PurgeOldestVolume bug (VolStatus not returned)
-- Don't crash if DB address record not specified.
-- Return VolStatus on find_next_volume.
-- Use alist for incexe name_list.
-- Use bget_dirmsg() everywhere possible when talking to FD.
-- Delete old semaphore job and workq job scheduling code.
-- edit_run_codes in one place (/lib) Add Job name
-- Update query.sql to find current backups correctly.
-- Correct ambiguous SQL statement for pruning.
-- Set heartbeat interval to zero by default.
-- Fix a possible race condition in stopping the
- heartbeat thread.
-- Eliminate gnome2-console directory. Everything is in gnome-console
-- Enhanced "packet too big" message to indicate who sent it.
-- Corrected console prompt problem in non-readline versions.
-- Correct a number of variable expansion problems.
-- Added a number of new regression tests.
-- In an attempt to make configuration a bit less confusing, I've changed
- the name of a number of variables. The old ones still work, but will
- be phased out over time. FDAddress, FDPassword, SDAddress SDPassword,
- SDDeviceName, and DBPassword.
-- A possible fix to the very intermittent SD crashes that Alex gets.
-
Items to note: !!!!!
-- Modifiers (sec, min, hour, day, ...) are now required on conf file
- time interval specifications.
-- Duplicate names within the same conf resource are prohibited.
-- If you have used a prior BETA version of 1.32, please do
- the following to cleanup any zero length spool files:
+- The daemon protocol has changed, you must update everything at once.
+- The database level has been updated. You must either re-initialize
+ your databases with:
+
+ ./drop_bacula_tables
+ ./make_bacula_tables
- cd <working-directory-as-in-Bacula-conf>
- rm -f *.spool.*
+ which will delete ALL prior catalog information, or you can
+ update your database with:
- Please be sure there are no spaces between the asterisks
- and the periods.
+ ./alter_bacula_tables
src/cats/Makefile \
src/cats/make_catalog_backup \
src/cats/delete_catalog_backup \
- src/cats/alter_mysql_tables \
src/cats/make_mysql_tables \
src/cats/drop_mysql_tables \
+ src/cats/update_mysql_tables \
src/cats/create_mysql_database \
src/cats/grant_mysql_privileges \
- src/cats/alter_sqlite_tables \
src/cats/make_sqlite_tables \
src/cats/drop_sqlite_tables \
+ src/cats/update_sqlite_tables \
src/cats/create_sqlite_database \
src/cats/sqlite \
src/cats/mysql \
src/cats/drop_bdb_tables \
src/cats/make_bacula_tables \
src/cats/drop_bacula_tables \
+ src/cats/update_bacula_tables \
src/findlib/Makefile \
src/tools/Makefile \
$PFILES ],
chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
chmod 755 src/cats/create_mysql_database
chmod 755 src/cats/make_catalog_backup src/cats/delete_catalog_backup
-chmod 755 src/cats/alter_mysql_tables
chmod 755 src/cats/grant_mysql_privileges
chmod 755 src/cats/make_sqlite_tables src/cats/drop_sqlite_tables
chmod 755 src/cats/make_bacula_tables src/cats/drop_bacula_tables
+chmod 755 src/cats/update_bacula_tables src/cats/update_mysql_tables
+chmod 755 src/cats/update/mysql_tables
chmod 755 src/cats/create_sqlite_database
-chmod 755 src/cats/alter_sqlite_tables
chmod 755 src/cats/sqlite
chmod 755 src/cats/make_bdb_tables src/cats/drop_bdb_tables
chmod 755 src/cats/create_bdb_database
exit 1
fi
- ac_config_files="$ac_config_files autoconf/Make.common Makefile rescue/Makefile rescue/linux/Makefile rescue/freebsd/Makefile rescue/solaris/Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/bconsole scripts/gconsole scripts/bacula scripts/fd scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/mtx-changer doc/Makefile src/Makefile src/host.h src/console/Makefile src/console/bconsole.conf src/gnome-console/Makefile src/gnome-console/gnome-console.conf src/gnome2-console/Makefile src/gnome2-console/gnome-console.conf src/tconsole/Makefile src/dird/Makefile src/dird/bacula-dir.conf src/lib/Makefile src/stored/Makefile src/stored/bacula-sd.conf src/filed/Makefile src/filed/bacula-fd.conf src/filed/win32/Makefile src/cats/Makefile src/cats/make_catalog_backup src/cats/delete_catalog_backup src/cats/alter_mysql_tables src/cats/make_mysql_tables src/cats/drop_mysql_tables src/cats/create_mysql_database src/cats/grant_mysql_privileges src/cats/alter_sqlite_tables src/cats/make_sqlite_tables src/cats/drop_sqlite_tables src/cats/create_sqlite_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/make_bdb_tables src/cats/drop_bdb_tables src/cats/make_bacula_tables src/cats/drop_bacula_tables src/findlib/Makefile src/tools/Makefile $PFILES"
+ ac_config_files="$ac_config_files autoconf/Make.common Makefile rescue/Makefile rescue/linux/Makefile rescue/freebsd/Makefile rescue/solaris/Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/bconsole scripts/gconsole scripts/bacula scripts/fd scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/mtx-changer doc/Makefile src/Makefile src/host.h src/console/Makefile src/console/bconsole.conf src/gnome-console/Makefile src/gnome-console/gnome-console.conf src/gnome2-console/Makefile src/gnome2-console/gnome-console.conf src/tconsole/Makefile src/dird/Makefile src/dird/bacula-dir.conf src/lib/Makefile src/stored/Makefile src/stored/bacula-sd.conf src/filed/Makefile src/filed/bacula-fd.conf src/filed/win32/Makefile src/cats/Makefile src/cats/make_catalog_backup src/cats/delete_catalog_backup src/cats/make_mysql_tables src/cats/drop_mysql_tables src/cats/update_mysql_tables src/cats/create_mysql_database src/cats/grant_mysql_privileges src/cats/make_sqlite_tables src/cats/drop_sqlite_tables src/cats/update_sqlite_tables src/cats/create_sqlite_database src/cats/sqlite src/cats/mysql src/cats/create_bdb_database src/cats/make_bdb_tables src/cats/drop_bdb_tables src/cats/make_bacula_tables src/cats/drop_bacula_tables src/cats/update_bacula_tables src/findlib/Makefile src/tools/Makefile $PFILES"
ac_config_commands="$ac_config_commands default"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
"src/cats/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/cats/Makefile" ;;
"src/cats/make_catalog_backup" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_catalog_backup" ;;
"src/cats/delete_catalog_backup" ) CONFIG_FILES="$CONFIG_FILES src/cats/delete_catalog_backup" ;;
- "src/cats/alter_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/alter_mysql_tables" ;;
"src/cats/make_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_mysql_tables" ;;
"src/cats/drop_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_mysql_tables" ;;
+ "src/cats/update_mysql_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_mysql_tables" ;;
"src/cats/create_mysql_database" ) CONFIG_FILES="$CONFIG_FILES src/cats/create_mysql_database" ;;
"src/cats/grant_mysql_privileges" ) CONFIG_FILES="$CONFIG_FILES src/cats/grant_mysql_privileges" ;;
- "src/cats/alter_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/alter_sqlite_tables" ;;
"src/cats/make_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_sqlite_tables" ;;
"src/cats/drop_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_sqlite_tables" ;;
+ "src/cats/update_sqlite_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_sqlite_tables" ;;
"src/cats/create_sqlite_database" ) CONFIG_FILES="$CONFIG_FILES src/cats/create_sqlite_database" ;;
"src/cats/sqlite" ) CONFIG_FILES="$CONFIG_FILES src/cats/sqlite" ;;
"src/cats/mysql" ) CONFIG_FILES="$CONFIG_FILES src/cats/mysql" ;;
"src/cats/drop_bdb_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_bdb_tables" ;;
"src/cats/make_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/make_bacula_tables" ;;
"src/cats/drop_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/drop_bacula_tables" ;;
+ "src/cats/update_bacula_tables" ) CONFIG_FILES="$CONFIG_FILES src/cats/update_bacula_tables" ;;
"src/findlib/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/findlib/Makefile" ;;
"src/tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tools/Makefile" ;;
"$PFILES" ) CONFIG_FILES="$CONFIG_FILES $PFILES" ;;
chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
chmod 755 src/cats/create_mysql_database
chmod 755 src/cats/make_catalog_backup src/cats/delete_catalog_backup
-chmod 755 src/cats/alter_mysql_tables
chmod 755 src/cats/grant_mysql_privileges
chmod 755 src/cats/make_sqlite_tables src/cats/drop_sqlite_tables
chmod 755 src/cats/make_bacula_tables src/cats/drop_bacula_tables
+chmod 755 src/cats/update_bacula_tables src/cats/update_mysql_tables
+chmod 755 src/cats/update/mysql_tables
chmod 755 src/cats/create_sqlite_database
-chmod 755 src/cats/alter_sqlite_tables
chmod 755 src/cats/sqlite
chmod 755 src/cats/make_bdb_tables src/cats/drop_bdb_tables
chmod 755 src/cats/create_bdb_database
For 1.33
+- Optimize fsf not to read.
+- Use ioctl() fsf if it exists. Figure out where we are from
+ the mt_status command. Use slow fsf only if other does not work.
+- Add flag to write only one EOF mark on the tape.
+- Implement autochanger testing in btape "test" command.
+- Make sure that Volumes are recycled based on "Least recently used"
+ rather than lowest MediaId.
+- Implement RestoreJobRetention? Maybe better "JobRetention" in a Job,
+ which would take precidence over the Catalog "JobRetention".
+- Implement Label Format in Add and Label console commands.
+- Enhance "update slots" to include a "scan" feature
+ scan 1; scan 1-5; scan 1,2,4 ... to update the catalog
+- Allow a slot or range of slots on the label barcodes command.
+- Finish implementation of Verify=DiskToCatalog
+- Possibly up network buffers to 65K.
+- Keep last 5 or 10 completed jobs and show them in a similar list.
+- Make a Running Jobs: output similar to current Scheduled Jobs:
+- Optimize fsf not to read.
+- Use ioctl() fsf if it exists. Figure out where we are from
+ the mt_status command. Use slow fsf only if other does not work.
+- Add flag to write only one EOF mark on the tape.
+- Implement autochanger testing in btape "test" command.
+
+After 1.33:
+- Print warning message if FileId > 4 billion
- do a "messages" before the first prompt in Console
- Add a date and time stamp at the beginning of every line in the
Job report (Volker Sauer).
to start a job or pass its DHCP obtained IP number.
- Implement multiple Consoles.
- Implement a query tape prompt/replace feature for a console
-- Make sure that Volumes are recycled based on "Least recently used"
- rather than lowest MediaId.
-- Implement RestoreJobRetention? Maybe better "JobRetention" in a Job,
- which would take precidence over the Catalog "JobRetention".
-- Implement Label Format in Add and Label console commands.
-- Enhance "update slots" to include a "scan" feature
- scan 1; scan 1-5; scan 1,2,4 ... to update the catalog
-- Allow a slot or range of slots on the label barcodes command.
-- Fix time difference problem between Bacula and Client
- so that everything is in GMT.
-- Finish implementation of Verify=DiskToCatalog
-- Change console to bconsole.
-- Change smtp to bsmtp.
-- Possibly up network buffers to 65K.
-- Keep last 5 or 10 completed jobs and show them in a similar list.
-- Make a Running Jobs: output similar to current Scheduled Jobs:
-- Fix TimeZone problem!
-- Optimize fsf not to read.
-- Use ioctl() fsf if it exists. Figure out where we are from
- the mt_status command. Use slow fsf only if other does
- not work.
-- Add flag to write only one EOF mark on the tape.
-- Implement autochange testing in btape.
- From Johan?
Two jobs ready to go, first one blocked waiting for media
Cancel 2nd job ("waiting execution" one)
gotten the CPU and created the file. You must use atomic functions
(those that don't get interrupted by other processes) and O_EXCL is
the only way for this particular example.
-- Mount a tape that is not right for the job (wrong # files on tape)
- Bacula asks for another tape, fix problems with first tape and
- say "mount". All works OK, but status shows:
- Device /dev/nst0 open but no Bacula volume is mounted.
- Total Bytes=1,153,820,213 Blocks=17,888 Bytes/block=64,502
- Positioned at File=9 Block=3,951
- Full Backup job Rufus.2003-10-26_16.45.31 using Volume "DLT-24Oct03" on device /dev/nst0
- Files=21,003 Bytes=253,954,408 Bytes/sec=2,919,016
- FDReadSeqNo=192,134 in_msg=129830 out_msg=5 fd=7
- Automatically create pools, but instead of looking for what
in in Job records, walk through the pool resources.
- Check and double check tree code, why does it take so long?
-- Upgrade to cygwin 1.5
- Add device name to "Current Volume not acceptable because ..."
- Make sure that Bacula rechecks the tape after the 20 min wait.
- Set IO_NOWAIT on Bacula TCP/IP packets.
It is somewhat like a Full save becomes an incremental since
the Base job (or jobs) plus other non-base files.
Need:
-- New BaseFile table that contains:
- JobId, BaseJobId, FileId (from Base).
+- A Base backup is same as Full backup, just different type.
+- New BaseFiles table that contains:
+ BaseId - index
+ BaseJobId - Base JobId referenced for this FileId (needed ???)
+ JobId - JobId currently running
+ FileId - File not backed up, exists in Base Job
+ FileIndex - FileIndex from Base Job.
i.e. for each base file that exists but is not saved because
it has not changed, the File daemon sends the JobId, BaseId,
- and FileId back to the Director who creates the DB entry.
+ FileId, FileIndex back to the Director who creates the DB entry.
- To initiate a Base save, the Director sends the FD
the FileId, and full filename for each file in the Base.
- When the FD finds a Base file, he requests the Director to
- Implement ClientRunBeforeJob and ClientRunAfterJob.
- Implement forward spacing block/file: position_device(bsr) --
just before read_block_from_device();
+- Change console to bconsole.
+- Change smtp to bsmtp.
+- Fix time difference problem between Bacula and Client
+ so that everything is in GMT.
+- Fix TimeZone problem!
+- Mount a tape that is not right for the job (wrong # files on tape)
+ Bacula asks for another tape, fix problems with first tape and
+ say "mount". All works OK, but status shows:
+ Device /dev/nst0 open but no Bacula volume is mounted.
+ Total Bytes=1,153,820,213 Blocks=17,888 Bytes/block=64,502
+ Positioned at File=9 Block=3,951
+ Full Backup job Rufus.2003-10-26_16.45.31 using Volume "DLT-24Oct03" on device /dev/nst0
+ Files=21,003 Bytes=253,954,408 Bytes/sec=2,919,016
+ FDReadSeqNo=192,134 in_msg=129830 out_msg=5 fd=7
+- Upgrade to cygwin 1.5
# bacula This shell script takes care of starting and stopping
# the bacula Director daemon
#
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
# description: It comes by night and sucks the vital essence from your computers.
#
# For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
# bacula This shell script takes care of starting and stopping
# the bacula File daemon.
#
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
# description: It comes by night and sucks the vital essence from your computers.
#
# For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
# bacula This shell script takes care of starting and stopping
# the bacula Storage daemon.
#
-# chkconfig: 2345 20 99
+# chkconfig: 2345 90 99
# description: It comes by night and sucks the vital essence from your computers.
#
# For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
Makefile
make_catalog_backup
delete_catalog_backup
-alter_mysql_tables
-alter_sqlite_tables
create_bdb_database
create_mysql_database
create_sqlite_database
sqlite
make_bacula_tables
drop_bacula_tables
+update.sql
+update2_sqlite_tables
+update_bacula_tables
+update_mysql_tables
+update_sqlite_tables
$(RMF) create_mysql_database make_sqlite_tables sqlite
$(RMF) create_bdb_database drop_bdb_tables make_dbd_tables
$(RMF) make_catalog_backup delete_catalog_backup
- $(RMF) alter_mysql_tables alter_sqlite_tables create_sqlite_database
+ $(RMF) update_mysql_tables update_sqlite_tables create_sqlite_database
$(RMF) drop_bacula_tables drop_sqlite_tables make_bacula_tables
+ $(RMF) update_bacula_tables
$(RMF) drop_bdb_tables make_bdb_tables mysql
distclean: realclean
$(INSTALL_SCRIPT) create_@DB_NAME@_database $(DESTDIR)$(scriptdir)/create_@DB_NAME@_database
$(INSTALL_SCRIPT) drop_@DB_NAME@_tables $(DESTDIR)$(scriptdir)/drop_@DB_NAME@_tables
$(INSTALL_SCRIPT) make_@DB_NAME@_tables $(DESTDIR)$(scriptdir)/make_@DB_NAME@_tables
+ $(INSTALL_SCRIPT) update_@DB_NAME@_tables $(DESTDIR)$(scriptdir)/update_@DB_NAME@_tables
$(INSTALL_SCRIPT) drop_bacula_tables $(DESTDIR)$(scriptdir)/drop_bacula_tables
$(INSTALL_SCRIPT) make_bacula_tables $(DESTDIR)$(scriptdir)/make_bacula_tables
+ $(INSTALL_SCRIPT) update_bacula_tables $(DESTDIR)$(scriptdir)/update_bacula_tables
$(INSTALL_SCRIPT) make_catalog_backup $(DESTDIR)$(scriptdir)/make_catalog_backup
$(INSTALL_SCRIPT) delete_catalog_backup $(DESTDIR)$(scriptdir)/delete_catalog_backup
$(INSTALL_SCRIPT) grant_mysql_privileges $(DESTDIR)$(scriptdir)/grant_mysql_privileges
(cd $(DESTDIR)$(scriptdir); $(RMF) create_@DB_NAME@_database)
(cd $(DESTDIR)$(scriptdir); $(RMF) drop_@DB_NAME@_tables)
(cd $(DESTDIR)$(scriptdir); $(RMF) make_@DB_NAME@_tables)
+ (cd $(DESTDIR)$(scriptdir); $(RMF) update_@DB_NAME@_tables)
(cd $(DESTDIR)$(scriptdir); $(RMF) drop_bacula_tables)
(cd $(DESTDIR)$(scriptdir); $(RMF) make_bacula_tables)
+ (cd $(DESTDIR)$(scriptdir); $(RMF) update_bacula_tables)
(cd $(DESTDIR)$(scriptdir); $(RMF) make_catalog_backup)
(cd $(DESTDIR)$(scriptdir); $(RMF) delete_catalog_backup)
(cd $(DESTDIR)$(scriptdir); $(RMF) grant_mysql_privileges)
#ifdef HAVE_SQLITE
-#define BDB_VERSION 6
+#define BDB_VERSION 7
#include <sqlite.h>
#ifdef HAVE_MYSQL
-#define BDB_VERSION 6
+#define BDB_VERSION 7
#include <mysql.h>
# ****FIXME**** make FileId BIGINT someday when MySQL works *****
CREATE TABLE File (
FileId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
- FileIndex INTEGER UNSIGNED NOT NULL,
+ FileIndex INTEGER UNSIGNED NOT NULL DEFAULT 0,
JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
FilenameId INTEGER UNSIGNED NOT NULL REFERENCES Filename,
StartTime DATETIME NOT NULL,
EndTime DATETIME NOT NULL,
JobTDate BIGINT UNSIGNED NOT NULL,
- VolSessionId INTEGER UNSIGNED NOT NULL,
- VolSessionTime INTEGER UNSIGNED NOT NULL,
- JobFiles INTEGER UNSIGNED NOT NULL,
+ VolSessionId INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolSessionTime INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ JobFiles INTEGER UNSIGNED NOT NULL DEFAULT 0,
JobBytes BIGINT UNSIGNED NOT NULL,
- JobErrors INTEGER UNSIGNED NOT NULL,
- JobMissingFiles INTEGER UNSIGNED NOT NULL,
+ JobErrors INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ JobMissingFiles INTEGER UNSIGNED NOT NULL DEFAULT 0,
PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
FileSetId INTEGER UNSIGNED NOT NULL REFERENCES FileSet,
PurgedFiles TINYINT NOT NULL DEFAULT 0,
JobMediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
MediaId INTEGER UNSIGNED NOT NULL REFERENCES Media,
- FirstIndex INTEGER UNSIGNED NOT NULL,
- LastIndex INTEGER UNSIGNED NOT NULL,
- StartFile INTEGER UNSIGNED NOT NULL,
- EndFile INTEGER UNSIGNED NOT NULL,
- StartBlock INTEGER UNSIGNED NOT NULL,
- EndBlock INTEGER UNSIGNED NOT NULL,
- VolIndex INTEGER UNSIGNED NOT NULL,
+ FirstIndex INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ LastIndex INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ StartFile INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ EndFile INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ StartBlock INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ EndBlock INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolIndex INTEGER UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY(JobMediaId),
INDEX (JobId, MediaId)
);
FirstWritten DATETIME NOT NULL,
LastWritten DATETIME NOT NULL,
LabelDate DATETIME NOT NULL,
- VolJobs INTEGER UNSIGNED NOT NULL,
- VolFiles INTEGER UNSIGNED NOT NULL,
- VolBlocks INTEGER UNSIGNED NOT NULL,
- VolMounts INTEGER UNSIGNED NOT NULL,
- VolBytes BIGINT UNSIGNED NOT NULL,
- VolErrors INTEGER UNSIGNED NOT NULL,
- VolWrites INTEGER UNSIGNED NOT NULL,
+ VolJobs INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolFiles INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolBlocks INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolMounts INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolBytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ VolErrors INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ VolWrites INTEGER UNSIGNED NOT NULL DEFAULT 0,
VolCapacityBytes BIGINT UNSIGNED NOT NULL,
VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Purged',
'Read-Only', 'Disabled', 'Error', 'Busy', 'Used', 'Cleaning') NOT NULL,
- Recycle TINYINT NOT NULL,
- VolRetention BIGINT UNSIGNED NOT NULL,
- VolUseDuration BIGINT UNSIGNED NOT NULL,
- MaxVolJobs INTEGER UNSIGNED NOT NULL,
- MaxVolFiles INTEGER UNSIGNED NOT NULL,
- MaxVolBytes BIGINT UNSIGNED NOT NULL,
+ Recycle TINYINT NOT NULL DEFAULT 0,
+ VolRetention BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ VolUseDuration BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ MaxVolJobs INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ MaxVolFiles INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ MaxVolBytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ Drive INTEGER NOT NULL DEFAULT 0,
+ InChanger TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY(MediaId),
INDEX (PoolId)
);
CREATE TABLE Pool (
PoolId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
Name TINYBLOB NOT NULL,
- NumVols INTEGER UNSIGNED NOT NULL,
- MaxVols INTEGER UNSIGNED NOT NULL,
+ NumVols INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ MaxVols INTEGER UNSIGNED NOT NULL DEFAULT 0,
UseOnce TINYINT NOT NULL,
UseCatalog TINYINT NOT NULL,
AcceptAnyVolume TINYINT DEFAULT 0,
VolRetention BIGINT UNSIGNED NOT NULL,
VolUseDuration BIGINT UNSIGNED NOT NULL,
- MaxVolJobs INTEGER UNSIGNED NOT NULL,
- MaxVolFiles INTEGER UNSIGNED NOT NULL,
+ MaxVolJobs INTEGER UNSIGNED NOT NULL DEFAULT 0,
+ MaxVolFiles INTEGER UNSIGNED NOT NULL DEFAULT 0,
MaxVolBytes BIGINT UNSIGNED NOT NULL,
AutoPrune TINYINT DEFAULT 0,
Recycle TINYINT DEFAULT 0,
);
-- Initialize Version
-INSERT INTO Version (VersionId) VALUES (6);
+INSERT INTO Version (VersionId) VALUES (7);
CREATE TABLE Counters (
Counter TINYBLOB NOT NULL,
MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+ Drive INTEGER DEFAULT 0,
+ InChanger TINYINT DEFAULT 0,
PRIMARY KEY(MediaId)
);
);
-- Initialize Version
-INSERT INTO Version (VersionId) VALUES (6);
+INSERT INTO Version (VersionId) VALUES (7);
CREATE TABLE Counters (
Counter TEXT NOT NULL,
/* sql.c */
B_DB *db_init_database(JCR *jcr, char *db_name, char *db_user, char *db_password,
- char *db_address, int db_port, char *db_socket);
+ char *db_address, int db_port, char *db_socket);
int db_open_database(JCR *jcr, B_DB *db);
void db_close_database(JCR *jcr, B_DB *db);
void db_escape_string(char *snew, char *old, int len);
int db_create_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *media_dbr);
int db_create_client_record(JCR *jcr, B_DB *db, CLIENT_DBR *cr);
int db_create_fileset_record(JCR *jcr, B_DB *db, FILESET_DBR *fsr);
-int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr);
+int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr);
int db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jr);
int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
int db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type);
int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
-void db_make_slot_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
+void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
#endif /* __SQL_PROTOS_H */
sql_free_result(mdb);
}
- /* Make sur Slot, if non-zero, is unique */
- db_make_slot_unique(jcr, mdb, mr);
+ /* Make sure that if InChanger is non-zero any other identical slot
+ * has InChanger zero.
+ */
+ db_make_inchanger_unique(jcr, mdb, mr);
/* Must create it */
if (mr->LabelDate) {
Mmsg(&mdb->cmd,
"INSERT INTO Media (VolumeName,MediaType,PoolId,MaxVolBytes,VolCapacityBytes,"
"Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-"VolStatus,LabelDate,Slot,VolBytes) "
-"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s','%s',%d,%s)",
+"VolStatus,LabelDate,Slot,VolBytes,Drive,InChanger) "
+"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s','%s',%d,%s,%d,%d)",
mr->VolumeName,
mr->MediaType, mr->PoolId,
edit_uint64(mr->MaxVolBytes,ed1),
mr->MaxVolFiles,
mr->VolStatus, dt,
mr->Slot,
- edit_uint64(mr->VolBytes, ed5));
+ edit_uint64(mr->VolBytes, ed5),
+ mr->Drive,
+ mr->InChanger);
Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
stat = UPDATE_DB(jcr, mdb, mdb->cmd);
}
- /* Make sure Slot, if non-zero, is unique */
- db_make_slot_unique(jcr, mdb, mr);
+ /* Make sure InChanger is 0 for any record having the same Slot */
+ db_make_inchanger_unique(jcr, mdb, mr);
ttime = mr->LastWritten;
localtime_r(&ttime, &tm);
strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
- Mmsg(&mdb->cmd, "UPDATE Media SET VolJobs=%u,\
- VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,\
- VolWrites=%u,MaxVolBytes=%s,LastWritten='%s',VolStatus='%s',\
- Slot=%d WHERE VolumeName='%s'",
- mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
- mr->VolMounts, mr->VolErrors, mr->VolWrites,
- edit_uint64(mr->MaxVolBytes, ed2), dt,
- mr->VolStatus, mr->Slot, mr->VolumeName);
+ Mmsg(&mdb->cmd, "UPDATE Media SET VolJobs=%u,"
+ "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
+ "VolWrites=%u,MaxVolBytes=%s,LastWritten='%s',VolStatus='%s',"
+ "Slot=%d,Drive=%d,InChanger=%d WHERE VolumeName='%s'",
+ mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
+ mr->VolMounts, mr->VolErrors, mr->VolWrites,
+ edit_uint64(mr->MaxVolBytes, ed2), dt,
+ mr->VolStatus, mr->Slot, mr->VolumeName, mr->Drive, mr->InChanger);
Dmsg1(400, "%s\n", mdb->cmd);
}
/*
- * If we have a non-zero Slot, ensure that no other Media
- * record in this Pool has the same Slot by setting Slot=0.
+ * If we have a non-zero InChanger, ensure that no other Media
+ * record in this Pool has InChanger set on the same Slot.
*
* This routine assumes the database is already locked.
*/
void
-db_make_slot_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
+db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
{
- if (mr->Slot != 0) {
- Mmsg(&mdb->cmd, "UPDATE Media SET Slot=0 WHERE PoolId=%u "
+ if (mr->InChanger != 0) {
+ Mmsg(&mdb->cmd, "UPDATE Media SET InChanger=0 WHERE PoolId=%u "
"AND Slot=%d\n", mr->PoolId, mr->Slot);
Dmsg1(400, "%s\n", mdb->cmd);
UPDATE_DB(jcr, mdb, mdb->cmd);
--- /dev/null
+#!/bin/sh
+#
+# This routine alters the appropriately configured
+# Bacula tables for either MySQL or SQLite
+#
+if test xsqlite = x@DB_NAME@ ; then
+ echo "Altering SQLite tables"
+ . ./update_sqlite_tables
+fi
+if test xmysql = x@DB_NAME@ ; then
+ echo "Altering MySQL tables"
+ . ./update_mysql_tables
+fi
--- /dev/null
+#!/bin/sh
+#
+# Shell script to update MySQL tables from version 1.32 to 1.33
+#
+echo " "
+echo "Depending on the size of your database,"
+echo "this script may take several minutes to run."
+echo " "
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql $* -f <<END-OF-DATA
+USE bacula;
+
+ALTER TABLE Media ADD COLUMN Drive INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE Media ADD COLUMN InChanger TINYINT NOT NULL DEFAULT 0;
+
+
+DROP TABLE BaseFiles;
+
+
+CREATE TABLE BaseFiles (
+ BaseId INTEGER UNSIGNED AUTO_INCREMENT,
+ JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+ FileId INTEGER UNSIGNED NOT NULL REFERENCES File,
+ FileIndex INTEGER UNSIGNED,
+ PRIMARY KEY(BaseId)
+ );
+
+DROP TABLE UnsavedFiles;
+
+CREATE TABLE UnsavedFiles (
+ UnsavedId INTEGER UNSIGNED AUTO_INCREMENT,
+ JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+ PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
+ FilenameId INTEGER UNSIGNED NOT NULL REFERENCES Filename,
+ PRIMARY KEY (UnsavedId)
+ );
+
+UPDATE Version SET VersionId=7;
+
+END-OF-DATA
+then
+ echo "Update of Bacula MySQL tables succeeded."
+else
+ echo "Update of Bacula MySQL tables failed."
+fi
+exit 0
--- /dev/null
+#!/bin/sh
+#
+# shell script to update SQLite from version 1.32 to 1.33
+#
+echo " "
+echo "Depending on the size of your database,"
+echo "this script may take several minutes to run."
+echo " "
+
+bindir=@SQL_BINDIR@
+cd @working_dir@
+
+$bindir/sqlite $* bacula.db <<END-OF-DATA
+
+BEGIN TRANSACTION;
+CREATE TEMPORARY TABLE Media_backup (
+ MediaId INTEGER UNSIGNED AUTOINCREMENT,
+ VolumeName VARCHAR(128) NOT NULL,
+ Slot INTEGER DEFAULT 0,
+ PoolId INTEGER UNSIGNED REFERENCES Pool NOT NULL,
+ MediaType VARCHAR(128) NOT NULL,
+ FirstWritten DATETIME DEFAULT 0,
+ LastWritten DATETIME DEFAULT 0,
+ LabelDate DATETIME DEFAULT 0,
+ VolJobs INTEGER UNSIGNED DEFAULT 0,
+ VolFiles INTEGER UNSIGNED DEFAULT 0,
+ VolBlocks INTEGER UNSIGNED DEFAULT 0,
+ VolMounts INTEGER UNSIGNED DEFAULT 0,
+ VolBytes BIGINT UNSIGNED DEFAULT 0,
+ VolErrors INTEGER UNSIGNED DEFAULT 0,
+ VolWrites INTEGER UNSIGNED DEFAULT 0,
+ VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
+ VolStatus VARCHAR(20) NOT NULL,
+ Recycle TINYINT DEFAULT 0,
+ VolRetention BIGINT UNSIGNED DEFAULT 0,
+ VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+ MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+ MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+ MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+ Drive INTEGER DEFAULT 0,
+ InChanger TINYINT DEFAULT 0,
+ PRIMARY KEY(MediaId)
+ );
+
+INSERT INTO Media_backup SELECT
+ MediaId, VolumeName, Slot, PoolId,
+ MediaType, FirstWritten, LastWritten,
+ LabelDate, VolJobs, VolFiles, VolBlocks,
+ VolMounts, VolBytes, VolErrors, VolWrites,
+ VolCapacityBytes, VolStatus, Recycle,
+ VolRetention, VolUseDuration, MaxVolJobs,
+ MaxVolFiles, MaxVolBytes
+ FROM Media;
+
+
+DROP TABLE Media;
+
+CREATE TABLE Media (
+ MediaId INTEGER UNSIGNED AUTOINCREMENT,
+ VolumeName VARCHAR(128) NOT NULL,
+ Slot INTEGER DEFAULT 0,
+ PoolId INTEGER UNSIGNED REFERENCES Pool NOT NULL,
+ MediaType VARCHAR(128) NOT NULL,
+ FirstWritten DATETIME DEFAULT 0,
+ LastWritten DATETIME DEFAULT 0,
+ LabelDate DATETIME DEFAULT 0,
+ VolJobs INTEGER UNSIGNED DEFAULT 0,
+ VolFiles INTEGER UNSIGNED DEFAULT 0,
+ VolBlocks INTEGER UNSIGNED DEFAULT 0,
+ VolMounts INTEGER UNSIGNED DEFAULT 0,
+ VolBytes BIGINT UNSIGNED DEFAULT 0,
+ VolErrors INTEGER UNSIGNED DEFAULT 0,
+ VolWrites INTEGER UNSIGNED DEFAULT 0,
+ VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
+ VolStatus VARCHAR(20) NOT NULL,
+ Recycle TINYINT DEFAULT 0,
+ VolRetention BIGINT UNSIGNED DEFAULT 0,
+ VolUseDuration BIGINT UNSIGNED DEFAULT 0,
+ MaxVolJobs INTEGER UNSIGNED DEFAULT 0,
+ MaxVolFiles INTEGER UNSIGNED DEFAULT 0,
+ MaxVolBytes BIGINT UNSIGNED DEFAULT 0,
+ Drive INTEGER DEFAULT 0,
+ InChanger TINYINT DEFAULT 0,
+ PRIMARY KEY(MediaId)
+ );
+
+INSERT INTO Media (
+ MediaId, VolumeName, Slot, PoolId,
+ MediaType, FirstWritten, LastWritten,
+ LabelDate, VolJobs, VolFiles, VolBlocks,
+ VolMounts, VolBytes, VolErrors, VolWrites,
+ VolCapacityBytes, VolStatus, Recycle,
+ VolRetention, VolUseDuration, MaxVolJobs,
+ MaxVolFiles, MaxVolBytes)
+ SELECT * FROM Media_backup;
+
+DROP TABLE Media_backup;
+
+CREATE INDEX inx8 ON Media (PoolId);
+
+COMMIT;
+
+UPDATE Version SET VersionId=7;
+
+END-OF-DATA
# and to the console
Messages {
Name = Standard
- mailcommand = "@sbindir@/bsmtp -h @bsmtp_host@ -f \"\(Bacula\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
- operatorcommand = "@sbindir@/bsmtp -h @bsmtp_host@ -f \"\(Bacula\) %r\" -s \"Bacula: Intervention needed for %j\" %r"
+ mailcommand = "@sbindir@/bsmtp -h @smtp_host@ -f \"\(Bacula\) %r\" -s \"Bacula: %t %e of %c %l\" %r"
+ operatorcommand = "@sbindir@/bsmtp -h @smtp_host@ -f \"\(Bacula\) %r\" -s \"Bacula: Intervention needed for %j\" %r"
mail = @job_email@ = all, !skipped
operator = @job_email@ = mount
console = all, !skipped, !saved
}
-/* Check if string is a number */
-static int is_num(char *num)
-{
- char *p = num;
- int ch;
- while ((ch = *p++)) {
- if (ch < '0' || ch > '9') {
- return FALSE;
- }
- }
- return TRUE;
-}
-
/* Keywords (RHS) permitted in Run records */
static struct s_kw RunFields[] = {
{"pool", 'P'},
*p++ = 0; /* separate two halves */
/* Check for day range */
- if (is_num(lc->str) && is_num(p)) {
+ if (is_an_integer(lc->str) && is_an_integer(p)) {
code = atoi(lc->str) - 1;
code2 = atoi(p) - 1;
if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
int first_id = 0;
char name[MAX_NAME_LENGTH];
STORE *store;
- int slot = 0;
+ int Slot = 0, InChanger = 0;
bsendmsg(ua, _(
"You probably don't want to be using this command since it\n"
if (!get_pint(ua, _("Enter slot (0 for none): "))) {
return 1;
}
- slot = ua->pint32_val;
+ Slot = ua->pint32_val;
+ if (!get_yesno(ua, _("InChanger? yes/no: "))) {
+ return 1;
+ }
+ InChanger = ua->pint32_val;
}
set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
for (i=startnum; i < num+startnum; i++) {
bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
- mr.Slot = slot++;
+ mr.Slot = Slot++;
+ mr.InChanger = InChanger;
Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
bsendmsg(ua, db_strerror(ua->db));
if (!db_sql_query(ua->db, query, NULL, NULL)) {
bsendmsg(ua, "%s", db_strerror(ua->db));
} else {
- bsendmsg(ua, _("New recycle flag is: %s\n"),
+ bsendmsg(ua, _("New Recycle flag is: %s\n"),
mr->Recycle==1?_("yes"):_("no"));
}
free_pool_memory(query);
add_prompt(ua, _("Maximum Volume Bytes"));
add_prompt(ua, _("Recycle Flag"));
add_prompt(ua, _("Slot"));
+ add_prompt(ua, _("InChanger Flag"));
add_prompt(ua, _("Volume Files"));
add_prompt(ua, _("Pool"));
add_prompt(ua, _("Done"));
break;
case 7: /* Slot */
- int slot;
+ int Slot;
memset(&pr, 0, sizeof(POOL_DBR));
pr.PoolId = mr.PoolId;
if (!get_pint(ua, _("Enter new Slot: "))) {
return 0;
}
- slot = ua->pint32_val;
- if (pr.MaxVols > 0 && slot > (int)pr.MaxVols) {
+ Slot = ua->pint32_val;
+ if (pr.MaxVols > 0 && Slot > (int)pr.MaxVols) {
bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
pr.MaxVols);
break;
}
- mr.Slot = slot;
+ mr.Slot = Slot;
/*
* Make sure to use db_update... rather than doing this directly,
* so that any Slot is handled correctly.
}
break;
- case 8: /* Volume Files */
+ case 8: /* InChanger */
+ bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
+ if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
+ return 0;
+ }
+ mr.InChanger = ua->pint32_val;
+ /*
+ * Make sure to use db_update... rather than doing this directly,
+ * so that any Slot is handled correctly.
+ */
+ if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+ bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
+ } else {
+ bsendmsg(ua, _("New InChanger flag is: %s\n"), mr.InChanger);
+ }
+ break;
+
+
+ case 9: /* Volume Files */
int32_t VolFiles;
bsendmsg(ua, _("Warning changing Volume Files can result\n"
"in loss of data on your Volume\n\n"));
free_pool_memory(query);
break;
- case 9: /* Volume's Pool */
+ case 10: /* Volume's Pool */
memset(&pr, 0, sizeof(POOL_DBR));
pr.PoolId = mr.PoolId;
if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
}
update_volpool(ua, ua->cmd, &mr);
return 1;
+
default: /* Done or error */
bsendmsg(ua, "Selection done.\n");
return 1;
static void label_from_barcodes(UAContext *ua);
static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
POOL_DBR *pr, int relabel, bool media_record_exits);
-static vol_list_t *get_slot_list_from_SD(UAContext *ua);
+static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
+static void free_vol_list(vol_list_t *vol_list);
static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
+static BSOCK *open_sd_bsock(UAContext *ua);
+static void close_sd_bsock(UAContext *ua);
+static char *get_volume_name_from_SD(UAContext *ua, int Slot);
/*
return do_label(ua, cmd, 1); /* relabel tape */
}
+#define MAX_SLOTS 5000
+
+static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
+{
+ int i;
+ char *msg;
+
+ for (int i=0; i<num_slots; i++) {
+ slot_list[i] = 0;
+ }
+ i = find_arg_with_value(ua, "slots");
+ if (i >= 0) {
+ /* scan slot list in ua->argv[i] */
+ char *p, *e, *h;
+ int beg, end;
+
+ strip_trailing_junk(ua->argv[i]);
+ for (p=ua->argv[i]; p && *p; p=e) {
+ /* Check for list */
+ e = strchr(p, ',');
+ if (e) {
+ *e++ = 0;
+ }
+ /* Check for range */
+ h = strchr(p, '-'); /* range? */
+ if (h == p) {
+ msg = _("Negative numbers not permitted\n");
+ goto bail_out;
+ }
+ if (h) {
+ *h++ = 0;
+ if (!is_an_integer(h)) {
+ msg = _("Range end is not integer.\n");
+ goto bail_out;
+ }
+ skip_spaces(&p);
+ if (!is_an_integer(p)) {
+ msg = _("Range start is not an integer.\n");
+ goto bail_out;
+ }
+ beg = atoi(p);
+ end = atoi(h);
+ if (end < beg) {
+ msg = _("Range end not bigger than start.\n");
+ goto bail_out;
+ }
+ } else {
+ skip_spaces(&p);
+ if (!is_an_integer(p)) {
+ msg = _("Input value is not an integer.\n");
+ goto bail_out;
+ }
+ beg = end = atoi(p);
+ }
+ if (beg <= 0 || end <= 0) {
+ msg = _("Values must be be greater than zero.\n");
+ goto bail_out;
+ }
+ if (end >= num_slots) {
+ msg = _("Slot too large.\n");
+ goto bail_out;
+ }
+ for (i=beg; i<=end; i++) {
+ slot_list[i] = 1; /* Turn on specified range */
+ }
+ }
+ } else {
+ /* Turn everything on */
+ for (i=0; i<num_slots; i++) {
+ slot_list[i] = 1;
+ }
+ }
+#ifdef xxx_debug
+ printf("Slots turned on:\n");
+ for (i=1; i<num_slots; i++) {
+ if (slot_list[i]) {
+ printf("%d\n", i);
+ }
+ }
+#endif
+ return true;
+
+bail_out:
+ return false;
+}
/*
* Update Slots corresponding to Volumes in autochanger
STORE *store;
vol_list_t *vl, *vol_list = NULL;
MEDIA_DBR mr;
+ char *slot_list;
+ bool scan;
if (!open_db(ua)) {
return 1;
}
ua->jcr->store = store;
- vol_list = get_slot_list_from_SD(ua);
+ scan = find_arg(ua, _("scan")) >= 0;
+
+ slot_list = (char *)malloc(MAX_SLOTS);
+ if (!get_user_slot_list(ua, slot_list, MAX_SLOTS)) {
+ free(slot_list);
+ return 1;
+ }
+ vol_list = get_vol_list_from_SD(ua, scan);
if (!vol_list) {
bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
/* Walk through the list updating the media records */
for (vl=vol_list; vl; vl=vl->next) {
-
+ /* Check if user wants us to look at this slot */
+ if (!slot_list[vl->Slot]) {
+ continue;
+ }
+ /* If scanning, we read the label rather than the barcode */
+ if (scan) {
+ if (vl->VolName) {
+ free(vl->VolName);
+ vl->VolName = NULL;
+ }
+ vl->VolName = get_volume_name_from_SD(ua, vl->Slot);
+ }
+ if (!vl->VolName) {
+ continue;
+ }
memset(&mr, 0, sizeof(mr));
bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
db_lock(ua->db);
if (db_get_media_record(ua->jcr, ua->db, &mr)) {
- if (mr.Slot != vl->Slot) {
+ if (mr.Slot != vl->Slot || !mr.InChanger) {
mr.Slot = vl->Slot;
+ mr.InChanger = 1;
if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
bsendmsg(ua, _("%s\n"), db_strerror(ua->db));
} else {
bail_out:
- /* Free list */
- for (vl=vol_list; vl; ) {
- vol_list_t *ovl;
- free(vl->VolName);
- ovl = vl;
- vl = vl->next;
- free(ovl);
- }
- if (ua->jcr->store_bsock) {
- bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
- bnet_close(ua->jcr->store_bsock);
- ua->jcr->store_bsock = NULL;
- }
+ free_vol_list(vol_list);
+ free(slot_list);
+ close_sd_bsock(ua);
+
return 1;
}
+
/*
* Common routine for both label and relabel
*/
{
STORE *store;
BSOCK *sd;
- sd = ua->jcr->store_bsock;
char dev_name[MAX_NAME_LENGTH];
MEDIA_DBR mr, omr;
POOL_DBR pr;
} else {
mr.Slot = ua->pint32_val;
}
+ mr.InChanger = 1; /* assumed if we are labeling it */
}
bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
}
}
- bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
- store->hdr.name, store->address, store->SDport);
- if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
- bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
- return 1;
- }
- sd = ua->jcr->store_bsock;
ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
if (ok) {
+ sd = ua->jcr->store_bsock;
if (relabel) {
if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
if (print_reminder) {
bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
}
- bnet_sig(sd, BNET_TERMINATE);
- bnet_close(sd);
- ua->jcr->store_bsock = NULL;
+ close_sd_bsock(ua);
return 1;
}
MEDIA_DBR mr, omr;
vol_list_t *vl, *vol_list = NULL;
bool media_record_exists;
+ char *slot_list;
- vol_list = get_slot_list_from_SD(ua);
+ slot_list = (char *)malloc(MAX_SLOTS);
+ if (!get_user_slot_list(ua, slot_list, MAX_SLOTS)) {
+ free(slot_list);
+ return;
+ }
+
+ vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
if (!vol_list) {
bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
"Slot Volume\n"
"==============\n"));
for (vl=vol_list; vl; vl=vl->next) {
+ if (!vl->VolName || !slot_list[vl->Slot]) {
+ continue;
+ }
bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
}
if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
/* Fire off the label requests */
for (vl=vol_list; vl; vl=vl->next) {
-
+ if (!vl->VolName || !slot_list[vl->Slot]) {
+ continue;
+ }
memset(&mr, 0, sizeof(mr));
bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
media_record_exists = false;
if (mr.VolBytes != 0) {
bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
vl->Slot, mr.VolumeName);
+ if (!mr.InChanger) {
+ mr.InChanger = 1;
+ if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+ bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
+ }
+ }
continue;
}
media_record_exists = true;
}
+ mr.InChanger = 1;
/*
* Deal with creating cleaning tape here. Normal tapes created in
* send_label_request() below
continue; /* done, go handle next volume */
}
bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
- if (ua->jcr->store_bsock) {
- bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
- bnet_close(ua->jcr->store_bsock);
- ua->jcr->store_bsock = NULL;
- }
- bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
- store->hdr.name, store->address, store->SDport);
- if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
- bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
- goto bail_out;
- }
mr.Slot = vl->Slot;
- send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
+ if (!send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists)) {
+ goto bail_out;
+ }
}
bail_out:
- /* Free list */
- for (vl=vol_list; vl; ) {
- vol_list_t *ovl;
- free(vl->VolName);
- ovl = vl;
- vl = vl->next;
- free(ovl);
- }
-
- if (ua->jcr->store_bsock) {
- bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
- bnet_close(ua->jcr->store_bsock);
- ua->jcr->store_bsock = NULL;
- }
+ free_vol_list(vol_list);
+ close_sd_bsock(ua);
return;
}
char dev_name[MAX_NAME_LENGTH];
int ok = FALSE;
- sd = ua->jcr->store_bsock;
+ if (!(sd=open_sd_bsock(ua))) {
+ return 0;
+ }
bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
bash_spaces(dev_name);
bash_spaces(mr->VolumeName);
if (ok) {
if (media_record_exists) { /* we update it */
mr->VolBytes = 1;
+ mr->InChanger = 1;
if (!db_update_media_record(ua->jcr, ua->db, mr)) {
bsendmsg(ua, "%s", db_strerror(ua->db));
ok = FALSE;
} else { /* create the media record */
set_pool_dbr_defaults_in_media_dbr(mr, pr);
mr->VolBytes = 1; /* flag indicating Volume labeled */
+ mr->InChanger = 1;
if (db_create_media_record(ua->jcr, ua->db, mr)) {
bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
mr->VolumeName, mr->Slot);
return ok;
}
-static vol_list_t *get_slot_list_from_SD(UAContext *ua)
+static BSOCK *open_sd_bsock(UAContext *ua)
+{
+ STORE *store = ua->jcr->store;
+
+ if (!ua->jcr->store_bsock) {
+ bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
+ store->hdr.name, store->address, store->SDport);
+ if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+ bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+ return NULL;
+ }
+ }
+ return ua->jcr->store_bsock;
+}
+
+static void close_sd_bsock(UAContext *ua)
+{
+ if (ua->jcr->store_bsock) {
+ bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
+ bnet_close(ua->jcr->store_bsock);
+ ua->jcr->store_bsock = NULL;
+ }
+}
+
+static char *get_volume_name_from_SD(UAContext *ua, int Slot)
+{
+ STORE *store = ua->jcr->store;
+ BSOCK *sd;
+ char dev_name[MAX_NAME_LENGTH];
+ char *VolName = NULL;
+ int rtn_slot;
+
+ if (!(sd=open_sd_bsock(ua))) {
+ return NULL;
+ }
+ bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
+ bash_spaces(dev_name);
+ /* Ask for autochanger list of volumes */
+ bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
+ Dmsg1(100, "Sent: %s", sd->msg);
+
+ /* Get Volume name in this Slot */
+ while (bnet_recv(sd) >= 0) {
+ bsendmsg(ua, "%s", sd->msg);
+ if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
+ VolName = (char *)malloc(sd->msglen);
+ if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
+ break;
+ }
+ free(VolName);
+ VolName = NULL;
+ }
+ }
+ Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
+ return VolName;
+}
+
+/*
+ * We get the slot list from the Storage daemon.
+ * If scan is set, we return all slots found,
+ * otherwise, we return only slots with valid barcodes (Volume names)
+ */
+static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
{
STORE *store = ua->jcr->store;
char dev_name[MAX_NAME_LENGTH];
vol_list_t *vol_list = NULL;
- bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
- store->hdr.name, store->address, store->SDport);
- if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
- bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+ if (!(sd=open_sd_bsock(ua))) {
return NULL;
}
- sd = ua->jcr->store_bsock;
bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
bash_spaces(dev_name);
continue;
}
- /* Validate Slot:Barcode */
+ /* Validate Slot: if scanning, otherwise Slot:Barcode */
p = strchr(sd->msg, ':');
- if (p && strlen(p) > 1) {
- *p++ = 0;
- if (!is_an_integer(sd->msg)) {
+ if (scan && p) {
+ /* Scanning -- require only valid slot */
+ Slot = atoi(sd->msg);
+ if (Slot <= 0) {
+ p--;
+ *p = ':';
+ bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
continue;
}
} else {
- continue;
- }
- Slot = atoi(sd->msg);
- if (Slot <= 0 || !is_volume_name_legal(ua, p)) {
- continue;
+ /* Not scanning */
+ if (p && strlen(p) > 1) {
+ *p++ = 0;
+ if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
+ p--;
+ *p = ':';
+ bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
+ continue;
+ }
+ } else {
+ continue;
+ }
+ if (!is_volume_name_legal(ua, p)) {
+ p--;
+ *p = ':';
+ bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
+ continue;
+ }
}
/* Add Slot and VolumeName to list */
vl = (vol_list_t *)malloc(sizeof(vol_list_t));
vl->Slot = Slot;
- vl->VolName = bstrdup(p);
+ if (p) {
+ vl->VolName = bstrdup(p);
+ } else {
+ vl->VolName = NULL;
+ }
if (!vol_list) {
vl->next = vol_list;
vol_list = vl;
}
}
}
+ close_sd_bsock(ua);
return vol_list;
}
+static void free_vol_list(vol_list_t *vol_list)
+{
+ vol_list_t *vl;
+ /* Free list */
+ for (vl=vol_list; vl; ) {
+ vol_list_t *ovl;
+ if (vl->VolName) {
+ free(vl->VolName);
+ }
+ ovl = vl;
+ vl = vl->next;
+ free(ovl);
+ }
+}
+
+
/*
* Check if this is a cleaning tape by comparing the Volume name
* with the Cleaning Prefix. If they match, this is a cleaning
for (i=1; i<ua->argc; i++) {
if (use_default && !ua->argv[i]) {
+ /* Ignore scan and barcode(s) keywords */
+ if (strncasecmp("scan", ua->argk[i], 4) == 0 ||
+ strncasecmp("barcode", ua->argk[i], 7) == 0) {
+ continue;
+ }
/* Default argument is storage */
if (store_name) {
bsendmsg(ua, _("Storage name given twice.\n"));
return NULL;
}
- /* Ignore barcode(s) keywords */
- if (strncasecmp("barcode", ua->argk[i], 7) == 0) {
- continue;
- }
store_name = ua->argk[i];
if (*store_name == '?') {
*store_name = 0;
clean:
rm -f *.exe *.o *.res *.a 1 2 3
+ rm -f bin/smtp.exe bin/console.exe
rm -f bin/bacula-fd.exe bin/bsmtp.exe bin/testfind.exe
distclean: clean
if (!p) {
return 0;
}
- while (*p && *p == ' ') {
+ while (*p && B_ISSPACE(*p)) {
p++;
}
*msg = p;
if (!p) {
return 0;
}
- while (*p && *p != ' ') {
+ while (*p && !B_ISSPACE(*p)) {
p++;
}
*msg = p;
/*
- *
+ * Request to mount next Volume, which Volume not specified
+ *
* Entered with device blocked.
* Leaves with device blocked.
*
wait_sec = min_wait;
num_wait = 0;
/* If no VolumeName, and cannot get one, try again */
- if (jcr->VolumeName[0] == 0 &&
- !dir_find_next_appendable_volume(jcr) && !job_canceled(jcr)) {
+ if (jcr->VolumeName[0] == 0 && !job_canceled(jcr) &&
+ !dir_find_next_appendable_volume(jcr)) {
Jmsg(jcr, M_MOUNT, 0, _(
"Someone woke me up, but I cannot find any appendable\n\
volumes for Job=%s.\n"), jcr->Job);
}
/*
- *
+ * Request to mount specific Volume
+ *
* Entered with device blocked and jcr->VolumeName is desired
* volume.
* Leaves with device blocked.
Dmsg1(100, "Additional wait %d sec.\n", add_wait);
}
- dev->dev_blocked = dev_blocked;
+ dev->dev_blocked = dev_blocked; /* restore entry state */
V(dev->mutex);
return stat;
}
/* Forward referenced functions */
static int label_cmd(JCR *jcr);
static int relabel_cmd(JCR *jcr);
+static int readlabel_cmd(JCR *jcr);
static int release_cmd(JCR *jcr);
static int setdebug_cmd(JCR *jcr);
static int cancel_cmd(JCR *cjcr);
static int unmount_cmd(JCR *jcr);
static int autochanger_cmd(JCR *sjcr);
static int do_label(JCR *jcr, int relabel);
+static bool find_device(JCR *jcr, char *dname);
+static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot);
static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
char *newname, char *poolname,
int Slot, int relabel);
{"status", status_cmd},
{"autochanger", autochanger_cmd},
{"release", release_cmd},
+ {"readlabel", readlabel_cmd},
{NULL, NULL} /* list terminator */
};
{
POOLMEM *dname, *newname, *oldname, *poolname, *mtype;
BSOCK *dir = jcr->dir_bsock;
- DEVRES *device;
DEVICE *dev;
- int found = 0, ok = 0;
+ bool ok = false;
int slot;
dname = get_memory(dir->msglen+1);
if (relabel) {
if (sscanf(dir->msg, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d",
dname, oldname, newname, poolname, mtype, &slot) == 6) {
- ok = 1;
+ ok = true;
}
} else {
*oldname = 0;
if (sscanf(dir->msg, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
dname, newname, poolname, mtype, &slot) == 5) {
- ok = 1;
+ ok = true;
}
}
if (ok) {
- unbash_spaces(dname);
unbash_spaces(newname);
unbash_spaces(oldname);
unbash_spaces(poolname);
unbash_spaces(mtype);
- device = NULL;
- LockRes();
- while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
- /* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
- Dmsg1(20, "Found device %s\n", device->hdr.name);
- found = 1;
- break;
- }
- }
- UnlockRes();
- if (found) {
+ if (find_device(jcr, dname)) {
/******FIXME**** compare MediaTypes */
- jcr->device = device;
- dev = device->dev;
+ dev = jcr->device->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!(dev->state & ST_OPENED)) {
/* Ensure that the device is open -- autoload_device() closes it */
for ( ; !(dev->state & ST_OPENED); ) {
if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
- if (dev->dev_errno == EAGAIN || dev->dev_errno == EBUSY) {
- bmicrosleep(30, 0);
- }
bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"),
dev_name(dev), strerror_dev(dev));
goto bail_out;
}
pm_strcpy(&jcr->VolumeName, newname);
bnet_fsend(dir, _("3000 OK label. Volume=%s Device=%s\n"),
- newname, dev->dev_name);
+ newname, dev_name(dev));
break;
case VOL_NO_MEDIA:
bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev));
break;
default:
bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"),
- dev->dev_name, jcr->errmsg);
+ dev_name(dev), jcr->errmsg);
stat = 0;
break;
}
return stat;
}
+static bool find_device(JCR *jcr, char *dname)
+{
+ DEVRES *device = NULL;
+ bool found = false;
+
+ unbash_spaces(dname);
+ LockRes();
+ while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+ /* Find resource, and make sure we were able to open it */
+ if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
+ Dmsg1(20, "Found device %s\n", device->hdr.name);
+ jcr->device = device;
+ found = true;
+ break;
+ }
+ }
+ UnlockRes();
+ return found;
+}
+
+
/*
* Mount command from Director
*/
static int mount_cmd(JCR *jcr)
{
- POOLMEM *dev_name;
+ POOLMEM *dname;
BSOCK *dir = jcr->dir_bsock;
- DEVRES *device;
DEVICE *dev;
- int found = 0;
-
- dev_name = get_memory(dir->msglen+1);
- if (sscanf(dir->msg, "mount %s", dev_name) == 1) {
- unbash_spaces(dev_name);
- device = NULL;
- LockRes();
- while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
- /* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
- Dmsg1(20, "Found device %s\n", device->hdr.name);
- found = 1;
- break;
- }
- }
- UnlockRes();
- if (found) {
+
+ dname = get_memory(dir->msglen+1);
+ if (sscanf(dir->msg, "mount %s", dname) == 1) {
+ if (find_device(jcr, dname)) {
DEV_BLOCK *block;
- jcr->device = device;
- dev = device->dev;
+ dev = jcr->device->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
switch (dev->dev_blocked) { /* device blocked? */
case BST_WAITING_FOR_SYSOP:
/* Someone is waiting, wake him */
Dmsg0(100, "Waiting for mount. Attempting to wake thread\n");
dev->dev_blocked = BST_MOUNT;
- bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev->dev_name);
+ bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev_name(dev));
pthread_cond_signal(&dev->wait_next_vol);
break;
+ /* In both of these two cases, we (the user) unmounted the Volume */
case BST_UNMOUNTED_WAITING_FOR_SYSOP:
case BST_UNMOUNTED:
/* We freed the device, so reopen it and wake any waiting threads */
read_dev_volume_label(jcr, dev, block);
free_block(block);
if (dev->dev_blocked == BST_UNMOUNTED) {
+ /* We blocked the device, so unblock it */
Dmsg0(100, "Unmounted. Unblocking device\n");
- read_label(jcr, dev);
+ read_label(jcr, dev); /* this should not be necessary */
unblock_device(dev);
} else {
Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n");
}
if (dev_state(dev, ST_LABEL)) {
bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
- dev->dev_name, dev->VolHdr.VolName);
+ dev_name(dev), dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
- dev->dev_name);
+ dev_name(dev));
}
pthread_cond_signal(&dev->wait_next_vol);
break;
case BST_DOING_ACQUIRE:
bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"),
- dev->dev_name);
+ dev_name(dev));
break;
case BST_WRITING_LABEL:
- bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev->dev_name);
+ bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev_name(dev));
break;
case BST_NOT_BLOCKED:
if (dev_state(dev, ST_OPENED)) {
if (dev_state(dev, ST_LABEL)) {
bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
- dev->dev_name, dev->VolHdr.VolName);
+ dev_name(dev), dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
- dev->dev_name);
+ dev_name(dev));
}
} else {
if (!dev_is_tape(dev)) {
read_label(jcr, dev);
if (dev_state(dev, ST_LABEL)) {
bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
- dev->dev_name, dev->VolHdr.VolName);
+ dev_name(dev), dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
- dev->dev_name);
+ dev_name(dev));
}
}
break;
}
V(dev->mutex);
} else {
- bnet_fsend(dir, _("3999 Device %s not found\n"), dev_name);
+ bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
}
} else {
pm_strcpy(&jcr->errmsg, dir->msg);
bnet_fsend(dir, _("3909 Error scanning mount command: %s\n"), jcr->errmsg);
}
- free_memory(dev_name);
+ free_memory(dname);
bnet_sig(dir, BNET_EOD);
return 1;
}
{
POOLMEM *dname;
BSOCK *dir = jcr->dir_bsock;
- DEVRES *device;
DEVICE *dev;
- int found = 0;
dname = get_memory(dir->msglen+1);
if (sscanf(dir->msg, "unmount %s", dname) == 1) {
- unbash_spaces(dname);
- device = NULL;
- LockRes();
- while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
- /* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
- Dmsg1(20, "Found device %s\n", device->hdr.name);
- found = 1;
- break;
- }
- }
- UnlockRes();
- if (found) {
- jcr->device = device;
- dev = device->dev;
+ if (find_device(jcr, dname)) {
+ dev = jcr->device->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!(dev->state & ST_OPENED)) {
Dmsg0(90, "Device already unmounted\n");
bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev));
} else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
- bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"), dev_name(dev));
} else if (dev->dev_blocked == BST_WRITING_LABEL) {
- bnet_fsend(dir, _("3903 Device %s is being labeled.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev_name(dev));
} else if (dev_state(dev, ST_READ) || dev->num_writers) {
if (dev_state(dev, ST_READ)) {
Dmsg0(90, "Device in read mode\n");
- bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"), dev_name(dev));
} else {
Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
{
POOLMEM *dname;
BSOCK *dir = jcr->dir_bsock;
- DEVRES *device;
DEVICE *dev;
- int found = 0;
dname = get_memory(dir->msglen+1);
if (sscanf(dir->msg, "release %s", dname) == 1) {
- unbash_spaces(dname);
- device = NULL;
- LockRes();
- while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
- /* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
- Dmsg1(20, "Found device %s\n", device->hdr.name);
- found = 1;
- break;
- }
- }
- UnlockRes();
- if (found) {
- jcr->device = device;
- dev = device->dev;
+ if (find_device(jcr, dname)) {
+ dev = jcr->device->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!(dev->state & ST_OPENED)) {
Dmsg0(90, "Device already released\n");
bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), dev_name(dev));
} else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
- bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), dev_name(dev));
} else if (dev->dev_blocked == BST_WRITING_LABEL) {
- bnet_fsend(dir, _("3914 Device %s is being labeled.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), dev_name(dev));
} else if (dev_state(dev, ST_READ) || dev->num_writers) {
if (dev_state(dev, ST_READ)) {
Dmsg0(90, "Device in read mode\n");
- bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"), dev_name(dev));
} else {
Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"),
*/
static int autochanger_cmd(JCR *jcr)
{
- POOLMEM *devname;
+ POOLMEM *dname;
BSOCK *dir = jcr->dir_bsock;
- DEVRES *device;
DEVICE *dev;
- int found = 0;
-
- devname = get_memory(dir->msglen+1);
- if (sscanf(dir->msg, "autochanger list %s ", devname) == 1) {
- unbash_spaces(devname);
- device = NULL;
- LockRes();
- while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
- /* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, devname) == 0 && device->dev) {
- Dmsg1(20, "Found device %s\n", device->hdr.name);
- found = 1;
- break;
- }
- }
- UnlockRes();
- if (found) {
- jcr->device = device;
- dev = device->dev;
+
+ dname = get_memory(dir->msglen+1);
+ if (sscanf(dir->msg, "autochanger list %s ", dname) == 1) {
+ if (find_device(jcr, dname)) {
+ dev = jcr->device->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev_is_tape(dev)) {
- bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), dev_name(dev));
} else if (!(dev->state & ST_OPENED)) {
if (open_dev(dev, NULL, READ_WRITE) < 0) {
bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
autochanger_list(jcr, dev, dir);
} else if (dev_state(dev, ST_READ) || dev->num_writers) {
if (dev_state(dev, ST_READ)) {
- bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
- dev_name(dev));
+ bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"), dev_name(dev));
} else {
bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
dev_name(dev), dev->num_writers);
}
V(dev->mutex);
} else {
- bnet_fsend(dir, _("3999 Device %s not found\n"), devname);
+ bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
}
} else { /* error on scanf */
pm_strcpy(&jcr->errmsg, dir->msg);
bnet_fsend(dir, _("3908 Error scanning autocharger list command: %s\n"),
jcr->errmsg);
}
- free_memory(devname);
+ free_memory(dname);
bnet_sig(dir, BNET_EOD);
return 1;
}
+
+/*
+ * Read and return the Volume label
+ */
+static int readlabel_cmd(JCR *jcr)
+{
+ POOLMEM *dname;
+ BSOCK *dir = jcr->dir_bsock;
+ DEVICE *dev;
+ int Slot;
+
+ dname = get_memory(dir->msglen+1);
+ if (sscanf(dir->msg, "readlabel %s Slot=%d", dname, &Slot) == 2) {
+ if (find_device(jcr, dname)) {
+ dev = jcr->device->dev;
+
+ P(dev->mutex); /* Use P to avoid indefinite block */
+ if (!(dev->state & ST_OPENED)) {
+ if (open_dev(dev, NULL, READ_WRITE) < 0) {
+ bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
+ } else {
+ read_volume_label(jcr, dev, Slot);
+ force_close_dev(dev);
+ }
+ /* Under certain "safe" conditions, we can steal the lock */
+ } else if (dev->dev_blocked &&
+ (dev->dev_blocked == BST_UNMOUNTED ||
+ dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
+ dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
+ read_volume_label(jcr, dev, Slot);
+ } else if (dev_state(dev, ST_READ) || dev->num_writers) {
+ if (dev_state(dev, ST_READ)) {
+ bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"),
+ dev_name(dev));
+ } else {
+ bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
+ dev_name(dev), dev->num_writers);
+ }
+ } else { /* device not being used */
+ read_volume_label(jcr, dev, Slot);
+ }
+ V(dev->mutex);
+ } else {
+ bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
+ }
+ } else {
+ pm_strcpy(&jcr->errmsg, dir->msg);
+ bnet_fsend(dir, _("3909 Error scanning readlabel command: %s\n"), jcr->errmsg);
+ }
+ free_memory(dname);
+ bnet_sig(dir, BNET_EOD);
+ return 1;
+}
+
+/*
+ * Read the tape label
+ *
+ * Enter with the mutex set
+ */
+static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot)
+{
+ BSOCK *dir = jcr->dir_bsock;
+ DEV_BLOCK *block;
+ bsteal_lock_t hold;
+
+ steal_device_lock(dev, &hold, BST_WRITING_LABEL);
+
+ jcr->VolumeName[0] = 0;
+ jcr->VolCatInfo.Slot = Slot;
+ autoload_device(jcr, dev, 0, dir); /* autoload if possible */
+ block = new_block(dev);
+
+ /* Ensure that the device is open -- autoload_device() closes it */
+ for ( ; !(dev->state & ST_OPENED); ) {
+ if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
+ bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"),
+ dev_name(dev), strerror_dev(dev));
+ goto bail_out;
+ }
+ }
+
+ dev->state &= ~ST_LABEL; /* force read of label */
+ switch (read_dev_volume_label(jcr, dev, block)) {
+ case VOL_OK:
+ bnet_fsend(dir, _("3001 Volume=%s Slot=%d\n"), dev->VolHdr.VolName, Slot);
+ Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolName);
+ break;
+ default:
+ bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"),
+ dev_name(dev), jcr->errmsg);
+ break;
+ }
+
+bail_out:
+ free_block(block);
+ give_back_device_lock(dev, &hold);
+ return;
+}
.c.o:
$(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
#-------------------------------------------------------------------------
-all: Makefile bsmtp dbcheck testfind testls hammer
+all: Makefile bsmtp dbcheck testfind testls
@echo "==== Make of tools is good ===="
@echo " "
#undef VERSION
#define VERSION "1.33"
#define VSTRING "1"
-#define BDATE "14 Nov 2003"
-#define LSMDATE "14Nov03"
+#define BDATE "18 Nov 2003"
+#define LSMDATE "18Nov03"
/* Debug flags */
#undef DEBUG