3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
11 Copyright (C) 2000-2005 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
33 /* Slot list definition */
34 typedef struct s_vol_list {
35 struct s_vol_list *next;
41 /* Forward referenced functions */
42 static int do_label(UAContext *ua, const char *cmd, int relabel);
43 static void label_from_barcodes(UAContext *ua);
44 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
45 POOL_DBR *pr, int relabel, bool media_record_exits);
46 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
47 static void free_vol_list(vol_list_t *vol_list);
48 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
49 static BSOCK *open_sd_bsock(UAContext *ua);
50 static void close_sd_bsock(UAContext *ua);
51 static char *get_volume_name_from_SD(UAContext *ua, int Slot);
52 static int get_num_slots_from_SD(UAContext *ua);
58 * label storage=xxx volume=vvv
60 int label_cmd(UAContext *ua, const char *cmd)
62 return do_label(ua, cmd, 0); /* standard label */
65 int relabel_cmd(UAContext *ua, const char *cmd)
67 return do_label(ua, cmd, 1); /* relabel tape */
70 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
75 for (int i=0; i <= num_slots; i++) {
78 i = find_arg_with_value(ua, "slots");
80 /* scan slot list in ua->argv[i] */
84 strip_trailing_junk(ua->argv[i]);
85 for (p=ua->argv[i]; p && *p; p=e) {
92 h = strchr(p, '-'); /* range? */
94 msg = _("Negative numbers not permitted\n");
99 if (!is_an_integer(h)) {
100 msg = _("Range end is not integer.\n");
104 if (!is_an_integer(p)) {
105 msg = _("Range start is not an integer.\n");
111 msg = _("Range end not bigger than start.\n");
116 if (!is_an_integer(p)) {
117 msg = _("Input value is not an integer.\n");
122 if (beg <= 0 || end <= 0) {
123 msg = _("Values must be be greater than zero.\n");
126 if (end >= num_slots) {
127 msg = _("Slot too large.\n");
130 for (i=beg; i<=end; i++) {
131 slot_list[i] = 1; /* Turn on specified range */
135 /* Turn everything on */
136 for (i=0; i <= num_slots; i++) {
141 printf("Slots turned on:\n");
142 for (i=1; i <= num_slots; i++) {
155 * Update Slots corresponding to Volumes in autochanger
157 int update_slots(UAContext *ua)
160 vol_list_t *vl, *vol_list = NULL;
170 store = get_storage_resource(ua, 1);
174 set_storage(ua->jcr, store);
176 scan = find_arg(ua, _("scan")) >= 0;
178 max_slots = get_num_slots_from_SD(ua);
179 if (max_slots <= 0) {
180 bsendmsg(ua, _("No slots in changer to scan.\n"));
183 slot_list = (char *)malloc(max_slots+1);
184 if (!get_user_slot_list(ua, slot_list, max_slots)) {
189 vol_list = get_vol_list_from_SD(ua, scan);
192 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
196 /* Walk through the list updating the media records */
197 for (vl=vol_list; vl; vl=vl->next) {
198 if (vl->Slot > max_slots) {
199 bsendmsg(ua, _("Slot %d larger than max %d ignored.\n"),
200 vl->Slot, max_slots);
203 /* Check if user wants us to look at this slot */
204 if (!slot_list[vl->Slot]) {
205 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
208 /* If scanning, we read the label rather than the barcode */
214 vl->VolName = get_volume_name_from_SD(ua, vl->Slot);
215 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
217 slot_list[vl->Slot] = 0; /* clear Slot */
219 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
220 memset(&mr, 0, sizeof(mr));
223 mr.StorageId = store->StorageId;
224 /* Set InChanger to zero for this Slot */
226 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
228 bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), vl->Slot);
231 memset(&mr, 0, sizeof(mr));
232 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
234 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
235 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
238 mr.StorageId = store->StorageId;
239 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
240 bsendmsg(ua, "%s", db_strerror(ua->db));
243 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
244 mr.VolumeName, mr.Slot);
247 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
253 bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
258 memset(&mr, 0, sizeof(mr));
260 mr.StorageId = store->StorageId;
262 for (int i=1; i <= max_slots; i++) {
265 /* Set InChanger to zero for this Slot */
266 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
273 free_vol_list(vol_list);
282 * Common routine for both label and relabel
284 static int do_label(UAContext *ua, const char *cmd, int relabel)
288 char dev_name[MAX_NAME_LENGTH];
291 bool print_reminder = true;
294 bool media_record_exists = false;
295 static const char *barcode_keyword[] = {
301 memset(&pr, 0, sizeof(pr));
305 store = get_storage_resource(ua, 1);
309 set_storage(ua->jcr, store);
311 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
312 label_from_barcodes(ua);
316 /* If relabel get name of Volume to relabel */
318 /* Check for oldvolume=name */
319 i = find_arg_with_value(ua, "oldvolume");
321 memset(&omr, 0, sizeof(omr));
322 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
323 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
326 bsendmsg(ua, "%s", db_strerror(ua->db));
328 /* No keyword or Vol not found, ask user to select */
329 if (!select_media_dbr(ua, &omr)) {
333 /* Require Volume to be Purged or Recycled */
335 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
336 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
337 omr.VolumeName, omr.VolStatus);
342 /* Check for volume=NewVolume */
343 i = find_arg_with_value(ua, "volume");
345 pm_strcpy(ua->cmd, ua->argv[i]);
349 /* Get a new Volume name */
351 media_record_exists = false;
352 if (!get_cmd(ua, _("Enter new Volume name: "))) {
356 if (!is_volume_name_legal(ua, ua->cmd)) {
360 memset(&mr, 0, sizeof(mr));
361 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
362 /* If VolBytes are zero the Volume is not labeled */
363 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
364 if (mr.VolBytes != 0) {
365 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
369 media_record_exists = true;
374 /* If autochanger, request slot */
375 if (store->autochanger) {
376 i = find_arg_with_value(ua, "slot");
378 mr.Slot = atoi(ua->argv[i]);
379 } else if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
382 mr.Slot = ua->pint32_val;
384 mr.InChanger = 1; /* assumed if we are labeling it */
386 mr.StorageId = store->StorageId;
388 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
390 /* Must select Pool if not already done */
391 if (pr.PoolId == 0) {
392 memset(&pr, 0, sizeof(pr));
393 if (!select_pool_dbr(ua, &pr)) {
398 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
401 sd = ua->jcr->store_bsock;
403 /* Delete the old media record */
404 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
405 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
406 omr.VolumeName, db_strerror(ua->db));
408 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
410 /* Update the number of Volumes in the pool */
412 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
413 bsendmsg(ua, "%s", db_strerror(ua->db));
418 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
419 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
420 bash_spaces(dev_name);
421 bnet_fsend(sd, "mount %s", dev_name);
422 unbash_spaces(dev_name);
423 while (bnet_recv(sd) >= 0) {
424 bsendmsg(ua, "%s", sd->msg);
426 * 3001 OK mount. Device=xxx or
427 * 3001 Mounted Volume vvvv
428 * 3906 is cannot mount non-tape
429 * So for those, no need to print a reminder
431 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
432 strncmp(sd->msg, "3906 ", 5) == 0) {
433 print_reminder = false;
438 if (print_reminder) {
439 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
447 * Request SD to send us the slot:barcodes, then wiffle
448 * through them all labeling them.
450 static void label_from_barcodes(UAContext *ua)
452 STORE *store = ua->jcr->store;
455 vol_list_t *vl, *vol_list = NULL;
456 bool media_record_exists;
461 max_slots = get_num_slots_from_SD(ua);
462 if (max_slots <= 0) {
463 bsendmsg(ua, _("No slots in changer to scan.\n"));
466 slot_list = (char *)malloc(max_slots+1);
467 if (!get_user_slot_list(ua, slot_list, max_slots)) {
471 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
474 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
478 /* Display list of Volumes and ask if he really wants to proceed */
479 bsendmsg(ua, _("The following Volumes will be labeled:\n"
481 "==============\n"));
482 for (vl=vol_list; vl; vl=vl->next) {
483 if (!vl->VolName || !slot_list[vl->Slot]) {
486 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
488 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
489 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
493 memset(&pr, 0, sizeof(pr));
494 if (!select_pool_dbr(ua, &pr)) {
497 memset(&omr, 0, sizeof(omr));
499 /* Fire off the label requests */
500 for (vl=vol_list; vl; vl=vl->next) {
501 if (!vl->VolName || !slot_list[vl->Slot]) {
504 memset(&mr, 0, sizeof(mr));
505 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
506 media_record_exists = false;
507 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
508 if (mr.VolBytes != 0) {
509 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
510 vl->Slot, mr.VolumeName);
513 mr.StorageId = store->StorageId;
514 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
515 bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
519 media_record_exists = true;
522 mr.StorageId = store->StorageId;
524 * Deal with creating cleaning tape here. Normal tapes created in
525 * send_label_request() below
527 if (is_cleaning_tape(ua, &mr, &pr)) {
528 if (media_record_exists) { /* we update it */
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 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
536 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
538 pr.NumVols++; /* this is a bit suspect */
539 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
540 bsendmsg(ua, "%s", db_strerror(ua->db));
543 bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
546 continue; /* done, go handle next volume */
548 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
551 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
557 free_vol_list(vol_list);
564 * Check if the Volume name has legal characters
565 * If ua is non-NULL send the message
567 bool is_volume_name_legal(UAContext *ua, const char *name)
571 const char *accept = ":.-_";
573 /* Restrict the characters permitted in the Volume name */
574 for (p=name; *p; p++) {
575 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
579 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
584 if (len >= MAX_NAME_LENGTH) {
586 bsendmsg(ua, _("Volume name too long.\n"));
592 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
600 * NOTE! This routine opens the SD socket but leaves it open
602 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
603 POOL_DBR *pr, int relabel, bool media_record_exists)
606 char dev_name[MAX_NAME_LENGTH];
609 if (!(sd=open_sd_bsock(ua))) {
612 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
613 bash_spaces(dev_name);
614 bash_spaces(mr->VolumeName);
615 bash_spaces(mr->MediaType);
616 bash_spaces(pr->Name);
618 bash_spaces(omr->VolumeName);
619 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d",
620 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
621 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
622 omr->VolumeName, mr->VolumeName);
624 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
625 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
626 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
627 mr->VolumeName, mr->Slot);
628 Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n",
629 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
632 while (bnet_recv(sd) >= 0) {
633 bsendmsg(ua, "%s", sd->msg);
634 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
638 unbash_spaces(mr->VolumeName);
639 unbash_spaces(mr->MediaType);
640 unbash_spaces(pr->Name);
641 mr->LabelDate = time(NULL);
642 mr->set_label_date = true;
644 if (media_record_exists) { /* we update it */
647 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
648 bsendmsg(ua, "%s", db_strerror(ua->db));
651 } else { /* create the media record */
652 set_pool_dbr_defaults_in_media_dbr(mr, pr);
653 mr->VolBytes = 1; /* flag indicating Volume labeled */
655 if (db_create_media_record(ua->jcr, ua->db, mr)) {
656 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
657 mr->VolumeName, mr->Slot);
658 /* Update number of volumes in pool */
660 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
661 bsendmsg(ua, "%s", db_strerror(ua->db));
664 bsendmsg(ua, "%s", db_strerror(ua->db));
669 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
674 static BSOCK *open_sd_bsock(UAContext *ua)
676 STORE *store = ua->jcr->store;
678 if (!ua->jcr->store_bsock) {
679 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
680 store->hdr.name, store->address, store->SDport);
681 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
682 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
686 return ua->jcr->store_bsock;
689 static void close_sd_bsock(UAContext *ua)
691 if (ua->jcr->store_bsock) {
692 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
693 bnet_close(ua->jcr->store_bsock);
694 ua->jcr->store_bsock = NULL;
698 static char *get_volume_name_from_SD(UAContext *ua, int Slot)
700 STORE *store = ua->jcr->store;
702 char dev_name[MAX_NAME_LENGTH];
703 char *VolName = NULL;
706 if (!(sd=open_sd_bsock(ua))) {
707 bsendmsg(ua, _("Could not open SD socket.\n"));
710 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
711 bash_spaces(dev_name);
712 /* Ask for autochanger list of volumes */
713 bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
714 Dmsg1(100, "Sent: %s", sd->msg);
716 /* Get Volume name in this Slot */
717 while (bnet_recv(sd) >= 0) {
718 bsendmsg(ua, "%s", sd->msg);
719 Dmsg1(100, "Got: %s", sd->msg);
720 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
721 VolName = (char *)malloc(sd->msglen);
722 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
730 Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
735 * We get the slot list from the Storage daemon.
736 * If scan is set, we return all slots found,
737 * otherwise, we return only slots with valid barcodes (Volume names)
739 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
741 STORE *store = ua->jcr->store;
742 char dev_name[MAX_NAME_LENGTH];
745 vol_list_t *vol_list = NULL;
748 if (!(sd=open_sd_bsock(ua))) {
752 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
753 bash_spaces(dev_name);
754 /* Ask for autochanger list of volumes */
755 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
757 /* Read and organize list of Volumes */
758 while (bnet_recv(sd) >= 0) {
761 strip_trailing_junk(sd->msg);
763 /* Check for returned SD messages */
764 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
765 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
767 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
771 /* Validate Slot: if scanning, otherwise Slot:Barcode */
772 p = strchr(sd->msg, ':');
774 /* Scanning -- require only valid slot */
775 Slot = atoi(sd->msg);
779 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
784 if (p && strlen(p) > 1) {
786 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
789 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
795 if (!is_volume_name_legal(ua, p)) {
798 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
803 /* Add Slot and VolumeName to list */
804 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
808 p++; /* skip separator */
810 vl->VolName = bstrdup(p);
814 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
819 /* Add new entry to end of list */
820 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
833 static void free_vol_list(vol_list_t *vol_list)
838 for (vl=vol_list; vl; ) {
850 * We get the number of slots in the changer from the SD
852 static int get_num_slots_from_SD(UAContext *ua)
854 STORE *store = ua->jcr->store;
855 char dev_name[MAX_NAME_LENGTH];
860 if (!(sd=open_sd_bsock(ua))) {
864 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
865 bash_spaces(dev_name);
866 /* Ask for autochanger list of volumes */
867 bnet_fsend(sd, _("autochanger slots %s \n"), dev_name);
869 while (bnet_recv(sd) >= 0) {
870 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
873 bsendmsg(ua, "%s", sd->msg);
877 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
884 * Check if this is a cleaning tape by comparing the Volume name
885 * with the Cleaning Prefix. If they match, this is a cleaning
888 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
890 /* Find Pool resource */
891 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
892 if (!ua->jcr->pool) {
893 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
896 if (ua->jcr->pool->cleaning_prefix == NULL) {
899 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
900 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
901 strlen(ua->jcr->pool->cleaning_prefix),
902 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
903 strlen(ua->jcr->pool->cleaning_prefix)));
904 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
905 strlen(ua->jcr->pool->cleaning_prefix)) == 0;