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