]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_label.c
kes Add job report indication of whether or not VSS and Encryption were
[bacula/bacula] / bacula / src / dird / ua_label.c
index 3dfa52094de7b9142e23fbf5d15c7a9901ee1da7..fbd26f8e0ba82e227151b713ed3991c1553b6229 100644 (file)
@@ -6,26 +6,33 @@
  *
  *   Version $Id$
  */
-
 /*
-   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2003-2006 Free Software Foundation Europe e.V.
 
-   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.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
 
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   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.
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
- */
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 
 #include "bacula.h"
 #include "dird.h"
@@ -39,113 +46,111 @@ typedef struct s_vol_list {
 
 
 /* Forward referenced functions */
-static int do_label(UAContext *ua, char *cmd, int relabel);
-static void label_from_barcodes(UAContext *ua);
-static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
-              POOL_DBR *pr, int relabel, bool media_record_exits);
+static int do_label(UAContext *ua, const char *cmd, int relabel);
+static void label_from_barcodes(UAContext *ua, int drive);
+static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
+               POOL_DBR *pr, int relabel, bool media_record_exits, int drive);
 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
 static void free_vol_list(vol_list_t *vol_list);
-static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
+static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
 static BSOCK *open_sd_bsock(UAContext *ua);
 static void close_sd_bsock(UAContext *ua);
-static char *get_volume_name_from_SD(UAContext *ua, int Slot);
+static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive);
+static int get_num_slots_from_SD(UAContext *ua);
 
 
 /*
- * Label a tape 
- *  
+ * Label a tape
+ *
  *   label storage=xxx volume=vvv
  */
-int label_cmd(UAContext *ua, char *cmd)
+int label_cmd(UAContext *ua, const char *cmd)
 {
    return do_label(ua, cmd, 0);       /* standard label */
 }
 
-int relabel_cmd(UAContext *ua, char *cmd)
+int relabel_cmd(UAContext *ua, const char *cmd)
 {
    return do_label(ua, cmd, 1);      /* relabel tape */
 }
 
