]> git.sur5r.net Git - bacula/bacula/commitdiff
Integrate Nicolas' patch for direct DVD support.
authorKern Sibbald <kern@sibbald.com>
Sat, 8 Jan 2005 14:44:25 +0000 (14:44 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 8 Jan 2005 14:44:25 +0000 (14:44 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1796 91ce42f0-d328-0410-95d8-f526ca767f89

60 files changed:
bacula/Makefile.in
bacula/autoconf/config.h.in
bacula/autoconf/configure.in
bacula/kernstodo
bacula/scripts/.cvsignore
bacula/scripts/Makefile.in
bacula/src/c
bacula/src/cats/cats.h
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/make_postgresql_tables.in
bacula/src/cats/make_sqlite_tables.in
bacula/src/cats/sql_create.c
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/cats/sql_list.c
bacula/src/cats/sql_update.c
bacula/src/cats/update_mysql_tables.in
bacula/src/cats/update_postgresql_tables.in
bacula/src/cats/update_sqlite_tables.in
bacula/src/dird/catreq.c
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/fd_cmds.c
bacula/src/dird/inc_conf.c
bacula/src/dird/job.c
bacula/src/dird/msgchan.c
bacula/src/dird/python.c
bacula/src/dird/run_conf.c
bacula/src/dird/scheduler.c
bacula/src/filed/backup.c
bacula/src/filed/job.c
bacula/src/filed/protos.h
bacula/src/filed/restore.c
bacula/src/findlib/find.c
bacula/src/findlib/find.h
bacula/src/findlib/find_one.c
bacula/src/findlib/fstype.c
bacula/src/findlib/protos.h
bacula/src/jcr.h
bacula/src/lib/bpipe.c
bacula/src/lib/protos.h
bacula/src/stored/acquire.c
bacula/src/stored/append.c
bacula/src/stored/askdir.c
bacula/src/stored/block.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/dircmd.c
bacula/src/stored/job.c
bacula/src/stored/label.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h
bacula/src/stored/python.c
bacula/src/stored/read.c
bacula/src/stored/status.c
bacula/src/stored/stored.h
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/tools/fstype.c
bacula/src/version.h

index ec47e0473a895ef07b197b81cd9265927f21a9a6..3f805b3ad0cd4115f24d81cf19a406f94e533d8d 100755 (executable)
@@ -181,7 +181,7 @@ clean:
        @(cd platforms; echo "==>Entering directory `pwd`"; ${MAKE} $@ || exit 1)
        @$(RMF) *~ 1 2 3 core core.* config.guess console.log console.sum
        @$(RMF) examples/1 examples/2 examples/devices/1 examples/devices/2
-       @$(RMF) autom4te.cache
+       @$(RMF) -r autom4te.cache
 
 
 # clean for distribution
index adac090114858ad76c045061c686d40ba76cfbdc..8d3797e6b419676a72723c0693afa14a01109b38 100644 (file)
 /* If using the C implementation of alloca, define if you know the
    direction of stack growth for your system; otherwise it will be
    automatically deduced at run-time.
-        STACK_DIRECTION > 0 => grows toward higher addresses
-        STACK_DIRECTION < 0 => grows toward lower addresses
-        STACK_DIRECTION = 0 => direction of growth unknown */
+       STACK_DIRECTION > 0 => grows toward higher addresses
+       STACK_DIRECTION < 0 => grows toward lower addresses
+       STACK_DIRECTION = 0 => direction of growth unknown */
 #undef STACK_DIRECTION
 
 /* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
index c30b359f3e0dcf9bdc1e7fce550afe645daa6a23..a3e70fa4a4566dbee322cc076278d5542ff9787e 100644 (file)
@@ -62,6 +62,10 @@ AC_PATH_PROG(AR, ar, ar)
 dnl AC_PATH_PROG(RANLIB, ranlib, ranlib)
 AC_PATH_PROG(OPENSSL, openssl, none)
 AC_PATH_PROG(MTX, mtx, mtx)
+AC_PATH_PROG(MKISOFS, mkisofs, mkisofs)
+AC_PATH_PROG(PYTHON, python, python)
+AC_PATH_PROG(GROWISOFS, growisofs, growisofs)
+AC_PATH_PROG(DVDRWMEDIAINFO, dvd+rw-mediainfo, dvd+rw-mediainfo)
 AC_PATH_PROG(PKGCONFIG, pkg-config, pkg-config)
 AC_PATH_PROG(WXCONFIG, wx-config, wx-config)
 AC_PATH_PROG(CDRECORD, cdrecord, cdrecord)
@@ -1952,6 +1956,8 @@ AC_OUTPUT([autoconf/Make.common \
           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 \
index 6fbfb3aec2f119d6bd9b39786976360d9bbf1be5..706e61127d53b10d1613df2a647ad30a9f7c57c4 100644 (file)
@@ -30,7 +30,6 @@ Suggestions for Preben:
 - Optimized bootstrap.
 
 For 1.37:
-- Look at Preben's fstype error handling code.
 - Look at Preben's acl.c error handling code.
 - See multiple-store.txt for Multiple Storage implementation
   design.
index 38362e56b4409a2379ba9c8586ea8e9be15d6b2f..c9cb41e404996d00c9a08b0560d152727a523844 100644 (file)
@@ -9,6 +9,8 @@ bconsole
 devel_bacula
 gconsole
 mtx-changer
+dvd-writepart
+dvd-freespace
 Makefile
 bacula
 btraceback
index 10f97167f73e2139dd52af79cb3eba290d1bab6f..c08fc344b34448f93f74d1698039fc22173da8f1 100755 (executable)
@@ -42,6 +42,16 @@ install: installdirs
           $(MV) -f ${DESTDIR}${scriptdir}/mtx-changer ${DESTDIR}${scriptdir}/mtx-changer.old; \
        fi
        $(INSTALL_SCRIPT) mtx-changer $(DESTDIR)$(scriptdir)/mtx-changer
+       @if  test -f ${DESTDIR}${scriptdir}/dvd-writepart; then \
+          echo "  ==> Saving existing dvd-writepart to dvd-writepart.old"; \
+          $(MV) -f ${DESTDIR}${scriptdir}/dvd-writepart ${DESTDIR}${scriptdir}/dvd-writepart.old; \
+       fi
+       $(INSTALL_SCRIPT) dvd-writepart $(DESTDIR)$(scriptdir)/dvd-writepart
+       @if  test -f ${DESTDIR}${scriptdir}/dvd-freespace; then \
+          echo "  ==> Saving existing dvd-freespace to dvd-freespace.old"; \
+          $(MV) -f ${DESTDIR}${scriptdir}/dvd-freespace ${DESTDIR}${scriptdir}/dvd-freespace.old; \
+       fi
+       $(INSTALL_SCRIPT) dvd-freespace $(DESTDIR)$(scriptdir)/dvd-freespace
        $(INSTALL_DATA)   btraceback.gdb $(DESTDIR)$(scriptdir)/btraceback.gdb
        $(INSTALL_DATA)   btraceback.dbx $(DESTDIR)$(scriptdir)/btraceback.dbx
        $(INSTALL_SCRIPT) btraceback $(DESTDIR)$(sbindir)/btraceback
@@ -54,6 +64,8 @@ uninstall:
        (cd $(DESTDIR)$(scriptdir); $(RMF) bacula)
        (cd $(DESTDIR)$(scriptdir); $(RMF) fd)
        (cd $(DESTDIR)$(scriptdir); $(RMF) mtx-changer)
+       (cd $(DESTDIR)$(scriptdir); $(RMF) dvd-writepart) 
+       (cd $(DESTDIR)$(scriptdir); $(RMF) dvd-freespace) 
        (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.gdb)
        (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.dbx)
        (cd $(DESTDIR)$(sbindir); $(RMF) btraceback)
@@ -62,12 +74,12 @@ Makefile: Makefile.in
        cd $(topdir) \
            && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
        chmod 755 startmysql stopmysql bacula startit stopit btraceback
-       chmod 755 mtx-changer bconsole gconsole
+       chmod 755 mtx-changer dvd-writepart dvd-freespace bconsole gconsole
 
 Makefiles:
        $(SHELL) config.status
        chmod 755 startmysql stopmysql bacula startit stopit btraceback
-       chmod 755 mtx-changer bconsole gconsole
+       chmod 755 mtx-changer dvd-writepart dvd-freespace bconsole gconsole
 
 clean:
        @$(RMF) *~ 1 2 3
@@ -76,7 +88,7 @@ clean:
 distclean: clean
        @$(RMF) startmysql stopmysql bacula fd startit stopit btraceback
        @$(RMF) bconsole gconsole logrotate bacula.desktop 
-       @$(RMF) bacula.desktop.gnome1 bacula.desktop.gnome2 mtx-changer
+       @$(RMF) bacula.desktop.gnome1 bacula.desktop.gnome2 mtx-changer dvd-writepart dvd-freespace
        @$(RMF) gnome-console.console_apps bacula.desktop.gnome2.xsu
        @$(RMF) bacula.desktop.gnome2.consolehelper bacula.desktop.gnome1.xsu
        @$(RMF) bacula.desktop.gnome1.consolehelper
index 5c8d1e7c4b7a553f0395c4534c9667e03cc4e415..fd4a244c2028dcff33e69ecc4a9a2225174a2ae4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2000-2005 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index 3a5d3756de51ad10f4e25da33540db918be54c29..28c6a41de1ab1eba941f56c1a09dacc46aae8ef9 100644 (file)
@@ -535,6 +535,7 @@ struct MEDIA_DBR {
    uint32_t VolWrites;                /* Number of writes */
    uint32_t VolReads;                 /* Number of reads */
    uint64_t VolBytes;                 /* Number of bytes written */
+   uint32_t VolParts;                 /* Number of parts written */
    uint64_t MaxVolBytes;              /* Max bytes to write to Volume */
    uint64_t VolCapacityBytes;         /* capacity estimate */
    uint64_t VolReadTime;              /* time spent reading volume */
index 3f292ea447f88460950f1f0e0e00552adaf861c0..8dc27817808c4f28deccde6676571510bac1fd02 100644 (file)
@@ -111,6 +111,7 @@ CREATE TABLE Media (
    VolBlocks INTEGER UNSIGNED NOT NULL DEFAULT 0,
    VolMounts INTEGER UNSIGNED NOT NULL DEFAULT 0,
    VolBytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
+   VolParts INTEGER UNSIGNED NOT NULL DEFAULT 0,
    VolErrors INTEGER UNSIGNED NOT NULL DEFAULT 0,
    VolWrites INTEGER UNSIGNED NOT NULL DEFAULT 0,
    VolCapacityBytes BIGINT UNSIGNED NOT NULL,
index b067f1548bf5dea22a9a682f9776e2152a89aa2c..25941db8670004cfe604bb03a1ed7b39e14cc03f 100644 (file)
@@ -122,6 +122,8 @@ create table media
        default 0,
     volbytes         bigint                not null
        default 0,
+    volparts         integer               not null
+       default 0,
     volerrors        integer               not null
        default 0,
     volwrites        integer               not null
index a780f9dc502d93050332de3706702bf0fe44ad0f..9288ca75757112cd3d81af0e1f8733af2ba32c31 100644 (file)
@@ -111,6 +111,7 @@ CREATE TABLE Media (
    VolBlocks INTEGER UNSIGNED DEFAULT 0,
    VolMounts INTEGER UNSIGNED DEFAULT 0,
    VolBytes BIGINT UNSIGNED DEFAULT 0,
+   VolParts INTEGER UNSIGNED DEFAULT 0,
    VolErrors INTEGER UNSIGNED DEFAULT 0,
    VolWrites INTEGER UNSIGNED DEFAULT 0,
    VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
index 147538484a9d333fb92daa699b8818ad27473a4a..6dffada30284cf544e095c4d4d675eaa4625e73c 100644 (file)
@@ -242,9 +242,9 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
    Mmsg(mdb->cmd,
 "INSERT INTO Media (VolumeName,MediaType,PoolId,MaxVolBytes,VolCapacityBytes,"
 "Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-"VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,"
+"VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
 "EndFile,EndBlock) "
-"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,0,0)",
+"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0)",
                  mr->VolumeName,
                  mr->MediaType, mr->PoolId,
                  edit_uint64(mr->MaxVolBytes,ed1),
@@ -259,7 +259,9 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
                  edit_uint64(mr->VolBytes, ed5),
                  mr->InChanger,
                  edit_uint64(mr->VolReadTime, ed6),
-                 edit_uint64(mr->VolWriteTime, ed7));
+                 edit_uint64(mr->VolWriteTime, ed7),
+                 mr->VolParts
+                 );
 
 
    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
index dd10220aa18481745d90db621a9b89391ace8de6..cb53f6b3d652a7f43db15dac8f9c93f6517520aa 100644 (file)
@@ -268,7 +268,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
          "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-         "FirstWritten,LastWritten,VolStatus,InChanger "
+         "FirstWritten,LastWritten,VolStatus,InChanger,VolParts "
          "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus IN ('Full',"
          "'Recycle','Purged','Used','Append') "
          "ORDER BY LastWritten LIMIT 1", mr->PoolId, mr->MediaType);
@@ -289,7 +289,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
          "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-         "FirstWritten,LastWritten,VolStatus,InChanger "
+         "FirstWritten,LastWritten,VolStatus,InChanger,VolParts "
          "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
          "%s "
          "%s LIMIT %d",
@@ -344,6 +344,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
    mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
    bstrncpy(mr->VolStatus, row[19], sizeof(mr->VolStatus));
    mr->InChanger = str_to_int64(row[20]);
+   mr->VolParts = str_to_int64(row[21]);
    sql_free_result(mdb);
 
    db_unlock(mdb);
index e53ecfa4db9f4c375e7b4365d84b539e4e50097b..958e86503c3be84ddf7cde4d18ca49b39c2b3e97 100644 (file)
@@ -810,13 +810,13 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
         "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
         "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-        "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock "
+        "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock,VolParts "
         "FROM Media WHERE MediaId=%d", mr->MediaId);
    } else {                          /* find by name */
       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
         "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
         "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-        "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock "
+        "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock,VolParts "
         "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
    }
 
@@ -860,6 +860,7 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
            mr->InChanger = str_to_uint64(row[22]);
            mr->EndFile = str_to_uint64(row[23]);
            mr->EndBlock = str_to_uint64(row[24]);
+           mr->VolParts = str_to_int64(row[25]);
            stat = mr->MediaId;
         }
       } else {
index ec69cda0448e38340a6236042d92fdfa2ce92389..287d7809352bf4c69c4e5aec791eb6797d241158 100644 (file)
@@ -141,7 +141,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
             "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
             "VolCapacityBytes,VolStatus,Recycle,VolRetention,"
             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
-            "EndFile,EndBlock "
+            "EndFile,EndBlock,VolParts "
             "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName);
       } else {
          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
@@ -149,7 +149,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
             "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
             "VolCapacityBytes,VolStatus,Recycle,VolRetention,"
             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
-            "EndFile,EndBlock "
+            "EndFile,EndBlock,VolParts "
             "FROM Media WHERE Media.PoolId=%u ORDER BY MediaId", mdbr->PoolId);
       }
    } else {
index 86f65d6c3994b4a968307214e3208c47d09a2d5e..3785fda5e7829fc2aad7c82ee318fbe6014c283c 100644 (file)
@@ -261,7 +261,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
    time_t ttime;
    struct tm tm;
    int stat;
-   char ed1[30], ed2[30], ed3[30], ed4[30];
+   char ed1[30], ed2[30], ed3[30], ed4[30], ed5[30];
 
 
    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
@@ -298,7 +298,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
       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,InChanger=%d,VolReadTime=%s,VolWriteTime=%s "
+          "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%s "
           " WHERE VolumeName='%s'",
           mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
           mr->VolMounts, mr->VolErrors, mr->VolWrites,
@@ -306,12 +306,13 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
           mr->VolStatus, mr->Slot, mr->InChanger,
           edit_uint64(mr->VolReadTime, ed3),
           edit_uint64(mr->VolWriteTime, ed4),
+           edit_uint64(mr->VolParts, ed5),
           mr->VolumeName);
    } else {
       Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
           "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
           "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
-          "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s "
+                 "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%s "
           " WHERE VolumeName='%s'",
           mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
           mr->VolMounts, mr->VolErrors, mr->VolWrites,
@@ -319,6 +320,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
           mr->VolStatus, mr->Slot, mr->InChanger,
           edit_uint64(mr->VolReadTime, ed3),
           edit_uint64(mr->VolWriteTime, ed4),
+           edit_uint64(mr->VolParts, ed5),
           mr->VolumeName);
    }
 
index 64797d65f2a439ded9f740d95c50a0e02fce220e..f47f2137c55f55eeab8c2328d105f6fbb7f5a96d 100755 (executable)
@@ -12,21 +12,7 @@ bindir=@SQL_BINDIR@
 if $bindir/mysql $* -f <<END-OF-DATA
 USE bacula;
 
-ALTER TABLE Media ADD COLUMN EndFile INTEGER UNSIGNED NOT NULL DEFAULT 0;
-ALTER TABLE Media ADD COLUMN EndBlock INTEGER UNSIGNED NOT NULL DEFAULT 0;
-
-ALTER TABLE File ADD INDEX (JobId, PathId, FilenameId);
-
-UPDATE Filename SET Name='' WHERE Name=' ';
-
-CREATE TABLE CDImages (
-   MediaId INTEGER UNSIGNED NOT NULL,
-   LastBurn DATETIME NOT NULL,
-   PRIMARY KEY (MediaId)
-   );
-
-DELETE FROM Version;
-INSERT INTO Version (VersionId) VALUES (8);
+ALTER TABLE Media ADD COLUMN VolParts INTEGER UNSIGNED NOT NULL DEFAULT 0;
 
 END-OF-DATA
 then
index 8739ffce6ae34518d09d433d5226559973c5c5d2..e13b850d2ed8880fe8f56f407b6afa6db8f9faee 100755 (executable)
@@ -12,35 +12,9 @@ bindir=@SQL_BINDIR@
 if $bindir/psql $* -f - <<END-OF-DATA
 \c bacula
 
-ALTER TABLE media ADD COLUMN EndFile integer;
-UPDATE media SET EndFile=0;
-ALTER TABLE media ALTER COLUMN EndFile SET NOT NULL;
-ALTER TABLE media ADD COLUMN EndBlock integer;
-UPDATE media SET EndBlock=0;
-ALTER TABLE media ALTER COLUMN EndBlock SET NOT NULL;
-
-UPDATE Filename SET Name='' WHERE Name=' ';
-
-alter table file rename column filenameid to filenameidold;
-alter table file add column filenameid integer;
-update file set filenameid = filenameidold;
-alter table file alter column filenameid set not null;
-alter table file drop column filenameidold;
-
-DELETE FROM Version;
-INSERT INTO Version (VersionId) VALUES (8);
-
-create index file_jobid_idx on file (jobid);
-create index file_pathid_idx on file(pathid);
-create index file_filenameid_idx on file(filenameid);
-create index file_jpfid_idx on file (jobid, pathid, filenameid);
-
-create table CDImages 
-(
-   MediaId integer not null,
-   LastBurn timestamp without time zone not null,
-   primary key (MediaId)
-);
+ALTER TABLE media ADD COLUMN volparts integer;
+UPDATE media SET volparts=0;
+ALTER TABLE media ALTER COLUMN volparts SET NOT NULL;
 
 vacuum;
 
index 1a507be38a47b5b2478497384ece31f2f2cc9bf1..82114207ddd27eadb3afaaffb9f36aa2de138a4c 100755 (executable)
@@ -28,6 +28,7 @@ CREATE TEMPORARY TABLE Media_backup (
    VolBlocks INTEGER UNSIGNED DEFAULT 0,
    VolMounts INTEGER UNSIGNED DEFAULT 0,
    VolBytes BIGINT UNSIGNED DEFAULT 0,
+   VolParts INTEGER UNSIGNED DEFAULT 0,
    VolErrors INTEGER UNSIGNED DEFAULT 0,
    VolWrites INTEGER UNSIGNED DEFAULT 0,
    VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
@@ -51,11 +52,11 @@ INSERT INTO Media_backup SELECT
    MediaId, VolumeName, Slot, PoolId,
    MediaType, FirstWritten, LastWritten,
    LabelDate, VolJobs, VolFiles, VolBlocks,
-   VolMounts, VolBytes, VolErrors, VolWrites,
+   VolMounts, VolBytes, 0, VolErrors, VolWrites,
    VolCapacityBytes, VolStatus, Recycle,
    VolRetention, VolUseDuration, MaxVolJobs,
    MaxVolFiles, MaxVolBytes, InChanger, MediaAddressing,
-   VolReadTime, VolWriteTime, 0, 0
+   VolReadTime, VolWriteTime, EndFile, EndBlock
    FROM Media;
 
 
@@ -75,6 +76,7 @@ CREATE TABLE Media (
    VolBlocks INTEGER UNSIGNED DEFAULT 0,
    VolMounts INTEGER UNSIGNED DEFAULT 0,
    VolBytes BIGINT UNSIGNED DEFAULT 0,
+   VolParts INTEGER UNSIGNED DEFAULT 0,
    VolErrors INTEGER UNSIGNED DEFAULT 0,
    VolWrites INTEGER UNSIGNED DEFAULT 0,
    VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
@@ -98,7 +100,7 @@ INSERT INTO Media (
    MediaId, VolumeName, Slot, PoolId,
    MediaType, FirstWritten, LastWritten,
    LabelDate, VolJobs, VolFiles, VolBlocks,
-   VolMounts, VolBytes, VolErrors, VolWrites,
+   VolMounts, VolBytes, VolParts, VolErrors, VolWrites,
    VolCapacityBytes, VolStatus, Recycle,
    VolRetention, VolUseDuration, MaxVolJobs,
    MaxVolFiles, MaxVolBytes,
@@ -109,19 +111,6 @@ INSERT INTO Media (
 
 DROP TABLE Media_backup;
 
-CREATE TABLE CDImages (
-   MediaId INTEGER UNSIGNED NOT NULL,
-   LastBurn DATETIME NOT NULL,
-   PRIMARY KEY (MediaId)
-   );
-
-CREATE INDEX inx9 ON File (JobId, PathId, FileNameId);
-
 COMMIT;
 
-UPDATE Filename SET Name='' WHERE Name=' ';
-
-DELETE FROM Version;
-INSERT INTO Version (VersionId) VALUES (8);
-
 END-OF-DATA
index 0c5abb76c1676857dd9358ed35a3e8eed2747932..1cacf017973dfe8bc17b6e30954ffb35b339bfca 100644 (file)
@@ -13,7 +13,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2001-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -47,7 +47,8 @@ static char Get_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s write=%d
 static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s"
 " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%" lld " VolMounts=%u"
 " VolErrors=%u VolWrites=%u MaxVolBytes=%" lld " EndTime=%d VolStatus=%10s"
-" Slot=%d relabel=%d InChanger=%d VolReadTime=%" lld " VolWriteTime=%" lld "\n";
+" Slot=%d relabel=%d InChanger=%d VolReadTime=%" lld " VolWriteTime=%" lld
+" VolParts=%u\n";
 
 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
 " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
@@ -59,7 +60,7 @@ static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u"
    " VolBlocks=%u VolBytes=%s VolMounts=%u VolErrors=%u VolWrites=%u"
    " MaxVolBytes=%s VolCapacityBytes=%s VolStatus=%s Slot=%d"
    " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s"
-   " VolWriteTime=%s EndFile=%u EndBlock=%u\n";
+   " VolWriteTime=%s EndFile=%u EndBlock=%u VolParts=%u\n";
 
 static char OK_create[] = "1000 OK CreateJobMedia\n";
 
@@ -81,7 +82,8 @@ static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr
       mr->InChanger,
       edit_uint64(mr->VolReadTime, ed4),
       edit_uint64(mr->VolWriteTime, ed5),
-      mr->EndFile, mr->EndBlock);
+      mr->EndFile, mr->EndBlock,
+      mr->VolParts);
    unbash_spaces(mr->VolumeName);
    Dmsg2(200, "Vol Info for %s: %s", jcr->Job, sd->msg);
    return stat;
@@ -111,7 +113,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       if (ok) {
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
       } else {
-        bnet_fsend(bs, "1901 No Media.\n");
+         bnet_fsend(bs, "1901 No Media.\n");
       }
 
    /*
@@ -138,18 +140,18 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
             *   and Media Type matches and Pool allows any volume.
             */
            if (mr.PoolId != jcr->PoolId) {
-              reason = "not in Pool";
+               reason = "not in Pool";
            } else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) {
-              reason = "not correct MediaType";
+               reason = "not correct MediaType";
            } else {
              /*
               * ****FIXME***
               *   This test (accept_any_volume) is turned off
-              *   because it doesn't properly check if the volume
+               *   because it doesn't properly check if the volume
               *   really is out of sequence!
               *
               * } else if (!jcr->pool->accept_any_volume) {
-              *    reason = "Volume not in sequence";
+               *    reason = "Volume not in sequence";
               */
 
               /*
@@ -166,12 +168,12 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
            send_volume_info_to_storage_daemon(jcr, bs, &mr);
         } else {
            /* Not suitable volume */
-           bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName,
+            bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName,
               mr.VolStatus, reason);
         }
 
       } else {
-        bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
+         bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
       }
 
 
@@ -184,7 +186,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes, &sdmr.VolMounts, &sdmr.VolErrors,
       &sdmr.VolWrites, &sdmr.MaxVolBytes, &sdmr.LastWritten, &sdmr.VolStatus,
       &sdmr.Slot, &label, &sdmr.InChanger, &sdmr.VolReadTime,
-      &sdmr.VolWriteTime) == 17) {
+      &sdmr.VolWriteTime, &sdmr.VolParts) == 18) {
 
       db_lock(jcr->db);
       Dmsg3(300, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
@@ -192,9 +194,9 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */
       unbash_spaces(mr.VolumeName);
       if (!db_get_media_record(jcr, jcr->db, &mr)) {
-        Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
+         Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
              mr.VolumeName, db_strerror(jcr->db));
-        bnet_fsend(bs, "1991 Catalog Request failed: %s", db_strerror(jcr->db));
+         bnet_fsend(bs, "1991 Catalog Request failed: %s", db_strerror(jcr->db));
         db_unlock(jcr->db);
         return;
       }
@@ -211,7 +213,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
          * Insanity check for VolFiles get set to a smaller value
          */
         if (sdmr.VolFiles < mr.VolFiles) {
-           Jmsg(jcr, M_ERROR, 0, _("ERROR!! Volume Files at %u being set to %u. This is probably wrong.\n"),
+            Jmsg(jcr, M_ERROR, 0, _("ERROR!! Volume Files at %u being set to %u. This is probably wrong.\n"),
               mr.VolFiles, sdmr.VolFiles);
         }
       }
@@ -229,6 +231,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       mr.InChanger    = sdmr.InChanger;
       mr.VolReadTime  = sdmr.VolReadTime;
       mr.VolWriteTime = sdmr.VolWriteTime;
+      mr.VolParts     = sdmr.VolParts;
       bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
 
       Dmsg2(300, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
@@ -241,10 +244,10 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       } else if (db_update_media_record(jcr, jcr->db, &mr)) {
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
       } else {
-        Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"),
+         Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"),
            db_strerror(jcr->db));
-        bnet_fsend(bs, "1992 Update Media error\n");
-        Dmsg0(190, "send error\n");
+         bnet_fsend(bs, "1992 Update Media error\n");
+         Dmsg0(190, "send error\n");
       }
       db_unlock(jcr->db);
 
@@ -260,11 +263,11 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
       Dmsg6(300, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n",
         jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex);
       if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) {
-        Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"),
+         Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"),
            db_strerror(jcr->db));
-        bnet_fsend(bs, "1991 Update JobMedia error\n");
+         bnet_fsend(bs, "1991 Update JobMedia error\n");
       } else {
-        Dmsg0(300, "JobMedia record created\n");
+         Dmsg0(300, "JobMedia record created\n");
         bnet_fsend(bs, OK_create);
       }
 
@@ -343,7 +346,7 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg)
       Dmsg1(120, "dird<filed: attr=%s\n", attr);
 
       if (!db_create_file_attributes_record(jcr, jcr->db, &ar)) {
-        Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
+         Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
       }
       /* Save values for SIG update */
       jcr->FileId = ar.FileId;
@@ -351,7 +354,7 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg)
    } else if (Stream == STREAM_MD5_SIGNATURE || Stream == STREAM_SHA1_SIGNATURE) {
       fname = p;
       if (jcr->FileIndex != FileIndex) {
-        Jmsg(jcr, M_WARNING, 0, "Got MD5/SHA1 but not same File as attributes\n");
+         Jmsg(jcr, M_WARNING, 0, "Got MD5/SHA1 but not same File as attributes\n");
       } else {
         /* Update signature in catalog */
         char SIGbuf[50];           /* 24 bytes should be enough */
@@ -364,9 +367,9 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg)
            type = SHA1_SIG;
         }
         bin_to_base64(SIGbuf, fname, len);
-        Dmsg3(190, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream);
+         Dmsg3(190, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream);
         if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIGbuf, type)) {
-           Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"),
+            Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"),
               db_strerror(jcr->db));
         }
       }
index 336f413d748cb8498aa9080870c5209b7fcfcead..430d0a6bec440f1d6c30bc6d1d7e9d0ea819d02e 100644 (file)
@@ -22,7 +22,7 @@
  *     Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -241,6 +241,7 @@ RES_ITEM job_items[] = {
    {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
    {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
    {"priority",   store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
+   {"writepartafterjob",   store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0},
    {NULL, NULL, NULL, 0, 0, 0}
 };
 
@@ -442,10 +443,10 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
         edit_uint64(res->res_dir.FDConnectTimeout, ed1),
         edit_uint64(res->res_dir.SDConnectTimeout, ed2));
       if (res->res_dir.query_file) {
-        sendit(sock, "   query_file=%s\n", res->res_dir.query_file);
+         sendit(sock, "   query_file=%s\n", res->res_dir.query_file);
       }
       if (res->res_dir.messages) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
       }
       break;
@@ -455,17 +456,17 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
       break;
    case R_COUNTER:
       if (res->res_counter.WrapCounter) {
-        sendit(sock, "Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n",
+         sendit(sock, "Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n",
            res->res_counter.hdr.name, res->res_counter.MinValue,
            res->res_counter.MaxValue, res->res_counter.CurrentValue,
            res->res_counter.WrapCounter->hdr.name);
       } else {
-        sendit(sock, "Counter: name=%s min=%d max=%d\n",
+         sendit(sock, "Counter: name=%s min=%d max=%d\n",
            res->res_counter.hdr.name, res->res_counter.MinValue,
            res->res_counter.MaxValue);
       }
       if (res->res_counter.Catalog) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
       }
       break;
@@ -479,7 +480,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
         edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
         res->res_client.AutoPrune);
       if (res->res_client.catalog) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
       }
       break;
@@ -500,72 +501,72 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
    case R_JOB:
    case R_JOBDEFS:
       sendit(sock, "%s: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n",
-        type == R_JOB ? "Job" : "JobDefs",
+         type == R_JOB ? "Job" : "JobDefs",
         res->res_job.hdr.name, res->res_job.JobType,
         level_to_str(res->res_job.JobLevel), res->res_job.Priority,
         res->res_job.MaxConcurrentJobs);
-      sendit(sock, "     Resched=%d Times=%d Interval=%s Spool=%d\n",
+      sendit(sock, "     Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n",
          res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
          edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
-         res->res_job.spool_data);
+         res->res_job.spool_data, res->res_job.write_part_after_job);
       if (res->res_job.client) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
       }
       if (res->res_job.fileset) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
       }
       if (res->res_job.schedule) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
       }
       if (res->res_job.RestoreWhere) {
-        sendit(sock, "  --> Where=%s\n", NPRT(res->res_job.RestoreWhere));
+         sendit(sock, "  --> Where=%s\n", NPRT(res->res_job.RestoreWhere));
       }
       if (res->res_job.RestoreBootstrap) {
-        sendit(sock, "  --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap));
+         sendit(sock, "  --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap));
       }
       if (res->res_job.RunBeforeJob) {
-        sendit(sock, "  --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob));
+         sendit(sock, "  --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob));
       }
       if (res->res_job.RunAfterJob) {
-        sendit(sock, "  --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob));
+         sendit(sock, "  --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob));
       }
       if (res->res_job.RunAfterFailedJob) {
-        sendit(sock, "  --> RunAfterFailed=%s\n", NPRT(res->res_job.RunAfterFailedJob));
+         sendit(sock, "  --> RunAfterFailed=%s\n", NPRT(res->res_job.RunAfterFailedJob));
       }
       if (res->res_job.WriteBootstrap) {
-        sendit(sock, "  --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap));
+         sendit(sock, "  --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap));
       }
       if (res->res_job.storage[0]) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         /* ***FIXME*** */
 //        dump_resource(-R_STORAGE, (RES *)res->res_job.storage, sendit, sock);
       }
       if (res->res_job.pool) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
       }
       if (res->res_job.full_pool) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
       }
       if (res->res_job.inc_pool) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
       }
       if (res->res_job.dif_pool) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
       }
       if (res->res_job.verify_job) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
       }
       break;
       if (res->res_job.messages) {
-        sendit(sock, "  --> ");
+         sendit(sock, "  --> ");
         dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
       }
       break;
@@ -577,54 +578,54 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
         INCEXE *incexe = res->res_fs.include_items[i];
         for (j=0; j<incexe->num_opts; j++) {
            FOPTS *fo = incexe->opts_list[j];
-           sendit(sock, "      O %s\n", fo->opts);
+            sendit(sock, "      O %s\n", fo->opts);
            for (k=0; k<fo->regex.size(); k++) {
-              sendit(sock, "      R %s\n", fo->regex.get(k));
+               sendit(sock, "      R %s\n", fo->regex.get(k));
            }
            for (k=0; k<fo->regexdir.size(); k++) {
-              sendit(sock, "      RD %s\n", fo->regexdir.get(k));
+               sendit(sock, "      RD %s\n", fo->regexdir.get(k));
            }
            for (k=0; k<fo->regexfile.size(); k++) {
-              sendit(sock, "      RF %s\n", fo->regexfile.get(k));
+               sendit(sock, "      RF %s\n", fo->regexfile.get(k));
            }
            for (k=0; k<fo->wild.size(); k++) {
-              sendit(sock, "      W %s\n", fo->wild.get(k));
+               sendit(sock, "      W %s\n", fo->wild.get(k));
            }
            for (k=0; k<fo->wilddir.size(); k++) {
-              sendit(sock, "      WD %s\n", fo->wilddir.get(k));
+               sendit(sock, "      WD %s\n", fo->wilddir.get(k));
            }
            for (k=0; k<fo->wildfile.size(); k++) {
-              sendit(sock, "      WF %s\n", fo->wildfile.get(k));
+               sendit(sock, "      WF %s\n", fo->wildfile.get(k));
            }
            for (k=0; k<fo->base.size(); k++) {
-              sendit(sock, "      B %s\n", fo->base.get(k));
+               sendit(sock, "      B %s\n", fo->base.get(k));
            }
            for (k=0; k<fo->fstype.size(); k++) {
-              sendit(sock, "      X %s\n", fo->fstype.get(k));
+               sendit(sock, "      X %s\n", fo->fstype.get(k));
            }
            if (fo->reader) {
-              sendit(sock, "      D %s\n", fo->reader);
+               sendit(sock, "      D %s\n", fo->reader);
            }
            if (fo->writer) {
-              sendit(sock, "      T %s\n", fo->writer);
+               sendit(sock, "      T %s\n", fo->writer);
            }
-           sendit(sock, "      N\n");
+            sendit(sock, "      N\n");
         }
         for (j=0; j<incexe->name_list.size(); j++) {
-           sendit(sock, "      I %s\n", incexe->name_list.get(j));
+            sendit(sock, "      I %s\n", incexe->name_list.get(j));
         }
         if (incexe->name_list.size()) {
-           sendit(sock, "      N\n");
+            sendit(sock, "      N\n");
         }
       }
 
       for (i=0; i<res->res_fs.num_excludes; i++) {
         INCEXE *incexe = res->res_fs.exclude_items[i];
         for (j=0; j<incexe->name_list.size(); j++) {
-           sendit(sock, "      E %s\n", incexe->name_list.get(j));
+            sendit(sock, "      E %s\n", incexe->name_list.get(j));
         }
         if (incexe->name_list.size()) {
-           sendit(sock, "      N\n");
+            sendit(sock, "      N\n");
         }
       }
       break;
@@ -634,77 +635,77 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
         int i;
         RUN *run = res->res_sch.run;
         char buf[1000], num[30];
-        sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name);
+         sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name);
         if (!run) {
            break;
         }
 next_run:
