]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Merge branch 'master' into basejobv3
[bacula/bacula] / bacula / src / dird / ua_label.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- Tape labeling commands
31  *
32  *     Kern Sibbald, April MMIII
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 /* Slot list definition */
41 typedef struct s_vol_list {
42    struct s_vol_list *next;
43    char *VolName;
44    int Slot;
45 } vol_list_t;
46
47
48 /* Forward referenced functions */
49 static int do_label(UAContext *ua, const char *cmd, int relabel);
50 static void label_from_barcodes(UAContext *ua, int drive);
51 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
52                POOL_DBR *pr, int relabel, bool media_record_exits, int drive);
53 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
54 static void free_vol_list(vol_list_t *vol_list);
55 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
56 static BSOCK *open_sd_bsock(UAContext *ua);
57 static void close_sd_bsock(UAContext *ua);
58 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive);
59 static int get_num_slots_from_SD(UAContext *ua);
60
61
62 /*
63  * Label a tape
64  *
65  *   label storage=xxx volume=vvv
66  */
67 int label_cmd(UAContext *ua, const char *cmd)
68 {
69    return do_label(ua, cmd, 0);       /* standard label */
70 }
71
72 int relabel_cmd(UAContext *ua, const char *cmd)
73 {
74    return do_label(ua, cmd, 1);      /* relabel tape */
75 }
76
77 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
78 {
79    int i;
80    const char *msg;
81
82    /* slots are numbered 1 to num_slots */
83    for (int i=0; i <= num_slots; i++) {
84       slot_list[i] = 0;
85    }
86    i = find_arg_with_value(ua, "slots");
87    if (i == -1) {  /* not found */
88       i = find_arg_with_value(ua, "slot");
89    }
90    if (i > 0) {
91       /* scan slot list in ua->argv[i] */
92       char *p, *e, *h;
93       int beg, end;
94
95       strip_trailing_junk(ua->argv[i]);
96       for (p=ua->argv[i]; p && *p; p=e) {
97          /* Check for list */
98          e = strchr(p, ',');
99          if (e) {
100             *e++ = 0;
101          }
102          /* Check for range */
103          h = strchr(p, '-');             /* range? */
104          if (h == p) {
105             msg = _("Negative numbers not permitted\n");
106             goto bail_out;
107          }
108          if (h) {
109             *h++ = 0;
110             if (!is_an_integer(h)) {
111                msg = _("Range end is not integer.\n");
112                goto bail_out;
113             }
114             skip_spaces(&p);
115             if (!is_an_integer(p)) {
116                msg = _("Range start is not an integer.\n");
117                goto bail_out;
118             }
119             beg = atoi(p);
120             end = atoi(h);
121             if (end < beg) {
122                msg = _("Range end not bigger than start.\n");
123                goto bail_out;
124             }
125          } else {
126             skip_spaces(&p);
127             if (!is_an_integer(p)) {
128                msg = _("Input value is not an integer.\n");
129                goto bail_out;
130             }
131             beg = end = atoi(p);
132          }
133          if (beg <= 0 || end <= 0) {
134             msg = _("Values must be be greater than zero.\n");
135             goto bail_out;
136          }
137          if (end > num_slots) {
138             msg = _("Slot too large.\n");
139             goto bail_out;
140          }
141          for (i=beg; i<=end; i++) {
142             slot_list[i] = 1;         /* Turn on specified range */
143          }
144       }
145    } else {
146       /* Turn everything on */
147       for (i=1; i <= num_slots; i++) {
148          slot_list[i] = 1;
149       }
150    }
151    Dmsg0(100, "Slots turned on:\n");
152    for (i=1; i <= num_slots; i++) {
153       if (slot_list[i]) {
154          Dmsg1(100, "%d\n", i);
155       }
156    }
157    return true;
158
159 bail_out:
160    return false;
161 }
162
163 /*
164  * Update Slots corresponding to Volumes in autochanger
165  */
166 void update_slots(UAContext *ua)
167 {
168    USTORE store;
169    vol_list_t *vl, *vol_list = NULL;
170    MEDIA_DBR mr;
171    char *slot_list;
172    bool scan;
173    int max_slots;
174    int drive;
175    int Enabled = 1;
176    bool have_enabled;
177    int i;
178
179
180    if (!open_client_db(ua)) {
181       return;
182    }
183    store.store = get_storage_resource(ua, true/*arg is storage*/);
184    if (!store.store) {
185       return;
186    }
187    pm_strcpy(store.store_source, _("command line"));
188    set_wstorage(ua->jcr, &store);
189    drive = get_storage_drive(ua, store.store);
190
191    scan = find_arg(ua, NT_("scan")) >= 0;
192    if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
193       Enabled = get_enabled(ua, ua->argv[i]);
194       if (Enabled < 0) {
195          return;
196       }
197       have_enabled = true;
198    } else {
199       have_enabled = false;
200    }
201
202    max_slots = get_num_slots_from_SD(ua);
203    Dmsg1(100, "max_slots=%d\n", max_slots);
204    if (max_slots <= 0) {
205       ua->warning_msg(_("No slots in changer to scan.\n"));
206       return;
207    }
208    slot_list = (char *)malloc(max_slots+1);
209    if (!get_user_slot_list(ua, slot_list, max_slots)) {
210       free(slot_list);
211       return;
212    }
213
214    vol_list = get_vol_list_from_SD(ua, scan);
215
216    if (!vol_list) {
217       ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
218       goto bail_out;
219    }
220
221    /* First zap out any InChanger with StorageId=0 */
222    db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
223
224    /* Walk through the list updating the media records */
225    for (vl=vol_list; vl; vl=vl->next) {
226       if (vl->Slot > max_slots) {
227          ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
228             vl->Slot, max_slots);
229          continue;
230       }
231       /* Check if user wants us to look at this slot */
232       if (!slot_list[vl->Slot]) {
233          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
234          continue;
235       }
236       /* If scanning, we read the label rather than the barcode */
237       if (scan) {
238          if (vl->VolName) {
239             free(vl->VolName);
240             vl->VolName = NULL;
241          }
242          vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
243          Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
244       }
245       slot_list[vl->Slot] = 0;        /* clear Slot */
246       memset(&mr, 0, sizeof(mr));
247       mr.Slot = vl->Slot;
248       mr.InChanger = 1;
249       mr.StorageId = store.store->StorageId;
250       /* Set InChanger to zero for this Slot */
251       db_lock(ua->db);
252       db_make_inchanger_unique(ua->jcr, ua->db, &mr);
253       db_unlock(ua->db);
254       if (!vl->VolName) {
255          Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
256          ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
257          continue;
258       }
259       memset(&mr, 0, sizeof(mr));
260       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
261       db_lock(ua->db);
262       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
263          if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
264             mr.Slot = vl->Slot;
265             mr.InChanger = 1;
266             mr.StorageId = store.store->StorageId;
267             if (have_enabled) {
268                mr.Enabled = Enabled;
269             }
270             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
271                ua->error_msg("%s", db_strerror(ua->db));
272             } else {
273                ua->info_msg(_(
274                  "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
275                  mr.VolumeName, mr.Slot);
276             }
277          } else {
278             ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"),
279                mr.VolumeName);
280          }
281          db_unlock(ua->db);
282          continue;
283       } else {
284          ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
285              mr.VolumeName, vl->Slot);
286       }
287       db_unlock(ua->db);
288    }
289    memset(&mr, 0, sizeof(mr));
290    mr.InChanger = 1;
291    mr.StorageId = store.store->StorageId;
292    db_lock(ua->db);
293    for (int i=1; i <= max_slots; i++) {
294       if (slot_list[i]) {
295          mr.Slot = i;
296          /* Set InChanger to zero for this Slot */
297          db_make_inchanger_unique(ua->jcr, ua->db, &mr);
298       }
299    }
300    db_unlock(ua->db);
301
302 bail_out:
303
304    free_vol_list(vol_list);
305    free(slot_list);
306    close_sd_bsock(ua);
307
308    return;
309 }
310
311
312 /*
313  * Common routine for both label and relabel
314  */
315 static int do_label(UAContext *ua, const char *cmd, int relabel)
316 {
317    USTORE store;
318    BSOCK *sd;
319    char dev_name[MAX_NAME_LENGTH];
320    MEDIA_DBR mr, omr;
321    POOL_DBR pr;
322    bool print_reminder = true;
323    bool label_barcodes = false;
324    int ok = FALSE;
325    int i, j;
326    int drive;
327    bool media_record_exists = false;
328    static const char *barcode_keyword[] = {
329       "barcode",
330       "barcodes",
331       NULL};
332
333
334    memset(&pr, 0, sizeof(pr));
335    if (!open_client_db(ua)) {
336       return 1;
337    }
338
339    /* Look for one of the barcode keywords */
340    if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
341       /* Now find the keyword in the list */
342       if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
343          *ua->argk[j] = 0;      /* zap barcode keyword */
344       }
345       label_barcodes = true;
346    }
347
348    store.store = get_storage_resource(ua, true/*use default*/);
349    if (!store.store) {
350       return 1;
351    }
352    pm_strcpy(store.store_source, _("command line"));
353    set_wstorage(ua->jcr, &store);
354    drive = get_storage_drive(ua, store.store);
355
356    if (label_barcodes) {
357       label_from_barcodes(ua, drive);
358       return 1;
359    }
360
361    /* If relabel get name of Volume to relabel */
362    if (relabel) {
363       /* Check for oldvolume=name */
364       i = find_arg_with_value(ua, "oldvolume");
365       if (i >= 0) {
366          memset(&omr, 0, sizeof(omr));
367          bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
368          if (db_get_media_record(ua->jcr, ua->db, &omr)) {
369             goto checkVol;
370          }
371          ua->error_msg("%s", db_strerror(ua->db));
372       }
373       /* No keyword or Vol not found, ask user to select */
374       if (!select_media_dbr(ua, &omr)) {
375          return 1;
376       }
377
378       /* Require Volume to be Purged or Recycled */
379 checkVol:
380       if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
381          ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
382             omr.VolumeName, omr.VolStatus);
383          return 1;
384       }
385    }
386
387    /* Check for volume=NewVolume */
388    i = find_arg_with_value(ua, "volume");
389    if (i >= 0) {
390       pm_strcpy(ua->cmd, ua->argv[i]);
391       goto checkName;
392    }
393
394    /* Get a new Volume name */
395    for ( ;; ) {
396       media_record_exists = false;
397       if (!get_cmd(ua, _("Enter new Volume name: "))) {
398          return 1;
399       }
400 checkName:
401       if (!is_volume_name_legal(ua, ua->cmd)) {
402          continue;
403       }
404
405       memset(&mr, 0, sizeof(mr));
406       bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
407       /* If VolBytes are zero the Volume is not labeled */
408       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
409          if (mr.VolBytes != 0) {
410              ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
411                 mr.VolumeName);
412              continue;
413           }
414           media_record_exists = true;
415       }
416       break;                          /* Got it */
417    }
418
419    /* If autochanger, request slot */
420    i = find_arg_with_value(ua, "slot");
421    if (i >= 0) {
422       mr.Slot = atoi(ua->argv[i]);
423       if (mr.Slot < 0) {
424          mr.Slot = 0;
425       }
426       mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
427    } else if (store.store->autochanger) {
428       if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
429          return 1;
430       }
431       mr.Slot = ua->pint32_val;
432       if (mr.Slot < 0) {
433          mr.Slot = 0;
434       }
435       mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
436    }
437    mr.StorageId = store.store->StorageId;
438
439    bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
440
441    /* Must select Pool if not already done */
442    if (pr.PoolId == 0) {
443       memset(&pr, 0, sizeof(pr));
444       if (!select_pool_dbr(ua, &pr)) {
445          return 1;
446       }
447    }
448
449    ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
450
451    if (ok) {
452       sd = ua->jcr->store_bsock;
453       if (relabel) {
454          /* Delete the old media record */
455          if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
456             ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
457                omr.VolumeName, db_strerror(ua->db));
458          } else {
459             ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
460                omr.VolumeName);
461             /* Update the number of Volumes in the pool */
462             pr.NumVols--;
463             if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
464                ua->error_msg("%s", db_strerror(ua->db));
465             }
466          }
467       }
468       if (ua->automount) {
469          bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
470          ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
471          bash_spaces(dev_name);
472          bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
473          unbash_spaces(dev_name);
474          while (bnet_recv(sd) >= 0) {
475             ua->send_msg("%s", sd->msg);
476             /* Here we can get
477              *  3001 OK mount. Device=xxx      or
478              *  3001 Mounted Volume vvvv
479              *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
480              *  3906 is cannot mount non-tape
481              * So for those, no need to print a reminder
482              */
483             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
484                 strncmp(sd->msg, "3002 ", 5) == 0 ||
485                 strncmp(sd->msg, "3906 ", 5) == 0) {
486                print_reminder = false;
487             }
488          }
489       }
490    }
491    if (print_reminder) {
492       ua->info_msg(_("Do not forget to mount the drive!!!\n"));
493    }
494    close_sd_bsock(ua);
495
496    return 1;
497 }
498
499 /*
500  * Request SD to send us the slot:barcodes, then wiffle
501  *  through them all labeling them.
502  */
503 static void label_from_barcodes(UAContext *ua, int drive)
504 {
505    STORE *store = ua->jcr->wstore;
506    POOL_DBR pr;
507    MEDIA_DBR mr, omr;
508    vol_list_t *vl, *vol_list = NULL;
509    bool media_record_exists;
510    char *slot_list;
511    int max_slots;
512
513   
514    max_slots = get_num_slots_from_SD(ua);
515    if (max_slots <= 0) {
516       ua->warning_msg(_("No slots in changer to scan.\n"));
517       return;
518    }
519    slot_list = (char *)malloc(max_slots+1);
520    if (!get_user_slot_list(ua, slot_list, max_slots)) {
521       goto bail_out;
522    }
523
524    vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
525
526    if (!vol_list) {
527       ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
528       goto bail_out;
529    }
530
531    /* Display list of Volumes and ask if he really wants to proceed */
532    ua->send_msg(_("The following Volumes will be labeled:\n"
533                   "Slot  Volume\n"
534                   "==============\n"));
535    for (vl=vol_list; vl; vl=vl->next) {
536       if (!vl->VolName || !slot_list[vl->Slot]) {
537          continue;
538       }
539       ua->send_msg("%4d  %s\n", vl->Slot, vl->VolName);
540    }
541    if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) ||
542        (ua->pint32_val == 0)) {
543       goto bail_out;
544    }
545    /* Select a pool */
546    memset(&pr, 0, sizeof(pr));
547    if (!select_pool_dbr(ua, &pr)) {
548       goto bail_out;
549    }
550    memset(&omr, 0, sizeof(omr));
551
552    /* Fire off the label requests */
553    for (vl=vol_list; vl; vl=vl->next) {
554       if (!vl->VolName || !slot_list[vl->Slot]) {
555          continue;
556       }
557       memset(&mr, 0, sizeof(mr));
558       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
559       media_record_exists = false;
560       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
561           if (mr.VolBytes != 0) {
562              ua->warning_msg(_("Media record for Slot %d Volume \"%s\" already exists.\n"),
563                 vl->Slot, mr.VolumeName);
564              mr.Slot = vl->Slot;
565              mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
566              mr.StorageId = store->StorageId;
567              if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
568                 ua->error_msg(_("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
569              }
570              continue;
571           }
572           media_record_exists = true;
573       }
574       mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
575       mr.StorageId = store->StorageId;
576       /*
577        * Deal with creating cleaning tape here. Normal tapes created in
578        *  send_label_request() below
579        */
580       if (is_cleaning_tape(ua, &mr, &pr)) {
581          if (media_record_exists) {      /* we update it */
582             mr.VolBytes = 1;             /* any bytes to indicate it exists */
583             bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
584             mr.MediaType[0] = 0;
585             mr.StorageId = store->StorageId;
586             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
587                 ua->error_msg("%s", db_strerror(ua->db));
588             }
589          } else {                        /* create the media record */
590             if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
591                ua->error_msg(_("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
592                goto bail_out;
593             }
594             set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
595             bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
596             mr.MediaType[0] = 0;
597             if (db_create_media_record(ua->jcr, ua->db, &mr)) {
598                ua->send_msg(_("Catalog record for cleaning tape \"%s\" successfully created.\n"),
599                   mr.VolumeName);
600                pr.NumVols++;          /* this is a bit suspect */
601                if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
602                   ua->error_msg("%s", db_strerror(ua->db));
603                }
604             } else {
605                ua->error_msg(_("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
606             }
607          }
608          continue;                    /* done, go handle next volume */
609       }
610       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
611
612       mr.Slot = vl->Slot;
613       send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
614    }
615
616
617 bail_out:
618    free(slot_list);
619    free_vol_list(vol_list);
620    close_sd_bsock(ua);
621
622    return;
623 }
624
625 /*
626  * Check if the Volume name has legal characters
627  * If ua is non-NULL send the message
628  */
629 bool is_volume_name_legal(UAContext *ua, const char *name)
630 {
631    int len;
632    const char *p;
633    const char *accept = ":.-_";
634
635    /* Restrict the characters permitted in the Volume name */
636    for (p=name; *p; p++) {
637       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
638          continue;
639       }
640       if (ua) {
641          ua->error_msg(_("Illegal character \"%c\" in a volume name.\n"), *p);
642       }
643       return 0;
644    }
645    len = strlen(name);
646    if (len >= MAX_NAME_LENGTH) {
647       if (ua) {
648          ua->error_msg(_("Volume name too long.\n"));
649       }
650       return 0;
651    }
652    if (len == 0) {
653       if (ua) {
654          ua->error_msg(_("Volume name must be at least one character long.\n"));
655       }
656       return 0;
657    }
658    return 1;
659 }
660
661 /*
662  * NOTE! This routine opens the SD socket but leaves it open
663  */
664 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
665                                POOL_DBR *pr, int relabel, bool media_record_exists,
666                                int drive)
667 {
668    BSOCK *sd;
669    char dev_name[MAX_NAME_LENGTH];
670    bool ok = false;
671    bool is_dvd = false;
672    uint64_t VolBytes = 0;
673
674    if (!(sd=open_sd_bsock(ua))) {
675       return false;
676    }
677    bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
678    bash_spaces(dev_name);
679    bash_spaces(mr->VolumeName);
680    bash_spaces(mr->MediaType);
681    bash_spaces(pr->Name);
682    if (relabel) {
683       bash_spaces(omr->VolumeName);
684       sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
685                      "MediaType=%s Slot=%d drive=%d",
686                  dev_name, omr->VolumeName, mr->VolumeName, pr->Name, 
687                  mr->MediaType, mr->Slot, drive);
688       ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"),
689          omr->VolumeName, mr->VolumeName);
690    } else {
691       sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s "
692                      "Slot=%d drive=%d",
693                  dev_name, mr->VolumeName, pr->Name, mr->MediaType, 
694                  mr->Slot, drive);
695       ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"),
696          mr->VolumeName, mr->Slot);
697       Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
698          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
699    }
700
701    while (sd->recv() >= 0) {
702       int dvd;
703       ua->send_msg("%s", sd->msg);
704       if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
705                  &dvd) == 2) {
706          is_dvd = dvd;
707          ok = true;
708       }
709    }
710    unbash_spaces(mr->VolumeName);
711    unbash_spaces(mr->MediaType);
712    unbash_spaces(pr->Name);
713    mr->LabelDate = time(NULL);
714    mr->set_label_date = true;
715    if (is_dvd) {
716       /* We know that a freshly labelled DVD has 1 VolParts */
717       /* This does not apply to auto-labelled DVDs. */
718       mr->VolParts = 1;
719    }
720    if (ok) {
721       if (media_record_exists) {      /* we update it */
722          mr->VolBytes = VolBytes;
723          mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
724          mr->StorageId = ua->jcr->wstore->StorageId;
725          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
726              ua->error_msg("%s", db_strerror(ua->db));
727              ok = false;
728          }
729       } else {                        /* create the media record */
730          set_pool_dbr_defaults_in_media_dbr(mr, pr);
731          mr->VolBytes = VolBytes;
732          mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
733          mr->StorageId = ua->jcr->wstore->StorageId;
734          mr->Enabled = 1;
735          if (db_create_media_record(ua->jcr, ua->db, mr)) {
736             ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
737             mr->VolumeName, mr->Slot);
738             /* Update number of volumes in pool */
739             pr->NumVols++;
740             if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
741                ua->error_msg("%s", db_strerror(ua->db));
742             }
743          } else {
744             ua->error_msg("%s", db_strerror(ua->db));
745             ok = false;
746          }
747       }
748    } else {
749       ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
750    }
751    return ok;
752 }
753
754 static BSOCK *open_sd_bsock(UAContext *ua)
755 {
756    STORE *store = ua->jcr->wstore;
757
758    if (!ua->jcr->store_bsock) {
759       ua->send_msg(_("Connecting to Storage daemon %s at %s:%d ...\n"),
760          store->name(), store->address, store->SDport);
761       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
762          ua->error_msg(_("Failed to connect to Storage daemon.\n"));
763          return NULL;
764       }
765    }
766    return ua->jcr->store_bsock;
767 }
768
769 static void close_sd_bsock(UAContext *ua)
770 {
771    if (ua->jcr->store_bsock) {
772       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
773       bnet_close(ua->jcr->store_bsock);
774       ua->jcr->store_bsock = NULL;
775    }
776 }
777
778 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
779 {
780    STORE *store = ua->jcr->wstore;
781    BSOCK *sd;
782    char dev_name[MAX_NAME_LENGTH];
783    char *VolName = NULL;
784    int rtn_slot;
785
786    if (!(sd=open_sd_bsock(ua))) {
787       ua->error_msg(_("Could not open SD socket.\n"));
788       return NULL;
789    }
790    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
791    bash_spaces(dev_name);
792    /* Ask for autochanger list of volumes */
793    sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
794    Dmsg1(100, "Sent: %s", sd->msg);
795
796    /* Get Volume name in this Slot */
797    while (sd->recv() >= 0) {
798       ua->send_msg("%s", sd->msg);
799       Dmsg1(100, "Got: %s", sd->msg);
800       if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
801          VolName = (char *)malloc(sd->msglen);
802          if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
803             break;
804          }
805          free(VolName);
806          VolName = NULL;
807       }
808    }
809    close_sd_bsock(ua);
810    Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
811    return VolName;
812 }
813
814 /*
815  * We get the slot list from the Storage daemon.
816  *  If scan is set, we return all slots found,
817  *  otherwise, we return only slots with valid barcodes (Volume names)
818  */
819 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
820 {
821    STORE *store = ua->jcr->wstore;
822    char dev_name[MAX_NAME_LENGTH];
823    BSOCK *sd;
824    vol_list_t *vl;
825    vol_list_t *vol_list = NULL;
826
827
828    if (!(sd=open_sd_bsock(ua))) {
829       return NULL;
830    }
831
832    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
833    bash_spaces(dev_name);
834    /* Ask for autochanger list of volumes */
835    bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
836
837    /* Read and organize list of Volumes */
838    while (bnet_recv(sd) >= 0) {
839       char *p;
840       int Slot;
841       strip_trailing_junk(sd->msg);
842
843       /* Check for returned SD messages */
844       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
845           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
846           sd->msg[4] == ' ') {
847          ua->send_msg("%s\n", sd->msg);   /* pass them on to user */
848          continue;
849       }
850
851       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
852       p = strchr(sd->msg, ':');
853       if (scan && p) {
854          /* Scanning -- require only valid slot */
855          Slot = atoi(sd->msg);
856          if (Slot <= 0) {
857             p--;
858             *p = ':';
859             ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
860             continue;
861          }
862       } else {
863          /* Not scanning */
864          if (p && strlen(p) > 1) {
865             *p++ = 0;
866             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
867                p--;
868                *p = ':';
869                ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
870                continue;
871             }
872          } else {
873             continue;
874          }
875          if (!is_volume_name_legal(ua, p)) {
876             p--;
877             *p = ':';
878             ua->error_msg(_("Invalid Volume name: %s\n"), sd->msg);
879             continue;
880          }
881       }
882
883       /* Add Slot and VolumeName to list */
884       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
885       vl->Slot = Slot;
886       if (p) {
887          if (*p == ':') {
888             p++;                      /* skip separator */
889          }
890          vl->VolName = bstrdup(p);
891       } else {
892          vl->VolName = NULL;
893       }
894       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
895       if (!vol_list) {
896          vl->next = vol_list;
897          vol_list = vl;
898       } else {
899          vol_list_t *prev=vol_list;
900          /* Add new entry to the right place in the list */
901          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
902             if (tvl->Slot > vl->Slot) {
903                /* no previous item, update vol_list directly */
904                if (prev == vol_list) {  
905                   vl->next = vol_list;
906                   vol_list = vl;
907
908                } else {     /* replace the previous pointer */
909                   prev->next = vl;
910                   vl->next = tvl;
911                }
912                break;
913             }
914             /* we are at the end */
915             if (!tvl->next) {
916                tvl->next = vl;
917                vl->next = NULL;
918                break;
919             }
920             prev = tvl;
921          }
922       }
923    }
924    close_sd_bsock(ua);
925    return vol_list;
926 }
927
928 static void free_vol_list(vol_list_t *vol_list)
929 {
930    vol_list_t *vl;
931
932    /* Free list */
933    for (vl=vol_list; vl; ) {
934       vol_list_t *ovl;
935       if (vl->VolName) {
936          free(vl->VolName);
937       }
938       ovl = vl;
939       vl = vl->next;
940       free(ovl);
941    }
942 }
943
944 /*
945  * We get the number of slots in the changer from the SD
946  */
947 static int get_num_slots_from_SD(UAContext *ua)
948 {
949    STORE *store = ua->jcr->wstore;
950    char dev_name[MAX_NAME_LENGTH];
951    BSOCK *sd;
952    int slots = 0;
953
954
955    if (!(sd=open_sd_bsock(ua))) {
956       return 0;
957    }
958
959    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
960    bash_spaces(dev_name);
961    /* Ask for autochanger number of slots */
962    sd->fsend(NT_("autochanger slots %s\n"), dev_name);
963
964    while (sd->recv() >= 0) {
965       if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
966          break;
967       } else {
968          ua->send_msg("%s", sd->msg);
969       }
970    }
971    close_sd_bsock(ua);
972    ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
973    return slots;
974 }
975
976 /*
977  * We get the number of drives in the changer from the SD
978  */
979 int get_num_drives_from_SD(UAContext *ua)
980 {
981    STORE *store = ua->jcr->wstore;
982    char dev_name[MAX_NAME_LENGTH];
983    BSOCK *sd;
984    int drives = 0;
985
986
987    if (!(sd=open_sd_bsock(ua))) {
988       return 0;
989    }
990
991    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
992    bash_spaces(dev_name);
993    /* Ask for autochanger number of slots */
994    sd->fsend(NT_("autochanger drives %s\n"), dev_name);
995
996    while (sd->recv() >= 0) {
997       if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
998          break;
999       } else {
1000          ua->send_msg("%s", sd->msg);
1001       }
1002    }
1003    close_sd_bsock(ua);
1004 //   bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
1005    return drives;
1006 }
1007
1008 /*
1009  * Check if this is a cleaning tape by comparing the Volume name
1010  *  with the Cleaning Prefix. If they match, this is a cleaning
1011  *  tape.
1012  */
1013 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
1014 {
1015    /* Find Pool resource */
1016    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
1017    if (!ua->jcr->pool) {
1018       ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
1019          pr->Name, mr->VolumeName);
1020       return false;
1021    }
1022    if (ua->jcr->pool->cleaning_prefix == NULL) {
1023       return false;
1024    }
1025    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1026       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1027       strlen(ua->jcr->pool->cleaning_prefix),
1028       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1029                   strlen(ua->jcr->pool->cleaning_prefix)));
1030    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1031                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
1032 }
1033
1034 static void content_send_info(UAContext *ua, char type, int Slot, char *vol_name)
1035 {
1036    char ed1[50], ed2[50], ed3[50];
1037    POOL_DBR pr;
1038    MEDIA_DBR mr;
1039    /* Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
1040    const char *slot_api_full_format="%c|%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
1041    const char *slot_api_empty_format="%c|%i||||||||\n";
1042
1043    if (is_volume_name_legal(NULL, vol_name)) {
1044       memset(&mr, 0, sizeof(mr));
1045       bstrncpy(mr.VolumeName, vol_name, sizeof(mr.VolumeName));
1046       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
1047          memset(&pr, 0, sizeof(POOL_DBR));
1048          pr.PoolId = mr.PoolId;
1049          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1050             strcpy(pr.Name, "?");
1051          }
1052          ua->send_msg(slot_api_full_format, type,
1053                       Slot, mr.Slot, mr.VolumeName, 
1054                       edit_uint64(mr.VolBytes, ed1), 
1055                       mr.VolStatus, mr.MediaType, pr.Name, 
1056                       edit_uint64(mr.LastWritten, ed2),
1057                       edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
1058          
1059       } else {                  /* Media unknown */
1060          ua->send_msg(slot_api_full_format,
1061                       type, Slot, 0, mr.VolumeName, "?", "?", "?", "?", 
1062                       "0", "0");
1063          
1064       }
1065    } else {
1066       ua->send_msg(slot_api_empty_format, type, Slot);
1067    }
1068 }         
1069
1070 /* 
1071  * Input (output of mxt-changer listall):
1072  *
1073  * Drive content:         D:Drive num:F:Slot loaded:Volume Name
1074  * D:0:F:2:vol2        or D:Drive num:E
1075  * D:1:F:42:vol42   
1076  * D:3:E
1077  *
1078  * Slot content:
1079  * S:1:F:vol1             S:Slot num:F:Volume Name
1080  * S:2:E               or S:Slot num:E
1081  * S:3:F:vol4
1082  *
1083  * Import/Export tray slots:
1084  * I:10:F:vol10           I:Slot num:F:Volume Name
1085  * I:11:E              or I:Slot num:E
1086  * I:12:F:vol40
1087  *
1088  * If a drive is loaded, the slot *should* be empty 
1089  * 
1090  * Output:
1091  *
1092  * Drive list:       D|Drive num|Slot loaded|Volume Name
1093  * D|0|45|vol45
1094  * D|1|42|vol42
1095  * D|3||
1096  *
1097  * Slot list: Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire
1098  *
1099  * S|1|1|vol1|31417344|Full|LTO1-ANSI|Inc|1250858902|1282394902
1100  * S|2||||||||
1101  * S|3|3|vol4|15869952|Append|LTO1-ANSI|Inc|1250858907|1282394907
1102  *
1103  * TODO: need to merge with status_slots()
1104  */
1105 void status_content(UAContext *ua, STORE *store)
1106 {
1107    int Slot, Drive;
1108    char type;
1109    char dev_name[MAX_NAME_LENGTH];
1110    char vol_name[MAX_NAME_LENGTH];
1111    BSOCK *sd;
1112    vol_list_t *vl=NULL, *vol_list = NULL;
1113
1114    if (!(sd=open_sd_bsock(ua))) {
1115       return;
1116    }
1117
1118    if (!open_client_db(ua)) {
1119       return;
1120    }
1121
1122    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1123    bash_spaces(dev_name);
1124    /* Ask for autochanger list of volumes */
1125    bnet_fsend(sd, NT_("autochanger listall %s \n"), dev_name);
1126
1127    /* Read and organize list of Drive, Slots and I/O Slots */
1128    while (bnet_recv(sd) >= 0) {
1129       strip_trailing_junk(sd->msg);
1130
1131       /* Check for returned SD messages */
1132       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
1133           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
1134           sd->msg[4] == ' ') {
1135          ua->send_msg("%s\n", sd->msg);   /* pass them on to user */
1136          continue;
1137       }
1138
1139       Drive = Slot = -1;
1140       *vol_name = 0;
1141
1142       if (sscanf(sd->msg, "D:%d:F:%d:%127s", &Drive, &Slot, vol_name) == 3) {
1143          ua->send_msg("D|%d|%d|%s\n", Drive, Slot, vol_name);
1144
1145          /* we print information on the slot if we have a volume name */
1146          if (*vol_name) {
1147             /* Add Slot and VolumeName to list */
1148             vl = (vol_list_t *)malloc(sizeof(vol_list_t));
1149             vl->Slot = Slot;
1150             vl->VolName = bstrdup(vol_name);
1151             vl->next = vol_list;
1152             vol_list = vl;
1153          }
1154
1155       } else if (sscanf(sd->msg, "D:%d:E", &Drive) == 1) {
1156          ua->send_msg("D|%d||\n", Drive);
1157
1158       } else if (sscanf(sd->msg, "%c:%d:F:%127s", &type, &Slot, vol_name)== 3) {
1159          content_send_info(ua, type, Slot, vol_name);
1160
1161       } else if (sscanf(sd->msg, "%c:%d:E", &type, &Slot) == 2) {
1162          /* type can be S (slot) or I (Import/Export slot) */
1163          vol_list_t *prev=NULL;
1164          for (vl = vol_list; vl; vl = vl->next) {
1165             if (vl->Slot == Slot) {
1166                bstrncpy(vol_name, vl->VolName, MAX_NAME_LENGTH);
1167
1168                /* remove the node */
1169                if (prev) {
1170                   prev->next = vl->next;
1171                } else {
1172                   vol_list = vl->next;
1173                }
1174                free(vl->VolName);
1175                free(vl);
1176                break;
1177             }
1178             prev = vl;
1179          }
1180          content_send_info(ua, type, Slot, vol_name);
1181
1182       } else {
1183          Dmsg1(10, "Discarding msg=%s\n", sd->msg);
1184       }
1185    }
1186    close_sd_bsock(ua);
1187 }
1188
1189 /*
1190  * Print slots from AutoChanger
1191  */
1192 void status_slots(UAContext *ua, STORE *store_r)
1193 {
1194    USTORE store;
1195    POOL_DBR pr;
1196    vol_list_t *vl, *vol_list = NULL;
1197    MEDIA_DBR mr;
1198    char *slot_list;
1199    int max_slots;
1200    int drive;
1201    int i=1;
1202    /* Slot | Volume | Status | MediaType | Pool */
1203    const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
1204
1205    if (ua->api) {
1206       status_content(ua, store_r);
1207       return;
1208    }
1209
1210    if (!open_client_db(ua)) {
1211       return;
1212    }
1213    store.store = store_r;
1214
1215    pm_strcpy(store.store_source, _("command line"));
1216    set_wstorage(ua->jcr, &store);
1217    drive = get_storage_drive(ua, store.store);
1218
1219    max_slots = get_num_slots_from_SD(ua);
1220
1221    if (max_slots <= 0) {
1222       ua->warning_msg(_("No slots in changer to scan.\n"));
1223       return;
1224    }
1225    slot_list = (char *)malloc(max_slots+1);
1226    if (!get_user_slot_list(ua, slot_list, max_slots)) {
1227       free(slot_list);
1228       return;
1229    }
1230
1231    vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
1232
1233    if (!vol_list) {
1234       ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
1235       goto bail_out;
1236    }
1237    ua->send_msg(_(" Slot |   Volume Name    |   Status  |     Media Type       |      Pool          |\n"));
1238    ua->send_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
1239
1240    /* Walk through the list getting the media records */
1241    for (vl=vol_list; vl; vl=vl->next) {
1242       if (vl->Slot > max_slots) {
1243          ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
1244             vl->Slot, max_slots);
1245          continue;
1246       }
1247       /* Check if user wants us to look at this slot */
1248       if (!slot_list[vl->Slot]) {
1249          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
1250          continue;
1251       }
1252
1253       slot_list[vl->Slot] = 0;        /* clear Slot */
1254
1255       if (!vl->VolName) {
1256          Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
1257          ua->send_msg(slot_hformat,
1258                       vl->Slot, '*',
1259                       "?", "?", "?", "?");
1260          continue;
1261       }
1262
1263       /* Hope that slots are ordered */
1264       for (; i < vl->Slot; i++) {
1265          if (slot_list[i]) {
1266             ua->send_msg(slot_hformat,
1267                          i, ' ', "", "", "", "");
1268             slot_list[i]=0;
1269          }
1270       }
1271
1272       memset(&mr, 0, sizeof(mr));
1273       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1274       db_lock(ua->db);
1275       if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
1276          memset(&pr, 0, sizeof(POOL_DBR));
1277          pr.PoolId = mr.PoolId;
1278          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1279             strcpy(pr.Name, "?");
1280          }
1281          db_unlock(ua->db);
1282
1283          /* Print information */
1284          ua->send_msg(slot_hformat,
1285                       vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
1286                       mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
1287          continue;
1288       } else {                  /* TODO: get information from catalog  */
1289          ua->send_msg(slot_hformat,
1290                       vl->Slot, '*',
1291                       mr.VolumeName, "?", "?", "?");
1292       }
1293       db_unlock(ua->db);
1294    }
1295
1296    /* Display the rest of the autochanger
1297     */
1298    for (; i <= max_slots; i++) {
1299       if (slot_list[i]) {
1300          ua->send_msg(slot_hformat,
1301                       i, ' ', "", "", "", "");
1302          slot_list[i]=0;
1303       }
1304    }
1305
1306 bail_out:
1307
1308    free_vol_list(vol_list);
1309    free(slot_list);
1310    close_sd_bsock(ua);
1311
1312    return;
1313 }