-#define MAX_SLOTS 5000
-
 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
 {
    int i;
-   char *msg;
+   const char *msg;
 
-   for (int i=0; i<num_slots; i++) {
+   /* slots are numbered 1 to num_slots */
+   for (int i=0; i <= num_slots; i++) {
       slot_list[i] = 0;
    }
    i = find_arg_with_value(ua, "slots");
-   if (i >= 0) {
+   if (i > 0) {
       /* scan slot list in ua->argv[i] */
       char *p, *e, *h;
       int beg, end;
 
       strip_trailing_junk(ua->argv[i]);
       for (p=ua->argv[i]; p && *p; p=e) {
-        /* Check for list */
+         /* Check for list */
          e = strchr(p, ',');
-        if (e) {
-           *e++ = 0;
-        }
-        /* Check for range */
+         if (e) {
+            *e++ = 0;
+         }
+         /* Check for range */
          h = strchr(p, '-');             /* range? */
-        if (h == p) {
+         if (h == p) {
             msg = _("Negative numbers not permitted\n");
-           goto bail_out;
-        }
-        if (h) {
-           *h++ = 0;
-           if (!is_an_integer(h)) {
+            goto bail_out;
+         }
+         if (h) {
+            *h++ = 0;
+            if (!is_an_integer(h)) {
                msg = _("Range end is not integer.\n");
-              goto bail_out;
-           }
-           skip_spaces(&p);
-           if (!is_an_integer(p)) {
+               goto bail_out;
+            }
+            skip_spaces(&p);
+            if (!is_an_integer(p)) {
                msg = _("Range start is not an integer.\n");
-              goto bail_out;
-           }
-           beg = atoi(p);
-           end = atoi(h);
-           if (end < beg) {
+               goto bail_out;
+            }
+            beg = atoi(p);
+            end = atoi(h);
+            if (end < beg) {
                msg = _("Range end not bigger than start.\n");
-              goto bail_out;
-           }
-        } else {
-           skip_spaces(&p);
-           if (!is_an_integer(p)) {
+               goto bail_out;
+            }
+         } else {
+            skip_spaces(&p);
+            if (!is_an_integer(p)) {
                msg = _("Input value is not an integer.\n");
-              goto bail_out;
-           }
-           beg = end = atoi(p);
-        }
-        if (beg <= 0 || end <= 0) {
+               goto bail_out;
+            }
+            beg = end = atoi(p);
+         }
+         if (beg <= 0 || end <= 0) {
             msg = _("Values must be be greater than zero.\n");
-           goto bail_out;
-        }
-        if (end >= num_slots) {
+            goto bail_out;
+         }
+         if (end > num_slots) {
             msg = _("Slot too large.\n");
-           goto bail_out;
-        }
-        for (i=beg; i<=end; i++) {
-           slot_list[i] = 1;         /* Turn on specified range */
-        }
+            goto bail_out;
+         }
+         for (i=beg; i<=end; i++) {
+            slot_list[i] = 1;         /* Turn on specified range */
+         }
       }
-   } else { 
+   } else {
       /* Turn everything on */
-      for (i=0; i<num_slots; i++) {
-        slot_list[i] = 1;
+      for (i=1; i <= num_slots; i++) {
+         slot_list[i] = 1;
       }
    }
-#ifdef xxx_debug
-   printf("Slots turned on:\n");
-   for (i=1; i<num_slots; i++) {
+   Dmsg0(100, "Slots turned on:\n");
+   for (i=1; i <= num_slots; i++) {
       if (slot_list[i]) {
-         printf("%d\n", i); 
+         Dmsg1(100, "%d\n", i);
       }
    }
-#endif
    return true;
 
 bail_out:
@@ -153,31 +158,54 @@ bail_out:
 }
 
 /*
- * Update Slots corresponding to Volumes in autochanger 
+ * Update Slots corresponding to Volumes in autochanger
  */
-int update_slots(UAContext *ua)
+void update_slots(UAContext *ua)
 {
-   STORE *store;
+   USTORE store;
    vol_list_t *vl, *vol_list = NULL;
    MEDIA_DBR mr;
    char *slot_list;
-   bool scan;       
+   bool scan;
+   int max_slots;
+   int drive;
+   int Enabled = 1;
+   bool have_enabled;
+   int i;
+
 
    if (!open_db(ua)) {
-      return 1;
+      return;
    }
-   store = get_storage_resource(ua, 1);
-   if (!store) {
-      return 1;
+   store.store = get_storage_resource(ua, true/*arg is storage*/);
+   if (!store.store) {
+      return;
    }
-   ua->jcr->store = store;
+   pm_strcpy(store.store_source, _("command line"));
+   set_wstorage(ua->jcr, &store);
+   drive = get_storage_drive(ua, store.store);
 
-   scan = find_arg(ua, _("scan")) >= 0;
+   scan = find_arg(ua, NT_("scan")) >= 0;
+   if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
+      Enabled = get_enabled(ua, ua->argv[i]);
+      if (Enabled < 0) {
+         return;
+      }
+      have_enabled = true;
+   } else {
+      have_enabled = false;
+   }
 
-   slot_list = (char *)malloc(MAX_SLOTS);
-   if (!get_user_slot_list(ua, slot_list, MAX_SLOTS)) {
+   max_slots = get_num_slots_from_SD(ua);
+   Dmsg1(100, "max_slots=%d\n", max_slots);
+   if (max_slots <= 0) {
+      bsendmsg(ua, _("No slots in changer to scan.\n"));
+      return;
+   }
+   slot_list = (char *)malloc(max_slots+1);
+   if (!get_user_slot_list(ua, slot_list, max_slots)) {
       free(slot_list);
-      return 1;
+      return;
    }
 
    vol_list = get_vol_list_from_SD(ua, scan);
@@ -187,50 +215,86 @@ int update_slots(UAContext *ua)
       goto bail_out;
    }
 
+   /* First zap out any InChanger with StorageId=0 */
+   db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
+
    /* Walk through the list updating the media records */
    for (vl=vol_list; vl; vl=vl->next) {
+      if (vl->Slot > max_slots) {
+         bsendmsg(ua, _("Slot %d greater than max %d ignored.\n"),
+            vl->Slot, max_slots);
+         continue;
+      }
       /* Check if user wants us to look at this slot */
       if (!slot_list[vl->Slot]) {
-        continue;
+         Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
+         continue;
       }
       /* If scanning, we read the label rather than the barcode */
       if (scan) {
-        if (vl->VolName) {
-           free(vl->VolName);
-           vl->VolName = NULL;
-        }
-        vl->VolName = get_volume_name_from_SD(ua, vl->Slot);
-      }
+         if (vl->VolName) {
+            free(vl->VolName);
+            vl->VolName = NULL;
+         }
+         vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
+         Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
+      }
+      slot_list[vl->Slot] = 0;        /* clear Slot */
+      memset(&mr, 0, sizeof(mr));
+      mr.Slot = vl->Slot;
+      mr.InChanger = 1;
+      mr.StorageId = store.store->StorageId;
+      /* Set InChanger to zero for this Slot */
+      db_lock(ua->db);
+      db_make_inchanger_unique(ua->jcr, ua->db, &mr);
+      db_unlock(ua->db);
       if (!vl->VolName) {
-        continue;
+         Dmsg1(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
+         bsendmsg(ua, _("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
+         continue;
       }
       memset(&mr, 0, sizeof(mr));
       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
       db_lock(ua->db);
       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
-         if (mr.Slot != vl->Slot || !mr.InChanger) {
-            mr.Slot = vl->Slot;
-            mr.InChanger = 1;
-            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
-                bsendmsg(ua, _("%s\n"), db_strerror(ua->db));
-            } else {
-               bsendmsg(ua, _(
-                  "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
-                 mr.VolumeName, mr.Slot);
-            }
-         } else {
-             bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
-               mr.VolumeName);
-         }   
-         db_unlock(ua->db);
-         continue;
+         if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
+            mr.Slot = vl->Slot;
+            mr.InChanger = 1;
+            mr.StorageId = store.store->StorageId;
+            if (have_enabled) {
+               mr.Enabled = Enabled;
+            }
+            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+               bsendmsg(ua, "%s", db_strerror(ua->db));
+            } else {
+               bsendmsg(ua, _(
+                 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
+                 mr.VolumeName, mr.Slot);
+            }
+         } else {
+            bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
+               mr.VolumeName);
+         }
+         db_unlock(ua->db);
+         continue;
       } else {
-          bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"), 
-            mr.VolumeName);
+         bsendmsg(ua, _("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
+             mr.VolumeName, vl->Slot);
       }
       db_unlock(ua->db);
    }
-
+   memset(&mr, 0, sizeof(mr));
+   mr.InChanger = 1;
+   mr.StorageId = store.store->StorageId;
+   db_lock(ua->db);
+   for (int i=1; i <= max_slots; i++) {
+      if (slot_list[i]) {
+         mr.Slot = i;
+         /* Set InChanger to zero for this Slot */
+         db_make_inchanger_unique(ua->jcr, ua->db, &mr);
+      }
+   }
+   db_unlock(ua->db);
 
 bail_out:
 
@@ -238,25 +302,27 @@ bail_out:
    free(slot_list);
    close_sd_bsock(ua);
 
-   return 1;
+   return;
 }
 
 
 /*
  * Common routine for both label and relabel
  */
-static int do_label(UAContext *ua, char *cmd, int relabel)
+static int do_label(UAContext *ua, const char *cmd, int relabel)
 {
-   STORE *store;
+   USTORE store;
    BSOCK *sd;
    char dev_name[MAX_NAME_LENGTH];
    MEDIA_DBR mr, omr;
    POOL_DBR pr;
    bool print_reminder = true;
+   bool label_barcodes = false;
    int ok = FALSE;
-   int i;
+   int i, j;
+   int drive;
    bool media_record_exists = false;
-   static char *barcode_keyword[] = {
+   static const char *barcode_keyword[] = {
       "barcode",
       "barcodes",
       NULL};
@@ -266,47 +332,59 @@ static int do_label(UAContext *ua, char *cmd, int relabel)
    if (!open_db(ua)) {
       return 1;
    }
-   store = get_storage_resource(ua, 1);
-   if (!store) {
+
+   /* Look for one of the barcode keywords */
+   if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
+      /* Now find the keyword in the list */
+      if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
+         *ua->argk[j] = 0;      /* zap barcode keyword */
+      }
+      label_barcodes = true;
+   }
+
+   store.store = get_storage_resource(ua, true/*use default*/);
+   if (!store.store) {
       return 1;
    }
-   ua->jcr->store = store;
+   pm_strcpy(store.store_source, _("command line"));
+   set_wstorage(ua->jcr, &store);
+   drive = get_storage_drive(ua, store.store);
 
-   if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
-      label_from_barcodes(ua);
+   if (label_barcodes) {
+      label_from_barcodes(ua, drive);
       return 1;
    }
 
    /* If relabel get name of Volume to relabel */
    if (relabel) {
       /* Check for oldvolume=name */
-      i = find_arg_with_value(ua, "oldvolume"); 
+      i = find_arg_with_value(ua, "oldvolume");
       if (i >= 0) {
-        memset(&omr, 0, sizeof(omr));
-        bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
-        if (db_get_media_record(ua->jcr, ua->db, &omr)) {
-           goto checkVol;
-        } 
+         memset(&omr, 0, sizeof(omr));
+         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
+         if (db_get_media_record(ua->jcr, ua->db, &omr)) {
+            goto checkVol;
+         }
          bsendmsg(ua, "%s", db_strerror(ua->db));
       }
       /* No keyword or Vol not found, ask user to select */
       if (!select_media_dbr(ua, &omr)) {
-        return 1;
+         return 1;
       }
 
       /* Require Volume to be Purged or Recycled */
 checkVol:
       if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
          bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
-           omr.VolumeName, omr.VolStatus);
-        return 1;
+            omr.VolumeName, omr.VolStatus);
+         return 1;
       }
    }
 
    /* Check for volume=NewVolume */
    i = find_arg_with_value(ua, "volume");
    if (i >= 0) {
-      pm_strcpy(&ua->cmd, ua->argv[i]);
+      pm_strcpy(ua->cmd, ua->argv[i]);
       goto checkName;
    }
 
