2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2007 Free Software Foundation Europe e.V.
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
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.
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
23 Bacula® is a registered trademark of John Walker.
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.
30 * Bacula Director -- Tape labeling commands
32 * Kern Sibbald, April MMIII
40 /* Slot list definition */
41 typedef struct s_vol_list {
42 struct s_vol_list *next;
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);
65 * label storage=xxx volume=vvv
67 int label_cmd(UAContext *ua, const char *cmd)
69 return do_label(ua, cmd, 0); /* standard label */
72 int relabel_cmd(UAContext *ua, const char *cmd)
74 return do_label(ua, cmd, 1); /* relabel tape */
77 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
82 /* slots are numbered 1 to num_slots */
83 for (int i=0; i <= num_slots; i++) {
86 i = find_arg_with_value(ua, "slots");
88 /* scan slot list in ua->argv[i] */
92 strip_trailing_junk(ua->argv[i]);
93 for (p=ua->argv[i]; p && *p; p=e) {
100 h = strchr(p, '-'); /* range? */
102 msg = _("Negative numbers not permitted\n");
107 if (!is_an_integer(h)) {
108 msg = _("Range end is not integer.\n");
112 if (!is_an_integer(p)) {
113 msg = _("Range start is not an integer.\n");
119 msg = _("Range end not bigger than start.\n");
124 if (!is_an_integer(p)) {
125 msg = _("Input value is not an integer.\n");
130 if (beg <= 0 || end <= 0) {
131 msg = _("Values must be be greater than zero.\n");
134 if (end > num_slots) {
135 msg = _("Slot too large.\n");
138 for (i=beg; i<=end; i++) {
139 slot_list[i] = 1; /* Turn on specified range */
143 /* Turn everything on */
144 for (i=1; i <= num_slots; i++) {
148 Dmsg0(100, "Slots turned on:\n");
149 for (i=1; i <= num_slots; i++) {
151 Dmsg1(100, "%d\n", i);
161 * Update Slots corresponding to Volumes in autochanger
163 void update_slots(UAContext *ua)
166 vol_list_t *vl, *vol_list = NULL;
177 if (!open_client_db(ua)) {
180 store.store = get_storage_resource(ua, true/*arg is storage*/);
184 pm_strcpy(store.store_source, _("command line"));
185 set_wstorage(ua->jcr, &store);
186 drive = get_storage_drive(ua, store.store);
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]);
196 have_enabled = false;
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"));
205 slot_list = (char *)malloc(max_slots+1);
206 if (!get_user_slot_list(ua, slot_list, max_slots)) {
211 vol_list = get_vol_list_from_SD(ua, scan);
214 ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
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);
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);
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);
233 /* If scanning, we read the label rather than the barcode */
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);
242 slot_list[vl->Slot] = 0; /* clear Slot */
243 memset(&mr, 0, sizeof(mr));
246 mr.StorageId = store.store->StorageId;
247 /* Set InChanger to zero for this Slot */
249 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
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);
256 memset(&mr, 0, sizeof(mr));
257 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
259 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
260 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
263 mr.StorageId = store.store->StorageId;
265 mr.Enabled = Enabled;
267 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
268 ua->error_msg("%s", db_strerror(ua->db));
271 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
272 mr.VolumeName, mr.Slot);
275 ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"),
281 ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
282 mr.VolumeName, vl->Slot);
286 memset(&mr, 0, sizeof(mr));
288 mr.StorageId = store.store->StorageId;
290 for (int i=1; i <= max_slots; i++) {
293 /* Set InChanger to zero for this Slot */
294 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
301 free_vol_list(vol_list);
310 * Common routine for both label and relabel
312 static int do_label(UAContext *ua, const char *cmd, int relabel)
316 char dev_name[MAX_NAME_LENGTH];
319 bool print_reminder = true;
320 bool label_barcodes = false;
324 bool media_record_exists = false;
325 static const char *barcode_keyword[] = {
331 memset(&pr, 0, sizeof(pr));
332 if (!open_client_db(ua)) {
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 */
342 label_barcodes = true;
345 store.store = get_storage_resource(ua, true/*use default*/);
349 pm_strcpy(store.store_source, _("command line"));
350 set_wstorage(ua->jcr, &store);
351 drive = get_storage_drive(ua, store.store);
353 if (label_barcodes) {
354 label_from_barcodes(ua, drive);
358 /* If relabel get name of Volume to relabel */
360 /* Check for oldvolume=name */
361 i = find_arg_with_value(ua, "oldvolume");
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)) {
368 ua->error_msg("%s", db_strerror(ua->db));
370 /* No keyword or Vol not found, ask user to select */
371 if (!select_media_dbr(ua, &omr)) {
375 /* Require Volume to be Purged or Recycled */
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);
384 /* Check for volume=NewVolume */
385 i = find_arg_with_value(ua, "volume");
387 pm_strcpy(ua->cmd, ua->argv[i]);
391 /* Get a new Volume name */
393 media_record_exists = false;
394 if (!get_cmd(ua, _("Enter new Volume name: "))) {
398 if (!is_volume_name_legal(ua, ua->cmd)) {
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"),
411 media_record_exists = true;
416 /* If autochanger, request slot */
417 i = find_arg_with_value(ua, "slot");
419 mr.Slot = atoi(ua->argv[i]);
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): "))) {
428 mr.Slot = ua->pint32_val;
432 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
434 mr.StorageId = store.store->StorageId;
436 bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
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)) {
446 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
449 sd = ua->jcr->store_bsock;
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));
456 ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
458 /* Update the number of Volumes in the pool */
460 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
461 ua->error_msg("%s", db_strerror(ua->db));
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);
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
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;
488 if (print_reminder) {
489 ua->info_msg(_("Do not forget to mount the drive!!!\n"));
497 * Request SD to send us the slot:barcodes, then wiffle
498 * through them all labeling them.
500 static void label_from_barcodes(UAContext *ua, int drive)
502 STORE *store = ua->jcr->wstore;
505 vol_list_t *vl, *vol_list = NULL;
506 bool media_record_exists;
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"));
516 slot_list = (char *)malloc(max_slots+1);
517 if (!get_user_slot_list(ua, slot_list, max_slots)) {
521 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
524 ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
528 /* Display list of Volumes and ask if he really wants to proceed */
529 ua->send_msg(_("The following Volumes will be labeled:\n"
531 "==============\n"));
532 for (vl=vol_list; vl; vl=vl->next) {
533 if (!vl->VolName || !slot_list[vl->Slot]) {
536 ua->send_msg("%4d %s\n", vl->Slot, vl->VolName);
538 if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) ||
539 (ua->pint32_val == 0)) {
543 memset(&pr, 0, sizeof(pr));
544 if (!select_pool_dbr(ua, &pr)) {
547 memset(&omr, 0, sizeof(omr));
549 /* Fire off the label requests */
550 for (vl=vol_list; vl; vl=vl->next) {
551 if (!vl->VolName || !slot_list[vl->Slot]) {
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);
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));
569 media_record_exists = true;
571 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
572 mr.StorageId = store->StorageId;
574 * Deal with creating cleaning tape here. Normal tapes created in
575 * send_label_request() below
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));
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));
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);
591 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
592 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
594 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
595 ua->send_msg(_("Catalog record for cleaning tape \"%s\" successfully created.\n"),
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));
602 ua->error_msg(_("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
605 continue; /* done, go handle next volume */
607 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
610 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
616 free_vol_list(vol_list);
623 * Check if the Volume name has legal characters
624 * If ua is non-NULL send the message
626 bool is_volume_name_legal(UAContext *ua, const char *name)
630 const char *accept = ":.-_";
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))) {
638 ua->error_msg(_("Illegal character \"%c\" in a volume name.\n"), *p);
643 if (len >= MAX_NAME_LENGTH) {
645 ua->error_msg(_("Volume name too long.\n"));
651 ua->error_msg(_("Volume name must be at least one character long.\n"));
659 * NOTE! This routine opens the SD socket but leaves it open
661 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
662 POOL_DBR *pr, int relabel, bool media_record_exists,
666 char dev_name[MAX_NAME_LENGTH];
669 uint64_t VolBytes = 0;
671 if (!(sd=open_sd_bsock(ua))) {
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);
680 bash_spaces(omr->VolumeName);
681 bnet_fsend(sd, "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);
688 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
690 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
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);
698 while (bnet_recv(sd) >= 0) {
700 ua->send_msg("%s", sd->msg);
701 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
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;
713 /* We know that a freshly labelled DVD has 1 VolParts */
714 /* This does not apply to auto-labelled DVDs. */
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));
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;
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 */
737 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
738 ua->error_msg("%s", db_strerror(ua->db));
741 ua->error_msg("%s", db_strerror(ua->db));
746 ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
751 static BSOCK *open_sd_bsock(UAContext *ua)
753 STORE *store = ua->jcr->wstore;
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"));
763 return ua->jcr->store_bsock;
766 static void close_sd_bsock(UAContext *ua)
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;
775 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
777 STORE *store = ua->jcr->wstore;
779 char dev_name[MAX_NAME_LENGTH];
780 char *VolName = NULL;
783 if (!(sd=open_sd_bsock(ua))) {
784 ua->error_msg(_("Could not open SD socket.\n"));
787 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
788 bash_spaces(dev_name);
789 /* Ask for autochanger list of volumes */
790 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
791 Dmsg1(100, "Sent: %s", sd->msg);
793 /* Get Volume name in this Slot */
794 while (bnet_recv(sd) >= 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) {
807 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
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)
816 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
818 STORE *store = ua->jcr->wstore;
819 char dev_name[MAX_NAME_LENGTH];
822 vol_list_t *vol_list = NULL;
825 if (!(sd=open_sd_bsock(ua))) {
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);
834 /* Read and organize list of Volumes */
835 while (bnet_recv(sd) >= 0) {
838 strip_trailing_junk(sd->msg);
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]) &&
844 ua->send_msg("%s\n", sd->msg); /* pass them on to user */
848 /* Validate Slot: if scanning, otherwise Slot:Barcode */
849 p = strchr(sd->msg, ':');
851 /* Scanning -- require only valid slot */
852 Slot = atoi(sd->msg);
856 ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
861 if (p && strlen(p) > 1) {
863 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
866 ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
872 if (!is_volume_name_legal(ua, p)) {
875 ua->error_msg(_("Invalid Volume name: %s\n"), sd->msg);
880 /* Add Slot and VolumeName to list */
881 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
885 p++; /* skip separator */
887 vl->VolName = bstrdup(p);
891 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
896 /* Add new entry to end of list */
897 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
910 static void free_vol_list(vol_list_t *vol_list)
915 for (vl=vol_list; vl; ) {
927 * We get the number of slots in the changer from the SD
929 static int get_num_slots_from_SD(UAContext *ua)
931 STORE *store = ua->jcr->wstore;
932 char dev_name[MAX_NAME_LENGTH];
937 if (!(sd=open_sd_bsock(ua))) {
941 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
942 bash_spaces(dev_name);
943 /* Ask for autochanger number of slots */
944 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
946 while (bnet_recv(sd) >= 0) {
947 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
950 ua->send_msg("%s", sd->msg);
954 ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
959 * We get the number of drives in the changer from the SD
961 int get_num_drives_from_SD(UAContext *ua)
963 STORE *store = ua->jcr->wstore;
964 char dev_name[MAX_NAME_LENGTH];
969 if (!(sd=open_sd_bsock(ua))) {
973 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
974 bash_spaces(dev_name);
975 /* Ask for autochanger number of slots */
976 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
978 while (bnet_recv(sd) >= 0) {
979 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
982 ua->send_msg("%s", sd->msg);
986 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
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
998 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
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);
1007 if (ua->jcr->pool->cleaning_prefix == NULL) {
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;