]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_label.c
Pool + label cleanups from bug reports
[bacula/bacula] / bacula / src / dird / ua_label.c
index be0746b3239ce59e3acc3980181855fe44e3fa10..2b3c95cdd521f8658077a2381d851e702f2739e5 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /*
-   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+   Copyright (C) 2000-2004 Kern Sibbald and John Walker
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -39,12 +39,16 @@ typedef struct s_vol_list {
 
 
 /* Forward referenced functions */
-static int do_label(UAContext *ua, char *cmd, int relabel);
+static int do_label(UAContext *ua, const 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);
-static vol_list_t *get_slot_list_from_SD(UAContext *ua);
-static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
+static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
+              POOL_DBR *pr, int relabel, bool media_record_exits);
+static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
+static void free_vol_list(vol_list_t *vol_list);
+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);
 
 
 /*
@@ -52,16 +56,101 @@ static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
  *  
  *   label storage=xxx volume=vvv
  */
-int labelcmd(UAContext *ua, char *cmd)
+int label_cmd(UAContext *ua, const char *cmd)
 {
    return do_label(ua, cmd, 0);       /* standard label */
 }
 
-int relabelcmd(UAContext *ua, char *cmd)
+int relabel_cmd(UAContext *ua, const char *cmd)
 {
    return do_label(ua, cmd, 1);      /* relabel tape */
 }
 
+static int const max_slots = 5000;
+
+static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
+{
+   int i;
+   const char *msg;
+
+   for (int i=0; i<num_slots; i++) {
+      slot_list[i] = 0;
+   }
+   i = find_arg_with_value(ua, "slots");
+   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 */
+         e = strchr(p, ',');
+        if (e) {
+           *e++ = 0;
+        }
+        /* Check for range */
+         h = strchr(p, '-');             /* range? */
+        if (h == p) {
+            msg = _("Negative numbers not permitted\n");
+           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)) {
+               msg = _("Range start is not an integer.\n");
+              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)) {
+               msg = _("Input value is not an integer.\n");
+              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) {
+            msg = _("Slot too large.\n");
+           goto bail_out;
+        }
+        for (i=beg; i<=end; i++) {
+           slot_list[i] = 1;         /* Turn on specified range */
+        }
+      }
+   } else { 
+      /* Turn everything on */
+      for (i=0; i<num_slots; i++) {
+        slot_list[i] = 1;
+      }
+   }
+#ifdef xxx_debug
+   printf("Slots turned on:\n");
+   for (i=1; i<num_slots; i++) {
+      if (slot_list[i]) {
+         printf("%d\n", i); 
+      }
+   }
+#endif
+   return true;
+
+bail_out:
+   return false;
+}
 
 /*
  * Update Slots corresponding to Volumes in autochanger 
@@ -71,6 +160,8 @@ int update_slots(UAContext *ua)
    STORE *store;
    vol_list_t *vl, *vol_list = NULL;
    MEDIA_DBR mr;
+   char *slot_list;
+   bool scan;       
 
    if (!open_db(ua)) {
       return 1;
@@ -81,8 +172,15 @@ int update_slots(UAContext *ua)
    }
    ua->jcr->store = store;
 
-   vol_list = get_slot_list_from_SD(ua);
+   scan = find_arg(ua, _("scan")) >= 0;
+
+   slot_list = (char *)malloc(max_slots);
+   if (!get_user_slot_list(ua, slot_list, max_slots)) {
+      free(slot_list);
+      return 1;
+   }
 
+   vol_list = get_vol_list_from_SD(ua, scan);
 
    if (!vol_list) {
       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
@@ -91,14 +189,46 @@ int update_slots(UAContext *ua)
 
    /* 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 larger than max %d ignored.\n"));
+        continue;
+      }
+      /* Check if user wants us to look at this slot */
+      if (!slot_list[vl->Slot]) {
+         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);
+         Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
+      }
+      slot_list[vl->Slot] = 0;       /* clear Slot */
+      if (!vl->VolName) {
+         Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
+        memset(&mr, 0, sizeof(mr));
+        mr.Slot = vl->Slot;
+        mr.InChanger = 1;
+        /* Set InChanger to zero for this Slot */
+        db_lock(ua->db);
+        db_make_inchanger_unique(ua->jcr, ua->db, &mr);
+        db_unlock(ua->db);
+         bsendmsg(ua, _("No VolName for Slot=%d set InChanger 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) {
+         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));
+                bsendmsg(ua, "%s", db_strerror(ua->db));
             } else {
                bsendmsg(ua, _(
                   "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
@@ -108,47 +238,52 @@ int update_slots(UAContext *ua)
              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);
       }
+      db_unlock(ua->db);
+   }
+   memset(&mr, 0, sizeof(mr));
+   mr.InChanger = 1;
+   for (int i=1; i<max_slots; i++) {
+      if (slot_list[i]) {
+        mr.Slot = i;
+        /* Set InChanger to zero for this Slot */
+        db_lock(ua->db);
+        db_make_inchanger_unique(ua->jcr, ua->db, &mr);
+        db_unlock(ua->db);
+         bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), i);
+      }
    }