@@ -314,83 +392,91 @@ checkVol:
    for ( ;; ) {
       media_record_exists = false;
       if (!get_cmd(ua, _("Enter new Volume name: "))) {
-        return 1;
+         return 1;
       }
 checkName:
       if (!is_volume_name_legal(ua, ua->cmd)) {
-        continue;
+         continue;
       }
 
       memset(&mr, 0, sizeof(mr));
       bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
       /* If VolBytes are zero the Volume is not labeled */
       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
-        if (mr.VolBytes != 0) {
-             bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
-               mr.VolumeName);
-            continue;
-         }
-         media_record_exists = true;
+         if (mr.VolBytes != 0) {
+             bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
+                mr.VolumeName);
+             continue;
+          }
+          media_record_exists = true;
       }
-      break;                         /* Got it */
+      break;                          /* Got it */
    }
 
    /* If autochanger, request slot */
-   if (store->autochanger) {
-      i = find_arg_with_value(ua, "slot"); 
-      if (i >= 0) {
-        mr.Slot = atoi(ua->argv[i]);
-      } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
-        return 1;
-      } else {
-        mr.Slot = ua->pint32_val;
+   i = find_arg_with_value(ua, "slot");
+   if (i >= 0) {
+      mr.Slot = atoi(ua->argv[i]);
+      mr.InChanger = 1;               /* assumed if we are labeling it */
+   } else if (store.store->autochanger) {
+      if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
+         return 1;
       }
-      mr.InChanger = 1;              /* assumed if we are labeling it */
+      mr.Slot = ua->pint32_val;
+      mr.InChanger = 1;               /* assumed if we are labeling it */
    }
