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