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