+   mr.StorageId = store.store->StorageId;
 
-   bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
+   bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
 
    /* Must select Pool if not already done */
    if (pr.PoolId == 0) {
       memset(&pr, 0, sizeof(pr));
       if (!select_pool_dbr(ua, &pr)) {
-        return 1;
+         return 1;
       }
    }
 
-
-   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
+   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
 
    if (ok) {
       sd = ua->jcr->store_bsock;
       if (relabel) {
-        if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
+         /* Delete the old media record */
+         if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
             bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
-              omr.VolumeName, db_strerror(ua->db));
-        } else {
-            bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
-              omr.VolumeName);
-        }
+               omr.VolumeName, db_strerror(ua->db));
+         } else {
+            bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
+               omr.VolumeName);
+            /* Update the number of Volumes in the pool */
+            pr.NumVols--;
+            if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
+               bsendmsg(ua, "%s", db_strerror(ua->db));
+            }
+         }
       }
       if (ua->automount) {
-        bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
+         bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
          bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
-        bash_spaces(dev_name);
-         bnet_fsend(sd, "mount %s", dev_name);
-        unbash_spaces(dev_name);
-        while (bnet_recv(sd) >= 0) {
+         bash_spaces(dev_name);
+         bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
+         unbash_spaces(dev_name);
+         while (bnet_recv(sd) >= 0) {
             bsendmsg(ua, "%s", sd->msg);
-           /* Here we can get
-            *  3001 OK mount. Device=xxx      or
-            *  3001 Mounted Volume vvvv
-            *  3906 is cannot mount non-tape
-            * So for those, no need to print a reminder
-            */
+            /* Here we can get
+             *  3001 OK mount. Device=xxx      or
+             *  3001 Mounted Volume vvvv
+             *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
+             *  3906 is cannot mount non-tape
+             * So for those, no need to print a reminder
+             */
             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
+                strncmp(sd->msg, "3002 ", 5) == 0 ||
                 strncmp(sd->msg, "3906 ", 5) == 0) {
-              print_reminder = false;
-           }
-        }
+               print_reminder = false;
+            }
+         }
       }
    }
    if (print_reminder) {
@@ -405,20 +491,26 @@ checkName:
  * Request SD to send us the slot:barcodes, then wiffle
  *  through them all labeling them.
  */
-static void label_from_barcodes(UAContext *ua)
+static void label_from_barcodes(UAContext *ua, int drive)
 {
-   STORE *store = ua->jcr->store;
+   STORE *store = ua->jcr->wstore;
    POOL_DBR pr;
    MEDIA_DBR mr, omr;
    vol_list_t *vl, *vol_list = NULL;
    bool media_record_exists;
    char *slot_list;
+   int max_slots;
 
-   slot_list = (char *)malloc(MAX_SLOTS);
-   if (!get_user_slot_list(ua, slot_list, MAX_SLOTS)) {
-      free(slot_list);
+  
+   max_slots = get_num_slots_from_SD(ua);
+   if (max_slots <= 0) {
+      bsendmsg(ua, _("No slots in changer to scan.\n"));
       return;
    }
+   slot_list = (char *)malloc(max_slots+1);
+   if (!get_user_slot_list(ua, slot_list, max_slots)) {
+      goto bail_out;
+   }
 
    vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
 
@@ -433,12 +525,12 @@ static void label_from_barcodes(UAContext *ua)
                   "==============\n"));
    for (vl=vol_list; vl; vl=vl->next) {
       if (!vl->VolName || !slot_list[vl->Slot]) {
-        continue;
+         continue;
       }
       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
    }
-   if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
-       (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
+   if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) ||
+       (ua->pint32_val == 0)) {
       goto bail_out;
    }
    /* Select a pool */
