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