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