@@ -451,77 +543,90 @@ static void label_from_barcodes(UAContext *ua)
    /* Fire off the label requests */
    for (vl=vol_list; vl; vl=vl->next) {
       if (!vl->VolName || !slot_list[vl->Slot]) {
-        continue;
+         continue;
       }
       memset(&mr, 0, sizeof(mr));
       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
       media_record_exists = false;
       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
-         if (mr.VolBytes != 0) {
-             bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
-               vl->Slot, mr.VolumeName);
-            if (!mr.InChanger) {
-               mr.InChanger = 1;
-               if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
-                   bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
-               }
-            }
-            continue;
-         } 
-         media_record_exists = true;
+          if (mr.VolBytes != 0) {
+             bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
+                vl->Slot, mr.VolumeName);
+             mr.Slot = vl->Slot;
+             mr.InChanger = 1;
+             mr.StorageId = store->StorageId;
+             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+                bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
+             }
+             continue;
+          }
+          media_record_exists = true;
       }
       mr.InChanger = 1;
+      mr.StorageId = store->StorageId;
       /*
        * Deal with creating cleaning tape here. Normal tapes created in
        *  send_label_request() below
        */
       if (is_cleaning_tape(ua, &mr, &pr)) {
-        if (media_record_exists) {      /* we update it */
-           mr.VolBytes = 1;
-           if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+         if (media_record_exists) {      /* we update it */
+            mr.VolBytes = 1;             /* any bytes to indicate it exists */
+            bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
+            mr.MediaType[0] = 0;
+            mr.StorageId = store->StorageId;
+            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
                 bsendmsg(ua, "%s", db_strerror(ua->db));
-           }
-        } else {                        /* create the media record */
-           set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
-           if (db_create_media_record(ua->jcr, ua->db, &mr)) {
+            }
+         } else {                        /* create the media record */
+            if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
+               bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
+               goto bail_out;
+            }
+            set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
+            bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
+            mr.MediaType[0] = 0;
+            if (db_create_media_record(ua->jcr, ua->db, &mr)) {
                bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
-                 mr.VolumeName);
-           } else {
-               bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
-           }
-        }
-        continue;                    /* done, go handle next volume */
+                  mr.VolumeName);
+               pr.NumVols++;          /* this is a bit suspect */
+               if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
+                  bsendmsg(ua, "%s", db_strerror(ua->db));
+               }
+            } else {
+               bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
+            }
+         }
+         continue;                    /* done, go handle next volume */
       }
       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
 
       mr.Slot = vl->Slot;
