]> git.sur5r.net Git - bacula/bacula/commitdiff
- Tweak dvd-writepart script to prevent door from opening/closing
authorKern Sibbald <kern@sibbald.com>
Sun, 3 Jul 2005 13:54:30 +0000 (13:54 +0000)
committerKern Sibbald <kern@sibbald.com>
Sun, 3 Jul 2005 13:54:30 +0000 (13:54 +0000)
  so much.
- Remove GROUP BY in several PostgreSQL commands to prevent error.
  Resolves bug report.
- Ensure that < as first character of filename list is not treated
  as a directory for restore.
- Add debug to heartbeat in FD as it seems to go into an
  infinite loop from time to time during SD failure in DVD writing.
- Add more debug code to dvd writing.
- Attempt not to destroy existing fs on DVD.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2171 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/kernstodo
bacula/kes-1.37
bacula/scripts/dvd-writepart.in
bacula/src/cats/sql_list.c
bacula/src/dird/sql_cmds.c
bacula/src/dird/ua_restore.c
bacula/src/filed/heartbeat.c
bacula/src/stored/dev.c
bacula/src/stored/dvd.c
bacula/src/version.h

index 2571adee1d89ac9a808ce2f03c819f1e36b1e6df..6387dc40acfb3d619d7a8a7b1a292258c71acf26 100644 (file)
@@ -22,6 +22,30 @@ Autochangers:
 -    Make "update slots" when pointing to Autochanger, remove
      all Volumes from other drives.  "update slots all-drives"?
 
+For 1.37:
+- Finish TLS implementation.
+- Fix PostgreSQL GROUP BY problems in restore.
+- Fix PostgreSQL sql problems in bugs.
+- Refuse to prune last valid Full backup. Same goes for Catalog.
+- --without-openssl breaks at least on Solaris.
+- Python:
+  - Make a callback when Rerun failed levels is called.
+  - Give Python program access to Scheduled jobs.
+  - Add setting Volume State via Python.
+  - Python script to save with Python, not save, save with Bacula.
+  - Python script to do backup.
+  - What events?
+  - Change the Priority, Client, Storage, JobStatus (error) 
+    at the start of a job.
+- Why is SpoolDirectory = /home/bacula/spool;  not reported
+  as an error when writing a DVD?
+- Make bootstrap file handle multiple MediaTypes (SD)
+- Remove all old Device resource code in Dir and code to pass it
+  back in SD -- better, rework it to pass back device statistics.
+- Check locking of resources -- be sure to lock devices where previously
+  resources were locked. 
+- The last part is left in the spool dir.
+
 Document:
 - Port limiting -m in iptables to prevent DoS attacks
   could cause broken pipes on Bacula.
@@ -50,31 +74,6 @@ Document:
 - Document Heartbeat Interval in the dealing with firewalls section.
 - Document the multiple-drive-changer.txt script.
 
-For 1.37:
-- Cleaning tapes should have Status "Cleaning" rather than append.
-- Refuse to prune last valid Full backup. Same goes for Catalog.
-- Why is   SpoolDirectory = /home/bacula/spool;  not reported
-  as an error when writing a DVD?
-- Add setting Volume State via Python.
-- Make bootstrap file handle multiple MediaTypes (SD)
-- --without-openssl breaks at least on Solaris.
-- Python:
-  - Make a callback when Rerun failed levels is called.
-  - Give Python program access to Scheduled jobs.
-  - Python script to save with Python, not save, save with Bacula.
-  - Python script to do backup.
-  - What events?
-  - Change the Priority, Client, Storage, JobStatus (error) 
-    at the start of a job.
-  - Make sure that Python has access to Client address/port so that
-    it can check if Clients are alive.
-
-- Remove all old Device resource code in Dir and code to pass it
-  back in SD -- better, rework it to pass back device statistics.
-- Check locking of resources -- be sure to lock devices where previously
-  resources were locked. 
-- Add global lock on all devices when creating a device structure.
-
 Maybe in 1.37:
 - In restore don't compare byte count on a raw device -- directory
   entry does not contain bytes.
@@ -1294,3 +1293,8 @@ Block Position: 0
 - Implement "PreferMountedVolumes = yes|no" in Job resource.
 ##   Integrate web-bacula into a new Bacula project with
      bimagemgr.
+- Cleaning tapes should have Status "Cleaning" rather than append.
+- Make sure that Python has access to Client address/port so that
+  it can check if Clients are alive.
+- Review all items in "restore".
+
index 9bdca223935353fff8923a6455aa34fc9688ceb6..dc904e44f8af3f8bf688bcd38326efe5882e4339 100644 (file)
@@ -4,6 +4,17 @@
 General:
 
 Changes to 1.37.28:
+02Jul05
+- Tweak dvd-writepart script to prevent door from opening/closing
+  so much.
+- Remove GROUP BY in several PostgreSQL commands to prevent error.
+  Resolves bug report.
+- Ensure that < as first character of filename list is not treated
+  as a directory for restore.
+- Add debug to heartbeat in FD as it seems to go into an
+  infinite loop from time to time during SD failure in DVD writing.
+- Add more debug code to dvd writing.
+- Attempt not to destroy existing fs on DVD. 
 30Jun05
 - Detect device mounted for DVD and suppress be sure to 
   mount message after label.
index 5de917c8e4c308555d6059b64762bfe1333aeb24..515daa8583cc474010f770fb7b5f11eff546fe69 100644 (file)
@@ -9,8 +9,8 @@
 #  Write Part Command = "path-to-this-script/dvd-writepart %n %a %v"
 #    you will have the following input to this script:
 #
-#  dvd-writepart "part_number"    "device"  "part_filename"
-#                     $1             $2           $3
+#  dvd-writepart "part_number"   "device"  "part_filename"
+#                    $1             $2           $3
 #
 #  for example:
 #
 MKISOFS=@MKISOFS@
 GROWISOFS=@GROWISOFS@
 
-GROWARGS="-use-the-force-luke=tty -quiet"
+# GROWARGS="-use-the-force-luke=tty -quiet"
+GROWARGS="-quiet"
 
 # Uncomment the following line if you do not want the tray to be reloaded
 # when writing ends.
-#GROWARGS="${GROWARGS} -use-the-force-luke=notray"
+GROWARGS="${GROWARGS} -use-the-force-luke=notray"
 
 # Uncomment the following line if you have a Linux kernel >=2.6.8, and
 # if you want to allow a session to start beyond the 4gb boundary.
index cb229b72c20bdeff1e006bce3578b195507ea0b4..7b2659e15d75518e5cc470c70a07292a8d0ee6be 100644 (file)
@@ -5,31 +5,25 @@
  *
  *    Version $Id$
  */
-
 /*
    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
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   modify it under the terms of the GNU General Public License
+   version 2 as ammended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
  */
 
 /* The following is necessary so that we do not include
  * the dummy external definition of DB.
  */
-#define __SQL_C                      /* indicate that this is sql.c */
+#define __SQL_C                       /* indicate that this is sql.c */
 
 #include "bacula.h"
 #include "cats.h"
@@ -52,13 +46,13 @@ extern int QueryDB(const char *file, int line, JCR *jcr, B_DB *db, char *select_
  * Submit general SQL query
  */
 int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit,
-                     void *ctx, int verbose, e_list_type type)
+                      void *ctx, int verbose, e_list_type type)
 {
    db_lock(mdb);
    if (sql_query(mdb, query) != 0) {
       Mmsg(mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb));
       if (verbose) {
-        sendit(ctx, mdb->errmsg);
+         sendit(ctx, mdb->errmsg);
       }
       db_unlock(mdb);
       return 0;
@@ -131,7 +125,7 @@ db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx,
  */
 void
 db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
-                     DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
+                      DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
 {
    char ed1[50];
    db_lock(mdb);
@@ -152,7 +146,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
             "EndFile,EndBlock,VolParts,LabelType,StorageId"
             " FROM Media WHERE Media.PoolId=%s ORDER BY MediaId", 
-           edit_int64(mdbr->PoolId, ed1));
+            edit_int64(mdbr->PoolId, ed1));
       }
    } else {
       if (mdbr->VolumeName[0] != 0) {
@@ -163,7 +157,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,"
             "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten "
             "FROM Media WHERE Media.PoolId=%s ORDER BY MediaId", 
-           edit_int64(mdbr->PoolId, ed1));
+            edit_int64(mdbr->PoolId, ed1));
       }
    }
 
