From: Kern Sibbald Date: Sat, 26 Jun 2004 12:51:12 +0000 (+0000) Subject: Rewrite spool error cod + level keyword for estimate X-Git-Tag: Release-1.35.1~88 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=53aebe54b9d45bae0c2e84593d71bb488ada8254;p=bacula%2Fbacula Rewrite spool error cod + level keyword for estimate git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1446 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/autoconf/aclocal.m4 b/bacula/autoconf/aclocal.m4 index 8a804a2bcf..b183570d6f 100644 --- a/bacula/autoconf/aclocal.m4 +++ b/bacula/autoconf/aclocal.m4 @@ -310,6 +310,9 @@ then elif test -f /etc/mandrake-release then DISTNAME=mandrake +elif test -f /etc/whitebox-release +then + DISTNAME=redhat elif test -f /etc/redhat-release then DISTNAME=redhat diff --git a/bacula/autoconf/config.guess b/bacula/autoconf/config.guess index 2fc3acce2e..670f24bd8d 100755 --- a/bacula/autoconf/config.guess +++ b/bacula/autoconf/config.guess @@ -12,7 +12,7 @@ timestamp='2003-06-17' # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License @@ -43,7 +43,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: - -h, --help print this help, then exit + -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -73,7 +73,7 @@ while test $# -gt 0 ; do echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - - ) # Use stdin as input. + - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 @@ -111,7 +111,7 @@ trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; + ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; @@ -121,8 +121,8 @@ case $CC_FOR_BUILD,$HOST_CC,$CC in CC_FOR_BUILD=no_compiler_found ; fi ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. @@ -137,7 +137,9 @@ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown ## for Red Hat Linux -if test -f /etc/redhat-release ; then +if test -f /etc/whitebox-release ; then + VENDOR=redhat ; +elif test -f /etc/redhat-release ; then VENDOR=redhat ; else VENDOR= ; @@ -156,7 +158,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # object file format. # # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". + # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` @@ -183,7 +185,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -248,7 +250,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that + # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` @@ -384,28 +386,28 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally + # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; + exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit 0 ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit 0 ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit 0 ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; @@ -471,8 +473,8 @@ EOF echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ @@ -485,8 +487,8 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit 0 ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) @@ -504,7 +506,7 @@ EOF exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; @@ -558,9 +560,9 @@ EOF ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit 0 ;; # report: romp-ibm BSD 4.3 + exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; @@ -576,57 +578,57 @@ EOF 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + sed 's/^ //' << EOF >$dummy.c - #define _HPUX_SOURCE - #include - #include + #define _HPUX_SOURCE + #include + #include - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa @@ -659,7 +661,7 @@ EOF long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ + results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) @@ -706,22 +708,22 @@ EOF exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit 0 ;; + exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit 0 ;; + exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit 0 ;; + exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit 0 ;; + exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit 0 ;; + exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; @@ -745,10 +747,10 @@ EOF exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit 0 ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; @@ -866,14 +868,14 @@ EOF exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; + EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; + EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; - esac + esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} @@ -883,7 +885,7 @@ EOF case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) @@ -893,7 +895,7 @@ EOF echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu exit 0 ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -911,11 +913,11 @@ EOF # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g + s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` - case "$ld_supported_targets" in + case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; @@ -964,11 +966,11 @@ EOF echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) @@ -1024,10 +1026,10 @@ EOF exit 0 ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp - exit 0 ;; + exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; @@ -1062,8 +1064,8 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4 && exit 0 ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; @@ -1097,9 +1099,9 @@ EOF fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit 0 ;; + # says + echo i586-unisys-sysv4 + exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm @@ -1121,11 +1123,11 @@ EOF exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit 0 ;; + exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; @@ -1210,7 +1212,7 @@ EOF echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; esac @@ -1234,11 +1236,11 @@ main () #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else "" #endif - ); exit (0); + ); exit (0); #endif #endif @@ -1386,12 +1388,12 @@ uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index 7818f6e74e..1c32b035ed 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -1477,9 +1477,14 @@ openbsd) platforms/openbsd/bacula-dir" ;; redhat) - if test `cat /etc/redhat-release | grep release |\ + if test -f /etc/whitebox-release ; then + f=/etc/whitebox-release + else + f=/etc/redhat-release + fi + if test `cat $f | grep release |\ cut -f 3 -d ' '`x = "Enterprise"x ; then - DISTVER="Enterprise "`cat /etc/redhat-release | grep release |\ + DISTVER="Enterprise "`cat $f | grep release |\ cut -f 6 -d ' '` else DISTVER=`cat /etc/redhat-release | grep release |\ diff --git a/bacula/configure b/bacula/configure index a445d54ecf..a1efe89302 100755 --- a/bacula/configure +++ b/bacula/configure @@ -4177,6 +4177,9 @@ then elif test -f /etc/mandrake-release then DISTNAME=mandrake +elif test -f /etc/whitebox-release +then + DISTNAME=redhat elif test -f /etc/redhat-release then DISTNAME=redhat @@ -18236,9 +18239,14 @@ openbsd) platforms/openbsd/bacula-dir" ;; redhat) - if test `cat /etc/redhat-release | grep release |\ + if test -f /etc/whitebox-release ; then + f=/etc/whitebox-release + else + f=/etc/redhat-release + fi + if test `cat $f | grep release |\ cut -f 3 -d ' '`x = "Enterprise"x ; then - DISTVER="Enterprise "`cat /etc/redhat-release | grep release |\ + DISTVER="Enterprise "`cat $f | grep release |\ cut -f 6 -d ' '` else DISTVER=`cat /etc/redhat-release | grep release |\ diff --git a/bacula/kernstodo b/bacula/kernstodo index 72acdfa69c..95e10108c6 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,9 +1,7 @@ Kern's ToDo List - 20 June 2004 + 26 June 2004 1.35 Items to do: -- Implement second cut of SIGHUP in Dir - (Implement resources on a single pointer) - Make btape release the drive during the "test" append. - Do tape alerts -- see tapealert.txt - Revisit and revise Disaster Recovery (fix SCSI and RAID @@ -24,7 +22,9 @@ jobs do. - Add regular expressions to FileSets. - Perhaps add read/write programs and/or plugins to FileSets. - +- Look at adding Client run command that will use the + port opened by the client. +- Test new I/O error despooling code. Documentation to do: (any release a little bit at a time) - Document query file format. @@ -1083,3 +1083,7 @@ Block Position: 0 - Implement fast tree insert (doubly linked list?) - Disallow using Internal database - Feedback while the tree is being built. +- Add detection of Whitebox +- Add InChanger to "list media" +- Implement second cut of SIGHUP in Dir + (Implement resources on a single pointer) diff --git a/bacula/scripts/mtx-changer.in b/bacula/scripts/mtx-changer.in index 6f237800c7..e1c0d4a98b 100644 --- a/bacula/scripts/mtx-changer.in +++ b/bacula/scripts/mtx-changer.in @@ -29,6 +29,15 @@ MTX=@MTX@ +# +# The purpose of this function to wait a maximum +# time for the drive. It will +# return as soon as the drive is ready, or after +# waiting a maximum of 180 seconds. +# Note, this is very system dependent, so if you are +# not running on Linux, you will probably need to +# re-write it. +# wait_for_drive() { for i in $(seq 180); do # Wait max 180 seconds if mt -f $1 status >/dev/null 2>&1; then diff --git a/bacula/src/cats/bdb_find.c b/bacula/src/cats/bdb_find.c index eed75e9b13..4d43cdfa96 100644 --- a/bacula/src/cats/bdb_find.c +++ b/bacula/src/cats/bdb_find.c @@ -97,13 +97,13 @@ StartTime=%100s", &JobId, Name, cType, cLevel, StartTime) == 5) { unbash_spaces(StartTime); Dmsg4(200, "Got Type=%c Level=%c Name=%s StartTime=%s\n", Type, Level, Name, StartTime); - Dmsg3(200, "Want Type=%c Level=%c Name=%s\n", jr->Type, jr->Level, + Dmsg3(200, "Want Type=%c Level=%c Name=%s\n", jr->JobType, jr->JobLevel, jr->Name); /* Differential is since last Full backup */ /* Incremental is since last FULL or Incremental or Differential */ - if (((jr->Level == L_DIFFERENTIAL) && (Type == jr->Type && + if (((jr->JobLevel == L_DIFFERENTIAL) && (Type == jr->JobType && Level == L_FULL && strcmp(Name, jr->Name) == 0)) || - ((jr->Level == L_INCREMENTAL) && (Type == jr->Type && + ((jr->JobLevel == L_INCREMENTAL) && (Type == jr->JobType && (Level == L_FULL || Level == L_INCREMENTAL || Level == L_DIFFERENTIAL) && strcmp(Name, jr->Name) == 0))) { addr = ftell(mdb->jobfd); /* save current location */ diff --git a/bacula/src/cats/bdb_update.c b/bacula/src/cats/bdb_update.c index cfba217730..4d60965d64 100755 --- a/bacula/src/cats/bdb_update.c +++ b/bacula/src/cats/bdb_update.c @@ -61,7 +61,7 @@ * most current start fields to the job record. * It is assumed that you did a db_create_job_record() already. */ -int db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) +bool db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { int len, stat = 1; JOB_DBR ojr; diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 88e49f90f1..a2fa2779aa 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -383,12 +383,12 @@ struct JOB_DBR { JobId_t JobId; char Job[MAX_NAME_LENGTH]; /* Job unique name */ char Name[MAX_NAME_LENGTH]; /* Job base name */ - int Type; /* actually char(1) */ - int Level; /* actually char(1) */ + int JobType; /* actually char(1) */ + int JobLevel; /* actually char(1) */ int JobStatus; /* actually char(1) */ - uint32_t ClientId; /* Id of client */ - uint32_t PoolId; /* Id of pool */ - uint32_t FileSetId; /* Id of FileSet */ + DBId_t ClientId; /* Id of client */ + DBId_t PoolId; /* Id of pool */ + DBId_t FileSetId; /* Id of FileSet */ time_t SchedTime; /* Time job scheduled */ time_t StartTime; /* Job start time */ time_t EndTime; /* Job termination time */ @@ -422,9 +422,9 @@ struct JOB_DBR { */ /* JobMedia record */ struct JOBMEDIA_DBR { - uint32_t JobMediaId; /* record id */ + DBId_t JobMediaId; /* record id */ JobId_t JobId; /* JobId */ - uint32_t MediaId; /* MediaId */ + DBId_t MediaId; /* MediaId */ uint32_t FirstIndex; /* First index this Volume */ uint32_t LastIndex; /* Last index this Volume */ uint32_t StartFile; /* File for start of data */ @@ -458,9 +458,9 @@ struct ATTR_DBR { uint32_t FileIndex; uint32_t Stream; JobId_t JobId; - uint32_t ClientId; - uint32_t PathId; - uint32_t FilenameId; + DBId_t ClientId; + DBId_t PathId; + DBId_t FilenameId; FileId_t FileId; }; @@ -470,8 +470,8 @@ struct FILE_DBR { FileId_t FileId; uint32_t FileIndex; JobId_t JobId; - uint32_t FilenameId; - uint32_t PathId; + DBId_t FilenameId; + DBId_t PathId; JobId_t MarkId; char LStat[256]; /* int Status; */ @@ -481,7 +481,7 @@ struct FILE_DBR { /* Pool record -- same format as database */ struct POOL_DBR { - uint32_t PoolId; + DBId_t PoolId; char Name[MAX_NAME_LENGTH]; /* Pool name */ uint32_t NumVols; /* total number of volumes */ uint32_t MaxVols; /* max allowed volumes */ @@ -503,10 +503,10 @@ struct POOL_DBR { /* Media record -- same as the database */ struct MEDIA_DBR { - uint32_t MediaId; /* Unique volume id */ + DBId_t MediaId; /* Unique volume id */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char MediaType[MAX_NAME_LENGTH]; /* Media type */ - uint32_t PoolId; /* Pool id */ + DBId_t PoolId; /* Pool id */ time_t FirstWritten; /* Time Volume first written */ time_t LastWritten; /* Time Volume last written */ time_t LabelDate; /* Date/Time Volume labeled */ @@ -542,7 +542,7 @@ struct MEDIA_DBR { /* Client record -- same as the database */ struct CLIENT_DBR { - uint32_t ClientId; /* Unique Client id */ + DBId_t ClientId; /* Unique Client id */ int AutoPrune; utime_t FileRetention; utime_t JobRetention; @@ -562,7 +562,7 @@ struct COUNTER_DBR { /* FileSet record -- same as the database */ struct FILESET_DBR { - uint32_t FileSetId; /* Unique FileSet id */ + DBId_t FileSetId; /* Unique FileSet id */ char FileSet[MAX_NAME_LENGTH]; /* FileSet name */ char MD5[50]; /* MD5 signature of include/exclude */ time_t CreateTime; /* date created */ diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index dc6e5ef6dc..ef5d6ade11 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -97,7 +97,7 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); /* update.c */ -int db_update_job_start_record(JCR *jcr, B_DB *db, JOB_DBR *jr); +bool db_update_job_start_record(JCR *jcr, B_DB *db, JOB_DBR *jr); int db_update_job_end_record(JCR *jcr, B_DB *db, JOB_DBR *jr); int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr); int db_update_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pr); diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 2d2a38c81b..cf5da1558e 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -85,7 +85,7 @@ db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) Mmsg(&mdb->cmd, "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate) VALUES \ ('%s','%s','%c','%c','%c','%s',%s)", - jr->Job, jr->Name, (char)(jr->Type), (char)(jr->Level), + jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel), (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1)); if (!INSERT_DB(jcr, mdb, mdb->cmd)) { diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 66229bd256..31dd629a4a 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -76,13 +76,13 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) "SELECT StartTime FROM Job WHERE JobStatus='T' AND Type='%c' AND " "Level='%c' AND Name='%s' AND ClientId=%u AND FileSetId=%u " "ORDER BY StartTime DESC LIMIT 1", - jr->Type, L_FULL, jr->Name, jr->ClientId, jr->FileSetId); + jr->JobType, L_FULL, jr->Name, jr->ClientId, jr->FileSetId); - if (jr->Level == L_DIFFERENTIAL) { + if (jr->JobLevel == L_DIFFERENTIAL) { /* SQL cmd for Differential backup already edited above */ /* Incremental is since last Full, Incremental, or Differential */ - } else if (jr->Level == L_INCREMENTAL) { + } else if (jr->JobLevel == L_INCREMENTAL) { /* * For an Incremental job, we must first ensure * that a Full backup was done (cmd edited above) @@ -107,10 +107,10 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) "SELECT StartTime FROM Job WHERE JobStatus='T' AND Type='%c' AND " "Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%u " "AND FileSetId=%u ORDER BY StartTime DESC LIMIT 1", - jr->Type, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name, + jr->JobType, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name, jr->ClientId, jr->FileSetId); } else { - Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->Level); + Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->JobLevel); db_unlock(mdb); return 0; } @@ -157,14 +157,14 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) /* Find last full */ db_lock(mdb); - if (jr->Level == L_VERIFY_CATALOG) { + if (jr->JobLevel == L_VERIFY_CATALOG) { Mmsg(&mdb->cmd, "SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND " " JobStatus='T' AND Name='%s' AND " "ClientId=%u ORDER BY StartTime DESC LIMIT 1", L_VERIFY_INIT, jr->Name, jr->ClientId); - } else if (jr->Level == L_VERIFY_VOLUME_TO_CATALOG || - jr->Level == L_VERIFY_DISK_TO_CATALOG) { + } else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || + jr->JobLevel == L_VERIFY_DISK_TO_CATALOG) { if (Name) { Mmsg(&mdb->cmd, "SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND " @@ -175,7 +175,7 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) "ClientId=%u ORDER BY StartTime DESC LIMIT 1", jr->ClientId); } } else { - Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->Level); + Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->JobLevel); db_unlock(mdb); return 0; } diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index b340e7ac19..1172cfd88e 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -300,8 +300,8 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) jr->JobTDate = str_to_int64(row[7]); bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job)); jr->JobStatus = (int)*row[9]; - jr->Type = (int)*row[10]; - jr->Level = (int)*row[11]; + jr->JobType = (int)*row[10]; + jr->JobLevel = (int)*row[11]; jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)""); sql_free_result(mdb); diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index 887f75e4fe..91625f563a 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -153,11 +153,11 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, } else { if (mdbr->VolumeName[0] != 0) { Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolStatus," - "VolBytes,VolFiles,VolRetention,Recycle,Slot,MediaType,LastWritten " + "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten " "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName); } else { Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolStatus," - "VolBytes,VolFiles,VolRetention,Recycle,Slot,MediaType,LastWritten " + "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten " "FROM Media WHERE Media.PoolId=%u ORDER BY MediaId", mdbr->PoolId); } } diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index 4c7bc5899e..c0af9184cc 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -82,12 +82,12 @@ int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId) } /* - * Update the Job record at end of Job + * Update the Job record at start of Job * * Returns: 0 on failure * 1 on success */ -int +bool db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { char dt[MAX_TIME_LENGTH]; @@ -103,9 +103,10 @@ db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) JobTDate = (btime_t)stime; db_lock(mdb); - Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime='%s'," -"ClientId=%u, JobTDate=%s WHERE JobId=%u", - (char)(jr->Level), dt, jr->ClientId, edit_uint64(JobTDate, ed1), jr->JobId); + Mmsg(&mdb->cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s'," +"ClientId=%u,JobTDate=%s WHERE JobId=%u", + (char)(jcr->JobStatus), + (char)(jr->JobLevel), dt, jr->ClientId, edit_uint64(JobTDate, ed1), jr->JobId); stat = UPDATE_DB(jcr, mdb, mdb->cmd); mdb->changes = 0; diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 0c221bce15..821e497368 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -509,7 +509,7 @@ get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec) char *line; rl_catch_signals = 0; /* do it ourselves */ - line = readline(prompt); + line = readline((char *)prompt); /* cast needed for old readlines */ if (!line) { exit(1); diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 0d4de906d9..9d0726f0dd 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -71,54 +71,17 @@ int do_backup(JCR *jcr) since[0] = 0; if (!get_or_create_client_record(jcr)) { - Jmsg(jcr, M_ERROR, 0, _("Could not get/create Client record. ERR=%s\n"), - db_strerror(jcr->db)); goto bail_out; } - /* - * Get or Create FileSet record - */ - memset(&fsr, 0, sizeof(fsr)); - bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet)); - if (jcr->fileset->have_MD5) { - struct MD5Context md5c; - unsigned char signature[16]; - memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c)); - MD5Final(signature, &md5c); - bin_to_base64(fsr.MD5, (char *)signature, 16); /* encode 16 bytes */ - bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5)); - } else { - Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature not found.\n")); - } - if (!db_create_fileset_record(jcr, jcr->db, &fsr)) { - Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"), - fsr.FileSet, db_strerror(jcr->db)); + if (!get_or_create_fileset_record(jcr, &fsr)) { goto bail_out; - } - jcr->jr.FileSetId = fsr.FileSetId; - if (fsr.created) { - Jmsg(jcr, M_INFO, 0, _("Created new FileSet record \"%s\" %s\n"), - fsr.FileSet, fsr.cCreateTime); } - Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name, - jcr->jr.FileSetId); get_level_since_time(jcr, since, sizeof(since)); - jcr->jr.JobId = jcr->JobId; - jcr->jr.StartTime = jcr->start_time; - if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { - Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); - goto bail_out; - } - jcr->fname = (char *) get_pool_memory(PM_FNAME); - /* Print Job Start message */ - Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %u, Job=%s\n"), - jcr->JobId, jcr->Job); - /* * Get the Pool record -- first apply any level defined pools */ @@ -155,6 +118,19 @@ int do_backup(JCR *jcr) jcr->PoolId = pr.PoolId; /****FIXME**** this can go away */ jcr->jr.PoolId = pr.PoolId; + + /* Print Job Start message */ + Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %u, Job=%s\n"), + jcr->JobId, jcr->Job); + + set_jcr_job_status(jcr, JS_Running); + Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel); + if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { + Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + goto bail_out; + } + + /* * Open a message channel connection with the Storage * daemon. This is to let him know that our client @@ -199,6 +175,10 @@ int do_backup(JCR *jcr) goto bail_out; } + if (!send_level_command(jcr)) { + goto bail_out; + } + /* * send Storage daemon address to the File daemon */ @@ -212,10 +192,6 @@ int do_backup(JCR *jcr) } - if (!send_level_command(jcr)) { - goto bail_out; - } - if (!send_run_before_and_after_commands(jcr)) { goto bail_out; } diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index fcd5aebad7..c37db4900a 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -140,8 +140,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time, */ void get_level_since_time(JCR *jcr, char *since, int since_len) { - /* Lookup the last - * FULL backup job to get the time/date for a + /* Lookup the last FULL backup job to get the time/date for a * differential or incremental save. */ if (!jcr->stime) { @@ -153,20 +152,21 @@ void get_level_since_time(JCR *jcr, char *since, int since_len) case L_DIFFERENTIAL: case L_INCREMENTAL: /* Look up start time of last job */ - jcr->jr.JobId = 0; + jcr->jr.JobId = 0; /* flag for db_find_job_start time */ if (!db_find_job_start_time(jcr, jcr->db, &jcr->jr, &jcr->stime)) { Jmsg(jcr, M_INFO, 0, "%s", db_strerror(jcr->db)); Jmsg(jcr, M_INFO, 0, _("No prior or suitable Full backup found. Doing FULL backup.\n")); bsnprintf(since, since_len, " (upgraded from %s)", level_to_str(jcr->JobLevel)); - jcr->JobLevel = jcr->jr.Level = L_FULL; + jcr->JobLevel = jcr->jr.JobLevel = L_FULL; } else { bstrncpy(since, ", since=", since_len); bstrncat(since, jcr->stime, since_len); } - Dmsg1(100, "Last start time = %s\n", jcr->stime); + jcr->jr.JobId = jcr->JobId; break; } + Dmsg2(100, "Level=%c last start time=%s\n", jcr->JobLevel, jcr->stime); } diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 19a0faf38c..80108dec34 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -82,16 +82,6 @@ void run_job(JCR *jcr) P(jcr->mutex); sm_check(__FILE__, __LINE__, true); init_msg(jcr, jcr->messages); - create_unique_job_name(jcr, jcr->job->hdr.name); - set_jcr_job_status(jcr, JS_Created); - jcr->jr.SchedTime = jcr->sched_time; - jcr->jr.StartTime = jcr->start_time; - jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */ - jcr->jr.Type = jcr->JobType; - jcr->jr.Level = jcr->JobLevel; - jcr->jr.JobStatus = jcr->JobStatus; - bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name)); - bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job)); /* Initialize termination condition variable */ if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) { @@ -120,15 +110,17 @@ void run_job(JCR *jcr) /* * Create Job record */ - jcr->jr.JobStatus = jcr->JobStatus; + create_unique_job_name(jcr, jcr->job->hdr.name); + set_jcr_job_status(jcr, JS_Created); + init_jcr_job_record(jcr); if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); goto bail_out; } jcr->JobId = jcr->jr.JobId; - Dmsg4(50, "Created job record JobId=%d Name=%s Type=%c Level=%c\n", - jcr->JobId, jcr->Job, jcr->jr.Type, jcr->jr.Level); + Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n", + jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel); Dmsg0(200, "Add jrc to work queue\n"); /* Queue the job to be run */ @@ -513,7 +505,7 @@ static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr) /* * Get or create a Client record for this Job */ -int get_or_create_client_record(JCR *jcr) +bool get_or_create_client_record(JCR *jcr) { CLIENT_DBR cr; @@ -529,7 +521,7 @@ int get_or_create_client_record(JCR *jcr) if (!db_create_client_record(jcr, jcr->db, &cr)) { Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"), db_strerror(jcr->db)); - return 0; + return false; } jcr->jr.ClientId = cr.ClientId; if (cr.Uname[0]) { @@ -540,9 +532,53 @@ int get_or_create_client_record(JCR *jcr) } Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name, jcr->jr.ClientId); - return 1; + return true; +} + +bool get_or_create_fileset_record(JCR *jcr, FILESET_DBR *fsr) +{ + /* + * Get or Create FileSet record + */ + memset(fsr, 0, sizeof(FILESET_DBR)); + bstrncpy(fsr->FileSet, jcr->fileset->hdr.name, sizeof(fsr->FileSet)); + if (jcr->fileset->have_MD5) { + struct MD5Context md5c; + unsigned char signature[16]; + memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c)); + MD5Final(signature, &md5c); + bin_to_base64(fsr->MD5, (char *)signature, 16); /* encode 16 bytes */ + bstrncpy(jcr->fileset->MD5, fsr->MD5, sizeof(jcr->fileset->MD5)); + } else { + Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature not found.\n")); + } + if (!db_create_fileset_record(jcr, jcr->db, fsr)) { + Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"), + fsr->FileSet, db_strerror(jcr->db)); + return false; + } + jcr->jr.FileSetId = fsr->FileSetId; + if (fsr->created) { + Jmsg(jcr, M_INFO, 0, _("Created new FileSet record \"%s\" %s\n"), + fsr->FileSet, fsr->cCreateTime); + } + Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name, + jcr->jr.FileSetId); + return true; } +void init_jcr_job_record(JCR *jcr) +{ + jcr->jr.SchedTime = jcr->sched_time; + jcr->jr.StartTime = jcr->start_time; + jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */ + jcr->jr.JobType = jcr->JobType; + jcr->jr.JobLevel = jcr->JobLevel; + jcr->jr.JobStatus = jcr->JobStatus; + jcr->jr.JobId = jcr->JobId; + bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name)); + bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job)); +} /* * Write status and such in DB diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 12463f2ee4..5dca711af4 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -85,9 +85,11 @@ extern int response(JCR *jcr, BSOCK *fd, char *resp, const char *cmd, e_prtmsg p extern void set_jcr_defaults(JCR *jcr, JOB *job); extern void create_unique_job_name(JCR *jcr, const char *base_name); extern void update_job_end_record(JCR *jcr); -extern int get_or_create_client_record(JCR *jcr); +extern bool get_or_create_client_record(JCR *jcr); +extern bool get_or_create_fileset_record(JCR *jcr, FILESET_DBR *fsr); extern void run_job(JCR *jcr); extern int cancel_job(UAContext *ua, JCR *jcr); +extern void init_jcr_job_record(JCR *jcr); /* mountreq.c */ extern void mount_request(JCR *jcr, BSOCK *bs, char *buf); @@ -174,6 +176,7 @@ int find_arg(UAContext *ua, const char *keyword); int find_arg_with_value(UAContext *ua, const char *keyword); int do_keyword_prompt(UAContext *ua, const char *msg, const char **list); int confirm_retention(UAContext *ua, utime_t *ret, const char *msg); +bool get_level_from_name(JCR *jcr, const char *level_name); /* ua_tree.c */ bool user_select_files_from_tree(TREE_CTX *tree); diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 3933586d54..e8b0da28f2 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -73,8 +73,7 @@ int do_restore(JCR *jcr) } memset(&rjr, 0, sizeof(rjr)); - jcr->jr.Level = L_FULL; /* Full restore */ - jcr->jr.StartTime = jcr->start_time; + jcr->jr.JobLevel = L_FULL; /* Full restore */ if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); restore_cleanup(jcr, JS_ErrorTerminated); @@ -240,7 +239,7 @@ int do_restore(JCR *jcr) } else if (jcr->job->RestoreWhere) { where = jcr->job->RestoreWhere; /* no override take from job */ } else { - where = ∅ /* None */ + where = ∅ /* None */ } jcr->prefix_links = jcr->job->PrefixLinks; bash_spaces(where); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 35b9212f3c..fa8dfe9559 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -1421,10 +1421,12 @@ static int estimate_cmd(UAContext *ua, const char *cmd) JOB *job = NULL; CLIENT *client = NULL; FILESET *fileset = NULL; + FILESET_DBR fsr; int listing = 0; - BSOCK *fd; char since[MAXSTRING]; + JCR *jcr = ua->jcr; + jcr->JobLevel = L_FULL; for (int i=1; iargc; i++) { if (strcasecmp(ua->argk[i], _("client")) == 0 || strcasecmp(ua->argk[i], _("fd")) == 0) { @@ -1447,6 +1449,13 @@ static int estimate_cmd(UAContext *ua, const char *cmd) } if (strcasecmp(ua->argk[i], _("listing")) == 0) { listing = 1; + continue; + } + if (strcasecmp(ua->argk[i], _("level")) == 0) { + if (!get_level_from_name(ua->jcr, ua->argv[i])) { + bsendmsg(ua, _("Level %s not valid.\n"), ua->argv[i]); + } + continue; } } if (!job && !(client && fileset)) { @@ -1456,6 +1465,10 @@ static int estimate_cmd(UAContext *ua, const char *cmd) } if (!job) { job = (JOB *)GetResWithName(R_JOB, ua->argk[1]); + if (!job) { + bsendmsg(ua, _("No job specified.\n")); + return 1; + } } if (!client) { client = job->client; @@ -1463,8 +1476,8 @@ static int estimate_cmd(UAContext *ua, const char *cmd) if (!fileset) { fileset = job->fileset; } - ua->jcr->client = client; - ua->jcr->fileset = fileset; + jcr->client = client; + jcr->fileset = fileset; close_db(ua); ua->catalog = client->catalog; @@ -1472,39 +1485,51 @@ static int estimate_cmd(UAContext *ua, const char *cmd) return 1; } + jcr->job = job; + jcr->JobType = JT_BACKUP; + init_jcr_job_record(jcr); + + if (!get_or_create_client_record(jcr)) { + return 1; + } + if (!get_or_create_fileset_record(jcr, &fsr)) { + return 1; + } + get_level_since_time(ua->jcr, since, sizeof(since)); bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), job->client->hdr.name, job->client->address, job->client->FDport); - if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) { + if (!connect_to_file_daemon(jcr, 1, 15, 0)) { bsendmsg(ua, _("Failed to connect to Client.\n")); return 1; } - fd = ua->jcr->file_bsock; - if (!send_include_list(ua->jcr)) { + if (!send_include_list(jcr)) { bsendmsg(ua, _("Error sending include list.\n")); - return 1; + goto bail_out; } - if (!send_exclude_list(ua->jcr)) { + if (!send_exclude_list(jcr)) { bsendmsg(ua, _("Error sending exclude list.\n")); - return 1; + goto bail_out; } - if (!send_level_command(ua->jcr)) { - return 1; + if (!send_level_command(jcr)) { + goto bail_out; } - bnet_fsend(fd, "estimate listing=%d\n", listing); - while (bnet_recv(fd) >= 0) { - bsendmsg(ua, "%s", fd->msg); + bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing); + while (bnet_recv(jcr->file_bsock) >= 0) { + bsendmsg(ua, "%s", jcr->file_bsock->msg); } - bnet_sig(fd, BNET_TERMINATE); - bnet_close(fd); - ua->jcr->file_bsock = NULL; - +bail_out: + if (jcr->file_bsock) { + bnet_sig(jcr->file_bsock, BNET_TERMINATE); + bnet_close(jcr->file_bsock); + jcr->file_bsock = NULL; + } return 1; } diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 856911680b..6fdd347847 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -33,7 +33,6 @@ /* Imported subroutines */ /* Imported variables */ -extern struct s_jl joblevels[]; extern struct s_kw ReplaceOptions[]; /* @@ -407,21 +406,11 @@ try_again: } } if (level_name) { - /* Look up level name and pull code */ - bool found = false; - for (i=0; joblevels[i].level_name; i++) { - if (strcasecmp(level_name, _(joblevels[i].level_name)) == 0) { - jcr->JobLevel = joblevels[i].level; - found = true; - break; - } - } - if (!found) { + if (!get_level_from_name(jcr, level_name)) { bsendmsg(ua, _("Level %s not valid.\n"), level_name); goto bail_out; } } - level_name = NULL; if (jid) { jcr->RestoreJobId = atoi(jid); } diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index e2a93ce54d..f0d3b2588c 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -31,6 +31,7 @@ #include "dird.h" /* Imported variables */ +extern struct s_jl joblevels[]; /* @@ -865,3 +866,17 @@ int get_media_type(UAContext *ua, char *MediaType, int max_media) UnlockRes(); return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1; } + +bool get_level_from_name(JCR *jcr, const char *level_name) +{ + /* Look up level name and pull code */ + bool found = false; + for (int i=0; joblevels[i].level_name; i++) { + if (strcasecmp(level_name, joblevels[i].level_name) == 0) { + jcr->JobLevel = joblevels[i].level; + found = true; + break; + } + } + return found; +} diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index c34dcd470a..e6ec1ac986 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -114,9 +114,6 @@ int do_verify(JCR *jcr) Dmsg1(100, "Last full jobid=%d\n", verify_jobid); } - jcr->jr.JobId = jcr->JobId; - jcr->jr.StartTime = jcr->start_time; - jcr->jr.Level = jcr->JobLevel; if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); goto bail_out; diff --git a/bacula/src/lib/bsys.c b/bacula/src/lib/bsys.c index b86ad53bf0..4d0e28a0b4 100644 --- a/bacula/src/lib/bsys.c +++ b/bacula/src/lib/bsys.c @@ -433,7 +433,7 @@ void write_state_file(char *dir, const char *progname, int port) goto bail_out; } if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) { - Dmsg1(000, "Write final hdr error: ERR=%s\n", strerror(errno)); + Pmsg1(000, "Write final hdr error: ERR=%s\n", strerror(errno)); } // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr)); bail_out: @@ -547,31 +547,31 @@ char *bfgets(char *s, int size, FILE *fd) *p = 0; for (int i=0; i < size-1; i++) { do { - errno = 0; - ch = fgetc(fd); + errno = 0; + ch = fgetc(fd); } while (ch == -1 && (errno == EINTR || errno == EAGAIN)); if (ch == -1) { - if (i == 0) { - return NULL; - } else { - return s; - } + if (i == 0) { + return NULL; + } else { + return s; + } } *p++ = ch; *p = 0; if (ch == '\r') { /* Support for Mac/Windows file format */ - ch = fgetc(fd); + ch = fgetc(fd); if (ch == '\n') { /* Windows (\r\n) */ - *p++ = ch; - *p = 0; - } + *p++ = ch; + *p = 0; + } else { /* Mac (\r only) */ - ungetc(ch, fd); /* Push next character back to fd */ - } - break; + ungetc(ch, fd); /* Push next character back to fd */ + } + break; } if (ch == '\n') { - break; + break; } } return s; diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index be9103d19a..52bd47b208 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -465,7 +465,7 @@ static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) dcr->StartFile = (uint32_t)(dev->file_addr >> 32); } mjcr->start_time = jr.StartTime; - mjcr->JobLevel = jr.Level; + mjcr->JobLevel = jr.JobLevel; mjcr->client_name = get_pool_memory(PM_FNAME); pm_strcpy(&mjcr->client_name, label.ClientName); @@ -892,8 +892,8 @@ static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label, struct tm tm; jr->JobId = label->JobId; - jr->Type = label->JobType; - jr->Level = label->JobLevel; + jr->JobType = label->JobType; + jr->JobLevel = label->JobLevel; jr->JobStatus = JS_Created; bstrncpy(jr->Name, label->JobName, sizeof(jr->Name)); bstrncpy(jr->Job, label->Job, sizeof(jr->Job)); @@ -1129,8 +1129,8 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) * the JobId and the ClientId. */ jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr); - jobjcr->JobType = jr->Type; - jobjcr->JobLevel = jr->Level; + jobjcr->JobType = jr->JobType; + jobjcr->JobLevel = jr->JobLevel; jobjcr->JobStatus = jr->JobStatus; bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job)); jobjcr->JobId = JobId; /* this is JobId on tape */ diff --git a/bacula/src/stored/spool.c b/bacula/src/stored/spool.c index a9caea326f..0267c248d3 100644 --- a/bacula/src/stored/spool.c +++ b/bacula/src/stored/spool.c @@ -32,10 +32,12 @@ static void make_unique_data_spool_filename(JCR *jcr, POOLMEM **name); static bool open_data_spool_file(JCR *jcr); static bool close_data_spool_file(JCR *jcr); -static bool despool_data(DCR *dcr); +static bool despool_data(DCR *dcr, bool commit); static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block); static bool open_attr_spool_file(JCR *jcr, BSOCK *bs); static bool close_attr_spool_file(JCR *jcr, BSOCK *bs); +static bool write_spool_header(DCR *dcr, DEV_BLOCK *block); +static bool write_spool_data(DCR *dcr, DEV_BLOCK *block); struct spool_stats_t { uint32_t data_jobs; /* current jobs spooling data */ @@ -112,13 +114,10 @@ bool discard_data_spool(JCR *jcr) bool commit_data_spool(JCR *jcr) { bool stat; - char ec1[40]; if (jcr->dcr->spooling) { Dmsg0(100, "Committing spooled data\n"); - Jmsg(jcr, M_INFO, 0, _("Writing spooled data to Volume. Despooling %s bytes ...\n"), - edit_uint64_with_commas(jcr->dcr->dev->spool_size, ec1)); - stat = despool_data(jcr->dcr); + stat = despool_data(jcr->dcr, true /*commit*/); if (!stat) { Dmsg1(000, "Bad return from despool WroteVol=%d\n", jcr->dcr->WroteVol); close_data_spool_file(jcr); @@ -185,7 +184,7 @@ static bool close_data_spool_file(JCR *jcr) return true; } -static bool despool_data(DCR *dcr) +static bool despool_data(DCR *dcr, bool commit) { DEVICE *rdev; DCR *rdcr; @@ -193,8 +192,12 @@ static bool despool_data(DCR *dcr) DEV_BLOCK *block; JCR *jcr = dcr->jcr; int stat; + char ec1[50]; Dmsg0(100, "Despooling data\n"); + Jmsg(jcr, M_INFO, 0, _("%s spooled data to Volume. Despooling %s bytes ...\n"), + commit?"Committing":"Writting", + edit_uint64_with_commas(jcr->dcr->dev->spool_size, ec1)); dcr->spooling = false; lock_device(dcr->dev); dcr->dev_locked = true; @@ -320,10 +323,7 @@ static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) */ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) { - ssize_t stat = 0; uint32_t wlen, hlen; /* length to write */ - int retry = 0; - spool_hdr hdr; bool despool = false; ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf))); @@ -331,7 +331,7 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) return true; } - hlen = sizeof(hdr); + hlen = sizeof(spool_hdr); wlen = block->binbuf; P(dcr->dev->spool_mutex); dcr->spool_size += hlen + wlen; @@ -348,9 +348,8 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) } V(mutex); if (despool) { - char ec1[30]; #ifdef xDEBUG - char ec2[30], ec3[30], ec4[30]; + char ec1[30], ec2[30], ec3[30], ec4[30]; Dmsg4(100, "Despool in write_block_to_spool_file max_size=%s size=%s " "max_job_size=%s job_size=%s\n", edit_uint64_with_commas(dcr->max_spool_size, ec1), @@ -358,9 +357,8 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) edit_uint64_with_commas(dcr->dev->max_spool_size, ec3), edit_uint64_with_commas(dcr->dev->spool_size, ec4)); #endif - Jmsg(dcr->jcr, M_INFO, 0, _("User specified spool size reached. Despooling %s bytes ...\n"), - edit_uint64_with_commas(dcr->dev->spool_size, ec1)); - if (!despool_data(dcr)) { + Jmsg(dcr->jcr, M_INFO, 0, _("User specified spool size reached.\n")); + if (!despool_data(dcr, false)) { Dmsg0(000, "Bad return from despool in write_block.\n"); return false; } @@ -372,54 +370,86 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) Jmsg(dcr->jcr, M_INFO, 0, _("Spooling data again ...\n")); } + + if (!write_spool_header(dcr, block)) { + return false; + } + if (!write_spool_data(dcr, block)) { + return false; + } + + Dmsg2(100, "Wrote block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); + empty_block(block); + return true; +} + +static bool write_spool_header(DCR *dcr, DEV_BLOCK *block) +{ + spool_hdr hdr; + ssize_t stat; + hdr.FirstIndex = block->FirstIndex; hdr.LastIndex = block->LastIndex; hdr.len = block->binbuf; /* Write header */ - for ( ;; ) { - stat = write(dcr->spool_fd, (char*)&hdr, (size_t)hlen); + for (int retry=0; retry<=1; retry++) { + stat = write(dcr->spool_fd, (char*)&hdr, sizeof(hdr)); if (stat == -1) { Jmsg(dcr->jcr, M_INFO, 0, _("Error writing header to spool file. ERR=%s\n"), strerror(errno)); } - if (stat != (ssize_t)hlen) { - if (!despool_data(dcr)) { - Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error.")); - return false; + if (stat != (ssize_t)sizeof(hdr)) { + /* If we wrote something, truncate it, then despool */ + if (stat != -1) { + ftruncate(dcr->spool_fd, lseek(dcr->spool_fd, (off_t)0, SEEK_CUR) - stat); } - if (retry++ > 1) { + if (!despool_data(dcr, false)) { + Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error.")); return false; } - continue; + continue; /* try again */ } - break; + return true; } + Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n")); + return false; +} + +static bool write_spool_data(DCR *dcr, DEV_BLOCK *block) +{ + ssize_t stat; /* Write data */ - for ( ;; ) { - stat = write(dcr->spool_fd, block->buf, (size_t)wlen); + for (int retry=0; retry<=1; retry++) { + stat = write(dcr->spool_fd, block->buf, (size_t)block->binbuf); if (stat == -1) { Jmsg(dcr->jcr, M_INFO, 0, _("Error writing data to spool file. ERR=%s\n"), strerror(errno)); } - if (stat != (ssize_t)wlen) { - if (!despool_data(dcr)) { + if (stat != (ssize_t)block->binbuf) { + /* + * If we wrote something, truncate it and the header, then despool + */ + if (stat != -1) { + ftruncate(dcr->spool_fd, lseek(dcr->spool_fd, (off_t)0, SEEK_CUR) + - stat - sizeof(spool_hdr)); + } + if (!despool_data(dcr, false)) { Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error.")); return false; } - if (retry++ > 1) { + if (!write_spool_header(dcr, block)) { return false; } - continue; + continue; /* try again */ } - break; + return true; } - Dmsg2(100, "Wrote block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); - - empty_block(block); - return true; + Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n")); + return false; } + bool are_attributes_spooled(JCR *jcr) { return jcr->spool_attributes && jcr->dir_bsock->spool_fd; diff --git a/bacula/src/version.h b/bacula/src/version.h index 15cf4033c0..06f0303dba 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.35.0" #define VSTRING "1" -#define BDATE "21 June 2004" -#define LSMDATE "21Jun04" +#define BDATE "26 June 2004" +#define LSMDATE "26Jun04" /* Debug flags */ #undef DEBUG