]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Revert "Warn of Storage Daemon version incompatibility if label fails. Bug #2193"
[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 (sscanf(sd->msg, "3000 OK label. VolBytes=%llu VolABytes=%lld VolType=%d ",
711                  &VolBytes, &VolABytes, &VolType) == 3) {
712          ok = true;
713       }
714    }
715    unbash_spaces(mr->VolumeName);
716    unbash_spaces(mr->MediaType);
717    unbash_spaces(pr->Name);
718    mr->LabelDate = time(NULL);
719    mr->set_label_date = true;
720    if (ok) {
721       if (media_record_exists) {      /* we update it */
722          mr->VolBytes = VolBytes;
723          mr->VolABytes = VolABytes;
724          mr->VolType = VolType;
725          mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
726          set_storageid_in_mr(ua->jcr->wstore, mr);
727          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
728              ua->error_msg("%s", db_strerror(ua->db));
729              ok = false;
730          }
731       } else {                        /* create the media record */
732          set_pool_dbr_defaults_in_media_dbr(mr, pr);
733          mr->VolBytes = VolBytes;
734          mr->VolABytes = VolABytes;
735          mr->VolType = VolType;
736          mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
737          mr->Enabled = 1;
738          set_storageid_in_mr(ua->jcr->wstore, mr);
739          if (db_create_media_record(ua->jcr, ua->db, mr)) {
740             ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
741             mr->VolumeName, mr->Slot);
742             /* Update number of volumes in pool */
743             pr->NumVols++;
744             if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
745                ua->error_msg("%s", db_strerror(ua->db));
746             }
747          } else {
748             ua->error_msg("%s", db_strerror(ua->db));
749             ok = false;
750          }
751       }
752    } else {
753       ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
754    }
755    return ok;
756 }
757
758 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
759 {
760    STORE *store = ua->jcr->wstore;
761    BSOCK *sd;
762    char dev_name[MAX_NAME_LENGTH];
763    char *VolName = NULL;
764    int rtn_slot;
765
766    if (!(sd=open_sd_bsock(ua))) {
767       ua->error_msg(_("Could not open SD socket.\n"));
768       return NULL;
769    }
770    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
771    bash_spaces(dev_name);
772    /* Ask for autochanger list of volumes */
773    sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
774    Dmsg1(100, "Sent: %s", sd->msg);
775
776    /* Get Volume name in this Slot */
777    while (sd->recv() >= 0) {
778       ua->send_msg("%s", sd->msg);
779       Dmsg1(100, "Got: %s", sd->msg);
780       if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
781          VolName = (char *)malloc(sd->msglen);
782          if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
783             break;
784          }
785          free(VolName);
786          VolName = NULL;
787       }
788    }
789    close_sd_bsock(ua);
790    Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
791    return VolName;
792 }
793
794 /*
795  * We get the slot list from the Storage daemon.
796  *  If scan is set, we return all slots found,
797  *  otherwise, we return only slots with valid barcodes (Volume names)
798  */
799 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
800 {
801    STORE *store = ua->jcr->wstore;
802    char dev_name[MAX_NAME_LENGTH];
803    BSOCK *sd;
804    vol_list_t *vl;
805    vol_list_t *vol_list = NULL;
806
807
808    if (!(sd=open_sd_bsock(ua))) {
809       return NULL;
810    }
811
812    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
813    bash_spaces(dev_name);
814    /* Ask for autochanger list of volumes */
815    sd->fsend(NT_("autochanger list %s \n"), dev_name);
816
817    /* Read and organize list of Volumes */
818    while (sd->recv() >= 0) {
819       char *p;
820       int Slot;
821       strip_trailing_junk(sd->msg);
822
823       /* Check for returned SD messages */
824       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
825           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
826           sd->msg[4] == ' ') {
827          ua->send_msg("%s\n", sd->msg);   /* pass them on to user */
828          continue;
829       }
830
831       /* Validate Slot: if scanning, otherwise  Slot:Barcode */
832       p = strchr(sd->msg, ':');
833       if (scan && p) {
834          /* Scanning -- require only valid slot */
835          Slot = atoi(sd->msg);
836          if (Slot <= 0) {
837             p--;
838             *p = ':';
839             ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
840             continue;
841          }
842       } else {
843          /* Not scanning */
844          if (p && strlen(p) > 1) {
845             *p++ = 0;
846             if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
847                p--;
848                *p = ':';
849                ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
850                continue;
851             }
852          } else {
853             continue;
854          }
855          if (!is_volume_name_legal(ua, p)) {
856             p--;
857             *p = ':';
858             ua->error_msg(_("Invalid Volume name: %s. Volume skipped.\n"), sd->msg);
859             continue;
860          }
861       }
862
863       /* Add Slot and VolumeName to list */
864       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
865       vl->Slot = Slot;
866       if (p) {
867          if (*p == ':') {
868             p++;                      /* skip separator */
869          }
870          vl->VolName = bstrdup(p);
871       } else {
872          vl->VolName = NULL;
873       }
874       Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
875       if (!vol_list) {
876          vl->next = vol_list;
877          vol_list = vl;
878       } else {
879          vol_list_t *prev=vol_list;
880          /* Add new entry to the right place in the list */
881          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
882             if (tvl->Slot > vl->Slot) {
883                /* no previous item, update vol_list directly */
884                if (prev == vol_list) {
885                   vl->next = vol_list;
886                   vol_list = vl;
887
888                } else {     /* replace the previous pointer */
889                   prev->next = vl;
890                   vl->next = tvl;
891                }
892                break;
893             }
894             /* we are at the end */
895             if (!tvl->next) {
896                tvl->next = vl;
897                vl->next = NULL;
898                break;
899             }
900             prev = tvl;
901          }
902       }
903    }
904    close_sd_bsock(ua);
905    return vol_list;
906 }
907
908 static void free_vol_list(vol_list_t *vol_list)
909 {
910    vol_list_t *vl;
911
912    /* Free list */
913    for (vl=vol_list; vl; ) {
914       vol_list_t *ovl;
915       if (vl->VolName) {
916          free(vl->VolName);
917       }
918       ovl = vl;
919       vl = vl->next;
920       free(ovl);
921    }
922 }
923
924 /*
925  * We get the number of slots in the changer from the SD
926  */
927 static int get_num_slots_from_SD(UAContext *ua)
928 {
929    STORE *store = ua->jcr->wstore;
930    char dev_name[MAX_NAME_LENGTH];
931    BSOCK *sd;
932    int slots = 0;
933
934
935    if (!(sd=open_sd_bsock(ua))) {
936       return 0;
937    }
938
939    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
940    bash_spaces(dev_name);
941    /* Ask for autochanger number of slots */
942    sd->fsend(NT_("autochanger slots %s\n"), dev_name);
943
944    while (sd->recv() >= 0) {
945       if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
946          break;
947       } else {
948          ua->send_msg("%s", sd->msg);
949       }
950    }
951    close_sd_bsock(ua);
952    ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
953    return slots;
954 }
955
956 /*
957  * We get the number of drives in the changer from the SD
958  */
959 int get_num_drives_from_SD(UAContext *ua)
960 {
961    STORE *store = ua->jcr->wstore;
962    char dev_name[MAX_NAME_LENGTH];
963    BSOCK *sd;
964    int drives = 0;
965
966
967    if (!(sd=open_sd_bsock(ua))) {
968       return 0;
969    }
970
971    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
972    bash_spaces(dev_name);
973    /* Ask for autochanger number of slots */
974    sd->fsend(NT_("autochanger drives %s\n"), dev_name);
975
976    while (sd->recv() >= 0) {
977       if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
978          break;
979       } else {
980          ua->send_msg("%s", sd->msg);
981       }
982    }
983    close_sd_bsock(ua);
984 //   bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
985    return drives;
986 }
987
988 /*
989  * Check if this is a cleaning tape by comparing the Volume name
990  *  with the Cleaning Prefix. If they match, this is a cleaning
991  *  tape.
992  */
993 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
994 {
995    /* Find Pool resource */
996    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
997    if (!ua->jcr->pool) {
998       ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
999          pr->Name, mr->VolumeName);
1000       return false;
1001    }
1002    if (ua->jcr->pool->cleaning_prefix == NULL) {
1003       return false;
1004    }
1005    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1006       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1007       strlen(ua->jcr->pool->cleaning_prefix),
1008       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1009                   strlen(ua->jcr->pool->cleaning_prefix)));
1010    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1011                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
1012 }
1013
1014 static void content_send_info(UAContext *ua, char type, int Slot, char *vol_name)
1015 {
1016    char ed1[50], ed2[50], ed3[50];
1017    POOL_DBR pr;
1018    MEDIA_DBR mr;
1019    /* Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
1020    const char *slot_api_full_format="%c|%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
1021    const char *slot_api_empty_format="%c|%i||||||||\n";
1022
1023    if (is_volume_name_legal(NULL, vol_name)) {
1024       bstrncpy(mr.VolumeName, vol_name, sizeof(mr.VolumeName));
1025       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
1026          memset(&pr, 0, sizeof(POOL_DBR));
1027          pr.PoolId = mr.PoolId;
1028          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1029             strcpy(pr.Name, "?");
1030          }
1031          ua->send_msg(slot_api_full_format, type,
1032                       Slot, mr.Slot, mr.VolumeName,
1033                       edit_uint64(mr.VolBytes, ed1),
1034                       mr.VolStatus, mr.MediaType, pr.Name,
1035                       edit_uint64(mr.LastWritten, ed2),
1036                       edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
1037
1038       } else {                  /* Media unknown */
1039          ua->send_msg(slot_api_full_format,
1040                       type, Slot, 0, mr.VolumeName, "?", "?", "?", "?",
1041                       "0", "0");
1042
1043       }
1044    } else {
1045       ua->send_msg(slot_api_empty_format, type, Slot);
1046    }
1047 }
1048
1049 /*
1050  * Input (output of mxt-changer listall):
1051  *
1052  * Drive content:         D:Drive num:F:Slot loaded:Volume Name
1053  * D:0:F:2:vol2        or D:Drive num:E
1054  * D:1:F:42:vol42
1055  * D:3:E
1056  *
1057  * Slot content:
1058  * S:1:F:vol1             S:Slot num:F:Volume Name
1059  * S:2:E               or S:Slot num:E
1060  * S:3:F:vol4
1061  *
1062  * Import/Export tray slots:
1063  * I:10:F:vol10           I:Slot num:F:Volume Name
1064  * I:11:E              or I:Slot num:E
1065  * I:12:F:vol40
1066  *
1067  * If a drive is loaded, the slot *should* be empty
1068  *
1069  * Output:
1070  *
1071  * Drive list:       D|Drive num|Slot loaded|Volume Name
1072  * D|0|45|vol45
1073  * D|1|42|vol42
1074  * D|3||
1075  *
1076  * Slot list: Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire
1077  *
1078  * S|1|1|vol1|31417344|Full|LTO1-ANSI|Inc|1250858902|1282394902
1079  * S|2||||||||
1080  * S|3|3|vol4|15869952|Append|LTO1-ANSI|Inc|1250858907|1282394907
1081  *
1082  * TODO: need to merge with status_slots()
1083  */
1084 void status_content(UAContext *ua, STORE *store)
1085 {
1086    int Slot, Drive;
1087    char type;
1088    char dev_name[MAX_NAME_LENGTH];
1089    char vol_name[MAX_NAME_LENGTH];
1090    BSOCK *sd;
1091    vol_list_t *vl=NULL, *vol_list = NULL;
1092
1093    if (!(sd=open_sd_bsock(ua))) {
1094       return;
1095    }
1096
1097    if (!open_client_db(ua)) {
1098       return;
1099    }
1100
1101    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1102    bash_spaces(dev_name);
1103    /* Ask for autochanger list of volumes */
1104    sd->fsend(NT_("autochanger listall %s \n"), dev_name);
1105
1106    /* Read and organize list of Drive, Slots and I/O Slots */
1107    while (sd->recv() >= 0) {
1108       strip_trailing_junk(sd->msg);
1109
1110       /* Check for returned SD messages */
1111       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
1112           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
1113           sd->msg[4] == ' ') {
1114          ua->send_msg("%s\n", sd->msg);   /* pass them on to user */
1115          continue;
1116       }
1117
1118       Drive = Slot = -1;
1119       *vol_name = 0;
1120
1121       if (sscanf(sd->msg, "D:%d:F:%d:%127s", &Drive, &Slot, vol_name) == 3) {
1122          ua->send_msg("D|%d|%d|%s\n", Drive, Slot, vol_name);
1123
1124          /* we print information on the slot if we have a volume name */
1125          if (*vol_name) {
1126             /* Add Slot and VolumeName to list */
1127             vl = (vol_list_t *)malloc(sizeof(vol_list_t));
1128             vl->Slot = Slot;
1129             vl->VolName = bstrdup(vol_name);
1130             vl->next = vol_list;
1131             vol_list = vl;
1132          }
1133
1134       } else if (sscanf(sd->msg, "D:%d:E", &Drive) == 1) {
1135          ua->send_msg("D|%d||\n", Drive);
1136
1137       } else if (sscanf(sd->msg, "%c:%d:F:%127s", &type, &Slot, vol_name)== 3) {
1138          content_send_info(ua, type, Slot, vol_name);
1139
1140       } else if (sscanf(sd->msg, "%c:%d:E", &type, &Slot) == 2) {
1141          /* type can be S (slot) or I (Import/Export slot) */
1142          vol_list_t *prev=NULL;
1143          for (vl = vol_list; vl; vl = vl->next) {
1144             if (vl->Slot == Slot) {
1145                bstrncpy(vol_name, vl->VolName, MAX_NAME_LENGTH);
1146
1147                /* remove the node */
1148                if (prev) {
1149                   prev->next = vl->next;
1150                } else {
1151                   vol_list = vl->next;
1152                }
1153                free(vl->VolName);
1154                free(vl);
1155                break;
1156             }
1157             prev = vl;
1158          }
1159          content_send_info(ua, type, Slot, vol_name);
1160
1161       } else {
1162          Dmsg1(10, "Discarding msg=%s\n", sd->msg);
1163       }
1164    }
1165    close_sd_bsock(ua);
1166 }
1167
1168 /*
1169  * Print slots from AutoChanger
1170  */
1171 void status_slots(UAContext *ua, STORE *store_r)
1172 {
1173    USTORE store;
1174    POOL_DBR pr;
1175    vol_list_t *vl, *vol_list = NULL;
1176    MEDIA_DBR mr;
1177    char *slot_list;
1178    int max_slots;
1179    int i=1;
1180    /* Slot | Volume | Status | MediaType | Pool */
1181    const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
1182
1183    if (ua->api) {
1184       status_content(ua, store_r);
1185       return;
1186    }
1187
1188    if (!open_client_db(ua)) {
1189       return;
1190    }
1191    store.store = store_r;
1192
1193    pm_strcpy(store.store_source, _("command line"));
1194    set_wstorage(ua->jcr, &store);
1195    get_storage_drive(ua, store.store);
1196
1197    max_slots = get_num_slots_from_SD(ua);
1198
1199    if (max_slots <= 0) {
1200       ua->warning_msg(_("No slots in changer to scan.\n"));
1201       return;
1202    }
1203    slot_list = (char *)malloc(max_slots+1);
1204    if (!get_user_slot_list(ua, slot_list, max_slots)) {
1205       free(slot_list);
1206       return;
1207    }
1208
1209    vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
1210
1211    if (!vol_list) {
1212       ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
1213       goto bail_out;
1214    }
1215    ua->send_msg(_(" Slot |   Volume Name    |   Status  |     Media Type       |      Pool          |\n"));
1216    ua->send_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
1217
1218    /* Walk through the list getting the media records */
1219    for (vl=vol_list; vl; vl=vl->next) {
1220       if (vl->Slot > max_slots) {
1221          ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
1222             vl->Slot, max_slots);
1223          continue;
1224       }
1225       /* Check if user wants us to look at this slot */
1226       if (!slot_list[vl->Slot]) {
1227          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
1228          continue;
1229       }
1230
1231       slot_list[vl->Slot] = 0;        /* clear Slot */
1232
1233       if (!vl->VolName) {
1234          Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
1235          ua->send_msg(slot_hformat,
1236                       vl->Slot, '*',
1237                       "?", "?", "?", "?");
1238          continue;
1239       }
1240
1241       /* Hope that slots are ordered */
1242       for (; i < vl->Slot; i++) {
1243          if (slot_list[i]) {
1244             ua->send_msg(slot_hformat,
1245                          i, ' ', "", "", "", "");
1246             slot_list[i]=0;
1247          }
1248       }
1249
1250       memset(&mr, 0, sizeof(MEDIA_DBR));
1251       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1252
1253       if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
1254          memset(&pr, 0, sizeof(POOL_DBR));
1255          pr.PoolId = mr.PoolId;
1256          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1257             strcpy(pr.Name, "?");
1258          }
1259
1260          /* Print information */
1261          ua->send_msg(slot_hformat,
1262                       vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
1263                       mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
1264
1265       } else {                  /* TODO: get information from catalog  */
1266          ua->send_msg(slot_hformat,
1267                       vl->Slot, '*',
1268                       mr.VolumeName, "?", "?", "?");
1269       }
1270    }
1271
1272    /* Display the rest of the autochanger
1273     */
1274    for (; i <= max_slots; i++) {
1275       if (slot_list[i]) {
1276          ua->send_msg(slot_hformat,
1277                       i, ' ', "", "", "", "");
1278          slot_list[i]=0;
1279       }
1280    }
1281
1282 bail_out:
1283
1284    free_vol_list(vol_list);
1285    free(slot_list);
1286    close_sd_bsock(ua);
1287
1288    return;
1289 }