-        sendit(sock, "  --> Run Level=%s\n", level_to_str(run->level));
-        bstrncpy(buf, "      hour=", sizeof(buf));
+         sendit(sock, "  --> Run Level=%s\n", level_to_str(run->level));
+         bstrncpy(buf, "      hour=", sizeof(buf));
         for (i=0; i<24; i++) {
            if (bit_is_set(i, run->hour)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        bstrncpy(buf, "      mday=", sizeof(buf));
+         bstrncpy(buf, "      mday=", sizeof(buf));
         for (i=0; i<31; i++) {
            if (bit_is_set(i, run->mday)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        bstrncpy(buf, "      month=", sizeof(buf));
+         bstrncpy(buf, "      month=", sizeof(buf));
         for (i=0; i<12; i++) {
            if (bit_is_set(i, run->month)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        bstrncpy(buf, "      wday=", sizeof(buf));
+         bstrncpy(buf, "      wday=", sizeof(buf));
         for (i=0; i<7; i++) {
            if (bit_is_set(i, run->wday)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        bstrncpy(buf, "      wom=", sizeof(buf));
+         bstrncpy(buf, "      wom=", sizeof(buf));
         for (i=0; i<5; i++) {
            if (bit_is_set(i, run->wom)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        bstrncpy(buf, "      woy=", sizeof(buf));
+         bstrncpy(buf, "      woy=", sizeof(buf));
         for (i=0; i<54; i++) {
            if (bit_is_set(i, run->woy)) {
-              bsnprintf(num, sizeof(num), "%d ", i);
+               bsnprintf(num, sizeof(num), "%d ", i);
               bstrncat(buf, num, sizeof(buf));
            }
         }
-        bstrncat(buf, "\n", sizeof(buf));
+         bstrncat(buf, "\n", sizeof(buf));
         sendit(sock, buf);
-        sendit(sock, "      mins=%d\n", run->minute);
+         sendit(sock, "      mins=%d\n", run->minute);
         if (run->pool) {
-           sendit(sock, "     --> ");
+            sendit(sock, "     --> ");
            dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
         }
         if (run->storage) {
-           sendit(sock, "     --> ");
+            sendit(sock, "     --> ");
            dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
         }
         if (run->msgs) {
-           sendit(sock, "     --> ");
+            sendit(sock, "     --> ");
            dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
         }
         /* If another Run record is chained in, go print it */
@@ -713,7 +714,7 @@ next_run:
            goto next_run;
         }
       } else {
-        sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name);
+         sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name);
       }
       break;
    case R_POOL:
@@ -739,9 +740,9 @@ next_run:
    case R_MSGS:
       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
       if (res->res_msgs.mail_cmd)
-        sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
+         sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
       if (res->res_msgs.operator_cmd)
-        sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
+         sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
       break;
    default:
       sendit(sock, "Unknown resource type %d in dump_resource.\n", type);
@@ -996,13 +997,13 @@ void save_resource(int type, RES_ITEM *items, int pass)
       for (i=0; items[i].name; i++) {
         if (items[i].flags & ITEM_REQUIRED) {
               if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
-                 Emsg2(M_ERROR_TERM, 0, "%s item is required in %s resource, but not found.\n",
+                  Emsg2(M_ERROR_TERM, 0, "%s item is required in %s resource, but not found.\n",
                    items[i].name, resources[rindex]);
                }
         }
         /* If this triggers, take a look at lib/parse_conf.h */
         if (i >= MAX_RES_ITEMS) {
-           Emsg1(M_ERROR_TERM, 0, "Too many items in %s resource\n", resources[rindex]);
+            Emsg1(M_ERROR_TERM, 0, "Too many items in %s resource\n", resources[rindex]);
         }
       }
    }
@@ -1027,14 +1028,14 @@ void save_resource(int type, RES_ITEM *items, int pass)
       /* Resources containing another resource */
       case R_DIRECTOR:
         if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
-           Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name);
+            Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name);
         }
         res->res_dir.messages = res_all.res_dir.messages;
         break;
       case R_JOB:
       case R_JOBDEFS:
         if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
-           Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n",
+            Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n",
                  res_all.res_dir.hdr.name);
         }
         res->res_job.messages   = res_all.res_job.messages;
@@ -1053,7 +1054,7 @@ void save_resource(int type, RES_ITEM *items, int pass)
         break;
       case R_COUNTER:
         if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
-           Emsg1(M_ERROR_TERM, 0, "Cannot find Counter resource %s\n", res_all.res_counter.hdr.name);
+            Emsg1(M_ERROR_TERM, 0, "Cannot find Counter resource %s\n", res_all.res_counter.hdr.name);
         }
         res->res_counter.Catalog = res_all.res_counter.Catalog;
         res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
@@ -1061,24 +1062,24 @@ void save_resource(int type, RES_ITEM *items, int pass)
 
       case R_CLIENT:
         if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
-           Emsg1(M_ERROR_TERM, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name);
+            Emsg1(M_ERROR_TERM, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name);
         }
         res->res_client.catalog = res_all.res_client.catalog;
         break;
       case R_SCHEDULE:
         /*
          * Schedule is a bit different in that it contains a RUN record
-         * chain which isn't a "named" resource. This chain was linked
+          * chain which isn't a "named" resource. This chain was linked
          * in by run_conf.c during pass 2, so here we jam the pointer
          * into the Schedule resource.
          */
         if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
-           Emsg1(M_ERROR_TERM, 0, "Cannot find Schedule resource %s\n", res_all.res_client.hdr.name);
+            Emsg1(M_ERROR_TERM, 0, "Cannot find Schedule resource %s\n", res_all.res_client.hdr.name);
         }
         res->res_sch.run = res_all.res_sch.run;
         break;
       default:
-        Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type);
+         Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type);
         error = 1;
         break;
       }
@@ -1146,7 +1147,7 @@ void save_resource(int type, RES_ITEM *items, int pass)
       memcpy(res, &res_all, size);
       if (!res_head[rindex]) {
         res_head[rindex] = (RES *)res; /* store first entry */
-        Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
+         Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
               res->res_dir.hdr.name, rindex);
       } else {
         RES *next;
@@ -1154,12 +1155,12 @@ void save_resource(int type, RES_ITEM *items, int pass)
         for (next=res_head[rindex]; next->next; next=next->next) {
            if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
               Emsg2(M_ERROR_TERM, 0,
-                 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
+                  _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
                  resources[rindex].name, res->res_dir.hdr.name);
            }
         }
         next->next = (RES *)res;
-        Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type),
+         Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type),
               res->res_dir.hdr.name, rindex, pass);
       }
    }
@@ -1245,10 +1246,10 @@ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
       if (pass == 1) {
         if (((alist **)item->value)[item->code] == NULL) {
            ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
-           Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
+            Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
         }
         ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
-        Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
+         Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
       }
       token = lex_get_token(lc, T_ALL);
       if (token == T_COMMA) {
index 779fe50335c474f0c10aa19dae1d38a48de5907d..084257de233b8a0453e9344dc18c52bd3c08cb5b 100644 (file)
@@ -6,7 +6,7 @@
  *    Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -44,7 +44,7 @@ enum {
    R_CONSOLE,
    R_JOBDEFS,
    R_FIRST = R_DIRECTOR,
-   R_LAST  = R_JOBDEFS                /* keep this updated */
+   R_LAST  = R_JOBDEFS               /* keep this updated */
 };
 
 
@@ -68,9 +68,9 @@ struct s_kw {
 
 /* Job Level keyword structure */
 struct s_jl {
-   const char *level_name;                  /* level keyword */
-   int  level;                        /* level */
-   int  job_type;                     /* JobType permitting this level */
+   const char *level_name;                 /* level keyword */
+   int level;                        /* level */
+   int job_type;                     /* JobType permitting this level */
 };
 
 /* Job Type keyword structure */
@@ -92,20 +92,20 @@ struct RUN;
  *
  */
 struct DIRRES {
-   RES   hdr;
+   RES  hdr;
    dlist *DIRaddrs;
-   char *password;                    /* Password for UA access */
-   int enable_ssl;                    /* Use SSL for UA */
-   char *query_file;                  /* SQL query file */
-   char *working_directory;           /* WorkingDirectory */
+   char *password;                   /* Password for UA access */
+   int enable_ssl;                   /* Use SSL for UA */
+   char *query_file;                 /* SQL query file */
+   char *working_directory;          /* WorkingDirectory */
    const char *scripts_directory;     /* ScriptsDirectory */
-   char *pid_directory;               /* PidDirectory */
-   char *subsys_directory;            /* SubsysDirectory */
-   int require_ssl;                   /* Require SSL for all connections */
-   MSGS *messages;                    /* Daemon message handler */
-   uint32_t MaxConcurrentJobs;        /* Max concurrent jobs for whole director */
-   utime_t FDConnectTimeout;          /* timeout for connect in seconds */
-   utime_t SDConnectTimeout;          /* timeout in seconds */
+   char *pid_directory;              /* PidDirectory */
+   char *subsys_directory;           /* SubsysDirectory */
+   int require_ssl;                  /* Require SSL for all connections */
+   MSGS *messages;                   /* Daemon message handler */
+   uint32_t MaxConcurrentJobs;       /* Max concurrent jobs for whole director */
+   utime_t FDConnectTimeout;         /* timeout for connect in seconds */
+   utime_t SDConnectTimeout;         /* timeout in seconds */
 };
 
 
@@ -122,17 +122,17 @@ enum {
    Command_ACL,
    FileSet_ACL,
    Catalog_ACL,
-   Num_ACL                            /* keep last */
+   Num_ACL                           /* keep last */
 };
 
 /*
  *    Console Resource
  */
 struct CONRES {
-   RES   hdr;
-   char *password;                    /* UA server password */
-   int enable_ssl;                    /* Use SSL */
-   alist *ACL_lists[Num_ACL];         /* pointers to ACLs */
+   RES  hdr;
+   char *password;                   /* UA server password */
+   int enable_ssl;                   /* Use SSL */
+   alist *ACL_lists[Num_ACL];        /* pointers to ACLs */
 };
 
 
@@ -141,15 +141,15 @@ struct CONRES {
  *
  */
 struct CAT {
-   RES   hdr;
+   RES  hdr;
 
-   int   db_port;                     /* Port -- not yet implemented */
-   char *db_address;                  /* host name for remote access */
-   char *db_socket;                   /* Socket for local access */
+   int  db_port;                     /* Port -- not yet implemented */
+   char *db_address;                 /* host name for remote access */
+   char *db_socket;                  /* Socket for local access */
    char *db_password;
    char *db_user;
    char *db_name;
-   int   mult_db_connections;         /* set if multiple connections wanted */
+   int  mult_db_connections;         /* set if multiple connections wanted */
 };
 
 
@@ -158,18 +158,18 @@ struct CAT {
  *
  */
 struct CLIENT {
-   RES   hdr;
+   RES  hdr;
 
-   int   FDport;                      /* Where File daemon listens */
-   int   AutoPrune;                   /* Do automatic pruning? */
-   utime_t FileRetention;             /* file retention period in seconds */
-   utime_t JobRetention;              /* job retention period in seconds */
+   int  FDport;                      /* Where File daemon listens */
+   int  AutoPrune;                   /* Do automatic pruning? */
+   utime_t FileRetention;            /* file retention period in seconds */
+   utime_t JobRetention;             /* job retention period in seconds */
    char *address;
    char *password;
-   CAT *catalog;                      /* Catalog resource */
-   uint32_t MaxConcurrentJobs;        /* Maximume concurrent jobs */
-   uint32_t NumConcurrentJobs;        /* number of concurrent jobs running */
-   int enable_ssl;                    /* Use SSL */
+   CAT *catalog;                     /* Catalog resource */
+   uint32_t MaxConcurrentJobs;       /* Maximume concurrent jobs */
+   uint32_t NumConcurrentJobs;       /* number of concurrent jobs running */
+   int enable_ssl;                   /* Use SSL */
 };
 
 /*
@@ -177,97 +177,98 @@ struct CLIENT {
  *
  */
 struct STORE {
-   RES   hdr;
+   RES  hdr;
 
-   int   SDport;                      /* port where Directors connect */
-   int   SDDport;                     /* data port for File daemon */
+   int  SDport;                      /* port where Directors connect */
+   int  SDDport;                     /* data port for File daemon */
    char *address;
    char *password;
    char *media_type;
    char *dev_name;
-   int  autochanger;                  /* set if autochanger */
-   uint32_t MaxConcurrentJobs;        /* Maximume concurrent jobs */
-   uint32_t NumConcurrentJobs;        /* number of concurrent jobs running */
-   int enable_ssl;                    /* Use SSL */
+   int autochanger;                  /* set if autochanger */
+   uint32_t MaxConcurrentJobs;       /* Maximume concurrent jobs */
+   uint32_t NumConcurrentJobs;       /* number of concurrent jobs running */
+   int enable_ssl;                   /* Use SSL */
 };
 
 
-#define MAX_STORE 2                   /* Max storage directives in Job */
+#define MAX_STORE 2                  /* Max storage directives in Job */
 
 /*
  *   Job Resource
  */
 struct JOB {
-   RES   hdr;
-
-   int   JobType;                     /* job type (backup, verify, restore */
-   int   JobLevel;                    /* default backup/verify level */
-   int   Priority;                    /* Job priority */
-   int   RestoreJobId;                /* What -- JobId to restore */
-   char *RestoreWhere;                /* Where on disk to restore -- directory */
-   char *RestoreBootstrap;            /* Bootstrap file */
-   char *RunBeforeJob;                /* Run program before Job */
-   char *RunAfterJob;                 /* Run program after Job */
-   char *RunAfterFailedJob;           /* Run program after Job that errs */
-   char *ClientRunBeforeJob;          /* Run client program before Job */
-   char *ClientRunAfterJob;           /* Run client program after Job */
-   char *WriteBootstrap;              /* Where to write bootstrap Job updates */
-   int   replace;                     /* How (overwrite, ..) */
-   utime_t MaxRunTime;                /* max run time in seconds */
-   utime_t MaxWaitTime;               /* max blocking time in seconds */
-   utime_t MaxStartDelay;             /* max start delay in seconds */
-   int PrefixLinks;                   /* prefix soft links with Where path */
-   int PruneJobs;                     /* Force pruning of Jobs */
-   int PruneFiles;                    /* Force pruning of Files */
-   int PruneVolumes;                  /* Force pruning of Volumes */
-   int SpoolAttributes;               /* Set to spool attributes in SD */
-   int spool_data;                    /* Set to spool data in SD */
-   int rerun_failed_levels;           /* Upgrade to rerun failed levels */
-   uint32_t MaxConcurrentJobs;        /* Maximume concurrent jobs */
-   int RescheduleOnError;             /* Set to reschedule on error */
-   int RescheduleTimes;               /* Number of times to reschedule job */
-   utime_t RescheduleInterval;        /* Reschedule interval */
-   utime_t JobRetention;              /* job retention period in seconds */
-
-   MSGS      *messages;               /* How and where to send messages */
-   SCHED     *schedule;               /* When -- Automatic schedule */
-   CLIENT    *client;                 /* Who to backup */
-   FILESET   *fileset;                /* What to backup -- Fileset */
+   RES  hdr;
+
+   int  JobType;                     /* job type (backup, verify, restore */
+   int  JobLevel;                    /* default backup/verify level */
+   int  Priority;                    /* Job priority */
+   int  RestoreJobId;                /* What -- JobId to restore */
+   char *RestoreWhere;               /* Where on disk to restore -- directory */
+   char *RestoreBootstrap;           /* Bootstrap file */
+   char *RunBeforeJob;               /* Run program before Job */
+   char *RunAfterJob;                /* Run program after Job */
+   char *RunAfterFailedJob;          /* Run program after Job that errs */
+   char *ClientRunBeforeJob;         /* Run client program before Job */
+   char *ClientRunAfterJob;          /* Run client program after Job */
+   char *WriteBootstrap;             /* Where to write bootstrap Job updates */
+   int  replace;                     /* How (overwrite, ..) */
+   utime_t MaxRunTime;               /* max run time in seconds */
+   utime_t MaxWaitTime;              /* max blocking time in seconds */
+   utime_t MaxStartDelay;            /* max start delay in seconds */
+   int PrefixLinks;                  /* prefix soft links with Where path */
+   int PruneJobs;                    /* Force pruning of Jobs */
+   int PruneFiles;                   /* Force pruning of Files */
+   int PruneVolumes;                 /* Force pruning of Volumes */
+   int SpoolAttributes;              /* Set to spool attributes in SD */
+   int spool_data;                   /* Set to spool data in SD */
+   int rerun_failed_levels;          /* Upgrade to rerun failed levels */
+   uint32_t MaxConcurrentJobs;       /* Maximume concurrent jobs */
+   int RescheduleOnError;            /* Set to reschedule on error */
+   int RescheduleTimes;              /* Number of times to reschedule job */
+   utime_t RescheduleInterval;       /* Reschedule interval */
+   utime_t JobRetention;             /* job retention period in seconds */
+   bool write_part_after_job;        /* Set to write part after job in SD */
+   
+   MSGS      *messages;              /* How and where to send messages */
+   SCHED     *schedule;              /* When -- Automatic schedule */
+   CLIENT    *client;                /* Who to backup */
+   FILESET   *fileset;               /* What to backup -- Fileset */
    alist     *storage[MAX_STORE];     /* Where is device -- Storage daemon */
-   POOL      *pool;                   /* Where is media -- Media Pool */
-   POOL      *full_pool;              /* Pool for Full backups */
-   POOL      *inc_pool;               /* Pool for Incremental backups */
-   POOL      *dif_pool;               /* Pool for Differental backups */
-   JOB       *verify_job;             /* Job name to verify */
-   JOB       *jobdefs;                /* Job defaults */
-   uint32_t NumConcurrentJobs;        /* number of concurrent jobs running */
+   POOL      *pool;                  /* Where is media -- Media Pool */
+   POOL      *full_pool;             /* Pool for Full backups */
+   POOL      *inc_pool;              /* Pool for Incremental backups */
+   POOL      *dif_pool;              /* Pool for Differental backups */
+   JOB      *verify_job;             /* Job name to verify */
+   JOB      *jobdefs;                /* Job defaults */
+   uint32_t NumConcurrentJobs;       /* number of concurrent jobs running */
 };
 
-#undef  MAX_FOPTS
+#undef MAX_FOPTS
 #define MAX_FOPTS 34
 
 /* File options structure */
 struct FOPTS {
-   char opts[MAX_FOPTS];              /* options string */
-   alist regex;                       /* regex string(s) */
-   alist regexdir;                    /* regex string(s) for directories */
-   alist regexfile;                   /* regex string(s) for files */
-   alist wild;                        /* wild card strings */
-   alist wilddir;                     /* wild card strings for directories */
-   alist wildfile;                    /* wild card strings for files */
-   alist base;                        /* list of base names */
-   alist fstype;                      /* file system type limitation */
-   char *reader;                      /* reader program */
-   char *writer;                      /* writer program */
+   char opts[MAX_FOPTS];             /* options string */
+   alist regex;                      /* regex string(s) */
+   alist regexdir;                   /* regex string(s) for directories */
+   alist regexfile;                  /* regex string(s) for files */
+   alist wild;                       /* wild card strings */
+   alist wilddir;                    /* wild card strings for directories */
+   alist wildfile;                   /* wild card strings for files */
+   alist base;                       /* list of base names */
+   alist fstype;                     /* file system type limitation */
+   char *reader;                     /* reader program */
+   char *writer;                     /* writer program */
 };
 
 
 /* This is either an include item or an exclude item */
 struct INCEXE {
-   FOPTS *current_opts;               /* points to current options structure */
-   FOPTS **opts_list;                 /* options list */
-   int num_opts;                      /* number of options items */
-   alist name_list;                   /* filename list -- holds char * */
+   FOPTS *current_opts;              /* points to current options structure */
+   FOPTS **opts_list;                /* options list */
+   int num_opts;                     /* number of options items */
+   alist name_list;                  /* filename list -- holds char * */
 };
 
 /*
@@ -275,16 +276,16 @@ struct INCEXE {
  *
  */
 struct FILESET {
-   RES   hdr;
+   RES  hdr;
 
-   bool new_include;                  /* Set if new include used */
-   INCEXE **include_items;            /* array of incexe structures */
-   int num_includes;                  /* number in array */
+   bool new_include;                 /* Set if new include used */
+   INCEXE **include_items;           /* array of incexe structures */
+   int num_includes;                 /* number in array */
    INCEXE **exclude_items;
    int num_excludes;
-   bool have_MD5;                     /* set if MD5 initialized */
-   struct MD5Context md5c;            /* MD5 of include/exclude */
-   char MD5[30];                      /* base 64 representation of MD5 */
+   bool have_MD5;                    /* set if MD5 initialized */
+   struct MD5Context md5c;           /* MD5 of include/exclude */
+   char MD5[30];                     /* base 64 representation of MD5 */
    int ignore_fs_changes;             /* Don't force Full if FS changed */
 };
 
@@ -294,7 +295,7 @@ struct FILESET {
  *
  */
 struct SCHED {
-   RES   hdr;
+   RES  hdr;
 
    RUN *run;
 };
@@ -303,14 +304,14 @@ struct SCHED {
  *   Counter Resource
  */
 struct COUNTER {
-   RES   hdr;
-
-   int32_t  MinValue;                 /* Minimum value */
-   int32_t  MaxValue;                 /* Maximum value */
-   int32_t  CurrentValue;             /* Current value */
-   COUNTER *WrapCounter;              /* Wrap counter name */
-   CAT     *Catalog;                  /* Where to store */
-   bool     created;                  /* Created in DB */
+   RES  hdr;
+
+   int32_t  MinValue;                /* Minimum value */
+   int32_t  MaxValue;                /* Maximum value */
+   int32_t  CurrentValue;            /* Current value */
+   COUNTER *WrapCounter;             /* Wrap counter name */
+   CAT    *Catalog;                  /* Where to store */
+   bool     created;                 /* Created in DB */
 };
 
 /*
@@ -318,26 +319,26 @@ struct COUNTER {
  *
  */
 struct POOL {
-   RES   hdr;
-
-   char *pool_type;                   /* Pool type */
-   char *label_format;                /* Label format string */
-   char *cleaning_prefix;             /* Cleaning label prefix */
-   int   use_catalog;                 /* maintain catalog for media */
-   int   catalog_files;               /* maintain file entries in catalog */
-   int   use_volume_once;             /* write on volume only once */
-   int   accept_any_volume;           /* accept any volume */
-   int   purge_oldest_volume;         /* purge oldest volume */
-   int   recycle_oldest_volume;       /* attempt to recycle oldest volume */
-   int   recycle_current_volume;      /* attempt recycle of current volume */
-   uint32_t max_volumes;              /* max number of volumes */
-   utime_t VolRetention;              /* volume retention period in seconds */
-   utime_t VolUseDuration;            /* duration volume can be used */
-   uint32_t MaxVolJobs;               /* Maximum jobs on the Volume */
-   uint32_t MaxVolFiles;              /* Maximum files on the Volume */
-   uint64_t MaxVolBytes;              /* Maximum bytes on the Volume */
-   int   AutoPrune;                   /* default for pool auto prune */
-   int   Recycle;                     /* default for media recycle yes/no */
+   RES  hdr;
+
+   char *pool_type;                  /* Pool type */
+   char *label_format;               /* Label format string */
+   char *cleaning_prefix;            /* Cleaning label prefix */
+   int  use_catalog;                 /* maintain catalog for media */
+   int  catalog_files;               /* maintain file entries in catalog */
+   int  use_volume_once;             /* write on volume only once */
+   int  accept_any_volume;           /* accept any volume */
+   int  purge_oldest_volume;         /* purge oldest volume */
+   int  recycle_oldest_volume;       /* attempt to recycle oldest volume */
+   int  recycle_current_volume;      /* attempt recycle of current volume */
+   uint32_t max_volumes;             /* max number of volumes */
+   utime_t VolRetention;             /* volume retention period in seconds */
+   utime_t VolUseDuration;           /* duration volume can be used */
+   uint32_t MaxVolJobs;              /* Maximum jobs on the Volume */
+   uint32_t MaxVolFiles;             /* Maximum files on the Volume */
+   uint64_t MaxVolBytes;             /* Maximum bytes on the Volume */
+   int  AutoPrune;                   /* default for pool auto prune */
+   int  Recycle;                     /* default for media recycle yes/no */
 };
 
 
@@ -349,37 +350,40 @@ union URES {
    CONRES     res_con;
    CLIENT     res_client;
    STORE      res_store;
-   CAT        res_cat;
-   JOB        res_job;
+   CAT       res_cat;
+   JOB       res_job;
    FILESET    res_fs;
    SCHED      res_sch;
    POOL       res_pool;
    MSGS       res_msgs;
    COUNTER    res_counter;
-   RES        hdr;
+   RES       hdr;
 };
 
 
 
 /* Run structure contained in Schedule Resource */
 struct RUN {
-   RUN *next;                         /* points to next run record */
-   int level;                         /* level override */
-   int Priority;                      /* priority override */
+   RUN *next;                        /* points to next run record */
+   int level;                        /* level override */
+   int Priority;                     /* priority override */
    int job_type;
-   bool spool_data;                   /* Data spooling override */
-   bool spool_data_set;               /* Data spooling override given */
-   POOL *pool;                        /* Pool override */
-   POOL *full_pool;                   /* Pool override */
-   POOL *inc_pool;                    /* Pool override */
-   POOL *dif_pool;                    /* Pool override */
-   STORE *storage;                    /* Storage override */
-   MSGS *msgs;                        /* Messages override */
+   bool spool_data;                  /* Data spooling override */
+   bool spool_data_set;              /* Data spooling override given */
+   bool write_part_after_job;        /* Write part after job override */
+   bool write_part_after_job_set;     /* Write part after job override given */
+   
+   POOL *pool;                       /* Pool override */
+   POOL *full_pool;                  /* Pool override */
+   POOL *inc_pool;                   /* Pool override */
+   POOL *dif_pool;                   /* Pool override */
+   STORE *storage;                   /* Storage override */
+   MSGS *msgs;                       /* Messages override */
    char *since;
    int level_no;
-   int minute;                        /* minute to run job */
-   time_t last_run;                   /* last time run */
-   time_t next_run;                   /* next time to run */
+   int minute;                       /* minute to run job */
+   time_t last_run;                  /* last time run */
+   time_t next_run;                  /* next time to run */
    char hour[nbytes_for_bits(24)];    /* bit set for each hour */
    char mday[nbytes_for_bits(31)];    /* bit set for each day of month */
    char month[nbytes_for_bits(12)];   /* bit set for each month */
index 1c9e38950203ba5bc159ab396e3612a80816766d..e4be6d4c3657cb237c58a68c5e2ed31b0de81ed9 100644 (file)
@@ -13,7 +13,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -78,7 +78,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time,
 
    if (!jcr->file_bsock) {
       fd = bnet_connect(jcr, retry_interval, max_retry_time,
-          _("File daemon"), jcr->client->address,
+           _("File daemon"), jcr->client->address,
           NULL, jcr->client->FDport, verbose);
       if (fd == NULL) {
         set_jcr_job_status(jcr, JS_ErrorTerminated);
@@ -109,7 +109,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time,
    if (bget_dirmsg(fd) > 0) {
        Dmsg1(110, "<filed: %s", fd->msg);
        if (strncmp(fd->msg, OKjob, strlen(OKjob)) != 0) {
-         Jmsg(jcr, M_FATAL, 0, _("File daemon \"%s\" rejected Job command: %s\n"),
+          Jmsg(jcr, M_FATAL, 0, _("File daemon \"%s\" rejected Job command: %s\n"),
             jcr->client->hdr.name, fd->msg);
          set_jcr_job_status(jcr, JS_ErrorTerminated);
          return 0;
@@ -122,7 +122,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time,
          cr.JobRetention = jcr->client->JobRetention;
          bstrncpy(cr.Uname, fd->msg+strlen(OKjob)+1, sizeof(cr.Uname));
          if (!db_update_client_record(jcr, jcr->db, &cr)) {
-            Jmsg(jcr, M_WARNING, 0, _("Error updating Client record. ERR=%s\n"),
+             Jmsg(jcr, M_WARNING, 0, _("Error updating Client record. ERR=%s\n"),
                db_strerror(jcr->db));
          }
        }
@@ -160,24 +160,24 @@ void get_level_since_time(JCR *jcr, char *since, int since_len)
       jcr->jr.JobId = 0;     /* flag for db_find_job_start time */
       if (!db_find_job_start_time(jcr, jcr->db, &jcr->jr, &jcr->stime)) {
         /* No job found, so upgrade this one to Full */
-        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)",
+         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.JobLevel = L_FULL;
       } else {
         if (jcr->job->rerun_failed_levels) {
            if (db_find_failed_job_since(jcr, jcr->db, &jcr->jr, jcr->stime, JobLevel)) {
-              Jmsg(jcr, M_INFO, 0, _("Prior failed job found. Upgrading to %s.\n"),
+               Jmsg(jcr, M_INFO, 0, _("Prior failed job found. Upgrading to %s.\n"),
                  level_to_str(JobLevel));
-              bsnprintf(since, since_len, " (upgraded from %s)",
+               bsnprintf(since, since_len, " (upgraded from %s)",
                  level_to_str(jcr->JobLevel));
               jcr->JobLevel = jcr->jr.JobLevel = JobLevel;
               jcr->jr.JobId = jcr->JobId;
               break;
            }
         }
-        bstrncpy(since, ", since=", since_len);
+         bstrncpy(since, ", since=", since_len);
         bstrncat(since, jcr->stime, since_len);
       }
       jcr->jr.JobId = jcr->JobId;
@@ -213,7 +213,7 @@ int send_level_command(JCR *jcr)
       stime = str_to_utime(jcr->stime);
       bnet_fsend(fd, levelcmd, "since_utime ", edit_uint64(stime, ed1), 0);
       while (bget_dirmsg(fd) >= 0) {  /* allow him to poll us to sync clocks */
-        Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg);
+         Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg);
       }
       break;
    case L_SINCE:
@@ -265,80 +265,80 @@ static int send_list(JCR *jcr, int list)
       for (int j=0; j<ie->name_list.size(); j++) {
         p = (char *)ie->name_list.get(j);
         switch (*p) {
-        case '|':
+         case '|':
            p++;                      /* skip over the | */
-           fd->msg = edit_job_codes(jcr, fd->msg, p, "");
-           bpipe = open_bpipe(fd->msg, 0, "r");
+            fd->msg = edit_job_codes(jcr, fd->msg, p, "");
+            bpipe = open_bpipe(fd->msg, 0, "r");
            if (!bpipe) {
               berrno be;
-              Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
+               Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
                  p, be.strerror());
               goto bail_out;
            }
            /* Copy File options */
            if (ie->num_opts) {
               bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf));
-              bstrncat(buf, " ", sizeof(buf));
+               bstrncat(buf, " ", sizeof(buf));
            } else {
-              bstrncpy(buf, "0 ", sizeof(buf));
+               bstrncpy(buf, "0 ", sizeof(buf));
            }
-           Dmsg1(500, "Opts=%s\n", buf);
+            Dmsg1(500, "Opts=%s\n", buf);
            optlen = strlen(buf);
            while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) {
-              fd->msglen = Mmsg(fd->msg, "%s", buf);
-              Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg);
+               fd->msglen = Mmsg(fd->msg, "%s", buf);
+               Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg);
               if (!bnet_send(fd)) {
-                 Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+                  Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
                  goto bail_out;
               }
            }
            if ((stat=close_bpipe(bpipe)) != 0) {
               berrno be;
-              Jmsg(jcr, M_FATAL, 0, _("Error running program %p: ERR=%s\n"),
+               Jmsg(jcr, M_FATAL, 0, _("Error running program %p: ERR=%s\n"),
                  p, be.strerror(stat));
               goto bail_out;
            }
            break;
-        case '<':
+         case '<':
            p++;                      /* skip over < */
-           if ((ffd = fopen(p, "r")) == NULL) {
-              Jmsg(jcr, M_FATAL, 0, _("Cannot open %s file: %s. ERR=%s\n"),
-                 list==INC_LIST?"included":"excluded", p, strerror(errno));
+            if ((ffd = fopen(p, "r")) == NULL) {
+               Jmsg(jcr, M_FATAL, 0, _("Cannot open %s file: %s. ERR=%s\n"),
+                  list==INC_LIST?"included":"excluded", p, strerror(errno));
               goto bail_out;
            }
            /* Copy File options */
            if (ie->num_opts) {
               bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf));
-              bstrncat(buf, " ", sizeof(buf));
+               bstrncat(buf, " ", sizeof(buf));
            } else {
-              bstrncpy(buf, "0 ", sizeof(buf));
+               bstrncpy(buf, "0 ", sizeof(buf));
            }
-           Dmsg1(500, "Opts=%s\n", buf);
+            Dmsg1(500, "Opts=%s\n", buf);
            optlen = strlen(buf);
            while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) {
-              fd->msglen = Mmsg(fd->msg, "%s", buf);
+               fd->msglen = Mmsg(fd->msg, "%s", buf);
               if (!bnet_send(fd)) {
-                 Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+                  Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
                  goto bail_out;
               }
            }
            fclose(ffd);
            break;
-        case '\\':
-           p++;                      /* skip over \ */
+         case '\\':
+            p++;                      /* skip over \ */
            /* Note, fall through wanted */
         default:
            if (ie->num_opts) {
-              Dmsg2(500, "numopts=%d opts=%s\n", ie->num_opts, NPRT(ie->opts_list[0]->opts));
+               Dmsg2(500, "numopts=%d opts=%s\n", ie->num_opts, NPRT(ie->opts_list[0]->opts));
               pm_strcpy(fd->msg, ie->opts_list[0]->opts);
-              pm_strcat(fd->msg, " ");
+               pm_strcat(fd->msg, " ");
            } else {
-              pm_strcpy(fd->msg, "0 ");
+               pm_strcpy(fd->msg, "0 ");
            }
            fd->msglen = pm_strcat(fd->msg, p);
-           Dmsg1(500, "Inc/Exc name=%s\n", fd->msg);
+            Dmsg1(500, "Inc/Exc name=%s\n", fd->msg);
            if (!bnet_send(fd)) {
-              Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+               Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
               goto bail_out;
            }
            break;
@@ -389,113 +389,113 @@ static int send_fileset(JCR *jcr)
 
         if (include) {
            ie = fileset->include_items[i];
-           bnet_fsend(fd, "I\n");
+            bnet_fsend(fd, "I\n");
         } else {
            ie = fileset->exclude_items[i];
-           bnet_fsend(fd, "E\n");
+            bnet_fsend(fd, "E\n");
         }
         for (j=0; j<ie->num_opts; j++) {
            FOPTS *fo = ie->opts_list[j];
-           bnet_fsend(fd, "O %s\n", fo->opts);
+            bnet_fsend(fd, "O %s\n", fo->opts);
            for (k=0; k<fo->regex.size(); k++) {
-              bnet_fsend(fd, "R %s\n", fo->regex.get(k));
+               bnet_fsend(fd, "R %s\n", fo->regex.get(k));
            }
            for (k=0; k<fo->regexdir.size(); k++) {
-              bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
+               bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
            }
            for (k=0; k<fo->regexfile.size(); k++) {
-              bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
+               bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
            }
            for (k=0; k<fo->wild.size(); k++) {
-              bnet_fsend(fd, "W %s\n", fo->wild.get(k));
+               bnet_fsend(fd, "W %s\n", fo->wild.get(k));
            }
            for (k=0; k<fo->wilddir.size(); k++) {
-              bnet_fsend(fd, "WD %s\n", fo->wilddir.get(k));
+               bnet_fsend(fd, "WD %s\n", fo->wilddir.get(k));
            }
            for (k=0; k<fo->wildfile.size(); k++) {
-              bnet_fsend(fd, "WF %s\n", fo->wildfile.get(k));
+               bnet_fsend(fd, "WF %s\n", fo->wildfile.get(k));
            }
            for (k=0; k<fo->base.size(); k++) {
-              bnet_fsend(fd, "B %s\n", fo->base.get(k));
+               bnet_fsend(fd, "B %s\n", fo->base.get(k));
            }
            for (k=0; k<fo->fstype.size(); k++) {
-              bnet_fsend(fd, "X %s\n", fo->fstype.get(k));
+               bnet_fsend(fd, "X %s\n", fo->fstype.get(k));
            }
            if (fo->reader) {
-              bnet_fsend(fd, "D %s\n", fo->reader);
+               bnet_fsend(fd, "D %s\n", fo->reader);
            }
            if (fo->writer) {
-              bnet_fsend(fd, "T %s\n", fo->writer);
+               bnet_fsend(fd, "T %s\n", fo->writer);
            }
-           bnet_fsend(fd, "N\n");
+            bnet_fsend(fd, "N\n");
         }
 
         for (j=0; j<ie->name_list.size(); j++) {
            p = (char *)ie->name_list.get(j);
            switch (*p) {
-           case '|':
+            case '|':
               p++;                      /* skip over the | */
-              fd->msg = edit_job_codes(jcr, fd->msg, p, "");
-              bpipe = open_bpipe(fd->msg, 0, "r");
+               fd->msg = edit_job_codes(jcr, fd->msg, p, "");
+               bpipe = open_bpipe(fd->msg, 0, "r");
               if (!bpipe) {
                  berrno be;
-                 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
+                  Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
                     p, be.strerror());
                  goto bail_out;
               }
-              bstrncpy(buf, "F ", sizeof(buf));
-              Dmsg1(500, "Opts=%s\n", buf);
+               bstrncpy(buf, "F ", sizeof(buf));
+               Dmsg1(500, "Opts=%s\n", buf);
               optlen = strlen(buf);
               while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) {
-                 fd->msglen = Mmsg(fd->msg, "%s", buf);
-                 Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg);
+                  fd->msglen = Mmsg(fd->msg, "%s", buf);
+                  Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg);
                  if (!bnet_send(fd)) {
-                    Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+                     Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
                     goto bail_out;
                  }
               }
               if ((stat=close_bpipe(bpipe)) != 0) {
                  berrno be;
-                 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. ERR=%s\n"),
+                  Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. ERR=%s\n"),
                     p, be.strerror(stat));
                  goto bail_out;
               }
               break;
-           case '<':
+            case '<':
               p++;                      /* skip over < */
-              if ((ffd = fopen(p, "r")) == NULL) {
+               if ((ffd = fopen(p, "r")) == NULL) {
                  berrno be;
-                 Jmsg(jcr, M_FATAL, 0, _("Cannot open included file: %s. ERR=%s\n"),
+                  Jmsg(jcr, M_FATAL, 0, _("Cannot open included file: %s. ERR=%s\n"),
                     p, be.strerror());
                  goto bail_out;
               }
-              bstrncpy(buf, "F ", sizeof(buf));
-              Dmsg1(500, "Opts=%s\n", buf);
+               bstrncpy(buf, "F ", sizeof(buf));
+               Dmsg1(500, "Opts=%s\n", buf);
               optlen = strlen(buf);
               while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) {
-                 fd->msglen = Mmsg(fd->msg, "%s", buf);
+                  fd->msglen = Mmsg(fd->msg, "%s", buf);
                  if (!bnet_send(fd)) {
-                    Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+                     Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
                     goto bail_out;
                  }
               }
               fclose(ffd);
               break;
-           case '\\':
-              p++;                      /* skip over \ */
+            case '\\':
+               p++;                      /* skip over \ */
               /* Note, fall through wanted */
            default:
-              pm_strcpy(fd->msg, "F ");
+               pm_strcpy(fd->msg, "F ");
               fd->msglen = pm_strcat(fd->msg, p);
-              Dmsg1(500, "Inc/Exc name=%s\n", fd->msg);
+               Dmsg1(500, "Inc/Exc name=%s\n", fd->msg);
               if (!bnet_send(fd)) {
-                 Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
+                  Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
                  goto bail_out;
               }
               break;
            }
         }
-        bnet_fsend(fd, "N\n");
+         bnet_fsend(fd, "N\n");
       }
       if (!include) {                /* If we just did excludes */
         break;                       /*   all done */
@@ -645,7 +645,7 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
 
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
       if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_SIG)) != 3) {
-        Jmsg(jcr, M_FATAL, 0, _("<filed: bad attributes, expected 3 fields got %d\n"
+         Jmsg(jcr, M_FATAL, 0, _("<filed: bad attributes, expected 3 fields got %d\n"
 "msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
         set_jcr_job_status(jcr, JS_ErrorTerminated);
         return 0;
@@ -677,27 +677,27 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
         ar.PathId = 0;
         ar.FilenameId = 0;
 
-        Dmsg2(111, "dird<filed: stream=%d %s\n", stream, jcr->fname);
-        Dmsg1(120, "dird<filed: attr=%s\n", attr);
+         Dmsg2(111, "dird<filed: stream=%d %s\n", stream, jcr->fname);
+         Dmsg1(120, "dird<filed: attr=%s\n", attr);
 
         if (!db_create_file_attributes_record(jcr, jcr->db, &ar)) {
-           Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+            Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
            set_jcr_job_status(jcr, JS_Error);
            continue;
         }
         jcr->FileId = ar.FileId;
       } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
         if (jcr->FileIndex != (uint32_t)file_index) {
-           Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
+            Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
               file_index, jcr->FileIndex);
            set_jcr_job_status(jcr, JS_Error);
            continue;
         }
         db_escape_string(SIG, Opts_SIG, strlen(Opts_SIG));
-        Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG);
+         Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG);
         if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIG,
                   stream==STREAM_MD5_SIGNATURE?MD5_SIG:SHA1_SIG)) {
-           Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+            Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
            set_jcr_job_status(jcr, JS_Error);
         }
       }
