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