]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Add Peter Eriksson's const code + turn bsscanf code
[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 int 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\n"), 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          if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
395             bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
396                omr.VolumeName, db_strerror(ua->db));
397          } else {
398             bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
399                omr.VolumeName);
400          }
401       }
402       if (ua->automount) {
403          bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
404          bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
405          bash_spaces(dev_name);
406          bnet_fsend(sd, "mount %s", dev_name);
407          unbash_spaces(dev_name);
408          while (bnet_recv(sd) >= 0) {
409             bsendmsg(ua, "%s", sd->msg);
410             /* Here we can get
411              *  3001 OK mount. Device=xxx      or
412              *  3001 Mounted Volume vvvv
413              *  3906 is cannot mount non-tape
414              * So for those, no need to print a reminder
415              */
416             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
417                 strncmp(sd->msg, "3906 ", 5) == 0) {
418                print_reminder = false;
419             }
420          }
421       }
422    }
423    if (print_reminder) {
424       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
425    }
426    close_sd_bsock(ua);
427
428    return 1;
429 }
430
431 /*
432  * Request SD to send us the slot:barcodes, then wiffle
433  *  through them all labeling them.
434  */
435 static void label_from_barcodes(UAContext *ua)
436 {
437    STORE *store = ua->jcr->store;
438    POOL_DBR pr;
439    MEDIA_DBR mr, omr;
440    vol_list_t *vl, *vol_list = NULL;
441    bool media_record_exists;
442    char *slot_list;
443
444    slot_list = (char *)malloc(max_slots);
445    if (!get_user_slot_list(ua, slot_list, max_slots)) {
446       goto bail_out;
447    }
448
449    vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
450
451    if (!vol_list) {
452       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
453       goto bail_out;
454    }
455
456    /* Display list of Volumes and ask if he really wants to proceed */
457    bsendmsg(ua, _("The following Volumes will be labeled:\n"
458                   "Slot  Volume\n"
459                   "==============\n"));
460    for (vl=vol_list; vl; vl=vl->next) {
461       if (!vl->VolName || !slot_list[vl->Slot]) {
462          continue;
463       }
464       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
465    }
466    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
467        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
468       goto bail_out;
469    }
470    /* Select a pool */
471    memset(&pr, 0, sizeof(pr));
472    if (!select_pool_dbr(ua, &pr)) {
473       goto bail_out;
474    }
475    memset(&omr, 0, sizeof(omr));
476
477    /* Fire off the label requests */
478    for (vl=vol_list; vl; vl=vl->next) {
479       if (!vl->VolName || !slot_list[vl->Slot]) {
480          continue;
481       }
482       memset(&mr, 0, sizeof(mr));
483       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
484       media_record_exists = false;
485       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
486           if (mr.VolBytes != 0) {
487              bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
488                 vl->Slot, mr.VolumeName);
489              if (!mr.InChanger) {
490                 mr.InChanger = 1;
491                 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
492                    bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
493                 }
494              }
495              continue;
496           } 
497           media_record_exists = true;
498       }
499       mr.InChanger = 1;
500       /*
501        * Deal with creating cleaning tape here. Normal tapes created in
502        *  send_label_request() below
503        */
504       if (is_cleaning_tape(ua, &mr, &pr)) {
505          if (media_record_exists) {      /* we update it */
506             mr.VolBytes = 1;
507             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
508                 bsendmsg(ua, "%s", db_strerror(ua->db));
509             }
510          } else {                        /* create the media record */
511             set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
512             if (db_create_media_record(ua->jcr, ua->db, &mr)) {
513                bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
514                   mr.VolumeName);
515             } else {
516                bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
517             }
518          }
519          continue;                    /* done, go handle next volume */
520       }
521       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
522
523       mr.Slot = vl->Slot;
524       send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
525    }
526
527
528 bail_out:
529    free(slot_list);
530    free_vol_list(vol_list);
531    close_sd_bsock(ua);
532
533    return;
534 }
535
536 /* 
537  * Check if the Volume name has legal characters
538  * If ua is non-NULL send the message
539  */
540 bool is_volume_name_legal(UAContext *ua, const char *name)
541 {
542    int len;
543    const char *p;
544    const char *accept = ":.-_";
545
546    /* Restrict the characters permitted in the Volume name */
547    for (p=name; *p; p++) {
548       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
549          continue;
550       }
551       if (ua) {
552          bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
553       }
554       return 0;
555    }
556    len = strlen(name);
557    if (len >= MAX_NAME_LENGTH) {
558       if (ua) {
559          bsendmsg(ua, _("Volume name too long.\n"));
560       }
561       return 0;
562    }
563    if (len == 0) {
564       if (ua) {
565          bsendmsg(ua, _("Volume name must be at least one character long.\n"));
566       }
567       return 0;
568    }
569    return 1;
570 }
571
572 /*
573  * NOTE! This routine opens the SD socket but leaves it open
574  */
575 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
576                               POOL_DBR *pr, int relabel, bool media_record_exists)
577 {
578    BSOCK *sd;
579    char dev_name[MAX_NAME_LENGTH];
580    int ok = FALSE;
581
582    if (!(sd=open_sd_bsock(ua))) {
583       return 0;
584    }
585    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
586    bash_spaces(dev_name);
587    bash_spaces(mr->VolumeName);
588    bash_spaces(mr->MediaType);
589    bash_spaces(pr->Name);
590    if (relabel) {
591       bash_spaces(omr->VolumeName);
592       bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d", 
593          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
594       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
595          omr->VolumeName, mr->VolumeName);
596    } else {
597       bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d", 
598          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
599       bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
600          mr->VolumeName, mr->Slot);
601       Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
602          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
603    }
604
605    while (bnet_recv(sd) >= 0) {
606       bsendmsg(ua, "%s", sd->msg);
607       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
608          ok = TRUE;
609       } 
610    }
611    unbash_spaces(mr->VolumeName);
612    unbash_spaces(mr->MediaType);
613    unbash_spaces(pr->Name);
614    mr->LabelDate = time(NULL);
615    if (ok) {
616       if (media_record_exists) {      /* we update it */
617          mr->VolBytes = 1;
618          mr->InChanger = 1;
619          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
620              bsendmsg(ua, "%s", db_strerror(ua->db));
621              ok = FALSE;
622          }
623       } else {                        /* create the media record */
624          set_pool_dbr_defaults_in_media_dbr(mr, pr);
625          mr->VolBytes = 1;               /* flag indicating Volume labeled */
626          mr->InChanger = 1;
627          if (db_create_media_record(ua->jcr, ua->db, mr)) {
628             bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
629             mr->VolumeName, mr->Slot);
630          } else {
631             bsendmsg(ua, "%s", db_strerror(ua->db));
632             ok = FALSE;
633          }
634       }
635    } else {
636       bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
637    }
638    return ok;
639 }
640
641 static BSOCK *open_sd_bsock(UAContext *ua) 
642 {
643    STORE *store = ua->jcr->store;
644
645    if (!ua->jcr->store_bsock) {
646       bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
647          store->hdr.name, store->address, store->SDport);
648       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
649          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
650          return NULL;
651       }
652    }
653    return ua->jcr->store_bsock;
654 }
655
656 static void close_sd_bsock(UAContext *ua)
657 {
658    if (ua->jcr->store_bsock) {
659       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
660       bnet_close(ua->jcr->store_bsock);
661       ua->jcr->store_bsock = NULL;
662    }
663 }
664
665 static char *get_volume_name_from_SD(UAContext *ua, int Slot) 
666 {
667    STORE *store = ua->jcr->store;
668    BSOCK *sd;
669    char dev_name[MAX_NAME_LENGTH];
670    char *VolName = NULL;
671    int rtn_slot;
672
673    if (!(sd=open_sd_bsock(ua))) {
674       bsendmsg(ua, _("Could not open SD socket.\n"));
675       return NULL;
676    }
677    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
678    bash_spaces(dev_name);
679    /* Ask for autochanger list of volumes */
680    bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
681    Dmsg1(100, "Sent: %s", sd->msg);
682
683    /* Get Volume name in this Slot */
684    while (bnet_recv(sd) >= 0) {
685       bsendmsg(ua, "%s", sd->msg);
686       Dmsg1(100, "Got: %s", sd->msg);
687       if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
688          VolName = (char *)malloc(sd->msglen);
689          if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
690             break;
691          }
692          free(VolName);
693          VolName = NULL;
694       }
695    }
696    close_sd_bsock(ua);
697    Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
698    return VolName;
699 }
700
701 /*
702  * We get the slot list from the Storage daemon.
703  *  If scan is set, we return all slots found,
704  *  otherwise, we return only slots with valid barcodes (Volume names)
705  */
706 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) 
707 {
708    STORE *store = ua->jcr->store;
709    char dev_name[MAX_NAME_LENGTH];
710    BSOCK *sd;
711    vol_list_t *vl;
712    vol_list_t *vol_list = NULL;
713
714
715    if (!(sd=open_sd_bsock(ua))) {
716       return NULL;
717    }
718
719    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
720    bash_spaces(dev_name);
721    /* Ask for autochanger list of volumes */
722    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
723
724    /* Read and organize list of Volumes */
725    while (bnet_recv(sd) >= 0) {
726       char *p;
727       int Slot;
728       strip_trailing_junk(sd->msg);
729
730       /* Check for returned SD messages */
731       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
732           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
733           sd->msg[4] == ' ') {
734          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
735          continue;
736       }
737
738       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
739       p = strchr(sd->msg, ':');
740       if (scan && p) {
741          /* Scanning -- require only valid slot */
742          Slot = atoi(sd->msg);
743          if (Slot <= 0) {
744             p--;
745             *p = ':';
746             bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
747             continue;
748          }
749       } else {
750          /* Not scanning */
751          if (p && strlen(p) > 1) {
752             *p++ = 0;
753             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
754                p--;
755                *p = ':';
756                bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
757                continue;
758             }
759          } else {
760             continue;
761          }
762          if (!is_volume_name_legal(ua, p)) {
763             p--;
764             *p = ':';
765             bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg); 
766             continue;
767          }
768       }
769
770       /* Add Slot and VolumeName to list */
771       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
772       vl->Slot = Slot;
773       if (p) {
774          if (*p == ':') {
775             p++;                      /* skip separator */
776          }
777          vl->VolName = bstrdup(p);
778       } else {
779          vl->VolName = NULL;
780       }
781       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
782       if (!vol_list) {
783          vl->next = vol_list;
784          vol_list = vl;
785       } else {
786          /* Add new entry to end of list */
787          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
788             if (!tvl->next) {
789                tvl->next = vl;
790                vl->next = NULL;
791                break;
792             }
793          }
794       }
795    }
796    close_sd_bsock(ua);
797    return vol_list;
798 }
799
800 static void free_vol_list(vol_list_t *vol_list)
801 {
802    vol_list_t *vl;
803
804    /* Free list */
805    for (vl=vol_list; vl; ) {
806       vol_list_t *ovl;
807       if (vl->VolName) {
808          free(vl->VolName);
809       }
810       ovl = vl;
811       vl = vl->next;
812       free(ovl);
813    }
814 }
815
816
817 /*
818  * Check if this is a cleaning tape by comparing the Volume name
819  *  with the Cleaning Prefix. If they match, this is a cleaning 
820  *  tape.
821  */
822 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
823 {
824    /* Find Pool resource */
825    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
826    if (!ua->jcr->pool) {
827       bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
828       return true;
829    }
830    if (ua->jcr->pool->cleaning_prefix == NULL) {
831       return false;
832    }
833    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
834       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
835       strlen(ua->jcr->pool->cleaning_prefix), 
836       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
837                   strlen(ua->jcr->pool->cleaning_prefix)));
838    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
839                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
840 }