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 /* 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_storage(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->store;
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];
633 if (!(sd=open_sd_bsock(ua))) {
636 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
637 bash_spaces(dev_name);
638 bash_spaces(mr->VolumeName);
639 bash_spaces(mr->MediaType);
640 bash_spaces(pr->Name);
642 bash_spaces(omr->VolumeName);
643 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
644 "MediaType=%s Slot=%d drive=%d",
645 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
646 mr->MediaType, mr->Slot, drive);
647 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
648 omr->VolumeName, mr->VolumeName);
650 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
652 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
654 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
655 mr->VolumeName, mr->Slot);
656 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
657 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
660 while (bnet_recv(sd) >= 0) {
661 bsendmsg(ua, "%s", sd->msg);
662 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
666 unbash_spaces(mr->VolumeName);
667 unbash_spaces(mr->MediaType);
668 unbash_spaces(pr->Name);
669 mr->LabelDate = time(NULL);
670 mr->set_label_date = true;
672 if (media_record_exists) { /* we update it */
675 mr->StorageId = ua->jcr->store->StorageId;
676 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
677 bsendmsg(ua, "%s", db_strerror(ua->db));
680 } else { /* create the media record */
681 set_pool_dbr_defaults_in_media_dbr(mr, pr);
682 mr->VolBytes = 1; /* flag indicating Volume labeled */
684 mr->StorageId = ua->jcr->store->StorageId;
685 if (db_create_media_record(ua->jcr, ua->db, mr)) {
686 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
687 mr->VolumeName, mr->Slot);
688 /* Update number of volumes in pool */
690 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
691 bsendmsg(ua, "%s", db_strerror(ua->db));
694 bsendmsg(ua, "%s", db_strerror(ua->db));
699 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
704 static BSOCK *open_sd_bsock(UAContext *ua)
706 STORE *store = ua->jcr->store;
708 if (!ua->jcr->store_bsock) {
709 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
710 store->hdr.name, store->address, store->SDport);
711 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
712 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
716 return ua->jcr->store_bsock;
719 static void close_sd_bsock(UAContext *ua)
721 if (ua->jcr->store_bsock) {
722 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
723 bnet_close(ua->jcr->store_bsock);
724 ua->jcr->store_bsock = NULL;
728 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
730 STORE *store = ua->jcr->store;
732 char dev_name[MAX_NAME_LENGTH];
733 char *VolName = NULL;
736 if (!(sd=open_sd_bsock(ua))) {
737 bsendmsg(ua, _("Could not open SD socket.\n"));
740 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
741 bash_spaces(dev_name);
742 /* Ask for autochanger list of volumes */
743 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
744 Dmsg1(100, "Sent: %s", sd->msg);
746 /* Get Volume name in this Slot */
747 while (bnet_recv(sd) >= 0) {
748 bsendmsg(ua, "%s", sd->msg);
749 Dmsg1(100, "Got: %s", sd->msg);
750 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
751 VolName = (char *)malloc(sd->msglen);
752 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
760 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
765 * We get the slot list from the Storage daemon.
766 * If scan is set, we return all slots found,
767 * otherwise, we return only slots with valid barcodes (Volume names)
769 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
771 STORE *store = ua->jcr->store;
772 char dev_name[MAX_NAME_LENGTH];
775 vol_list_t *vol_list = NULL;
778 if (!(sd=open_sd_bsock(ua))) {
782 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
783 bash_spaces(dev_name);
784 /* Ask for autochanger list of volumes */
785 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
787 /* Read and organize list of Volumes */
788 while (bnet_recv(sd) >= 0) {
791 strip_trailing_junk(sd->msg);
793 /* Check for returned SD messages */
794 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
795 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
797 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
801 /* Validate Slot: if scanning, otherwise Slot:Barcode */
802 p = strchr(sd->msg, ':');
804 /* Scanning -- require only valid slot */
805 Slot = atoi(sd->msg);
809 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
814 if (p && strlen(p) > 1) {
816 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
819 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
825 if (!is_volume_name_legal(ua, p)) {
828 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
833 /* Add Slot and VolumeName to list */
834 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
838 p++; /* skip separator */
840 vl->VolName = bstrdup(p);
844 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
849 /* Add new entry to end of list */
850 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
863 static void free_vol_list(vol_list_t *vol_list)
868 for (vl=vol_list; vl; ) {
880 * We get the number of slots in the changer from the SD
882 static int get_num_slots_from_SD(UAContext *ua)
884 STORE *store = ua->jcr->store;
885 char dev_name[MAX_NAME_LENGTH];
890 if (!(sd=open_sd_bsock(ua))) {
894 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
895 bash_spaces(dev_name);
896 /* Ask for autochanger number of slots */
897 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
899 while (bnet_recv(sd) >= 0) {
900 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
903 bsendmsg(ua, "%s", sd->msg);
907 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
912 * We get the number of drives in the changer from the SD
914 int get_num_drives_from_SD(UAContext *ua)
916 STORE *store = ua->jcr->store;
917 char dev_name[MAX_NAME_LENGTH];
922 if (!(sd=open_sd_bsock(ua))) {
926 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
927 bash_spaces(dev_name);
928 /* Ask for autochanger number of slots */
929 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
931 while (bnet_recv(sd) >= 0) {
932 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
935 bsendmsg(ua, "%s", sd->msg);
939 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
947 * Check if this is a cleaning tape by comparing the Volume name
948 * with the Cleaning Prefix. If they match, this is a cleaning
951 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
953 /* Find Pool resource */
954 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
955 if (!ua->jcr->pool) {
956 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
957 pr->Name, mr->VolumeName);
960 if (ua->jcr->pool->cleaning_prefix == NULL) {
963 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
964 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
965 strlen(ua->jcr->pool->cleaning_prefix),
966 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
967 strlen(ua->jcr->pool->cleaning_prefix)));
968 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
969 strlen(ua->jcr->pool->cleaning_prefix)) == 0;