-      if (!send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists)) {
-        goto bail_out;
-      }
+      send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
    }
 
 
 bail_out:
+   free(slot_list);
    free_vol_list(vol_list);
    close_sd_bsock(ua);
 
    return;
 }
 
-/* 
+/*
  * Check if the Volume name has legal characters
  * If ua is non-NULL send the message
  */
-int is_volume_name_legal(UAContext *ua, char *name)
+bool is_volume_name_legal(UAContext *ua, const char *name)
 {
    int len;
-   char *p;
-   char *accept = ":.-_";
+   const char *p;
+   const char *accept = ":.-_";
 
    /* Restrict the characters permitted in the Volume name */
    for (p=name; *p; p++) {
       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
-        continue;
+         continue;
       }
       if (ua) {
          bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
@@ -544,82 +649,109 @@ int is_volume_name_legal(UAContext *ua, char *name)
    return 1;
 }
 
-static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
-                             POOL_DBR *pr, int relabel, bool media_record_exists)
+/*
+ * NOTE! This routine opens the SD socket but leaves it open
+ */
+static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
+                               POOL_DBR *pr, int relabel, bool media_record_exists,
+                               int drive)
 {
    BSOCK *sd;
    char dev_name[MAX_NAME_LENGTH];
-   int ok = FALSE;
+   bool ok = false;
+   bool is_dvd = false;
+   uint64_t VolBytes = 0;
 
    if (!(sd=open_sd_bsock(ua))) {
-      return 0;
+      return false;
    }
-   bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
+   bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
    bash_spaces(dev_name);
    bash_spaces(mr->VolumeName);
    bash_spaces(mr->MediaType);
    bash_spaces(pr->Name);
    if (relabel) {
       bash_spaces(omr->VolumeName);
-      bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d", 
-        dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
+      bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
+                     "MediaType=%s Slot=%d drive=%d",
+                 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, 
+                 mr->MediaType, mr->Slot, drive);
       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
-        omr->VolumeName, mr->VolumeName);
+         omr->VolumeName, mr->VolumeName);
    } else {
-      bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d", 
-        dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
-      bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
-        mr->VolumeName, mr->Slot);
-      Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
-        dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
+      bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
+                     "Slot=%d drive=%d",
+                 dev_name, mr->VolumeName, pr->Name, mr->MediaType, 
+                 mr->Slot, drive);
+      bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
+         mr->VolumeName, mr->Slot);
+      Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
+         dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
    }
 
    while (bnet_recv(sd) >= 0) {
+      int dvd;
       bsendmsg(ua, "%s", sd->msg);
-      if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
-        ok = TRUE;
-      } 
+      if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
+                 &dvd) == 2) {
+         is_dvd = dvd;
+         ok = true;
+      }
    }
    unbash_spaces(mr->VolumeName);
    unbash_spaces(mr->MediaType);
    unbash_spaces(pr->Name);
    mr->LabelDate = time(NULL);
+   mr->set_label_date = true;
+   if (is_dvd) {
+      /* We know that a freshly labelled DVD has 1 VolParts */
+      /* This does not apply to auto-labelled DVDs. */
+      mr->VolParts = 1;
+   }
    if (ok) {
       if (media_record_exists) {      /* we update it */
-        mr->VolBytes = 1;
-        mr->InChanger = 1;
-        if (!db_update_media_record(ua->jcr, ua->db, mr)) {
+         mr->VolBytes = VolBytes;
+         mr->InChanger = 1;
+         mr->StorageId = ua->jcr->wstore->StorageId;
+         if (!db_update_media_record(ua->jcr, ua->db, mr)) {
              bsendmsg(ua, "%s", db_strerror(ua->db));
-            ok = FALSE;
-        }
-      } else {                       /* create the media record */
-        set_pool_dbr_defaults_in_media_dbr(mr, pr);
-        mr->VolBytes = 1;               /* flag indicating Volume labeled */
-        mr->InChanger = 1;
-        if (db_create_media_record(ua->jcr, ua->db, mr)) {
+             ok = false;
+         }
+      } else {                        /* create the media record */
+         set_pool_dbr_defaults_in_media_dbr(mr, pr);
+         mr->VolBytes = VolBytes;
+         mr->InChanger = 1;
+         mr->StorageId = ua->jcr->wstore->StorageId;
+         mr->Enabled = 1;
+         if (db_create_media_record(ua->jcr, ua->db, mr)) {
             bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
-           mr->VolumeName, mr->Slot);
-        } else {
+            mr->VolumeName, mr->Slot);
+            /* Update number of volumes in pool */
+            pr->NumVols++;
+            if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
+               bsendmsg(ua, "%s", db_strerror(ua->db));
+            }
+         } else {
             bsendmsg(ua, "%s", db_strerror(ua->db));
-           ok = FALSE;
-        }
+            ok = false;
+         }
       }
    } else {
-      bsendmsg(ua, _("Label command failed.\n"));
+      bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
    }
    return ok;
 }
 
