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 */
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];
634 if (!(sd=open_sd_bsock(ua))) {
637 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
638 bash_spaces(dev_name);
639 bash_spaces(mr->VolumeName);
640 bash_spaces(mr->MediaType);
641 bash_spaces(pr->Name);
643 bash_spaces(omr->VolumeName);
644 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
645 "MediaType=%s Slot=%d drive=%d",
646 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
647 mr->MediaType, mr->Slot, drive);
648 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
649 omr->VolumeName, mr->VolumeName);
651 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
653 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
655 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
656 mr->VolumeName, mr->Slot);
657 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
658 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
661 while (bnet_recv(sd) >= 0) {
662 bsendmsg(ua, "%s", sd->msg);
663 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
666 if (strncmp(sd->msg, "3000 OK label. DVD=1 ", 21) == 0) {
670 unbash_spaces(mr->VolumeName);
671 unbash_spaces(mr->MediaType);
672 unbash_spaces(pr->Name);
673 mr->LabelDate = time(NULL);
674 mr->set_label_date = true;
676 /* We know that a freshly labelled DVD has 1 VolParts */
677 /* This does not apply to auto-labelled DVDs. */
681 if (media_record_exists) { /* we update it */
684 mr->StorageId = ua->jcr->wstore->StorageId;
685 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
686 bsendmsg(ua, "%s", db_strerror(ua->db));
689 } else { /* create the media record */
690 set_pool_dbr_defaults_in_media_dbr(mr, pr);
691 mr->VolBytes = 1; /* flag indicating Volume labeled */
693 mr->StorageId = ua->jcr->wstore->StorageId;
695 if (db_create_media_record(ua->jcr, ua->db, mr)) {
696 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
697 mr->VolumeName, mr->Slot);
698 /* Update number of volumes in pool */
700 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
701 bsendmsg(ua, "%s", db_strerror(ua->db));
704 bsendmsg(ua, "%s", db_strerror(ua->db));
709 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
714 static BSOCK *open_sd_bsock(UAContext *ua)
716 STORE *store = ua->jcr->wstore;
718 if (!ua->jcr->store_bsock) {
719 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
720 store->name(), store->address, store->SDport);
721 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
722 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
726 return ua->jcr->store_bsock;
729 static void close_sd_bsock(UAContext *ua)
731 if (ua->jcr->store_bsock) {
732 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
733 bnet_close(ua->jcr->store_bsock);
734 ua->jcr->store_bsock = NULL;
738 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
740 STORE *store = ua->jcr->wstore;
742 char dev_name[MAX_NAME_LENGTH];
743 char *VolName = NULL;
746 if (!(sd=open_sd_bsock(ua))) {
747 bsendmsg(ua, _("Could not open SD socket.\n"));
750 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
751 bash_spaces(dev_name);
752 /* Ask for autochanger list of volumes */
753 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
754 Dmsg1(100, "Sent: %s", sd->msg);
756 /* Get Volume name in this Slot */
757 while (bnet_recv(sd) >= 0) {
758 bsendmsg(ua, "%s", sd->msg);
759 Dmsg1(100, "Got: %s", sd->msg);
760 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
761 VolName = (char *)malloc(sd->msglen);
762 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
770 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
775 * We get the slot list from the Storage daemon.
776 * If scan is set, we return all slots found,
777 * otherwise, we return only slots with valid barcodes (Volume names)
779 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
781 STORE *store = ua->jcr->wstore;
782 char dev_name[MAX_NAME_LENGTH];
785 vol_list_t *vol_list = NULL;
788 if (!(sd=open_sd_bsock(ua))) {
792 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
793 bash_spaces(dev_name);
794 /* Ask for autochanger list of volumes */
795 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
797 /* Read and organize list of Volumes */
798 while (bnet_recv(sd) >= 0) {
801 strip_trailing_junk(sd->msg);
803 /* Check for returned SD messages */
804 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
805 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
807 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
811 /* Validate Slot: if scanning, otherwise Slot:Barcode */
812 p = strchr(sd->msg, ':');
814 /* Scanning -- require only valid slot */
815 Slot = atoi(sd->msg);
819 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
824 if (p && strlen(p) > 1) {
826 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
829 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
835 if (!is_volume_name_legal(ua, p)) {
838 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
843 /* Add Slot and VolumeName to list */
844 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
848 p++; /* skip separator */
850 vl->VolName = bstrdup(p);
854 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
859 /* Add new entry to end of list */
860 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
873 static void free_vol_list(vol_list_t *vol_list)
878 for (vl=vol_list; vl; ) {
890 * We get the number of slots in the changer from the SD
892 static int get_num_slots_from_SD(UAContext *ua)
894 STORE *store = ua->jcr->wstore;
895 char dev_name[MAX_NAME_LENGTH];
900 if (!(sd=open_sd_bsock(ua))) {
904 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
905 bash_spaces(dev_name);
906 /* Ask for autochanger number of slots */
907 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
909 while (bnet_recv(sd) >= 0) {
910 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
913 bsendmsg(ua, "%s", sd->msg);
917 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
922 * We get the number of drives in the changer from the SD
924 int get_num_drives_from_SD(UAContext *ua)
926 STORE *store = ua->jcr->wstore;
927 char dev_name[MAX_NAME_LENGTH];
932 if (!(sd=open_sd_bsock(ua))) {
936 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
937 bash_spaces(dev_name);
938 /* Ask for autochanger number of slots */
939 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
941 while (bnet_recv(sd) >= 0) {
942 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
945 bsendmsg(ua, "%s", sd->msg);
949 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
957 * Check if this is a cleaning tape by comparing the Volume name
958 * with the Cleaning Prefix. If they match, this is a cleaning
961 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
963 /* Find Pool resource */
964 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
965 if (!ua->jcr->pool) {
966 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
967 pr->Name, mr->VolumeName);
970 if (ua->jcr->pool->cleaning_prefix == NULL) {
973 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
974 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
975 strlen(ua->jcr->pool->cleaning_prefix),
976 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
977 strlen(ua->jcr->pool->cleaning_prefix)));
978 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
979 strlen(ua->jcr->pool->cleaning_prefix)) == 0;