]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Merge branch 'master' into basejobv3
[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
992
993 /*
994  * Check if this is a cleaning tape by comparing the Volume name
995  *  with the Cleaning Prefix. If they match, this is a cleaning
996  *  tape.
997  */
998 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
999 {
1000    /* Find Pool resource */
1001    ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
1002    if (!ua->jcr->pool) {
1003       ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
1004          pr->Name, mr->VolumeName);
1005       return false;
1006    }
1007    if (ua->jcr->pool->cleaning_prefix == NULL) {
1008       return false;
1009    }
1010    Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1011       ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1012       strlen(ua->jcr->pool->cleaning_prefix),
1013       strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1014                   strlen(ua->jcr->pool->cleaning_prefix)));
1015    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1016                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
1017 }
1018
1019
1020 /*
1021  * Print slots from AutoChanger
1022  */
1023 void status_slots(UAContext *ua, STORE *store_r)
1024 {
1025    USTORE store;
1026    POOL_DBR pr;
1027    vol_list_t *vl, *vol_list = NULL;
1028    MEDIA_DBR mr;
1029    char ed1[50], ed2[50], ed3[50];
1030    char *slot_list;
1031    int max_slots;
1032    int drive;
1033    int i=1;
1034    /* output format */
1035    const char *slot_api_empty_format="%i||||||||\n";
1036
1037    /* Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
1038    const char *slot_api_full_format="%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
1039
1040    /* Slot | Volume | Status | MediaType | Pool */
1041    const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
1042
1043    if (!open_client_db(ua)) {
1044       return;
1045    }
1046    store.store = store_r;
1047
1048    pm_strcpy(store.store_source, _("command line"));
1049    set_wstorage(ua->jcr, &store);
1050    drive = get_storage_drive(ua, store.store);
1051
1052    max_slots = get_num_slots_from_SD(ua);
1053
1054    if (max_slots <= 0) {
1055       ua->warning_msg(_("No slots in changer to scan.\n"));
1056       return;
1057    }
1058    slot_list = (char *)malloc(max_slots+1);
1059    if (!get_user_slot_list(ua, slot_list, max_slots)) {
1060       free(slot_list);
1061       return;
1062    }
1063
1064    vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
1065
1066    if (!vol_list) {
1067       ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
1068       goto bail_out;
1069    }
1070    if (!ua->api) {
1071       ua->send_msg(_(" Slot |   Volume Name    |   Status  |     Media Type       |      Pool          |\n"));
1072       ua->send_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
1073    }
1074
1075    /* Walk through the list getting the media records */
1076    for (vl=vol_list; vl; vl=vl->next) {
1077       if (vl->Slot > max_slots) {
1078          ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
1079             vl->Slot, max_slots);
1080          continue;
1081       }
1082       /* Check if user wants us to look at this slot */
1083       if (!slot_list[vl->Slot]) {
1084          Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
1085          continue;
1086       }
1087
1088       slot_list[vl->Slot] = 0;        /* clear Slot */
1089
1090       if (!vl->VolName) {
1091          Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
1092          if (ua->api) {
1093             ua->send_msg(slot_api_empty_format, vl->Slot);
1094
1095          } else {
1096             ua->send_msg(slot_hformat,
1097                          vl->Slot, '*',
1098                          "?", "?", "?", "?");
1099          }
1100          continue;
1101       }
1102
1103       /* Hope that slots are ordered */
1104       for (; i < vl->Slot; i++) {
1105          if (slot_list[i]) {
1106             if (ua->api) {
1107                ua->send_msg(slot_api_empty_format, i);
1108
1109             } else {
1110                ua->send_msg(slot_hformat,
1111                             i, ' ', "", "", "", "");
1112             }       
1113             slot_list[i]=0;
1114          }
1115       }
1116
1117       memset(&mr, 0, sizeof(mr));
1118       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1119       db_lock(ua->db);
1120       if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
1121          memset(&pr, 0, sizeof(POOL_DBR));
1122          pr.PoolId = mr.PoolId;
1123          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1124             strcpy(pr.Name, "?");
1125          }
1126          db_unlock(ua->db);
1127
1128          if (ua->api) {
1129             ua->send_msg(slot_api_full_format,
1130                          vl->Slot, mr.Slot, mr.VolumeName, 
1131                          edit_uint64(mr.VolBytes, ed1), 
1132                          mr.VolStatus, mr.MediaType, pr.Name, 
1133                          edit_uint64(mr.LastWritten, ed2),
1134                          edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
1135          } else {
1136             /* Print information */
1137             ua->send_msg(slot_hformat,
1138                          vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
1139                          mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
1140          }
1141
1142          continue;
1143       } else {                  /* TODO: get information from catalog  */
1144          if (ua->api) {
1145             ua->send_msg(slot_api_empty_format, vl->Slot);
1146
1147          } else {
1148             ua->send_msg(slot_hformat,
1149                          vl->Slot, '*',
1150                          mr.VolumeName, "?", "?", "?");
1151          }
1152       }
1153       db_unlock(ua->db);
1154    }
1155
1156    /* Display the rest of the autochanger
1157     */
1158    for (; i <= max_slots; i++) {
1159       if (slot_list[i]) {
1160          if (!ua->api) {
1161             ua->send_msg(slot_api_empty_format, i);
1162
1163          } else {
1164             ua->send_msg(slot_hformat,
1165                          i, ' ', "", "", "", "");
1166          } 
1167          slot_list[i]=0;
1168       }
1169    }
1170
1171 bail_out:
1172
1173    free_vol_list(vol_list);
1174    free(slot_list);
1175    close_sd_bsock(ua);
1176
1177    return;
1178 }