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 for (int i=0; i <= num_slots; i++) {
72 i = find_arg_with_value(ua, "slots");
74 /* scan slot list in ua->argv[i] */
78 strip_trailing_junk(ua->argv[i]);
79 for (p=ua->argv[i]; p && *p; p=e) {
86 h = strchr(p, '-'); /* range? */
88 msg = _("Negative numbers not permitted\n");
93 if (!is_an_integer(h)) {
94 msg = _("Range end is not integer.\n");
98 if (!is_an_integer(p)) {
99 msg = _("Range start is not an integer.\n");
105 msg = _("Range end not bigger than start.\n");
110 if (!is_an_integer(p)) {
111 msg = _("Input value is not an integer.\n");
116 if (beg <= 0 || end <= 0) {
117 msg = _("Values must be be greater than zero.\n");
120 if (end >= num_slots) {
121 msg = _("Slot too large.\n");
124 for (i=beg; i<=end; i++) {
125 slot_list[i] = 1; /* Turn on specified range */
129 /* Turn everything on */
130 for (i=0; i <= num_slots; i++) {
134 Dmsg0(100, "Slots turned on:\n");
135 for (i=1; i <= num_slots; i++) {
137 Dmsg1(100, "%d\n", i);
147 * Update Slots corresponding to Volumes in autochanger
149 int update_slots(UAContext *ua)
152 vol_list_t *vl, *vol_list = NULL;
163 store = get_storage_resource(ua, 1);
167 drive = get_storage_drive(ua, store);
168 set_storage(ua->jcr, store);
170 scan = find_arg(ua, N_("scan")) >= 0;
172 max_slots = get_num_slots_from_SD(ua);
173 if (max_slots <= 0) {
174 bsendmsg(ua, _("No slots in changer to scan.\n"));
177 slot_list = (char *)malloc(max_slots+1);
178 if (!get_user_slot_list(ua, slot_list, max_slots)) {
183 vol_list = get_vol_list_from_SD(ua, scan);
186 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
190 /* Walk through the list updating the media records */
191 for (vl=vol_list; vl; vl=vl->next) {
192 if (vl->Slot > max_slots) {
193 bsendmsg(ua, _("Slot %d larger than max %d ignored.\n"),
194 vl->Slot, max_slots);
197 /* Check if user wants us to look at this slot */
198 if (!slot_list[vl->Slot]) {
199 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
202 /* If scanning, we read the label rather than the barcode */
208 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
209 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
211 slot_list[vl->Slot] = 0; /* clear Slot */
213 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
214 memset(&mr, 0, sizeof(mr));
217 mr.StorageId = store->StorageId;
218 /* Set InChanger to zero for this Slot */
220 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
222 bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), vl->Slot);
225 memset(&mr, 0, sizeof(mr));
226 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
228 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
229 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
232 mr.StorageId = store->StorageId;
233 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
234 bsendmsg(ua, "%s", db_strerror(ua->db));
237 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
238 mr.VolumeName, mr.Slot);
241 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
247 bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
252 memset(&mr, 0, sizeof(mr));
254 mr.StorageId = store->StorageId;
256 for (int i=1; i <= max_slots; i++) {
259 /* Set InChanger to zero for this Slot */
260 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
267 free_vol_list(vol_list);
276 * Common routine for both label and relabel
278 static int do_label(UAContext *ua, const char *cmd, int relabel)
282 char dev_name[MAX_NAME_LENGTH];
285 bool print_reminder = true;
289 bool media_record_exists = false;
290 static const char *barcode_keyword[] = {
296 memset(&pr, 0, sizeof(pr));
300 store = get_storage_resource(ua, true/*use default*/);
304 drive = get_storage_drive(ua, store);
305 set_storage(ua->jcr, store);
307 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
308 label_from_barcodes(ua, drive);
312 /* If relabel get name of Volume to relabel */
314 /* Check for oldvolume=name */
315 i = find_arg_with_value(ua, "oldvolume");
317 memset(&omr, 0, sizeof(omr));
318 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
319 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
322 bsendmsg(ua, "%s", db_strerror(ua->db));
324 /* No keyword or Vol not found, ask user to select */
325 if (!select_media_dbr(ua, &omr)) {
329 /* Require Volume to be Purged or Recycled */
331 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
332 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
333 omr.VolumeName, omr.VolStatus);
338 /* Check for volume=NewVolume */
339 i = find_arg_with_value(ua, "volume");
341 pm_strcpy(ua->cmd, ua->argv[i]);
345 /* Get a new Volume name */
347 media_record_exists = false;
348 if (!get_cmd(ua, _("Enter new Volume name: "))) {
352 if (!is_volume_name_legal(ua, ua->cmd)) {
356 memset(&mr, 0, sizeof(mr));
357 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
358 /* If VolBytes are zero the Volume is not labeled */
359 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
360 if (mr.VolBytes != 0) {
361 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
365 media_record_exists = true;
370 /* If autochanger, request slot */
371 i = find_arg_with_value(ua, "slot");
373 mr.Slot = atoi(ua->argv[i]);
374 mr.InChanger = 1; /* assumed if we are labeling it */
375 } else if (store->autochanger) {
376 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
379 mr.Slot = ua->pint32_val;
380 mr.InChanger = 1; /* assumed if we are labeling it */
382 mr.StorageId = store->StorageId;
384 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
386 /* Must select Pool if not already done */
387 if (pr.PoolId == 0) {
388 memset(&pr, 0, sizeof(pr));
389 if (!select_pool_dbr(ua, &pr)) {
394 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
397 sd = ua->jcr->store_bsock;
399 /* Delete the old media record */
400 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
401 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
402 omr.VolumeName, db_strerror(ua->db));
404 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
406 /* Update the number of Volumes in the pool */
408 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
409 bsendmsg(ua, "%s", db_strerror(ua->db));
414 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
415 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
416 bash_spaces(dev_name);
417 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
418 unbash_spaces(dev_name);
419 while (bnet_recv(sd) >= 0) {
420 bsendmsg(ua, "%s", sd->msg);
422 * 3001 OK mount. Device=xxx or
423 * 3001 Mounted Volume vvvv
424 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
425 * 3906 is cannot mount non-tape
426 * So for those, no need to print a reminder
428 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
429 strncmp(sd->msg, "3002 ", 5) == 0 ||
430 strncmp(sd->msg, "3906 ", 5) == 0) {
431 print_reminder = false;
436 if (print_reminder) {
437 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
445 * Request SD to send us the slot:barcodes, then wiffle
446 * through them all labeling them.
448 static void label_from_barcodes(UAContext *ua, int drive)
450 STORE *store = ua->jcr->store;
453 vol_list_t *vl, *vol_list = NULL;
454 bool media_record_exists;
459 max_slots = get_num_slots_from_SD(ua);
460 if (max_slots <= 0) {
461 bsendmsg(ua, _("No slots in changer to scan.\n"));
464 slot_list = (char *)malloc(max_slots+1);
465 if (!get_user_slot_list(ua, slot_list, max_slots)) {
469 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
472 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
476 /* Display list of Volumes and ask if he really wants to proceed */
477 bsendmsg(ua, _("The following Volumes will be labeled:\n"
479 "==============\n"));
480 for (vl=vol_list; vl; vl=vl->next) {
481 if (!vl->VolName || !slot_list[vl->Slot]) {
484 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
486 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
487 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
491 memset(&pr, 0, sizeof(pr));
492 if (!select_pool_dbr(ua, &pr)) {
495 memset(&omr, 0, sizeof(omr));
497 /* Fire off the label requests */
498 for (vl=vol_list; vl; vl=vl->next) {
499 if (!vl->VolName || !slot_list[vl->Slot]) {
502 memset(&mr, 0, sizeof(mr));
503 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
504 media_record_exists = false;
505 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
506 if (mr.VolBytes != 0) {
507 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
508 vl->Slot, mr.VolumeName);
511 mr.StorageId = store->StorageId;
512 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
513 bsendmsg(ua, _("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
517 media_record_exists = true;
520 mr.StorageId = store->StorageId;
522 * Deal with creating cleaning tape here. Normal tapes created in
523 * send_label_request() below
525 if (is_cleaning_tape(ua, &mr, &pr)) {
526 if (media_record_exists) { /* we update it */
528 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
530 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
531 bsendmsg(ua, "%s", db_strerror(ua->db));
533 } else { /* create the media record */
534 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
535 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
537 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
538 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
540 pr.NumVols++; /* this is a bit suspect */
541 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
542 bsendmsg(ua, "%s", db_strerror(ua->db));
545 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
548 continue; /* done, go handle next volume */
550 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
553 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
559 free_vol_list(vol_list);
566 * Check if the Volume name has legal characters
567 * If ua is non-NULL send the message
569 bool is_volume_name_legal(UAContext *ua, const char *name)
573 const char *accept = ":.-_";
575 /* Restrict the characters permitted in the Volume name */
576 for (p=name; *p; p++) {
577 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
581 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
586 if (len >= MAX_NAME_LENGTH) {
588 bsendmsg(ua, _("Volume name too long.\n"));
594 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
602 * NOTE! This routine opens the SD socket but leaves it open
604 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
605 POOL_DBR *pr, int relabel, bool media_record_exists,
609 char dev_name[MAX_NAME_LENGTH];
612 if (!(sd=open_sd_bsock(ua))) {
615 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
616 bash_spaces(dev_name);
617 bash_spaces(mr->VolumeName);
618 bash_spaces(mr->MediaType);
619 bash_spaces(pr->Name);
621 bash_spaces(omr->VolumeName);
622 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
623 "MediaType=%s Slot=%d drive=%d",
624 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
625 mr->MediaType, mr->Slot, drive);
626 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
627 omr->VolumeName, mr->VolumeName);
629 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
631 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
633 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
634 mr->VolumeName, mr->Slot);
635 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
636 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
639 while (bnet_recv(sd) >= 0) {
640 bsendmsg(ua, "%s", sd->msg);
641 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
645 unbash_spaces(mr->VolumeName);
646 unbash_spaces(mr->MediaType);
647 unbash_spaces(pr->Name);
648 mr->LabelDate = time(NULL);
649 mr->set_label_date = true;
651 if (media_record_exists) { /* we update it */
654 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
655 bsendmsg(ua, "%s", db_strerror(ua->db));
658 } else { /* create the media record */
659 set_pool_dbr_defaults_in_media_dbr(mr, pr);
660 mr->VolBytes = 1; /* flag indicating Volume labeled */
662 if (db_create_media_record(ua->jcr, ua->db, mr)) {
663 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
664 mr->VolumeName, mr->Slot);
665 /* Update number of volumes in pool */
667 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
668 bsendmsg(ua, "%s", db_strerror(ua->db));
671 bsendmsg(ua, "%s", db_strerror(ua->db));
676 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
681 static BSOCK *open_sd_bsock(UAContext *ua)
683 STORE *store = ua->jcr->store;
685 if (!ua->jcr->store_bsock) {
686 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
687 store->hdr.name, store->address, store->SDport);
688 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
689 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
693 return ua->jcr->store_bsock;
696 static void close_sd_bsock(UAContext *ua)
698 if (ua->jcr->store_bsock) {
699 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
700 bnet_close(ua->jcr->store_bsock);
701 ua->jcr->store_bsock = NULL;
705 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
707 STORE *store = ua->jcr->store;
709 char dev_name[MAX_NAME_LENGTH];
710 char *VolName = NULL;
713 if (!(sd=open_sd_bsock(ua))) {
714 bsendmsg(ua, _("Could not open SD socket.\n"));
717 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
718 bash_spaces(dev_name);
719 /* Ask for autochanger list of volumes */
720 bnet_fsend(sd, _("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
721 Dmsg1(100, "Sent: %s", sd->msg);
723 /* Get Volume name in this Slot */
724 while (bnet_recv(sd) >= 0) {
725 bsendmsg(ua, "%s", sd->msg);
726 Dmsg1(100, "Got: %s", sd->msg);
727 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
728 VolName = (char *)malloc(sd->msglen);
729 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
737 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
742 * We get the slot list from the Storage daemon.
743 * If scan is set, we return all slots found,
744 * otherwise, we return only slots with valid barcodes (Volume names)
746 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
748 STORE *store = ua->jcr->store;
749 char dev_name[MAX_NAME_LENGTH];
752 vol_list_t *vol_list = NULL;
755 if (!(sd=open_sd_bsock(ua))) {
759 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
760 bash_spaces(dev_name);
761 /* Ask for autochanger list of volumes */
762 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
764 /* Read and organize list of Volumes */
765 while (bnet_recv(sd) >= 0) {
768 strip_trailing_junk(sd->msg);
770 /* Check for returned SD messages */
771 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
772 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
774 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
778 /* Validate Slot: if scanning, otherwise Slot:Barcode */
779 p = strchr(sd->msg, ':');
781 /* Scanning -- require only valid slot */
782 Slot = atoi(sd->msg);
786 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
791 if (p && strlen(p) > 1) {
793 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
796 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
802 if (!is_volume_name_legal(ua, p)) {
805 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
810 /* Add Slot and VolumeName to list */
811 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
815 p++; /* skip separator */
817 vl->VolName = bstrdup(p);
821 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
826 /* Add new entry to end of list */
827 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
840 static void free_vol_list(vol_list_t *vol_list)
845 for (vl=vol_list; vl; ) {
857 * We get the number of slots in the changer from the SD
859 static int get_num_slots_from_SD(UAContext *ua)
861 STORE *store = ua->jcr->store;
862 char dev_name[MAX_NAME_LENGTH];
867 if (!(sd=open_sd_bsock(ua))) {
871 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
872 bash_spaces(dev_name);
873 /* Ask for autochanger list of volumes */
874 bnet_fsend(sd, _("autochanger slots %s \n"), dev_name);
876 while (bnet_recv(sd) >= 0) {
877 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
880 bsendmsg(ua, "%s", sd->msg);
884 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
891 * Check if this is a cleaning tape by comparing the Volume name
892 * with the Cleaning Prefix. If they match, this is a cleaning
895 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
897 /* Find Pool resource */
898 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
899 if (!ua->jcr->pool) {
900 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
903 if (ua->jcr->pool->cleaning_prefix == NULL) {
906 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
907 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
908 strlen(ua->jcr->pool->cleaning_prefix),
909 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
910 strlen(ua->jcr->pool->cleaning_prefix)));
911 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
912 strlen(ua->jcr->pool->cleaning_prefix)) == 0;