]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Fix new FileSet exclusion
[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    db_lock(ua->db);
252    for (int i=1; i<max_slots; i++) {
253       if (slot_list[i]) {
254          mr.Slot = i;
255          /* Set InChanger to zero for this Slot */
256          db_make_inchanger_unique(ua->jcr, ua->db, &mr);
257       }
258    }
259    db_unlock(ua->db);
260       
261 bail_out:
262
263    free_vol_list(vol_list);
264    free(slot_list);
265    close_sd_bsock(ua);
266
267    return 1;
268 }
269
270
271 /*
272  * Common routine for both label and relabel
273  */
274 static int do_label(UAContext *ua, const char *cmd, int relabel)
275 {
276    STORE *store;
277    BSOCK *sd;
278    char dev_name[MAX_NAME_LENGTH];
279    MEDIA_DBR mr, omr;
280    POOL_DBR pr;
281    bool print_reminder = true;
282    int ok = FALSE;
283    int i;
284    bool media_record_exists = false;
285    static const char *barcode_keyword[] = {
286       "barcode",
287       "barcodes",
288       NULL};
289
290
291    memset(&pr, 0, sizeof(pr));
292    if (!open_db(ua)) {
293       return 1;
294    }
295    store = get_storage_resource(ua, 1);
296    if (!store) {
297       return 1;
298    }
299    ua->jcr->store = store;
300
301    if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
302       label_from_barcodes(ua);
303       return 1;
304    }
305
306    /* If relabel get name of Volume to relabel */
307    if (relabel) {
308       /* Check for oldvolume=name */
309       i = find_arg_with_value(ua, "oldvolume"); 
310       if (i >= 0) {
311          memset(&omr, 0, sizeof(omr));
312          bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
313          if (db_get_media_record(ua->jcr, ua->db, &omr)) {
314             goto checkVol;
315          } 
316          bsendmsg(ua, "%s", db_strerror(ua->db));
317       }
318       /* No keyword or Vol not found, ask user to select */
319       if (!select_media_dbr(ua, &omr)) {
320          return 1;
321       }
322
323       /* Require Volume to be Purged or Recycled */
324 checkVol:
325       if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
326          bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
327             omr.VolumeName, omr.VolStatus);
328          return 1;
329       }
330    }
331
332    /* Check for volume=NewVolume */
333    i = find_arg_with_value(ua, "volume");
334    if (i >= 0) {
335       pm_strcpy(&ua->cmd, ua->argv[i]);
336       goto checkName;
337    }
338
339    /* Get a new Volume name */
340    for ( ;; ) {
341       media_record_exists = false;
342       if (!get_cmd(ua, _("Enter new Volume name: "))) {
343          return 1;
344       }
345 checkName:
346       if (!is_volume_name_legal(ua, ua->cmd)) {
347          continue;
348       }
349
350       memset(&mr, 0, sizeof(mr));
351       bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
352       /* If VolBytes are zero the Volume is not labeled */
353       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
354          if (mr.VolBytes != 0) {
355              bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
356                 mr.VolumeName);
357              continue;
358           }
359           media_record_exists = true;
360       }
361       break;                          /* Got it */
362    }
363
364    /* If autochanger, request slot */
365    if (store->autochanger) {
366       i = find_arg_with_value(ua, "slot"); 
367       if (i >= 0) {
368          mr.Slot = atoi(ua->argv[i]);
369       } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
370          return 1;
371       } else {
372          mr.Slot = ua->pint32_val;
373       }
374       mr.InChanger = 1;               /* assumed if we are labeling it */
375    }
376
377    bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
378
379    /* Must select Pool if not already done */
380    if (pr.PoolId == 0) {
381       memset(&pr, 0, sizeof(pr));
382       if (!select_pool_dbr(ua, &pr)) {
383          return 1;
384       }
385    }
386
387
388    ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
389
390    if (ok) {
391       sd = ua->jcr->store_bsock;
392       if (relabel) {
393          /* Delete the old media record */
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             /* Update the number of Volumes in the pool */
401             pr.NumVols--;
402             if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
403                bsendmsg(ua, "%s", db_strerror(ua->db));
404             }
405          }
406       }
407       if (ua->automount) {
408          bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
409          bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
410          bash_spaces(dev_name);
411          bnet_fsend(sd, "mount %s", dev_name);
412          unbash_spaces(dev_name);
413          while (bnet_recv(sd) >= 0) {
414             bsendmsg(ua, "%s", sd->msg);
415             /* Here we can get
416              *  3001 OK mount. Device=xxx      or
417              *  3001 Mounted Volume vvvv
418              *  3906 is cannot mount non-tape
419              * So for those, no need to print a reminder
420              */
421             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
422                 strncmp(sd->msg, "3906 ", 5) == 0) {
423                print_reminder = false;
424             }
425          }
426       }
427    }
428    if (print_reminder) {
429       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
430    }
431    close_sd_bsock(ua);
432
433    return 1;
434 }
435
436 /*
437  * Request SD to send us the slot:barcodes, then wiffle
438  *  through them all labeling them.
439  */
440 static void label_from_barcodes(UAContext *ua)
441 {
442    STORE *store = ua->jcr->store;
443    POOL_DBR pr;
444    MEDIA_DBR mr, omr;
445    vol_list_t *vl, *vol_list = NULL;
446    bool media_record_exists;
447    char *slot_list;
448
449    slot_list = (char *)malloc(max_slots);
450    if (!get_user_slot_list(ua, slot_list, max_slots)) {
451       goto bail_out;
452    }
453
454    vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
455
456    if (!vol_list) {
457       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
458       goto bail_out;
459    }
460
461    /* Display list of Volumes and ask if he really wants to proceed */
462    bsendmsg(ua, _("The following Volumes will be labeled:\n"
463                   "Slot  Volume\n"
464                   "==============\n"));
465    for (vl=vol_list; vl; vl=vl->next) {
466       if (!vl->VolName || !slot_list[vl->Slot]) {
467          continue;
468       }
469       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
470    }
471    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
472        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
473       goto bail_out;
474    }
475    /* Select a pool */
476    memset(&pr, 0, sizeof(pr));
477    if (!select_pool_dbr(ua, &pr)) {
478       goto bail_out;
479    }
480    memset(&omr, 0, sizeof(omr));
481
482    /* Fire off the label requests */
483    for (vl=vol_list; vl; vl=vl->next) {
484       if (!vl->VolName || !slot_list[vl->Slot]) {
485          continue;
486       }
487       memset(&mr, 0, sizeof(mr));
488       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
489       media_record_exists = false;
490       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
491           if (mr.VolBytes != 0) {
492              bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
493                 vl->Slot, mr.VolumeName);
494              if (!mr.InChanger) {
495                 mr.InChanger = 1;
496                 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
497                    bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
498                 }
499              }
500              continue;
501           } 
502           media_record_exists = true;
503       }
504       mr.InChanger = 1;
505       /*
506        * Deal with creating cleaning tape here. Normal tapes created in
507        *  send_label_request() below
508        */
509       if (is_cleaning_tape(ua, &mr, &pr)) {
510          if (media_record_exists) {      /* we update it */
511             mr.VolBytes = 1;
512             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
513                 bsendmsg(ua, "%s", db_strerror(ua->db));
514             }
515          } else {                        /* create the media record */
516             set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
517             if (db_create_media_record(ua->jcr, ua->db, &mr)) {
518                bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
519                   mr.VolumeName);
520                pr.NumVols++;          /* this is a bit suspect */
521                if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
522                   bsendmsg(ua, "%s", db_strerror(ua->db));
523                }
524             } else {
525                bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
526             }
527          }
528          continue;                    /* done, go handle next volume */
529       }
530       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
531
532       mr.Slot = vl->Slot;
533       send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
534    }
535
536
537 bail_out:
538    free(slot_list);
539    free_vol_list(vol_list);
540    close_sd_bsock(ua);
541
542    return;
543 }
544
545 /* 
546  * Check if the Volume name has legal characters
547  * If ua is non-NULL send the message
548  */
549 bool is_volume_name_legal(UAContext *ua, const char *name)
550 {
551    int len;
552    const char *p;
553    const char *accept = ":.-_";
554
555    /* Restrict the characters permitted in the Volume name */
556    for (p=name; *p; p++) {
557       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
558          continue;
559       }
560       if (ua) {
561          bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
562       }
563       return 0;
564    }
565    len = strlen(name);
566    if (len >= MAX_NAME_LENGTH) {
567       if (ua) {
568          bsendmsg(ua, _("Volume name too long.\n"));
569       }
570       return 0;
571    }
572    if (len == 0) {
573       if (ua) {
574          bsendmsg(ua, _("Volume name must be at least one character long.\n"));
575       }
576       return 0;
577    }
578    return 1;
579 }
580
581 /*
582  * NOTE! This routine opens the SD socket but leaves it open
583  */
584 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
585                                POOL_DBR *pr, int relabel, bool media_record_exists)
586 {
587    BSOCK *sd;
588    char dev_name[MAX_NAME_LENGTH];
589    bool ok = false;
590
591    if (!(sd=open_sd_bsock(ua))) {
592       return false;
593    }
594    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
595    bash_spaces(dev_name);
596    bash_spaces(mr->VolumeName);
597    bash_spaces(mr->MediaType);
598    bash_spaces(pr->Name);
599    if (relabel) {
600       bash_spaces(omr->VolumeName);
601       bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d", 
602          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
603       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
604          omr->VolumeName, mr->VolumeName);
605    } else {
606       bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d", 
607          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
608       bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
609          mr->VolumeName, mr->Slot);
610       Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
611          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
612    }
613
614    while (bnet_recv(sd) >= 0) {
615       bsendmsg(ua, "%s", sd->msg);
616       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
617          ok = true;
618       } 
619    }
620    unbash_spaces(mr->VolumeName);
621    unbash_spaces(mr->MediaType);
622    unbash_spaces(pr->Name);
623    mr->LabelDate = time(NULL);
624    if (ok) {
625       if (media_record_exists) {      /* we update it */
626          mr->VolBytes = 1;
627          mr->InChanger = 1;
628          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
629              bsendmsg(ua, "%s", db_strerror(ua->db));
630              ok = false;
631          }
632       } else {                        /* create the media record */
633          set_pool_dbr_defaults_in_media_dbr(mr, pr);
634          mr->VolBytes = 1;               /* flag indicating Volume labeled */
635          mr->InChanger = 1;
636          if (db_create_media_record(ua->jcr, ua->db, mr)) {
637             bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
638             mr->VolumeName, mr->Slot);
639             /* Update number of volumes in pool */
640             pr->NumVols++;
641             if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
642                bsendmsg(ua, "%s", db_strerror(ua->db));
643             }
644          } else {
645             bsendmsg(ua, "%s", db_strerror(ua->db));
646             ok = false;
647          }
648       }
649    } else {
650       bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
651    }
652    return ok;
653 }
654
655 static BSOCK *open_sd_bsock(UAContext *ua) 
656 {
657    STORE *store = ua->jcr->store;
658
659    if (!ua->jcr->store_bsock) {
660       bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
661          store->hdr.name, store->address, store->SDport);
662       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
663          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
664          return NULL;
665       }
666    }
667    return ua->jcr->store_bsock;
668 }
669
670 static void close_sd_bsock(UAContext *ua)
671 {
672    if (ua->jcr->store_bsock) {
673       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
674       bnet_close(ua->jcr->store_bsock);
675       ua->jcr->store_bsock = NULL;
676    }
677 }
678
679 static char *get_volume_name_from_SD(UAContext *ua, int Slot) 
680 {
681    STORE *store = ua->jcr->store;
682    BSOCK *sd;
683    char dev_name[MAX_NAME_LENGTH];
684    char *VolName = NULL;
685    int rtn_slot;
686
687    if (!(sd=open_sd_bsock(ua))) {
688       bsendmsg(ua, _("Could not open SD socket.\n"));
689       return NULL;
690    }
691    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
692    bash_spaces(dev_name);
693    /* Ask for autochanger list of volumes */
694    bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
695    Dmsg1(100, "Sent: %s", sd->msg);
696
697    /* Get Volume name in this Slot */
698    while (bnet_recv(sd) >= 0) {
699       bsendmsg(ua, "%s", sd->msg);
700       Dmsg1(100, "Got: %s", sd->msg);
701       if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
702          VolName = (char *)malloc(sd->msglen);
703          if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
704             break;
705          }
706          free(VolName);
707          VolName = NULL;
708       }
709    }
710    close_sd_bsock(ua);
711    Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
712    return VolName;
713 }
714
715 /*
716  * We get the slot list from the Storage daemon.
717  *  If scan is set, we return all slots found,
718  *  otherwise, we return only slots with valid barcodes (Volume names)
719  */
720 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) 
721 {
722    STORE *store = ua->jcr->store;
723    char dev_name[MAX_NAME_LENGTH];
724    BSOCK *sd;
725    vol_list_t *vl;
726    vol_list_t *vol_list = NULL;
727
728
729    if (!(sd=open_sd_bsock(ua))) {
730       return NULL;
731    }
732
733    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
734    bash_spaces(dev_name);
735    /* Ask for autochanger list of volumes */
736    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
737
738    /* Read and organize list of Volumes */
739    while (bnet_recv(sd) >= 0) {
740       char *p;
741       int Slot;
742       strip_trailing_junk(sd->msg);
743
744       /* Check for returned SD messages */
745       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
746           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
747           sd->msg[4] == ' ') {
748          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
749          continue;
750       }
751
752       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
753       p = strchr(sd->msg, ':');
754       if (scan && p) {
755          /* Scanning -- require only valid slot */
756          Slot = atoi(sd->msg);
757          if (Slot <= 0) {
758             p--;
759             *p = ':';
760             bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
761             continue;
762          }
763       } else {
764          /* Not scanning */
765          if (p && strlen(p) > 1) {
766             *p++ = 0;
767             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
768                p--;
769                *p = ':';
770                bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
771                continue;
772             }
773          } else {
774             continue;
775          }
776          if (!is_volume_name_legal(ua, p)) {
777             p--;
778             *p = ':';
779             bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg); 
780             continue;
781          }
782       }
783
784       /* Add Slot and VolumeName to list */
785       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
786       vl->Slot = Slot;
787       if (p) {
788          if (*p == ':') {
789             p++;                      /* skip separator */
790          }
791          vl->VolName = bstrdup(p);
792       } else {
793          vl->VolName = NULL;
794       }
795       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
796       if (!vol_list) {
797          vl->next = vol_list;
798          vol_list = vl;
799       } else {
800          /* Add new entry to end of list */
801          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
802             if (!tvl->next) {
803                tvl->next = vl;
804                vl->next = NULL;
805                break;
806             }
807          }
808       }
809    }
810    close_sd_bsock(ua);
811    return vol_list;
812 }
813
814 static void free_vol_list(vol_list_t *vol_list)
815 {
816    vol_list_t *vl;
817
818    /* Free list */
819    for (vl=vol_list; vl; ) {
820       vol_list_t *ovl;
821       if (vl->VolName) {
822          free(vl->VolName);
823       }
824       ovl = vl;
825       vl = vl->next;
826       free(ovl);
827    }
828 }
829
830
831 /*
832  * Check if this is a cleaning tape by comparing the Volume name
833  *  with the Cleaning Prefix. If they match, this is a cleaning 
834  *  tape.
835  */
836 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
837 {
838    /* Find Pool resource */
839    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
840    if (!ua->jcr->pool) {
841       bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
842       return true;
843    }
844    if (ua->jcr->pool->cleaning_prefix == NULL) {
845       return false;
846    }
847    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
848       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
849       strlen(ua->jcr->pool->cleaning_prefix), 
850       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
851                   strlen(ua->jcr->pool->cleaning_prefix)));
852    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
853                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
854 }