]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
fix status slots command when SD slots are mixed
[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          vol_list_t *prev=vol_list;
897          /* Add new entry to the right place in the list */
898          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
899             if (tvl->Slot > vl->Slot) {
900                /* no previous item, update vol_list directly */
901                if (prev == vol_list) {  
902                   vl->next = vol_list;
903                   vol_list = vl;
904
905                } else {     /* replace the previous pointer */
906                   prev->next = vl;
907                   vl->next = tvl;
908                }
909                break;
910             }
911             /* we are at the end */
912             if (!tvl->next) {
913                tvl->next = vl;
914                vl->next = NULL;
915                break;
916             }
917             prev = tvl;
918          }
919       }
920    }
921    close_sd_bsock(ua);
922    return vol_list;
923 }
924
925 static void free_vol_list(vol_list_t *vol_list)
926 {
927    vol_list_t *vl;
928
929    /* Free list */
930    for (vl=vol_list; vl; ) {
931       vol_list_t *ovl;
932       if (vl->VolName) {
933          free(vl->VolName);
934       }
935       ovl = vl;
936       vl = vl->next;
937       free(ovl);
938    }
939 }
940
941 /*
942  * We get the number of slots in the changer from the SD
943  */
944 static int get_num_slots_from_SD(UAContext *ua)
945 {
946    STORE *store = ua->jcr->wstore;
947    char dev_name[MAX_NAME_LENGTH];
948    BSOCK *sd;
949    int slots = 0;
950
951
952    if (!(sd=open_sd_bsock(ua))) {
953       return 0;
954    }
955
956    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
957    bash_spaces(dev_name);
958    /* Ask for autochanger number of slots */
959    sd->fsend(NT_("autochanger slots %s\n"), dev_name);
960
961    while (sd->recv() >= 0) {
962       if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
963          break;
964       } else {
965          ua->send_msg("%s", sd->msg);
966       }
967    }
968    close_sd_bsock(ua);
969    ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
970    return slots;
971 }
972
973 /*
974  * We get the number of drives in the changer from the SD
975  */
976 int get_num_drives_from_SD(UAContext *ua)
977 {
978    STORE *store = ua->jcr->wstore;
979    char dev_name[MAX_NAME_LENGTH];
980    BSOCK *sd;
981    int drives = 0;
982
983
984    if (!(sd=open_sd_bsock(ua))) {
985       return 0;
986    }
987
988    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
989    bash_spaces(dev_name);
990    /* Ask for autochanger number of slots */
991    sd->fsend(NT_("autochanger drives %s\n"), dev_name);
992
993    while (sd->recv() >= 0) {
994       if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
995          break;
996       } else {
997          ua->send_msg("%s", sd->msg);
998       }
999    }
1000    close_sd_bsock(ua);
1001 //   bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
1002    return drives;
1003 }
1004
1005 /*
1006  * Check if this is a cleaning tape by comparing the Volume name
1007  *  with the Cleaning Prefix. If they match, this is a cleaning
1008  *  tape.
1009  */
1010 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
1011 {
1012    /* Find Pool resource */
1013    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
1014    if (!ua->jcr->pool) {
1015       ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
1016          pr->Name, mr->VolumeName);
1017       return false;
1018    }
1019    if (ua->jcr->pool->cleaning_prefix == NULL) {
1020       return false;
1021    }
1022    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1023       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1024       strlen(ua->jcr->pool->cleaning_prefix),
1025       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1026                   strlen(ua->jcr->pool->cleaning_prefix)));
1027    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1028                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
1029 }
1030
1031 static void content_send_info(UAContext *ua, char type, int Slot, char *vol_name)
1032 {
1033    char ed1[50], ed2[50], ed3[50];
1034    POOL_DBR pr;
1035    MEDIA_DBR mr;
1036    /* Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
1037    const char *slot_api_full_format="%c|%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
1038    const char *slot_api_empty_format="%c|%i||||||||\n";
1039
1040    if (is_volume_name_legal(NULL, vol_name)) {
1041       memset(&mr, 0, sizeof(mr));
1042       bstrncpy(mr.VolumeName, vol_name, sizeof(mr.VolumeName));
1043       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
1044          memset(&pr, 0, sizeof(POOL_DBR));
1045          pr.PoolId = mr.PoolId;
1046          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1047             strcpy(pr.Name, "?");
1048          }
1049          ua->send_msg(slot_api_full_format, type,
1050                       Slot, mr.Slot, mr.VolumeName, 
1051                       edit_uint64(mr.VolBytes, ed1), 
1052                       mr.VolStatus, mr.MediaType, pr.Name, 
1053                       edit_uint64(mr.LastWritten, ed2),
1054                       edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
1055          
1056       } else {                  /* Media unknown */
1057          ua->send_msg(slot_api_full_format,
1058                       type, Slot, 0, mr.VolumeName, "?", "?", "?", "?", 
1059                       "0", "0");
1060          
1061       }
1062    } else {
1063       ua->send_msg(slot_api_empty_format, type, Slot);
1064    }
1065 }         
1066
1067 /* 
1068  * Input (output of mxt-changer listall):
1069  *
1070  * Drive content:         D:Drive num:F:Slot loaded:Volume Name
1071  * D:0:F:2:vol2        or D:Drive num:E
1072  * D:1:F:42:vol42   
1073  * D:3:E
1074  *
1075  * Slot content:
1076  * S:1:F:vol1             S:Slot num:F:Volume Name
1077  * S:2:E               or S:Slot num:E
1078  * S:3:F:vol4
1079  *
1080  * Import/Export tray slots:
1081  * I:10:F:vol10           I:Slot num:F:Volume Name
1082  * I:11:E              or I:Slot num:E
1083  * I:12:F:vol40
1084  *
1085  * If a drive is loaded, the slot *should* be empty 
1086  * 
1087  * Output:
1088  *
1089  * Drive list:       D|Drive num|Slot loaded|Volume Name
1090  * D|0|45|vol45
1091  * D|1|42|vol42
1092  * D|3||
1093  *
1094  * Slot list: Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire
1095  *
1096  * S|1|1|vol1|31417344|Full|LTO1-ANSI|Inc|1250858902|1282394902
1097  * S|2||||||||
1098  * S|3|3|vol4|15869952|Append|LTO1-ANSI|Inc|1250858907|1282394907
1099  *
1100  * TODO: need to merge with status_slots()
1101  */
1102 void status_content(UAContext *ua, STORE *store)
1103 {
1104    int Slot, Drive;
1105    char type;
1106    char dev_name[MAX_NAME_LENGTH];
1107    char vol_name[MAX_NAME_LENGTH];
1108    BSOCK *sd;
1109    vol_list_t *vl=NULL, *vol_list = NULL;
1110
1111    if (!(sd=open_sd_bsock(ua))) {
1112       return;
1113    }
1114
1115    if (!open_client_db(ua)) {
1116       return;
1117    }
1118
1119    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1120    bash_spaces(dev_name);
1121    /* Ask for autochanger list of volumes */
1122    bnet_fsend(sd, NT_("autochanger listall %s \n"), dev_name);
1123
1124    /* Read and organize list of Drive, Slots and I/O Slots */
1125    while (bnet_recv(sd) >= 0) {
1126       strip_trailing_junk(sd->msg);
1127
1128       /* Check for returned SD messages */
1129       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
1130           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
1131           sd->msg[4] == ' ') {
1132          ua->send_msg("%s\n", sd->msg);   /* pass them on to user */
1133          continue;
1134       }
1135
1136       Drive = Slot = -1;
1137       *vol_name = 0;
1138
1139       if (sscanf(sd->msg, "D:%d:F:%d:%127s", &Drive, &Slot, vol_name) == 3) {
1140          ua->send_msg("D|%d|%d|%s\n", Drive, Slot, vol_name);
1141
1142          /* we print information on the slot if we have a volume name */
1143          if (*vol_name) {
1144             /* Add Slot and VolumeName to list */
1145             vl = (vol_list_t *)malloc(sizeof(vol_list_t));
1146             vl->Slot = Slot;
1147             vl->VolName = bstrdup(vol_name);
1148             vl->next = vol_list;
1149             vol_list = vl;
1150          }
1151
1152       } else if (sscanf(sd->msg, "D:%d:E", &Drive) == 1) {
1153          ua->send_msg("D|%d||\n", Drive);
1154
1155       } else if (sscanf(sd->msg, "%c:%d:F:%127s", &type, &Slot, vol_name)== 3) {
1156          content_send_info(ua, type, Slot, vol_name);
1157
1158       } else if (sscanf(sd->msg, "%c:%d:E", &type, &Slot) == 2) {
1159          /* type can be S (slot) or I (Import/Export slot) */
1160          vol_list_t *prev=NULL;
1161          for (vl = vol_list; vl; vl = vl->next) {
1162             if (vl->Slot == Slot) {
1163                bstrncpy(vol_name, vl->VolName, MAX_NAME_LENGTH);
1164
1165                /* remove the node */
1166                if (prev) {
1167                   prev->next = vl->next;
1168                } else {
1169                   vol_list = vl->next;
1170                }
1171                free(vl->VolName);
1172                free(vl);
1173                break;
1174             }
1175             prev = vl;
1176          }
1177          content_send_info(ua, type, Slot, vol_name);
1178
1179       } else {
1180          Dmsg1(10, "Discarding msg=%s\n", sd->msg);
1181       }
1182    }
1183    close_sd_bsock(ua);
1184 }
1185
1186 /*
1187  * Print slots from AutoChanger
1188  */
1189 void status_slots(UAContext *ua, STORE *store_r)
1190 {
1191    USTORE store;
1192    POOL_DBR pr;
1193    vol_list_t *vl, *vol_list = NULL;
1194    MEDIA_DBR mr;
1195    char *slot_list;
1196    int max_slots;
1197    int drive;
1198    int i=1;
1199    /* Slot | Volume | Status | MediaType | Pool */
1200    const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
1201
1202    if (ua->api) {
1203       status_content(ua, store_r);
1204       return;
1205    }
1206
1207    if (!open_client_db(ua)) {
1208       return;
1209    }
1210    store.store = store_r;
1211
1212    pm_strcpy(store.store_source, _("command line"));
1213    set_wstorage(ua->jcr, &store);
1214    drive = get_storage_drive(ua, store.store);
1215
1216    max_slots = get_num_slots_from_SD(ua);
1217
1218    if (max_slots <= 0) {
1219       ua->warning_msg(_("No slots in changer to scan.\n"));
1220       return;
1221    }
1222    slot_list = (char *)malloc(max_slots+1);
1223    if (!get_user_slot_list(ua, slot_list, max_slots)) {
1224       free(slot_list);
1225       return;
1226    }
1227
1228    vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
1229
1230    if (!vol_list) {
1231       ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
1232       goto bail_out;
1233    }
1234    ua->send_msg(_(" Slot |   Volume Name    |   Status  |     Media Type       |      Pool          |\n"));
1235    ua->send_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
1236
1237    /* Walk through the list getting the media records */
1238    for (vl=vol_list; vl; vl=vl->next) {
1239       if (vl->Slot > max_slots) {
1240          ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
1241             vl->Slot, max_slots);
1242          continue;
1243       }
1244       /* Check if user wants us to look at this slot */
1245       if (!slot_list[vl->Slot]) {
1246          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
1247          continue;
1248       }
1249
1250       slot_list[vl->Slot] = 0;        /* clear Slot */
1251
1252       if (!vl->VolName) {
1253          Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
1254          ua->send_msg(slot_hformat,
1255                       vl->Slot, '*',
1256                       "?", "?", "?", "?");
1257          continue;
1258       }
1259
1260       /* Hope that slots are ordered */
1261       for (; i < vl->Slot; i++) {
1262          if (slot_list[i]) {
1263             ua->send_msg(slot_hformat,
1264                          i, ' ', "", "", "", "");
1265             slot_list[i]=0;
1266          }
1267       }
1268
1269       memset(&mr, 0, sizeof(mr));
1270       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1271       db_lock(ua->db);
1272       if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
1273          memset(&pr, 0, sizeof(POOL_DBR));
1274          pr.PoolId = mr.PoolId;
1275          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1276             strcpy(pr.Name, "?");
1277          }
1278          db_unlock(ua->db);
1279
1280          /* Print information */
1281          ua->send_msg(slot_hformat,
1282                       vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
1283                       mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
1284          continue;
1285       } else {                  /* TODO: get information from catalog  */
1286          ua->send_msg(slot_hformat,
1287                       vl->Slot, '*',
1288                       mr.VolumeName, "?", "?", "?");
1289       }
1290       db_unlock(ua->db);
1291    }
1292
1293    /* Display the rest of the autochanger
1294     */
1295    for (; i <= max_slots; i++) {
1296       if (slot_list[i]) {
1297          ua->send_msg(slot_hformat,
1298                       i, ' ', "", "", "", "");
1299          slot_list[i]=0;
1300       }
1301    }
1302
1303 bail_out:
1304
1305    free_vol_list(vol_list);
1306    free(slot_list);
1307    close_sd_bsock(ua);
1308
1309    return;
1310 }