@@ -179,12 +173,12 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
 }
 
 void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
-                             DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
+                              DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
 {
    char ed1[50];
    db_lock(mdb);
    if (type == VERT_LIST) {
-      if (JobId > 0) {                  /* do by JobId */
+      if (JobId > 0) {                   /* do by JobId */
          Mmsg(mdb->cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
             "JobMedia.EndBlock,Copy,Stripe "
@@ -198,7 +192,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
       }
 
    } else {
-      if (JobId > 0) {                  /* do by JobId */
+      if (JobId > 0) {                   /* do by JobId */
          Mmsg(mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
             "AND JobMedia.JobId=%s", edit_int64(JobId, ed1));
@@ -228,7 +222,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
  */
 void
 db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
-                   void *ctx, e_list_type type)
+                    void *ctx, e_list_type type)
 {
    char ed1[50];
    char limit[100];
@@ -240,7 +234,7 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
    }
    if (type == VERT_LIST) {
       if (jr->JobId == 0 && jr->Job[0] == 0) {
-        Mmsg(mdb->cmd,
+         Mmsg(mdb->cmd,
             "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
             "Job.ClientId,Client.Name,JobStatus,SchedTime,"
             "StartTime,EndTime,JobTDate,"
@@ -249,8 +243,8 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
             "FROM Job,Client,Pool,FileSet WHERE "
             "Client.ClientId=Job.ClientId AND Pool.PoolId=Job.PoolId "
             "AND FileSet.FileSetId=Job.FileSetId  ORDER BY StartTime%s", limit);
-      } else {                          /* single record */
-        Mmsg(mdb->cmd,
+      } else {                           /* single record */
+         Mmsg(mdb->cmd,
             "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
             "Job.ClientId,Client.Name,JobStatus,SchedTime,"
             "StartTime,EndTime,JobTDate,"
@@ -259,17 +253,17 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
             "FROM Job,Client,Pool,FileSet WHERE Job.JobId=%s AND "
             "Client.ClientId=Job.ClientId AND Pool.PoolId=Job.PoolId "
             "AND FileSet.FileSetId=Job.FileSetId", 
-           edit_int64(jr->JobId, ed1));
+            edit_int64(jr->JobId, ed1));
       }
    } else {
       if (jr->JobId == 0 && jr->Job[0] == 0) {
-        Mmsg(mdb->cmd,
+         Mmsg(mdb->cmd,
            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
            "FROM Job ORDER BY StartTime%s", limit);
-      } else {                          /* single record */
+      } else {                           /* single record */
          Mmsg(mdb->cmd, "SELECT JobId,Name,StartTime,Type,Level,"
             "JobFiles,JobBytes,JobStatus FROM Job WHERE JobId=%s", 
-           edit_int64(jr->JobId, ed1));
+            edit_int64(jr->JobId, ed1));
       }
    }
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
@@ -306,7 +300,7 @@ db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo
 
    /* Do Grand Total */
    Mmsg(mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
-"AS Files,sum(JobBytes) As Bytes FROM Job");
+        "AS Files,sum(JobBytes) As Bytes FROM Job");
 
    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
       db_unlock(mdb);
index 9a2a5aa3f4efdbe74d0753dc68eb7845e4d0a913..f0fa6bb0a0b1aa9f14c819067e172681f4b488f6 100644 (file)
@@ -304,10 +304,20 @@ const char *uar_inc =
    "AND FileSet.FileSet='%s' "
    "%s";
 
+#ifdef HAVE_POSTGRESQL
+/* Note, the PostgreSQL will have a much uglier looking
+ * list since it cannot do GROUP BY of different values.
+ */
+const char *uar_list_temp =
+   "SELECT JobId,Level,JobFiles,JobBytes,StartTime,VolumeName,StartFile"
+   " FROM temp"
+   " ORDER BY StartTime,StartFile ASC";
+#else
 const char *uar_list_temp =
    "SELECT JobId,Level,JobFiles,JobBytes,StartTime,VolumeName,StartFile"
    " FROM temp"
    " GROUP BY JobId ORDER BY StartTime,StartFile ASC";
+#endif
 
 
 const char *uar_sel_jobid_temp = "SELECT JobId FROM temp ORDER BY StartTime ASC";
@@ -359,7 +369,24 @@ const char *uar_jobids_fileindex =
    "AND Filename.FilenameId=File.FilenameId "
    "ORDER BY Job.StartTime DESC LIMIT 1";
 
-/* Query to get all files in a directory -- no recursing */
+/* Query to get all files in a directory -- no recursing   
+ *  Note, for PostgreSQL since it respects the "Single Value
+ *  rule", the results of the SELECT will be unoptimized.
+ *  I.e. the same file will be restored multiple times, once
+ *  for each time it was backed up.
+ */
+
+#ifdef HAVE_POSTGRESQL
+const char *uar_jobid_fileindex_from_dir = 
+   "SELECT Job.JobId,File.FileIndex FROM Job,File,Path,Filename,Client "
+   "WHERE Job.JobId IN (%s) "
+   "AND Job.JobId=File.JobId "
+   "AND Path.Path='%s' "
+   "AND Client.Name='%s' "
+   "AND Job.ClientId=Client.ClientId "
+   "AND Path.PathId=File.Pathid "
+   "AND Filename.FilenameId=File.FilenameId"; 
+#else
 const char *uar_jobid_fileindex_from_dir = 
    "SELECT Job.JobId,File.FileIndex FROM Job,File,Path,Filename,Client "
    "WHERE Job.JobId IN (%s) "
@@ -370,4 +397,5 @@ const char *uar_jobid_fileindex_from_dir =
    "AND Path.PathId=File.Pathid "
    "AND Filename.FilenameId=File.FilenameId "
    "GROUP BY File.FileIndex ";
+#endif
  
index 23a02883cfda9f10f803074d48c54416c0971674..5bff2b886d4256e06b50fd86559e282f3a9611aa 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
  *   Bacula Director -- User Agent Database restore Command
- *     Creates a bootstrap file for restoring files and
- *     starts the restore job.
+ *      Creates a bootstrap file for restoring files and
+ *      starts the restore job.
  *
- *     Tree handling routines split into ua_tree.c July MMIII.
- *     BSR (bootstrap record) handling routines split into
- *       bsr.c July MMIII
+ *      Tree handling routines split into ua_tree.c July MMIII.
+ *      BSR (bootstrap record) handling routines split into
+ *        bsr.c July MMIII
  *
  *     Kern Sibbald, July MMII
  *
 extern void print_bsr(UAContext *ua, RBSR *bsr);
 
 /* Imported variables */
-extern char *uar_list_jobs,     *uar_file,        *uar_sel_files;
-extern char *uar_del_temp,      *uar_del_temp1,   *uar_create_temp;
-extern char *uar_create_temp1,  *uar_last_full,   *uar_full;
-extern char *uar_inc,           *uar_list_temp,   *uar_sel_jobid_temp;
+extern char *uar_list_jobs,      *uar_file,        *uar_sel_files;
+extern char *uar_del_temp,       *uar_del_temp1,   *uar_create_temp;
+extern char *uar_create_temp1,   *uar_last_full,   *uar_full;
+extern char *uar_inc,            *uar_list_temp,   *uar_sel_jobid_temp;
 extern char *uar_sel_all_temp1,  *uar_sel_fileset, *uar_mediatype;
-extern char *uar_jobid_fileindex, *uar_dif,       *uar_sel_all_temp;
-extern char *uar_count_files,    *uar_jobids_fileindex;
+extern char *uar_jobid_fileindex, *uar_dif,        *uar_sel_all_temp;
+extern char *uar_count_files,     *uar_jobids_fileindex;
 extern char *uar_jobid_fileindex_from_dir;
 
 
 struct NAME_LIST {
-   char **name;                      /* list of names */
-   int num_ids;                      /* ids stored */
-   int max_ids;                      /* size of array */
-   int num_del;                      /* number deleted */
-   int tot_ids;                      /* total to process */
+   char **name;                       /* list of names */
+   int num_ids;                       /* ids stored */
+   int max_ids;                       /* size of array */
+   int num_del;                       /* number deleted */
+   int tot_ids;                       /* total to process */
 };
 
 
@@ -62,7 +62,7 @@ struct RESTORE_CTX {
    uint32_t JobId;
    char ClientName[MAX_NAME_LENGTH];
    char last_jobid[20];
-   POOLMEM *JobIds;                  /* User entered string of JobIds */
+   POOLMEM *JobIds;                   /* User entered string of JobIds */
    STORE  *store;
    JOB *restore_job;
    POOL *pool;
@@ -70,13 +70,13 @@ struct RESTORE_CTX {
    uint32_t selected_files;
    char *where;
    RBSR *bsr;
-   POOLMEM *fname;                   /* filename only */
-   POOLMEM *path;                    /* path only */
+   POOLMEM *fname;                    /* filename only */
+   POOLMEM *path;                     /* path only */
    POOLMEM *query;
-   int fnl;                          /* filename length */
-   int pnl;                          /* path length */
+   int fnl;                           /* filename length */
+   int pnl;                           /* path length */
    bool found;
-   bool all;                         /* mark all as default */
+   bool all;                          /* mark all as default */
    NAME_LIST name_list;
 };
 
@@ -100,9 +100,9 @@ static void free_rx(RESTORE_CTX *rx);
 static void split_path_and_filename(RESTORE_CTX *rx, char *fname);
 static int jobid_fileindex_handler(void *ctx, int num_fields, char **row);
 static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file,
-                                        char *date);
+                                         char *date);
 static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *dir,
-                                       char *date);
+                                        char *date);
 static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, bool dir);
 static int get_client_name(UAContext *ua, RESTORE_CTX *rx);
 static int get_date(UAContext *ua, char *date, int date_len);