index d1ec4bb8ca321493923471a2853491ee198b8b11..6f30607143a22f597f92144c351d28e12bda7eed 100644 (file)
@@ -7,7 +7,7 @@
  *     Version $Id$
  */
 /*
-   Copyright (C) 2003-2004 Kern Sibbald
+   Copyright (C) 2003-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -497,15 +497,15 @@ static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass)
         }
         regfree(&preg);
         if (item->code == 1) {
-           type = "regexdir";
+            type = "regexdir";
            res_incexe.current_opts->regexdir.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->regexdir.size();
         } else if (item->code == 2) {
-           type = "regexfile";
+            type = "regexfile";
            res_incexe.current_opts->regexfile.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->regexfile.size();
         } else {
-           type = "regex";
+            type = "regex";
            res_incexe.current_opts->regex.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->regex.size();
         }
@@ -583,15 +583,15 @@ static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass)
       case T_UNQUOTED_STRING:
       case T_QUOTED_STRING:
         if (item->code == 1) {
-           type = "wilddir";
+            type = "wilddir";
            res_incexe.current_opts->wilddir.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->wilddir.size();
         } else if (item->code == 2) {
-           type = "wildfile";
+            type = "wildfile";
            res_incexe.current_opts->wildfile.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->wildfile.size();
         } else {
-           type = "wild";
+            type = "wild";
            res_incexe.current_opts->wild.append(bstrdup(lc->str));
            newsize = res_incexe.current_opts->wild.size();
         }
index 44d14fec75b8b9159ffda519f27eb5a28ebaebf4..de88b1e9141efe930dcaa540d74fe9899b298b18 100644 (file)
@@ -7,7 +7,7 @@
  *    Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -786,6 +786,7 @@ void set_jcr_defaults(JCR *jcr, JOB *job)
    jcr->fileset = job->fileset;
    jcr->messages = job->messages;
    jcr->spool_data = job->spool_data;
+   jcr->write_part_after_job = job->write_part_after_job;
    if (jcr->RestoreBootstrap) {
       free(jcr->RestoreBootstrap);
       jcr->RestoreBootstrap = NULL;
index f5c8ee2ff03fd7037782ae959999da86211df441..b34e29e4c0eb869375841f751bb2ed6ce3a04238 100644 (file)
@@ -16,7 +16,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -40,7 +40,7 @@
 
 /* Commands sent to Storage daemon */
 static char jobcmd[]     = "JobId=%d job=%s job_name=%s client_name=%s "
-"type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s SpoolData=%d";
+"type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s SpoolData=%d WritePartAfterJob=%d";
 static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n";
 
 /* Response from Storage daemon */
@@ -74,7 +74,7 @@ bool connect_to_storage_daemon(JCR *jcr, int retry_interval,
    Dmsg2(200, "bnet_connect to Storage daemon %s:%d\n", store->address,
       store->SDport);
    sd = bnet_connect(jcr, retry_interval, max_retry_time,
-         _("Storage daemon"), store->address,
+          _("Storage daemon"), store->address,
          NULL, store->SDport, verbose);
    if (sd == NULL) {
       return false;
@@ -113,7 +113,7 @@ int start_storage_daemon_job(JCR *jcr)
    bnet_fsend(sd, jobcmd, jcr->JobId, jcr->Job, jcr->job->hdr.name,
              jcr->client->hdr.name, jcr->JobType, jcr->JobLevel,
              jcr->fileset->hdr.name, !jcr->pool->catalog_files,
-             jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data);
+             jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data, jcr->write_part_after_job);
    Dmsg1(200, "Jobcmd=%s\n", sd->msg);
    unbash_spaces(jcr->job->hdr.name);
    unbash_spaces(jcr->client->hdr.name);
@@ -122,12 +122,12 @@ int start_storage_daemon_job(JCR *jcr)
        Dmsg1(110, "<stored: %s", sd->msg);
        if (sscanf(sd->msg, OKjob, &jcr->VolSessionId,
                  &jcr->VolSessionTime, &auth_key) != 3) {
-         Dmsg1(100, "BadJob=%s\n", sd->msg);
-         Jmsg(jcr, M_FATAL, 0, _("Storage daemon rejected Job command: %s\n"), sd->msg);
+          Dmsg1(100, "BadJob=%s\n", sd->msg);
+          Jmsg(jcr, M_FATAL, 0, _("Storage daemon rejected Job command: %s\n"), sd->msg);
          return 0;
        } else {
          jcr->sd_auth_key = bstrdup(auth_key);
-         Dmsg1(150, "sd_auth_key=%s\n", jcr->sd_auth_key);
+          Dmsg1(150, "sd_auth_key=%s\n", jcr->sd_auth_key);
        }
    } else {
       Jmsg(jcr, M_FATAL, 0, _("<stored: bad response to Job command: %s\n"),
@@ -152,12 +152,12 @@ int start_storage_daemon_job(JCR *jcr)
         bash_spaces(pool_name);
         bnet_fsend(sd, use_device, device_name.c_str(),
                    media_type.c_str(), pool_name.c_str(), pool_type.c_str());
-        Dmsg1(110, ">stored: %s", sd->msg);
-        status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY);
+         Dmsg1(110, ">stored: %s", sd->msg);
+         status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY);
         if (!status) {
            pm_strcpy(pool_type, sd->msg); /* save message */
-           Jmsg(jcr, M_FATAL, 0, _("\n"
-              "     Storage daemon didn't accept Device \"%s\" because:\n     %s"),
+            Jmsg(jcr, M_FATAL, 0, _("\n"
+               "     Storage daemon didn't accept Device \"%s\" because:\n     %s"),
               device_name.c_str(), pool_type.c_str()/* sd->msg */);
         }
       }
index 882e1ae23668968c60472cdd7db7cb1dbae2ee7d..50e71cd6059ff1981275a6fbac1f55d40662a25e 100644 (file)
@@ -9,8 +9,7 @@
  */
 
 /*
-
-   Copyright (C) 2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index cd3092a262ddc3c932942c242c0202c49bc3ce9e..23f5956dc24676b8f4f843499f67a826e25a2417 100644 (file)
@@ -8,7 +8,7 @@
  *     Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -139,15 +139,16 @@ static void set_defaults()
 
 /* Keywords (RHS) permitted in Run records */
 static struct s_kw RunFields[] = {
-   {"pool",             'P'},
-   {"fullpool",         'f'},
-   {"incrementalpool",  'i'},
-   {"differentialpool", 'd'},
-   {"level",            'L'},
-   {"storage",          'S'},
-   {"messages",         'M'},
-   {"priority",         'p'},
-   {"spooldata",        's'},
+   {"pool",              'P'},
+   {"fullpool",          'f'},
+   {"incrementalpool",   'i'},
+   {"differentialpool",  'd'},
+   {"level",             'L'},
+   {"storage",           'S'},
+   {"messages",          'M'},
+   {"priority",          'p'},
+   {"spooldata",         's'},
+   {"writepartafterjob", 'W'},
    {NULL,                0}
 };
 
@@ -189,23 +190,35 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         if (strcasecmp(lc->str, RunFields[i].name) == 0) {
            found = true;
            if (lex_get_token(lc, T_ALL) != T_EQUALS) {
-              scan_err1(lc, "Expected an equals, got: %s", lc->str);
+               scan_err1(lc, "Expected an equals, got: %s", lc->str);
               /* NOT REACHED */
            }
            switch (RunFields[i].token) {
-           case 's':                 /* Data spooling */
+            case 's':                 /* Data spooling */
               token = lex_get_token(lc, T_NAME);
-              if (strcasecmp(lc->str, "yes") == 0) {
+               if (strcasecmp(lc->str, "yes") == 0) {
                  lrun.spool_data = true;
                  lrun.spool_data_set = true;
-              } else if (strcasecmp(lc->str, "no") == 0) {
+               } else if (strcasecmp(lc->str, "no") == 0) {
                  lrun.spool_data = false;
                  lrun.spool_data_set = true;
               } else {
-                 scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
+                  scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
               }
               break;
-           case 'L':                 /* level */
+            case 'W':                 /* Write part after job */
+              token = lex_get_token(lc, T_NAME);
+               if (strcasecmp(lc->str, "yes") == 0) {
+                 lrun.write_part_after_job = true;
+                 lrun.write_part_after_job_set = true;
+               } else if (strcasecmp(lc->str, "no") == 0) {
+                 lrun.write_part_after_job = false;
+                 lrun.write_part_after_job_set = true;
+              } else {
+                  scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
+              }
+              break;
+            case 'L':                 /* level */
               token = lex_get_token(lc, T_NAME);
               for (j=0; joblevels[j].level_name; j++) {
                  if (strcasecmp(lc->str, joblevels[j].level_name) == 0) {
@@ -216,62 +229,62 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
                  }
               }
               if (j != 0) {
-                 scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
+                  scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
                  /* NOT REACHED */
               }
               break;
-           case 'p':                 /* Priority */
+            case 'p':                 /* Priority */
               token = lex_get_token(lc, T_PINT32);
               if (pass == 2) {
                  lrun.Priority = lc->pint32_val;
               }
               break;
-           case 'P':                 /* Pool */
-           case 'f':                 /* FullPool */
-           case 'i':                 /* IncPool */
-           case 'd':                 /* DifPool */
+            case 'P':                 /* Pool */
+            case 'f':                 /* FullPool */
+            case 'i':                 /* IncPool */
+            case 'd':                 /* DifPool */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_POOL, lc->str);
                  if (res == NULL) {
-                    scan_err1(lc, "Could not find specified Pool Resource: %s",
+                     scan_err1(lc, "Could not find specified Pool Resource: %s",
                                lc->str);
                     /* NOT REACHED */
                  }
                  switch(RunFields[i].token) {
-                 case 'P':
+                  case 'P':
                     lrun.pool = (POOL *)res;
                     break;
-                 case 'f':
+                  case 'f':
                     lrun.full_pool = (POOL *)res;
                     break;
-                 case 'i':
+                  case 'i':
                     lrun.inc_pool = (POOL *)res;
                     break;
-                 case 'd':
+                  case 'd':
                     lrun.dif_pool = (POOL *)res;
                     break;
                  }
               }
               break;
-           case 'S':                 /* storage */
+            case 'S':                 /* storage */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_STORAGE, lc->str);
                  if (res == NULL) {
-                    scan_err1(lc, "Could not find specified Storage Resource: %s",
+                     scan_err1(lc, "Could not find specified Storage Resource: %s",
                                lc->str);
                     /* NOT REACHED */
                  }
                  lrun.storage = (STORE *)res;
               }
               break;
-           case 'M':                 /* messages */
+            case 'M':                 /* messages */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_MSGS, lc->str);
                  if (res == NULL) {
-                    scan_err1(lc, "Could not find specified Messages Resource: %s",
+                     scan_err1(lc, "Could not find specified Messages Resource: %s",
                                lc->str);
                     /* NOT REACHED */
                  }
@@ -279,7 +292,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
               }
               break;
            default:
-              scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
+               scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
               /* NOT REACHED */
               break;
            } /* end switch */
@@ -314,24 +327,24 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         state = s_mday;
         code = atoi(lc->str) - 1;
         if (code < 0 || code > 30) {
-           scan_err0(lc, _("Day number out of range (1-31)"));
+            scan_err0(lc, _("Day number out of range (1-31)"));
         }
         break;
       case T_NAME:                /* this handles drop through from keyword */
       case T_UNQUOTED_STRING:
-        if (strchr(lc->str, (int)'-')) {
+         if (strchr(lc->str, (int)'-')) {
            state = s_range;
            break;
         }
-        if (strchr(lc->str, (int)':')) {
+         if (strchr(lc->str, (int)':')) {
            state = s_time;
            break;
         }
-        if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
+         if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
             is_an_integer(lc->str+1)) {
            code = atoi(lc->str+1);
            if (code < 0 || code > 53) {
-              scan_err0(lc, _("Week number out of range (0-53)"));
+               scan_err0(lc, _("Week number out of range (0-53)"));
            }
            state = s_woy;            /* week of year */
            break;
@@ -346,14 +359,14 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
            }
         }
         if (i != 0) {
-           scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
+            scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
            /* NOT REACHED */
         }
         break;
       case T_COMMA:
         continue;
       default:
-        scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
+         scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
         /* NOT REACHED */
         break;
       }
@@ -397,27 +410,27 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         break;
       case s_time:                /* time */
         if (!have_at) {
-           scan_err0(lc, _("Time must be preceded by keyword AT."));
+            scan_err0(lc, _("Time must be preceded by keyword AT."));
            /* NOT REACHED */
         }
         if (!have_hour) {
            clear_bits(0, 23, lrun.hour);
         }
-        p = strchr(lc->str, ':');
+         p = strchr(lc->str, ':');
         if (!p)  {
-           scan_err0(lc, _("Time logic error.\n"));
+            scan_err0(lc, _("Time logic error.\n"));
            /* NOT REACHED */
         }
         *p++ = 0;                 /* separate two halves */
         code = atoi(lc->str);
         len = strlen(p);
-        if (len > 2 && p[len-1] == 'm') {
-           if (p[len-2] == 'a') {
+         if (len > 2 && p[len-1] == 'm') {
+            if (p[len-2] == 'a') {
               pm = 0;
-           } else if (p[len-2] == 'p') {
+            } else if (p[len-2] == 'p') {
               pm = 1;
            } else {
-              scan_err0(lc, _("Bad time specification."));
+               scan_err0(lc, _("Bad time specification."));
               /* NOT REACHED */
            }
         } else {
@@ -428,7 +441,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
            code += 12;
         }
         if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
-           scan_err0(lc, _("Bad time specification."));
+            scan_err0(lc, _("Bad time specification."));
            /* NOT REACHED */
         }
         /****FIXME**** convert to UTC */
@@ -440,9 +453,9 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         have_at = true;
         break;
       case s_range:
-        p = strchr(lc->str, '-');
+         p = strchr(lc->str, '-');
         if (!p) {
-           scan_err0(lc, _("Range logic error.\n"));
+            scan_err0(lc, _("Range logic error.\n"));
         }
         *p++ = 0;                 /* separate two halves */
 
@@ -451,7 +464,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
            code = atoi(lc->str) - 1;
            code2 = atoi(p) - 1;
            if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
-              scan_err0(lc, _("Bad day range specification."));
+               scan_err0(lc, _("Bad day range specification."));
            }
            if (!have_mday) {
               clear_bits(0, 30, lrun.mday);
@@ -467,13 +480,13 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         }
         /* Check for week of year range */
         if (strlen(lc->str) == 3 && strlen(p) == 3 &&
-            (lc->str[0] == 'w' || lc->str[0] == 'W') &&
-            (p[0] == 'w' || p[0] == 'W') &&
+             (lc->str[0] == 'w' || lc->str[0] == 'W') &&
+             (p[0] == 'w' || p[0] == 'W') &&
             is_an_integer(lc->str+1) && is_an_integer(p+1)) {
            code = atoi(lc->str+1);
            code2 = atoi(p+1);
            if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
-              scan_err0(lc, _("Week number out of range (0-53)"));
+               scan_err0(lc, _("Week number out of range (0-53)"));
            }
            if (!have_woy) {
               clear_bits(0, 53, lrun.woy);
@@ -498,7 +511,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
            }
         }
         if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) {
-           scan_err0(lc, _("Invalid month, week or position day range"));
+            scan_err0(lc, _("Invalid month, week or position day range"));
            /* NOT REACHED */
         }
 
@@ -513,7 +526,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
            }
         }
         if (i != 0 || state != state2 || code == code2) {
-           scan_err0(lc, _("Invalid month, weekday or position range"));
+            scan_err0(lc, _("Invalid month, weekday or position range"));
            /* NOT REACHED */
         }
         if (state == s_wday) {
@@ -572,7 +585,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
         set_bits(0, 11, lrun.month);
         break;
       default:
-        scan_err0(lc, _("Unexpected run state\n"));
+         scan_err0(lc, _("Unexpected run state\n"));
         /* NOT REACHED */
         break;
       }
index abe5668a863b29e89c776effe07a3e7bb4f4df2c..3cbcee500055d35df1087abb62d547a63fc14c19 100644 (file)
@@ -10,7 +10,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -82,9 +82,9 @@ JCR *wait_for_next_job(char *one_shot_job_to_run)
       if (one_shot_job_to_run) {           /* one shot */
         job = (JOB *)GetResWithName(R_JOB, one_shot_job_to_run);
         if (!job) {
-           Emsg1(M_ABORT, 0, _("Job %s not found\n"), one_shot_job_to_run);
+            Emsg1(M_ABORT, 0, _("Job %s not found\n"), one_shot_job_to_run);
         }
-        Dmsg1(5, "Found one_shot_job_to_run %s\n", one_shot_job_to_run);
+         Dmsg1(5, "Found one_shot_job_to_run %s\n", one_shot_job_to_run);
         jcr = new_jcr(sizeof(JCR), dird_free_jcr);
         set_jcr_defaults(jcr, job);
         return jcr;
@@ -168,6 +168,9 @@ JCR *wait_for_next_job(char *one_shot_job_to_run)
    if (run->spool_data_set) {
       jcr->spool_data = run->spool_data;
    }
+   if (run->write_part_after_job_set) {
+      jcr->write_part_after_job = run->write_part_after_job;
+   }
    Dmsg0(200, "Leave wait_for_next_job()\n");
    return jcr;
 }
@@ -246,10 +249,10 @@ static void find_runs()
          * Find runs scheduled between now and the next hour.
          */
 #ifdef xxxx
-        Dmsg0(000, "\n");
-        Dmsg6(000, "run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n",
+         Dmsg0(000, "\n");
+         Dmsg6(000, "run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n",
            hour, month, mday, wday, wom, woy);
-        Dmsg6(000, "bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n",
+         Dmsg6(000, "bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n",
            bit_is_set(hour, run->hour),
            bit_is_set(month, run->month),
            bit_is_set(mday, run->mday),
@@ -257,9 +260,9 @@ static void find_runs()
            bit_is_set(wom, run->wom),
            bit_is_set(woy, run->woy));
 
-        Dmsg6(000, "nh_run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n",
+         Dmsg6(000, "nh_run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n",
            nh_hour, nh_month, nh_mday, nh_wday, nh_wom, nh_woy);
-        Dmsg6(000, "nh_bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n",
+         Dmsg6(000, "nh_bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n",
            bit_is_set(nh_hour, run->hour),
            bit_is_set(nh_month, run->month),
            bit_is_set(nh_mday, run->mday),
@@ -282,7 +285,7 @@ static void find_runs()
            bit_is_set(nh_wom, run->wom) &&
            bit_is_set(nh_woy, run->woy);
 
-        Dmsg2(200, "run_now=%d run_nh=%d\n", run_now, run_nh);
+         Dmsg2(200, "run_now=%d run_nh=%d\n", run_now, run_nh);
 
         /* find time (time_t) job is to be run */
         localtime_r(&now, &tm);      /* reset tm structure */
@@ -344,7 +347,7 @@ static void add_job(JOB *job, RUN *run, time_t now, time_t runtime)
       if (ji->runtime > je->runtime ||
          (ji->runtime == je->runtime && ji->Priority > je->Priority)) {
         jobs_to_run->insert_before(je, ji);
-        dump_job(je, "Inserted job");
+         dump_job(je, "Inserted job");
         inserted = true;
         break;
       }
index 23a2a79c12363584f98e72189866f93cc4219496..9405ec0d24748fe4c69a49ceb6b57e9b00907b40 100644 (file)
@@ -8,7 +8,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index e7fb78c3416f5947a11ee787672a0bf6d23c2bcb..0c40531ad67dbe6019659b9740e64792941a4474 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -724,7 +724,7 @@ static void add_fileset(JCR *jcr, const char *item)
    if (code != '\0') {
       ++item;
    }
-   int subcode = ' ';              /* A space is always a valid subcode */
+   int subcode = ' ';               /* A space is always a valid subcode */
    if (item[0] != '\0' && item[0] != ' ') {
       subcode = item[0];
       ++item;
@@ -862,21 +862,21 @@ static bool term_fileset(JCR *jcr)
         for (k=0; k<fo->regex.size(); k++) {
             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
         }
-        for (k=0; k<fo->regexdir.size(); k++) {
-           Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
-        }
-        for (k=0; k<fo->regexfile.size(); k++) {
-           Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
-        }
-        for (k=0; k<fo->wild.size(); k++) {
-           Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
-        }
-        for (k=0; k<fo->wilddir.size(); k++) {
-           Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
-        }
-        for (k=0; k<fo->wildfile.size(); k++) {
-           Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
-        }
+        for (k=0; k<fo->regexdir.size(); k++) {
+            Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
+        }
+        for (k=0; k<fo->regexfile.size(); k++) {
+            Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
+        }
+        for (k=0; k<fo->wild.size(); k++) {
+            Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
+        }
+        for (k=0; k<fo->wilddir.size(); k++) {
+            Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
+        }
+        for (k=0; k<fo->wildfile.size(); k++) {
+            Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
+        }
         for (k=0; k<fo->base.size(); k++) {
             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
         }
@@ -902,21 +902,21 @@ static bool term_fileset(JCR *jcr)
         for (k=0; k<fo->regex.size(); k++) {
             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
         }
-        for (k=0; k<fo->regexdir.size(); k++) {
-           Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
-        }
-        for (k=0; k<fo->regexfile.size(); k++) {
-           Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
-        }
-        for (k=0; k<fo->wild.size(); k++) {
-           Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
-        }
-        for (k=0; k<fo->wilddir.size(); k++) {
-           Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
-        }
-        for (k=0; k<fo->wildfile.size(); k++) {
-           Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
-        }
+        for (k=0; k<fo->regexdir.size(); k++) {
+            Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
+        }
+        for (k=0; k<fo->regexfile.size(); k++) {
+            Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
+        }
+        for (k=0; k<fo->wild.size(); k++) {
+            Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
+        }
+        for (k=0; k<fo->wilddir.size(); k++) {
+            Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
+        }
+        for (k=0; k<fo->wildfile.size(); k++) {
+            Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
+        }
         for (k=0; k<fo->base.size(); k++) {
             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
         }
index 6d30c93dfc5a6e4114c49fdf579df82c8c224cee..bac523bde47b4f4dc4fc38991d802913f46d34e6 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index 5c1d65fed9dff3263bcdf63b20a0ab3646c6e219..ada10e9cae42d4531a441d13482db8330a61b458 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -152,15 +152,15 @@ void do_restore(JCR *jcr)
     *  3. Repeat step 1
     *
     * NOTE: We keep track of two bacula file descriptors:
-    *   1. bfd for file data.
+    *  1. bfd for file data.
     *     This fd is opened for non empty files when an attribute stream is
     *     encountered and closed when we find the next attribute stream.
-    *   2. alt_bfd for alternate data streams
+    *  2. alt_bfd for alternate data streams
     *     This fd is opened every time we encounter a new alternate data
     *     stream for the current file. When we find any other stream, we
     *     close it again.
-    *      The expected size of the stream, alt_len, should be set when
-    *      opening the fd.
+    *     The expected size of the stream, alt_len, should be set when
+    *     opening the fd.
     */
    binit(&bfd);
    binit(&altbfd);
@@ -173,18 +173,18 @@ void do_restore(JCR *jcr)
       /* First we expect a Stream Record Header */
       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
          &stream, &size) != 5) {
-        Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
+         Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
         goto bail_out;
       }
       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
 
       /* * Now we expect the Stream Data */
       if (bget_msg(sd) < 0) {
-        Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
+         Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
         goto bail_out;
       }
       if (size != (uint32_t)sd->msglen) {
-        Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
+         Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
         goto bail_out;
       }
       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
@@ -202,20 +202,20 @@ void do_restore(JCR *jcr)
       switch (stream) {
       case STREAM_UNIX_ATTRIBUTES:
       case STREAM_UNIX_ATTRIBUTES_EX:
-        Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
+         Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
         /*
          * If extracting, it was from previous stream, so
          * close the output file.
          */
         if (extract) {
            if (size > 0 && !is_bopen(&bfd)) {
-              Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
+               Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
            }
            set_attributes(jcr, attr, &bfd);
            extract = false;
-           Dmsg0(30, "Stop extracting.\n");
+            Dmsg0(30, "Stop extracting.\n");
         } else if (is_bopen(&bfd)) {
-           Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
+            Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
            bclose(&bfd);
         }
 
@@ -226,20 +226,20 @@ void do_restore(JCR *jcr)
            goto bail_out;
         }
         if (file_index != attr->file_index) {
-           Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
+            Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
                 file_index, attr->file_index);
-           Dmsg0(100, "File index error\n");
+            Dmsg0(100, "File index error\n");
            goto bail_out;
         }
 
-        Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
+         Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
               attr->attr, attr->attrEx);
 
         attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
 
         if (!is_stream_supported(attr->data_stream)) {
            if (!non_support_data++) {
-              Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
+               Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
                  stream_to_ascii(attr->data_stream));
            }
            continue;
@@ -251,7 +251,7 @@ void do_restore(JCR *jcr)
          * Now determine if we are extracting or not.
          */
         jcr->num_files_examined++;
-        Dmsg1(30, "Outfile=%s\n", attr->ofname);
+         Dmsg1(30, "Outfile=%s\n", attr->ofname);
         extract = false;
         stat = create_file(jcr, attr, &bfd, jcr->replace);
         switch (stat) {
@@ -316,12 +316,12 @@ void do_restore(JCR *jcr)
         if (extract) {
            if (prev_stream != stream) {
               if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
-                 Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s\n"), jcr->last_fname);
+                  Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s\n"), jcr->last_fname);
                  extract = false;
                  continue;
               }
               alt_size = rsrc_len;
-              Dmsg0(30, "Restoring resource fork\n");
+               Dmsg0(30, "Restoring resource fork\n");
            }
            flags = 0;
            if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
@@ -337,13 +337,13 @@ void do_restore(JCR *jcr)
 
       case STREAM_HFSPLUS_ATTRIBUTES:
 #ifdef HAVE_DARWIN_OS
-        Dmsg0(30, "Restoring Finder Info\n");
+         Dmsg0(30, "Restoring Finder Info\n");
         if (sd->msglen != 32) {
-           Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
+            Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
            continue;
         }
         if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
-           Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
+            Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
            continue;
         }
 #else
@@ -357,7 +357,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
         /* Recover Acess ACL from stream and check it */
         acl = acl_from_text(sd->msg);
         if (acl_valid(acl) != 0) {
-           Jmsg1(jcr, M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
+            Jmsg1(jcr, M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
            acl_free(acl);
         }
 
@@ -365,14 +365,14 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
         if (attr->type == FT_DIREND) {
            /* Directory */
            if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
-              Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
+               Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
            }
         /* File or Link */
         } else if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
-           Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
+            Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
         }
         acl_free(acl);
-        Dmsg1(200, "ACL of file: %s successfully restored!\n", jcr->last_fname);
+         Dmsg1(200, "ACL of file: %s successfully restored!\n", jcr->last_fname);
         break;
 #else
         non_support_acl++;
@@ -383,7 +383,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
       /* Recover Default ACL from stream and check it */
         acl = acl_from_text(sd->msg);
         if (acl_valid(acl) != 0) {
-           Jmsg1(jcr, M_WARNING, 0, "Failure in the Default ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
+            Jmsg1(jcr, M_WARNING, 0, "Failure in the Default ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
            acl_free(acl);
         }
 
@@ -391,11 +391,11 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
         if (attr->type == FT_DIREND) {
            /* Directory */
            if (acl_set_file(jcr->last_fname, ACL_TYPE_DEFAULT, acl) != 0) {
-              Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore Default ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
+               Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore Default ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
             }
         }
         acl_free(acl);
-        Dmsg1(200, "Default ACL of file: %s successfully restored!\n", jcr->last_fname);
+         Dmsg1(200, "Default ACL of file: %s successfully restored!\n", jcr->last_fname);
         break;
 #else
         non_support_acl++;
@@ -410,7 +410,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
       case STREAM_PROGRAM_NAMES:
       case STREAM_PROGRAM_DATA:
         if (!non_support_progname) {
-           Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
+            Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
            non_support_progname++;
         }
         break;
@@ -418,18 +418,18 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
       default:
         /* If extracting, wierd stream (not 1 or 2), close output file anyway */
         if (extract) {
-           Dmsg1(30, "Found wierd stream %d\n", stream);
+            Dmsg1(30, "Found wierd stream %d\n", stream);
            if (size > 0 && !is_bopen(&bfd)) {
-              Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
+               Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
            }
            set_attributes(jcr, attr, &bfd);
            extract = false;
         } else if (is_bopen(&bfd)) {
-           Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
+            Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
            bclose(&bfd);
         }
-        Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
-        Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
+         Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
+         Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
         break;
       } /* end switch(stream) */
 
@@ -536,7 +536,7 @@ int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
         if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
            berrno be;
            be.set_errno(bfd->berrno);
-           Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
+            Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
                  edit_uint64(*addr, ec1), jcr->last_fname, be.strerror());
            return -1;
         }
@@ -553,7 +553,7 @@ int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
       Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
       if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
                  (const Byte *)wbuf, (uLong)rsize)) != Z_OK) {
-        Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
+         Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
               jcr->last_fname, zlib_strerror(stat));
         return -1;
       }
