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