@@ -114,7 +114,7 @@ static int count_handler(void *ctx, int num_fields, char **row);
  */
 int restore_cmd(UAContext *ua, const char *cmd)
 {
-   RESTORE_CTX rx;                   /* restore context */
+   RESTORE_CTX rx;                    /* restore context */
    JOB *job;
    int i;
    POOLMEM *fname;
@@ -139,10 +139,10 @@ int restore_cmd(UAContext *ua, const char *cmd)
    LockRes();
    foreach_res(job, R_JOB) {
       if (job->JobType == JT_RESTORE) {
-        if (!rx.restore_job) {
-           rx.restore_job = job;
-        }
-        rx.restore_jobs++;
+         if (!rx.restore_job) {
+            rx.restore_job = job;
+         }
+         rx.restore_jobs++;
       }
    }
    UnlockRes();
@@ -160,26 +160,26 @@ int restore_cmd(UAContext *ua, const char *cmd)
     *  add_findex()
     */
    switch (user_select_jobids_or_files(ua, &rx)) {
-   case 0:                           /* error */
+   case 0:                            /* error */
       goto bail_out;
-   case 1:                           /* selected by jobid */
+   case 1:                            /* selected by jobid */
       if (!build_directory_tree(ua, &rx)) {
          bsendmsg(ua, _("Restore not done.\n"));
-        goto bail_out;
+         goto bail_out;
       }
       break;
-   case 2:                           /* selected by filename, no tree needed */
+   case 2:                            /* selected by filename, no tree needed */
       break;
    }
 
    if (rx.bsr->JobId) {
-      if (!complete_bsr(ua, rx.bsr)) {  /* find Vol, SessId, SessTime from JobIds */
+      if (!complete_bsr(ua, rx.bsr)) {   /* find Vol, SessId, SessTime from JobIds */
          bsendmsg(ua, _("Unable to construct a valid BSR. Cannot continue.\n"));
-        goto bail_out;
+         goto bail_out;
       }
       if (!(rx.selected_files = write_bsr_file(ua, rx.bsr))) {
          bsendmsg(ua, _("No files selected to be restored.\n"));
-        goto bail_out;
+         goto bail_out;
       }
       bsendmsg(ua, _("\n%u file%s selected to be restored.\n\n"), rx.selected_files,
          rx.selected_files==1?"":"s");
@@ -211,13 +211,13 @@ int restore_cmd(UAContext *ua, const char *cmd)
           "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\""
           " where=\"%s\" files=%d catalog=\"%s\"",
           job->hdr.name, rx.ClientName, rx.store?rx.store->hdr.name:"",
-         fname, rx.where, rx.selected_files, ua->catalog->hdr.name);
+          fname, rx.where, rx.selected_files, ua->catalog->hdr.name);
    } else {
       Mmsg(ua->cmd,
           "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\""
           " files=%d catalog=\"%s\"",
           job->hdr.name, rx.ClientName, rx.store?rx.store->hdr.name:"",
-         fname, rx.selected_files, ua->catalog->hdr.name);
+          fname, rx.selected_files, ua->catalog->hdr.name);
    }
    free_pool_memory(fname);
    if (find_arg(ua, _("yes")) > 0) {
@@ -266,12 +266,12 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx)
       /* try command line argument */
       int i = find_arg_with_value(ua, _("client"));
       if (i >= 0) {
-        bstrncpy(rx->ClientName, ua->argv[i], sizeof(rx->ClientName));
-        return 1;
+         bstrncpy(rx->ClientName, ua->argv[i], sizeof(rx->ClientName));
+         return 1;
       }
       memset(&cr, 0, sizeof(cr));
       if (!get_client_dbr(ua, &cr)) {
-        return 0;
+         return 0;
       }
       bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
    }
@@ -284,8 +284,8 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx)
  *  select which files are to be restored.
  *
  *  Returns:  2  if filename list made
- *           1  if jobid list made
- *           0  on error
+ *            1  if jobid list made
+ *            0  on error
  */
 static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
 {
@@ -307,7 +307,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       "Enter a list of files to restore before a specified time",
       "Find the JobIds of the most recent backup for a client",
       "Find the JobIds for a backup for a client before a specified time",
-      "Enter a list of directories to restore for given JobIds",
+      "Enter a list of directories to restore for found JobIds",
       "Cancel",
       NULL };
 