-
-
+      
 bail_out:
-   /* Free list */
-   for (vl=vol_list; vl; ) {
-      vol_list_t *ovl;
-      free(vl->VolName);
-      ovl = vl;
-      vl = vl->next;
-      free(ovl);
-   }
 
-   if (ua->jcr->store_bsock) {
-      bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
-      bnet_close(ua->jcr->store_bsock);
-      ua->jcr->store_bsock = NULL;
-   }
+   free_vol_list(vol_list);
+   free(slot_list);
+   close_sd_bsock(ua);
+
    return 1;
 }
 
+
 /*
  * 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;
    BSOCK *sd;
-   sd = ua->jcr->store_bsock;
    char dev_name[MAX_NAME_LENGTH];
    MEDIA_DBR mr, omr;
    POOL_DBR pr;
+   bool print_reminder = true;
    int ok = FALSE;
-   int mounted = FALSE;
    int i;
-   static char *barcode_keyword[] = {
+   bool media_record_exists = false;
+   static const char *barcode_keyword[] = {
       "barcode",
       "barcodes",
       NULL};
@@ -171,8 +306,8 @@ static int do_label(UAContext *ua, char *cmd, int relabel)
 
    /* If relabel get name of Volume to relabel */
    if (relabel) {
-      /* Check for volume=OldVolume */
-      i = find_arg_with_value(ua, "volume"); 
+      /* Check for oldvolume=name */
+      i = find_arg_with_value(ua, "oldvolume"); 
       if (i >= 0) {
         memset(&omr, 0, sizeof(omr));
         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
@@ -186,17 +321,17 @@ static int do_label(UAContext *ua, char *cmd, int relabel)
         return 1;
       }
 
-      /* Require Volume to be Purged */
+      /* Require Volume to be Purged or Recycled */
 checkVol:
-      if (strcmp(omr.VolStatus, "Purged") != 0) {
-         bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
+      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;
       }
    }
 
-   /* Check for name=NewVolume */
-   i = find_arg_with_value(ua, "name");
+   /* Check for volume=NewVolume */
+   i = find_arg_with_value(ua, "volume");
    if (i >= 0) {
       pm_strcpy(&ua->cmd, ua->argv[i]);
       goto checkName;
@@ -204,6 +339,7 @@ checkVol:
 
    /* Get a new Volume name */
    for ( ;; ) {
+      media_record_exists = false;
       if (!get_cmd(ua, _("Enter new Volume name: "))) {
         return 1;
       }
@@ -214,10 +350,14 @@ checkName:
 
       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)) {
-          bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
-            mr.VolumeName);
-         continue;
+        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 */
    }
@@ -232,6 +372,7 @@ checkName:
       } else {
         mr.Slot = ua->pint32_val;
       }
+      mr.InChanger = 1;              /* assumed if we are labeling it */
    }
 
    bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
@@ -244,29 +385,29 @@ checkName:
       }
    }
 
-   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
-      store->hdr.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 1;   
-   }
-   sd = ua->jcr->store_bsock;
 