-static BSOCK *open_sd_bsock(UAContext *ua) 
+static BSOCK *open_sd_bsock(UAContext *ua)
 {
-   STORE *store = ua->jcr->store;
+   STORE *store = ua->jcr->wstore;
 
    if (!ua->jcr->store_bsock) {
-      bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
-        store->hdr.name, store->address, store->SDport);
+      bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
+         store->name(), store->address, store->SDport);
       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
-        return NULL;
+         return NULL;
       }
    }
    return ua->jcr->store_bsock;
@@ -634,36 +766,39 @@ static void close_sd_bsock(UAContext *ua)
    }
 }
 
-static char *get_volume_name_from_SD(UAContext *ua, int Slot
+static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
 {
-   STORE *store = ua->jcr->store;
+   STORE *store = ua->jcr->wstore;
    BSOCK *sd;
    char dev_name[MAX_NAME_LENGTH];
    char *VolName = NULL;
    int rtn_slot;
 
    if (!(sd=open_sd_bsock(ua))) {
+      bsendmsg(ua, _("Could not open SD socket.\n"));
       return NULL;
    }
-   bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
+   bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
    bash_spaces(dev_name);
    /* Ask for autochanger list of volumes */
-   bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
+   bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
    Dmsg1(100, "Sent: %s", sd->msg);
 
    /* Get Volume name in this Slot */
    while (bnet_recv(sd) >= 0) {
       bsendmsg(ua, "%s", sd->msg);
-      if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
-        VolName = (char *)malloc(sd->msglen);
-         if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
-           break;
-        }
-        free(VolName);
-        VolName = NULL;
+      Dmsg1(100, "Got: %s", sd->msg);
+      if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
+         VolName = (char *)malloc(sd->msglen);
+         if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
+            break;
+         }
+         free(VolName);
+         VolName = NULL;
       }
    }
-   Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
+   close_sd_bsock(ua);
+   Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
    return VolName;
 }
 
@@ -672,9 +807,9 @@ static char *get_volume_name_from_SD(UAContext *ua, int Slot)
  *  If scan is set, we return all slots found,
  *  otherwise, we return only slots with valid barcodes (Volume names)
  */
-static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) 
+static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
 {
-   STORE *store = ua->jcr->store;
+   STORE *store = ua->jcr->wstore;
    char dev_name[MAX_NAME_LENGTH];
    BSOCK *sd;
    vol_list_t *vl;
@@ -685,10 +820,10 @@ static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
       return NULL;
    }
 
-   bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
+   bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
    bash_spaces(dev_name);
    /* Ask for autochanger list of volumes */
-   bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
+   bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
 
    /* Read and organize list of Volumes */
    while (bnet_recv(sd) >= 0) {
@@ -698,64 +833,68 @@ static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
 
       /* Check for returned SD messages */
       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
-         B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
+          B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
           sd->msg[4] == ' ') {
          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
-        continue;
+         continue;
       }
 
-      /* Validate Slot: if scanning, otherwise Slot:Barcode */
+      /* Validate Slot: if scanning, otherwise  Slot:Barcode */
       p = strchr(sd->msg, ':');
       if (scan && p) {
-        /* Scanning -- require only valid slot */
-        Slot = atoi(sd->msg);
-        if (Slot <= 0) {
-           p--;
+         /* Scanning -- require only valid slot */
+         Slot = atoi(sd->msg);
+         if (Slot <= 0) {
+            p--;
             *p = ':';
-            bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
-           continue;
-        }
+            bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
+            continue;
+         }
       } else {
-        /* Not scanning */
-        if (p && strlen(p) > 1) {
-           *p++ = 0;
-           if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
-              p--;
+         /* Not scanning */
+         if (p && strlen(p) > 1) {
+            *p++ = 0;
+            if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
+               p--;
                *p = ':';
-               bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
-              continue;
-           }
-        } else {
-           continue;
-        }
-        if (!is_volume_name_legal(ua, p)) {
-           p--;
+               bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
+               continue;
+            }
+         } else {
+            continue;
+         }
+         if (!is_volume_name_legal(ua, p)) {
+            p--;
             *p = ':';
-            bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg); 
-           continue;
-        }
+            bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
+            continue;
+         }
       }
 
       /* Add Slot and VolumeName to list */
       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
       vl->Slot = Slot;
       if (p) {
-        vl->VolName = bstrdup(p);
+         if (*p == ':') {
+            p++;                      /* skip separator */
+         }
+         vl->VolName = bstrdup(p);
       } else {
-        vl->VolName = NULL;
+         vl->VolName = NULL;
       }