index 1d5f1009fcc13a138bd53a68f0cb1bf49145dc17..13bf2c47a4b76fa58c78841ad232acaa1ab1eca1 100644 (file)
@@ -10,7 +10,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -140,7 +140,7 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void
            bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
         }
         for (j=0; j<incexe->name_list.size(); j++) {
-           Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
+            Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
            char *fname = (char *)incexe->name_list.get(j);
            if (find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, 1) == 0) {
               return 0;                  /* error return */
@@ -154,7 +154,7 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void
       while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) {
         /* Copy options for this file */
         bstrncat(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts));
-        Dmsg1(100, "find_files: file=%s\n", inc->fname);
+         Dmsg1(100, "find_files: file=%s\n", inc->fname);
         if (!file_is_excluded(ff, inc->fname)) {
            if (find_one_file(jcr, ff, callback, his_pkt, inc->fname, (dev_t)-1, 1) ==0) {
               return 0;                  /* error return */
@@ -184,9 +184,9 @@ static bool accept_file(FF_PKT *ff)
         for (k=0; k<fo->wilddir.size(); k++) {
            if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) {
               if (ff->flags & FO_EXCLUDE) {
-                 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
+                  Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
                     ff->fname);
-                 return false;       /* reject file */
+                 return false;       /* reject file */
               }
               return true;           /* accept file */
            }
@@ -195,9 +195,9 @@ static bool accept_file(FF_PKT *ff)
         for (k=0; k<fo->wildfile.size(); k++) {
            if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) {
               if (ff->flags & FO_EXCLUDE) {
-                 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
+                  Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
                     ff->fname);
-                 return false;       /* reject file */
+                 return false;       /* reject file */
               }
               return true;           /* accept file */
            }
@@ -206,7 +206,7 @@ static bool accept_file(FF_PKT *ff)
       for (k=0; k<fo->wild.size(); k++) {
         if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
            if (ff->flags & FO_EXCLUDE) {
-              Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
+               Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
                  ff->fname);
               return false;          /* reject file */
            }
@@ -220,7 +220,7 @@ static bool accept_file(FF_PKT *ff)
            regmatch_t pmatch[nmatch];
            if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
               if (ff->flags & FO_EXCLUDE) {
-                 return false;       /* reject file */
+                 return false;       /* reject file */
               }
               return true;           /* accept file */
            }
@@ -231,7 +231,7 @@ static bool accept_file(FF_PKT *ff)
            regmatch_t pmatch[nmatch];
            if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
               if (ff->flags & FO_EXCLUDE) {
-                 return false;       /* reject file */
+                 return false;       /* reject file */
               }
               return true;           /* accept file */
            }
@@ -257,7 +257,7 @@ static bool accept_file(FF_PKT *ff)
         ic = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
         for (k=0; k<fo->wild.size(); k++) {
            if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
-              Dmsg1(100, "Reject wild1: %s\n", ff->fname);
+               Dmsg1(100, "Reject wild1: %s\n", ff->fname);
               return false;          /* reject file */
            }
         }
@@ -266,7 +266,7 @@ static bool accept_file(FF_PKT *ff)
             ? FNM_CASEFOLD : 0;
       for (j=0; j<incexe->name_list.size(); j++) {
         if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|ic) == 0) {
-           Dmsg1(100, "Reject wild2: %s\n", ff->fname);
+            Dmsg1(100, "Reject wild2: %s\n", ff->fname);
            return false;          /* reject file */
         }
       }
@@ -307,7 +307,7 @@ static int our_callback(FF_PKT *ff, void *hpkt)
       if (accept_file(ff)) {
         return ff->callback(ff, hpkt);
       } else {
-        Dmsg1(100, "Skip file %s\n", ff->fname);
+         Dmsg1(100, "Skip file %s\n", ff->fname);
         return -1;                   /* ignore this file */
       }
 
index 16d1a393a933d6976f351348e1ab0b3797099e16..cf35bd589a8f576d7cbf54dcd51457bcdad44338 100755 (executable)
@@ -1,10 +1,10 @@
 /*
  * File types as returned by find_files()
  *
- *     Kern Sibbald MIM
+ *     Kern Sibbald MMI
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald
+   Copyright (C) 2001-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -63,41 +63,41 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
  * Status codes returned by create_file()
  */
 enum {
-   CF_SKIP = 1,                       /* skip file (not newer or something) */
-   CF_ERROR,                          /* error creating file */
-   CF_EXTRACT,                        /* file created, data to extract */
-   CF_CREATED                         /* file created, no data to extract */
+   CF_SKIP = 1,                      /* skip file (not newer or something) */
+   CF_ERROR,                         /* error creating file */
+   CF_EXTRACT,                       /* file created, data to extract */
+   CF_CREATED                        /* file created, no data to extract */
 };
 
 
 /* Options saved int "options" of the include/exclude lists.
  * They are directly jammed ito  "flag" of ff packet
  */
-#define FO_MD5          (1<<1)        /* Do MD5 checksum */
-#define FO_GZIP         (1<<2)        /* Do Zlib compression */
-#define FO_NO_RECURSION (1<<3)        /* no recursion in directories */
-#define FO_MULTIFS      (1<<4)        /* multiple file systems */
-#define FO_SPARSE       (1<<5)        /* do sparse file checking */
-#define FO_IF_NEWER     (1<<6)        /* replace if newer */
-#define FO_NOREPLACE    (1<<7)        /* never replace */
-#define FO_READFIFO     (1<<8)        /* read data from fifo */
-#define FO_SHA1         (1<<9)        /* Do SHA1 checksum */
-#define FO_PORTABLE     (1<<10)       /* Use portable data format -- no BackupWrite */
-#define FO_MTIMEONLY    (1<<11)       /* Use mtime rather than mtime & ctime */
-#define FO_KEEPATIME    (1<<12)       /* Reset access time */
-#define FO_EXCLUDE      (1<<13)       /* Exclude file */
-#define FO_ACL          (1<<14)       /* Backup ACLs */
+#define FO_MD5         (1<<1)        /* Do MD5 checksum */
+#define FO_GZIP        (1<<2)        /* Do Zlib compression */
+#define FO_NO_RECURSION (1<<3)       /* no recursion in directories */
+#define FO_MULTIFS     (1<<4)        /* multiple file systems */
+#define FO_SPARSE      (1<<5)        /* do sparse file checking */
+#define FO_IF_NEWER    (1<<6)        /* replace if newer */
+#define FO_NOREPLACE   (1<<7)        /* never replace */
+#define FO_READFIFO    (1<<8)        /* read data from fifo */
+#define FO_SHA1        (1<<9)        /* Do SHA1 checksum */
+#define FO_PORTABLE    (1<<10)       /* Use portable data format -- no BackupWrite */
+#define FO_MTIMEONLY   (1<<11)       /* Use mtime rather than mtime & ctime */
+#define FO_KEEPATIME   (1<<12)       /* Reset access time */
+#define FO_EXCLUDE     (1<<13)       /* Exclude file */
+#define FO_ACL         (1<<14)       /* Backup ACLs */
 #define FO_NO_HARDLINK  (1<<15)       /* don't handle hard links */
-#define FO_IGNORECASE   (1<<16)       /* Ignore file name case */
-#define FO_HFSPLUS      (1<<17)       /* Resource forks and Finder Info */
+#define FO_IGNORECASE  (1<<16)       /* Ignore file name case */
+#define FO_HFSPLUS     (1<<17)       /* Resource forks and Finder Info */
 
 struct s_included_file {
    struct s_included_file *next;
-   uint32_t options;                  /* backup options */
-   int level;                         /* compression level */
-   int len;                           /* length of fname */
-   int pattern;                       /* set if wild card pattern */
-   char VerifyOpts[20];               /* Options for verify */
+   uint32_t options;                 /* backup options */
+   int level;                        /* compression level */
+   int len;                          /* length of fname */
+   int pattern;                      /* set if wild card pattern */
+   char VerifyOpts[20];              /* Options for verify */
    char fname[1];
 };
 
@@ -112,7 +112,7 @@ struct s_excluded_file {
  *  of the structure are passed by the Director to the
  *  File daemon and recompiled back into this structure
  */
-#undef  MAX_FOPTS
+#undef MAX_FOPTS
 #define MAX_FOPTS 30
 
 enum {
@@ -124,27 +124,27 @@ enum {
 
 /* File options structure */
 struct findFOPTS {
-   uint32_t flags;                    /* options in bits */
-   int GZIP_level;                    /* GZIP level */
-   char VerifyOpts[MAX_FOPTS];        /* verify options */
-   alist regex;                       /* regex string(s) */
-   alist regexdir;                    /* regex string(s) for directories */
-   alist regexfile;                   /* regex string(s) for files */
-   alist wild;                        /* wild card strings */
-   alist wilddir;                     /* wild card strings for directories */
-   alist wildfile;                    /* wild card strings for files */
-   alist base;                        /* list of base names */
-   alist fstype;                      /* file system type limitation */
-   char *reader;                      /* reader program */
-   char *writer;                      /* writer program */
+   uint32_t flags;                   /* options in bits */
+   int GZIP_level;                   /* GZIP level */
+   char VerifyOpts[MAX_FOPTS];       /* verify options */
+   alist regex;                      /* regex string(s) */
+   alist regexdir;                   /* regex string(s) for directories */
+   alist regexfile;                  /* regex string(s) for files */
+   alist wild;                       /* wild card strings */
+   alist wilddir;                    /* wild card strings for directories */
+   alist wildfile;                   /* wild card strings for files */
+   alist base;                       /* list of base names */
+   alist fstype;                     /* file system type limitation */
+   char *reader;                     /* reader program */
+   char *writer;                     /* writer program */
 };
 
 
 /* This is either an include item or an exclude item */
 struct findINCEXE {
-   findFOPTS *current_opts;           /* points to current options structure */
-   alist opts_list;                   /* options list */
-   alist name_list;                   /* filename list -- holds char * */
+   findFOPTS *current_opts;          /* points to current options structure */
+   alist opts_list;                  /* options list */
+   alist name_list;                  /* filename list -- holds char * */
 };
 
 /*
@@ -153,16 +153,16 @@ struct findINCEXE {
  */
 struct findFILESET {
    int state;
-   findINCEXE *incexe;                /* current item */
+   findINCEXE *incexe;               /* current item */
    alist include_list;
    alist exclude_list;
 };
 
 #ifdef HAVE_DARWIN_OS
 struct HFSPLUS_INFO {
-   unsigned long length;              /* Mandatory field */
-   char fndrinfo[32];                 /* Finder Info */
-   off_t rsrclength;                  /* Size of resource fork */
+   unsigned long length;             /* Mandatory field */
+   char fndrinfo[32];                /* Finder Info */
+   off_t rsrclength;                 /* Size of resource fork */
 };
 #endif
 
@@ -171,20 +171,20 @@ struct HFSPLUS_INFO {
  * first argument to the find_files callback subroutine.
  */
 struct FF_PKT {
-   char *fname;                       /* filename */
-   char *link;                        /* link if file linked */
-   POOLMEM *sys_fname;                /* system filename */
-   struct stat statp;                 /* stat packet */
-   int32_t FileIndex;                 /* FileIndex of this file */
-   int32_t LinkFI;                    /* FileIndex of main hard linked file */
-   struct f_link *linked;             /* Set if this file is hard linked */
-   int type;                          /* FT_ type from above */
-   int ff_errno;                      /* errno */
-   BFILE bfd;                         /* Bacula file descriptor */
-   time_t save_time;                  /* start of incremental time */
-   bool dereference;                  /* follow links (not implemented) */
-   bool null_output_device;           /* using null output device */
-   bool incremental;                  /* incremental save */
+   char *fname;                      /* filename */
+   char *link;                       /* link if file linked */
+   POOLMEM *sys_fname;               /* system filename */
+   struct stat statp;                /* stat packet */
+   int32_t FileIndex;                /* FileIndex of this file */
+   int32_t LinkFI;                   /* FileIndex of main hard linked file */
+   struct f_link *linked;            /* Set if this file is hard linked */
+   int type;                         /* FT_ type from above */
+   int ff_errno;                     /* errno */
+   BFILE bfd;                        /* Bacula file descriptor */
+   time_t save_time;                 /* start of incremental time */
+   bool dereference;                 /* follow links (not implemented) */
+   bool null_output_device;          /* using null output device */
+   bool incremental;                 /* incremental save */
    char VerifyOpts[20];
    struct s_included_file *included_files_list;
    struct s_excluded_file *excluded_files_list;
@@ -193,18 +193,18 @@ struct FF_PKT {
    int (*callback)(FF_PKT *, void *); /* User's callback */
 
    /* Values set by accept_file while processing Options */
-   uint32_t flags;                    /* backup options */
-   int GZIP_level;                    /* compression level */
-   char *reader;                      /* reader program */
-   char *writer;                      /* writer program */
-   alist fstypes;                     /* allowed file system types */
+   uint32_t flags;                   /* backup options */
+   int GZIP_level;                   /* compression level */
+   char *reader;                     /* reader program */
+   char *writer;                     /* writer program */
+   alist fstypes;                    /* allowed file system types */
 
    /* List of all hard linked files found */
-   struct f_link *linklist;           /* hard linked files */
+   struct f_link *linklist;          /* hard linked files */
 
    /* Darwin specific things. So as not to clutter every bclose()
     * with an #ifdef, we always include rsrc_bfd */
-   BFILE rsrc_bfd;                    /* fd for resource forks */
+   BFILE rsrc_bfd;                   /* fd for resource forks */
 #ifdef HAVE_DARWIN_OS
    struct HFSPLUS_INFO hfsinfo;       /* Finder Info and resource fork size */
 #endif
index 354811db8762736fd555aed455dff3a6560da161..d3516d37fe3984eb2abf4f2f2d5d7d04d936ac10 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-20054 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index 1ab43f0a4cc0eb178d66c5df42e4a09ba36ad34e..a23d9aaa651672fa2a8582454b8adf921130156c 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 /*
-   Copyright (C) Kern Sibbald
+   Copyright (C) 2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index e269c39e1e17bbe1f2b231c5ffd742efaf86425b..16867ba6a3c51a191e3d9b3a9cabcf1d6e6fc3e6 100644 (file)
@@ -4,7 +4,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index d534be3ab05f7528a0d39fb24a9cbe1387fb9265..38a9cd7b5afaa8e8a435992acdfebd15df7df966 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -185,6 +185,7 @@ struct JCR {
    bool acquired_resource_locks;      /* set if resource locks acquired */
    bool term_wait_inited;             /* Set when cond var inited */
    bool fn_printed;                   /* printed filename */
+   bool write_part_after_job;         /* Write part after job in SD */
 #endif /* DIRECTOR_DAEMON */
 
 
@@ -239,7 +240,8 @@ struct JCR {
    bool spool_data;                   /* set to spool data */
    int CurVol;                        /* Current Volume count */
    DIRRES* director;                  /* Director resource */
-
+   bool write_part_after_job;         /* Set to write part after job */
+   
    uint32_t FileId;                   /* Last file id inserted */
 
    /* Parmaters for Open Read Session */
index f7a340034b93010b7d19e88cd547fba2ddb88890..4350de4c05da60ec9b0c3b1a5b596542a3159ba1 100644 (file)
@@ -282,6 +282,65 @@ int run_program(char *prog, int wait, POOLMEM *results)
    return stat1;
 }
 
+/*
+ * Run an external program. Optionally wait a specified number
+ *   of seconds. Program killed if wait exceeded (it is done by the 
+ *   watchdog, as fgets is a blocking function).
+ *   Return the full output from the program (not only the first line).
+ *
+ * Contrary to my normal calling conventions, this program
+ *
+ *  Returns: 0 on success
+ *          non-zero on error == berrno status
+ *
+ */
+int run_program_full_output(char *prog, int wait, POOLMEM *results)
+{
+   BPIPE *bpipe;
+   int stat1, stat2;
+   char *mode;
+   POOLMEM* tmp;
+
+   if (results == NULL) {
+      return run_program(prog, wait, NULL);
+   }
+   
+   tmp = get_pool_memory(PM_MESSAGE);
+   
+   mode = (char *)"r";
+   bpipe = open_bpipe(prog, wait, mode);
+   if (!bpipe) {
+      return ENOENT;
+   }
+   
+   results[0] = 0;
+
+   while (1) {
+      fgets(tmp, sizeof_pool_memory(tmp), bpipe->rfd);
+      Dmsg1(200, "Run program fgets=%s", tmp);
+      pm_strcat(results, tmp);
+      if (feof(bpipe->rfd)) {
+         stat1 = 0;
+         Dmsg1(100, "Run program fgets stat=%d\n", stat1);
+         break;
+      } else {
+         stat1 = ferror(bpipe->rfd);
+      }
+      if (stat1 < 0) {
+         Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
+         break;
+      } else if (stat1 != 0) {
+         Dmsg1(100, "Run program fgets stat=%d\n", stat1);
+      }
+   }
+   
+   stat2 = close_bpipe(bpipe);
+   stat1 = stat2 != 0 ? stat2 : stat1;
+   
+   Dmsg1(100, "Run program returning %d\n", stat);
+   free_pool_memory(tmp);
+   return stat1;
+}
 
 /*
  * Build argc and argv from a string
index 199abd8f0369955dfd0453bd609d57e5311180e0..d1cc5cc99b6f297c0aae243687588b059eccb90a 100644 (file)
@@ -209,6 +209,7 @@ char *           encode_mode             (mode_t mode, char *buf);
 int              do_shell_expansion      (char *name, int name_len);
 void             jobstatus_to_ascii      (int JobStatus, char *msg, int maxlen);
 int              run_program             (char *prog, int wait, POOLMEM *results);
+int              run_program_full_output (char *prog, int wait, POOLMEM *results);
 const char *     job_type_to_str         (int type);
 const char *     job_status_to_str       (int stat);
 const char *     job_level_to_str        (int level);
index cd6e846d1717073bc4ed17ebb50c9dfd1e1c0af0..67a40872d805d86eb2d5631f801d40e196efaf2c 100644 (file)
@@ -6,7 +6,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2002-2004 Kern Sibbald and John Walker
+   Copyright (C) 2002-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -93,7 +93,8 @@ DCR *acquire_device_for_read(JCR *jcr)
    int i;
    DCR *dcr = jcr->dcr;
    DEVICE *dev;
-
+   int vol_label_status;
+   
    /* Called for each volume */
    if (!dcr) {
       dcr = new_dcr(jcr, jcr->device->dev);
@@ -131,10 +132,18 @@ DCR *acquire_device_for_read(JCR *jcr)
    }
    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
 
+   /* Volume info is always needed because of VolParts */
+   Dmsg0(200, "dir_get_volume_info\n");
+   if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
+      Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+   }
+   
+   dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
+   
    for (i=0; i<5; i++) {
       dcr->dev->state &= ~ST_LABEL;          /* force reread of label */
       if (job_canceled(jcr)) {
-        Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
+         Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
         goto get_out;                /* error return */
       }
       /*
@@ -143,23 +152,39 @@ DCR *acquire_device_for_read(JCR *jcr)
        * If it is a tape, it checks the volume name
        */
       for ( ; !(dev->state & ST_OPENED); ) {
-        Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
+         Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
         if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) {
            if (dev->dev_errno == EIO) {   /* no tape loaded */
               goto default_path;
            }
-           Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
+           
+           /* If we have a device that requires mount, 
+            * we need to try to open the label, so the info can be reported
+            * if a wrong volume has been mounted. */
+           if (dev_cap(dev, CAP_REQMOUNT) && (dcr->VolCatInfo.VolCatParts > 0)) {
+              break;
+           }
+           
+            Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
                dev_name(dev), dcr->VolumeName, strerror_dev(dev));
            goto get_out;
         }
-        Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
+         Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
+      }
+      
+      if (dev_cap(dev, CAP_REQMOUNT)) {
+        vol_label_status = read_dev_volume_label_guess(dcr, 0);
+      }
+      else {
+        vol_label_status = read_dev_volume_label(dcr);
       }
+      
       /****FIXME***** do not reread label if ioctl() says we are
        *  correctly possitioned.  Possibly have way user can turn
        *  this optimization (to be implemented) off.
        */
       Dmsg0(200, "calling read-vol-label\n");
-      switch (read_dev_volume_label(dcr)) {
+      switch (vol_label_status) {
       case VOL_OK:
         vol_ok = true;
         memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
@@ -171,7 +196,7 @@ DCR *acquire_device_for_read(JCR *jcr)
          *  error messages when nothing is mounted.
          */
         if (tape_previously_mounted) {
-           Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+            Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
         }
         goto default_path;
       case VOL_NAME_ERROR:
@@ -181,17 +206,20 @@ DCR *acquire_device_for_read(JCR *jcr)
         }
         /* Fall through */
       default:
-        Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+         Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
 default_path:
         tape_previously_mounted = true;
-        Dmsg0(200, "dir_get_volume_info\n");
-        if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
-           Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+        
+        /* If the device requires mount, close it, so the device can be ejected.
+         * FIXME: This should perhaps be done for all devices. */
+        if (dev_cap(dev, CAP_REQMOUNT)) {
+           force_close_dev(dev);
         }
+        
         /* Call autochanger only once unless ask_sysop called */
         if (try_autochanger) {
            int stat;
-           Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
+            Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
               dcr->VolumeName, dcr->VolCatInfo.Slot);
            stat = autoload_device(dcr, 0, NULL);
            if (stat > 0) {
@@ -199,8 +227,9 @@ default_path:
               continue;
            }
         }
+        
         /* Mount a specific volume and no other */
-        Dmsg0(200, "calling dir_ask_sysop\n");
+         Dmsg0(200, "calling dir_ask_sysop\n");
         if (!dir_ask_sysop_to_mount_volume(dcr)) {
            goto get_out;             /* error return */
         }
@@ -277,7 +306,7 @@ DCR *acquire_device_for_append(JCR *jcr)
       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
          !(dir_find_next_appendable_volume(dcr) &&
            strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
-        Dmsg0(190, "Wrong tape mounted.\n");
+         Dmsg0(190, "Wrong tape mounted.\n");
         if (dev->num_writers != 0) {
            DEVICE *d = ((DEVRES *)dev->device)->dev;
            uint32_t open_vols = 0;
@@ -301,12 +330,12 @@ DCR *acquire_device_for_append(JCR *jcr)
               block_device(dev, BST_DOING_ACQUIRE);
               unlock_device(dev);
            } else {
-              Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
+               Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
               goto get_out;
            }
         }
         /* Wrong tape mounted, release it, then fall through to get correct one */
-        Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
+         Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
         release = true;
         do_mount = true;
       } else {
@@ -315,11 +344,11 @@ DCR *acquire_device_for_append(JCR *jcr)
          *   we do not need to do mount_next_write_volume(), unless
          *   we need to recycle the tape.
          */
-         recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
-         Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
+          recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
+          Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
          if (recycle && dev->num_writers != 0) {
-            Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
-                 " because it is in use by another job.\n"));
+             Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
+                  " because it is in use by another job.\n"));
             goto get_out;
          }
          if (dev->num_writers == 0) {
@@ -330,7 +359,7 @@ DCR *acquire_device_for_append(JCR *jcr)
       /* Not already in append mode, so mount the device */
       Dmsg0(190, "Not in append mode, try mount.\n");
       if (dev_state(dev, ST_READ)) {
-        Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
+         Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
         goto get_out;
       }
       ASSERT(dev->num_writers == 0);
@@ -344,8 +373,8 @@ DCR *acquire_device_for_append(JCR *jcr)
       P(mutex);                      /* re-lock */
       if (!mounted) {
         if (!job_canceled(jcr)) {
-           /* Reduce "noise" -- don't print if job canceled */
-           Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
+            /* Reduce "noise" -- don't print if job canceled */
+            Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
               dev_name(dev));
         }
         goto get_out;
@@ -398,9 +427,9 @@ bool release_device(JCR *jcr)
       dev->num_writers--;
       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
       if (dev_state(dev, ST_LABEL)) {
-        Dmsg0(100, "dir_create_jobmedia_record. Release\n");
+         Dmsg0(100, "dir_create_jobmedia_record. Release\n");
         if (!dir_create_jobmedia_record(dcr)) {
-           Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+            Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
               dcr->VolCatInfo.VolCatName, jcr->Job);
         }
         /* If no more writers, write an EOF */
@@ -410,7 +439,7 @@ bool release_device(JCR *jcr)
         dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
         dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
         /* Note! do volume update before close, which zaps VolCatInfo */
-        Dmsg0(100, "dir_update_vol_info. Release0\n");
+         Dmsg0(100, "dir_update_vol_info. Release0\n");
         dir_update_volume_info(dcr, false); /* send Volume info to Director */
       }
 
@@ -435,7 +464,7 @@ bool release_device(JCR *jcr)
       bpipe = open_bpipe(alert, 0, "r");
       if (bpipe) {
         while (fgets(line, sizeof(line), bpipe->rfd)) {
-           Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
+            Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
         }
         status = close_bpipe(bpipe);
       } else {
@@ -443,7 +472,7 @@ bool release_device(JCR *jcr)
       }
       if (status != 0) {
         berrno be;
-        Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
+         Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
              alert, be.strerror(status));
       }
 
index 97edb1b97c92edac712c91f56934af0f1f57705e..c188c4d409329b6e0e473de7a1e83b18a1763504 100644 (file)
@@ -5,7 +5,7 @@
  *  Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -136,7 +136,7 @@ bool do_append_data(JCR *jcr)
         if (n == BNET_SIGNAL && ds->msglen == BNET_EOD) {
            break;                    /* end of data */
         }
-        Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
+         Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
               bnet_strerror(ds));
         ok = false;
         break;
@@ -158,7 +158,7 @@ bool do_append_data(JCR *jcr)
         p++;
       }
       if (!B_ISSPACE(*p) || !B_ISDIGIT(*(p+1))) {
-        Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg);
+         Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg);
         ok = false;
         break;
       }
@@ -168,7 +168,7 @@ bool do_append_data(JCR *jcr)
 
       if (!(file_index > 0 && (file_index == last_file_index ||
          file_index == last_file_index + 1))) {
-        Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
+         Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
         ok = false;
         break;
       }
@@ -188,28 +188,28 @@ bool do_append_data(JCR *jcr)
         rec.data_len = ds->msglen;
         rec.data = ds->msg;            /* use message buffer */
 
-        Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
+         Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
            rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream,rec.FileIndex),
            rec.data_len);
 
         while (!write_record_to_block(dcr->block, &rec)) {
-           Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
+            Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
                       rec.remainder);
            if (!write_block_to_device(dcr)) {
-              Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
+               Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
                  dev_name(dev), strerror_dev(dev));
-              Jmsg(jcr, M_FATAL, 0, _("Fatal device error: ERR=%s\n"),
+               Jmsg(jcr, M_FATAL, 0, _("Fatal device error: ERR=%s\n"),
                     strerror_dev(dev));
               ok = false;
               break;
            }
         }
         if (!ok) {
-           Dmsg0(400, "Not OK\n");
+            Dmsg0(400, "Not OK\n");
            break;
         }
         jcr->JobBytes += rec.data_len;   /* increment bytes this job */
-        Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
+         Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
            FI_to_ascii(rec.FileIndex), rec.VolSessionId,
            stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len);
 
@@ -220,10 +220,10 @@ bool do_append_data(JCR *jcr)
               if (are_attributes_spooled(jcr)) {
                  jcr->dir_bsock->spool = true;
               }
-              Dmsg0(850, "Send attributes to dir.\n");
+               Dmsg0(850, "Send attributes to dir.\n");
               if (!dir_update_file_attributes(dcr, &rec)) {
                  jcr->dir_bsock->spool = false;
-                 Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
+                  Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
                     bnet_strerror(jcr->dir_bsock));
                  ok = false;
                  break;
@@ -231,12 +231,12 @@ bool do_append_data(JCR *jcr)
               jcr->dir_bsock->spool = false;
            }
         }
-        Dmsg0(350, "Enter bnet_get\n");
+         Dmsg0(350, "Enter bnet_get\n");
       }
       Dmsg1(350, "End read loop with FD. Stat=%d\n", n);
       if (is_bnet_error(ds)) {
-        Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds));
-        Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
+         Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds));
+         Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
               bnet_strerror(ds));
         ok = false;
         break;
@@ -257,18 +257,18 @@ bool do_append_data(JCR *jcr)
     */
    if (ok || dev_can_write(dev)) {
       if (!write_session_label(dcr, EOS_LABEL)) {
-        Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
+         Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
               strerror_dev(dev));
         set_jcr_job_status(jcr, JS_ErrorTerminated);
         ok = false;
       }
       if (dev->VolCatInfo.VolCatName[0] == 0) {
-        Dmsg0(000, "NULL Volume name. This shouldn't happen!!!\n");
+         Dmsg0(000, "NULL Volume name. This shouldn't happen!!!\n");
       }
       Dmsg0(90, "back from write_end_session_label()\n");
       /* Flush out final partial block of this session */
       if (!write_block_to_device(dcr)) {
-        Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
+         Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
         set_jcr_job_status(jcr, JS_ErrorTerminated);
         ok = false;
       }
@@ -282,6 +282,29 @@ bool do_append_data(JCR *jcr)
    } else {
       commit_data_spool(jcr);
    }
+   
+   /* If the device is nor a tape, nor a fifo, and WritePartAfterJob
+    * is set to yes, open the next part, so, in case of a device
+    * that requires mount, it will be written to the device.
+    */
+   if (!(dcr->dev->state & (ST_TAPE|ST_FIFO)) && (jcr->write_part_after_job) && (dcr->dev->part_size > 0)) {
+      Dmsg0(100, "Writing last part because write_part_after_job is set.\n");
+      if (dcr->dev->part < dcr->dev->num_parts) {
+         Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
+              dev->part, dev->num_parts, dev_name(dev));
+        dcr->dev->dev_errno = EIO;
+        ok = false;
+      }
+      
+      if (ok && (open_next_part(dcr->dev) < 0)) {
+         Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"),
+              dev_name(dcr->dev), strerror_dev(dcr->dev));
+        dcr->dev->dev_errno = EIO;
+        ok = false;
+      }
+      
+      dcr->dev->VolCatInfo.VolCatParts = dcr->dev->num_parts;
+   }
 
    Dmsg1(200, "calling release device JobStatus=%d\n", jcr->JobStatus);
    /* Release the device */
index b77c5e1e25b9d10205fefe4386041a4573b22e1f..645993c72c3ecb2ec81583f46ddc36e681fda08a 100644 (file)
@@ -7,7 +7,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -35,7 +35,8 @@ static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
-   " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s\n";
+   " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
+   " VolParts=%u\n";
 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
    " StartBlock=%u EndBlock=%u\n";
@@ -48,7 +49,7 @@ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
    " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
    " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
    " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
-   " VolReadTime=%" lld " VolWriteTime=%" lld " EndFile=%u EndBlock=%u";
+   " VolReadTime=%" lld " VolWriteTime=%" lld " EndFile=%u EndBlock=%u VolParts=%u";
 
 
 static char OK_create[] = "1000 OK CreateJobMedia\n";
@@ -97,8 +98,8 @@ static bool do_get_volume_info(DCR *dcr)
               &vol.VolCatCapacityBytes, vol.VolCatStatus,
               &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
               &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
-              &vol.EndFile, &vol.EndBlock);
-    if (n != 19) {
+              &vol.EndFile, &vol.EndBlock, &vol.VolCatParts);
+    if (n != 20) {
        Dmsg2(100, "Bad response from Dir fields=%d: %s\n", n, dir->msg);
        Mmsg(jcr->errmsg, _("Error getting Volume info: %s\n"), dir->msg);
        return false;
@@ -162,7 +163,7 @@ bool dir_find_next_appendable_volume(DCR *dcr)
     for (int vol_index=1;  vol_index < 3; vol_index++) {
        bnet_fsend(dir, Find_media, jcr->Job, vol_index);
        if (do_get_volume_info(dcr)) {
-         Dmsg2(300, "JobId=%d got possible Vol=%s\n", jcr->JobId, dcr->VolumeName);
+          Dmsg2(300, "JobId=%d got possible Vol=%s\n", jcr->JobId, dcr->VolumeName);
          bool found = false;
          /*
           * Walk through all jobs and see if the volume is
@@ -176,10 +177,10 @@ bool dir_find_next_appendable_volume(DCR *dcr)
                free_locked_jcr(njcr);
                continue;             /* us */
             }
-            Dmsg2(300, "Compare to JobId=%d using Vol=%s\n", njcr->JobId, njcr->dcr->VolumeName);
+             Dmsg2(300, "Compare to JobId=%d using Vol=%s\n", njcr->JobId, njcr->dcr->VolumeName);
             if (njcr->dcr && strcmp(dcr->VolumeName, njcr->dcr->VolumeName) == 0) {
                found = true;
-               Dmsg1(400, "Vol in use by JobId=%u\n", njcr->JobId);
+                Dmsg1(400, "Vol in use by JobId=%u\n", njcr->JobId);
                free_locked_jcr(njcr);
                break;
             }
@@ -187,11 +188,11 @@ bool dir_find_next_appendable_volume(DCR *dcr)
          }
          unlock_jcr_chain();
          if (!found) {
-            Dmsg0(400, "dir_find_next_appendable_volume return true\n");
+             Dmsg0(400, "dir_find_next_appendable_volume return true\n");
             return true;             /* Got good Volume */
          }
        } else {
-         Dmsg0(200, "No volume info, return false\n");
+          Dmsg0(200, "No volume info, return false\n");
          return false;
        }
     }