@@ -337,86 +337,86 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
 
    for (i=1; i<ua->argc; i++) {       /* loop through arguments */
       bool found_kw = false;
-      for (j=0; kw[j]; j++) {        /* loop through keywords */
-        if (strcasecmp(kw[j], ua->argk[i]) == 0) {
-           found_kw = true;
-           break;
-        }
+      for (j=0; kw[j]; j++) {         /* loop through keywords */
+         if (strcasecmp(kw[j], ua->argk[i]) == 0) {
+            found_kw = true;
+            break;
+         }
       }
       if (!found_kw) {
          bsendmsg(ua, _("Unknown keyword: %s\n"), ua->argk[i]);
-        return 0;
+         return 0;
       }
       /* Found keyword in kw[] list, process it */
       switch (j) {
-      case 0:                           /* jobid */
-        if (*rx->JobIds != 0) {
+      case 0:                            /* jobid */
+         if (*rx->JobIds != 0) {
             pm_strcat(rx->JobIds, ",");
-        }
-        pm_strcat(rx->JobIds, ua->argv[i]);
-        done = true;
-        break;
-      case 1:                           /* current */
-        bstrutime(date, sizeof(date), time(NULL));
-        have_date = true;
-        break;
-      case 2:                           /* before */
-        if (str_to_utime(ua->argv[i]) == 0) {
+         }
+         pm_strcat(rx->JobIds, ua->argv[i]);
+         done = true;
+         break;
+      case 1:                            /* current */
+         bstrutime(date, sizeof(date), time(NULL));
+         have_date = true;
+         break;
+      case 2:                            /* before */
+         if (str_to_utime(ua->argv[i]) == 0) {
             bsendmsg(ua, _("Improper date format: %s\n"), ua->argv[i]);
-           return 0;
-        }
-        bstrncpy(date, ua->argv[i], sizeof(date));
-        have_date = true;
-        break;
-      case 3:                           /* file */
-      case 4:                           /* dir */
-        if (!have_date) {
-           bstrutime(date, sizeof(date), time(NULL));
-        }
-        if (!get_client_name(ua, rx)) {
-           return 0;
-        }
-        pm_strcpy(ua->cmd, ua->argv[i]);
-        insert_one_file_or_dir(ua, rx, date, j==4);
-        if (rx->name_list.num_ids) {
-           /* Check MediaType and select storage that corresponds */
-           get_storage_from_mediatype(ua, &rx->name_list, rx);
-           done = true;
-        }
-        break;
-      case 5:                           /* select */
-        if (!have_date) {
-           bstrutime(date, sizeof(date), time(NULL));
-        }
-        if (!select_backups_before_date(ua, rx, date)) {
-           return 0;
-        }
-        done = true;
-        break;
-      case 6:                           /* pool specified */
-        rx->pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
-        if (!rx->pool) {
+            return 0;
+         }
+         bstrncpy(date, ua->argv[i], sizeof(date));
+         have_date = true;
+         break;
+      case 3:                            /* file */
+      case 4:                            /* dir */
+         if (!have_date) {
+            bstrutime(date, sizeof(date), time(NULL));
+         }
+         if (!get_client_name(ua, rx)) {
+            return 0;
+         }
+         pm_strcpy(ua->cmd, ua->argv[i]);
+         insert_one_file_or_dir(ua, rx, date, j==4);
+         if (rx->name_list.num_ids) {
+            /* Check MediaType and select storage that corresponds */
+            get_storage_from_mediatype(ua, &rx->name_list, rx);
+            done = true;
+         }
+         break;
+      case 5:                            /* select */
+         if (!have_date) {
+            bstrutime(date, sizeof(date), time(NULL));
+         }
+         if (!select_backups_before_date(ua, rx, date)) {
+            return 0;
+         }
+         done = true;
+         break;
+      case 6:                            /* pool specified */
+         rx->pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
+         if (!rx->pool) {
             bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
-           return 0;
-        }
-        if (!acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
-           rx->pool = NULL;
+            return 0;
+         }
+         if (!acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
+            rx->pool = NULL;
             bsendmsg(ua, _("Error: Pool resource \"%s\" access not allowed.\n"), ua->argv[i]);
-           return 0;
-        }
-        break;
-      case 7:                        /* all specified */
-        rx->all = true;
-        break;
+            return 0;
+         }
+         break;
+      case 7:                         /* all specified */
+         rx->all = true;
+         break;
       /*
        * All keywords 7 or greater are ignored or handled by a select prompt
        */
       default:
-        break;
+         break;
       }
    }
    if (rx->name_list.num_ids) {
-      return 2;                      /* filename list made */
+      return 2;                       /* filename list made */
    }
 
    if (!done) {
@@ -434,175 +434,176 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
 
       start_prompt(ua, _("To select the JobIds, you have the following choices:\n"));
       for (int i=0; list[i]; i++) {
-        add_prompt(ua, list[i]);
+         add_prompt(ua, list[i]);
       }
       done = true;
       switch (do_prompt(ua, "", _("Select item: "), NULL, 0)) {
-      case -1:                       /* error */
-        return 0;
-      case 0:                        /* list last 20 Jobs run */
-        gui_save = ua->jcr->gui;
-        ua->jcr->gui = true;
-        db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, HORZ_LIST);
-        ua->jcr->gui = gui_save;
-        done = false;
-        break;
-      case 1:                        /* list where a file is saved */
-        if (!get_client_name(ua, rx)) {
-           return 0;
-        }
+      case -1:                        /* error */
+         return 0;
+      case 0:                         /* list last 20 Jobs run */
+         gui_save = ua->jcr->gui;
+         ua->jcr->gui = true;
+         db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, HORZ_LIST);
+         ua->jcr->gui = gui_save;
+         done = false;
+         break;
+      case 1:                         /* list where a file is saved */
+         if (!get_client_name(ua, rx)) {
+            return 0;
+         }
          if (!get_cmd(ua, _("Enter Filename (no path):"))) {
-           return 0;
-        }
-        len = strlen(ua->cmd);
-        fname = (char *)malloc(len * 2 + 1);
-        db_escape_string(fname, ua->cmd, len);
-        Mmsg(rx->query, uar_file, rx->ClientName, fname);
-        free(fname);
-        gui_save = ua->jcr->gui;
-        ua->jcr->gui = true;
-        db_list_sql_query(ua->jcr, ua->db, rx->query, prtit, ua, 1, HORZ_LIST);
-        ua->jcr->gui = gui_save;
-        done = false;
-        break;
-      case 2:                        /* enter a list of JobIds */
+            return 0;
+         }
+         len = strlen(ua->cmd);
+         fname = (char *)malloc(len * 2 + 1);
+         db_escape_string(fname, ua->cmd, len);
+         Mmsg(rx->query, uar_file, rx->ClientName, fname);
+         free(fname);
+         gui_save = ua->jcr->gui;
+         ua->jcr->gui = true;
+         db_list_sql_query(ua->jcr, ua->db, rx->query, prtit, ua, 1, HORZ_LIST);
+         ua->jcr->gui = gui_save;
+         done = false;
+         break;
+      case 2:                         /* enter a list of JobIds */
          if (!get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
-           return 0;
-        }
-        pm_strcpy(rx->JobIds, ua->cmd);
-        break;
-      case 3:                        /* Enter an SQL list command */
+            return 0;
+         }
+         pm_strcpy(rx->JobIds, ua->cmd);
+         break;
+      case 3:                         /* Enter an SQL list command */
          if (!get_cmd(ua, _("Enter SQL list command: "))) {
-           return 0;
-        }
-        gui_save = ua->jcr->gui;
-        ua->jcr->gui = true;
-        db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, HORZ_LIST);
-        ua->jcr->gui = gui_save;
-        done = false;
-        break;
-      case 4:                        /* Select the most recent backups */
-        bstrutime(date, sizeof(date), time(NULL));
-        if (!select_backups_before_date(ua, rx, date)) {
-           return 0;
-        }
-        break;
-      case 5:                        /* select backup at specified time */
-        if (!get_date(ua, date, sizeof(date))) {
-           return 0;
-        }
-        if (!select_backups_before_date(ua, rx, date)) {
-           return 0;
-        }
-        break;
-      case 6:                        /* Enter files */
-        bstrutime(date, sizeof(date), time(NULL));
-        if (!get_client_name(ua, rx)) {
-           return 0;
-        }
+            return 0;
+         }
+         gui_save = ua->jcr->gui;
+         ua->jcr->gui = true;
+         db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, HORZ_LIST);
+         ua->jcr->gui = gui_save;
+         done = false;
+         break;
+      case 4:                         /* Select the most recent backups */
+         bstrutime(date, sizeof(date), time(NULL));
+         if (!select_backups_before_date(ua, rx, date)) {
+            return 0;
+         }
+         break;
+      case 5:                         /* select backup at specified time */
+         if (!get_date(ua, date, sizeof(date))) {
+            return 0;
+         }
+         if (!select_backups_before_date(ua, rx, date)) {
+            return 0;
+         }
+         break;
+      case 6:                         /* Enter files */
+         bstrutime(date, sizeof(date), time(NULL));
+         if (!get_client_name(ua, rx)) {
+            return 0;
+         }
          bsendmsg(ua, _("Enter file names with paths, or < to enter a filename\n"
                         "containg a list of file names with paths, and terminate\n"
                         "them with a blank line.\n"));
-        for ( ;; ) {
+         for ( ;; ) {
             if (!get_cmd(ua, _("Enter full filename: "))) {
-              return 0;
-           }
-           len = strlen(ua->cmd);
-           if (len == 0) {
-              break;
-           }
-           insert_one_file_or_dir(ua, rx, date, false);
-        }
-        /* Check MediaType and select storage that corresponds */
-        if (rx->name_list.num_ids) {
-           get_storage_from_mediatype(ua, &rx->name_list, rx);
-        }
-        return 2;
-       case 7:                       /* enter files backed up before specified time */
-        if (!get_date(ua, date, sizeof(date))) {
-           return 0;
-        }
-        if (!get_client_name(ua, rx)) {
-           return 0;
-        }
+               return 0;
+            }
+            len = strlen(ua->cmd);
+            if (len == 0) {
+               break;
+            }
+            insert_one_file_or_dir(ua, rx, date, false);
+         }
+         /* Check MediaType and select storage that corresponds */
+         if (rx->name_list.num_ids) {
+            get_storage_from_mediatype(ua, &rx->name_list, rx);
+         }
+         return 2;
+       case 7:                        /* enter files backed up before specified time */
+         if (!get_date(ua, date, sizeof(date))) {
+            return 0;
+         }
+         if (!get_client_name(ua, rx)) {
+            return 0;
+         }
          bsendmsg(ua, _("Enter file names with paths, or < to enter a filename\n"
                         "containg a list of file names with paths, and terminate\n"
                         "them with a blank line.\n"));
