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;
164 store = get_storage_resource(ua, true/*arg is storage*/);
168 set_storage(ua->jcr, store);
169 drive = get_storage_drive(ua, store);
171 scan = find_arg(ua, NT_("scan")) >= 0;
173 max_slots = get_num_slots_from_SD(ua);
174 Dmsg1(100, "max_slots=%d\n", max_slots);
175 if (max_slots <= 0) {
176 bsendmsg(ua, _("No slots in changer to scan.\n"));
179 slot_list = (char *)malloc(max_slots+1);
180 if (!get_user_slot_list(ua, slot_list, max_slots)) {
185 vol_list = get_vol_list_from_SD(ua, scan);
188 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
192 /* First zap out any InChanger with StorageId=0 */
193 db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
195 /* Walk through the list updating the media records */
196 for (vl=vol_list; vl; vl=vl->next) {
197 if (vl->Slot > max_slots) {
198 bsendmsg(ua, _("Slot %d greater than max %d ignored.\n"),
199 vl->Slot, max_slots);
202 /* Check if user wants us to look at this slot */
203 if (!slot_list[vl->Slot]) {
204 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
207 /* If scanning, we read the label rather than the barcode */
213 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
214 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
216 slot_list[vl->Slot] = 0; /* clear Slot */
217 memset(&mr, 0, sizeof(mr));
220 mr.StorageId = store->StorageId;
221 /* Set InChanger to zero for this Slot */
223 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
226 Dmsg1(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
227 bsendmsg(ua, _("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
230 memset(&mr, 0, sizeof(mr));
231 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
233 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
234 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
237 mr.StorageId = store->StorageId;
238 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
239 bsendmsg(ua, "%s", db_strerror(ua->db));
242 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
243 mr.VolumeName, mr.Slot);
246 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
252 bsendmsg(ua, _("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
253 mr.VolumeName, vl->Slot);
257 memset(&mr, 0, sizeof(mr));
259 mr.StorageId = store->StorageId;
261 for (int i=1; i <= max_slots; i++) {
264 /* Set InChanger to zero for this Slot */
265 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
272 free_vol_list(vol_list);
281 * Common routine for both label and relabel
283 static int do_label(UAContext *ua, const char *cmd, int relabel)
287 char dev_name[MAX_NAME_LENGTH];
290 bool print_reminder = true;
291 bool label_barcodes = false;
295 bool media_record_exists = false;
296 static const char *barcode_keyword[] = {
302 memset(&pr, 0, sizeof(pr));
307 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
308 *ua->argk[i] = 0; /* zap barcode keyword */
309 label_barcodes = true;
312 store = get_storage_resource(ua, true/*use default*/);
316 set_storage(ua->jcr, store);
317 drive = get_storage_drive(ua, store);
319 if (label_barcodes) {
320 label_from_barcodes(ua, drive);
324 /* If relabel get name of Volume to relabel */
326 /* Check for oldvolume=name */
327 i = find_arg_with_value(ua, "oldvolume");
329 memset(&omr, 0, sizeof(omr));
330 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
331 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
334 bsendmsg(ua, "%s", db_strerror(ua->db));
336 /* No keyword or Vol not found, ask user to select */
337 if (!select_media_dbr(ua, &omr)) {
341 /* Require Volume to be Purged or Recycled */
343 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
344 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
345 omr.VolumeName, omr.VolStatus);
350 /* Check for volume=NewVolume */
351 i = find_arg_with_value(ua, "volume");
353 pm_strcpy(ua->cmd, ua->argv[i]);
357 /* Get a new Volume name */
359 media_record_exists = false;
360 if (!get_cmd(ua, _("Enter new Volume name: "))) {
364 if (!is_volume_name_legal(ua, ua->cmd)) {
368 memset(&mr, 0, sizeof(mr));
369 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
370 /* If VolBytes are zero the Volume is not labeled */
371 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
372 if (mr.VolBytes != 0) {
373 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
377 media_record_exists = true;
382 /* If autochanger, request slot */
383 i = find_arg_with_value(ua, "slot");
385 mr.Slot = atoi(ua->argv[i]);
386 mr.InChanger = 1; /* assumed if we are labeling it */
387 } else if (store->autochanger) {
388 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
391 mr.Slot = ua->pint32_val;
392 mr.InChanger = 1; /* assumed if we are labeling it */
394 mr.StorageId = store->StorageId;
396 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
398 /* Must select Pool if not already done */
399 if (pr.PoolId == 0) {
400 memset(&pr, 0, sizeof(pr));
401 if (!select_pool_dbr(ua, &pr)) {
406 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
409 sd = ua->jcr->store_bsock;
411 /* Delete the old media record */
412 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
413 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
414 omr.VolumeName, db_strerror(ua->db));
416 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
418 /* Update the number of Volumes in the pool */
420 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
421 bsendmsg(ua, "%s", db_strerror(ua->db));
426 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
427 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
428 bash_spaces(dev_name);
429 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
430 unbash_spaces(dev_name);
431 while (bnet_recv(sd) >= 0) {
432 bsendmsg(ua, "%s", sd->msg);
434 * 3001 OK mount. Device=xxx or
435 * 3001 Mounted Volume vvvv
436 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
437 * 3906 is cannot mount non-tape
438 * So for those, no need to print a reminder
440 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
441 strncmp(sd->msg, "3002 ", 5) == 0 ||
442 strncmp(sd->msg, "3906 ", 5) == 0) {
443 print_reminder = false;
448 if (print_reminder) {
449 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
457 * Request SD to send us the slot:barcodes, then wiffle
458 * through them all labeling them.
460 static void label_from_barcodes(UAContext *ua, int drive)
462 STORE *store = ua->jcr->store;
465 vol_list_t *vl, *vol_list = NULL;
466 bool media_record_exists;
471 max_slots = get_num_slots_from_SD(ua);
472 if (max_slots <= 0) {
473 bsendmsg(ua, _("No slots in changer to scan.\n"));
476 slot_list = (char *)malloc(max_slots+1);
477 if (!get_user_slot_list(ua, slot_list, max_slots)) {
481 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
484 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
488 /* Display list of Volumes and ask if he really wants to proceed */
489 bsendmsg(ua, _("The following Volumes will be labeled:\n"
491 "==============\n"));
492 for (vl=vol_list; vl; vl=vl->next) {
493 if (!vl->VolName || !slot_list[vl->Slot]) {
496 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
498 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
499 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
503 memset(&pr, 0, sizeof(pr));
504 if (!select_pool_dbr(ua, &pr)) {
507 memset(&omr, 0, sizeof(omr));
509 /* Fire off the label requests */
510 for (vl=vol_list; vl; vl=vl->next) {
511 if (!vl->VolName || !slot_list[vl->Slot]) {
514 memset(&mr, 0, sizeof(mr));
515 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
516 media_record_exists = false;
517 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
518 if (mr.VolBytes != 0) {
519 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
520 vl->Slot, mr.VolumeName);
523 mr.StorageId = store->StorageId;
524 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
525 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
529 media_record_exists = true;
532 mr.StorageId = store->StorageId;
534 * Deal with creating cleaning tape here. Normal tapes created in
535 * send_label_request() below
537 if (is_cleaning_tape(ua, &mr, &pr)) {
538 if (media_record_exists) { /* we update it */
540 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
542 mr.StorageId = store->StorageId;
543 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
544 bsendmsg(ua, "%s", db_strerror(ua->db));
546 } else { /* create the media record */
547 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
548 bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
551 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
552 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
554 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
555 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
557 pr.NumVols++; /* this is a bit suspect */
558 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
559 bsendmsg(ua, "%s", db_strerror(ua->db));
562 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
565 continue; /* done, go handle next volume */
567 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
570 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
576 free_vol_list(vol_list);
583 * Check if the Volume name has legal characters
584 * If ua is non-NULL send the message
586 bool is_volume_name_legal(UAContext *ua, const char *name)
590 const char *accept = ":.-_";
592 /* Restrict the characters permitted in the Volume name */
593 for (p=name; *p; p++) {
594 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
598 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
603 if (len >= MAX_NAME_LENGTH) {
605 bsendmsg(ua, _("Volume name too long.\n"));
611 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
619 * NOTE! This routine opens the SD socket but leaves it open
621 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
622 POOL_DBR *pr, int relabel, bool media_record_exists,
626 char dev_name[MAX_NAME_LENGTH];
629 if (!(sd=open_sd_bsock(ua))) {
632 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
633 bash_spaces(dev_name);
634 bash_spaces(mr->VolumeName);
635 bash_spaces(mr->MediaType);
636 bash_spaces(pr->Name);
638 bash_spaces(omr->VolumeName);
639 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
640 "MediaType=%s Slot=%d drive=%d",
641 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
642 mr->MediaType, mr->Slot, drive);
643 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
644 omr->VolumeName, mr->VolumeName);
646 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
648 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
650 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
651 mr->VolumeName, mr->Slot);
652 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
653 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
656 while (bnet_recv(sd) >= 0) {
657 bsendmsg(ua, "%s", sd->msg);
658 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
662 unbash_spaces(mr->VolumeName);
663 unbash_spaces(mr->MediaType);
664 unbash_spaces(pr->Name);
665 mr->LabelDate = time(NULL);
666 mr->set_label_date = true;
668 if (media_record_exists) { /* we update it */
671 mr->StorageId = ua->jcr->store->StorageId;
672 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
673 bsendmsg(ua, "%s", db_strerror(ua->db));
676 } else { /* create the media record */
677 set_pool_dbr_defaults_in_media_dbr(mr, pr);
678 mr->VolBytes = 1; /* flag indicating Volume labeled */
680 mr->StorageId = ua->jcr->store->StorageId;
681 if (db_create_media_record(ua->jcr, ua->db, mr)) {
682 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
683 mr->VolumeName, mr->Slot);
684 /* Update number of volumes in pool */
686 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
687 bsendmsg(ua, "%s", db_strerror(ua->db));
690 bsendmsg(ua, "%s", db_strerror(ua->db));
695 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
700 static BSOCK *open_sd_bsock(UAContext *ua)
702 STORE *store = ua->jcr->store;
704 if (!ua->jcr->store_bsock) {
705 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
706 store->hdr.name, store->address, store->SDport);
707 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
708 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
712 return ua->jcr->store_bsock;
715 static void close_sd_bsock(UAContext *ua)
717 if (ua->jcr->store_bsock) {
718 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
719 bnet_close(ua->jcr->store_bsock);
720 ua->jcr->store_bsock = NULL;
724 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
726 STORE *store = ua->jcr->store;
728 char dev_name[MAX_NAME_LENGTH];
729 char *VolName = NULL;
732 if (!(sd=open_sd_bsock(ua))) {
733 bsendmsg(ua, _("Could not open SD socket.\n"));
736 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
737 bash_spaces(dev_name);
738 /* Ask for autochanger list of volumes */
739 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
740 Dmsg1(100, "Sent: %s", sd->msg);
742 /* Get Volume name in this Slot */
743 while (bnet_recv(sd) >= 0) {
744 bsendmsg(ua, "%s", sd->msg);
745 Dmsg1(100, "Got: %s", sd->msg);
746 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
747 VolName = (char *)malloc(sd->msglen);
748 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
756 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
761 * We get the slot list from the Storage daemon.
762 * If scan is set, we return all slots found,
763 * otherwise, we return only slots with valid barcodes (Volume names)
765 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
767 STORE *store = ua->jcr->store;
768 char dev_name[MAX_NAME_LENGTH];
771 vol_list_t *vol_list = NULL;
774 if (!(sd=open_sd_bsock(ua))) {
778 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
779 bash_spaces(dev_name);
780 /* Ask for autochanger list of volumes */
781 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
783 /* Read and organize list of Volumes */
784 while (bnet_recv(sd) >= 0) {
787 strip_trailing_junk(sd->msg);
789 /* Check for returned SD messages */
790 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
791 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
793 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
797 /* Validate Slot: if scanning, otherwise Slot:Barcode */
798 p = strchr(sd->msg, ':');
800 /* Scanning -- require only valid slot */
801 Slot = atoi(sd->msg);
805 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
810 if (p && strlen(p) > 1) {
812 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
815 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
821 if (!is_volume_name_legal(ua, p)) {
824 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
829 /* Add Slot and VolumeName to list */
830 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
834 p++; /* skip separator */
836 vl->VolName = bstrdup(p);
840 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
845 /* Add new entry to end of list */
846 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
859 static void free_vol_list(vol_list_t *vol_list)
864 for (vl=vol_list; vl; ) {
876 * We get the number of slots in the changer from the SD
878 static int get_num_slots_from_SD(UAContext *ua)
880 STORE *store = ua->jcr->store;
881 char dev_name[MAX_NAME_LENGTH];
886 if (!(sd=open_sd_bsock(ua))) {
890 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
891 bash_spaces(dev_name);
892 /* Ask for autochanger number of slots */
893 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
895 while (bnet_recv(sd) >= 0) {
896 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
899 bsendmsg(ua, "%s", sd->msg);
903 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
908 * We get the number of drives in the changer from the SD
910 int get_num_drives_from_SD(UAContext *ua)
912 STORE *store = ua->jcr->store;
913 char dev_name[MAX_NAME_LENGTH];
918 if (!(sd=open_sd_bsock(ua))) {
922 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
923 bash_spaces(dev_name);
924 /* Ask for autochanger number of slots */
925 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
927 while (bnet_recv(sd) >= 0) {
928 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
931 bsendmsg(ua, "%s", sd->msg);
935 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
943 * Check if this is a cleaning tape by comparing the Volume name
944 * with the Cleaning Prefix. If they match, this is a cleaning
947 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
949 /* Find Pool resource */
950 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
951 if (!ua->jcr->pool) {
952 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
955 if (ua->jcr->pool->cleaning_prefix == NULL) {
958 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
959 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
960 strlen(ua->jcr->pool->cleaning_prefix),
961 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
962 strlen(ua->jcr->pool->cleaning_prefix)));
963 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
964 strlen(ua->jcr->pool->cleaning_prefix)) == 0;