@@ -242,7 +243,8 @@ bool dir_update_volume_info(DCR *dcr, bool label)
       LastWritten, vol->VolCatStatus, vol->Slot, label,
       InChanger,                     /* bool in structure */
       edit_uint64(vol->VolReadTime, ed3),
-      edit_uint64(vol->VolWriteTime, ed4) );
+      edit_uint64(vol->VolWriteTime, ed4),
+      vol->VolCatParts );
 
    Dmsg1(300, "update_volume_info(): %s", dir->msg);
    unbash_spaces(vol->VolCatName);
@@ -347,9 +349,9 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
    for ( ;; ) {
       if (job_canceled(jcr)) {
         Mmsg(dev->errmsg,
-             _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
+              _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
              jcr->Job, dcr->dev_name);
-        Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
+         Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
         return false;
       }
       /* First pass, we *know* there are no appendable volumes, so no need to call */
@@ -365,7 +367,7 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
         if (!unmounted && ((dcr->VolumeName[0] && !dev_cap(dev, CAP_REM) &&
                dev_cap(dev, CAP_LABEL)) ||
                 (dcr->VolumeName[0] && dcr->VolCatInfo.Slot))) {
-           Dmsg0(400, "Return 1 from mount without wait.\n");
+            Dmsg0(400, "Return 1 from mount without wait.\n");
            return true;
         }
         jstat = JS_WaitMount;
@@ -374,7 +376,7 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
 "Please mount Volume \"%s\" on Storage Device \"%s\" for Job %s\n"
 "Use \"mount\" command to release Job.\n"),
              dcr->VolumeName, dcr->dev_name, jcr->Job);
-           Dmsg3(400, "Mount %s on %s for Job %s\n",
+            Dmsg3(400, "Mount %s on %s for Job %s\n",
                  dcr->VolumeName, dcr->dev_name, jcr->Job);
         }
       } else {
@@ -399,30 +401,30 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
 
       stat = wait_for_sysop(dcr);
       if (dev->poll) {
-        Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev_name(dev));
+         Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev_name(dev));
         continue;
       }
 
       if (stat == ETIMEDOUT) {
         if (!double_dev_wait_time(dev)) {
-           Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"),
+            Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"),
               dev_name(dev), jcr->Job);
-           Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
-           Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev));
+            Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
+            Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev));
            return false;             /* exceeded maximum waits */
         }
         continue;
       }
       if (stat == EINVAL) {
         berrno be;
-        Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"),
+         Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"),
               stat, be.strerror(stat));
-        Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
+         Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
         return false;
       }
       if (stat != 0) {
         berrno be;
-        Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
+         Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
            be.strerror(stat));
       }
       Dmsg1(400, "Someone woke me for device %s\n", dev_name(dev));
@@ -481,16 +483,16 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr)
    ASSERT(dev->dev_blocked);
    for ( ;; ) {
       if (job_canceled(jcr)) {
-        Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
+         Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
              jcr->Job, dcr->dev_name);
         return false;
       }
 
       if (!dev->poll) {
-        msg = _("Please mount");
-        Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"),
+         msg = _("Please mount");
+         Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"),
              msg, dcr->VolumeName, dcr->dev_name, jcr->Job);
-        Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
+         Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
               dcr->VolumeName, dcr->dev_name, jcr->Job);
       }
 
@@ -499,31 +501,31 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr)
 
       stat = wait_for_sysop(dcr);    ;    /* wait on device */
       if (dev->poll) {
-        Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev_name(dev));
-        Dmsg1(400, "Blocked=%s\n", edit_blocked_reason(dev));
+         Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev_name(dev));
+         Dmsg1(400, "Blocked=%s\n", edit_blocked_reason(dev));
         return true;
       }
 
       if (stat == ETIMEDOUT) {
         if (!double_dev_wait_time(dev)) {
-           Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"),
+            Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"),
               dev_name(dev), jcr->Job);
-           Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
-           Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev));
+            Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
+            Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev));
            return false;             /* exceeded maximum waits */
         }
         continue;
       }
       if (stat == EINVAL) {
         berrno be;
-        Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"),
+         Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"),
               stat, be.strerror(stat));
-        Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
+         Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
         return false;
       }
       if (stat != 0) {
         berrno be;
-        Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
+         Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
            be.strerror(stat));
       }
       Dmsg1(400, "Someone woke me for device %s\n", dev_name(dev));
@@ -600,7 +602,7 @@ static int wait_for_sysop(DCR *dcr)
            /* send heartbeats */
            if (jcr->file_bsock) {
               bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
-              Dmsg0(400, "Send heartbeat to FD.\n");
+               Dmsg0(400, "Send heartbeat to FD.\n");
            }
            if (jcr->dir_bsock) {
               bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
@@ -619,13 +621,13 @@ static int wait_for_sysop(DCR *dcr)
         break;                    /* on error return */
       }
       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
-        Dmsg0(400, "Exceed wait time.\n");
+         Dmsg0(400, "Exceed wait time.\n");
         break;
       }
 
       if (!unmounted && dev->vol_poll_interval &&
          (now - first_start >= dev->vol_poll_interval)) {
-        Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
+         Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
         dev->poll = true;            /* returning a poll event */
         break;
       }
index 4ad745f3fa10517843944826f72c7d4bff245c2b..8fb8a2681566bf028525646d35ee764199984a1a 100644 (file)
@@ -9,7 +9,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -234,10 +234,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       block->bufp = block->buf + bhl;
       if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) {
         dev->dev_errno = EIO;
-        Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
+         Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
            dev->file, dev->block_num, BLKHDR1_ID, Id);
         if (block->read_errors == 0 || verbose >= 2) {
-           Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
         }
         block->read_errors++;
         return false;
@@ -250,10 +250,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       block->bufp = block->buf + bhl;
       if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) {
         dev->dev_errno = EIO;
-        Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
+         Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
            dev->file, dev->block_num, BLKHDR2_ID, Id);
         if (block->read_errors == 0 || verbose >= 2) {
-           Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
         }
         block->read_errors++;
         return false;
@@ -263,7 +263,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
          dev->file, dev->block_num, BLKHDR2_ID, Id);
       if (block->read_errors == 0 || verbose >= 2) {
-        Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
       }
       block->read_errors++;
       unser_uint32(block->VolSessionId);
@@ -277,7 +277,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       Mmsg3(dev->errmsg,  _("Volume data error at %u:%u! Block length %u is insane (too large), probably due to a bad archive.\n"),
         dev->file, dev->block_num, block_len);
       if (block->read_errors == 0 || verbose >= 2) {
-        Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
       }
       block->read_errors++;
       return false;
@@ -300,10 +300,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
                         block_len-BLKHDR_CS_LENGTH);
       if (BlockCheckSum != CheckSum) {
         dev->dev_errno = EIO;
-        Mmsg5(dev->errmsg, _("Volume data error at %u:%u! Block checksum mismatch in block %u: calc=%x blk=%x\n"),
+         Mmsg5(dev->errmsg, _("Volume data error at %u:%u! Block checksum mismatch in block %u: calc=%x blk=%x\n"),
            dev->file, dev->block_num, (unsigned)BlockNumber, BlockCheckSum, CheckSum);
         if (block->read_errors == 0 || verbose >= 2) {
-           Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
         }
         block->read_errors++;
         if (!forge_on) {
@@ -350,7 +350,7 @@ bool write_block_to_device(DCR *dcr)
       /* Create a jobmedia record for this job */
       if (!dir_create_jobmedia_record(dcr)) {
         dev->dev_errno = EIO;
-        Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+         Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
            dcr->VolCatInfo.VolCatName, jcr->Job);
         set_new_volume_parameters(dcr);
         stat = false;
@@ -476,7 +476,7 @@ bool write_block_to_dev(DCR *dcr)
       dev->file_size = 0;            /* reset file size */
 
       if (dev_state(dev, ST_TAPE) && weof_dev(dev, 1) != 0) {           /* write eof */
-        Dmsg0(190, "WEOF error in max file size.\n");
+         Dmsg0(190, "WEOF error in max file size.\n");
         terminate_writing_volume(dcr);
         dev->dev_errno = ENOSPC;
         return false;
@@ -484,9 +484,9 @@ bool write_block_to_dev(DCR *dcr)
 
       /* Create a JobMedia record so restore can seek */
       if (!dir_create_jobmedia_record(dcr)) {
-        Dmsg0(190, "Error from create_job_media.\n");
+         Dmsg0(190, "Error from create_job_media.\n");
         dev->dev_errno = EIO;
-         Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+          Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
               dcr->VolCatInfo.VolCatName, jcr->Job);
          terminate_writing_volume(dcr);
          dev->dev_errno = EIO;
@@ -494,7 +494,7 @@ bool write_block_to_dev(DCR *dcr)
       }
       dev->VolCatInfo.VolCatFiles = dev->file;
       if (!dir_update_volume_info(dcr, false)) {
-        Dmsg0(190, "Error from update_vol_info.\n");
+         Dmsg0(190, "Error from update_vol_info.\n");
         terminate_writing_volume(dcr);
         dev->dev_errno = EIO;
         return false;
@@ -516,6 +516,60 @@ bool write_block_to_dev(DCR *dcr)
       /* Set new file/block parameters for current dcr */
       set_new_file_parameters(dcr);
    }
+   
+   /* Limit maximum part size to value specified by user (not applicable to tapes/fifos) */
+   if (!(dev->state & (ST_TAPE|ST_FIFO)) && 
+        (dev->max_part_size > 0) &&
+       ((dev->part_size + block->binbuf) >= dev->max_part_size)) {
+      if (dev->part < dev->num_parts) {
+         Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
+              dev->part, dev->num_parts, dev_name(dev));
+        dev->dev_errno = EIO;
+        return false;
+      }
+      
+      if (open_next_part(dev) < 0) {
+         Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"),
+               dev_name(dev), strerror_dev(dev));
+        dev->dev_errno = EIO;
+        return false;
+      }
+      
+      dev->VolCatInfo.VolCatParts = dev->num_parts;
+           
+      if (!dir_update_volume_info(dcr, false)) {
+         Dmsg0(190, "Error from update_vol_info.\n");
+        dev->dev_errno = EIO;
+        return false;
+      }
+   }
+   
+   if (dev->free_space_errno < 0) { /* Error while getting free space */
+      char ed1[50];
+      char ed2[50];
+      Dmsg1(10, "Cannot get free space on the device ERR=%s.\n", dev->errmsg);
+      Jmsg(jcr, M_FATAL, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d, errmsg=%s).\n"),
+          dev->VolCatInfo.VolCatName,
+          dev->file, dev->block_num, dev->dev_name,
+          edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2),
+          dev->free_space_errno, dev->errmsg);
+      dev->dev_errno = -dev->free_space_errno;
+      return false;
+   }
+   
+   if (((dev->free_space_errno > 0) && ((dev->part_size + block->binbuf) >= dev->free_space))) {
+      char ed1[50];
+      char ed2[50];
+      Dmsg0(10, "==== Just enough free space on the device to write the current part...\n");
+      Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d).\n"),
+           dev->VolCatInfo.VolCatName,
+           dev->file, dev->block_num, dev->dev_name,
+           edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2),
+           dev->free_space_errno);
+      terminate_writing_volume(dcr);
+      dev->dev_errno = ENOSPC;
+      return false;
+   }   
 
    dev->VolCatInfo.VolCatWrites++;
    Dmsg1(300, "Write block of %u bytes\n", wlen);
@@ -548,14 +602,14 @@ bool write_block_to_dev(DCR *dcr)
            dev->dev_errno = ENOSPC;        /* out of space */
         }
         if (dev->dev_errno != ENOSPC) {
-           Jmsg4(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"),
+            Jmsg4(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"),
               dev->file, dev->block_num, dev->dev_name, be.strerror());
         }
       } else {
        dev->dev_errno = ENOSPC;            /* out of space */
       }
       if (dev->dev_errno == ENOSPC) {
-        Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes got %d.\n"),
+         Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes got %d.\n"),
            dev->VolCatInfo.VolCatName,
            dev->file, dev->block_num, dev->dev_name, wlen, stat);
       }
@@ -580,19 +634,19 @@ bool write_block_to_dev(DCR *dcr)
         /* Now back up over what we wrote and read the last block */
         if (!bsf_dev(dev, 1)) {
            ok = false;
-           Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
+            Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
         }
         if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) {
            ok = false;
-           Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
+            Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
         }
         /* Backspace over record */
         if (ok && !bsr_dev(dev, 1)) {
            ok = false;
-           Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
+            Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
            /*
             *  On FreeBSD systems, if the user got here, it is likely that his/her
-            *    tape drive is "frozen".  The correct thing to do is a
+             *    tape drive is "frozen".  The correct thing to do is a
             *    rewind(), but if we do that, higher levels in cleaning up, will
             *    most likely write the EOS record over the beginning of the
             *    tape.  The rewind *is* done later in mount.c when another
@@ -605,10 +659,10 @@ bool write_block_to_dev(DCR *dcr)
            /* Note, this can destroy dev->errmsg */
            dcr->block = lblock;
            if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
-              Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), dev->errmsg);
+               Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), dev->errmsg);
            } else {
               if (lblock->BlockNumber+1 == block->BlockNumber) {
-                 Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
+                  Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
               } else {
                  Jmsg(jcr, M_ERROR, 0, _(
 "Re-read of last block failed. Last block=%u Current block=%u.\n"),
@@ -650,6 +704,7 @@ bool write_block_to_dev(DCR *dcr)
    dcr->WroteVol = true;
    dev->file_addr += wlen;           /* update file address */
    dev->file_size += wlen;
+   dev->part_size += wlen;
 
    Dmsg2(300, "write_block: wrote block %d bytes=%d\n", dev->block_num, wlen);
    empty_block(block);
@@ -675,11 +730,16 @@ static bool terminate_writing_volume(DCR *dcr)
    if (weof_dev(dev, 1) != 0) {        /* end the tape */
       dev->VolCatInfo.VolCatErrors++;
       Jmsg(dcr->jcr, M_ERROR, 0, "Error writing final EOF to tape. This tape may not be readable.\n"
-          "%s", dev->errmsg);
+           "%s", dev->errmsg);
       ok = false;
       Dmsg0(100, "WEOF error.\n");
    }
    dev->VolCatInfo.VolCatFiles = dev->file;
+   
+   if (dev_cap(dev, CAP_REQMOUNT)) { /* Write the current (and last) part. */
+      open_next_part(dev);
+   }
+   
    if (!dir_update_volume_info(dcr, false)) {
       ok = false;
    }
@@ -743,7 +803,7 @@ bool read_block_from_dev(DCR *dcr, bool check_block_numbers)
    JCR *jcr = dcr->jcr;
    DEVICE *dev = dcr->dev;
    DEV_BLOCK *block = dcr->block;
-
+   
    if (dev_state(dev, ST_EOT)) {
       return false;
    }
@@ -759,6 +819,27 @@ reread:
       block->read_len = 0;
       return false;
    }
+   
+   /*Dmsg1(200, "dev.c 111->file_size=%u\n",(unsigned int)dev->file_size);
+   Dmsg1(200, "dev.c          lseek=%u\n",(unsigned int)lseek(dev->fd, 0, SEEK_CUR));
+   Dmsg1(200, "dev.c dev->part_start=%u\n",(unsigned int)dev->part_start);
+   Dmsg1(200, "dev.c dev->file_size-dev->part_start=%u\n",(unsigned int)dev->file_size-dev->part_start);
+   Dmsg1(200, "dev.c dev->part_size=%u\n", (unsigned int)dev->part_size);
+   Dmsg1(200, "dev.c dev->part=%u\n", (unsigned int)dev->part);
+   Dmsg1(200, "dev.c dev->VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
+   Dmsg3(200, "dev.c Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0), ((dev->file_size-dev->part_start) == dev->part_size), (dev->part <= dev->VolCatInfo.VolCatParts));*/
+   /* Check for part file end */
+   if ((dev->num_parts > 0) &&
+       ((dev->file_size-dev->part_start) == dev->part_size) && 
+       (dev->part < dev->num_parts)) {
+      if (open_next_part(dev) < 0) {
+         Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"),
+              dev_name(dev), strerror_dev(dev));
+        dev->dev_errno = EIO;
+        return false;
+      }
+   }
+   
    retry = 0;
    do {
 //    uint32_t *bp = (uint32_t *)block->buf;
@@ -836,17 +917,17 @@ reread:
       Pmsg1(000, "%s", dev->errmsg);
       /* Attempt to reposition to re-read the block */
       if (dev->state & ST_TAPE) {
-        Dmsg0(200, "BSR for reread; block too big for buffer.\n");
+         Dmsg0(200, "BSR for reread; block too big for buffer.\n");
         if (!bsr_dev(dev, 1)) {
-           Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev));
+            Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev));
            block->read_len = 0;
            return false;
         }
       } else {
-        Dmsg0(200, "Seek to beginning of block for reread.\n");
-        off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */
+         Dmsg0(200, "Seek to beginning of block for reread.\n");
+        off_t pos = lseek_dev(dev, (off_t)0, SEEK_CUR); /* get curr pos */
         pos -= block->read_len;
-        lseek(dev->fd, pos, SEEK_SET);
+        lseek_dev(dev, pos, SEEK_SET);
         dev->file_addr = pos;
       }
       Mmsg1(dev->errmsg, _("Setting block buffer size to %u bytes.\n"), block->block_len);
@@ -910,9 +991,9 @@ reread:
     */
    Dmsg0(200, "At end of read block\n");
    if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
-      off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */
+      off_t pos = lseek_dev(dev, (off_t)0, SEEK_CUR); /* get curr pos */
       pos -= (block->read_len - block->block_len);
-      lseek(dev->fd, pos, SEEK_SET);
+      lseek_dev(dev, pos, SEEK_SET);
       Dmsg2(200, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
            block->read_len);
       dev->file_addr = pos;
index b8967bfb292ff6d8a6324cfea5a472c4761d9b2b..1aa389c542be8f0168faf3cacf0cb2a381c67fef 100644 (file)
@@ -29,7 +29,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
 
 /* Forward referenced functions */
 void set_os_device_parameters(DEVICE *dev);
+int mount_dev(DEVICE* dev, int timeout);
+int unmount_dev(DEVICE* dev, int timeout);
+int write_part(DEVICE *dev);
+char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg);
+void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name);
+void update_free_space_dev(DEVICE* dev);
 
 /*
  * Allocate and initialize the DEVICE structure
@@ -109,9 +115,34 @@ init_dev(DEVICE *dev, DEVRES *device)
         dev->dev_errno = errno;
       }
       Emsg2(M_FATAL, 0, "Unable to stat device %s : %s\n", device->device_name,
-           be.strerror());
+        be.strerror());
       return NULL;
    }
+   
+   /* If the device requires mount :
+    * - Check that the mount point is available 
+    * - Check that (un)mount commands are defined
+    */
+   if (device->cap_bits & CAP_REQMOUNT) {
+      if (stat(device->mount_point, &statp) < 0) {
+        berrno be;
+        if (dev) {
+           dev->dev_errno = errno;
+        }
+         Emsg2(M_FATAL, 0, "Unable to stat mount point %s : %s\n", device->mount_point,
+           be.strerror());
+        return NULL;
+      }
+      if (!device->mount_command || !device->unmount_command) {
+         Emsg0(M_FATAL, 0, "Mount and unmount commands must defined for a device which requires mount.\n");
+        return NULL;
+      }
+      if (!device->write_part_command) {
+         Emsg0(M_FATAL, 0, "Write part command must be defined for a device which requires mount.\n");
+        return NULL;
+      }
+   }
+   
    tape = false;
    fifo = false;
    if (S_ISDIR(statp.st_mode)) {
@@ -151,6 +182,12 @@ init_dev(DEVICE *dev, DEVRES *device)
    dev->vol_poll_interval = device->vol_poll_interval;
    dev->max_spool_size = device->max_spool_size;
    dev->drive_index = device->drive_index;
+   if (tape) { /* No parts on tapes */
+      dev->max_part_size = 0;
+   }
+   else {
+      dev->max_part_size = device->max_part_size;
+   }
    /* Sanity check */
    if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
       dev->vol_poll_interval = 60;
@@ -213,10 +250,48 @@ init_dev(DEVICE *dev, DEVRES *device)
    dev->fd = -1;
    dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link));
    Dmsg2(29, "init_dev: tape=%d dev_name=%s\n", dev_is_tape(dev), dev->dev_name);
-
+   
    return dev;
 }
 
+/* 
+ * Write the current volume/part filename to archive_name.
+ */
+
+void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name) {
+   char partnumber[20];
+   
+   if (dev_cap(dev, CAP_REQMOUNT)) {
+        /* If we try to open the last part, just open it from disk, 
+        * otherwise, open it from the spooling directory */
+      if (dev->part < dev->num_parts) {
+        pm_strcpy(archive_name, dev->device->mount_point);
+      }
+      else {
+        /* Use the working directory if spool directory is not defined */
+        if (dev->device->spool_directory) {
+           pm_strcpy(archive_name, dev->device->spool_directory);
+        } else {
+           pm_strcpy(archive_name, working_directory);
+        }
+      }
+   }
+   else {
+      pm_strcpy(archive_name, dev->dev_name);
+   }
+      
+   if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
+      pm_strcat(archive_name, "/");
+   }
+   pm_strcat(archive_name, VolName);
+   /* if part != 0, append .# to the filename (where # is the part number) */
+   if (dev->part != 0) {
+      pm_strcat(archive_name, ".");
+      bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
+      pm_strcat(archive_name, partnumber);
+   }
+}  
+
 /* Open the device with the operating system and
  * initialize buffer pointers.
  *
@@ -229,8 +304,6 @@ init_dev(DEVICE *dev, DEVRES *device)
 int
 open_dev(DEVICE *dev, char *VolName, int mode)
 {
-   POOLMEM *archive_name;
-
    if (dev->state & ST_OPENED) {
       /*
        *  *****FIXME***** how to handle two threads wanting
@@ -254,8 +327,8 @@ open_dev(DEVICE *dev, char *VolName, int mode)
    Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev),
         dev->dev_name, dev->VolCatInfo.VolCatName);
    dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
-   dev->file_size = 0;
    if (dev->state & (ST_TAPE|ST_FIFO)) {
+      dev->file_size = 0;
       int timeout;
       Dmsg0(29, "open_dev: device is tape\n");
       if (mode == OPEN_READ_WRITE) {
@@ -265,7 +338,7 @@ open_dev(DEVICE *dev, char *VolName, int mode)
       } else if (mode == OPEN_WRITE_ONLY) {
         dev->mode = O_WRONLY | O_BINARY;
       } else {
-        Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
+         Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
       }
       timeout = dev->max_open_wait;
       errno = 0;
@@ -280,12 +353,12 @@ open_dev(DEVICE *dev, char *VolName, int mode)
            continue;
         }
         if (errno == EBUSY && timeout-- > 0) {
-           Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, be.strerror());
+            Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, be.strerror());
            bmicrosleep(1, 0);
            continue;
         }
         dev->dev_errno = errno;
-        Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n"),
+         Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n"),
               dev->dev_name, be.strerror());
         /* Stop any open timer we set */
         if (dev->tid) {
@@ -309,21 +382,49 @@ open_dev(DEVICE *dev, char *VolName, int mode)
       }
       Dmsg1(29, "open_dev: tape %d opened\n", dev->fd);
    } else {
+      POOL_MEM archive_name(PM_FNAME);
+      struct stat filestat;
       /*
        * Handle opening of File Archive (not a tape)
-       */
+       */     
+      if (dev->part == 0) {
+        dev->file_size = 0;
+      }
+      dev->part_size = 0;
+      
+      /* if num_parts has not been set, but VolCatInfo is available, copy
+       * it from the VolCatInfo.VolCatParts */
+      if (dev->num_parts < dev->VolCatInfo.VolCatParts) {
+        dev->num_parts = dev->VolCatInfo.VolCatParts;
+      }
+      
       if (VolName == NULL || *VolName == 0) {
-        Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"),
+         Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"),
            dev->dev_name);
         return -1;
       }
-      archive_name = get_pool_memory(PM_FNAME);
-      pm_strcpy(archive_name, dev->dev_name);
-      if (archive_name[strlen(archive_name)] != '/') {
-        pm_strcat(archive_name, "/");
+      get_filename(dev, VolName, archive_name);
+
+      if (dev_cap(dev, CAP_REQMOUNT) && (dev->num_parts > 0)) {
+        if (mount_dev(dev, 1) < 0) {
+            Mmsg(dev->errmsg, _("Could not mount device %s.\n"),
+                dev->dev_name);
+           Emsg0(M_FATAL, 0, dev->errmsg);
+           dev->fd = -1;
+           return dev->fd;
+        }
       }
-      pm_strcat(archive_name, VolName);
-      Dmsg1(29, "open_dev: device is disk %s\n", archive_name);
+           
+      Dmsg2(29, "open_dev: device is disk %s (mode:%d)\n", archive_name.c_str(), mode);
+      dev->openmode = mode;
+      
+      /* If we are not trying to access the last part, set mode to OPEN_READ_ONLY,
+       * as writing would be an error.
+       */
+      if (dev->part < dev->num_parts) {
+        mode = OPEN_READ_ONLY;
+      }
+      
       if (mode == OPEN_READ_WRITE) {
         dev->mode = O_CREAT | O_RDWR | O_BINARY;
       } else if (mode == OPEN_READ_ONLY) {
@@ -331,26 +432,503 @@ open_dev(DEVICE *dev, char *VolName, int mode)
       } else if (mode == OPEN_WRITE_ONLY) {
         dev->mode = O_WRONLY | O_BINARY;
       } else {
-        Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
+         Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
       }
       /* If creating file, give 0640 permissions */
-      if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) {
+      if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) {
         berrno be;
         dev->dev_errno = errno;
-        Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, be.strerror());
+         Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.strerror());
         Emsg0(M_FATAL, 0, dev->errmsg);
       } else {
         dev->dev_errno = 0;
         dev->state |= ST_OPENED;
         dev->use_count = 1;
         update_pos_dev(dev);                /* update position */
+        if (fstat(dev->fd, &filestat) < 0) {
+           berrno be;
+           dev->dev_errno = errno;
+            Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.strerror());
+           Emsg0(M_FATAL, 0, dev->errmsg);
+        }
+        else {
+           dev->part_size = filestat.st_size;
+        }
+      }
+      Dmsg4(29, "open_dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", dev->fd, dev->part, dev->num_parts, dev->part_size);
+      if ((dev->mode != OPEN_READ_ONLY) && ((dev->free_space_errno == 0) || (dev->num_parts == dev->part))) {
+        update_free_space_dev(dev);
       }
-      Dmsg1(29, "open_dev: disk fd=%d opened\n", dev->fd);
-      free_pool_memory(archive_name);
    }
    return dev->fd;
 }
 
+/* (Un)mount the device */
+int do_mount_dev(DEVICE* dev, int mount, int dotimeout) {
+   POOL_MEM ocmd(PM_FNAME);
+   POOLMEM* results;
+   results = get_pool_memory(PM_MESSAGE);
+   char* icmd;
+   int status, timeout;
+   
+   if (mount) {
+      icmd = dev->device->mount_command;
+   }
+   else {
+      icmd = dev->device->unmount_command;
+   }
+   
+   edit_device_codes_dev(dev, ocmd.c_str(), icmd);
+   
+   Dmsg2(29, "do_mount_dev: cmd=%s state=%d\n", ocmd.c_str(), dev->state & ST_MOUNTED);
+
+   if (dotimeout) {
+      /* Try at most 5 times to (un)mount the device. This should perhaps be configurable. */
+      timeout = 5;
+   }
+   else {
+      timeout = 0;
+   }
+   /* If busy retry each second */
+   while ((status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results)) != 0) {
+      if (--timeout > 0) {
+         Dmsg2(40, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results);
+        /* Sometimes the device cannot be mounted because it is already mounted.
+         * Try to unmount it, then remount it */
+        if (mount) {
+            Dmsg1(40, "Trying to unmount the device %s...\n", dev->dev_name);
+           do_mount_dev(dev, 0, 0);
+        }
+        bmicrosleep(1, 0);
+        continue;
+      }
+      free_pool_memory(results);
+      Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->dev_name, results);
+      return -1;
+   }
+   
+   if (mount) {
+     dev->state |= ST_MOUNTED;
+   }
+   else {
+     dev->state &= ~ST_MOUNTED;
+   }
+   free_pool_memory(results);
+   
+   Dmsg1(29, "do_mount_dev: end_state=%d\n", dev->state & ST_MOUNTED);
+   return 0;
+}
+
+/* Only for devices that requires mount.
+ * Try to find the volume name of the loaded device, and open the
+ * first part of this volume. 
+ *
+ * Returns 0 if read_dev_volume_label can now read the label,
+ * -1 if an error occured, and read_dev_volume_label_guess must abort with an IO_ERROR.
+ *
+ * To guess the device name, it lists all the files on the DVD, and searches for a 
+ * file which has a minimum size (500 bytes). If this file has a numeric extension,
+ * like part files, try to open the file which has no extension (e.g. the first
+ * part file).
+ * So, if the DVD does not contains a Bacula volume, a random file is opened,
+ * and no valid label could be read from this file.
+ */
+int open_guess_name_dev(DEVICE *dev) {
+   Dmsg1(29, "open_guess_name_dev: dev=%s\n", dev->dev_name);
+   POOL_MEM guessedname(PM_FNAME);
+   DIR* dp;
+   struct dirent *entry, *result;
+   struct stat statp;
+   int index;
+   int name_max;
+   
+   if (!dev_cap(dev, CAP_REQMOUNT)) {
+      Dmsg1(100, "open_guess_name_dev: device does not require mount, returning 0. dev=%s\n", dev->dev_name);
+      return 0;
+   }
+
+#ifndef HAVE_DIRENT_H
+   Dmsg0(29, "open_guess_name_dev: readdir not available, cannot guess volume name\n");
+   return 0; 
+#endif
+   
+   update_free_space_dev(dev);
+
+   if (mount_dev(dev, 1) < 0) {
+      /* If the device cannot be mounted, check if it is writable */
+      if (dev->free_space_errno >= 0) {
+         Dmsg1(100, "open_guess_name_dev: device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name);
+        return 0;
+      }
+      else {
+         Dmsg1(100, "open_guess_name_dev: device cannot be mounted, and is not writable, returning 0. dev=%s\n", dev->dev_name);
+        /* read_dev_volume_label_guess must now check dev->free_space_errno to understand that the media is not writable. */
+        return 0;
+      }
+   }
+      
+   name_max = pathconf(".", _PC_NAME_MAX);
+   if (name_max < 1024) {
+      name_max = 1024;
+   }
+      
+   if (!(dp = opendir(dev->device->mount_point))) {
+      berrno be;
+      dev->dev_errno = errno;
+      Dmsg3(29, "open_guess_name_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
+      return -1;
+   }
+   
+   entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
+   while (1) {
+      if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+        dev->dev_errno = ENOENT;
+         Dmsg2(29, "open_guess_name_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
+        closedir(dp);
+        return -1;
+      }
+      
+      ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
+      
+      if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+        continue;
+      }
+      
+      pm_strcpy(guessedname, dev->device->mount_point);
+      if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') {
+         pm_strcat(guessedname, "/");
+      }
+      pm_strcat(guessedname, entry->d_name);
+      
+      if (stat(guessedname.c_str(), &statp) < 0) {
+        berrno be;
+         Dmsg3(29, "open_guess_name_dev: failed to stat %s (dev=%s), ERR=%s\n",
+              guessedname.c_str(), dev->dev_name, be.strerror());
+        continue;
+      }
+      
+      if (!S_ISREG(statp.st_mode) || (statp.st_size < 500)) {
+         Dmsg2(100, "open_guess_name_dev: %s is not a regular file, or less than 500 bytes (dev=%s)\n", 
+              guessedname.c_str(), dev->dev_name);
+        continue;
+      }
+      
+      /* Ok, we found a good file, remove the part extension if possible. */
+      for (index = strlen(guessedname.c_str())-1; index >= 0; index--) {
+         if ((guessedname.c_str()[index] == '/') || 
+             (guessedname.c_str()[index] < '0') || 
+             (guessedname.c_str()[index] > '9')) {
+           break;
+        }
+         if (guessedname.c_str()[index] == '.') {
+            guessedname.c_str()[index] = '\0';
+           break;
+        }
+      }
+      
+      if ((stat(guessedname.c_str(), &statp) < 0) || (statp.st_size < 500)) {
+        /* The file with extension truncated does not exists or is too small, so use it with its extension. */
+        berrno be;
+         Dmsg3(100, "open_guess_name_dev: failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n", 
+              guessedname.c_str(), dev->dev_name, be.strerror());
+        pm_strcpy(guessedname, dev->device->mount_point);
+         if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') {
+            pm_strcat(guessedname, "/");
+        }
+        pm_strcat(guessedname, entry->d_name);
+        continue;
+      }
+      break;
+   }
+   
+   closedir(dp);
+   
+   if (dev->fd >= 0) {
+      close(dev->fd);
+   }
+     
+   if ((dev->fd = open(guessedname.c_str(), O_RDONLY | O_BINARY)) < 0) {
+      berrno be;
+      dev->dev_errno = errno;
+      Dmsg3(29, "open_guess_name_dev: failed to open %s (dev=%s), ERR=%s\n", 
+           guessedname.c_str(), dev->dev_name, be.strerror());
+      if (open_first_part(dev) < 0) {
+        berrno be;
+        dev->dev_errno = errno;
+         Mmsg1(&dev->errmsg, _("Could not open_first_part, ERR=%s\n"), be.strerror());
+        Emsg0(M_FATAL, 0, dev->errmsg);         
+      }
+      return -1;
+   }
+   dev->part_start = 0;
+   dev->part_size = statp.st_size;
+   dev->part = 0;
+   dev->state |= ST_OPENED;
+   dev->use_count = 1;
+   
+   Dmsg2(29, "open_guess_name_dev: %s opened (dev=%s)\n", guessedname.c_str(), dev->dev_name);
+   
+   return 0;
+}
+
+/* Mount the device.
+ * If timeout, wait until the mount command returns 0.
+ * If !timeout, try to mount the device only once.
+ */
+int mount_dev(DEVICE* dev, int timeout) {
+   if (dev->state & ST_MOUNTED) {
+      Dmsg0(100, "mount_dev: Device already mounted\n");
+      return 0;
+   }
+   else {
+      return do_mount_dev(dev, 1, timeout);
+   }
+}
+
+/* Unmount the device
+ * If timeout, wait until the unmount command returns 0.
+ * If !timeout, try to unmount the device only once.
+ */
+int unmount_dev(DEVICE* dev, int timeout) {
+   if (dev->state & ST_MOUNTED) {
+      return do_mount_dev(dev, 0, timeout);
+   }
+   else {
+      Dmsg0(100, "mount_dev: Device already unmounted\n");
+      return 0;
+   }
+}
+
+/* Update the free space on the device */
+void update_free_space_dev(DEVICE* dev) {
+   POOL_MEM ocmd(PM_FNAME);
+   POOLMEM* results;
+   char* icmd;
+   int timeout;
+   char* statstr;
+   long long int free;
+   
+   icmd = dev->device->free_space_command;
+   
+   if (!icmd) {
+      dev->free_space = 0;
+      dev->free_space_errno = 0;
+      Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
+      return;
+   }
+   
+   edit_device_codes_dev(dev, ocmd.c_str(), icmd);
+   
+   Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
+
+   results = get_pool_memory(PM_MESSAGE);
+   
+   /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
+   timeout = 3;
+   
+   while (1) {
+      if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
+         Dmsg1(100, "Free space program run : %s\n", results);
+         /* We also need negatives values, so we can't use dev->free_space, which is unsigned */
+        free = strtoll(results, &statstr, 10);
+        if (results != statstr) { /* Something parsed */
+           if (free >= 0) {
+              dev->free_space = free;
+              dev->free_space_errno = 1;
+               Mmsg0(dev->errmsg, "");
+              break;
+           }
+           else {
+              dev->free_space_errno = free;
+              dev->free_space = 0;
+               if (*statstr == '\n') {
+                 statstr++;
+              }
+               if (statstr[strlen(statstr)-1] == '\n') {
+                 statstr[strlen(statstr)-1] = 0;
+              }
+               Mmsg1(dev->errmsg, "Error while getting free space (%s)", statstr);
+           }
+        }
+        else {
+           dev->free_space = 0;
+           dev->free_space_errno = -EPIPE;
+            Mmsg1(dev->errmsg, "Error while getting free space (output=%s)", results);
+        }
+      }
+      else {
+        dev->free_space = 0;
+        dev->free_space_errno = -EPIPE;
+         Mmsg1(dev->errmsg, "Cannot run free space command (%s)", results);
+      }
+      
+      if (--timeout > 0) {
+         Dmsg4(40, "Cannot get free space on device %s. free_space=%lld, free_space_errno=%d ERR=%s\n", dev->dev_name, 
+              dev->free_space, dev->free_space_errno, dev->errmsg);
+        bmicrosleep(1, 0);
+        continue;
+      }
+
+      dev->dev_errno = -dev->free_space_errno;
+      Dmsg4(40, "Cannot get free space on device %s. free_space=%lld, free_space_errno=%d ERR=%s\n",
+           dev->dev_name, dev->free_space, dev->free_space_errno, dev->errmsg);
+      free_pool_memory(results);
+      return;
+   }
+   
+   free_pool_memory(results);
+   
+   Dmsg2(29, "update_free_space_dev: free_space=%lld, free_space_errno=%d\n", dev->free_space, dev->free_space_errno);
+}
+
+int write_part(DEVICE *dev) {
+   Dmsg1(29, "write_part: device is %s\n", dev->dev_name);
+   
+   if (unmount_dev(dev, 1) < 0) {
+      Dmsg0(29, "write_part: unable to unmount the device\n");
+   }
+   
+   POOL_MEM ocmd(PM_FNAME);
+   POOLMEM *results;
+   results = get_pool_memory(PM_MESSAGE);
+   char* icmd;
+   int status;
+   int timeout;
+   
+   icmd = dev->device->write_part_command;
+   
+   edit_device_codes_dev(dev, ocmd.c_str(), icmd);
+      
+   /* Wait at most the time a maximum size part is written in DVD 0.5x speed
+    * FIXME: Minimum speed should be in device configuration 
+    */
+   timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
+   
+   Dmsg2(29, "write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
+      
+   status = run_program_full_output(ocmd.c_str(), timeout, results);
+   if (status != 0) {
+      Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", results);
+      dev->dev_errno = EIO;
+      free_pool_memory(results);
+      return -1;
+   }
+   else {
+      Dmsg1(29, "write_part: command output=%s\n", results);
+      POOL_MEM archive_name(PM_FNAME);
+      get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+      unlink(archive_name.c_str());
+      free_pool_memory(results);
+      return 0;
+   }
+}
+
+/* Open the next part file.
+ *  - Close the fd
+ *  - Increment part number 
+ *  - Reopen the device
+ */
+int open_next_part(DEVICE *dev) {
+   int state;
+      
+   Dmsg3(29, "open_next_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode);
+   /* When appending, do not open a new part if the current is empty */
+   if ((dev->state & ST_APPEND) && (dev->part == dev->num_parts) && (dev->part_size == 0)) {
+      Dmsg0(29, "open_next_part exited immediatly (dev->part_size == 0).\n");
+      return dev->fd;
+   }
+   
+   if (dev->fd >= 0) {
+      close(dev->fd);
+   }
+   
+   dev->fd = -1;
+   
+   state = dev->state;
+   dev->state &= ~ST_OPENED;
+   
+   if ((dev_cap(dev, CAP_REQMOUNT)) && (dev->part == dev->num_parts) && (dev->state & ST_APPEND)) {
+      if (write_part(dev) < 0) {
+        return -1;
+      }
+   }
+     
+   dev->part_start += dev->part_size;
+   dev->part++;
+   
+   if ((dev->num_parts < dev->part) && (dev->state & ST_APPEND)) {
+      dev->num_parts = dev->part;
+      
+      /* Check that the next part file does not exists.
+       * If it does, move it away... */
+      POOL_MEM archive_name(PM_FNAME);
+      POOL_MEM archive_bkp_name(PM_FNAME);
+      struct stat buf;
+      
+      get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+      
+      /* Check if the next part exists. */
+      if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
+         Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
+        pm_strcpy(archive_bkp_name, archive_name.c_str());
+         pm_strcat(archive_bkp_name, ".bak");
+        unlink(archive_bkp_name.c_str()); 
+        
+        /* First try to rename it */
+        if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) {
+           berrno be;
+            Dmsg3(29, "open_next_part can't rename %s to %s, ERR=%s\n", 
+                 archive_name.c_str(), archive_bkp_name.c_str(), be.strerror());
+           /* Then try to unlink it */
+           if (unlink(archive_name.c_str()) < 0) {
+              berrno be;
+              dev->dev_errno = errno;
+               Mmsg2(&dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
+                     archive_name.c_str(), be.strerror());
+              Emsg0(M_FATAL, 0, dev->errmsg);
+              return -1;
+           }
+        }
+      }
+   }
+   
+   if (open_dev(dev, dev->VolCatInfo.VolCatName, dev->openmode) < 0) {
+      return -1;
+   }
+   else {
+      dev->state = state;
+      return dev->fd;
+   }
+}
+
+/* Open the first part file.
+ *  - Close the fd
+ *  - Reopen the device
+ */
+int open_first_part(DEVICE *dev) {
+   int state;
+      
+   Dmsg3(29, "open_first_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode);
+   if (dev->fd >= 0) {
+      close(dev->fd);
+   }
+   
+   dev->fd = -1;
+   state = dev->state;
+   dev->state &= ~ST_OPENED;
+   
+   dev->part_start = 0;
+   dev->part = 0;
+   
+   if (open_dev(dev, dev->VolCatInfo.VolCatName, dev->openmode)) {
+      dev->state = state;
+      return dev->fd;
+   }
+   else {
+      return 0;
+   }
+}
+
 #ifdef debug_tracing
 #undef rewind_dev
 bool _rewind_dev(char *file, int line, DEVICE *dev)
@@ -360,6 +938,108 @@ bool _rewind_dev(char *file, int line, DEVICE *dev)
 }
 #endif
 
