From 3b0d6cc5142902295226a78e931a73ffa1c3d1a7 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 10 Oct 2005 14:15:00 +0000 Subject: [PATCH] - Add Arno's dvd-handler script to the scripts directory and integrate with configure. It replaces both existing scripts. - Make default schedule start at 23:10 - Implement gui release in Makefile. It creates two .tar.gz bacula-web and bimagemgr. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2429 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/autoconf/configure.in | 1 + bacula/configure | 3 +- bacula/kernstodo | 21 +- bacula/kes-1.37 | 6 + bacula/scripts/dvd-handler.in | 333 +++++++++++++++++++++++++++++ bacula/src/dird/bacula-dir.conf.in | 8 +- bacula/src/version.h | 4 +- 7 files changed, 359 insertions(+), 17 deletions(-) create mode 100644 bacula/scripts/dvd-handler.in diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index 5aea1cf665..693c8e718f 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -1908,6 +1908,7 @@ AC_OUTPUT([autoconf/Make.common \ scripts/mtx-changer \ scripts/dvd-writepart \ scripts/dvd-freespace \ + scripts/dvd-handler \ scripts/bacula-tray-monitor.desktop \ scripts/logwatch/Makefile \ scripts/logwatch/logfile.bacula.conf \ diff --git a/bacula/configure b/bacula/configure index e4af2eaa63..dba26a5d57 100755 --- a/bacula/configure +++ b/bacula/configure @@ -29506,7 +29506,7 @@ if test "x${subsysdir}" = "x${sbindir}" ; then exit 1 fi - ac_config_files="$ac_config_files autoconf/Make.common Makefile scripts/startmysql scripts/stopmysql scripts/btraceback scripts/startit scripts/stopit scripts/bconsole scripts/gconsole scripts/bacula scripts/devel_bacula scripts/Makefile scripts/logrotate scripts/bacula.desktop.gnome1 scripts/bacula.desktop.gnome2 scripts/bacula.desktop.gnome1.consolehelper scripts/bacula.desktop.gnome2.consolehelper scripts/bacula.desktop.gnome1.xsu scripts/bacula.desktop.gnome2.xsu scripts/gnome-console.console_apps scripts/mtx-changer scripts/dvd-writepart scripts/dvd-freespace 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/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/dvd-writepart scripts/dvd-freespace 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/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 @@ -30072,6 +30072,7 @@ do "scripts/mtx-changer" ) CONFIG_FILES="$CONFIG_FILES scripts/mtx-changer" ;; "scripts/dvd-writepart" ) CONFIG_FILES="$CONFIG_FILES scripts/dvd-writepart" ;; "scripts/dvd-freespace" ) CONFIG_FILES="$CONFIG_FILES scripts/dvd-freespace" ;; + "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" ;; "scripts/logwatch/logfile.bacula.conf" ) CONFIG_FILES="$CONFIG_FILES scripts/logwatch/logfile.bacula.conf" ;; diff --git a/bacula/kernstodo b/bacula/kernstodo index 8da1f16093..a74f4dfd4f 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 01 October 2005 + 10 October 2005 Major development: Project Developer @@ -9,9 +9,7 @@ Version 1.37 Kern (see below) Final items for 1.37 before release: 1. Fix bugs -- Look at fixing restore status stats in SD. - Mount after manually unloading changer causes hang in SD -- Close STDOUT if debug_level == 0 - Check if ANSI tape labeling works with drive in read-only mode. > > btape: label.c:299 write_volume_label() @@ -40,16 +38,9 @@ Final items for 1.37 before release: non-bacula tape in the drive. - --without-openssl breaks at least on Solaris. -- Figure out how to package gui, and rescue programs. - Arno had to do -- to get update slots=x to work UPDATE Media SET InChanger=0,Slot=0 WHERE InChanger>0 AND Slot>0; (MySQL) -- Add recycle event. -- Add scratch pool event. -- Implement NeedVolume event -- Add Win32 FileSet definition somewhere - - Document: - Does ClientRunAfterJob fail the job on a bad return code? - Document cleaning up the spool files: @@ -59,6 +50,14 @@ Document: - Does WildFile match against full name? Doc. For 1.39: +- Close STDOUT if debug_level == 0 +- Add recycle event. +- Add scratch pool event. +- Implement NeedVolume event +- Add Win32 FileSet definition somewhere +- Look at fixing restore status stats in SD. +- Make selection of Database used in restore correspond to + client. - implement a mode that says when a hard read error is encountered, read many times (as it currently does), and if the block cannot be read, skip to the next block, and try again. If @@ -1494,3 +1493,5 @@ Block Position: 0 wants a Volume that is released but in another drive -- chaos. - Run the regression scripts on Solaris and FreeBSD +- Figure out how to package gui, and rescue programs. + diff --git a/bacula/kes-1.37 b/bacula/kes-1.37 index ff59da48c2..dc06ad95f8 100644 --- a/bacula/kes-1.37 +++ b/bacula/kes-1.37 @@ -4,6 +4,12 @@ General: Changes to 1.37.41: +10Oct05 +- Add Arno's dvd-handler script to the scripts directory and + integrate with configure. It replaces both existing scripts. +- Make default schedule start at 23:10 +- Implement gui release in Makefile. It creates two .tar.gz + bacula-web and bimagemgr. 08Oct05 - Add README plus tar release to gui project. - Manual documentation diff --git a/bacula/scripts/dvd-handler.in b/bacula/scripts/dvd-handler.in new file mode 100644 index 0000000000..e25893284a --- /dev/null +++ b/bacula/scripts/dvd-handler.in @@ -0,0 +1,333 @@ +#!/usr/bin/python +# +# Check the free space available on a writable DVD +# Should always exit with 0 status, otherwise it indicates a serious error. +# (wrong number of arguments, Python exception...) +# +# called: dvd-handler operation args +# +# where operation is one of +# free +# write +# +# further arguments: +# free: one argument: 0 to keep the existing data on disk, i.e. +# free space is measured +# anything else: overwrite entire disk, so +# free space is always maximum space +# +# in case of operation ``free'' returns: +# Prints on the first output line the free space available in bytes. +# If an error occurs, prints a negative number (-errno), followed, +# on the second line, by an error message. +# +# $Id$ +# + +# end of configurable values + +import popen2 +import os +import errno +import sys +import re +import signal +import time + +class disk: + # Configurable values: + df = "@DF@ -P" + dvdrwmediainfo = "@DVDRWMEDIAINFO@" + growisofs = "@GROWISOFS@" + margin = 10485760 # 10 mb security margin + # We disable 4GB boundary checking - function free should handle this + # already, and it doesn't seem to work anyway (here: 2.6.8-24.18 from SuSE, + # LG GSA-5163D, dvd+rw-tools 5.21 + growcmd = growisofs + " -use-the-force-luke=notray -use-the-force-luke=4gms " + growcmd += "-A 'Bacula Data' -input-charset=default -iso-level 3 -pad " + \ + "-publisher 'ITS Lehmann info@its-lehmann.de' " + \ + "-p 'dvd-handler / growisofs' -sysid 'BACULADATA'" + +############################################################################### +# +# This class represents a DVD disk (various flavours). +# When instantiated, it needs a device name. +# Status information about the device and the disk loaded is collected. +# +# The following methods are implemented: +# __init__ we need that... +# NOTE: Currently, this class only works with DVD+RW +# and simply refuses to work with anything else. +# This is because I had to start with some sort of disk, +# and I learned that +RW and -RW are quite different, so +# I decided to play it safe. +# __repr__ this seems to be a good idea to have. +# Quite minimalistic implementation, though. +# __str__ For casts to string. Return the current disk information +# is_empty Returns TRUE if the disk is empty, blank... this needs more +# work, especially concerning non-RW media and blank vs. no +# filesystem considerations. Here, we should also look for +# other filesystems - probably we don't want to silently +# overwrite UDF or ext2 or anything not mentioned in fstab... +# is_RW TRUE if disk is rewritable. We need that to determine if +# a new filesystem can be written onto a used disk. +# lasterr returns a string describing the last error in the class. +# Valuable after creating the object and after free() +# free Returns the available free space, distinguishing between +# new volume disks (overwrite everything) and appending +# There are some assumtions about disk status and usage that +# need work. +# write Writes one part file to disk, either starting a new file +# system on disk, or appending to it. +# This method should also prepare a blank disk so that a +# certain part of the disk is used to allow detection of a +# used disk by all / more disk drives. +# blank NOT IMPLEMENTED +# +############################################################################### + def __init__(self, devicename): + self.device = "none" + self.disktype = "none" + self.leadout = -1 + self.track = -1 + self.maximum = -1 + self.used = 0 + self.lasterror = "none" + self.hardwaredevice = "none" + self.pid = 0 + + # first, we collect information about the media as reported by + # dvd+rw-mediainfo + # we need an indication of the usable total size. + + self.cmd = self.dvdrwmediainfo + " " + devicename + self.processi = popen2.Popen4(self.cmd) + self.status = self.processi.wait() + if not os.WIFEXITED(self.status): + self.lasterror = self.dvdrwmediainfo + " process did not exit correctly." + return + if os.WEXITSTATUS(self.status) != 0: + self.lasterror = "Cannot get media info from " + self.dvdrwmediainfo + return + self.device = str(devicename) + self.result = self.processi.fromchild.read() + self.hardware = re.search(r"INQUIRY:\s+(.*)\n", self.result, re.MULTILINE) + self.mediatype = re.search(r"\sMounted Media:\s+([0-9A-F]{2})h, (\S*)\s", + self.result, re.MULTILINE) + self.tracksize = re.search(r"\sTrack Size:\s+(\d+)\*2KB\s", + self.result, re.MULTILINE) + self.leadout = re.search(r"\sLegacy lead-out at:\s+(\d+)\*2KB=(\d+)\s", + self.result, re.MULTILINE) + if self.hardware: + self.hardwaredevice = self.hardware.group(1) + if self.mediatype: + self.disktype = self.mediatype.group(2) + else: + self.lasterror = "Media type not found." + if self.leadout: + self.leadout = long(self.leadout.group(1))*2048 + else: + self.lasterror = "Lead-out block not found." + if self.tracksize: + self.track = long(self.tracksize.group(1))*2048 + else: + self.lasterror = "Track size not found." + self.result = 0 + if ( "DVD+RW" == self.disktype ): + if self.leadout > self.track: + self.result = self.leadout + else: + self.result = self.track + else: + self.lasterror = "Unsupported media: " + self.disktype + self.maximum = self.result - self.margin + if self.maximum < 0: + self.maximum = 0 + + # now, the actual size used on the disk. + # here, we use what df reports, although the + # current track size should give us the necessary information, + # too. Well, depending on the media type, it seems. + # We should see if the media is mounted, try to mount, if possible + # proceed and, if necessary, unmount. Otherwise assume 0 used bytes. + # __init__ and __del__ would be the right places to mount and + # unmount - mounting before df'ing is always a good idea, + # and setting the previos state might be important. + + self.cmd = self.df + " " + self.device + self.process = popen2.Popen4(self.cmd) + self.status = self.process.wait() + if not os.WIFEXITED(self.status): + self.lasterror = self.df + " process did not not exit correctly." + return + self.exitstat = os.WEXITSTATUS(self.status) & ~0x80 + if self.exitstat == errno.ENOSPC: + self.used = 0 + elif self.exitstat != 0: + self.lasterror = os.strerror(self.exitstat) + return + self.dftext = self.process.fromchild.read() + self.blocks = re.search(self.device + r"\s+(\d+)\s+", + self.dftext, re.MULTILINE) + if self.blocks: + self.used = long(self.blocks.group(1))*1024 + else: + self.used = 0 + self.lasterror = "No blocks found in " + self.cmd + " output:\n" + self.lasterror += self.dftext + return + + def __repr__(self): + return "disk(" + self.device + ") # This is an instance of class disk" + + def __str__(self): + self.me = "Class disk, initialized with device " + self.device + "\n" + self.me += "type = " + self.disktype + " leadout = " + str(self.leadout) + self.me += " track = " + str(self.track) + " maximum = " + str(self.maximum) + "\n" + self.me += "used = " + str(self.used) + "\n" + self.me += "Hardware device is " + self.hardwaredevice + "\n" + self.me += "last error = " + self.lasterror + "\n" + return self.me + + def is_empty(self): + return 0 == self.used + # This works for DVD+RW, probably for all rewritable media. self.blank for -R? + # This is quite definitely not the best method. I need something + # that detects if a session exists on disk, but I didn't do any + # experiments with non-RW media yet. + + def is_RW(self): + return "DVD-RW" == self.disktype or "DVD+RW" == self.disktype or "DVD-RAM" == self.disktype + + def free(self, newvol): + if self.used < 0 or self.maximum <= 0: + return -1 + elif newvol: + self.ret = self.maximum + if not self.is_empty() and not self.is_RW(): + # better check real disks usage state as read from dvd+rw-mediainfo. + # introduce self.blank + self.ret = -1 + self.lasterror = self.disktype + " can not be overwritten and is already used" + else: + self.ret = self.maximum - self.used + if self.used > 4278190080: # if more than 4GB-16MB are already used + self.ret = 0 + return self.ret + + def lasterr(self): + return self.lasterror + + def term_handler(self, signum, frame): + print 'dvd-handler: Signal term_handler called with signal', signum + if self.pid != 0: + print "dvd-handler: Sending SIGTERM to pid", self.pid + os.kill(self.pid, signal.SIGTERM) + time.sleep(10) + print "dvd-handler: Sending SIGKILL to pid", self.pid + os.kill(self.pid, signal.SIGKILL) + sys.exit(1) + + def write(self, newvol, partfile): + self.lasterror = "none" + self.partstat = os.stat(partfile) + if not self.partstat: + self.lasterror = "Could not stat " + str(partfile) + " which is a fatal error." + return + if self.partstat.st_size > self.free(newvol): + self.lasterror = "Part " + str(partfile) + " is too big: " \ + + str(self.partstat.st_size) + ", free " + str(self.free(newvol)) + return + if "DVD-RW" == self.disktype: + self.cmd = self.growcmd + " -R " + if newvol: + self.cmd += "-Z " + else: + self.cmd += "-M " + self.cmd += self.device + " " + str(partfile) + self.oldsig = signal.signal(signal.SIGTERM, self.term_handler) + self.proc = popen2.Popen4(self.cmd) + self.pid = self.proc.pid + self.status = self.proc.poll() + while -1 == self.status: + self.out = self.proc.fromchild.read(512) + while "" != self.out: + sys.stdout.write(self.out) + self.out = self.proc.fromchild.read(512) + time.sleep(1) + self.status = self.proc.poll() + self.pid = 0 + print + signal.signal(signal.SIGTERM, self.oldsig) + if 0 != os.WEXITSTATUS(self.status): + self.lasterror = self.cmd + " exited with status " + str(os.WEXITSTATUS(self.status)) + print self.cmd + " exited with signal/status " + hex(self.status) + else: # Other disk type + self.lasterror = "Can't write to " + self.disktype +# class disk ends here. + + +if len(sys.argv) < 3: + print "Wrong number of arguments." + print """ +This program needs to be called with the following parameters. + +device operation [more arguments] + +where device is a device name like /dev/sr0 or /dev/dvd and +operation can be "test", "free" or "write". + +Operations: +test Scan the device and report the information found. + This operation needs no further arguments. +free Scan the device and report the available space. + "free" needs one additional argument to determine + if data is to be appended or if the disk will be + started from the beginning: "0" means append, + everything else indicates a new volume. +write Write a part file to disk. + This operation needs two additional arguments. + The first indicates to append or restart the + disk; see above. The second is the file to write. +""" + sys.exit(1) + +dvd = disk(sys.argv[1]) + +if "free" == sys.argv[2]: + if len(sys.argv) == 4: + newvol = 1 + if "0" == sys.argv[3]: + newvol = 0 + free = dvd.free(newvol) + print free + if free >= 0: + print "No Error reported." + else: + print dvd.lasterr() + else: + print "Wrong number of arguments." + sys.exit(1) +elif "test" == sys.argv[2]: + print str(dvd) + print "Empty disk: " + str(dvd.is_empty()) + " ReWritable disk: " + str(dvd.is_RW()) + print "Free for new volume: " + str(dvd.free(1)) + print "Free for append: " + str(dvd.free(0)) +elif "write" == sys.argv[2]: + if len(sys.argv) == 5: + newvol = 1 + if "0" == sys.argv[3]: + newvol = 0 + dvd.write(newvol, sys.argv[4]) + if "none" != dvd.lasterr(): + print str(dvd.lasterr()) + sys.exit(1) + else: + print "Part file " + sys.argv[4] + " successfully written to disk." + else: + print "Wrong number of arguments." + sys.exit(1) +else: + print "No operation - use test, free or write." + print "THIS MIGHT BE A CASE OF DEBUGGING BACULA OR AN ERROR!" +sys.exit(0) diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in index 33db255b72..6b9283ea7b 100644 --- a/bacula/src/dird/bacula-dir.conf.in +++ b/bacula/src/dird/bacula-dir.conf.in @@ -126,15 +126,15 @@ FileSet { # and incremental backups other days Schedule { Name = "WeeklyCycle" - Run = Full 1st sun at 1:05 - Run = Differential 2nd-5th sun at 1:05 - Run = Incremental mon-sat at 1:05 + Run = Full 1st sun at 23:05 + Run = Differential 2nd-5th sun at 23:05 + Run = Incremental mon-sat at 23:05 } # This schedule does the catalog. It starts after the WeeklyCycle Schedule { Name = "WeeklyCycleAfterBackup" - Run = Full sun-sat at 1:10 + Run = Full sun-sat at 23:10 } # This is the backup of the catalog diff --git a/bacula/src/version.h b/bacula/src/version.h index 5b54e5a374..726541a078 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "1.37.41" -#define BDATE "08 October 2005" -#define LSMDATE "08Oct05" +#define BDATE "10 October 2005" +#define LSMDATE "10Oct05" /* Debug flags */ #undef DEBUG -- 2.39.5