3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2003-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
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;
180 store = get_storage_resource(ua, true/*arg is storage*/);
184 set_wstorage(ua->jcr, store);
185 drive = get_storage_drive(ua, store);
187 scan = find_arg(ua, NT_("scan")) >= 0;
188 if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
189 Enabled = get_enabled(ua, ua->argv[i]);
195 have_enabled = false;
198 max_slots = get_num_slots_from_SD(ua);
199 Dmsg1(100, "max_slots=%d\n", max_slots);
200 if (max_slots <= 0) {
201 bsendmsg(ua, _("No slots in changer to scan.\n"));
204 slot_list = (char *)malloc(max_slots+1);
205 if (!get_user_slot_list(ua, slot_list, max_slots)) {
210 vol_list = get_vol_list_from_SD(ua, scan);
213 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
217 /* First zap out any InChanger with StorageId=0 */
218 db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
220 /* Walk through the list updating the media records */
221 for (vl=vol_list; vl; vl=vl->next) {
222 if (vl->Slot > max_slots) {
223 bsendmsg(ua, _("Slot %d greater than max %d ignored.\n"),
224 vl->Slot, max_slots);
227 /* Check if user wants us to look at this slot */
228 if (!slot_list[vl->Slot]) {
229 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
232 /* If scanning, we read the label rather than the barcode */
238 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
239 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
241 slot_list[vl->Slot] = 0; /* clear Slot */
242 memset(&mr, 0, sizeof(mr));
245 mr.StorageId = store->StorageId;
246 /* Set InChanger to zero for this Slot */
248 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
251 Dmsg1(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
252 bsendmsg(ua, _("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
255 memset(&mr, 0, sizeof(mr));
256 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
258 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
259 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
262 mr.StorageId = store->StorageId;
264 mr.Enabled = Enabled;
266 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
267 bsendmsg(ua, "%s", db_strerror(ua->db));
270 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
271 mr.VolumeName, mr.Slot);
274 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
280 bsendmsg(ua, _("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
281 mr.VolumeName, vl->Slot);
285 memset(&mr, 0, sizeof(mr));
287 mr.StorageId = store->StorageId;
289 for (int i=1; i <= max_slots; i++) {
292 /* Set InChanger to zero for this Slot */
293 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
300 free_vol_list(vol_list);
309 * Common routine for both label and relabel
311 static int do_label(UAContext *ua, const char *cmd, int relabel)
315 char dev_name[MAX_NAME_LENGTH];
318 bool print_reminder = true;
319 bool label_barcodes = false;
323 bool media_record_exists = false;
324 static const char *barcode_keyword[] = {
330 memset(&pr, 0, sizeof(pr));
335 /* Look for one of the barcode keywords */
336 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
337 /* Now find the keyword in the list */
338 if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
339 *ua->argk[j] = 0; /* zap barcode keyword */
341 label_barcodes = true;
344 store = get_storage_resource(ua, true/*use default*/);
348 set_wstorage(ua->jcr, store);
349 drive = get_storage_drive(ua, store);
351 if (label_barcodes) {
352 label_from_barcodes(ua, drive);
356 /* If relabel get name of Volume to relabel */
358 /* Check for oldvolume=name */
359 i = find_arg_with_value(ua, "oldvolume");
361 memset(&omr, 0, sizeof(omr));
362 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
363 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
366 bsendmsg(ua, "%s", db_strerror(ua->db));
368 /* No keyword or Vol not found, ask user to select */
369 if (!select_media_dbr(ua, &omr)) {
373 /* Require Volume to be Purged or Recycled */
375 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
376 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
377 omr.VolumeName, omr.VolStatus);
382 /* Check for volume=NewVolume */
383 i = find_arg_with_value(ua, "volume");
385 pm_strcpy(ua->cmd, ua->argv[i]);
389 /* Get a new Volume name */
391 media_record_exists = false;
392 if (!get_cmd(ua, _("Enter new Volume name: "))) {
396 if (!is_volume_name_legal(ua, ua->cmd)) {
400 memset(&mr, 0, sizeof(mr));
401 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
402 /* If VolBytes are zero the Volume is not labeled */
403 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
404 if (mr.VolBytes != 0) {
405 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
409 media_record_exists = true;
414 /* If autochanger, request slot */
415 i = find_arg_with_value(ua, "slot");
417 mr.Slot = atoi(ua->argv[i]);
418 mr.InChanger = 1; /* assumed if we are labeling it */
419 } else if (store->autochanger) {
420 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
423 mr.Slot = ua->pint32_val;
424 mr.InChanger = 1; /* assumed if we are labeling it */
426 mr.StorageId = store->StorageId;
428 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
430 /* Must select Pool if not already done */
431 if (pr.PoolId == 0) {
432 memset(&pr, 0, sizeof(pr));
433 if (!select_pool_dbr(ua, &pr)) {
438 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
441 sd = ua->jcr->store_bsock;
443 /* Delete the old media record */
444 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
445 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
446 omr.VolumeName, db_strerror(ua->db));
448 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
450 /* Update the number of Volumes in the pool */
452 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
453 bsendmsg(ua, "%s", db_strerror(ua->db));
458 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
459 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
460 bash_spaces(dev_name);
461 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
462 unbash_spaces(dev_name);
463 while (bnet_recv(sd) >= 0) {
464 bsendmsg(ua, "%s", sd->msg);
466 * 3001 OK mount. Device=xxx or
467 * 3001 Mounted Volume vvvv
468 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
469 * 3906 is cannot mount non-tape
470 * So for those, no need to print a reminder
472 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
473 strncmp(sd->msg, "3002 ", 5) == 0 ||
474 strncmp(sd->msg, "3906 ", 5) == 0) {
475 print_reminder = false;
480 if (print_reminder) {
481 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
489 * Request SD to send us the slot:barcodes, then wiffle
490 * through them all labeling them.
492 static void label_from_barcodes(UAContext *ua, int drive)
494 STORE *store = ua->jcr->wstore;
497 vol_list_t *vl, *vol_list = NULL;
498 bool media_record_exists;
503 max_slots = get_num_slots_from_SD(ua);
504 if (max_slots <= 0) {
505 bsendmsg(ua, _("No slots in changer to scan.\n"));
508 slot_list = (char *)malloc(max_slots+1);
509 if (!get_user_slot_list(ua, slot_list, max_slots)) {
513 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
516 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
520 /* Display list of Volumes and ask if he really wants to proceed */
521 bsendmsg(ua, _("The following Volumes will be labeled:\n"
523 "==============\n"));
524 for (vl=vol_list; vl; vl=vl->next) {
525 if (!vl->VolName || !slot_list[vl->Slot]) {
528 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
530 if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) ||
531 (ua->pint32_val == 0)) {
535 memset(&pr, 0, sizeof(pr));
536 if (!select_pool_dbr(ua, &pr)) {
539 memset(&omr, 0, sizeof(omr));
541 /* Fire off the label requests */
542 for (vl=vol_list; vl; vl=vl->next) {
543 if (!vl->VolName || !slot_list[vl->Slot]) {
546 memset(&mr, 0, sizeof(mr));
547 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
548 media_record_exists = false;
549 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
550 if (mr.VolBytes != 0) {
551 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
552 vl->Slot, mr.VolumeName);
555 mr.StorageId = store->StorageId;
556 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
557 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
561 media_record_exists = true;
564 mr.StorageId = store->StorageId;
566 * Deal with creating cleaning tape here. Normal tapes created in
567 * send_label_request() below
569 if (is_cleaning_tape(ua, &mr, &pr)) {
570 if (media_record_exists) { /* we update it */
571 mr.VolBytes = 1; /* any bytes to indicate it exists */
572 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
574 mr.StorageId = store->StorageId;
575 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
576 bsendmsg(ua, "%s", db_strerror(ua->db));
578 } else { /* create the media record */
579 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
580 bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
583 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
584 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
586 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
587 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
589 pr.NumVols++; /* this is a bit suspect */
590 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
591 bsendmsg(ua, "%s", db_strerror(ua->db));
594 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
597 continue; /* done, go handle next volume */
599 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
602 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
608 free_vol_list(vol_list);
615 * Check if the Volume name has legal characters
616 * If ua is non-NULL send the message
618 bool is_volume_name_legal(UAContext *ua, const char *name)
622 const char *accept = ":.-_";
624 /* Restrict the characters permitted in the Volume name */
625 for (p=name; *p; p++) {
626 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
630 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
635 if (len >= MAX_NAME_LENGTH) {
637 bsendmsg(ua, _("Volume name too long.\n"));
643 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
651 * NOTE! This routine opens the SD socket but leaves it open
653 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
654 POOL_DBR *pr, int relabel, bool media_record_exists,
658 char dev_name[MAX_NAME_LENGTH];
661 uint64_t VolBytes = 0;
663 if (!(sd=open_sd_bsock(ua))) {
666 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
667 bash_spaces(dev_name);
668 bash_spaces(mr->VolumeName);
669 bash_spaces(mr->MediaType);
670 bash_spaces(pr->Name);
672 bash_spaces(omr->VolumeName);
673 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
674 "MediaType=%s Slot=%d drive=%d",
675 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
676 mr->MediaType, mr->Slot, drive);
677 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
678 omr->VolumeName, mr->VolumeName);
680 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
682 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
684 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
685 mr->VolumeName, mr->Slot);
686 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
687 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
690 while (bnet_recv(sd) >= 0) {
692 bsendmsg(ua, "%s", sd->msg);
693 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
699 unbash_spaces(mr->VolumeName);
700 unbash_spaces(mr->MediaType);
701 unbash_spaces(pr->Name);
702 mr->LabelDate = time(NULL);
703 mr->set_label_date = true;
705 /* We know that a freshly labelled DVD has 1 VolParts */
706 /* This does not apply to auto-labelled DVDs. */
710 if (media_record_exists) { /* we update it */
711 mr->VolBytes = VolBytes;
713 mr->StorageId = ua->jcr->wstore->StorageId;
714 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
715 bsendmsg(ua, "%s", db_strerror(ua->db));
718 } else { /* create the media record */
719 set_pool_dbr_defaults_in_media_dbr(mr, pr);
720 mr->VolBytes = VolBytes;
722 mr->StorageId = ua->jcr->wstore->StorageId;
724 if (db_create_media_record(ua->jcr, ua->db, mr)) {
725 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
726 mr->VolumeName, mr->Slot);
727 /* Update number of volumes in pool */
729 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
730 bsendmsg(ua, "%s", db_strerror(ua->db));
733 bsendmsg(ua, "%s", db_strerror(ua->db));
738 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
743 static BSOCK *open_sd_bsock(UAContext *ua)
745 STORE *store = ua->jcr->wstore;
747 if (!ua->jcr->store_bsock) {
748 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
749 store->name(), store->address, store->SDport);
750 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
751 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
755 return ua->jcr->store_bsock;
758 static void close_sd_bsock(UAContext *ua)
760 if (ua->jcr->store_bsock) {
761 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
762 bnet_close(ua->jcr->store_bsock);
763 ua->jcr->store_bsock = NULL;
767 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
769 STORE *store = ua->jcr->wstore;
771 char dev_name[MAX_NAME_LENGTH];
772 char *VolName = NULL;
775 if (!(sd=open_sd_bsock(ua))) {
776 bsendmsg(ua, _("Could not open SD socket.\n"));
779 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
780 bash_spaces(dev_name);
781 /* Ask for autochanger list of volumes */
782 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
783 Dmsg1(100, "Sent: %s", sd->msg);
785 /* Get Volume name in this Slot */
786 while (bnet_recv(sd) >= 0) {
787 bsendmsg(ua, "%s", sd->msg);
788 Dmsg1(100, "Got: %s", sd->msg);
789 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
790 VolName = (char *)malloc(sd->msglen);
791 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
799 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
804 * We get the slot list from the Storage daemon.
805 * If scan is set, we return all slots found,
806 * otherwise, we return only slots with valid barcodes (Volume names)
808 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
810 STORE *store = ua->jcr->wstore;
811 char dev_name[MAX_NAME_LENGTH];
814 vol_list_t *vol_list = NULL;
817 if (!(sd=open_sd_bsock(ua))) {
821 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
822 bash_spaces(dev_name);
823 /* Ask for autochanger list of volumes */
824 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
826 /* Read and organize list of Volumes */
827 while (bnet_recv(sd) >= 0) {
830 strip_trailing_junk(sd->msg);
832 /* Check for returned SD messages */
833 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
834 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
836 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
840 /* Validate Slot: if scanning, otherwise Slot:Barcode */
841 p = strchr(sd->msg, ':');
843 /* Scanning -- require only valid slot */
844 Slot = atoi(sd->msg);
848 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
853 if (p && strlen(p) > 1) {
855 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
858 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
864 if (!is_volume_name_legal(ua, p)) {
867 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
872 /* Add Slot and VolumeName to list */
873 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
877 p++; /* skip separator */
879 vl->VolName = bstrdup(p);
883 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
888 /* Add new entry to end of list */
889 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
902 static void free_vol_list(vol_list_t *vol_list)
907 for (vl=vol_list; vl; ) {
919 * We get the number of slots in the changer from the SD
921 static int get_num_slots_from_SD(UAContext *ua)
923 STORE *store = ua->jcr->wstore;
924 char dev_name[MAX_NAME_LENGTH];
929 if (!(sd=open_sd_bsock(ua))) {
933 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
934 bash_spaces(dev_name);
935 /* Ask for autochanger number of slots */
936 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
938 while (bnet_recv(sd) >= 0) {
939 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
942 bsendmsg(ua, "%s", sd->msg);
946 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
951 * We get the number of drives in the changer from the SD
953 int get_num_drives_from_SD(UAContext *ua)
955 STORE *store = ua->jcr->wstore;
956 char dev_name[MAX_NAME_LENGTH];
961 if (!(sd=open_sd_bsock(ua))) {
965 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
966 bash_spaces(dev_name);
967 /* Ask for autochanger number of slots */
968 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
970 while (bnet_recv(sd) >= 0) {
971 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
974 bsendmsg(ua, "%s", sd->msg);
978 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
986 * Check if this is a cleaning tape by comparing the Volume name
987 * with the Cleaning Prefix. If they match, this is a cleaning
990 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
992 /* Find Pool resource */
993 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
994 if (!ua->jcr->pool) {
995 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
996 pr->Name, mr->VolumeName);
999 if (ua->jcr->pool->cleaning_prefix == NULL) {
1002 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1003 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1004 strlen(ua->jcr->pool->cleaning_prefix),
1005 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1006 strlen(ua->jcr->pool->cleaning_prefix)));
1007 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1008 strlen(ua->jcr->pool->cleaning_prefix)) == 0;