-        for ( ;; ) {
+         for ( ;; ) {
             if (!get_cmd(ua, _("Enter full filename: "))) {
-              return 0;
-           }
-           len = strlen(ua->cmd);
-           if (len == 0) {
-              break;
-           }
-           insert_one_file_or_dir(ua, rx, date, false);
-        }
-        /* Check MediaType and select storage that corresponds */
-        if (rx->name_list.num_ids) {
-           get_storage_from_mediatype(ua, &rx->name_list, rx);
-        }
-        return 2;
-
-      case 8:                        /* Find JobIds for current backup */
-        bstrutime(date, sizeof(date), time(NULL));
-        if (!select_backups_before_date(ua, rx, date)) {
-           return 0;
-        }
-        done = false;
-        break;
-
-      case 9:                        /* Find JobIds for give date */
-        if (!get_date(ua, date, sizeof(date))) {
-           return 0;
-        }
-        if (!select_backups_before_date(ua, rx, date)) {
-           return 0;
-        }
-        done = false;
-        break;
-
-      case 10:                       /* Enter directories */
-        if (*rx->JobIds != 0) {
+               return 0;
+            }
+            len = strlen(ua->cmd);
+            if (len == 0) {
+               break;
+            }
+            insert_one_file_or_dir(ua, rx, date, false);
+         }
+         /* Check MediaType and select storage that corresponds */
+         if (rx->name_list.num_ids) {
+            get_storage_from_mediatype(ua, &rx->name_list, rx);
+         }
+         return 2;
+
+      case 8:                         /* Find JobIds for current backup */
+         bstrutime(date, sizeof(date), time(NULL));
+         if (!select_backups_before_date(ua, rx, date)) {
+            return 0;
+         }
+         done = false;
+         break;
+
+      case 9:                         /* Find JobIds for give date */
+         if (!get_date(ua, date, sizeof(date))) {
+            return 0;
+         }
+         if (!select_backups_before_date(ua, rx, date)) {
+            return 0;
+         }
+         done = false;
+         break;
+
+      case 10:                        /* Enter directories */
+         if (*rx->JobIds != 0) {
             bsendmsg(ua, _("You have already seleted the following JobIds: %s\n"),
-              rx->JobIds);
+               rx->JobIds);
          } else if (get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
-           if (*rx->JobIds != 0 && *ua->cmd) {
+            if (*rx->JobIds != 0 && *ua->cmd) {
                pm_strcat(rx->JobIds, ",");
-           }
-           pm_strcat(rx->JobIds, ua->cmd);
-        }
+            }
+            pm_strcat(rx->JobIds, ua->cmd);
+         }
          if (*rx->JobIds == 0 || *rx->JobIds == '.') {
-           return 0;                 /* nothing entered, return */
-        }
-        bstrutime(date, sizeof(date), time(NULL));
-        if (!get_client_name(ua, rx)) {
-           return 0;
-        }
-         bsendmsg(ua, _("Enter directory names with a trailing /, or < to enter a filename\n"
-                        "containg a list of directories and terminate\n"
-                        "them with a blank line.\n"));
-        for ( ;; ) {
+            return 0;                 /* nothing entered, return */
+         }
+         bstrutime(date, sizeof(date), time(NULL));
+         if (!get_client_name(ua, rx)) {
+            return 0;
+         }
+         bsendmsg(ua, _("Enter full directory names or start the name\n"
+                        "with a < to indicate it is a filename containg a list\n"
+                        "of directories and terminate them with a blank line.\n"));
+         for ( ;; ) {
             if (!get_cmd(ua, _("Enter directory name: "))) {
-              return 0;
-           }
-           len = strlen(ua->cmd);
-           if (len == 0) {
-              break;
-           }
-            if (ua->cmd[len-1] != '/') {
+               return 0;
+            }
+            len = strlen(ua->cmd);
+            if (len == 0) {
+               break;
+            }
+            /* Add trailing slash to end of directory names */
+            if (ua->cmd[0] != '<' && ua->cmd[len-1] != '/') {
                strcat(ua->cmd, "/");
-           }
-           insert_one_file_or_dir(ua, rx, date, true);
-        }
-        /* Check MediaType and select storage that corresponds */
-        if (rx->name_list.num_ids) {
-           get_storage_from_mediatype(ua, &rx->name_list, rx);
-        }
-        return 2;
-
-      case 11:                       /* Cancel or quit */
-        return 0;
+            }
+            insert_one_file_or_dir(ua, rx, date, true);
+         }
+         /* Check MediaType and select storage that corresponds */
+         if (rx->name_list.num_ids) {
+            get_storage_from_mediatype(ua, &rx->name_list, rx);
+         }
+         return 2;
+
+      case 11:                        /* Cancel or quit */
+         return 0;
       }
    }
 
@@ -620,25 +621,25 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       int stat = get_next_jobid_from_list(&p, &JobId);
       if (stat < 0) {
          bsendmsg(ua, _("Invalid JobId in list.\n"));
-        return 0;
+         return 0;
       }
       if (stat == 0) {
-        break;
+         break;
       }
       if (jr.JobId == JobId) {
-        continue;                    /* duplicate of last JobId */
+         continue;                    /* duplicate of last JobId */
       }
       jr.JobId = JobId;
       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
-        char ed1[50];
+         char ed1[50];
          bsendmsg(ua, _("Unable to get Job record for JobId=%s: ERR=%s\n"),
-           edit_int64(JobId, ed1), db_strerror(ua->db));
-        return 0;
+            edit_int64(JobId, ed1), db_strerror(ua->db));
+         return 0;
       }
       if (!acl_access_ok(ua, Job_ACL, jr.Name)) {
          bsendmsg(ua, _("No authorization. Job \"%s\" not selected.\n"),
-           jr.Name);
-        continue;
+            jr.Name);
+         continue;
       }
       rx->TotalFiles += jr.JobFiles;
    }
@@ -654,10 +655,10 @@ static int get_date(UAContext *ua, char *date, int date_len)
                   "BEFORE the date you specify below.\n\n"));
    for ( ;; ) {
       if (!get_cmd(ua, _("Enter date as YYYY-MM-DD HH:MM:SS :"))) {
-        return 0;
+         return 0;
       }
       if (str_to_utime(ua->cmd) != 0) {
-        break;
+         break;
       }
       bsendmsg(ua, _("Improper date format.\n"));
    }
@@ -679,30 +680,30 @@ static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, b
    case '<':
       p++;
       if ((ffd = fopen(p, "r")) == NULL) {
-        berrno be;
+         berrno be;
          bsendmsg(ua, _("Cannot open file %s: ERR=%s\n"),
-           p, be.strerror());
-        break;
+            p, be.strerror());
+         break;
       }
       while (fgets(file, sizeof(file), ffd)) {
-        line++;
-        if (dir) {
-           if (!insert_dir_into_findex_list(ua, rx, file, date)) {
+         line++;
+         if (dir) {
+            if (!insert_dir_into_findex_list(ua, rx, file, date)) {
                bsendmsg(ua, _("Error occurred on line %d of %s\n"), line, p);
-           }
-        } else {
-           if (!insert_file_into_findex_list(ua, rx, file, date)) {
+            }
+         } else {
+            if (!insert_file_into_findex_list(ua, rx, file, date)) {
                bsendmsg(ua, _("Error occurred on line %d of %s\n"), line, p);
-           }
-        }
+            }
+         }
       }
       fclose(ffd);
       break;
    default:
       if (dir) {
-        insert_dir_into_findex_list(ua, rx, ua->cmd, date);
+         insert_dir_into_findex_list(ua, rx, ua->cmd, date);
       } else {
-        insert_file_into_findex_list(ua, rx, ua->cmd, date);
+         insert_file_into_findex_list(ua, rx, ua->cmd, date);
       }
       break;
    }
@@ -714,7 +715,7 @@ static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, b
  *   and FileIndex, then insert them into the findex list.
  */
 static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file,