-   ok = send_label_request(ua, &mr, &omr, &pr, relabel);
+   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
 
    if (ok) {
+      sd = ua->jcr->store_bsock;
       if (relabel) {
+        /* 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);
+           /* 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) {
-        strcpy(dev_name, store->dev_name);
-         bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
+        bstrncpy(dev_name, 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);
@@ -275,17 +416,20 @@ checkName:
            /* 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
             */
-            mounted = strncmp(sd->msg, "3001 ", 5) == 0;
+            if (strncmp(sd->msg, "3001 ", 5) == 0 ||
+                strncmp(sd->msg, "3906 ", 5) == 0) {
+              print_reminder = false;
+           }
         }
       }
    }
-   if (!mounted) {
+   if (print_reminder) {
       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
    }
-   bnet_sig(sd, BNET_TERMINATE);
-   bnet_close(sd);
-   ua->jcr->store_bsock = NULL;
+   close_sd_bsock(ua);
 
    return 1;
 }
@@ -300,8 +444,15 @@ static void label_from_barcodes(UAContext *ua)
    POOL_DBR pr;
    MEDIA_DBR mr, omr;
    vol_list_t *vl, *vol_list = NULL;
+   bool media_record_exists;
+   char *slot_list;
 
-   vol_list = get_slot_list_from_SD(ua);
+   slot_list = (char *)malloc(max_slots);
+   if (!get_user_slot_list(ua, slot_list, max_slots)) {
+      goto bail_out;
+   }
+
+   vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
 
    if (!vol_list) {
       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
@@ -313,6 +464,9 @@ static void label_from_barcodes(UAContext *ua)
                   "Slot  Volume\n"
                   "==============\n"));
    for (vl=vol_list; vl; vl=vl->next) {
+      if (!vl->VolName || !slot_list[vl->Slot]) {
+        continue;
+      }
       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
    }
    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
@@ -328,61 +482,63 @@ 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;
+      }
       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)) {
-          bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
-            vl->Slot, mr.VolumeName);
-         continue;
+         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;
       }
+      mr.InChanger = 1;
       /*
        * Deal with creating cleaning tape here. Normal tapes created in
        *  send_label_request() below
        */
       if (is_cleaning_tape(ua, &mr, &pr)) {
-        set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
-        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));
+        if (media_record_exists) {      /* we update it */
+           mr.VolBytes = 1;
+           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)) {
+               bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
+                 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;
+        continue;                    /* done, go handle next volume */
       }
       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
-      if (ua->jcr->store_bsock) {
-        bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
-        bnet_close(ua->jcr->store_bsock);
-        ua->jcr->store_bsock = NULL;
-      }
-      bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
-        store->hdr.name, store->address, store->SDport);
-      if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
-         bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
-        goto bail_out;
-      }
 
       mr.Slot = vl->Slot;
-      send_label_request(ua, &mr, &omr, &pr, 0);
+      send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
    }
 
 
 bail_out:
-   /* Free list */
-   for (vl=vol_list; vl; ) {
-      vol_list_t *ovl;
-      free(vl->VolName);
-      ovl = vl;
-      vl = vl->next;
-      free(ovl);
-   }
-
-   if (ua->jcr->store_bsock) {
-      bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
-      bnet_close(ua->jcr->store_bsock);
-      ua->jcr->store_bsock = NULL;
-   }
+   free(slot_list);
+   free_vol_list(vol_list);
+   close_sd_bsock(ua);
 
    return;
 }
@@ -391,11 +547,11 @@ bail_out:
  * 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++) {
@@ -423,14 +579,19 @@ 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)
+/*
+ * 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)
 {
    BSOCK *sd;
    char dev_name[MAX_NAME_LENGTH];
-   int ok = FALSE;
+   bool ok = false;
 
-   sd = ua->jcr->store_bsock;
+   if (!(sd=open_sd_bsock(ua))) {
+      return false;
+   }
    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
    bash_spaces(dev_name);
    bash_spaces(mr->VolumeName);
@@ -438,12 +599,12 @@ static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
    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")
+      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);
       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
         omr->VolumeName, mr->VolumeName);
    } else {
-      bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d")
+      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);
@@ -454,7 +615,7 @@ static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
    while (bnet_recv(sd) >= 0) {
       bsendmsg(ua, "%s", sd->msg);
       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
-        ok = TRUE;
+        ok = true;
       } 
    }
    unbash_spaces(mr->VolumeName);
@@ -462,21 +623,102 @@ static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
    unbash_spaces(pr->Name);
    mr->LabelDate = time(NULL);
    if (ok) {
-      set_pool_dbr_defaults_in_media_dbr(mr, pr);
-      if (db_create_media_record(ua->jcr, ua->db, mr)) {
-         bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
+      if (media_record_exists) {      /* we update it */
+        mr->VolBytes = 1;
+        mr->InChanger = 1;
+        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)) {
+            bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
            mr->VolumeName, mr->Slot);
