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