-                                       char *date)
+                                        char *date)
 {
    char ed1[50];
 
@@ -722,16 +723,16 @@ static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *f
    split_path_and_filename(rx, file);
    if (*rx->JobIds == 0) {
       Mmsg(rx->query, uar_jobid_fileindex, date, rx->path, rx->fname, 
-          rx->ClientName);
+           rx->ClientName);
    } else {
       Mmsg(rx->query, uar_jobids_fileindex, rx->JobIds, date,
-          rx->path, rx->fname, rx->ClientName);
+           rx->path, rx->fname, rx->ClientName);
    }
    rx->found = false;
    /* Find and insert jobid and File Index */
    if (!db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx)) {
       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"),
-        rx->query, db_strerror(ua->db));
+         rx->query, db_strerror(ua->db));
    }
    if (!rx->found) {
       bsendmsg(ua, _("No database record found for: %s\n"), file);
@@ -753,7 +754,7 @@ static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *f
  * to get the JobId and FileIndexes of all files in that directory.
  */
 static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *dir,
-                                       char *date)
+                                        char *date)
 {
    char ed1[50];
 
@@ -763,13 +764,13 @@ static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *di
       return false;
    } else {
       Mmsg(rx->query, uar_jobid_fileindex_from_dir, rx->JobIds, 
-          dir, rx->ClientName);
+           dir, rx->ClientName);
    }
    rx->found = false;
    /* Find and insert jobid and File Index */
    if (!db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx)) {
       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"),
-        rx->query, db_strerror(ua->db));
+         rx->query, db_strerror(ua->db));
    }
    if (!rx->found) {
       bsendmsg(ua, _("No database record found for: %s\n"), dir);
@@ -799,12 +800,12 @@ static void split_path_and_filename(RESTORE_CTX *rx, char *name)
     */
    for (p=f=name; *p; p++) {
       if (*p == '/') {
-        f = p;                       /* set pos of last slash */
+         f = p;                       /* set pos of last slash */
       }
    }
    if (*f == '/') {                   /* did we find a slash? */
-      f++;                           /* yes, point to filename */
-   } else {                          /* no, whole thing must be path name */
+      f++;                            /* yes, point to filename */
+   } else {                           /* no, whole thing must be path name */
       f = p;
    }
 
@@ -816,7 +817,7 @@ static void split_path_and_filename(RESTORE_CTX *rx, char *name)
    rx->fnl = p - f;
    if (rx->fnl > 0) {
       rx->fname = check_pool_memory_size(rx->fname, rx->fnl+1);
-      memcpy(rx->fname, f, rx->fnl);   /* copy filename */
+      memcpy(rx->fname, f, rx->fnl);    /* copy filename */
       rx->fname[rx->fnl] = 0;
    } else {
       rx->fname[0] = 0;
@@ -866,20 +867,20 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
          bsendmsg(ua, "%s\n", db_strerror(ua->db));
       }
       if (rx->found) {
-        /* Add about 25% more than this job for over estimate */
-        tree.FileEstimate = rx->JobId + (rx->JobId >> 2);
-        tree.DeltaCount = rx->JobId/50; /* print 50 ticks */
+         /* Add about 25% more than this job for over estimate */
+         tree.FileEstimate = rx->JobId + (rx->JobId >> 2);
+         tree.DeltaCount = rx->JobId/50; /* print 50 ticks */
       }
    }
    for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
       char ed1[50];
 
       if (JobId == last_JobId) {
-        continue;                    /* eliminate duplicate JobIds */
+         continue;                    /* eliminate duplicate JobIds */
       }
       last_JobId = JobId;
       bsendmsg(ua, _("\nBuilding directory tree for JobId %s ...  "), 
-        edit_int64(JobId, ed1));
+         edit_int64(JobId, ed1));
       items++;
       /*
        * Find files for this JobId and insert them in the tree
@@ -900,16 +901,16 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
       bsendmsg(ua, "\nThere were no files inserted into the tree, so file selection\n"
          "is not possible.Most likely your retention policy pruned the files\n");
       if (!get_yesno(ua, _("\nDo you want to restore all the files? (yes|no): "))) {
-        OK = false;
+         OK = false;
       } else {
-        last_JobId = 0;
-        for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
-            if (JobId == last_JobId) {
-               continue;                    /* eliminate duplicate JobIds */
-            }
-            add_findex_all(rx->bsr, JobId);
-         }
-         OK = true;
+         last_JobId = 0;
+         for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
+             if (JobId == last_JobId) {
+                continue;                    /* eliminate duplicate JobIds */
+             }
+             add_findex_all(rx->bsr, JobId);
+          }
+          OK = true;
       }
    } else {
       char ec1[50];
@@ -921,8 +922,8 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
       get_storage_from_mediatype(ua, &rx->name_list, rx);
 
       if (find_arg(ua, _("done")) < 0) {
-        /* Let the user interact in selecting which files to restore */
-        OK = user_select_files_from_tree(&tree);
+         /* Let the user interact in selecting which files to restore */
+         OK = user_select_files_from_tree(&tree);
       }
 
       /*
@@ -930,20 +931,20 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
        *  extracted making a bootstrap file.
        */
       if (OK) {
-        for (TREE_NODE *node=first_tree_node(tree.root); node; node=next_tree_node(node)) {
+         for (TREE_NODE *node=first_tree_node(tree.root); node; node=next_tree_node(node)) {
             Dmsg2(400, "FI=%d node=0x%x\n", node->FileIndex, node);
-           if (node->extract || node->extract_dir) {
+            if (node->extract || node->extract_dir) {
                Dmsg2(400, "type=%d FI=%d\n", node->type, node->FileIndex);
-              add_findex(rx->bsr, node->JobId, node->FileIndex);
-              if (node->extract && node->type != TN_NEWDIR) {
-                 rx->selected_files++;  /* count only saved files */
-              }
-           }
-        }
+               add_findex(rx->bsr, node->JobId, node->FileIndex);
+               if (node->extract && node->type != TN_NEWDIR) {
+                  rx->selected_files++;  /* count only saved files */
+               }
+            }
+         }
       }
    }
 
-   free_tree(tree.root);             /* free the directory tree */
+   free_tree(tree.root);              /* free the directory tree */
    return OK;
 }
 
@@ -990,11 +991,11 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
       bstrncpy(fsr.FileSet, ua->argv[i], sizeof(fsr.FileSet));
       if (!db_get_fileset_record(ua->jcr, ua->db, &fsr)) {
          bsendmsg(ua, _("Error getting FileSet \"%s\": ERR=%s\n"), fsr.FileSet,
-           db_strerror(ua->db));
-        i = -1;
+            db_strerror(ua->db));
+         i = -1;
       }
    }
-   if (i < 0) {                      /* fileset not found */
+   if (i < 0) {                       /* fileset not found */
       edit_int64(cr.ClientId, ed1);
       Mmsg(rx->query, uar_sel_fileset, ed1, ed1);
       start_prompt(ua, _("The defined FileSet resources are:\n"));
@@ -1002,8 +1003,8 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
          bsendmsg(ua, "%s\n", db_strerror(ua->db));
       }
       if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"),
-                fileset_name, sizeof(fileset_name)) < 0) {
-        goto bail_out;
+                 fileset_name, sizeof(fileset_name)) < 0) {
+         goto bail_out;
       }
 
       bstrncpy(fsr.FileSet, fileset_name, sizeof(fsr.FileSet));
@@ -1022,7 +1023,7 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
       bstrncpy(pr.Name, rx->pool->hdr.name, sizeof(pr.Name));
       if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
          bsnprintf(pool_select, sizeof(pool_select), "AND Media.PoolId=%s ", 
-           edit_int64(pr.PoolId, ed1));
+            edit_int64(pr.PoolId, ed1));
       } else {
          bsendmsg(ua, _("Pool \"%s\" not found, using any pool.\n"), pr.Name);
       }
@@ -1031,7 +1032,7 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    /* Find JobId of last Full backup for this client, fileset */
    edit_int64(cr.ClientId, ed1);
    Mmsg(rx->query, uar_last_full, ed1, ed1, date, fsr.FileSet,
-        pool_select);
+         pool_select);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
       goto bail_out;
@@ -1056,7 +1057,7 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find most recent Differental Job after Full save, if any */
    Mmsg(rx->query, uar_dif, edit_uint64(rx->JobTDate, ed1), date,
-       edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
    }
@@ -1072,7 +1073,7 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find all Incremental Jobs after Full/dif save */
    Mmsg(rx->query, uar_inc, edit_uint64(rx->JobTDate, ed1), date,
-       edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
    }
