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