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