@@ -1108,10 +1109,10 @@ static int get_next_jobid_from_list(char **p, uint32_t *JobId)
    jobid[0] = 0;
    for (int i=0; i<(int)sizeof(jobid); i++) {
       if (*q == 0) {
-        break;
+         break;
       } else if (*q == ',') {
-        q++;
-        break;
+         q++;
+         break;
       }
       jobid[i] = *q++;
       jobid[i+1] = 0;
@@ -1119,7 +1120,7 @@ static int get_next_jobid_from_list(char **p, uint32_t *JobId)
    if (jobid[0] == 0) {
       return 0;
    } else if (!is_a_number(jobid)) {
-      return -1;                     /* error */
+      return -1;                      /* error */
    }
    *p = q;
    *JobId = str_to_int64(jobid);
@@ -1156,7 +1157,7 @@ static int jobid_handler(void *ctx, int num_fields, char **row)
    RESTORE_CTX *rx = (RESTORE_CTX *)ctx;
 
    if (strcmp(rx->last_jobid, row[0]) == 0) {
-      return 0;                      /* duplicate id */
+      return 0;                       /* duplicate id */
    }
    bstrncpy(rx->last_jobid, row[0], sizeof(rx->last_jobid));
    if (rx->JobIds[0] != 0) {
@@ -1205,16 +1206,16 @@ static int unique_name_list_handler(void *ctx, int num_fields, char **row)
    }
    if (name->num_ids == name->max_ids) {
       if (name->max_ids == 0) {
-        name->max_ids = 1000;
-        name->name = (char **)bmalloc(sizeof(char *) * name->max_ids);
+         name->max_ids = 1000;
+         name->name = (char **)bmalloc(sizeof(char *) * name->max_ids);
       } else {
-        name->max_ids = (name->max_ids * 3) / 2;
-        name->name = (char **)brealloc(name->name, sizeof(char *) * name->max_ids);
+         name->max_ids = (name->max_ids * 3) / 2;
+         name->name = (char **)brealloc(name->name, sizeof(char *) * name->max_ids);
       }
    }
    for (int i=0; i<name->num_ids; i++) {
       if (strcmp(name->name[i], row[0]) == 0) {
-        return 0;                    /* already in list, return */
+         return 0;                    /* already in list, return */
       }
    }
    /* Add new name to list */
@@ -1276,10 +1277,10 @@ static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, REST
    LockRes();
    foreach_res(store, R_STORAGE) {
       if (strcmp(name_list->name[0], store->media_type) == 0) {
-        if (acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
-           rx->store = store;
-        }
-        break;
+         if (acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
+            rx->store = store;
+         }
+         break;
       }
    }
    UnlockRes();
@@ -1289,15 +1290,15 @@ static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, REST
       store = NULL;
       int i = find_arg_with_value(ua, "storage");
       if (i > 0) {
-        store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
-        if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
-           store = NULL;
-        }
+         store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
+         if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
+            store = NULL;
+         }
       }
       if (store && (store != rx->store)) {
          bsendmsg(ua, _("Warning default storage overridden by %s on command line.\n"),
-           store->hdr.name);
-        rx->store = store;
+            store->hdr.name);
+         rx->store = store;
       }
       return;
    }
@@ -1309,6 +1310,6 @@ static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, REST
       bsendmsg(ua, _("\nWarning. Unable to find Storage resource for\n"
          "MediaType \"%s\", needed by the Jobs you selected.\n"
          "You will be allowed to select a Storage device later.\n"),
-        name_list->name[0]);
+         name_list->name[0]);
    }
 }
index 93e2bc45431d2ad98ce76b7bed04acdf32cafcae..cb80c769eaf5fc3a260faf58da360a0922863cee 100644 (file)
@@ -61,30 +61,31 @@ extern "C" void *sd_heartbeat_thread(void *arg)
    jcr->hb_dir_bsock = dir;
 
    /* Hang reading the socket to the SD, and every time we get
-    *  a heartbeat or we get a wait timeout (1 minute), we
-    *  check to see if we need to send a heartbeat to the
-    *  Director.
+    *   a heartbeat or we get a wait timeout (1 minute), we
+    *   check to see if we need to send a heartbeat to the
+    *   Director.
     */
    for ( ; !is_bnet_stop(sd); ) {
       n = bnet_wait_data_intr(sd, WAIT_INTERVAL);
       if (me->heartbeat_interval) {
-        now = time(NULL);
-        if (now-last_heartbeat >= me->heartbeat_interval) {
-           bnet_sig(dir, BNET_HEARTBEAT);
-           last_heartbeat = now;
-        }
+         now = time(NULL);
+         if (now-last_heartbeat >= me->heartbeat_interval) {
+            bnet_sig(dir, BNET_HEARTBEAT);
+            last_heartbeat = now;
+         }
       }
       if (is_bnet_stop(sd)) {
-        break;
+         break;
       }
-      if (n == 1) {                  /* input waiting */
-        bnet_recv(sd);               /* read it -- probably heartbeat from sd */
-        if (sd->msglen <= 0) {
+      if (n == 1) {                   /* input waiting */
+         bnet_recv(sd);               /* read it -- probably heartbeat from sd */
+         if (sd->msglen <= 0) {
             Dmsg1(100, "Got BNET_SIG %d from SD\n", sd->msglen);
-        } else {
+         } else {
             Dmsg2(100, "Got %d bytes from SD. MSG=%s\n", sd->msglen, sd->msg);
-        }
+         }
       }
+      Dmsg2(000, "wait_intr=%d stop=%d\n", n, is_bnet_stop(sd));
    }
    bnet_close(sd);
    bnet_close(dir);
@@ -117,7 +118,7 @@ void stop_heartbeat_monitor(JCR *jcr)
    }
    /* Wait max 10 secs for heartbeat thread to start */
    while (jcr->hb_bsock == NULL && cnt++ < 200) {
-      bmicrosleep(0, 50000);        /* wait for start */
+      bmicrosleep(0, 50000);         /* wait for start */
    }
    if (!jcr->hb_bsock) {
    }
@@ -135,7 +136,7 @@ void stop_heartbeat_monitor(JCR *jcr)
    cnt = 0;
    /* Wait max 100 secs for heartbeat thread to stop */
    while (jcr->hb_bsock && cnt++ < 200) {
-      pthread_kill(jcr->heartbeat_id, TIMEOUT_SIGNAL); /* make heartbeat thread go away */
+      pthread_kill(jcr->heartbeat_id, TIMEOUT_SIGNAL);  /* make heartbeat thread go away */
       bmicrosleep(0, 500000);
    }
    if (jcr->hb_bsock) {
@@ -166,8 +167,8 @@ extern "C" void *dir_heartbeat_thread(void *arg)
       now = time(NULL);
       next = now - last_heartbeat;
       if (next >= me->heartbeat_interval) {
-        bnet_sig(dir, BNET_HEARTBEAT);
-        last_heartbeat = now;
+         bnet_sig(dir, BNET_HEARTBEAT);
+         last_heartbeat = now;
       }
       bmicrosleep(next, 0);
    }
index 195857477091129e07016edd89f182b95be930d4..b495f9f70b7f2de392759d208ec793802d84f1a1 100644 (file)
@@ -89,6 +89,7 @@ static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
 static void open_tape_device(DCR *dcr, int mode);
 static void open_file_device(DCR *dcr, int mode);
 static void open_dvd_device(DCR *dcr, int mode);
+static char *mode_to_str(int mode);
 
 /*
  * Allocate and initialize the DEVICE structure
@@ -275,17 +276,17 @@ DEVICE::open(DCR *dcr, int mode)
    }
   bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
 
-   Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%d\n", is_tape(),
-         dev_name, VolCatInfo.VolCatName, mode);
+   Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%s\n", is_tape(),
+         dev_name, VolCatInfo.VolCatName, mode_to_str(mode));
    state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
    label_type = B_BACULA_LABEL;
    if (is_tape() || is_fifo()) {
       open_tape_device(dcr, mode);
    } else if (is_dvd()) {
-      Dmsg1(100, "call open_dvd_device mode=%d\n", mode);
+      Dmsg1(100, "call open_dvd_device mode=%s\n", mode_to_str(mode));
       open_dvd_device(dcr, mode);
    } else {
-      Dmsg1(100, "call open_file_device mode=%d\n", mode);
+      Dmsg1(100, "call open_file_device mode=%d\n", mode_to_str(mode));
       open_file_device(dcr, mode);
    }
    return fd;
@@ -404,8 +405,8 @@ static void open_file_device(DCR *dcr, int mode)
    /*
     * Handle opening of File Archive (not a tape)
     */     
-   Dmsg3(29, "Enter: open_file_dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
-         archive_name.c_str(), mode);
+   Dmsg3(29, "Enter: open_file_dev: %s dev=%s mode=%s\n", dev->is_dvd()?"DVD":"disk",
+         archive_name.c_str(), mode_to_str(mode));
 
    if (dev->VolCatInfo.VolCatName[0] == 0) {
       Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"),
@@ -420,13 +421,14 @@ static void open_file_device(DCR *dcr, int mode)
    }
    pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
          
