]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Pool + label cleanups from bug reports
[bacula/bacula] / bacula / src / dird / ua_label.c
1 /*
2  *
3  *   Bacula Director -- Tape labeling commands
4  *
5  *     Kern Sibbald, April MMIII
6  *
7  *   Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Slot list definition */
34 typedef struct s_vol_list {
35    struct s_vol_list *next;
36    char *VolName;
37    int Slot;
38 } vol_list_t;
39
40
41 /* Forward referenced functions */
42 static int do_label(UAContext *ua, const char *cmd, int relabel);
43 static void label_from_barcodes(UAContext *ua);
44 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
45                POOL_DBR *pr, int relabel, bool media_record_exits);
46 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
47 static void free_vol_list(vol_list_t *vol_list);
48 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
49 static BSOCK *open_sd_bsock(UAContext *ua);
50 static void close_sd_bsock(UAContext *ua);
51 static char *get_volume_name_from_SD(UAContext *ua, int Slot);
52
53
54 /*
55  * Label a tape 
56  *  
57  *   label storage=xxx volume=vvv
58  */
59 int label_cmd(UAContext *ua, const char *cmd)
60 {
61    return do_label(ua, cmd, 0);       /* standard label */
62 }
63
64 int relabel_cmd(UAContext *ua, const char *cmd)
65 {
66    return do_label(ua, cmd, 1);      /* relabel tape */
67 }
68
69 static int const max_slots = 5000;
70
71 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
72 {
73    int i;
74    const char *msg;
75
76    for (int i=0; i<num_slots; i++) {
77       slot_list[i] = 0;
78    }
79    i = find_arg_with_value(ua, "slots");
80    if (i >= 0) {
81       /* scan slot list in ua->argv[i] */
82       char *p, *e, *h;
83       int beg, end;
84
85       strip_trailing_junk(ua->argv[i]);
86       for (p=ua->argv[i]; p && *p; p=e) {
87          /* Check for list */
88          e = strchr(p, ',');
89          if (e) {
90             *e++ = 0;
91          }
92          /* Check for range */
93          h = strchr(p, '-');             /* range? */
94          if (h == p) {
95             msg = _("Negative numbers not permitted\n");
96             goto bail_out;
97          }
98          if (h) {
99             *h++ = 0;
100             if (!is_an_integer(h)) {
101                msg = _("Range end is not integer.\n");
102                goto bail_out;
103             }
104             skip_spaces(&p);
105             if (!is_an_integer(p)) {
106                msg = _("Range start is not an integer.\n");
107                goto bail_out;
108             }
109             beg = atoi(p);
110             end = atoi(h);
111             if (end < beg) {
112                msg = _("Range end not bigger than start.\n");
113                goto bail_out;
114             }
115          } else {
116             skip_spaces(&p);
117             if (!is_an_integer(p)) {
118                msg = _("Input value is not an integer.\n");
119                goto bail_out;
120             }
121             beg = end = atoi(p);
122          }
123          if (beg <= 0 || end <= 0) {
124             msg = _("Values must be be greater than zero.\n");
125             goto bail_out;
126          }
127          if (end >= num_slots) {
128             msg = _("Slot too large.\n");
129             goto bail_out;
130          }
131          for (i=beg; i<=end; i++) {
132             slot_list[i] = 1;         /* Turn on specified range */
133          }
134       }
135    } else { 
136       /* Turn everything on */
137       for (i=0; i<num_slots; i++) {
138          slot_list[i] = 1;
139       }
140    }
141 #ifdef xxx_debug
142    printf("Slots turned on:\n");
143    for (i=1; i<num_slots; i++) {
144       if (slot_list[i]) {
145          printf("%d\n", i); 
146       }
147    }
148 #endif
149    return true;
150
151 bail_out:
152    return false;
153 }
154
155 /*
156  * Update Slots corresponding to Volumes in autochanger 
157  */
158 int update_slots(UAContext *ua)
159 {
160    STORE *store;
161    vol_list_t *vl, *vol_list = NULL;
162    MEDIA_DBR mr;
163    char *slot_list;
164    bool scan;        
165
166    if (!open_db(ua)) {
167       return 1;
168    }
169    store = get_storage_resource(ua, 1);
170    if (!store) {
171       return 1;
172    }
173    ua->jcr->store = store;
174
175    scan = find_arg(ua, _("scan")) >= 0;
176
177    slot_list = (char *)malloc(max_slots);
178    if (!get_user_slot_list(ua, slot_list, max_slots)) {
179       free(slot_list);
180       return 1;
181    }
182
183    vol_list = get_vol_list_from_SD(ua, scan);
184
185    if (!vol_list) {
186       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
187       goto bail_out;
188    }
189
190    /* Walk through the list updating the media records */
191    for (vl=vol_list; vl; vl=vl->next) {
192       if (vl->Slot >= max_slots) {
193          bsendmsg(ua, _("Slot %d larger than max %d ignored.\n"));
194          continue;
195       }
196       /* Check if user wants us to look at this slot */
197       if (!slot_list[vl->Slot]) {
198          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
199          continue;
200       }
201       /* If scanning, we read the label rather than the barcode */
202       if (scan) {
203          if (vl->VolName) {
204             free(vl->VolName);
205             vl->VolName = NULL;
206          }
207          vl->VolName = get_volume_name_from_SD(ua, vl->Slot);
208          Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
209       }
210       slot_list[vl->Slot] = 0;        /* clear Slot */
211       if (!vl->VolName) {
212          Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
213          memset(&mr, 0, sizeof(mr));
214          mr.Slot = vl->Slot;
215          mr.InChanger = 1;
216          /* Set InChanger to zero for this Slot */
217          db_lock(ua->db);
218          db_make_inchanger_unique(ua->jcr, ua->db, &mr);
219          db_unlock(ua->db);
220          bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), vl->Slot);
221          continue;
222       }
223       memset(&mr, 0, sizeof(mr));
224       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
225       db_lock(ua->db);
226       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
227           if (mr.Slot != vl->Slot || !mr.InChanger) {
228              mr.Slot = vl->Slot;
229              mr.InChanger = 1;
230              if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
231                 bsendmsg(ua, "%s", db_strerror(ua->db));
232              } else {
233                 bsendmsg(ua, _(
234                   "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
235                   mr.VolumeName, mr.Slot);
236              }
237           } else {
238              bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
239                 mr.VolumeName);
240           }   
241           db_unlock(ua->db);
242           continue;
243       } else {
244           bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"), 
245              mr.VolumeName);
246       }
247       db_unlock(ua->db);
248    }
249    memset(&mr, 0, sizeof(mr));
250    mr.InChanger = 1;
251    for (int i=1; i<max_slots; i++) {
252       if (slot_list[i]) {
253          mr.Slot = i;
254          /* Set InChanger to zero for this Slot */
255          db_lock(ua->db);
256          db_make_inchanger_unique(ua->jcr, ua->db, &mr);
257          db_unlock(ua->db);
258          bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), i);
259       }
260    }
261       
262 bail_out:
263
264    free_vol_list(vol_list);
265    free(slot_list);
266    close_sd_bsock(ua);
267
268    return 1;
269 }
270
271
272 /*
273  * Common routine for both label and relabel
274  */
275 static int do_label(UAContext *ua, const char *cmd, int relabel)
276 {
277    STORE *store;
278    BSOCK *sd;
279    char dev_name[MAX_NAME_LENGTH];
280    MEDIA_DBR mr, omr;
281    POOL_DBR pr;
282    bool print_reminder = true;
283    int ok = FALSE;
284    int i;
285    bool media_record_exists = false;
286    static const char *barcode_keyword[] = {
287       "barcode",
288       "barcodes",
289       NULL};
290
291
292    memset(&pr, 0, sizeof(pr));
293    if (!open_db(ua)) {
294       return 1;
295    }
296    store = get_storage_resource(ua, 1);
297    if (!store) {
298       return 1;
299    }
300    ua->jcr->store = store;
301
302    if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
303       label_from_barcodes(ua);
304       return 1;
305    }
306
307    /* If relabel get name of Volume to relabel */
308    if (relabel) {
309       /* Check for oldvolume=name */
310       i = find_arg_with_value(ua, "oldvolume"); 
311       if (i >= 0) {
312          memset(&omr, 0, sizeof(omr));
313          bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
314          if (db_get_media_record(ua->jcr, ua->db, &omr)) {
315             goto checkVol;
316          } 
317          bsendmsg(ua, "%s", db_strerror(ua->db));
318       }
319       /* No keyword or Vol not found, ask user to select */
320       if (!select_media_dbr(ua, &omr)) {
321          return 1;
322       }
323
324       /* Require Volume to be Purged or Recycled */
325 checkVol:
326       if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
327          bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
328             omr.VolumeName, omr.VolStatus);
329          return 1;
330       }
331    }
332
333    /* Check for volume=NewVolume */
334    i = find_arg_with_value(ua, "volume");
335    if (i >= 0) {
336       pm_strcpy(&ua->cmd, ua->argv[i]);
337       goto checkName;
338    }
339
340    /* Get a new Volume name */
341    for ( ;; ) {
342       media_record_exists = false;
343       if (!get_cmd(ua, _("Enter new Volume name: "))) {
344          return 1;
345       }
346 checkName:
347       if (!is_volume_name_legal(ua, ua->cmd)) {
348          continue;
349       }
350
351       memset(&mr, 0, sizeof(mr));
352       bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
353       /* If VolBytes are zero the Volume is not labeled */
354       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
355          if (mr.VolBytes != 0) {
356              bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
357                 mr.VolumeName);
358              continue;
359           }
360           media_record_exists = true;
361       }
362       break;                          /* Got it */
363    }
364
365    /* If autochanger, request slot */
366    if (store->autochanger) {
367       i = find_arg_with_value(ua, "slot"); 
368       if (i >= 0) {
369          mr.Slot = atoi(ua->argv[i]);
370       } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
371          return 1;
372       } else {
373          mr.Slot = ua->pint32_val;
374       }
375       mr.InChanger = 1;               /* assumed if we are labeling it */
376    }
377
378    bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
379
380    /* Must select Pool if not already done */
381    if (pr.PoolId == 0) {
382       memset(&pr, 0, sizeof(pr));
383       if (!select_pool_dbr(ua, &pr)) {
384          return 1;
385       }
386    }
387
388
389    ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
390
391    if (ok) {
392       sd = ua->jcr->store_bsock;
393       if (relabel) {
394          /* Delete the old media record */
395          if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
396             bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
397                omr.VolumeName, db_strerror(ua->db));
398          } else {
399             bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
400                omr.VolumeName);
401             /* Update the number of Volumes in the pool */
402             pr.NumVols--;
403             if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
404                bsendmsg(ua, "%s", db_strerror(ua->db));
405             }
406          }
407       }
408       if (ua->automount) {
409          bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
410          bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
411          bash_spaces(dev_name);
412          bnet_fsend(sd, "mount %s", dev_name);
413          unbash_spaces(dev_name);
414          while (bnet_recv(sd) >= 0) {
415             bsendmsg(ua, "%s", sd->msg);
416             /* Here we can get
417              *  3001 OK mount. Device=xxx      or
418              *  3001 Mounted Volume vvvv
419              *  3906 is cannot mount non-tape
420              * So for those, no need to print a reminder
421              */
422             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
423                 strncmp(sd->msg, "3906 ", 5) == 0) {
424                print_reminder = false;
425             }
426          }
427       }
428    }
429    if (print_reminder) {
430       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
431    }
432    close_sd_bsock(ua);
433
434    return 1;
435 }
436
437 /*
438  * Request SD to send us the slot:barcodes, then wiffle
439  *  through them all labeling them.
440  */
441 static void label_from_barcodes(UAContext *ua)
442 {
443    STORE *store = ua->jcr->store;
444    POOL_DBR pr;
445    MEDIA_DBR mr, omr;
446    vol_list_t *vl, *vol_list = NULL;
447    bool media_record_exists;
448    char *slot_list;
449
450    slot_list = (char *)malloc(max_slots);
451    if (!get_user_slot_list(ua, slot_list, max_slots)) {
452       goto bail_out;
453    }
454
455    vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
456
457    if (!vol_list) {
458       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
459       goto bail_out;
460    }
461
462    /* Display list of Volumes and ask if he really wants to proceed */
463    bsendmsg(ua, _("The following Volumes will be labeled:\n"
464                   "Slot  Volume\n"
465                   "==============\n"));
466    for (vl=vol_list; vl; vl=vl->next) {
467       if (!vl->VolName || !slot_list[vl->Slot]) {
468          continue;
469       }
470       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
471    }
472    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
473        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
474       goto bail_out;
475    }
476    /* Select a pool */
477    memset(&pr, 0, sizeof(pr));
478    if (!select_pool_dbr(ua, &pr)) {
479       goto bail_out;
480    }
481    memset(&omr, 0, sizeof(omr));
482
483    /* Fire off the label requests */
484    for (vl=vol_list; vl; vl=vl->next) {
485       if (!vl->VolName || !slot_list[vl->Slot]) {
486          continue;
487       }
488       memset(&mr, 0, sizeof(mr));
489       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
490       media_record_exists = false;
491       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
492           if (mr.VolBytes != 0) {
493              bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
494                 vl->Slot, mr.VolumeName);
495              if (!mr.InChanger) {
496                 mr.InChanger = 1;
497                 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
498                    bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
499                 }
500              }
501              continue;
502           } 
503           media_record_exists = true;
504       }
505       mr.InChanger = 1;
506       /*
507        * Deal with creating cleaning tape here. Normal tapes created in
508        *  send_label_request() below
509        */
510       if (is_cleaning_tape(ua, &mr, &pr)) {
511          if (media_record_exists) {      /* we update it */
512             mr.VolBytes = 1;
513             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
514                 bsendmsg(ua, "%s", db_strerror(ua->db));
515             }
516          } else {                        /* create the media record */
517             set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
518             if (db_create_media_record(ua->jcr, ua->db, &mr)) {
519                bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
520                   mr.VolumeName);
521                pr.NumVols++;          /* this is a bit suspect */
522                if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
523                   bsendmsg(ua, "%s", db_strerror(ua->db));
524                }
525             } else {
526                bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
527             }
528          }
529          continue;                    /* done, go handle next volume */
530       }
531       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
532
533       mr.Slot = vl->Slot;
534       send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
535    }
536
537
538 bail_out:
539    free(slot_list);
540    free_vol_list(vol_list);
541    close_sd_bsock(ua);
542
543    return;
544 }
545
546 /* 
547  * Check if the Volume name has legal characters
548  * If ua is non-NULL send the message
549  */
550 bool is_volume_name_legal(UAContext *ua, const char *name)
551 {
552    int len;
553    const char *p;
554    const char *accept = ":.-_";
555
556    /* Restrict the characters permitted in the Volume name */
557    for (p=name; *p; p++) {
558       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
559          continue;
560       }
561       if (ua) {
562          bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
563       }
564       return 0;
565    }
566    len = strlen(name);
567    if (len >= MAX_NAME_LENGTH) {
568       if (ua) {
569          bsendmsg(ua, _("Volume name too long.\n"));
570       }
571       return 0;
572    }
573    if (len == 0) {
574       if (ua) {
575          bsendmsg(ua, _("Volume name must be at least one character long.\n"));
576       }
577       return 0;
578    }
579    return 1;
580 }
581
582 /*
583  * NOTE! This routine opens the SD socket but leaves it open
584  */
585 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
586                                POOL_DBR *pr, int relabel, bool media_record_exists)
587 {
588    BSOCK *sd;
589    char dev_name[MAX_NAME_LENGTH];
590    bool ok = false;
591
592    if (!(sd=open_sd_bsock(ua))) {
593       return false;
594    }
595    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
596    bash_spaces(dev_name);
597    bash_spaces(mr->VolumeName);
598    bash_spaces(mr->MediaType);
599    bash_spaces(pr->Name);
600    if (relabel) {
601       bash_spaces(omr->VolumeName);
602       bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d", 
603          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
604       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
605          omr->VolumeName, mr->VolumeName);
606    } else {
607       bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d", 
608          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
609       bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
610          mr->VolumeName, mr->Slot);
611       Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
612          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
613    }
614
615    while (bnet_recv(sd) >= 0) {
616       bsendmsg(ua, "%s", sd->msg);
617       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
618          ok = true;
619       } 
620    }
621    unbash_spaces(mr->VolumeName);
622    unbash_spaces(mr->MediaType);
623    unbash_spaces(pr->Name);
624    mr->LabelDate = time(NULL);
625    if (ok) {
626       if (media_record_exists) {      /* we update it */
627          mr->VolBytes = 1;
628          mr->InChanger = 1;
629          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
630              bsendmsg(ua, "%s", db_strerror(ua->db));
631              ok = false;
632          }
633       } else {                        /* create the media record */
634          set_pool_dbr_defaults_in_media_dbr(mr, pr);
635          mr->VolBytes = 1;               /* flag indicating Volume labeled */
636          mr->InChanger = 1;
637          if (db_create_media_record(ua->jcr, ua->db, mr)) {
638             bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
639             mr->VolumeName, mr->Slot);
640             /* Update number of volumes in pool */
641             pr->NumVols++;
642             if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
643                bsendmsg(ua, "%s", db_strerror(ua->db));
644             }
645          } else {
646             bsendmsg(ua, "%s", db_strerror(ua->db));
647             ok = false;
648          }
649       }
650    } else {
651       bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
652    }
653    return ok;
654 }
655
656 static BSOCK *open_sd_bsock(UAContext *ua) 
657 {
658    STORE *store = ua->jcr->store;
659
660    if (!ua->jcr->store_bsock) {
661       bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
662          store->hdr.name, store->address, store->SDport);
663       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
664          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
665          return NULL;
666       }
667    }
668    return ua->jcr->store_bsock;
669 }
670
671 static void close_sd_bsock(UAContext *ua)
672 {
673    if (ua->jcr->store_bsock) {
674       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
675       bnet_close(ua->jcr->store_bsock);
676       ua->jcr->store_bsock = NULL;
677    }
678 }
679
680 static char *get_volume_name_from_SD(UAContext *ua, int Slot) 
681 {
682    STORE *store = ua->jcr->store;
683    BSOCK *sd;
684    char dev_name[MAX_NAME_LENGTH];
685    char *VolName = NULL;
686    int rtn_slot;
687
688    if (!(sd=open_sd_bsock(ua))) {
689       bsendmsg(ua, _("Could not open SD socket.\n"));
690       return NULL;
691    }
692    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
693    bash_spaces(dev_name);
694    /* Ask for autochanger list of volumes */
695    bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
696    Dmsg1(100, "Sent: %s", sd->msg);
697
698    /* Get Volume name in this Slot */
699    while (bnet_recv(sd) >= 0) {
700       bsendmsg(ua, "%s", sd->msg);
701       Dmsg1(100, "Got: %s", sd->msg);
702       if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
703          VolName = (char *)malloc(sd->msglen);
704          if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
705             break;
706          }
707          free(VolName);
708          VolName = NULL;
709       }
710    }
711    close_sd_bsock(ua);
712    Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
713    return VolName;
714 }
715
716 /*
717  * We get the slot list from the Storage daemon.
718  *  If scan is set, we return all slots found,
719  *  otherwise, we return only slots with valid barcodes (Volume names)
720  */
721 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) 
722 {
723    STORE *store = ua->jcr->store;
724    char dev_name[MAX_NAME_LENGTH];
725    BSOCK *sd;
726    vol_list_t *vl;
727    vol_list_t *vol_list = NULL;
728
729
730    if (!(sd=open_sd_bsock(ua))) {
731       return NULL;
732    }
733
734    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
735    bash_spaces(dev_name);
736    /* Ask for autochanger list of volumes */
737    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
738
739    /* Read and organize list of Volumes */
740    while (bnet_recv(sd) >= 0) {
741       char *p;
742       int Slot;
743       strip_trailing_junk(sd->msg);
744
745       /* Check for returned SD messages */
746       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
747           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
748           sd->msg[4] == ' ') {
749          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
750          continue;
751       }
752
753       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
754       p = strchr(sd->msg, ':');
755       if (scan && p) {
756          /* Scanning -- require only valid slot */
757          Slot = atoi(sd->msg);
758          if (Slot <= 0) {
759             p--;
760             *p = ':';
761             bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
762             continue;
763          }
764       } else {
765          /* Not scanning */
766          if (p && strlen(p) > 1) {
767             *p++ = 0;
768             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
769                p--;
770                *p = ':';
771                bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
772                continue;
773             }
774          } else {
775             continue;
776          }
777          if (!is_volume_name_legal(ua, p)) {
778             p--;
779             *p = ':';
780             bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg); 
781             continue;
782          }
783       }
784
785       /* Add Slot and VolumeName to list */
786       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
787       vl->Slot = Slot;
788       if (p) {
789          if (*p == ':') {
790             p++;                      /* skip separator */
791          }
792          vl->VolName = bstrdup(p);
793       } else {
794          vl->VolName = NULL;
795       }
796       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
797       if (!vol_list) {
798          vl->next = vol_list;
799          vol_list = vl;
800       } else {
801          /* Add new entry to end of list */
802          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
803             if (!tvl->next) {
804                tvl->next = vl;
805                vl->next = NULL;
806                break;
807             }
808          }
809       }
810    }
811    close_sd_bsock(ua);
812    return vol_list;
813 }
814
815 static void free_vol_list(vol_list_t *vol_list)
816 {
817    vol_list_t *vl;
818
819    /* Free list */
820    for (vl=vol_list; vl; ) {
821       vol_list_t *ovl;
822       if (vl->VolName) {
823          free(vl->VolName);
824       }
825       ovl = vl;
826       vl = vl->next;
827       free(ovl);
828    }
829 }
830
831
832 /*
833  * Check if this is a cleaning tape by comparing the Volume name
834  *  with the Cleaning Prefix. If they match, this is a cleaning 
835  *  tape.
836  */
837 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
838 {
839    /* Find Pool resource */
840    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
841    if (!ua->jcr->pool) {
842       bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
843       return true;
844    }
845    if (ua->jcr->pool->cleaning_prefix == NULL) {
846       return false;
847    }
848    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
849       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
850       strlen(ua->jcr->pool->cleaning_prefix), 
851       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
852                   strlen(ua->jcr->pool->cleaning_prefix)));
853    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
854                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
855 }