-      } else {
-         bsendmsg(ua, "%s", db_strerror(ua->db));
-        ok = FALSE;
+           /* 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;
+        }
       }
    } else {
-      bsendmsg(ua, _("Label command failed.\n"));
+      bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
    }
    return ok;
 }
 
-static vol_list_t *get_slot_list_from_SD(UAContext *ua)
+static BSOCK *open_sd_bsock(UAContext *ua) 
+{
+   STORE *store = ua->jcr->store;
+
+   if (!ua->jcr->store_bsock) {
+      bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
+        store->hdr.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 ua->jcr->store_bsock;
+}
+
+static void close_sd_bsock(UAContext *ua)
+{
+   if (ua->jcr->store_bsock) {
+      bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
+      bnet_close(ua->jcr->store_bsock);
+      ua->jcr->store_bsock = NULL;
+   }
+}
+
+static char *get_volume_name_from_SD(UAContext *ua, int Slot) 
+{
+   STORE *store = ua->jcr->store;
+   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));
+   bash_spaces(dev_name);
+   /* Ask for autochanger list of volumes */
+   bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
+   Dmsg1(100, "Sent: %s", sd->msg);
+
+   /* Get Volume name in this Slot */
+   while (bnet_recv(sd) >= 0) {
+      bsendmsg(ua, "%s", sd->msg);
+      Dmsg1(100, "Got: %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;
+      }
+   }
+   close_sd_bsock(ua);
+   Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
+   return VolName;
+}
+
+/*
+ * We get the slot list from the Storage daemon.
+ *  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) 
 {
    STORE *store = ua->jcr->store;
    char dev_name[MAX_NAME_LENGTH];
@@ -485,13 +727,9 @@ static vol_list_t *get_slot_list_from_SD(UAContext *ua)
    vol_list_t *vol_list = NULL;
 
 
-   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
-      store->hdr.name, store->address, store->SDport);
-   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
-      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+   if (!(sd=open_sd_bsock(ua))) {
       return NULL;
    }
-   sd  = ua->jcr->store_bsock;
 
    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
    bash_spaces(dev_name);
@@ -512,25 +750,50 @@ static vol_list_t *get_slot_list_from_SD(UAContext *ua)
         continue;
       }
 
-      /* Validate Slot:Barcode */
+      /* Validate Slot: if scanning, otherwise Slot:Barcode */
       p = strchr(sd->msg, ':');
-      if (p && strlen(p) > 1) {
-        *p++ = 0;
-        if (!is_an_integer(sd->msg)) {
+      if (scan && 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;
         }
       } else {
-        continue;
-      }
-      Slot = atoi(sd->msg);
-      if (Slot <= 0 || !is_volume_name_legal(ua, p)) {
-        continue;
+        /* 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--;
+            *p = ':';
+            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;
-      vl->VolName = bstrdup(p);
+      if (p) {
+         if (*p == ':') {
+           p++;                      /* skip separator */
+        }
+        vl->VolName = bstrdup(p);
+      } else {
+        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;
@@ -545,27 +808,48 @@ static vol_list_t *get_slot_list_from_SD(UAContext *ua)
         }
       }
    }
+   close_sd_bsock(ua);
    return vol_list;
 }
 
+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);
+      }
+      ovl = vl;
+      vl = vl->next;
+      free(ovl);
+   }
+}
+
+
 /*
  * Check if this is a cleaning tape by comparing the Volume name
  *  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!\n"), pr->Name);
+      return true;
    }
    if (ua->jcr->pool->cleaning_prefix == NULL) {
-      return 0;
+      return false;
    }
+   Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
+      ua->jcr->pool->cleaning_prefix, mr->VolumeName,
+      strlen(ua->jcr->pool->cleaning_prefix), 
+      strncmp(mr->VolumeName, 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;
 }