-   Dmsg3(29, "open dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
-         archive_name.c_str(), mode);
+   Dmsg3(29, "open dev: %s dev=%s mode=%s\n", dev->is_dvd()?"DVD":"disk",
+         archive_name.c_str(), mode_to_str(mode));
    dev->openmode = mode;
    
    dev->set_mode(mode);
    /* If creating file, give 0640 permissions */
-   Dmsg3(29, "mode=%d open(%s, 0x%x, 0640)\n", mode, archive_name.c_str(), dev->mode);
+   Dmsg3(29, "mode=%s open(%s, 0x%x, 0640)\n", mode, archive_name.c_str(), 
+         mode_to_str(dev->mode));
    if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) {
       berrno be;
       dev->dev_errno = errno;
@@ -459,8 +461,8 @@ static void open_dvd_device(DCR *dcr, int mode)
    /*
     * Handle opening of DVD Volume
     */     
-   Dmsg3(29, "Enter: open_file_dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
-         archive_name.c_str(), mode);
+   Dmsg3(29, "Enter: open_dvd_dev: %s dev=%s mode=%s\n", dev->is_dvd()?"DVD":"disk",
+         archive_name.c_str(), mode_to_str(mode));
 
    if (dev->VolCatInfo.VolCatName[0] == 0) {
       Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"),
@@ -483,8 +485,8 @@ static void open_dvd_device(DCR *dcr, int mode)
       return;
    }
          
-   Dmsg3(29, "open dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
-         archive_name.c_str(), mode);
+   Dmsg3(29, "open dev: %s dev=%s mode=%s\n", dev->is_dvd()?"DVD":"disk",
+         archive_name.c_str(), mode_to_str(mode));
    dev->openmode = mode;
    
    /*
@@ -496,7 +498,6 @@ static void open_dvd_device(DCR *dcr, int mode)
    }
    dev->set_mode(mode);
 
-   Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
    /* 
     * If we are opening it read-only, it is *probably* on the
     *   DVD, so try the DVD first, otherwise look in the spool dir.
@@ -508,7 +509,8 @@ static void open_dvd_device(DCR *dcr, int mode)
    }
 
    /* If creating file, give 0640 permissions */
-   Dmsg3(29, "mode=%d open(%s, 0x%x, 0640)\n", mode, archive_name.c_str(), dev->mode);
+   Dmsg3(29, "mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(mode), 
+         archive_name.c_str(), dev->mode);
    if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) {
       berrno be;
       dev->dev_errno = errno;
@@ -1877,3 +1879,16 @@ static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
           ioctl(dev->fd, MTIOCGET, (char *)mt_stat) == 0 &&
           mt_stat->mt_fileno >= 0;
 }
+
+static char *modes[] = {
+   "CREATE_READ_WRITE",
+   "OPEN_READ_WRITE",
+   "OPEN_READ_ONLY",
+   "OPEN_WRITE_ONLY"
+};
+
+
+static char *mode_to_str(int mode)  
+{
+   return modes[mode-1];
+}
index c60cb5f87818654836227d562f5bad36525118f1..7cda72f7d5b43328bfba7ccb0b8ad3a9627e84c2 100644 (file)
@@ -28,7 +28,6 @@
 /* Forward referenced functions */
 static char *edit_device_codes_dev(DEVICE *dev, char *omsg, const char *imsg);
 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
-static bool dvd_write_part(DEVICE *dev);
 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
 
 /* 
@@ -131,6 +130,7 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
    /* If busy retry each second */
    while ((status = run_program_full_output(ocmd.c_str(), 
                        dev->max_open_wait/2, results)) != 0) {
+      Dmsg1(100, "results len=%d\n", strlen(results));
       if (fnmatch("*is already mounted on", results, 0) == 0) {
          break;
       }
@@ -147,6 +147,45 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
       Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
       Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n", 
            dev->print_name(), results);
+#ifdef xxx
+      /*
+       * Now, just to be sure it is not mounted, try to read the
+       *  filesystem.
+       */
+      DIR* dp;
+      struct dirent *entry, *result;
+      int name_max;
+      int count = 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_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
+         goto get_out;
+      }
+      
+      entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+      while (1) {
+         if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+            dev->dev_errno = ENOENT;
+            Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
+            break;
+         }
+         count++;
+      }
+      free(entry);
+      closedir(dp);
+      if (count > 2) {
+         mount = 1;                      /* If we got more than . and .. */
+         break;                          /*   there must be something mounted */
+      }
+get_out:
+#endif
       free_pool_memory(results);
       return false;
    }
@@ -188,6 +227,7 @@ void update_free_space_dev(DEVICE* dev)
    
    while (1) {
       if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
+         Dmsg1(100, "results len=%d\n", strlen(results));
          Dmsg1(100, "Free space program run : %s\n", results);
          free = str_to_int64(results);
          if (free >= 0) {
@@ -225,9 +265,13 @@ void update_free_space_dev(DEVICE* dev)
    return;
 }
 
-static bool dvd_write_part(DEVICE *dev) 
+/*
+ * Write a part (Vol, Vol.1, ...) from the spool to the DVD   
+ */
+static bool dvd_write_part(DCR *dcr) 
 {
-   Dmsg1(29, "dvd_write_part: device is %s\n", dev->dev_name);
+   DEVICE *dev = dcr->dev;
+   Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name());
    
    if (unmount_dev(dev, 1) < 0) {
       Dmsg0(29, "dvd_write_part: unable to unmount the device\n");
@@ -238,12 +282,25 @@ static bool dvd_write_part(DEVICE *dev)
    char* icmd;
    int status;
    int timeout;
+   int part;
+   char ed1[50];
    
    results = get_pool_memory(PM_MESSAGE);
    results[0] = 0;
    icmd = dev->device->write_part_command;
    
+   /* 
+    * Note! part is used to control whether or not we create a
+    *   new filesystem. If the device could be mounted, it is because
+    *   it already has a filesystem, so we artificially set part=1
+    *   to avoid zapping an existing filesystem.
+    */
+   part = dev->part;
+   if (dev->is_mounted() && dev->part == 0) {
+      dev->part = 1;      /* do not wipe out existing filesystem */
+   }
    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
+   dev->part = part;
       
    /* Wait at most the time a maximum size part is written in DVD 0.5x speed
     * FIXME: Minimum speed should be in device configuration 
@@ -253,6 +310,7 @@ static bool dvd_write_part(DEVICE *dev)
    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
       
    status = run_program_full_output(ocmd.c_str(), timeout, results);
+   Dmsg1(100, "results len=%d\n", strlen(results));
    if (status != 0) {
       Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", 
             results);
@@ -266,7 +324,11 @@ static bool dvd_write_part(DEVICE *dev)
    /* Delete spool file */
    make_spooled_dvd_filename(dev, archive_name);
    unlink(archive_name.c_str());
+   Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
    free_pool_memory(results);
+   update_free_space_dev(dev);
+   Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
+      edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
    return true;
 }
 
@@ -301,7 +363,7 @@ int open_next_part(DCR *dcr)
     *  DVD before opening the next part.
     */
    if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) {
-      if (!dvd_write_part(dev)) {
+      if (!dvd_write_part(dcr)) {
          return -1;
       }
    }
@@ -356,6 +418,9 @@ int open_next_part(DCR *dcr)
 /* Open the first part file.
  *  - Close the fd
  *  - Reopen the device
+ *
+ *   I don't see why this is necessary unless the current
+ *   part is not zero.
  */
 int open_first_part(DCR *dcr, int mode)
 {
@@ -500,14 +565,16 @@ bool dvd_close_job(DCR *dcr)
          ok = false;
       }
       
-      if (ok && (open_next_part(dcr) < 0)) {
-         Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"),
+      /* This should be !dvd_write_part(dcr) */
+      if (ok && open_next_part(dcr) < 0) {
+//    if (ok && !dvd_write_part(dcr)) {
+         Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
                dev->print_name(), strerror_dev(dev));
          dev->dev_errno = EIO;
          ok = false;
       }
-      dev->VolCatInfo.VolCatParts = dev->num_parts;
    }
+   dev->VolCatInfo.VolCatParts = dev->num_parts;
    return ok;
 }
 
index c1659c10843925dbfe2c7b85b93aa5656f86fa0c..0aee6f7f73a9aef0bd178dc2f30516a9afafba63 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #undef  VERSION
 #define VERSION "1.37.28"
-#define BDATE   "30 June 2005"
-#define LSMDATE "30Jun05"
+#define BDATE   "02 July 2005"
+#define LSMDATE "02Jul05"
 
 /* Debug flags */
 #undef  DEBUG