+/* Protected version of lseek, which opens the right part if necessary */
+off_t lseek_dev(DEVICE *dev, off_t offset, int whence) {
+   int pos, openmode;
+   
+   if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */
+      return lseek(dev->fd, offset, whence);
+   }
+      
+   switch(whence) {
+      case SEEK_SET:
+         Dmsg1(100, "lseek_dev SEEK_SET called %d\n", offset);
+        if ((uint64_t)offset >= dev->part_start) {
+           if ((uint64_t)(offset - dev->part_start) < dev->part_size) {
+              /* We are staying in the current part, just seek */
+              if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) {
+                 return pos;   
+              }
+              else {
+                 return pos + dev->part_start;
+              }
+           }
+           else {
+              /* Load next part, and start again */
+              if (open_next_part(dev) < 0) {
+                  Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
+                 return -1;
+              }
+              return lseek_dev(dev, offset, SEEK_SET);
+           }
+        }
+        else {
+           /* pos < dev->part_start :
+            * We need to access a previous part, 
+            * so just load the first one, and seek again
+            * until the right one is loaded */
+           if (open_first_part(dev) < 0) {
+               Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
+              return -1;
+           }
+           return lseek_dev(dev, offset, SEEK_SET);
+        }
+        break;
+      case SEEK_CUR:
+         Dmsg1(100, "lseek_dev SEEK_CUR called %d\n", offset);
+        if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
+           return pos;   
+        }
+        pos += dev->part_start;
+        if (offset == 0) {
+           return pos;
+        }
+        else { /* Not used in Bacula, but should work */
+           return lseek_dev(dev, pos, SEEK_SET);
+        }
+        break;
+      case SEEK_END:
+         Dmsg1(100, "lseek_dev SEEK_END called %d\n", offset);
+        if (offset > 0) { /* Not used by bacula */
+            Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", offset);
+           errno = EINVAL;
+           return -1;
+        }
+        
+        if (dev->part == dev->num_parts) { /* The right part is already loaded */
+           if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
+              return pos;   
+           }
+           else {
+              return pos + dev->part_start;
+           }
+        }
+        else {
+           /* Load the first part, then load the next until we reach the last one.
+            * This is the only way to be sure we compute the right file address. */
+           /* Save previous openmode, and open all but last part read-only (useful for DVDs) */
+           openmode = dev->openmode;
+           dev->openmode = OPEN_READ_ONLY;
+           
+           /* Works because num_parts > 0. */
+           if (open_first_part(dev) < 0) {
+               Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
+              return -1;
+           }
+           while (dev->part < (dev->num_parts-1)) {
+              if (open_next_part(dev) < 0) {
+                  Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
+                 return -1;
+              }
+           }
+           dev->openmode = openmode;
+           if (open_next_part(dev) < 0) {
+               Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
+              return -1;
+           }
+           return lseek_dev(dev, 0, SEEK_END);
+        }
+        break;
+      default:
+        errno = EINVAL;
+        return -1;
+   }
+}
 
 /*
  * Rewind the device.
@@ -395,24 +1075,24 @@ bool rewind_dev(DEVICE *dev)
            berrno be;
            clrerror_dev(dev, MTREW);
            if (i == dev->max_rewind_wait) {
-              Dmsg1(200, "Rewind error, %s. retrying ...\n", be.strerror());
+               Dmsg1(200, "Rewind error, %s. retrying ...\n", be.strerror());
            }
            if (dev->dev_errno == EIO && i > 0) {
-              Dmsg0(200, "Sleeping 5 seconds.\n");
+               Dmsg0(200, "Sleeping 5 seconds.\n");
               bmicrosleep(5, 0);
               continue;
            }
-           Mmsg2(&dev->errmsg, _("Rewind error on %s. ERR=%s.\n"),
+            Mmsg2(&dev->errmsg, _("Rewind error on %s. ERR=%s.\n"),
               dev->dev_name, be.strerror());
            return false;
         }
         break;
       }
-   } else if (dev->state & ST_FILE) {
-      if (lseek(dev->fd, (off_t)0, SEEK_SET) < 0) {
+   } else if (dev->state & ST_FILE) {     
+      if (lseek_dev(dev, (off_t)0, SEEK_SET) < 0) {
         berrno be;
         dev->dev_errno = errno;
-        Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
+         Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         return false;
       }
@@ -445,7 +1125,7 @@ eod_dev(DEVICE *dev)
       return 1;
    }
    if (!(dev->state & ST_TAPE)) {
-      pos = lseek(dev->fd, (off_t)0, SEEK_END);
+      pos = lseek_dev(dev, (off_t)0, SEEK_END);
 //    Dmsg1(100, "====== Seek to %lld\n", pos);
       if (pos >= 0) {
         update_pos_dev(dev);
@@ -454,7 +1134,7 @@ eod_dev(DEVICE *dev)
       }
       dev->dev_errno = errno;
       berrno be;
-      Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
+      Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
             dev->dev_name, be.strerror());
       return 0;
    }
@@ -481,7 +1161,7 @@ eod_dev(DEVICE *dev)
 
    if (dev_cap(dev, CAP_MTIOCGET) && (dev_cap(dev, CAP_FASTFSF) || dev_cap(dev, CAP_EOM))) {
       if (dev_cap(dev, CAP_EOM)) {
-        Dmsg0(100,"Using EOM for EOM\n");
+         Dmsg0(100,"Using EOM for EOM\n");
         mt_com.mt_op = MTEOM;
         mt_com.mt_count = 1;
       }
@@ -489,9 +1169,9 @@ eod_dev(DEVICE *dev)
       if ((stat=ioctl(dev->fd, MTIOCTOP, (char *)&mt_com)) < 0) {
         berrno be;
         clrerror_dev(dev, mt_com.mt_op);
-        Dmsg1(50, "ioctl error: %s\n", be.strerror());
+         Dmsg1(50, "ioctl error: %s\n", be.strerror());
         update_pos_dev(dev);
-        Mmsg2(&dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
+         Mmsg2(&dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         return 0;
       }
@@ -499,7 +1179,7 @@ eod_dev(DEVICE *dev)
       if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
         berrno be;
         clrerror_dev(dev, -1);
-        Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
+         Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         return 0;
       }
@@ -521,9 +1201,9 @@ eod_dev(DEVICE *dev)
        */
       int file_num;
       for (file_num=dev->file; !(dev->state & ST_EOT); file_num++) {
-        Dmsg0(200, "eod_dev: doing fsf 1\n");
+         Dmsg0(200, "eod_dev: doing fsf 1\n");
         if (!fsf_dev(dev, 1)) {
-           Dmsg0(200, "fsf_dev error.\n");
+            Dmsg0(200, "fsf_dev error.\n");
            return 0;
         }
         /*
@@ -532,10 +1212,10 @@ eod_dev(DEVICE *dev)
          */
         if (file_num == (int)dev->file) {
            struct mtget mt_stat;
-           Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num);
+            Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num);
            if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 &&
                      mt_stat.mt_fileno >= 0) {
-              Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
+               Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
               dev->file = mt_stat.mt_fileno;
            }
            stat = 0;
@@ -554,7 +1234,7 @@ eod_dev(DEVICE *dev)
       stat = bsf_dev(dev, 1);
       /* If BSF worked and fileno is known (not -1), set file */
       if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) {
-        Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
+         Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
         dev->file = mt_stat.mt_fileno;
       } else {
         dev->file++;                 /* wing it -- not correct on all OSes */
@@ -589,12 +1269,12 @@ bool update_pos_dev(DEVICE *dev)
    if (dev->state & ST_FILE) {
       dev->file = 0;
       dev->file_addr = 0;
-      pos = lseek(dev->fd, (off_t)0, SEEK_CUR);
+      pos = lseek_dev(dev, (off_t)0, SEEK_CUR);
       if (pos < 0) {
         berrno be;
         dev->dev_errno = errno;
-        Pmsg1(000, "Seek error: ERR=%s\n", be.strerror());
-        Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
+         Pmsg1(000, "Seek error: ERR=%s\n", be.strerror());
+         Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         ok = false;
       } else {
@@ -634,7 +1314,7 @@ uint32_t status_dev(DEVICE *dev)
       if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
         berrno be;
         dev->dev_errno = errno;
-        Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
+         Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         return 0;
       }
@@ -643,45 +1323,45 @@ uint32_t status_dev(DEVICE *dev)
 #if defined(HAVE_LINUX_OS)
       if (GMT_EOF(mt_stat.mt_gstat)) {
         stat |= BMT_EOF;
-        Dmsg0(-20, " EOF");
+         Dmsg0(-20, " EOF");
       }
       if (GMT_BOT(mt_stat.mt_gstat)) {
         stat |= BMT_BOT;
-        Dmsg0(-20, " BOT");
+         Dmsg0(-20, " BOT");
       }
       if (GMT_EOT(mt_stat.mt_gstat)) {
         stat |= BMT_EOT;
-        Dmsg0(-20, " EOT");
+         Dmsg0(-20, " EOT");
       }
       if (GMT_SM(mt_stat.mt_gstat)) {
         stat |= BMT_SM;
-        Dmsg0(-20, " SM");
+         Dmsg0(-20, " SM");
       }
       if (GMT_EOD(mt_stat.mt_gstat)) {
         stat |= BMT_EOD;
-        Dmsg0(-20, " EOD");
+         Dmsg0(-20, " EOD");
       }
       if (GMT_WR_PROT(mt_stat.mt_gstat)) {
         stat |= BMT_WR_PROT;
-        Dmsg0(-20, " WR_PROT");
+         Dmsg0(-20, " WR_PROT");
       }
       if (GMT_ONLINE(mt_stat.mt_gstat)) {
         stat |= BMT_ONLINE;
-        Dmsg0(-20, " ONLINE");
+         Dmsg0(-20, " ONLINE");
       }
       if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
         stat |= BMT_DR_OPEN;
-        Dmsg0(-20, " DR_OPEN");
+         Dmsg0(-20, " DR_OPEN");
       }
       if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
         stat |= BMT_IM_REP_EN;
-        Dmsg0(-20, " IM_REP_EN");
+         Dmsg0(-20, " IM_REP_EN");
       }
 #endif /* !SunOS && !OSF */
       if (dev_cap(dev, CAP_MTIOCGET)) {
-        Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+         Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
       } else {
-        Dmsg2(-20, " file=%d block=%d\n", -1, -1);
+         Dmsg2(-20, " file=%d block=%d\n", -1, -1);
       }
    } else {
       stat |= BMT_ONLINE | BMT_BOT;
@@ -758,6 +1438,7 @@ bool offline_dev(DEVICE *dev)
    dev->block_num = dev->file = 0;
    dev->file_size = 0;
    dev->file_addr = 0;
+   dev->part = 0;
 #ifdef MTUNLOCK
    mt_com.mt_op = MTUNLOCK;
    mt_com.mt_count = 1;
@@ -843,11 +1524,11 @@ fsf_dev(DEVICE *dev, int num)
       if (stat < 0 || ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
         berrno be;
         dev->state |= ST_EOT;
-        Dmsg0(200, "Set ST_EOT\n");
+         Dmsg0(200, "Set ST_EOT\n");
         clrerror_dev(dev, MTFSF);
-        Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
+         Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
-        Dmsg1(200, "%s", dev->errmsg);
+         Dmsg1(200, "%s", dev->errmsg);
         return false;
       }
       Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
@@ -877,7 +1558,7 @@ fsf_dev(DEVICE *dev, int num)
       mt_com.mt_op = MTFSF;
       mt_com.mt_count = 1;
       while (num-- && !(dev->state & ST_EOT)) {
-        Dmsg0(100, "Doing read before fsf\n");
+         Dmsg0(100, "Doing read before fsf\n");
         if ((stat = read(dev->fd, (char *)rbuf, rbuf_len)) < 0) {
            if (errno == ENOMEM) {     /* tape record exceeds buf len */
               stat = rbuf_len;        /* This is OK */
@@ -885,21 +1566,21 @@ fsf_dev(DEVICE *dev, int num)
               berrno be;
               dev->state |= ST_EOT;
               clrerror_dev(dev, -1);
-              Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno,
+               Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno,
                  be.strerror());
-              Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"),
+               Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"),
                  dev->dev_name, be.strerror());
-              Dmsg1(100, "%s", dev->errmsg);
+               Dmsg1(100, "%s", dev->errmsg);
               break;
            }
         }
         if (stat == 0) {                /* EOF */
            update_pos_dev(dev);
-           Dmsg1(100, "End of File mark from read. File=%d\n", dev->file+1);
+            Dmsg1(100, "End of File mark from read. File=%d\n", dev->file+1);
            /* Two reads of zero means end of tape */
            if (dev->state & ST_EOF) {
               dev->state |= ST_EOT;
-              Dmsg0(100, "Set ST_EOT\n");
+               Dmsg0(100, "Set ST_EOT\n");
               break;
            } else {
               dev->state |= ST_EOF;
@@ -912,17 +1593,17 @@ fsf_dev(DEVICE *dev, int num)
            dev->state &= ~(ST_EOF|ST_EOT);
         }
 
-        Dmsg0(100, "Doing MTFSF\n");
+         Dmsg0(100, "Doing MTFSF\n");
         stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
         if (stat < 0) {                 /* error => EOT */
            berrno be;
            dev->state |= ST_EOT;
-           Dmsg0(100, "Set ST_EOT\n");
+            Dmsg0(100, "Set ST_EOT\n");
            clrerror_dev(dev, MTFSF);
-           Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
+            Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
               dev->dev_name, be.strerror());
-           Dmsg0(100, "Got < 0 for MTFSF\n");
-           Dmsg1(100, "%s", dev->errmsg);
+            Dmsg0(100, "Got < 0 for MTFSF\n");
+            Dmsg1(100, "%s", dev->errmsg);
         } else {
            dev->state |= ST_EOF;     /* just read EOF */
            dev->file++;
@@ -942,7 +1623,7 @@ fsf_dev(DEVICE *dev, int num)
       }
       if (dev->state & ST_EOT) {
         dev->dev_errno = 0;
-        Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
+         Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
         stat = -1;
       } else {
         stat = 0;
@@ -1039,7 +1720,7 @@ fsr_dev(DEVICE *dev, int num)
       clrerror_dev(dev, MTFSR);
       Dmsg1(100, "FSF fail: ERR=%s\n", be.strerror());
       if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) {
-        Dmsg4(100, "Adjust from %d:%d to %d:%d\n", dev->file,
+         Dmsg4(100, "Adjust from %d:%d to %d:%d\n", dev->file,
            dev->block_num, mt_stat.mt_fileno, mt_stat.mt_blkno);
         dev->file = mt_stat.mt_fileno;
         dev->block_num = mt_stat.mt_blkno;
@@ -1121,11 +1802,11 @@ reposition_dev(DEVICE *dev, uint32_t file, uint32_t block)
 
    if (!(dev_state(dev, ST_TAPE))) {
       off_t pos = (((off_t)file)<<32) + block;
-      Dmsg1(100, "===== lseek to %d\n", (int)pos);
-      if (lseek(dev->fd, pos, SEEK_SET) == (off_t)-1) {
+      Dmsg1(100, "===== lseek_dev to %d\n", (int)pos);
+      if (lseek_dev(dev, pos, SEEK_SET) == (off_t)-1) {
         berrno be;
         dev->dev_errno = errno;
-        Mmsg2(dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
+         Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
         return false;
       }
@@ -1145,7 +1826,7 @@ reposition_dev(DEVICE *dev, uint32_t file, uint32_t block)
    if (file > dev->file) {
       Dmsg1(100, "fsf %d\n", file-dev->file);
       if (!fsf_dev(dev, file-dev->file)) {
-        Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev));
+         Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev));
         return false;
       }
       Dmsg2(100, "wanted_file=%d at_file=%d\n", file, dev->file);
@@ -1178,7 +1859,8 @@ weof_dev(DEVICE *dev, int num)
 {
    struct mtop mt_com;
    int stat;
-
+   Dmsg0(29, "weof_dev\n");
+   
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
       Mmsg0(dev->errmsg, _("Bad call to weof_dev. Archive drive not open\n"));
@@ -1191,7 +1873,6 @@ weof_dev(DEVICE *dev, int num)
       return 0;
    }
    dev->state &= ~(ST_EOT | ST_EOF);  /* remove EOF/EOT flags */
-   Dmsg0(29, "weof_dev\n");
    mt_com.mt_op = MTWEOF;
    mt_com.mt_count = num;
    stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
@@ -1203,7 +1884,7 @@ weof_dev(DEVICE *dev, int num)
       berrno be;
       clrerror_dev(dev, MTWEOF);
       if (stat == -1) {
-        Mmsg2(dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
+         Mmsg2(dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
            dev->dev_name, be.strerror());
        }
    }
@@ -1244,41 +1925,41 @@ clrerror_dev(DEVICE *dev, int func)
    if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
       switch (func) {
       case -1:
-        Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n");
+         Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n");
         break;
       case MTWEOF:
-        msg = "WTWEOF";
+         msg = "WTWEOF";
         dev->capabilities &= ~CAP_EOF; /* turn off feature */
         break;
 #ifdef MTEOM
       case MTEOM:
-        msg = "WTEOM";
+         msg = "WTEOM";
         dev->capabilities &= ~CAP_EOM; /* turn off feature */
         break;
 #endif
       case MTFSF:
-        msg = "MTFSF";
+         msg = "MTFSF";
         dev->capabilities &= ~CAP_FSF; /* turn off feature */
         break;
       case MTBSF:
-        msg = "MTBSF";
+         msg = "MTBSF";
         dev->capabilities &= ~CAP_BSF; /* turn off feature */
         break;
       case MTFSR:
-        msg = "MTFSR";
+         msg = "MTFSR";
         dev->capabilities &= ~CAP_FSR; /* turn off feature */
         break;
       case MTBSR:
-        msg = "MTBSR";
+         msg = "MTBSR";
         dev->capabilities &= ~CAP_BSR; /* turn off feature */
         break;
       default:
-        msg = "Unknown";
+         msg = "Unknown";
         break;
       }
       if (msg != NULL) {
         dev->dev_errno = ENOSYS;
-        Mmsg1(&dev->errmsg, _("This device does not support %s.\n"), msg);
+         Mmsg1(&dev->errmsg, _("This device does not support %s.\n"), msg);
         Emsg0(M_ERROR, 0, dev->errmsg);
       }
    }
@@ -1337,12 +2018,33 @@ static void do_close(DEVICE *dev)
    if (dev->fd >= 0) {
       close(dev->fd);
    }
+   if (dev_cap(dev, CAP_REQMOUNT)) {
+      if (unmount_dev(dev, 1) < 0) {
+         Dmsg1(0, "Cannot unmount device %s.\n", dev->dev_name);
+      }
+   }
+   
+   /* Remove the last part file if it is empty */
+   if ((dev->state & ST_APPEND) && (dev->num_parts > 0)) {
+      struct stat statp;
+      POOL_MEM archive_name(PM_FNAME);
+      dev->part = dev->num_parts;
+      get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+      /* Check that the part file is empty */
+      if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
+        unlink(archive_name.c_str());
+      }
+   }
+   
    /* Clean up device packet so it can be reused */
    dev->fd = -1;
    dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
    dev->file = dev->block_num = 0;
    dev->file_size = 0;
    dev->file_addr = 0;
+   dev->part = 0;
+   dev->part_size = 0;
+   dev->part_start = 0;
    dev->EndFile = dev->EndBlock = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
@@ -1364,7 +2066,11 @@ close_dev(DEVICE *dev)
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
-   if (dev->fd >= 0 && dev->use_count == 1) {
+   /*if (dev->fd >= 0 && dev->use_count == 1) {*/
+   /* No need to check if dev->fd >= 0: it is checked again
+    * in do_close, and do_close MUST be called for volumes
+    * splitted in parts, even if dev->fd == -1. */
+   if (dev->use_count == 1) {
       do_close(dev);
    } else if (dev->use_count > 0) {
       dev->use_count--;
@@ -1395,10 +2101,22 @@ void force_close_dev(DEVICE *dev)
 
 bool truncate_dev(DEVICE *dev)
 {
+   Dmsg1(100, "truncate_dev %s\n", dev->dev_name);
    if (dev->state & ST_TAPE) {
       return true;                    /* we don't really truncate tapes */
       /* maybe we should rewind and write and eof ???? */
    }
+   
+   /* If there is more than one part, open the first one, and then truncate it. */
+   if (dev->num_parts > 0) {
+      dev->num_parts = 0;
+      dev->VolCatInfo.VolCatParts = 0;
+      if (open_first_part(dev) < 0) {
+        berrno be;
+         Mmsg1(&dev->errmsg, "Unable to truncate device, because I'm unable to open the first part. ERR=%s\n", be.strerror());
+      }
+   }
+   
    if (ftruncate(dev->fd, 0) != 0) {
       berrno be;
       Mmsg1(&dev->errmsg, _("Unable to truncate device. ERR=%s\n"), be.strerror());
@@ -1596,3 +2314,63 @@ void set_os_device_parameters(DEVICE *dev)
    return;
 #endif
 }
+
+/*
+ * Edit codes into (Un)MountCommand, Write(First)PartCommand
+ *  %% = %
+ *  %a = archive device name
+ *  %m = mount point
+ *  %v = last part name
+ *
+ *  omsg = edited output message
+ *  imsg = input string containing edit codes (%x)
+ *
+ */
+char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg)
+{
+   const char *p;
+   const char *str;
+   char add[20];
+   
+   POOL_MEM archive_name(PM_FNAME);
+   get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+
+   *omsg = 0;
+   Dmsg1(800, "edit_device_codes: %s\n", imsg);
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+        switch (*++p) {
+            case '%':
+               str = "%";
+              break;
+            case 'n':
+               bsnprintf(add, sizeof(add), "%d", dev->part);
+              str = add;
+              break;
+            case 'a':
+              str = dev->dev_name;
+              break;
+            case 'm':
+              str = dev->device->mount_point;
+              break;
+            case 'v':
+              str = archive_name.c_str();
+              break;
+           default:
+               add[0] = '%';
+              add[1] = *p;
+              add[2] = 0;
+              str = add;
+              break;
+        }
+      } else {
+        add[0] = *p;
+        add[1] = 0;
+        str = add;
+      }
+      Dmsg1(900, "add_str %s\n", str);
+      pm_strcat(&omsg, (char *)str);
+      Dmsg1(800, "omsg=%s\n", omsg);
+   }
+   return omsg;
+}
index bca2c42694286937403fcd49642e67dd706f3a93..181398c6307d9dd48742ec6ccff16475ea4885f3 100644 (file)
@@ -8,7 +8,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
 #ifndef __DEV_H
 #define __DEV_H 1
 
-#undef DCR                            /* used by Bacula */
+#undef DCR                           /* used by Bacula */
 
 /* #define NEW_LOCK 1 */
 
-#define new_lock_device(dev)             _new_lock_device(__FILE__, __LINE__, (dev))
+#define new_lock_device(dev)            _new_lock_device(__FILE__, __LINE__, (dev))
 #define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state))
-#define new_unlock_device(dev)           _new_unlock_device(__FILE__, __LINE__, (dev))
+#define new_unlock_device(dev)          _new_unlock_device(__FILE__, __LINE__, (dev))
 
 #define lock_device(d) _lock_device(__FILE__, __LINE__, (d))
 #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d))
@@ -54,109 +54,112 @@ enum {
 };
 
 /* Generic status bits returned from status_dev() */
-#define BMT_TAPE           (1<<0)     /* is tape device */
-#define BMT_EOF            (1<<1)     /* just read EOF */
-#define BMT_BOT            (1<<2)     /* at beginning of tape */
-#define BMT_EOT            (1<<3)     /* end of tape reached */
-#define BMT_SM             (1<<4)     /* DDS setmark */
-#define BMT_EOD            (1<<5)     /* DDS at end of data */
-#define BMT_WR_PROT        (1<<6)     /* tape write protected */
-#define BMT_ONLINE         (1<<7)     /* tape online */
-#define BMT_DR_OPEN        (1<<8)     /* tape door open */
-#define BMT_IM_REP_EN      (1<<9)     /* immediate report enabled */
+#define BMT_TAPE          (1<<0)     /* is tape device */
+#define BMT_EOF           (1<<1)     /* just read EOF */
+#define BMT_BOT           (1<<2)     /* at beginning of tape */
+#define BMT_EOT           (1<<3)     /* end of tape reached */
+#define BMT_SM            (1<<4)     /* DDS setmark */
+#define BMT_EOD           (1<<5)     /* DDS at end of data */
+#define BMT_WR_PROT       (1<<6)     /* tape write protected */
+#define BMT_ONLINE        (1<<7)     /* tape online */
+#define BMT_DR_OPEN       (1<<8)     /* tape door open */
+#define BMT_IM_REP_EN     (1<<9)     /* immediate report enabled */
 
 
 /* Test capabilities */
 #define dev_cap(dev, cap) ((dev)->capabilities & (cap))
 
 /* Bits for device capabilities */
-#define CAP_EOF            (1<<0)     /* has MTWEOF */
-#define CAP_BSR            (1<<1)     /* has MTBSR */
-#define CAP_BSF            (1<<2)     /* has MTBSF */
-#define CAP_FSR            (1<<3)     /* has MTFSR */
-#define CAP_FSF            (1<<4)     /* has MTFSF */
-#define CAP_EOM            (1<<5)     /* has MTEOM */
-#define CAP_REM            (1<<6)     /* is removable media */
-#define CAP_RACCESS        (1<<7)     /* is random access device */
-#define CAP_AUTOMOUNT      (1<<8)     /* Read device at start to see what is there */
-#define CAP_LABEL          (1<<9)     /* Label blank tapes */
-#define CAP_ANONVOLS       (1<<10)    /* Mount without knowing volume name */
-#define CAP_ALWAYSOPEN     (1<<11)    /* always keep device open */
+#define CAP_EOF           (1<<0)     /* has MTWEOF */
+#define CAP_BSR           (1<<1)     /* has MTBSR */
+#define CAP_BSF           (1<<2)     /* has MTBSF */
+#define CAP_FSR           (1<<3)     /* has MTFSR */
+#define CAP_FSF           (1<<4)     /* has MTFSF */
+#define CAP_EOM           (1<<5)     /* has MTEOM */
+#define CAP_REM           (1<<6)     /* is removable media */
+#define CAP_RACCESS       (1<<7)     /* is random access device */
+#define CAP_AUTOMOUNT     (1<<8)     /* Read device at start to see what is there */
+#define CAP_LABEL         (1<<9)     /* Label blank tapes */
+#define CAP_ANONVOLS      (1<<10)    /* Mount without knowing volume name */
+#define CAP_ALWAYSOPEN    (1<<11)    /* always keep device open */
 #define CAP_AUTOCHANGER    (1<<12)    /* AutoChanger */
 #define CAP_OFFLINEUNMOUNT (1<<13)    /* Offline before unmount */
-#define CAP_STREAM         (1<<14)    /* Stream device */
-#define CAP_BSFATEOM       (1<<15)    /* Backspace file at EOM */
-#define CAP_FASTFSF        (1<<16)    /* Fast forward space file */
-#define CAP_TWOEOF         (1<<17)    /* Write two eofs for EOM */
+#define CAP_STREAM        (1<<14)    /* Stream device */
+#define CAP_BSFATEOM      (1<<15)    /* Backspace file at EOM */
+#define CAP_FASTFSF       (1<<16)    /* Fast forward space file */
+#define CAP_TWOEOF        (1<<17)    /* Write two eofs for EOM */
 #define CAP_CLOSEONPOLL    (1<<18)    /* Close device on polling */
 #define CAP_POSITIONBLOCKS (1<<19)    /* Use block positioning */