+      Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
       if (!vol_list) {
-        vl->next = vol_list;
-        vol_list = vl;
+         vl->next = vol_list;
+         vol_list = vl;
       } else {
-        /* Add new entry to end of list */
-        for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
-           if (!tvl->next) {
-              tvl->next = vl;
-              vl->next = NULL;
-              break;
-           }
-        }
+         /* Add new entry to end of list */
+         for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
+            if (!tvl->next) {
+               tvl->next = vl;
+               vl->next = NULL;
+               break;
+            }
+         }
       }
    }
    close_sd_bsock(ua);
@@ -765,11 +904,12 @@ static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
 static void free_vol_list(vol_list_t *vol_list)
 {
    vol_list_t *vl;
+
    /* Free list */
    for (vl=vol_list; vl; ) {
       vol_list_t *ovl;
       if (vl->VolName) {
-        free(vl->VolName);
+         free(vl->VolName);
       }
       ovl = vl;
       vl = vl->next;
@@ -777,30 +917,95 @@ static void free_vol_list(vol_list_t *vol_list)
    }
 }
 
+/*
+ * We get the number of slots in the changer from the SD
+ */
+static int get_num_slots_from_SD(UAContext *ua)
+{
+   STORE *store = ua->jcr->wstore;
+   char dev_name[MAX_NAME_LENGTH];
+   BSOCK *sd;
+   int slots = 0;
+
+
+   if (!(sd=open_sd_bsock(ua))) {
+      return 0;
+   }
+
+   bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
+   bash_spaces(dev_name);
+   /* Ask for autochanger number of slots */
+   bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
+
+   while (bnet_recv(sd) >= 0) {
+      if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
+         break;
+      } else {
+         bsendmsg(ua, "%s", sd->msg);
+      }
+   }
+   close_sd_bsock(ua);
+   bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
+   return slots;
+}
+
+/*
+ * We get the number of drives in the changer from the SD
+ */
+int get_num_drives_from_SD(UAContext *ua)
+{
+   STORE *store = ua->jcr->wstore;
+   char dev_name[MAX_NAME_LENGTH];
+   BSOCK *sd;
+   int drives = 0;
+
+
+   if (!(sd=open_sd_bsock(ua))) {
+      return 0;
+   }
+
+   bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
+   bash_spaces(dev_name);
+   /* Ask for autochanger number of slots */
+   bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
+
+   while (bnet_recv(sd) >= 0) {
+      if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
+         break;
+      } else {
+         bsendmsg(ua, "%s", sd->msg);
+      }
+   }
+   close_sd_bsock(ua);
+//   bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
+   return drives;
+}
+
+
+
 
 /*
  * Check if this is a cleaning tape by comparing the Volume name
- *  with the Cleaning Prefix. If they match, this is a cleaning 
+ *  with the Cleaning Prefix. If they match, this is a cleaning
  *  tape.
  */
-static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
+static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
 {
+   /* Find Pool resource */
+   ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
    if (!ua->jcr->pool) {
-      /* Find Pool resource */
-      ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
-      if (!ua->jcr->pool) {
-         bsendmsg(ua, _("Pool %s resource not found!\n"), pr->Name);
-        return 1;
-      }
+      bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
+         pr->Name, mr->VolumeName);
+      return false;
    }
    if (ua->jcr->pool->cleaning_prefix == NULL) {
-      return 0;
+      return false;
    }
-   Dmsg4(200, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
+   Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
-      strlen(ua->jcr->pool->cleaning_prefix), 
+      strlen(ua->jcr->pool->cleaning_prefix),
       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
-                 strlen(ua->jcr->pool->cleaning_prefix)));
+                  strlen(ua->jcr->pool->cleaning_prefix)));
    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
-                 strlen(ua->jcr->pool->cleaning_prefix)) == 0;
+                  strlen(ua->jcr->pool->cleaning_prefix)) == 0;
 }