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_wstorage(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 /* Look for one of the barcode keywords */
308 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
309 /* Now find the keyword in the list */
310 if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
311 *ua->argk[j] = 0; /* zap barcode keyword */
313 label_barcodes = true;
316 store = get_storage_resource(ua, true/*use default*/);
320 set_wstorage(ua->jcr, store);
321 drive = get_storage_drive(ua, store);
323 if (label_barcodes) {
324 label_from_barcodes(ua, drive);
328 /* If relabel get name of Volume to relabel */
330 /* Check for oldvolume=name */
331 i = find_arg_with_value(ua, "oldvolume");
333 memset(&omr, 0, sizeof(omr));
334 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
335 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
338 bsendmsg(ua, "%s", db_strerror(ua->db));
340 /* No keyword or Vol not found, ask user to select */
341 if (!select_media_dbr(ua, &omr)) {
345 /* Require Volume to be Purged or Recycled */
347 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
348 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
349 omr.VolumeName, omr.VolStatus);
354 /* Check for volume=NewVolume */
355 i = find_arg_with_value(ua, "volume");
357 pm_strcpy(ua->cmd, ua->argv[i]);
361 /* Get a new Volume name */
363 media_record_exists = false;
364 if (!get_cmd(ua, _("Enter new Volume name: "))) {
368 if (!is_volume_name_legal(ua, ua->cmd)) {
372 memset(&mr, 0, sizeof(mr));
373 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
374 /* If VolBytes are zero the Volume is not labeled */
375 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
376 if (mr.VolBytes != 0) {
377 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
381 media_record_exists = true;
386 /* If autochanger, request slot */
387 i = find_arg_with_value(ua, "slot");
389 mr.Slot = atoi(ua->argv[i]);
390 mr.InChanger = 1; /* assumed if we are labeling it */
391 } else if (store->autochanger) {
392 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
395 mr.Slot = ua->pint32_val;
396 mr.InChanger = 1; /* assumed if we are labeling it */
398 mr.StorageId = store->StorageId;
400 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
402 /* Must select Pool if not already done */
403 if (pr.PoolId == 0) {
404 memset(&pr, 0, sizeof(pr));
405 if (!select_pool_dbr(ua, &pr)) {
410 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
413 sd = ua->jcr->store_bsock;
415 /* Delete the old media record */
416 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
417 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
418 omr.VolumeName, db_strerror(ua->db));
420 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
422 /* Update the number of Volumes in the pool */
424 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
425 bsendmsg(ua, "%s", db_strerror(ua->db));
430 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
431 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
432 bash_spaces(dev_name);
433 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
434 unbash_spaces(dev_name);
435 while (bnet_recv(sd) >= 0) {
436 bsendmsg(ua, "%s", sd->msg);
438 * 3001 OK mount. Device=xxx or
439 * 3001 Mounted Volume vvvv
440 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
441 * 3906 is cannot mount non-tape
442 * So for those, no need to print a reminder
444 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
445 strncmp(sd->msg, "3002 ", 5) == 0 ||
446 strncmp(sd->msg, "3906 ", 5) == 0) {
447 print_reminder = false;
452 if (print_reminder) {
453 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
461 * Request SD to send us the slot:barcodes, then wiffle
462 * through them all labeling them.
464 static void label_from_barcodes(UAContext *ua, int drive)
466 STORE *store = ua->jcr->wstore;
469 vol_list_t *vl, *vol_list = NULL;
470 bool media_record_exists;
475 max_slots = get_num_slots_from_SD(ua);
476 if (max_slots <= 0) {
477 bsendmsg(ua, _("No slots in changer to scan.\n"));
480 slot_list = (char *)malloc(max_slots+1);
481 if (!get_user_slot_list(ua, slot_list, max_slots)) {
485 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
488 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
492 /* Display list of Volumes and ask if he really wants to proceed */
493 bsendmsg(ua, _("The following Volumes will be labeled:\n"
495 "==============\n"));
496 for (vl=vol_list; vl; vl=vl->next) {
497 if (!vl->VolName || !slot_list[vl->Slot]) {
500 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
502 if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) ||
503 (ua->pint32_val == 0)) {
507 memset(&pr, 0, sizeof(pr));
508 if (!select_pool_dbr(ua, &pr)) {
511 memset(&omr, 0, sizeof(omr));
513 /* Fire off the label requests */
514 for (vl=vol_list; vl; vl=vl->next) {
515 if (!vl->VolName || !slot_list[vl->Slot]) {
518 memset(&mr, 0, sizeof(mr));
519 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
520 media_record_exists = false;
521 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
522 if (mr.VolBytes != 0) {
523 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
524 vl->Slot, mr.VolumeName);
527 mr.StorageId = store->StorageId;
528 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
529 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
533 media_record_exists = true;
536 mr.StorageId = store->StorageId;
538 * Deal with creating cleaning tape here. Normal tapes created in
539 * send_label_request() below
541 if (is_cleaning_tape(ua, &mr, &pr)) {
542 if (media_record_exists) { /* we update it */
543 mr.VolBytes = 1; /* any bytes to indicate it exists */
544 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
546 mr.StorageId = store->StorageId;
547 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
548 bsendmsg(ua, "%s", db_strerror(ua->db));
550 } else { /* create the media record */
551 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
552 bsendmsg(ua, _("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
555 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
556 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
558 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
559 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
561 pr.NumVols++; /* this is a bit suspect */
562 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
563 bsendmsg(ua, "%s", db_strerror(ua->db));
566 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
569 continue; /* done, go handle next volume */
571 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
574 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
580 free_vol_list(vol_list);
587 * Check if the Volume name has legal characters
588 * If ua is non-NULL send the message
590 bool is_volume_name_legal(UAContext *ua, const char *name)
594 const char *accept = ":.-_";
596 /* Restrict the characters permitted in the Volume name */
597 for (p=name; *p; p++) {
598 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
602 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
607 if (len >= MAX_NAME_LENGTH) {
609 bsendmsg(ua, _("Volume name too long.\n"));
615 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
623 * NOTE! This routine opens the SD socket but leaves it open
625 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
626 POOL_DBR *pr, int relabel, bool media_record_exists,
630 char dev_name[MAX_NAME_LENGTH];
633 uint64_t VolBytes = 0;
635 if (!(sd=open_sd_bsock(ua))) {
638 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
639 bash_spaces(dev_name);
640 bash_spaces(mr->VolumeName);
641 bash_spaces(mr->MediaType);
642 bash_spaces(pr->Name);
644 bash_spaces(omr->VolumeName);
645 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
646 "MediaType=%s Slot=%d drive=%d",
647 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
648 mr->MediaType, mr->Slot, drive);
649 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
650 omr->VolumeName, mr->VolumeName);
652 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
654 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
656 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
657 mr->VolumeName, mr->Slot);
658 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
659 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
662 while (bnet_recv(sd) >= 0) {
664 bsendmsg(ua, "%s", sd->msg);
665 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
671 unbash_spaces(mr->VolumeName);
672 unbash_spaces(mr->MediaType);
673 unbash_spaces(pr->Name);
674 mr->LabelDate = time(NULL);
675 mr->set_label_date = true;
677 /* We know that a freshly labelled DVD has 1 VolParts */
678 /* This does not apply to auto-labelled DVDs. */
682 if (media_record_exists) { /* we update it */
683 mr->VolBytes = VolBytes;
685 mr->StorageId = ua->jcr->wstore->StorageId;
686 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
687 bsendmsg(ua, "%s", db_strerror(ua->db));
690 } else { /* create the media record */
691 set_pool_dbr_defaults_in_media_dbr(mr, pr);
692 mr->VolBytes = VolBytes;
694 mr->StorageId = ua->jcr->wstore->StorageId;
696 if (db_create_media_record(ua->jcr, ua->db, mr)) {
697 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
698 mr->VolumeName, mr->Slot);
699 /* Update number of volumes in pool */
701 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
702 bsendmsg(ua, "%s", db_strerror(ua->db));
705 bsendmsg(ua, "%s", db_strerror(ua->db));
710 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
715 static BSOCK *open_sd_bsock(UAContext *ua)
717 STORE *store = ua->jcr->wstore;
719 if (!ua->jcr->store_bsock) {
720 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
721 store->name(), store->address, store->SDport);
722 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
723 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
727 return ua->jcr->store_bsock;
730 static void close_sd_bsock(UAContext *ua)
732 if (ua->jcr->store_bsock) {
733 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
734 bnet_close(ua->jcr->store_bsock);
735 ua->jcr->store_bsock = NULL;
739 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
741 STORE *store = ua->jcr->wstore;
743 char dev_name[MAX_NAME_LENGTH];
744 char *VolName = NULL;
747 if (!(sd=open_sd_bsock(ua))) {
748 bsendmsg(ua, _("Could not open SD socket.\n"));
751 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
752 bash_spaces(dev_name);
753 /* Ask for autochanger list of volumes */
754 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
755 Dmsg1(100, "Sent: %s", sd->msg);
757 /* Get Volume name in this Slot */
758 while (bnet_recv(sd) >= 0) {
759 bsendmsg(ua, "%s", sd->msg);
760 Dmsg1(100, "Got: %s", sd->msg);
761 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
762 VolName = (char *)malloc(sd->msglen);
763 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
771 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
776 * We get the slot list from the Storage daemon.
777 * If scan is set, we return all slots found,
778 * otherwise, we return only slots with valid barcodes (Volume names)
780 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
782 STORE *store = ua->jcr->wstore;
783 char dev_name[MAX_NAME_LENGTH];
786 vol_list_t *vol_list = NULL;
789 if (!(sd=open_sd_bsock(ua))) {
793 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
794 bash_spaces(dev_name);
795 /* Ask for autochanger list of volumes */
796 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
798 /* Read and organize list of Volumes */
799 while (bnet_recv(sd) >= 0) {
802 strip_trailing_junk(sd->msg);
804 /* Check for returned SD messages */
805 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
806 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
808 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
812 /* Validate Slot: if scanning, otherwise Slot:Barcode */
813 p = strchr(sd->msg, ':');
815 /* Scanning -- require only valid slot */
816 Slot = atoi(sd->msg);
820 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
825 if (p && strlen(p) > 1) {
827 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
830 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
836 if (!is_volume_name_legal(ua, p)) {
839 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
844 /* Add Slot and VolumeName to list */
845 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
849 p++; /* skip separator */
851 vl->VolName = bstrdup(p);
855 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
860 /* Add new entry to end of list */
861 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
874 static void free_vol_list(vol_list_t *vol_list)
879 for (vl=vol_list; vl; ) {
891 * We get the number of slots in the changer from the SD
893 static int get_num_slots_from_SD(UAContext *ua)
895 STORE *store = ua->jcr->wstore;
896 char dev_name[MAX_NAME_LENGTH];
901 if (!(sd=open_sd_bsock(ua))) {
905 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
906 bash_spaces(dev_name);
907 /* Ask for autochanger number of slots */
908 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
910 while (bnet_recv(sd) >= 0) {
911 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
914 bsendmsg(ua, "%s", sd->msg);
918 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
923 * We get the number of drives in the changer from the SD
925 int get_num_drives_from_SD(UAContext *ua)
927 STORE *store = ua->jcr->wstore;
928 char dev_name[MAX_NAME_LENGTH];
933 if (!(sd=open_sd_bsock(ua))) {
937 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
938 bash_spaces(dev_name);
939 /* Ask for autochanger number of slots */
940 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
942 while (bnet_recv(sd) >= 0) {
943 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
946 bsendmsg(ua, "%s", sd->msg);
950 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
958 * Check if this is a cleaning tape by comparing the Volume name
959 * with the Cleaning Prefix. If they match, this is a cleaning
962 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
964 /* Find Pool resource */
965 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
966 if (!ua->jcr->pool) {
967 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
968 pr->Name, mr->VolumeName);
971 if (ua->jcr->pool->cleaning_prefix == NULL) {
974 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
975 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
976 strlen(ua->jcr->pool->cleaning_prefix),
977 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
978 strlen(ua->jcr->pool->cleaning_prefix)));
979 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
980 strlen(ua->jcr->pool->cleaning_prefix)) == 0;