-#define CAP_MTIOCGET       (1<<20)    /* Basic support for fileno and blkno */
+#define CAP_MTIOCGET      (1<<20)    /* Basic support for fileno and blkno */
+#define CAP_REQMOUNT      (1<<21)    /* Require mount to read files back (typically: DVD) */
 
 /* Test state */
 #define dev_state(dev, st_state) ((dev)->state & (st_state))
 
 /* Device state bits */
-#define ST_OPENED          (1<<0)     /* set when device opened */
-#define ST_TAPE            (1<<1)     /* is a tape device */
-#define ST_FILE            (1<<2)     /* is a file device */
-#define ST_FIFO            (1<<3)     /* is a fifo device */
-#define ST_PROG            (1<<4)     /* is a program device */
-#define ST_LABEL           (1<<5)     /* label found */
+#define ST_OPENED         (1<<0)     /* set when device opened */
+#define ST_TAPE           (1<<1)     /* is a tape device */
+#define ST_FILE           (1<<2)     /* is a file device */
+#define ST_FIFO           (1<<3)     /* is a fifo device */
+#define ST_PROG           (1<<4)     /* is a program device */
+#define ST_LABEL          (1<<5)     /* label found */
 #define ST_MALLOC          (1<<6)     /* dev packet malloc'ed in init_dev() */
-#define ST_APPEND          (1<<7)     /* ready for Bacula append */
-#define ST_READ            (1<<8)     /* ready for Bacula read */
-#define ST_EOT             (1<<9)     /* at end of tape */
-#define ST_WEOT            (1<<10)    /* Got EOT on write */
-#define ST_EOF             (1<<11)    /* Read EOF i.e. zero bytes */
-#define ST_NEXTVOL         (1<<12)    /* Start writing on next volume */
-#define ST_SHORT           (1<<13)    /* Short block read */
+#define ST_APPEND         (1<<7)     /* ready for Bacula append */
+#define ST_READ           (1<<8)     /* ready for Bacula read */
+#define ST_EOT            (1<<9)     /* at end of tape */
+#define ST_WEOT           (1<<10)    /* Got EOT on write */
+#define ST_EOF            (1<<11)    /* Read EOF i.e. zero bytes */
+#define ST_NEXTVOL        (1<<12)    /* Start writing on next volume */
+#define ST_SHORT          (1<<13)    /* Short block read */
+#define ST_MOUNTED        (1<<14)    /* the device is mounted to the mount point */
 
 /* dev_blocked states (mutually exclusive) */
 enum {
-   BST_NOT_BLOCKED = 0,               /* not blocked */
-   BST_UNMOUNTED,                     /* User unmounted device */
-   BST_WAITING_FOR_SYSOP,             /* Waiting for operator to mount tape */
-   BST_DOING_ACQUIRE,                 /* Opening/validating/moving tape */
-   BST_WRITING_LABEL,                  /* Labeling a tape */
+   BST_NOT_BLOCKED = 0,              /* not blocked */
+   BST_UNMOUNTED,                    /* User unmounted device */
+   BST_WAITING_FOR_SYSOP,            /* Waiting for operator to mount tape */
+   BST_DOING_ACQUIRE,                /* Opening/validating/moving tape */
+   BST_WRITING_LABEL,                 /* Labeling a tape */
    BST_UNMOUNTED_WAITING_FOR_SYSOP,    /* Closed by user during mount request */
-   BST_MOUNT                           /* Mount request */
+   BST_MOUNT                          /* Mount request */
 };
 
 /* Volume Catalog Information structure definition */
 struct VOLUME_CAT_INFO {
    /* Media info for the current Volume */
-   uint32_t VolCatJobs;               /* number of jobs on this Volume */
-   uint32_t VolCatFiles;              /* Number of files */
-   uint32_t VolCatBlocks;             /* Number of blocks */
-   uint64_t VolCatBytes;              /* Number of bytes written */
-   uint32_t VolCatMounts;             /* Number of mounts this volume */
-   uint32_t VolCatErrors;             /* Number of errors this volume */
-   uint32_t VolCatWrites;             /* Number of writes this volume */
-   uint32_t VolCatReads;              /* Number of reads this volume */
-   uint64_t VolCatRBytes;             /* Number of bytes read */
-   uint32_t VolCatRecycles;           /* Number of recycles this volume */
-   uint32_t EndFile;                  /* Last file number */
-   uint32_t EndBlock;                 /* Last block number */
-   int32_t  Slot;                     /* Slot in changer */
-   bool     InChanger;                /* Set if vol in current magazine */
-   uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
-   uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
-   uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
+   uint32_t VolCatJobs;              /* number of jobs on this Volume */
+   uint32_t VolCatFiles;             /* Number of files */
+   uint32_t VolCatBlocks;            /* Number of blocks */
+   uint64_t VolCatBytes;             /* Number of bytes written */
+   uint32_t VolCatParts;             /* Number of parts written */
+   uint32_t VolCatMounts;            /* Number of mounts this volume */
+   uint32_t VolCatErrors;            /* Number of errors this volume */
+   uint32_t VolCatWrites;            /* Number of writes this volume */
+   uint32_t VolCatReads;             /* Number of reads this volume */
+   uint64_t VolCatRBytes;            /* Number of bytes read */
+   uint32_t VolCatRecycles;          /* Number of recycles this volume */
+   uint32_t EndFile;                 /* Last file number */
+   uint32_t EndBlock;                /* Last block number */
+   int32_t  Slot;                    /* Slot in changer */
+   bool     InChanger;               /* Set if vol in current magazine */
+   uint32_t VolCatMaxJobs;           /* Maximum Jobs to write to volume */
+   uint32_t VolCatMaxFiles;          /* Maximum files to write to volume */
+   uint64_t VolCatMaxBytes;          /* Max bytes to write to volume */
    uint64_t VolCatCapacityBytes;      /* capacity estimate */
-   uint64_t VolReadTime;              /* time spent reading */
-   uint64_t VolWriteTime;             /* time spent writing this Volume */
-   char VolCatStatus[20];             /* Volume status */
+   uint64_t VolReadTime;             /* time spent reading */
+   uint64_t VolWriteTime;            /* time spent writing this Volume */
+   char VolCatStatus[20];            /* Volume status */
    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
 };
 
 
 typedef struct s_steal_lock {
-   pthread_t  no_wait_id;             /* id of no wait thread */
-   int        dev_blocked;            /* state */
-   int        dev_prev_blocked;       /* previous blocked state */
+   pthread_t  no_wait_id;            /* id of no wait thread */
+   int       dev_blocked;            /* state */
+   int       dev_prev_blocked;       /* previous blocked state */
 } bsteal_lock_t;
 
-struct DEVRES;                        /* Device resource defined in stored_conf.h */
+struct DEVRES;                       /* Device resource defined in stored_conf.h */
 
 /*
  * Device structure definition. There is one of these for
@@ -165,58 +168,71 @@ struct DEVRES;                        /* Device resource defined in stored_conf.
  */
 struct DEVICE {
 public:
-   DEVICE *next;                      /* pointer to next open device */
-   DEVICE *prev;                      /* pointer to prev open device */
-   JCR *attached_jcrs;                /* attached JCR list */
-   dlist *attached_dcrs;              /* attached DCR list */
-   pthread_mutex_t mutex;             /* access control */
+   DEVICE *next;                     /* pointer to next open device */
+   DEVICE *prev;                     /* pointer to prev open device */
+   JCR *attached_jcrs;               /* attached JCR list */
+   dlist *attached_dcrs;             /* attached DCR list */
+   pthread_mutex_t mutex;            /* access control */
    pthread_mutex_t spool_mutex;       /* mutex for updating spool_size */
-   pthread_cond_t wait;               /* thread wait variable */
+   pthread_cond_t wait;              /* thread wait variable */
    pthread_cond_t wait_next_vol;      /* wait for tape to be mounted */
-   pthread_t no_wait_id;              /* this thread must not wait */
-   int dev_blocked;                   /* set if we must wait (i.e. change tape) */
-   int dev_prev_blocked;              /* previous blocked state */
-   int num_waiting;                   /* number of threads waiting */
-   int num_writers;                   /* number of writing threads */
+   pthread_t no_wait_id;             /* this thread must not wait */
+   int dev_blocked;                  /* set if we must wait (i.e. change tape) */
+   int dev_prev_blocked;             /* previous blocked state */
+   int num_waiting;                  /* number of threads waiting */
+   int num_writers;                  /* number of writing threads */
 
    /* New access control in process of being implemented */
-   brwlock_t lock;                    /* New mutual exclusion lock */
+   brwlock_t lock;                   /* New mutual exclusion lock */
 
-   int use_count;                     /* usage count on this device */
-   int fd;                            /* file descriptor */
-   int capabilities;                  /* capabilities mask */
-   int state;                         /* state mask */
-   int dev_errno;                     /* Our own errno */
-   int mode;                          /* read/write modes */
-   uint32_t drive_index;              /* Autochanger drive index */
-   POOLMEM *dev_name;                 /* device name */
-   char *errmsg;                      /* nicely edited error message */
-   uint32_t block_num;                /* current block number base 0 */
-   uint32_t file;                     /* current file number base 0 */
-   uint64_t file_addr;                /* Current file read/write address */
-   uint64_t file_size;                /* Current file size */
-   uint32_t EndBlock;                 /* last block written */
-   uint32_t EndFile;                  /* last file written */
-   uint32_t min_block_size;           /* min block size */
-   uint32_t max_block_size;           /* max block size */
-   uint64_t max_volume_size;          /* max bytes to put on one volume */
-   uint64_t max_file_size;            /* max file size to put in one file on volume */
-   uint64_t volume_capacity;          /* advisory capacity */
-   uint64_t max_spool_size;           /* maximum spool file size */
-   uint64_t spool_size;               /* curren spool size */
-   uint32_t max_rewind_wait;          /* max secs to allow for rewind */
-   uint32_t max_open_wait;            /* max secs to allow for open */
-   uint32_t max_open_vols;            /* max simultaneous open volumes */
-   utime_t  vol_poll_interval;        /* interval between polling Vol mount */
-   DEVRES *device;                    /* pointer to Device Resource */
-   btimer_t *tid;                     /* timer id */
+   int use_count;                    /* usage count on this device */
+   int fd;                           /* file descriptor */
+   int capabilities;                 /* capabilities mask */
+   int state;                        /* state mask */
+   int dev_errno;                    /* Our own errno */
+   int mode;                         /* read/write modes */
+   int openmode;                     /* parameter passed to open_dev (useful to reopen the device) */
+   uint32_t drive_index;             /* Autochanger drive index */
+   POOLMEM *dev_name;                /* device name */
+   char *errmsg;                     /* nicely edited error message */
+   uint32_t block_num;               /* current block number base 0 */
+   uint32_t file;                    /* current file number base 0 */
+   uint64_t file_addr;               /* Current file read/write address */
+   uint64_t file_size;               /* Current file size */
+   uint32_t EndBlock;                /* last block written */
+   uint32_t EndFile;                 /* last file written */
+   uint32_t min_block_size;          /* min block size */
+   uint32_t max_block_size;          /* max block size */
+   uint64_t max_volume_size;         /* max bytes to put on one volume */
+   uint64_t max_file_size;           /* max file size to put in one file on volume */
+   uint64_t volume_capacity;         /* advisory capacity */
+   uint64_t max_spool_size;          /* maximum spool file size */
+   uint64_t spool_size;              /* current spool size */
+   uint32_t max_rewind_wait;         /* max secs to allow for rewind */
+   uint32_t max_open_wait;           /* max secs to allow for open */
+   uint32_t max_open_vols;           /* max simultaneous open volumes */
+   
+   uint64_t max_part_size;           /* max part size */
+   uint64_t part_size;               /* current part size */
+   uint32_t part;                    /* current part number */
+   uint64_t part_start;              /* current part start address (relative to the whole volume) */
+   uint32_t num_parts;               /* number of parts (total) */
+   uint64_t free_space;              /* current free space on medium (without the current part) */
+   int free_space_errno;             /* indicates:
+                                      * - free_space_errno == 0: ignore free_space.
+                                      * - free_space_errno < 0: an error occured. 
+                                      * - free_space_errno > 0: free_space is valid. */
+   
+   utime_t  vol_poll_interval;       /* interval between polling Vol mount */
+   DEVRES *device;                   /* pointer to Device Resource */
+   btimer_t *tid;                    /* timer id */
 
-   VOLUME_CAT_INFO VolCatInfo;        /* Volume Catalog Information */
-   VOLUME_LABEL VolHdr;               /* Actual volume label */
+   VOLUME_CAT_INFO VolCatInfo;       /* Volume Catalog Information */
+   VOLUME_LABEL VolHdr;              /* Actual volume label */
 
    /* Device wait times ***FIXME*** look at durations */
    char BadVolName[MAX_NAME_LENGTH];  /* Last wrong Volume mounted */
-   bool poll;                         /* set to poll Volume */
+   bool poll;                        /* set to poll Volume */
    int min_wait;
    int max_wait;
    int max_num_wait;
@@ -233,33 +249,33 @@ public:
  */
 class DCR {
 public:
-   dlink dev_link;                    /* link to attach to dev */
-   JCR *jcr;                          /* pointer to JCR */
-   DEVICE *dev;                       /* pointer to device */
-   DEV_BLOCK *block;                  /* pointer to block */
-   DEV_RECORD *rec;                   /* pointer to record */
-   int spool_fd;                      /* fd if spooling */
-   bool spool_data;                   /* set to spool data */
-   bool spooling;                     /* set when actually spooling */
-   bool dev_locked;                   /* set if dev already locked */
-   bool NewVol;                       /* set if new Volume mounted */
-   bool WroteVol;                     /* set if Volume written */
-   bool NewFile;                      /* set when EOF written */
-   uint32_t VolFirstIndex;            /* First file index this Volume */
-   uint32_t VolLastIndex;             /* Last file index this Volume */
-   uint32_t FileIndex;                /* Current File Index */
-   uint32_t EndFile;                  /* End file written */
-   uint32_t StartFile;                /* Start write file */
-   uint32_t StartBlock;               /* Start write block */
-   uint32_t EndBlock;                 /* Ending block written */
-   int64_t spool_size;                /* Current spool size */
-   int64_t max_spool_size;            /* Max job spool size */
+   dlink dev_link;                   /* link to attach to dev */
+   JCR *jcr;                         /* pointer to JCR */
+   DEVICE *dev;                      /* pointer to device */
+   DEV_BLOCK *block;                 /* pointer to block */
+   DEV_RECORD *rec;                  /* pointer to record */
+   int spool_fd;                     /* fd if spooling */
+   bool spool_data;                  /* set to spool data */
+   bool spooling;                    /* set when actually spooling */
+   bool dev_locked;                  /* set if dev already locked */
+   bool NewVol;                      /* set if new Volume mounted */
+   bool WroteVol;                    /* set if Volume written */
+   bool NewFile;                     /* set when EOF written */
+   uint32_t VolFirstIndex;           /* First file index this Volume */
+   uint32_t VolLastIndex;            /* Last file index this Volume */
+   uint32_t FileIndex;               /* Current File Index */
+   uint32_t EndFile;                 /* End file written */
+   uint32_t StartFile;               /* Start write file */
+   uint32_t StartBlock;              /* Start write block */
+   uint32_t EndBlock;                /* Ending block written */
+   int64_t spool_size;               /* Current spool size */
+   int64_t max_spool_size;           /* Max job spool size */
    char VolumeName[MAX_NAME_LENGTH];  /* Volume name */
    char pool_name[MAX_NAME_LENGTH];   /* pool name */
    char pool_type[MAX_NAME_LENGTH];   /* pool type */
    char media_type[MAX_NAME_LENGTH];  /* media type */
    char dev_name[MAX_NAME_LENGTH];    /* dev name */
-   VOLUME_CAT_INFO VolCatInfo;        /* Catalog info for desired volume */
+   VOLUME_CAT_INFO VolCatInfo;       /* Catalog info for desired volume */
 };
 
 
@@ -268,7 +284,7 @@ public:
  *  dependent. Arrgggg!
  */
 #ifndef MTEOM
-#ifdef  MTSEOD
+#ifdef MTSEOD
 #define MTEOM MTSEOD
 #endif
 #ifdef MTEOD
index de9904b31a5acde469c93fb319171cd696839c09..12c67cb156946e1ee5b9fb17e93454a9e0df7dfa 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 /*
-   Copyright (C) 2001-2004 Kern Sibbald and John Walker
+   Copyright (C) 2001-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -188,14 +188,14 @@ void *handle_connection_request(void *arg)
       for (i=0; cmds[i].cmd; i++) {
        if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
           if ((!cmds[i].monitoraccess) && (jcr->director->monitor)) {
-             Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
+              Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
              bnet_fsend(bs, illegal_cmd);
              bnet_sig(bs, BNET_EOD);
              break;
           }
           if (!cmds[i].func(jcr)) { /* do command */
              quit = true; /* error, get out */
-             Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd);
+              Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd);
           }
           found = true;             /* indicate command found */
           break;
@@ -245,7 +245,7 @@ static bool cancel_cmd(JCR *cjcr)
 
    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
       if (!(jcr=get_jcr_by_full_name(Job))) {
-        bnet_fsend(dir, _("3992 Job %s not found.\n"), Job);
+         bnet_fsend(dir, _("3992 Job %s not found.\n"), Job);
       } else {
         P(jcr->mutex);
         oldStatus = jcr->JobStatus;
@@ -264,7 +264,7 @@ static bool cancel_cmd(JCR *cjcr)
               jcr->dcr->dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
             pthread_cond_signal(&jcr->dcr->dev->wait_next_vol);
         }
-        bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job);
+         bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job);
         free_jcr(jcr);
       }
    } else {
@@ -325,7 +325,7 @@ static bool do_label(JCR *jcr, int relabel)
         if (!(dev->state & ST_OPENED)) {
            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
            force_close_dev(dev);
-        /* Under certain "safe" conditions, we can steal the lock */
+         /* 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 ||
@@ -333,10 +333,10 @@ static bool do_label(JCR *jcr, int relabel)
            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
         } 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"),
+                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"),
+                bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
         } else {                     /* device not being used */
@@ -344,7 +344,7 @@ static bool do_label(JCR *jcr, int relabel)
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
@@ -383,6 +383,14 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
 
    /* See what we have for a Volume */
    label_status = read_dev_volume_label(dcr);
+   
+   if (dev_cap(dev, CAP_REQMOUNT)) {
+      label_status = read_dev_volume_label_guess(dcr, 1);
+   }
+   else {
+      label_status = read_dev_volume_label(dcr);
+   }
+   
    switch(label_status) {
    case VOL_NAME_ERROR:
    case VOL_VERSION_ERROR:
@@ -390,20 +398,20 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
    case VOL_OK:
       if (!relabel) {
         bnet_fsend(dir, _(
-           "3911 Cannot label Volume because it is already labeled: \"%s\"\n"),
+            "3911 Cannot label Volume because it is already labeled: \"%s\"\n"),
             dev->VolHdr.VolName);
         break;
       }
       /* Relabel request. If oldname matches, continue */
       if (strcmp(oldname, dev->VolHdr.VolName) != 0) {
-        bnet_fsend(dir, _("Wrong volume mounted.\n"));
+         bnet_fsend(dir, _("Wrong volume mounted.\n"));
         break;
       }
       /* Fall through wanted! */
    case VOL_IO_ERROR:
    case VOL_NO_LABEL:
       if (!write_new_volume_label_to_dev(dcr, newname, poolname)) {
-        bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev));
+         bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev));
         break;
       }
       bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
@@ -468,7 +476,7 @@ static DEVICE *find_device(JCR *jcr, POOL_MEM &dname)
    foreach_res(device, R_DEVICE) {
       /* Find resource, and make sure we were able to open it */
       if (strcmp(device->hdr.name, dname.c_str()) == 0 && device->dev) {
-        Dmsg1(20, "Found device %s\n", device->hdr.name);
+         Dmsg1(20, "Found device %s\n", device->hdr.name);
         jcr->device = device;
         found = true;
         break;
@@ -506,9 +514,9 @@ static bool mount_cmd(JCR *jcr)
         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");
+            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_name(dev));
+            bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev_name(dev));
            pthread_cond_signal(&dev->wait_next_vol);
            break;
 
@@ -517,79 +525,79 @@ static bool mount_cmd(JCR *jcr)
         case BST_UNMOUNTED:
            /* We freed the device, so reopen it and wake any waiting threads */
            if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) {
-              bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
+               bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
                  strerror_dev(dev));
               break;
            }
            read_dev_volume_label(dcr);
            if (dev->dev_blocked == BST_UNMOUNTED) {
               /* We blocked the device, so unblock it */
-              Dmsg0(100, "Unmounted. Unblocking device\n");
+               Dmsg0(100, "Unmounted. Unblocking device\n");
               read_label(dcr);       /* this should not be necessary */
               unblock_device(dev);
            } else {
-              Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n");
+               Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n");
               dev->dev_blocked = BST_MOUNT;
            }
            if (dev_state(dev, ST_LABEL)) {
-              bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
+               bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
                  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"),
+               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_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"),
+            bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"),
                       dev_name(dev));
            break;
 
         case 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));
            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"),
+                  bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
                     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"),
+                  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_name(dev));
               }
            } else {
               if (!dev_is_tape(dev)) {
-                 bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
+                  bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
                  break;
               }
               if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) {
-                 bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
+                  bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
                     strerror_dev(dev));
                  break;
               }
               read_label(dcr);
               if (dev_state(dev, ST_LABEL)) {
-                 bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"),
+                  bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"),
                     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"),
+                  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_name(dev));
               }
            }
            break;
 
         default:
-           bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
+            bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
            break;
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
@@ -613,36 +621,36 @@ static bool unmount_cmd(JCR *jcr)
       if (dev) {
         P(dev->mutex);               /* Use P to avoid indefinite block */
         if (!(dev->state & ST_OPENED)) {
-           Dmsg0(90, "Device already unmounted\n");
-           bnet_fsend(dir, _("3901 Device \"%s\" is already unmounted.\n"), dev_name(dev));
+            Dmsg0(90, "Device already unmounted\n");
+            bnet_fsend(dir, _("3901 Device \"%s\" is already unmounted.\n"), dev_name(dev));
 
         } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
-           Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
+            Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
               dev->dev_blocked);
            open_dev(dev, NULL, 0);     /* fake open for close */
            offline_or_rewind_dev(dev);
            force_close_dev(dev);
            dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
-           bnet_fsend(dir, _("3001 Device \"%s\" unmounted.\n"), dev_name(dev));
+            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 reading.\n"), dev_name(dev));
+                Dmsg0(90, "Device in read mode\n");
+                bnet_fsend(dir, _("3904 Device \"%s\" is busy reading.\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"),
+                Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
+                bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
 
         } else {                     /* device not being used */
-           Dmsg0(90, "Device not in use, unmounting\n");
+            Dmsg0(90, "Device not in use, unmounting\n");
            /* On FreeBSD, I am having ASSERT() failures in block_device()
             * and I can only imagine that the thread id that we are
             * leaving in no_wait_id is being re-used. So here,
@@ -654,11 +662,11 @@ static bool unmount_cmd(JCR *jcr)
            open_dev(dev, NULL, 0);     /* fake open for close */
            offline_or_rewind_dev(dev);
            force_close_dev(dev);
-           bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
+            bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
@@ -687,39 +695,39 @@ static bool release_cmd(JCR *jcr)
       if (dev) {
         P(dev->mutex);               /* Use P to avoid indefinite block */
         if (!(dev->state & ST_OPENED)) {
-           Dmsg0(90, "Device already released\n");
-           bnet_fsend(dir, _("3911 Device %s already released.\n"), dev_name(dev));
+            Dmsg0(90, "Device already released\n");
+            bnet_fsend(dir, _("3911 Device %s already released.\n"), dev_name(dev));
 
         } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                    dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) {
-           Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
+            Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
               dev->dev_blocked);
-           bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), dev_name(dev));
+            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));
+                Dmsg0(90, "Device in read mode\n");
+                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"),
+                Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
+                bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
 
         } else {                     /* device not being used */
-           Dmsg0(90, "Device not in use, unmounting\n");
+            Dmsg0(90, "Device not in use, unmounting\n");
            release_volume(jcr->dcr);
-           bnet_fsend(dir, _("3012 Device %s released.\n"), dev_name(dev));
+            bnet_fsend(dir, _("3012 Device %s released.\n"), dev_name(dev));
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
@@ -748,10 +756,10 @@ static bool autochanger_cmd(JCR *jcr)
       if (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)) {
            autochanger_list(dcr, dir);
-        /* Under certain "safe" conditions, we can steal the lock */
+         /* 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 ||
@@ -759,9 +767,9 @@ static bool autochanger_cmd(JCR *jcr)
            autochanger_list(dcr, 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"),
+                bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
         } else {                     /* device not being used */
@@ -769,7 +777,7 @@ static bool autochanger_cmd(JCR *jcr)
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {  /* error on scanf */
       pm_strcpy(jcr->errmsg, dir->msg);
@@ -797,7 +805,7 @@ static bool readlabel_cmd(JCR *jcr)
         if (!dev_state(dev, ST_OPENED)) {
            read_volume_label(jcr, dev, Slot);
            force_close_dev(dev);
-        /* Under certain "safe" conditions, we can steal the lock */
+         /* 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 ||
@@ -805,10 +813,10 @@ static bool readlabel_cmd(JCR *jcr)
            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"),
+                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"),
+                bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
                   dev_name(dev), dev->num_writers);
            }
         } else {                     /* device not being used */
@@ -816,7 +824,7 @@ static bool readlabel_cmd(JCR *jcr)
         }
         V(dev->mutex);
       } else {
-        bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str());
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
@@ -878,7 +886,7 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName)
    /* Ensure that the device is open -- autoload_device() closes it */
    for ( ; !(dev->state & ST_OPENED); ) {
       if (open_dev(dev, dcr->VolumeName, OPEN_READ_WRITE) < 0) {
-        bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"),
+         bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"),
            dev_name(dev), strerror_dev(dev));
         return false;
       }
index 4381db297d69e6105fba7738ad59c2fa439b0d6b..1be408cfeb4e44df096496f779c3c9d1bbc84ff4 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -40,8 +40,8 @@ static bool use_device_cmd(JCR *jcr);
 
 /* Requests from the Director daemon */
 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-        "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
-        "SpoolData=%d";
+      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
+      "SpoolData=%d  WritePartAfterJob=%d";
 static char use_device[]  = "use device=%127s media_type=%127s pool_name=%127s pool_type=%127s\n";
 static char use_devices[] = "use devices=%127s media_type=%127s pool_name=%127s pool_type=%127s\n";
 
@@ -68,7 +68,7 @@ bool job_cmd(JCR *jcr)
    char auth_key[100];
    BSOCK *dir = jcr->dir_bsock;
    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
-   int JobType, level, spool_attributes, no_attributes, spool_data;
+   int JobType, level, spool_attributes, no_attributes, spool_data, write_part_after_job;
    struct timeval tv;
    struct timezone tz;
    struct timespec timeout;
@@ -81,7 +81,7 @@ bool job_cmd(JCR *jcr)
    if (sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
              client_name.c_str(),
              &JobType, &level, fileset_name.c_str(), &no_attributes,
-             &spool_attributes, fileset_md5.c_str(), &spool_data) != 11) {
+             &spool_attributes, fileset_md5.c_str(), &spool_data, &write_part_after_job) != 12) {
       pm_strcpy(jcr->errmsg, dir->msg);
       bnet_fsend(dir, BAD_job, jcr->errmsg);
       Emsg1(M_FATAL, 0, _("Bad Job Command from Director: %s\n"), jcr->errmsg);
@@ -116,6 +116,7 @@ bool job_cmd(JCR *jcr)
    jcr->no_attributes = no_attributes;
    jcr->spool_attributes = spool_attributes;
    jcr->spool_data = spool_data;
+   jcr->write_part_after_job = write_part_after_job;
    jcr->fileset_md5 = get_pool_memory(PM_NAME);
    pm_strcpy(jcr->fileset_md5, fileset_md5);
 
@@ -247,7 +248,7 @@ static bool use_device_cmd(JCR *jcr)
    while (!quit) {
       bool ok;
       if (bnet_recv(dir) <= 0) {
-        Jmsg0(jcr, M_FATAL, 0, _("No Device from Director\n"));
+         Jmsg0(jcr, M_FATAL, 0, _("No Device from Director\n"));
         return false;
       }
 
@@ -283,13 +284,13 @@ static bool use_device_cmd(JCR *jcr)
               if (!dcr) {
                  return false;
               }
-              Dmsg1(120, "Found device %s\n", device->hdr.name);
+               Dmsg1(120, "Found device %s\n", device->hdr.name);
               bstrncpy(dcr->pool_name, pool_name, name_len);
               bstrncpy(dcr->pool_type, pool_type, name_len);
               bstrncpy(dcr->media_type, media_type, name_len);
               bstrncpy(dcr->dev_name, dev_name, name_len);
               jcr->device = device;
-              Dmsg1(220, "Got: %s", dir->msg);
+               Dmsg1(220, "Got: %s", dir->msg);
               return bnet_fsend(dir, OK_device);
            }
         }
@@ -297,19 +298,19 @@ static bool use_device_cmd(JCR *jcr)
         if (verbose) {
            unbash_spaces(dir->msg);
            pm_strcpy(jcr->errmsg, dir->msg);
-           Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
+            Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
         }
-        Jmsg(jcr, M_FATAL, 0, _("\n"
-           "     Device \"%s\" with MediaType \"%s\" requested by Dir not found in SD Device resources.\n"),
+         Jmsg(jcr, M_FATAL, 0, _("\n"
+            "     Device \"%s\" with MediaType \"%s\" requested by Dir not found in SD Device resources.\n"),
              dev_name.c_str(), media_type.c_str());
         bnet_fsend(dir, NO_device, dev_name.c_str());
       } else {
         unbash_spaces(dir->msg);
         pm_strcpy(jcr->errmsg, dir->msg);
         if (verbose) {
-           Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
+            Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
         }
-        Jmsg(jcr, M_FATAL, 0, _("Bad Use Device command: %s\n"), jcr->errmsg);
+         Jmsg(jcr, M_FATAL, 0, _("Bad Use Device command: %s\n"), jcr->errmsg);
         bnet_fsend(dir, BAD_use, jcr->errmsg);
       }
    }
index d822b6b4fd96f4ca9340914487f4523ddedc689f..9b5e03aba2265b660722cb6c488fcc997d0d51ab 100644 (file)
@@ -8,7 +8,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -71,14 +71,14 @@ int read_dev_volume_label(DCR *dcr)
    if (dev_state(dev, ST_LABEL)) {      /* did we already read label? */
       /* Compare Volume Names allow special wild card */
       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) {
-        Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
+         Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
            dev_name(dev), VolName, dev->VolHdr.VolName);
         /*
          * Cancel Job if too many label errors
          *  => we are in a loop
          */
         if (!dev->poll && jcr->label_errors++ > 100) {
-           Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
+            Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
         }
         return VOL_NAME_ERROR;
       }
@@ -95,14 +95,14 @@ int read_dev_volume_label(DCR *dcr)
       return VOL_NO_MEDIA;
    }
    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
-
+  
    /* Read the Volume label block */
    record = new_record();
    empty_block(block);
    Dmsg0(90, "Big if statement in read_volume_label\n");
    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
-          "labeled Volume, because: ERR=%s"), NPRT(VolName), dev_name(dev),
+           "labeled Volume, because: ERR=%s"), NPRT(VolName), dev_name(dev),
           strerror_dev(dev));
       Dmsg1(30, "%s", jcr->errmsg);
    } else if (!read_record_from_block(block, record)) {
@@ -123,7 +123,7 @@ int read_dev_volume_label(DCR *dcr)
       free_record(record);
       if (forge_on || jcr->ignore_label_errors) {
         dev->state |= ST_LABEL;      /* set has Bacula label */
-        Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
+         Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
         return VOL_OK;
       }
       empty_block(block);
@@ -170,7 +170,7 @@ int read_dev_volume_label(DCR *dcr)
        *  => we are in a loop
        */
       if (!dev->poll && jcr->label_errors++ > 100) {
-        Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
+         Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
       }
       return VOL_NAME_ERROR;
    }
@@ -183,6 +183,95 @@ int read_dev_volume_label(DCR *dcr)
    return VOL_OK;
 }
 
+/* Read the volume label by guessing the volume name. (only for mounted devices)
+ * write is true if we are reading the label before writing to the device.
+ *
+ * If the volume name cannot be guessed :
+ *  Writing : returns the label of the current file (on the harddisk).
+ *  Reading : returns an error
+ */
+int read_dev_volume_label_guess(DCR *dcr, bool write) {
+   int vol_label_status;
+   Dmsg3(100, "Enter read_dev_volume_label_guess device=%s vol=%s dev_Vol=%s\n",
+        dev_name(dcr->dev), dcr->VolumeName, dcr->dev->VolHdr.VolName);
+   
+   if (!dev_cap(dcr->dev, CAP_REQMOUNT)) {
+      Dmsg0(100, "Leave read_dev_volume_label_guess !CAP_REQMOUNT\n");
+      return read_dev_volume_label(dcr);
+   }
+   
+   if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
+      Dmsg0(100, "Leave read_dev_volume_label_guess !writing, and VolCatParts == 0\n");
+      return read_dev_volume_label(dcr);
+   }
+   
+   /* For mounted devices, tries to guess the volume name, and read the label if possible.
+   */
+   if (open_guess_name_dev(dcr->dev) < 0) {    
+      if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) {
+         Mmsg2(dcr->jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
+              dev_name(dcr->dev), dcr->VolumeName);
+         Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev)\n");
+        return VOL_NO_LABEL;
+      }
+      
+      if (write && (dcr->dev->free_space_errno < 0)) {
+         Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
+         Mmsg2(dcr->jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"),
+              dcr->dev->dev_name, dcr->dev->errmsg);
+        return VOL_NO_MEDIA;
+      }
+      
+      /* If we can't guess the name, and we are writing, just reopen the right file with open_first_part. */
+      if (open_first_part(dcr->dev) < 0) {
+        berrno be;
+         Mmsg2(dcr->jcr->errmsg, _("open_first_part error on %s. ERR=%s.\n"),
+              dcr->dev->dev_name, be.strerror());
+         Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev && !open_first_part)\n");
+        return VOL_IO_ERROR;
+      }
+      
+      Dmsg0(100, "Leave read_dev_volume_label_guess !open_guess_name_dev\n");
+      return read_dev_volume_label(dcr);
+   }
+   else {
+      if (write && (dcr->dev->free_space_errno < 0)) {
+         Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
+         Mmsg2(dcr->jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"),
+              dcr->dev->dev_name, dcr->dev->errmsg);
+        return VOL_NO_MEDIA;
+      }
+      
+      vol_label_status = read_dev_volume_label(dcr);
+
+      if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) {
+         Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
+        return vol_label_status;
+      }
+      
+      if (open_first_part(dcr->dev) < 0) {
+        berrno be;
+         Mmsg2(dcr->jcr->errmsg, _("open_first_part error on %s. ERR=%s.\n"),
+              dcr->dev->dev_name, be.strerror());
+         Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (open_guess_name_dev && !open_first_part)\n");
+        return VOL_IO_ERROR;
+      }
+      
+      /* When writing, if the guessed volume name is no the right volume name, 
+       * report the error, otherwise, just continue with the right file.
+       */
+      if (vol_label_status != VOL_NAME_ERROR) {
+         Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && !VOL_NAME_ERROR)\n");
+        dcr->dev->state &= ~ST_LABEL;
+        return read_dev_volume_label(dcr);
+      }
+      else {
+         Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && VOL_NAME_ERROR)\n");
+        return vol_label_status;
+      }
+   }
+}
+
 /*  unser_volume_label
  *
  * Unserialize the Volume label into the device Volume_Label
@@ -546,9 +635,9 @@ bool write_session_label(DCR *dcr, int label)
    if (!can_write_record_to_block(block, rec)) {
       Dmsg0(100, "Cannot write session label to block.\n");
       if (!write_block_to_device(dcr)) {
-        Dmsg0(90, "Got session label write_block_to_dev error.\n");
+         Dmsg0(90, "Got session label write_block_to_dev error.\n");
         /* ****FIXME***** errno is not set here */
