3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
10 Copyright (C) 2003-2005 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 int 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, N_("scan")) >= 0;
173 max_slots = get_num_slots_from_SD(ua);
174 if (max_slots <= 0) {
175 bsendmsg(ua, _("No slots in changer to scan.\n"));
178 slot_list = (char *)malloc(max_slots+1);
179 if (!get_user_slot_list(ua, slot_list, max_slots)) {
184 vol_list = get_vol_list_from_SD(ua, scan);
187 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
191 /* Walk through the list updating the media records */
192 for (vl=vol_list; vl; vl=vl->next) {
193 if (vl->Slot > max_slots) {
194 bsendmsg(ua, _("Slot %d greater than max %d ignored.\n"),
195 vl->Slot, max_slots);
198 /* Check if user wants us to look at this slot */
199 if (!slot_list[vl->Slot]) {
200 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
203 /* If scanning, we read the label rather than the barcode */
209 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
210 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
212 slot_list[vl->Slot] = 0; /* clear Slot */
213 memset(&mr, 0, sizeof(mr));
216 mr.StorageId = store->StorageId;
217 /* Set InChanger to zero for this Slot */
219 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
222 Dmsg1(000, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
223 bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), vl->Slot);
226 memset(&mr, 0, sizeof(mr));
227 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
229 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
230 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
233 mr.StorageId = store->StorageId;
234 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
235 bsendmsg(ua, "%s", db_strerror(ua->db));
238 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
239 mr.VolumeName, mr.Slot);
242 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
248 bsendmsg(ua, _("Volume \"%s\" not found in catalog. Slot=%d set InChanger to zero.\n"),
249 mr.VolumeName, vl->Slot);
253 memset(&mr, 0, sizeof(mr));
255 mr.StorageId = store->StorageId;
257 for (int i=1; i <= max_slots; i++) {
260 /* Set InChanger to zero for this Slot */
261 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
268 free_vol_list(vol_list);
277 * Common routine for both label and relabel
279 static int do_label(UAContext *ua, const char *cmd, int relabel)
283 char dev_name[MAX_NAME_LENGTH];
286 bool print_reminder = true;
287 bool label_barcodes = false;
291 bool media_record_exists = false;
292 static const char *barcode_keyword[] = {
298 memset(&pr, 0, sizeof(pr));
303 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
304 *ua->argk[i] = 0; /* zap barcode keyword */
305 label_barcodes = true;
308 store = get_storage_resource(ua, true/*use default*/);
312 set_storage(ua->jcr, store);
313 drive = get_storage_drive(ua, store);
315 if (label_barcodes) {
316 label_from_barcodes(ua, drive);
320 /* If relabel get name of Volume to relabel */
322 /* Check for oldvolume=name */
323 i = find_arg_with_value(ua, "oldvolume");
325 memset(&omr, 0, sizeof(omr));
326 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
327 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
330 bsendmsg(ua, "%s", db_strerror(ua->db));
332 /* No keyword or Vol not found, ask user to select */
333 if (!select_media_dbr(ua, &omr)) {
337 /* Require Volume to be Purged or Recycled */
339 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
340 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
341 omr.VolumeName, omr.VolStatus);
346 /* Check for volume=NewVolume */
347 i = find_arg_with_value(ua, "volume");
349 pm_strcpy(ua->cmd, ua->argv[i]);
353 /* Get a new Volume name */
355 media_record_exists = false;
356 if (!get_cmd(ua, _("Enter new Volume name: "))) {
360 if (!is_volume_name_legal(ua, ua->cmd)) {
364 memset(&mr, 0, sizeof(mr));
365 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
366 /* If VolBytes are zero the Volume is not labeled */
367 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
368 if (mr.VolBytes != 0) {
369 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
373 media_record_exists = true;
378 /* If autochanger, request slot */
379 i = find_arg_with_value(ua, "slot");
381 mr.Slot = atoi(ua->argv[i]);
382 mr.InChanger = 1; /* assumed if we are labeling it */
383 } else if (store->autochanger) {
384 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
387 mr.Slot = ua->pint32_val;
388 mr.InChanger = 1; /* assumed if we are labeling it */
390 mr.StorageId = store->StorageId;
392 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
394 /* Must select Pool if not already done */
395 if (pr.PoolId == 0) {
396 memset(&pr, 0, sizeof(pr));
397 if (!select_pool_dbr(ua, &pr)) {
402 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
405 sd = ua->jcr->store_bsock;
407 /* Delete the old media record */
408 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
409 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
410 omr.VolumeName, db_strerror(ua->db));
412 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
414 /* Update the number of Volumes in the pool */
416 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
417 bsendmsg(ua, "%s", db_strerror(ua->db));
422 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
423 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
424 bash_spaces(dev_name);
425 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
426 unbash_spaces(dev_name);
427 while (bnet_recv(sd) >= 0) {
428 bsendmsg(ua, "%s", sd->msg);
430 * 3001 OK mount. Device=xxx or
431 * 3001 Mounted Volume vvvv
432 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
433 * 3906 is cannot mount non-tape
434 * So for those, no need to print a reminder
436 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
437 strncmp(sd->msg, "3002 ", 5) == 0 ||
438 strncmp(sd->msg, "3906 ", 5) == 0) {
439 print_reminder = false;
444 if (print_reminder) {
445 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
453 * Request SD to send us the slot:barcodes, then wiffle
454 * through them all labeling them.
456 static void label_from_barcodes(UAContext *ua, int drive)
458 STORE *store = ua->jcr->store;
461 vol_list_t *vl, *vol_list = NULL;
462 bool media_record_exists;
467 max_slots = get_num_slots_from_SD(ua);
468 if (max_slots <= 0) {
469 bsendmsg(ua, _("No slots in changer to scan.\n"));
472 slot_list = (char *)malloc(max_slots+1);
473 if (!get_user_slot_list(ua, slot_list, max_slots)) {
477 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
480 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
484 /* Display list of Volumes and ask if he really wants to proceed */
485 bsendmsg(ua, _("The following Volumes will be labeled:\n"
487 "==============\n"));
488 for (vl=vol_list; vl; vl=vl->next) {
489 if (!vl->VolName || !slot_list[vl->Slot]) {
492 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
494 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
495 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
499 memset(&pr, 0, sizeof(pr));
500 if (!select_pool_dbr(ua, &pr)) {
503 memset(&omr, 0, sizeof(omr));
505 /* Fire off the label requests */
506 for (vl=vol_list; vl; vl=vl->next) {
507 if (!vl->VolName || !slot_list[vl->Slot]) {
510 memset(&mr, 0, sizeof(mr));
511 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
512 media_record_exists = false;
513 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
514 if (mr.VolBytes != 0) {
515 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
516 vl->Slot, mr.VolumeName);
519 mr.StorageId = store->StorageId;
520 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
521 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
525 media_record_exists = true;
528 mr.StorageId = store->StorageId;
530 * Deal with creating cleaning tape here. Normal tapes created in
531 * send_label_request() below
533 if (is_cleaning_tape(ua, &mr, &pr)) {
534 if (media_record_exists) { /* we update it */
536 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
538 mr.StorageId = store->StorageId;
539 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
540 bsendmsg(ua, "%s", db_strerror(ua->db));
542 } else { /* create the media record */
543 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
544 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
546 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
547 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
549 pr.NumVols++; /* this is a bit suspect */
550 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
551 bsendmsg(ua, "%s", db_strerror(ua->db));
554 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
557 continue; /* done, go handle next volume */
559 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
562 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
568 free_vol_list(vol_list);
575 * Check if the Volume name has legal characters
576 * If ua is non-NULL send the message
578 bool is_volume_name_legal(UAContext *ua, const char *name)
582 const char *accept = ":.-_";
584 /* Restrict the characters permitted in the Volume name */
585 for (p=name; *p; p++) {
586 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
590 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
595 if (len >= MAX_NAME_LENGTH) {
597 bsendmsg(ua, _("Volume name too long.\n"));
603 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
611 * NOTE! This routine opens the SD socket but leaves it open
613 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
614 POOL_DBR *pr, int relabel, bool media_record_exists,
618 char dev_name[MAX_NAME_LENGTH];
621 if (!(sd=open_sd_bsock(ua))) {
624 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
625 bash_spaces(dev_name);
626 bash_spaces(mr->VolumeName);
627 bash_spaces(mr->MediaType);
628 bash_spaces(pr->Name);
630 bash_spaces(omr->VolumeName);
631 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
632 "MediaType=%s Slot=%d drive=%d",
633 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
634 mr->MediaType, mr->Slot, drive);
635 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
636 omr->VolumeName, mr->VolumeName);
638 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
640 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
642 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
643 mr->VolumeName, mr->Slot);
644 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
645 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
648 while (bnet_recv(sd) >= 0) {
649 bsendmsg(ua, "%s", sd->msg);
650 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
654 unbash_spaces(mr->VolumeName);
655 unbash_spaces(mr->MediaType);
656 unbash_spaces(pr->Name);
657 mr->LabelDate = time(NULL);
658 mr->set_label_date = true;
660 if (media_record_exists) { /* we update it */
663 mr->StorageId = ua->jcr->store->StorageId;
664 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
665 bsendmsg(ua, "%s", db_strerror(ua->db));
668 } else { /* create the media record */
669 set_pool_dbr_defaults_in_media_dbr(mr, pr);
670 mr->VolBytes = 1; /* flag indicating Volume labeled */
672 mr->StorageId = ua->jcr->store->StorageId;
673 if (db_create_media_record(ua->jcr, ua->db, mr)) {
674 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
675 mr->VolumeName, mr->Slot);
676 /* Update number of volumes in pool */
678 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
679 bsendmsg(ua, "%s", db_strerror(ua->db));
682 bsendmsg(ua, "%s", db_strerror(ua->db));
687 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
692 static BSOCK *open_sd_bsock(UAContext *ua)
694 STORE *store = ua->jcr->store;
696 if (!ua->jcr->store_bsock) {
697 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
698 store->hdr.name, store->address, store->SDport);
699 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
700 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
704 return ua->jcr->store_bsock;
707 static void close_sd_bsock(UAContext *ua)
709 if (ua->jcr->store_bsock) {
710 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
711 bnet_close(ua->jcr->store_bsock);
712 ua->jcr->store_bsock = NULL;
716 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
718 STORE *store = ua->jcr->store;
720 char dev_name[MAX_NAME_LENGTH];
721 char *VolName = NULL;
724 if (!(sd=open_sd_bsock(ua))) {
725 bsendmsg(ua, _("Could not open SD socket.\n"));
728 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
729 bash_spaces(dev_name);
730 /* Ask for autochanger list of volumes */
731 bnet_fsend(sd, _("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
732 Dmsg1(100, "Sent: %s", sd->msg);
734 /* Get Volume name in this Slot */
735 while (bnet_recv(sd) >= 0) {
736 bsendmsg(ua, "%s", sd->msg);
737 Dmsg1(100, "Got: %s", sd->msg);
738 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
739 VolName = (char *)malloc(sd->msglen);
740 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
748 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
753 * We get the slot list from the Storage daemon.
754 * If scan is set, we return all slots found,
755 * otherwise, we return only slots with valid barcodes (Volume names)
757 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
759 STORE *store = ua->jcr->store;
760 char dev_name[MAX_NAME_LENGTH];
763 vol_list_t *vol_list = NULL;
766 if (!(sd=open_sd_bsock(ua))) {
770 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
771 bash_spaces(dev_name);
772 /* Ask for autochanger list of volumes */
773 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
775 /* Read and organize list of Volumes */
776 while (bnet_recv(sd) >= 0) {
779 strip_trailing_junk(sd->msg);
781 /* Check for returned SD messages */
782 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
783 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
785 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
789 /* Validate Slot: if scanning, otherwise Slot:Barcode */
790 p = strchr(sd->msg, ':');
792 /* Scanning -- require only valid slot */
793 Slot = atoi(sd->msg);
797 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
802 if (p && strlen(p) > 1) {
804 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
807 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
813 if (!is_volume_name_legal(ua, p)) {
816 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
821 /* Add Slot and VolumeName to list */
822 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
826 p++; /* skip separator */
828 vl->VolName = bstrdup(p);
832 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
837 /* Add new entry to end of list */
838 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
851 static void free_vol_list(vol_list_t *vol_list)
856 for (vl=vol_list; vl; ) {
868 * We get the number of slots in the changer from the SD
870 static int get_num_slots_from_SD(UAContext *ua)
872 STORE *store = ua->jcr->store;
873 char dev_name[MAX_NAME_LENGTH];
878 if (!(sd=open_sd_bsock(ua))) {
882 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
883 bash_spaces(dev_name);
884 /* Ask for autochanger number of slots */
885 bnet_fsend(sd, _("autochanger slots %s\n"), dev_name);
887 while (bnet_recv(sd) >= 0) {
888 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
891 bsendmsg(ua, "%s", sd->msg);
895 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
900 * We get the number of drives in the changer from the SD
902 int get_num_drives_from_SD(UAContext *ua)
904 STORE *store = ua->jcr->store;
905 char dev_name[MAX_NAME_LENGTH];
910 if (!(sd=open_sd_bsock(ua))) {
914 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
915 bash_spaces(dev_name);
916 /* Ask for autochanger number of slots */
917 bnet_fsend(sd, _("autochanger drives %s\n"), dev_name);
919 while (bnet_recv(sd) >= 0) {
920 if (sscanf(sd->msg, "drives=%d\n", &drives) == 1) {
923 bsendmsg(ua, "%s", sd->msg);
927 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
935 * Check if this is a cleaning tape by comparing the Volume name
936 * with the Cleaning Prefix. If they match, this is a cleaning
939 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
941 /* Find Pool resource */
942 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
943 if (!ua->jcr->pool) {
944 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
947 if (ua->jcr->pool->cleaning_prefix == NULL) {
950 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
951 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
952 strlen(ua->jcr->pool->cleaning_prefix),
953 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
954 strlen(ua->jcr->pool->cleaning_prefix)));
955 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
956 strlen(ua->jcr->pool->cleaning_prefix)) == 0;