]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Fix uninitialized stack variable + seg fault in label + PoolId in InChanger clear
[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 /*
551  * NOTE! This routine opens the SD socket but leaves it open
552  */
553 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
554                               POOL_DBR *pr, int relabel, bool media_record_exists)
555 {
556    BSOCK *sd;
557    char dev_name[MAX_NAME_LENGTH];
558    int ok = FALSE;
559
560    if (!(sd=open_sd_bsock(ua))) {
561       return 0;
562    }
563    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
564    bash_spaces(dev_name);
565    bash_spaces(mr->VolumeName);
566    bash_spaces(mr->MediaType);
567    bash_spaces(pr->Name);
568    if (relabel) {
569       bash_spaces(omr->VolumeName);
570       bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d", 
571          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
572       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
573          omr->VolumeName, mr->VolumeName);
574    } else {
575       bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d", 
576          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
577       bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
578          mr->VolumeName, mr->Slot);
579       Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
580          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
581    }
582
583    while (bnet_recv(sd) >= 0) {
584       bsendmsg(ua, "%s", sd->msg);
585       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
586          ok = TRUE;
587       } 
588    }
589    unbash_spaces(mr->VolumeName);
590    unbash_spaces(mr->MediaType);
591    unbash_spaces(pr->Name);
592    mr->LabelDate = time(NULL);
593    if (ok) {
594       if (media_record_exists) {      /* we update it */
595          mr->VolBytes = 1;
596          mr->InChanger = 1;
597          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
598              bsendmsg(ua, "%s", db_strerror(ua->db));
599              ok = FALSE;
600          }
601       } else {                        /* create the media record */
602          set_pool_dbr_defaults_in_media_dbr(mr, pr);
603          mr->VolBytes = 1;               /* flag indicating Volume labeled */
604          mr->InChanger = 1;
605          if (db_create_media_record(ua->jcr, ua->db, mr)) {
606             bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
607             mr->VolumeName, mr->Slot);
608          } else {
609             bsendmsg(ua, "%s", db_strerror(ua->db));
610             ok = FALSE;
611          }
612       }
613    } else {
614       bsendmsg(ua, _("Label command failed.\n"));
615    }
616    return ok;
617 }
618
619 static BSOCK *open_sd_bsock(UAContext *ua) 
620 {
621    STORE *store = ua->jcr->store;
622
623    if (!ua->jcr->store_bsock) {
624       bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
625          store->hdr.name, store->address, store->SDport);
626       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
627          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
628          return NULL;
629       }
630    }
631    return ua->jcr->store_bsock;
632 }
633
634 static void close_sd_bsock(UAContext *ua)
635 {
636    if (ua->jcr->store_bsock) {
637       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
638       bnet_close(ua->jcr->store_bsock);
639       ua->jcr->store_bsock = NULL;
640    }
641 }
642
643 static char *get_volume_name_from_SD(UAContext *ua, int Slot) 
644 {
645    STORE *store = ua->jcr->store;
646    BSOCK *sd;
647    char dev_name[MAX_NAME_LENGTH];
648    char *VolName = NULL;
649    int rtn_slot;
650
651    if (!(sd=open_sd_bsock(ua))) {
652       bsendmsg(ua, _("Could not open SD socket.\n"));
653       return NULL;
654    }
655    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
656    bash_spaces(dev_name);
657    /* Ask for autochanger list of volumes */
658    bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
659    Dmsg1(100, "Sent: %s", sd->msg);
660
661    /* Get Volume name in this Slot */
662    while (bnet_recv(sd) >= 0) {
663       bsendmsg(ua, "%s", sd->msg);
664       Dmsg1(100, "Got: %s", sd->msg);
665       if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
666          VolName = (char *)malloc(sd->msglen);
667          if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
668             break;
669          }
670          free(VolName);
671          VolName = NULL;
672       }
673    }
674    close_sd_bsock(ua);
675    Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
676    return VolName;
677 }
678
679 /*
680  * We get the slot list from the Storage daemon.
681  *  If scan is set, we return all slots found,
682  *  otherwise, we return only slots with valid barcodes (Volume names)
683  */
684 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) 
685 {
686    STORE *store = ua->jcr->store;
687    char dev_name[MAX_NAME_LENGTH];
688    BSOCK *sd;
689    vol_list_t *vl;
690    vol_list_t *vol_list = NULL;
691
692
693    if (!(sd=open_sd_bsock(ua))) {
694       return NULL;
695    }
696
697    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
698    bash_spaces(dev_name);
699    /* Ask for autochanger list of volumes */
700    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
701
702    /* Read and organize list of Volumes */
703    while (bnet_recv(sd) >= 0) {
704       char *p;
705       int Slot;
706       strip_trailing_junk(sd->msg);
707
708       /* Check for returned SD messages */
709       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
710           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
711           sd->msg[4] == ' ') {
712          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
713          continue;
714       }
715
716       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
717       p = strchr(sd->msg, ':');
718       if (scan && p) {
719          /* Scanning -- require only valid slot */
720          Slot = atoi(sd->msg);
721          if (Slot <= 0) {
722             p--;
723             *p = ':';
724             bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
725             continue;
726          }
727       } else {
728          /* Not scanning */
729          if (p && strlen(p) > 1) {
730             *p++ = 0;
731             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
732                p--;
733                *p = ':';
734                bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg); 
735                continue;
736             }
737          } else {
738             continue;
739          }
740          if (!is_volume_name_legal(ua, p)) {
741             p--;
742             *p = ':';
743             bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg); 
744             continue;
745          }
746       }
747
748       /* Add Slot and VolumeName to list */
749       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
750       vl->Slot = Slot;
751       if (p) {
752          if (*p == ':') {
753             p++;                      /* skip separator */
754          }
755          vl->VolName = bstrdup(p);
756       } else {
757          vl->VolName = NULL;
758       }
759       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
760       if (!vol_list) {
761          vl->next = vol_list;
762          vol_list = vl;
763       } else {
764          /* Add new entry to end of list */
765          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
766             if (!tvl->next) {
767                tvl->next = vl;
768                vl->next = NULL;
769                break;
770             }
771          }
772       }
773    }
774    close_sd_bsock(ua);
775    return vol_list;
776 }
777
778 static void free_vol_list(vol_list_t *vol_list)
779 {
780    vol_list_t *vl;
781    /* Free list */
782    for (vl=vol_list; vl; ) {
783       vol_list_t *ovl;
784       if (vl->VolName) {
785          free(vl->VolName);
786       }
787       ovl = vl;
788       vl = vl->next;
789       free(ovl);
790    }
791 }
792
793
794 /*
795  * Check if this is a cleaning tape by comparing the Volume name
796  *  with the Cleaning Prefix. If they match, this is a cleaning 
797  *  tape.
798  */
799 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
800 {
801    /* Find Pool resource */
802    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
803    if (!ua->jcr->pool) {
804       bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
805       return true;
806    }
807    if (ua->jcr->pool->cleaning_prefix == NULL) {
808       return false;
809    }
810    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
811       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
812       strlen(ua->jcr->pool->cleaning_prefix), 
813       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
814                   strlen(ua->jcr->pool->cleaning_prefix)));
815    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
816                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
817 }