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;
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 bsendmsg(ua, _("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 bsendmsg(ua, _("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 bsendmsg(ua, _("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(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
253 bsendmsg(ua, _("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 bsendmsg(ua, "%s", db_strerror(ua->db));
271 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
272 mr.VolumeName, mr.Slot);
275 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
281 bsendmsg(ua, _("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 bsendmsg(ua, "%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 bsendmsg(ua, _("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 bsendmsg(ua, _("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]);
420 mr.InChanger = 1; /* assumed if we are labeling it */
421 } else if (store.store->autochanger) {
422 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
425 mr.Slot = ua->pint32_val;
426 mr.InChanger = 1; /* assumed if we are labeling it */
428 mr.StorageId = store.store->StorageId;
430 bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
432 /* Must select Pool if not already done */
433 if (pr.PoolId == 0) {
434 memset(&pr, 0, sizeof(pr));
435 if (!select_pool_dbr(ua, &pr)) {
440 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
443 sd = ua->jcr->store_bsock;
445 /* Delete the old media record */
446 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
447 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
448 omr.VolumeName, db_strerror(ua->db));
450 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
452 /* Update the number of Volumes in the pool */
454 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
455 bsendmsg(ua, "%s", db_strerror(ua->db));
460 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
461 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
462 bash_spaces(dev_name);
463 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
464 unbash_spaces(dev_name);
465 while (bnet_recv(sd) >= 0) {
466 bsendmsg(ua, "%s", sd->msg);
468 * 3001 OK mount. Device=xxx or
469 * 3001 Mounted Volume vvvv
470 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
471 * 3906 is cannot mount non-tape
472 * So for those, no need to print a reminder
474 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
475 strncmp(sd->msg, "3002 ", 5) == 0 ||
476 strncmp(sd->msg, "3906 ", 5) == 0) {
477 print_reminder = false;
482 if (print_reminder) {
483 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
491 * Request SD to send us the slot:barcodes, then wiffle
492 * through them all labeling them.
494 static void label_from_barcodes(UAContext *ua, int drive)
496 STORE *store = ua->jcr->wstore;
499 vol_list_t *vl, *vol_list = NULL;
500 bool media_record_exists;
505 max_slots = get_num_slots_from_SD(ua);
506 if (max_slots <= 0) {
507 bsendmsg(ua, _("No slots in changer to scan.\n"));
510 slot_list = (char *)malloc(max_slots+1);
511 if (!get_user_slot_list(ua, slot_list, max_slots)) {
515 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
518 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
522 /* Display list of Volumes and ask if he really wants to proceed */
523 bsendmsg(ua, _("The following Volumes will be labeled:\n"
525 "==============\n"));
526 for (vl=vol_list; vl; vl=vl->next) {
527 if (!vl->VolName || !slot_list[vl->Slot]) {
530 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
532 if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) ||
533 (ua->pint32_val == 0)) {
537 memset(&pr, 0, sizeof(pr));
538 if (!select_pool_dbr(ua, &pr)) {
541 memset(&omr, 0, sizeof(omr));
543 /* Fire off the label requests */
544 for (vl=vol_list; vl; vl=vl->next) {
545 if (!vl->VolName || !slot_list[vl->Slot]) {
548 memset(&mr, 0, sizeof(mr));
549 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
550 media_record_exists = false;
551 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
552 if (mr.VolBytes != 0) {
553 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
554 vl->Slot, mr.VolumeName);
557 mr.StorageId = store->StorageId;
558 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
559 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
563 media_record_exists = true;
566 mr.StorageId = store->StorageId;
568 * Deal with creating cleaning tape here. Normal tapes created in
569 * send_label_request() below
571 if (is_cleaning_tape(ua, &mr, &pr)) {
572 if (media_record_exists) { /* we update it */
573 mr.VolBytes = 1; /* any bytes to indicate it exists */
574 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
576 mr.StorageId = store->StorageId;
577 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
578 bsendmsg(ua, "%s", db_strerror(ua->db));
580 } else { /* create the media record */
581 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
582 bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
585 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
586 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
588 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
589 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
591 pr.NumVols++; /* this is a bit suspect */
592 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
593 bsendmsg(ua, "%s", db_strerror(ua->db));
596 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
599 continue; /* done, go handle next volume */
601 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
604 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
610 free_vol_list(vol_list);
617 * Check if the Volume name has legal characters
618 * If ua is non-NULL send the message
620 bool is_volume_name_legal(UAContext *ua, const char *name)
624 const char *accept = ":.-_";
626 /* Restrict the characters permitted in the Volume name */
627 for (p=name; *p; p++) {
628 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
632 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
637 if (len >= MAX_NAME_LENGTH) {
639 bsendmsg(ua, _("Volume name too long.\n"));
645 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
653 * NOTE! This routine opens the SD socket but leaves it open
655 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
656 POOL_DBR *pr, int relabel, bool media_record_exists,
660 char dev_name[MAX_NAME_LENGTH];
663 uint64_t VolBytes = 0;
665 if (!(sd=open_sd_bsock(ua))) {
668 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
669 bash_spaces(dev_name);
670 bash_spaces(mr->VolumeName);
671 bash_spaces(mr->MediaType);
672 bash_spaces(pr->Name);
674 bash_spaces(omr->VolumeName);
675 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
676 "MediaType=%s Slot=%d drive=%d",
677 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
678 mr->MediaType, mr->Slot, drive);
679 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
680 omr->VolumeName, mr->VolumeName);
682 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
684 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
686 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
687 mr->VolumeName, mr->Slot);
688 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
689 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
692 while (bnet_recv(sd) >= 0) {
694 bsendmsg(ua, "%s", sd->msg);
695 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
701 unbash_spaces(mr->VolumeName);
702 unbash_spaces(mr->MediaType);
703 unbash_spaces(pr->Name);
704 mr->LabelDate = time(NULL);
705 mr->set_label_date = true;
707 /* We know that a freshly labelled DVD has 1 VolParts */
708 /* This does not apply to auto-labelled DVDs. */
712 if (media_record_exists) { /* we update it */
713 mr->VolBytes = VolBytes;
715 mr->StorageId = ua->jcr->wstore->StorageId;
716 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
717 bsendmsg(ua, "%s", db_strerror(ua->db));
720 } else { /* create the media record */
721 set_pool_dbr_defaults_in_media_dbr(mr, pr);
722 mr->VolBytes = VolBytes;
724 mr->StorageId = ua->jcr->wstore->StorageId;
726 if (db_create_media_record(ua->jcr, ua->db, mr)) {
727 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
728 mr->VolumeName, mr->Slot);
729 /* Update number of volumes in pool */
731 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
732 bsendmsg(ua, "%s", db_strerror(ua->db));
735 bsendmsg(ua, "%s", db_strerror(ua->db));
740 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
745 static BSOCK *open_sd_bsock(UAContext *ua)
747 STORE *store = ua->jcr->wstore;
749 if (!ua->jcr->store_bsock) {
750 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
751 store->name(), store->address, store->SDport);
752 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
753 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
757 return ua->jcr->store_bsock;
760 static void close_sd_bsock(UAContext *ua)
762 if (ua->jcr->store_bsock) {
763 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
764 bnet_close(ua->jcr->store_bsock);
765 ua->jcr->store_bsock = NULL;
769 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
771 STORE *store = ua->jcr->wstore;
773 char dev_name[MAX_NAME_LENGTH];
774 char *VolName = NULL;
777 if (!(sd=open_sd_bsock(ua))) {
778 bsendmsg(ua, _("Could not open SD socket.\n"));
781 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
782 bash_spaces(dev_name);
783 /* Ask for autochanger list of volumes */
784 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
785 Dmsg1(100, "Sent: %s", sd->msg);
787 /* Get Volume name in this Slot */
788 while (bnet_recv(sd) >= 0) {
789 bsendmsg(ua, "%s", sd->msg);
790 Dmsg1(100, "Got: %s", sd->msg);
791 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
792 VolName = (char *)malloc(sd->msglen);
793 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
801 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
806 * We get the slot list from the Storage daemon.
807 * If scan is set, we return all slots found,
808 * otherwise, we return only slots with valid barcodes (Volume names)
810 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
812 STORE *store = ua->jcr->wstore;
813 char dev_name[MAX_NAME_LENGTH];
816 vol_list_t *vol_list = NULL;
819 if (!(sd=open_sd_bsock(ua))) {
823 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
824 bash_spaces(dev_name);
825 /* Ask for autochanger list of volumes */
826 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
828 /* Read and organize list of Volumes */
829 while (bnet_recv(sd) >= 0) {
832 strip_trailing_junk(sd->msg);
834 /* Check for returned SD messages */
835 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
836 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
838 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
842 /* Validate Slot: if scanning, otherwise Slot:Barcode */
843 p = strchr(sd->msg, ':');
845 /* Scanning -- require only valid slot */
846 Slot = atoi(sd->msg);
850 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
855 if (p && strlen(p) > 1) {
857 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
860 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
866 if (!is_volume_name_legal(ua, p)) {
869 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
874 /* Add Slot and VolumeName to list */
875 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
879 p++; /* skip separator */
881 vl->VolName = bstrdup(p);
885 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
890 /* Add new entry to end of list */
891 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
904 static void free_vol_list(vol_list_t *vol_list)
909 for (vl=vol_list; vl; ) {
921 * We get the number of slots in the changer from the SD
923 static int get_num_slots_from_SD(UAContext *ua)
925 STORE *store = ua->jcr->wstore;
926 char dev_name[MAX_NAME_LENGTH];
931 if (!(sd=open_sd_bsock(ua))) {
935 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
936 bash_spaces(dev_name);
937 /* Ask for autochanger number of slots */
938 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
940 while (bnet_recv(sd) >= 0) {
941 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
944 bsendmsg(ua, "%s", sd->msg);
948 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
953 * We get the number of drives in the changer from the SD
955 int get_num_drives_from_SD(UAContext *ua)
957 STORE *store = ua->jcr->wstore;
958 char dev_name[MAX_NAME_LENGTH];
963 if (!(sd=open_sd_bsock(ua))) {
967 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
968 bash_spaces(dev_name);
969 /* Ask for autochanger number of slots */
970 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
972 while (bnet_recv(sd) >= 0) {
973 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
976 bsendmsg(ua, "%s", sd->msg);
980 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
988 * Check if this is a cleaning tape by comparing the Volume name
989 * with the Cleaning Prefix. If they match, this is a cleaning
992 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
994 /* Find Pool resource */
995 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
996 if (!ua->jcr->pool) {
997 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
998 pr->Name, mr->VolumeName);
1001 if (ua->jcr->pool->cleaning_prefix == NULL) {
1004 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1005 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1006 strlen(ua->jcr->pool->cleaning_prefix),
1007 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1008 strlen(ua->jcr->pool->cleaning_prefix)));
1009 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1010 strlen(ua->jcr->pool->cleaning_prefix)) == 0;