-        Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
+         Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
                           dev_vol_name(dev), strerror(errno));
         free_record(rec);
         return false;
@@ -562,7 +651,7 @@ bool write_session_label(DCR *dcr, int label)
    }
 
    Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
-            "remainder=%d\n", jcr->JobId,
+             "remainder=%d\n", jcr->JobId,
       FI_to_ascii(rec->FileIndex), rec->VolSessionId,
       stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
       rec->remainder);
@@ -586,25 +675,25 @@ void dump_volume_label(DEVICE *dev)
    File = dev->file;
    switch (dev->VolHdr.LabelType) {
       case PRE_LABEL:
-        LabelType = "PRE_LABEL";
+         LabelType = "PRE_LABEL";
         break;
       case VOL_LABEL:
-        LabelType = "VOL_LABEL";
+         LabelType = "VOL_LABEL";
         break;
       case EOM_LABEL:
-        LabelType = "EOM_LABEL";
+         LabelType = "EOM_LABEL";
         break;
       case SOS_LABEL:
-        LabelType = "SOS_LABEL";
+         LabelType = "SOS_LABEL";
         break;
       case EOS_LABEL:
-        LabelType = "EOS_LABEL";
+         LabelType = "EOS_LABEL";
         break;
       case EOT_LABEL:
         goto bail_out;
       default:
         LabelType = buf;
-        sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
+         sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
         break;
    }
 
@@ -804,14 +893,14 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
         dump_session_label(rec, type);
         break;
       case EOM_LABEL:
-        Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
+         Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
            type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
         break;
       case EOT_LABEL:
-        Pmsg0(-1, _("End of physical tape.\n"));
+         Pmsg0(-1, _("End of physical tape.\n"));
         break;
       default:
-        Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
+         Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
            type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
         break;
       }
@@ -820,17 +909,17 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
       switch (rec->FileIndex) {
       case SOS_LABEL:
         unser_session_label(&label, rec);
-        Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
+         Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
            type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
            label.JobLevel, label.JobType);
         break;
       case EOS_LABEL:
         char ed1[30], ed2[30];
         unser_session_label(&label, rec);
-        Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
+         Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
            type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
            label.JobLevel, label.JobType);
-        Pmsg4(-1, "   Files=%s Bytes=%s Errors=%d Status=%c\n",
+         Pmsg4(-1, "   Files=%s Bytes=%s Errors=%d Status=%c\n",
            edit_uint64_with_commas(label.JobFiles, ed1),
            edit_uint64_with_commas(label.JobBytes, ed2),
            label.JobErrors, (char)label.JobStatus);
@@ -839,7 +928,7 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
       case PRE_LABEL:
       case VOL_LABEL:
       default:
-        Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
+         Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
       type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
         break;
       case EOT_LABEL:
index 1b0cd6b52dc27cdcf8261c6ad3a128adacf7a28f..4b58a57aab6cd6effd64958d4a689a72ae8ed60a 100644 (file)
@@ -8,7 +8,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -69,7 +69,7 @@ mount_next_vol:
       /* Last ditch effort before giving up, force operator to respond */
       dcr->VolCatInfo.Slot = 0;
       if (!dir_ask_sysop_to_mount_volume(dcr)) {
-        Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
+         Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
              dev_name(dev));
         return false;
       }
@@ -100,8 +100,10 @@ mount_next_vol:
    if (job_canceled(jcr)) {
       return false;
    }
-   Dmsg2(100, "After find_next_append. Vol=%s Slot=%d\n",
-        dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot);
+   Dmsg3(100, "After find_next_append. Vol=%s Slot=%d Parts=%d\n",
+        dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatParts);
+   
+   dev->num_parts = dcr->VolCatInfo.VolCatParts;
 
    /*
     * Get next volume and ready it for append
@@ -154,13 +156,24 @@ mount_next_vol:
    }
 
    /* Ensure the device is open */
-   if (!open_device(dcr)) {
-      if (dev->poll) {
-        goto mount_next_vol;
-      } else {
-        return false;
+   /* If we have a device that requires mount, we first want to guess
+    * which device is loaded, so we continue (if the wrong device is
+    * loaded, open_device would fail). */
+   if (!dev_cap(dev, CAP_REQMOUNT)) {
+      if (!open_device(dcr)) {
+        if (dev->poll) {
+           goto mount_next_vol;
+        } 
+        else {
+           return false;
+        }
       }
    }
+   else {
+      /* Just copy the VolCatName in the device resource (usually done by open_dev).
+       * It is necessary so we can open the real files later. */
+      bstrncpy(dcr->dev->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatName, sizeof(dcr->dev->VolCatInfo.VolCatName));
+   }
 
    /*
     * Now make sure we have the right tape mounted
@@ -174,7 +187,10 @@ read_volume:
       vol_label_status = VOL_OK;
       create_volume_label(dev, dcr->VolumeName, "Default");
       dev->VolHdr.LabelType = PRE_LABEL;
-   } else {
+   } else if (dev_cap(dev, CAP_REQMOUNT)) {
+      vol_label_status = read_dev_volume_label_guess(dcr, 1);
+   }
+   else {
       vol_label_status = read_dev_volume_label(dcr);
    }
    if (job_canceled(jcr)) {
@@ -198,7 +214,7 @@ read_volume:
 
       /* If not removable, Volume is broken */
       if (!dev_cap(dev, CAP_REM)) {
-        Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
+         Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
            dcr->VolumeName, dev_name(dev));
         mark_volume_in_error(dcr);
         goto mount_next_vol;
@@ -208,7 +224,7 @@ read_volume:
       /* If polling and got a previous bad name, ignore it */
       if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolName) == 0) {
         ask = true;
-        Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n",
+         Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n",
            dcr->VolumeName);
         goto mount_next_vol;
       }
@@ -223,9 +239,9 @@ read_volume:
       bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
         bstrncpy(dev->BadVolName, dev->VolHdr.VolName, sizeof(dev->BadVolName));
-        Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n"
-             "    Current Volume \"%s\" not acceptable because:\n"
-             "    %s"),
+         Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n"
+              "    Current Volume \"%s\" not acceptable because:\n"
+              "    %s"),
             VolCatInfo.VolCatName, dev->VolHdr.VolName,
             jcr->dir_bsock->msg);
         /* Restore desired volume name, note device info out of sync */
@@ -255,27 +271,27 @@ read_volume:
        */
       if (dev_cap(dev, CAP_LABEL) && (dcr->VolCatInfo.VolCatBytes == 0 ||
            (!dev_is_tape(dev) && strcmp(dcr->VolCatInfo.VolCatStatus,
-                                  "Recycle") == 0))) {
-        Dmsg0(100, "Create volume label\n");
+                                   "Recycle") == 0))) {
+         Dmsg0(100, "Create volume label\n");
         /* Create a new Volume label and write it to the device */
         if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
                dcr->pool_name)) {
-           Dmsg0(100, "!write_vol_label\n");
+            Dmsg0(100, "!write_vol_label\n");
            goto mount_next_vol;
         }
-        Dmsg0(100, "dir_update_vol_info. Set Append\n");
-        /* Copy Director's info into the device info */
+         Dmsg0(100, "dir_update_vol_info. Set Append\n");
+         /* Copy Director's info into the device info */
         memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
         if (!dir_update_volume_info(dcr, true)) {  /* indicate tape labeled */
            return false;
         }
-        Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
+         Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
            dcr->VolumeName, dev_name(dev));
         goto read_volume;      /* read label we just wrote */
       }
       /* If not removable, Volume is broken */
       if (!dev_cap(dev, CAP_REM)) {
-        Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
+         Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
            dcr->VolumeName, dev_name(dev));
         mark_volume_in_error(dcr);
         goto mount_next_vol;
@@ -285,11 +301,15 @@ read_volume:
    default:
       /* Send error message */
       if (!dev->poll) {
-        Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+         Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
       } else {
-        Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg);
+         Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg);
       }
       ask = true;
+      /* Needed, so the medium can be changed */
+      if (dev_cap(dev, CAP_REQMOUNT)) {
+        close_dev(dev);  
+      }
       goto mount_next_vol;
    }
 
@@ -320,7 +340,7 @@ read_volume:
       Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"),
         dcr->VolumeName);
       if (!eod_dev(dev)) {
-        Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device \"%s\". ERR=%s\n"),
+         Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device \"%s\". ERR=%s\n"),
            dev_name(dev), strerror_dev(dev));
         mark_volume_in_error(dcr);
         goto mount_next_vol;
@@ -332,10 +352,10 @@ read_volume:
          * that the database says we should be.
          */
         if (dev->VolCatInfo.VolCatFiles == dev_file(dev)) {
-           Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"),
+            Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"),
                 dcr->VolumeName, dev_file(dev));
         } else {
-           Jmsg(jcr, M_ERROR, 0, _("I canot write on Volume \"%s\" because:\n"
+            Jmsg(jcr, M_ERROR, 0, _("I canot write on Volume \"%s\" because:\n"
 "The number of files mismatch! Volume=%u Catalog=%u\n"),
                 dcr->VolumeName, dev_file(dev), dev->VolCatInfo.VolCatFiles);
            mark_volume_in_error(dcr);
@@ -379,21 +399,21 @@ static bool rewrite_volume_label(DCR *dcr, bool recycle)
     */
    if (!dev_cap(dev, CAP_STREAM)) {
       if (!rewind_dev(dev)) {
-        Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"),
+         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"),
               dev_name(dev), strerror_dev(dev));
       }
       if (recycle) {
         if (!truncate_dev(dev)) {
-           Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"),
+            Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"),
                  dev_name(dev), strerror_dev(dev));
         }
       }
       /* Attempt write to check write permission */
       Dmsg0(200, "Attempt to write to device.\n");
       if (!write_block_to_dev(dcr)) {
-        Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"),
+         Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"),
            dev_name(dev), strerror_dev(dev));
-        Dmsg0(200, "===ERROR write block to dev\n");
+         Dmsg0(200, "===ERROR write block to dev\n");
         return false;
       }
    }
@@ -463,7 +483,7 @@ bool mount_next_read_volume(DCR *dcr)
       close_dev(dev);
       dev->state &= ~ST_READ;
       if (!acquire_device_for_read(jcr)) {
-        Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev),
+         Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev),
               dcr->VolumeName);
         return false;
       }
index 29cb0491585bdd41b43239bacb0bf0f95ad580ac..dc3e1eda071a7a2961cb13d6d835ddff001d5366 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -85,6 +85,10 @@ void display_tape_error_status(JCR *jcr, DEVICE *dev);
 /* From dev.c */
 DEVICE *init_dev(DEVICE *dev, DEVRES *device);
 int     open_dev(DEVICE *dev, char *VolName, int mode);
+off_t   lseek_dev(DEVICE *dev, off_t offset, int whence);
+int     open_first_part(DEVICE *dev);
+int     open_next_part(DEVICE *dev);
+int     open_guess_name_dev(DEVICE *dev);
 void    close_dev(DEVICE *dev);
 void    force_close_dev(DEVICE *dev);
 bool    truncate_dev(DEVICE *dev);
@@ -113,7 +117,6 @@ bool         reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
 void    init_dev_wait_timers(DEVICE *dev);
 bool    double_dev_wait_time(DEVICE *dev);
 
-
 /* Get info about device */
 char *  dev_name(DEVICE *dev);
 char *  dev_vol_name(DEVICE *dev);
@@ -153,6 +156,7 @@ void         handle_filed_connection(BSOCK *fd, char *job_name);
 
 /* From label.c */
 int     read_dev_volume_label(DCR *dcr);
+int     read_dev_volume_label_guess(DCR *dcr, bool write);
 void    create_session_label(DCR *dcr, DEV_RECORD *rec, int label);
 void    create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName);
 bool    write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName);
index e2ff88acb32b4ba39d84c52ee8e0e59ea0606cf6..9a93f48fedb63ec0107b7a7c68c170d060eeb334 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 /*
-
    Copyright (C) 2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
index c91aca91205707c660aefe7291e679842208f22a..6bceb324b1c57215df59d25efc1fc45f1a089922 100644 (file)
@@ -6,7 +6,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -117,7 +117,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
         bnet_strerror(fd));
       return false;
    } else {
-      Dmsg1(30, ">filed: Hdr=%s\n", fd->msg);
+      Dmsg1(31, ">filed: Hdr=%s\n", fd->msg);
    }
 
 
@@ -125,7 +125,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
    save_msg = fd->msg;         /* save fd message pointer */
    fd->msg = rec->data;        /* pass data directly to bnet_send */
    fd->msglen = rec->data_len;
-   Dmsg1(30, ">filed: send %d bytes data.\n", fd->msglen);
+   Dmsg1(31, ">filed: send %d bytes data.\n", fd->msglen);
    if (!bnet_send(fd)) {
       Pmsg1(000, "Error sending to FD. ERR=%s\n", bnet_strerror(fd));
       Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"),
index 878376b79cecf17400f9db924edc9bb1135d825a..a9c0bf9146a111f4f58bcbf11d72769883792bb0 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -71,7 +71,7 @@ bool status_cmd(JCR *jcr)
              HOST_OS, DISTNAME, DISTVER);
    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
    bnet_fsend(user, _("Daemon started %s, %d Job%s run since started.\n"), dt, num_jobs_run,
-       num_jobs_run == 1 ? "" : "s");
+        num_jobs_run == 1 ? "" : "s");
    if (debug_level > 0) {
       char b1[35], b2[35], b3[35], b4[35];
       bnet_fsend(user, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
@@ -100,10 +100,10 @@ bool status_cmd(JCR *jcr)
       for (dev=device->dev; dev; dev=dev->next) {
         if (dev_state(dev, ST_OPENED)) {
            if (dev_state(dev, ST_LABEL)) {
-              bnet_fsend(user, _("Device \"%s\" is mounted with Volume \"%s\"\n"),
+               bnet_fsend(user, _("Device \"%s\" is mounted with Volume \"%s\"\n"),
                  dev_name(dev), dev->VolHdr.VolName);
            } else {
-              bnet_fsend(user, _("Device \"%s\" open but no Bacula volume is mounted.\n"), dev_name(dev));
+               bnet_fsend(user, _("Device \"%s\" open but no Bacula volume is mounted.\n"), dev_name(dev));
            }
            send_blocked_status(jcr, dev);
            if (dev_state(dev, ST_APPEND)) {
@@ -112,7 +112,7 @@ bool status_cmd(JCR *jcr)
                  bpb = 1;
               }
               bpb = dev->VolCatInfo.VolCatBytes / bpb;
-              bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
+               bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
                  edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
                  edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
                  edit_uint64_with_commas(bpb, b3));
@@ -126,17 +126,17 @@ bool status_cmd(JCR *jcr)
               } else {
                  bpb = 0;
               }
-              bnet_fsend(user, _("    Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
+               bnet_fsend(user, _("    Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
                  edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
                  edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
                  edit_uint64_with_commas(bpb, b3));
            }
-           bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"),
+            bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"),
               edit_uint64_with_commas(dev->file, b1),
               edit_uint64_with_commas(dev->block_num, b2));
 
         } else {
-           bnet_fsend(user, _("Device \"%s\" is not open.\n"), dev_name(dev));
+            bnet_fsend(user, _("Device \"%s\" is not open.\n"), dev_name(dev));
            send_blocked_status(jcr, dev);
         }
       }
@@ -170,10 +170,10 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev)
       break;
    case BST_WAITING_FOR_SYSOP:
       if (jcr->JobStatus == JS_WaitMount) {
-        bnet_fsend(user, _("    Device is BLOCKED waiting for mount of volume \"%s\".\n"),
+         bnet_fsend(user, _("    Device is BLOCKED waiting for mount of volume \"%s\".\n"),
            dcr->VolumeName);
       } else {
-        bnet_fsend(user, _("    Device is BLOCKED waiting for appendable media.\n"));
+         bnet_fsend(user, _("    Device is BLOCKED waiting for appendable media.\n"));
       }
       break;
    case BST_DOING_ACQUIRE:
@@ -213,6 +213,7 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev)
       bnet_fsend(user, "%sEOF ", dev->state & ST_EOF ? "" : "!");
       bnet_fsend(user, "%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");
       bnet_fsend(user, "%sSHORT ", dev->state & ST_SHORT ? "" : "!");
+      bnet_fsend(user, "%sMOUNTED ", dev->state & ST_MOUNTED ? "" : "!");
       bnet_fsend(user, "\n");
 
       bnet_fsend(user, _("Device parameters:\n"));
@@ -235,7 +236,7 @@ static void list_running_jobs(BSOCK *user)
    lock_jcr_chain();
    foreach_jcr(jcr) {
       if (jcr->JobStatus == JS_WaitFD) {
-        bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
+         bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
            job_type_to_str(jcr->JobType), jcr->Job);
       }
       if (jcr->device) {
@@ -243,35 +244,35 @@ static void list_running_jobs(BSOCK *user)
         /* There are three periods after the Job name */
         char *p;
         for (int i=0; i<3; i++) {
-           if ((p=strrchr(JobName, '.')) != NULL) {
+            if ((p=strrchr(JobName, '.')) != NULL) {
               *p = 0;
            }
         }
-        bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\" device=\"%s\"\n"),
+         bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\" device=\"%s\"\n"),
                   job_level_to_str(jcr->JobLevel),
                   job_type_to_str(jcr->JobType),
                   JobName,
                   jcr->JobId,
-                  jcr->dcr?jcr->dcr->VolumeName:"*none*",
-                  jcr->device?jcr->device->device_name:"none");
+                   jcr->dcr?jcr->dcr->VolumeName:"*none*",
+                   jcr->device?jcr->device->device_name:"none");
         sec = time(NULL) - jcr->run_time;
         if (sec <= 0) {
            sec = 1;
         }
         bps = jcr->JobBytes / sec;
-        bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
+         bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
            edit_uint64_with_commas(jcr->JobFiles, b1),
            edit_uint64_with_commas(jcr->JobBytes, b2),
            edit_uint64_with_commas(bps, b3));
         found = true;
 #ifdef DEBUG
         if (jcr->file_bsock) {
-           bnet_fsend(user, "    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n",
+            bnet_fsend(user, "    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n",
               edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
               jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
               jcr->file_bsock->fd);
         } else {
-           bnet_fsend(user, "    FDSocket closed\n");
+            bnet_fsend(user, "    FDSocket closed\n");
         }
 #endif
       }
@@ -312,7 +313,7 @@ static void list_terminated_jobs(void *arg)
       switch (je->JobType) {
       case JT_ADMIN:
       case JT_RESTORE:
-        bstrncpy(level, "    ", sizeof(level));
+         bstrncpy(level, "    ", sizeof(level));
         break;
       default:
         bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
@@ -321,30 +322,30 @@ static void list_terminated_jobs(void *arg)
       }
       switch (je->JobStatus) {
       case JS_Created:
-        termstat = "Created";
+         termstat = "Created";
         break;
       case JS_FatalError:
       case JS_ErrorTerminated:
-        termstat = "Error";
+         termstat = "Error";
         break;
       case JS_Differences:
-        termstat = "Diffs";
+         termstat = "Diffs";
         break;
       case JS_Canceled:
-        termstat = "Cancel";
+         termstat = "Cancel";
         break;
       case JS_Terminated:
-        termstat = "OK";
+         termstat = "OK";
         break;
       default:
-        termstat = "Other";
+         termstat = "Other";
         break;
       }
       bstrncpy(JobName, je->Job, sizeof(JobName));
       /* There are three periods after the Job name */
       char *p;
       for (int i=0; i<3; i++) {
-        if ((p=strrchr(JobName, '.')) != NULL) {
+         if ((p=strrchr(JobName, '.')) != NULL) {
            *p = 0;
         }
       }
index 2933237cc0e21b73f1a47052dd47f86883002032..cfd68b0e834861c74f075df13766fdf171991e83 100644 (file)
@@ -4,7 +4,7 @@
  *  Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -47,7 +47,7 @@
 #include "jcr.h"
 #include "protos.h"
 #ifdef HAVE_LIBZ
-#include <zlib.h>                     /* compression headers */
+#include <zlib.h>                    /* compression headers */
 #else
 #define uLongf uint32_t
 #endif
 #else
 #include "lib/fnmatch.h"
 #endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMELEN(dirent) (strlen((dirent)->d_name))
+#endif
+#ifndef HAVE_READDIR_R
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+#endif
 
 extern STORES *me;                    /* "Global" daemon resource */
-extern bool forge_on;                 /* proceed inspite of I/O errors */
+extern bool forge_on;                /* proceed inspite of I/O errors */
 
 #ifdef debug_tracing
 extern int _rewind_dev(char *file, int line, DEVICE *dev);
index 9f8edaa23d93fd4d6ce1ea55bca7483634518b6d..00c7b2df588487379a6f752b54f6cc999ad064ae 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -122,6 +122,13 @@ static RES_ITEM dev_items[] = {
    {"maximumspoolsize",      store_size,   ITEM(res_dev.max_spool_size), 0, 0, 0},
    {"maximumjobspoolsize",   store_size,   ITEM(res_dev.max_job_spool_size), 0, 0, 0},
    {"driveindex",            store_pint,   ITEM(res_dev.drive_index), 0, 0, 0},
+   {"maximumpartsize",       store_size,   ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
+   {"requiresmount",         store_yesno,  ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
+   {"mountpoint",            store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
+   {"mountcommand",          store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
+   {"unmountcommand",        store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
+   {"writepartcommand",      store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
+   {"freespacecommand",      store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
    {NULL, NULL, 0, 0, 0, 0}
 };
 
@@ -172,11 +179,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
           get_first_port_host_order(res->res_store.sddaddrs),
           edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
          foreach_dlist(p, res->res_store.sdaddrs) {
-               sendit(sock, "        SDaddr=%s SDport=%d\n",
+                sendit(sock, "        SDaddr=%s SDport=%d\n",
                             p->get_address(buf, sizeof(buf)), p->get_port_host_order());
          }
          foreach_dlist(p, res->res_store.sddaddrs) {
-               sendit(sock, "        SDDaddr=%s SDDport=%d\n",
+                sendit(sock, "        SDDaddr=%s SDDport=%d\n",
                             p->get_address(buf, sizeof(buf)), p->get_port_host_order());
          }
       break;
@@ -197,40 +204,40 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
         res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
       strcpy(buf, "        ");
       if (res->res_dev.cap_bits & CAP_EOF) {
-        bstrncat(buf, "CAP_EOF ", sizeof(buf));
+         bstrncat(buf, "CAP_EOF ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_BSR) {
-        bstrncat(buf, "CAP_BSR ", sizeof(buf));
+         bstrncat(buf, "CAP_BSR ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_BSF) {
-        bstrncat(buf, "CAP_BSF ", sizeof(buf));
+         bstrncat(buf, "CAP_BSF ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_FSR) {
-        bstrncat(buf, "CAP_FSR ", sizeof(buf));
+         bstrncat(buf, "CAP_FSR ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_FSF) {
-        bstrncat(buf, "CAP_FSF ", sizeof(buf));
+         bstrncat(buf, "CAP_FSF ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_EOM) {
-        bstrncat(buf, "CAP_EOM ", sizeof(buf));
+         bstrncat(buf, "CAP_EOM ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_REM) {
-        bstrncat(buf, "CAP_REM ", sizeof(buf));
+         bstrncat(buf, "CAP_REM ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_RACCESS) {
-        bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
+         bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
-        bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
+         bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_LABEL) {
-        bstrncat(buf, "CAP_LABEL ", sizeof(buf));
+         bstrncat(buf, "CAP_LABEL ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_ANONVOLS) {
-        bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
+         bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
       }
       if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
-        bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
+         bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
       }
       bstrncat(buf, "\n", sizeof(buf));
       sendit(sock, buf);
@@ -238,9 +245,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
    case R_MSGS:
       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
       if (res->res_msgs.mail_cmd)
-        sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
+         sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
       if (res->res_msgs.operator_cmd)
-        sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
+         sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
       break;
    default:
       sendit(sock, _("Warning: unknown resource type %d\n"), type);
@@ -320,6 +327,21 @@ void free_resource(RES *sres, int type)
         if (res->res_dev.spool_directory) {
            free(res->res_dev.spool_directory);
         }
+        if (res->res_dev.mount_point) {
+           free(res->res_dev.mount_point);
+        }
+        if (res->res_dev.mount_command) {
+           free(res->res_dev.mount_command);
+        }
+        if (res->res_dev.unmount_command) {
+           free(res->res_dev.unmount_command);
+        }
+        if (res->res_dev.write_part_command) {
+           free(res->res_dev.write_part_command);
+        }
+        if (res->res_dev.free_space_command) {
+           free(res->res_dev.free_space_command);
+        }
         break;
       case R_MSGS:
         if (res->res_msgs.mail_cmd) {
@@ -332,7 +354,7 @@ void free_resource(RES *sres, int type)
         res = NULL;
         break;
       default:
-        Dmsg1(0, "Unknown resource type %d\n", type);
+         Dmsg1(0, "Unknown resource type %d\n", type);
         break;
    }
    /* Common stuff again -- free the resource, recurse to next one */
@@ -361,13 +383,13 @@ void save_resource(int type, RES_ITEM *items, int pass)
    for (i=0; items[i].name; i++) {
       if (items[i].flags & ITEM_REQUIRED) {
         if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
-           Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
+            Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
              items[i].name, resources[rindex]);
          }
       }
       /* If this triggers, take a look at lib/parse_conf.h */
       if (i >= MAX_RES_ITEMS) {
-        Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
+         Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
       }
    }
 
@@ -387,12 +409,12 @@ void save_resource(int type, RES_ITEM *items, int pass)
         /* Resources containing a resource */
         case R_STORAGE:
            if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
-              Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name);
+               Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name);
            }
            res->res_store.messages = res_all.res_store.messages;
            break;
         default:
-           printf("Unknown resource type %d\n", type);
+            printf("Unknown resource type %d\n", type);
            error = 1;
            break;
       }
@@ -424,7 +446,7 @@ void save_resource(int type, RES_ITEM *items, int pass)
         size = sizeof(MSGS);
         break;
       default:
-        printf("Unknown resource type %d\n", type);
+         printf("Unknown resource type %d\n", type);
         error = 1;
         size = 1;
         break;
@@ -441,12 +463,12 @@ void save_resource(int type, RES_ITEM *items, int pass)
         for (next=res_head[rindex]; next->next; next=next->next) {
            if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
               Emsg2(M_ERROR_TERM, 0,
-                 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
+                  _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
                  resources[rindex].name, res->res_dir.hdr.name);
            }
         }
         next->next = (RES *)res;
-        Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
+         Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
               res->res_dir.hdr.name);
       }
    }
index 7274d34787d8c337f5c9ec3ff0c69e616acfc6d1..4e68d83d696a4787a652e634933a84db71cea80b 100644 (file)
@@ -4,7 +4,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -29,7 +29,7 @@ enum {
    R_DEVICE,
    R_MSGS,
    R_FIRST = R_DIRECTOR,
-   R_LAST  = R_MSGS                   /* keep this updated */
+   R_LAST  = R_MSGS                  /* keep this updated */
 };
 
 enum {
@@ -43,59 +43,67 @@ enum {
 
 /* Definition of the contents of each Resource */
 struct DIRRES {
-   RES   hdr;
+   RES  hdr;
 
-   char *password;                    /* Director password */
-   char *address;                     /* Director IP address or zero */
-   int enable_ssl;                    /* Use SSL with this Director */
-   int monitor;                       /* Have only access to status and .status functions */
+   char *password;                   /* Director password */
+   char *address;                    /* Director IP address or zero */
+   int enable_ssl;                   /* Use SSL with this Director */
+   int monitor;                      /* Have only access to status and .status functions */
 };
 
 
 /* Storage daemon "global" definitions */
 struct s_res_store {
-   RES   hdr;
+   RES  hdr;
 
    dlist *sdaddrs;
    dlist *sddaddrs;
-   char *working_directory;           /* working directory for checkpoints */
+   char *working_directory;          /* working directory for checkpoints */
    char *pid_directory;
    char *subsys_directory;
-   int require_ssl;                   /* Require SSL on all connections */
+   int require_ssl;                  /* Require SSL on all connections */
    uint32_t max_concurrent_jobs;      /* maximum concurrent jobs to run */
-   MSGS *messages;                    /* Daemon message handler */
-   utime_t heartbeat_interval;        /* Interval to send hb to FD */
+   MSGS *messages;                   /* Daemon message handler */
+   utime_t heartbeat_interval;       /* Interval to send hb to FD */
 };
 typedef struct s_res_store STORES;
 
 /* Device specific definitions */
 struct DEVRES {
-   RES   hdr;
+   RES  hdr;
 
-   char *media_type;                  /* User assigned media type */
-   char *device_name;                 /* Archive device name */
-   char *changer_name;                /* Changer device name */
-   char *changer_command;             /* Changer command  -- external program */
-   char *alert_command;               /* Alert command -- external program */
-   char *spool_directory;             /* Spool file directory */
-   uint32_t drive_index;              /* Autochanger drive index */
-   uint32_t cap_bits;                 /* Capabilities of this device */
-   uint32_t max_changer_wait;         /* Changer timeout */
-   uint32_t max_rewind_wait;          /* maximum secs to wait for rewind */
-   uint32_t max_open_wait;            /* maximum secs to wait for open */
-   uint32_t max_open_vols;            /* maximum simultaneous open volumes */
-   uint32_t min_block_size;           /* min block size */
-   uint32_t max_block_size;           /* max block size */
-   uint32_t max_volume_jobs;          /* max jobs to put on one volume */
+   char *media_type;                 /* User assigned media type */
+   char *device_name;                /* Archive device name */
+   char *changer_name;               /* Changer device name */
+   char *changer_command;            /* Changer command  -- external program */
+   char *alert_command;              /* Alert command -- external program */
+   char *spool_directory;            /* Spool file directory */
+   uint32_t drive_index;             /* Autochanger drive index */
+   uint32_t cap_bits;                /* Capabilities of this device */
+   uint32_t max_changer_wait;        /* Changer timeout */
+   uint32_t max_rewind_wait;         /* maximum secs to wait for rewind */
+   uint32_t max_open_wait;           /* maximum secs to wait for open */
+   uint32_t max_open_vols;           /* maximum simultaneous open volumes */
+   uint32_t min_block_size;          /* min block size */
+   uint32_t max_block_size;          /* max block size */
+   uint32_t max_volume_jobs;         /* max jobs to put on one volume */
    uint32_t max_network_buffer_size;  /* max network buf size */
-   utime_t  vol_poll_interval;        /* interval between polling volume during mount */
-   int64_t max_volume_files;          /* max files to put on one volume */
-   int64_t max_volume_size;           /* max bytes to put on one volume */
-   int64_t max_file_size;             /* max file size in bytes */
-   int64_t volume_capacity;           /* advisory capacity */
-   int64_t max_spool_size;            /* Max spool size for all jobs */
-   int64_t max_job_spool_size;        /* Max spool size for any single job */
-   DEVICE *dev;                       /* Pointer to phyical dev -- set at runtime */
+   utime_t  vol_poll_interval;       /* interval between polling volume during mount */
+   int64_t max_volume_files;         /* max files to put on one volume */
+   int64_t max_volume_size;          /* max bytes to put on one volume */
+   int64_t max_file_size;            /* max file size in bytes */
+   int64_t volume_capacity;          /* advisory capacity */
+   int64_t max_spool_size;           /* Max spool size for all jobs */
+   int64_t max_job_spool_size;       /* Max spool size for any single job */
+   
+   int64_t max_part_size;            /* Max part size */
+   char *mount_point;                /* Mount point for require mount devices */
+   char *mount_command;              /* Mount command */
+   char *unmount_command;            /* Unmount command */
+   char *write_part_command;         /* Write part command */
+   char *free_space_command;         /* Free space command */
+   
+   DEVICE *dev;                      /* Pointer to phyical dev -- set at runtime */
 };
 
 union URES {
@@ -103,5 +111,5 @@ union URES {
    STORES res_store;
    DEVRES res_dev;
    MSGS   res_msgs;
-   RES    hdr;
+   RES   hdr;
 };
index 458f776767992b12f137a902ff512b6f2b65db81..32abe6fa40b644b8bcf41fee3002e5e33723803b 100644 (file)
@@ -50,17 +50,17 @@ static void usage()
 int
 main (int argc, char *const *argv)
 {
-   POOLMEM *fs;
    int verbose = 0;
    int status = 0;
    int ch, i;
+   char fs[1000];
 
    while ((ch = getopt(argc, argv, "v?")) != -1) {
       switch (ch) {
-        case 'v':
+         case 'v':
            verbose = 1;
            break;
-        case '?':
+         case '?':
         default:
            usage();
 
@@ -74,15 +74,14 @@ main (int argc, char *const *argv)
    }
 
    for (i = 0; i < argc; --argc, ++argv) {
-      if ((fs = fstype(*argv)) != NULL) {
+      if (fstype(*argv, fs, sizeof(fs))) {
         if (verbose) {
-           printf("%s: %s\n", *argv, fs);
+            printf("%s: %s\n", *argv, fs);
         } else {
            puts(fs);
         }
-        free(fs);
       } else {
-        fprintf(stderr, "%s: unknown\n", *argv);
+         fprintf(stderr, "%s: unknown\n", *argv);
         status = 1;
       }
    }
index beaab4303c8de2cc8a71baca68a56f3096b97984..f44707ce51bb97e3e1d7e8afa897eb4f7db09288 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #undef  VERSION
-#define VERSION "1.37.1"
-#define BDATE   "07 January 2005"
-#define LSMDATE "07Jan05"
+#define VERSION "1.37.2"
+#define BDATE   "08 January 2005"
+#define LSMDATE "08Jan05"
 
 /* Debug flags */
 #undef  DEBUG