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];
633 if (!(sd=open_sd_bsock(ua))) {
636 bstrncpy(dev_name, ua->jcr->wstore->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->wstore->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->wstore->StorageId;
686 if (db_create_media_record(ua->jcr, ua->db, mr)) {
687 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
688 mr->VolumeName, mr->Slot);
689 /* Update number of volumes in pool */
691 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
692 bsendmsg(ua, "%s", db_strerror(ua->db));
695 bsendmsg(ua, "%s", db_strerror(ua->db));
700 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
705 static BSOCK *open_sd_bsock(UAContext *ua)
707 STORE *store = ua->jcr->wstore;
709 if (!ua->jcr->store_bsock) {
710 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
711 store->name(), store->address, store->SDport);
712 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
713 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
717 return ua->jcr->store_bsock;
720 static void close_sd_bsock(UAContext *ua)
722 if (ua->jcr->store_bsock) {
723 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
724 bnet_close(ua->jcr->store_bsock);
725 ua->jcr->store_bsock = NULL;
729 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
731 STORE *store = ua->jcr->wstore;
733 char dev_name[MAX_NAME_LENGTH];
734 char *VolName = NULL;
737 if (!(sd=open_sd_bsock(ua))) {
738 bsendmsg(ua, _("Could not open SD socket.\n"));
741 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
742 bash_spaces(dev_name);
743 /* Ask for autochanger list of volumes */
744 bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
745 Dmsg1(100, "Sent: %s", sd->msg);
747 /* Get Volume name in this Slot */
748 while (bnet_recv(sd) >= 0) {
749 bsendmsg(ua, "%s", sd->msg);
750 Dmsg1(100, "Got: %s", sd->msg);
751 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
752 VolName = (char *)malloc(sd->msglen);
753 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
761 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
766 * We get the slot list from the Storage daemon.
767 * If scan is set, we return all slots found,
768 * otherwise, we return only slots with valid barcodes (Volume names)
770 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
772 STORE *store = ua->jcr->wstore;
773 char dev_name[MAX_NAME_LENGTH];
776 vol_list_t *vol_list = NULL;
779 if (!(sd=open_sd_bsock(ua))) {
783 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
784 bash_spaces(dev_name);
785 /* Ask for autochanger list of volumes */
786 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
788 /* Read and organize list of Volumes */
789 while (bnet_recv(sd) >= 0) {
792 strip_trailing_junk(sd->msg);
794 /* Check for returned SD messages */
795 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
796 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
798 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
802 /* Validate Slot: if scanning, otherwise Slot:Barcode */
803 p = strchr(sd->msg, ':');
805 /* Scanning -- require only valid slot */
806 Slot = atoi(sd->msg);
810 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
815 if (p && strlen(p) > 1) {
817 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
820 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
826 if (!is_volume_name_legal(ua, p)) {
829 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
834 /* Add Slot and VolumeName to list */
835 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
839 p++; /* skip separator */
841 vl->VolName = bstrdup(p);
845 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
850 /* Add new entry to end of list */
851 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
864 static void free_vol_list(vol_list_t *vol_list)
869 for (vl=vol_list; vl; ) {
881 * We get the number of slots in the changer from the SD
883 static int get_num_slots_from_SD(UAContext *ua)
885 STORE *store = ua->jcr->wstore;
886 char dev_name[MAX_NAME_LENGTH];
891 if (!(sd=open_sd_bsock(ua))) {
895 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
896 bash_spaces(dev_name);
897 /* Ask for autochanger number of slots */
898 bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name);
900 while (bnet_recv(sd) >= 0) {
901 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
904 bsendmsg(ua, "%s", sd->msg);
908 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
913 * We get the number of drives in the changer from the SD
915 int get_num_drives_from_SD(UAContext *ua)
917 STORE *store = ua->jcr->wstore;
918 char dev_name[MAX_NAME_LENGTH];
923 if (!(sd=open_sd_bsock(ua))) {
927 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
928 bash_spaces(dev_name);
929 /* Ask for autochanger number of slots */
930 bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name);
932 while (bnet_recv(sd) >= 0) {
933 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
936 bsendmsg(ua, "%s", sd->msg);
940 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
948 * Check if this is a cleaning tape by comparing the Volume name
949 * with the Cleaning Prefix. If they match, this is a cleaning
952 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
954 /* Find Pool resource */
955 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
956 if (!ua->jcr->pool) {
957 bsendmsg(ua, _("Pool \"%s\" resource not found for volume \"%s\"!\n"),
958 pr->Name, mr->VolumeName);
961 if (ua->jcr->pool->cleaning_prefix == NULL) {
964 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
965 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
966 strlen(ua->jcr->pool->cleaning_prefix),
967 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
968 strlen(ua->jcr->pool->cleaning_prefix)));
969 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
970 strlen(ua->jcr->pool->cleaning_prefix)) == 0;