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