3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
10 Copyright (C) 2003-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
27 /* Slot list definition */
28 typedef struct s_vol_list {
29 struct s_vol_list *next;
35 /* Forward referenced functions */
36 static int do_label(UAContext *ua, const char *cmd, int relabel);
37 static void label_from_barcodes(UAContext *ua, int drive);
38 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
39 POOL_DBR *pr, int relabel, bool media_record_exits, int drive);
40 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
41 static void free_vol_list(vol_list_t *vol_list);
42 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
43 static BSOCK *open_sd_bsock(UAContext *ua);
44 static void close_sd_bsock(UAContext *ua);
45 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive);
46 static int get_num_slots_from_SD(UAContext *ua);
52 * label storage=xxx volume=vvv
54 int label_cmd(UAContext *ua, const char *cmd)
56 return do_label(ua, cmd, 0); /* standard label */
59 int relabel_cmd(UAContext *ua, const char *cmd)
61 return do_label(ua, cmd, 1); /* relabel tape */
64 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
69 /* slots are numbered 1 to num_slots */
70 for (int i=0; i <= num_slots; i++) {
73 i = find_arg_with_value(ua, "slots");
75 /* scan slot list in ua->argv[i] */
79 strip_trailing_junk(ua->argv[i]);
80 for (p=ua->argv[i]; p && *p; p=e) {
87 h = strchr(p, '-'); /* range? */
89 msg = _("Negative numbers not permitted\n");
94 if (!is_an_integer(h)) {
95 msg = _("Range end is not integer.\n");
99 if (!is_an_integer(p)) {
100 msg = _("Range start is not an integer.\n");
106 msg = _("Range end not bigger than start.\n");
111 if (!is_an_integer(p)) {
112 msg = _("Input value is not an integer.\n");
117 if (beg <= 0 || end <= 0) {
118 msg = _("Values must be be greater than zero.\n");
121 if (end > num_slots) {
122 msg = _("Slot too large.\n");
125 for (i=beg; i<=end; i++) {
126 slot_list[i] = 1; /* Turn on specified range */
130 /* Turn everything on */
131 for (i=1; i <= num_slots; i++) {
135 Dmsg0(100, "Slots turned on:\n");
136 for (i=1; i <= num_slots; i++) {
138 Dmsg1(100, "%d\n", i);
148 * Update Slots corresponding to Volumes in autochanger
150 void update_slots(UAContext *ua)
153 vol_list_t *vl, *vol_list = NULL;
167 store = get_storage_resource(ua, true/*arg is storage*/);
171 set_wstorage(ua->jcr, store);
172 drive = get_storage_drive(ua, store);
174 scan = find_arg(ua, NT_("scan")) >= 0;
175 if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
176 Enabled = get_enabled(ua, ua->argv[i]);
182 have_enabled = false;
185 max_slots = get_num_slots_from_SD(ua);
186 Dmsg1(100, "max_slots=%d\n", max_slots);
187 if (max_slots <= 0) {
188 bsendmsg(ua, _("No slots in changer to scan.\n"));
191 slot_list = (char *)malloc(max_slots+1);
192 if (!get_user_slot_list(ua, slot_list, max_slots)) {
197 vol_list = get_vol_list_from_SD(ua, scan);
200 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
204 /* First zap out any InChanger with StorageId=0 */
205 db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
207 /* Walk through the list updating the media records */
208 for (vl=vol_list; vl; vl=vl->next) {
209 if (vl->Slot > max_slots) {
210 bsendmsg(ua, _("Slot %d greater than max %d ignored.\n"),
211 vl->Slot, max_slots);
214 /* Check if user wants us to look at this slot */
215 if (!slot_list[vl->Slot]) {
216 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
219 /* If scanning, we read the label rather than the barcode */
225 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
226 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
228 slot_list[vl->Slot] = 0; /* clear Slot */
229 memset(&mr, 0, sizeof(mr));
232 mr.StorageId = store->StorageId;
233 /* Set InChanger to zero for this Slot */
235 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
238 Dmsg1(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
239 bsendmsg(ua, _("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
242 memset(&mr, 0, sizeof(mr));
243 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
245 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
246 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
249 mr.StorageId = store->StorageId;
251 mr.Enabled = Enabled;
253 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
254 bsendmsg(ua, "%s", db_strerror(ua->db));
257 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
258 mr.VolumeName, mr.Slot);
261 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
267 bsendmsg(ua, _("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
268 mr.VolumeName, vl->Slot);
272 memset(&mr, 0, sizeof(mr));
274 mr.StorageId = store->StorageId;
276 for (int i=1; i <= max_slots; i++) {
279 /* Set InChanger to zero for this Slot */
280 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
287 free_vol_list(vol_list);
296 * Common routine for both label and relabel
298 static int do_label(UAContext *ua, const char *cmd, int relabel)
302 char dev_name[MAX_NAME_LENGTH];
305 bool print_reminder = true;
306 bool label_barcodes = false;
310 bool media_record_exists = false;
311 static const char *barcode_keyword[] = {
317 memset(&pr, 0, sizeof(pr));
322 /* Look for one of the barcode keywords */
323 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
324 /* Now find the keyword in the list */
325 if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
326 *ua->argk[j] = 0; /* zap barcode keyword */
328 label_barcodes = true;
331 store = get_storage_resource(ua, true/*use default*/);
335 set_wstorage(ua->jcr, store);
336 drive = get_storage_drive(ua, store);
338 if (label_barcodes) {
339 label_from_barcodes(ua, drive);
343 /* If relabel get name of Volume to relabel */
345 /* Check for oldvolume=name */
346 i = find_arg_with_value(ua, "oldvolume");
348 memset(&omr, 0, sizeof(omr));
349 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
350 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
353 bsendmsg(ua, "%s", db_strerror(ua->db));
355 /* No keyword or Vol not found, ask user to select */
356 if (!select_media_dbr(ua, &omr)) {
360 /* Require Volume to be Purged or Recycled */
362 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
363 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
364 omr.VolumeName, omr.VolStatus);
369 /* Check for volume=NewVolume */
370 i = find_arg_with_value(ua, "volume");
372 pm_strcpy(ua->cmd, ua->argv[i]);
376 /* Get a new Volume name */
378 media_record_exists = false;
379 if (!get_cmd(ua, _("Enter new Volume name: "))) {
383 if (!is_volume_name_legal(ua, ua->cmd)) {
387 memset(&mr, 0, sizeof(mr));
388 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
389 /* If VolBytes are zero the Volume is not labeled */
390 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
391 if (mr.VolBytes != 0) {
392 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
396 media_record_exists = true;
401 /* If autochanger, request slot */
402 i = find_arg_with_value(ua, "slot");
404 mr.Slot = atoi(ua->argv[i]);
405 mr.InChanger = 1; /* assumed if we are labeling it */
406 } else if (store->autochanger) {
407 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
410 mr.Slot = ua->pint32_val;
411 mr.InChanger = 1; /* assumed if we are labeling it */
413 mr.StorageId = store->StorageId;
415 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
417 /* Must select Pool if not already done */
418 if (pr.PoolId == 0) {
419 memset(&pr, 0, sizeof(pr));
420 if (!select_pool_dbr(ua, &pr)) {
425 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
428 sd = ua->jcr->store_bsock;
430 /* Delete the old media record */
431 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
432 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
433 omr.VolumeName, db_strerror(ua->db));
435 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
437 /* Update the number of Volumes in the pool */
439 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
440 bsendmsg(ua, "%s", db_strerror(ua->db));
445 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
446 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
447 bash_spaces(dev_name);
448 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
449 unbash_spaces(dev_name);
450 while (bnet_recv(sd) >= 0) {
451 bsendmsg(ua, "%s", sd->msg);
453 * 3001 OK mount. Device=xxx or
454 * 3001 Mounted Volume vvvv
455 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
456 * 3906 is cannot mount non-tape
457 * So for those, no need to print a reminder
459 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
460 strncmp(sd->msg, "3002 ", 5) == 0 ||
461 strncmp(sd->msg, "3906 ", 5) == 0) {
462 print_reminder = false;
467 if (print_reminder) {
468 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
476 * Request SD to send us the slot:barcodes, then wiffle
477 * through them all labeling them.
479 static void label_from_barcodes(UAContext *ua, int drive)
481 STORE *store = ua->jcr->wstore;
484 vol_list_t *vl, *vol_list = NULL;
485 bool media_record_exists;
490 max_slots = get_num_slots_from_SD(ua);
491 if (max_slots <= 0) {
492 bsendmsg(ua, _("No slots in changer to scan.\n"));
495 slot_list = (char *)malloc(max_slots+1);
496 if (!get_user_slot_list(ua, slot_list, max_slots)) {
500 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
503 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
507 /* Display list of Volumes and ask if he really wants to proceed */
508 bsendmsg(ua, _("The following Volumes will be labeled:\n"
510 "==============\n"));
511 for (vl=vol_list; vl; vl=vl->next) {
512 if (!vl->VolName || !slot_list[vl->Slot]) {
515 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
517 if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) ||
518 (ua->pint32_val == 0)) {
522 memset(&pr, 0, sizeof(pr));
523 if (!select_pool_dbr(ua, &pr)) {
526 memset(&omr, 0, sizeof(omr));
528 /* Fire off the label requests */
529 for (vl=vol_list; vl; vl=vl->next) {
530 if (!vl->VolName || !slot_list[vl->Slot]) {
533 memset(&mr, 0, sizeof(mr));
534 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
535 media_record_exists = false;
536 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
537 if (mr.VolBytes != 0) {
538 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
539 vl->Slot, mr.VolumeName);
542 mr.StorageId = store->StorageId;
543 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
544 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
548 media_record_exists = true;
551 mr.StorageId = store->StorageId;
553 * Deal with creating cleaning tape here. Normal tapes created in
554 * send_label_request() below
556 if (is_cleaning_tape(ua, &mr, &pr)) {
557 if (media_record_exists) { /* we update it */
558 mr.VolBytes = 1; /* any bytes to indicate it exists */
559 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
561 mr.StorageId = store->StorageId;
562 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
563 bsendmsg(ua, "%s", db_strerror(ua->db));
565 } else { /* create the media record */
566 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
567 bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
570 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
571 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
573 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
574 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
576 pr.NumVols++; /* this is a bit suspect */
577 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
578 bsendmsg(ua, "%s", db_strerror(ua->db));
581 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
584 continue; /* done, go handle next volume */
586 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
589 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
595 free_vol_list(vol_list);
602 * Check if the Volume name has legal characters
603 * If ua is non-NULL send the message
605 bool is_volume_name_legal(UAContext *ua, const char *name)
609 const char *accept = ":.-_";
611 /* Restrict the characters permitted in the Volume name */
612 for (p=name; *p; p++) {
613 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
617 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
622 if (len >= MAX_NAME_LENGTH) {
624 bsendmsg(ua, _("Volume name too long.\n"));
630 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
638 * NOTE! This routine opens the SD socket but leaves it open
640 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
641 POOL_DBR *pr, int relabel, bool media_record_exists,
645 char dev_name[MAX_NAME_LENGTH];
648 uint64_t VolBytes = 0;
650 if (!(sd=open_sd_bsock(ua))) {
653 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
654 bash_spaces(dev_name);
655 bash_spaces(mr->VolumeName);
656 bash_spaces(mr->MediaType);
657 bash_spaces(pr->Name);
659 bash_spaces(omr->VolumeName);
660 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
661 "MediaType=%s Slot=%d drive=%d",
662 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
663 mr->MediaType, mr->Slot, drive);
664 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
665 omr->VolumeName, mr->VolumeName);
667 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
669 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
671 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
672 mr->VolumeName, mr->Slot);
673 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
674 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
677 while (bnet_recv(sd) >= 0) {
679 bsendmsg(ua, "%s", sd->msg);
680 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
686 unbash_spaces(mr->VolumeName);
687 unbash_spaces(mr->MediaType);
688 unbash_spaces(pr->Name);
689 mr->LabelDate = time(NULL);
690 mr->set_label_date = true;
692 /* We know that a freshly labelled DVD has 1 VolParts */
693 /* This does not apply to auto-labelled DVDs. */
697 if (media_record_exists) { /* we update it */
698 mr->VolBytes = VolBytes;
700 mr->StorageId = ua->jcr->wstore->StorageId;
701 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
702 bsendmsg(ua, "%s", db_strerror(ua->db));
705 } else { /* create the media record */
706 set_pool_dbr_defaults_in_media_dbr(mr, pr);
707 mr->VolBytes = VolBytes;
709 mr->StorageId = ua->jcr->wstore->StorageId;
711 if (db_create_media_record(ua->jcr, ua->db, mr)) {
712 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
713 mr->VolumeName, mr->Slot);
714 /* Update number of volumes in pool */
716 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
717 bsendmsg(ua, "%s", db_strerror(ua->db));
720 bsendmsg(ua, "%s", db_strerror(ua->db));
725 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
730 static BSOCK *open_sd_bsock(UAContext *ua)
732 STORE *store = ua->jcr->wstore;
734 if (!ua->jcr->store_bsock) {
735 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
736 store->name(), store->address, store->SDport);
737 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
738 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
742 return ua->jcr->store_bsock;
745 static void close_sd_bsock(UAContext *ua)
747 if (ua->jcr->store_bsock) {
748 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
749 bnet_close(ua->jcr->store_bsock);
750 ua->jcr->store_bsock = NULL;
754 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
756 STORE *store = ua->jcr->wstore;
758 char dev_name[MAX_NAME_LENGTH];
759 char *VolName = NULL;
762 if (!(sd=open_sd_bsock(ua))) {
763 bsendmsg(ua, _("Could not open SD socket.\n"));
766 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
767 bash_spaces(dev_name);
768 /* Ask for autochanger list of volumes */
769 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
770 Dmsg1(100, "Sent: %s", sd->msg);
772 /* Get Volume name in this Slot */
773 while (bnet_recv(sd) >= 0) {
774 bsendmsg(ua, "%s", sd->msg);
775 Dmsg1(100, "Got: %s", sd->msg);
776 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
777 VolName = (char *)malloc(sd->msglen);
778 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
786 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
791 * We get the slot list from the Storage daemon.
792 * If scan is set, we return all slots found,
793 * otherwise, we return only slots with valid barcodes (Volume names)
795 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
797 STORE *store = ua->jcr->wstore;
798 char dev_name[MAX_NAME_LENGTH];
801 vol_list_t *vol_list = NULL;
804 if (!(sd=open_sd_bsock(ua))) {
808 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
809 bash_spaces(dev_name);
810 /* Ask for autochanger list of volumes */
811 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
813 /* Read and organize list of Volumes */
814 while (bnet_recv(sd) >= 0) {
817 strip_trailing_junk(sd->msg);
819 /* Check for returned SD messages */
820 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
821 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
823 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
827 /* Validate Slot: if scanning, otherwise Slot:Barcode */
828 p = strchr(sd->msg, ':');
830 /* Scanning -- require only valid slot */
831 Slot = atoi(sd->msg);
835 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
840 if (p && strlen(p) > 1) {
842 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
845 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
851 if (!is_volume_name_legal(ua, p)) {
854 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
859 /* Add Slot and VolumeName to list */
860 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
864 p++; /* skip separator */
866 vl->VolName = bstrdup(p);
870 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
875 /* Add new entry to end of list */
876 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
889 static void free_vol_list(vol_list_t *vol_list)
894 for (vl=vol_list; vl; ) {
906 * We get the number of slots in the changer from the SD
908 static int get_num_slots_from_SD(UAContext *ua)
910 STORE *store = ua->jcr->wstore;
911 char dev_name[MAX_NAME_LENGTH];
916 if (!(sd=open_sd_bsock(ua))) {
920 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
921 bash_spaces(dev_name);
922 /* Ask for autochanger number of slots */
923 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
925 while (bnet_recv(sd) >= 0) {
926 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
929 bsendmsg(ua, "%s", sd->msg);
933 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
938 * We get the number of drives in the changer from the SD
940 int get_num_drives_from_SD(UAContext *ua)
942 STORE *store = ua->jcr->wstore;
943 char dev_name[MAX_NAME_LENGTH];
948 if (!(sd=open_sd_bsock(ua))) {
952 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
953 bash_spaces(dev_name);
954 /* Ask for autochanger number of slots */
955 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
957 while (bnet_recv(sd) >= 0) {
958 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
961 bsendmsg(ua, "%s", sd->msg);
965 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
973 * Check if this is a cleaning tape by comparing the Volume name
974 * with the Cleaning Prefix. If they match, this is a cleaning
977 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
979 /* Find Pool resource */
980 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
981 if (!ua->jcr->pool) {
982 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
983 pr->Name, mr->VolumeName);
986 if (ua->jcr->pool->cleaning_prefix == NULL) {
989 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
990 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
991 strlen(ua->jcr->pool->cleaning_prefix),
992 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
993 strlen(ua->jcr->pool->cleaning_prefix)));
994 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
995 strlen(ua->jcr->pool->cleaning_prefix)) == 0;