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 ammended 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);
38 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
39 POOL_DBR *pr, int relabel, bool media_record_exits);
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);
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++) {
135 printf("Slots turned on:\n");
136 for (i=1; i <= num_slots; i++) {
149 * Update Slots corresponding to Volumes in autochanger
151 int update_slots(UAContext *ua)
154 vol_list_t *vl, *vol_list = NULL;
164 store = get_storage_resource(ua, 1);
168 set_storage(ua->jcr, store);
170 scan = find_arg(ua, _("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);
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;
288 bool media_record_exists = false;
289 static const char *barcode_keyword[] = {
295 memset(&pr, 0, sizeof(pr));
299 store = get_storage_resource(ua, 1);
303 set_storage(ua->jcr, store);
305 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
306 label_from_barcodes(ua);
310 /* If relabel get name of Volume to relabel */
312 /* Check for oldvolume=name */
313 i = find_arg_with_value(ua, "oldvolume");
315 memset(&omr, 0, sizeof(omr));
316 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
317 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
320 bsendmsg(ua, "%s", db_strerror(ua->db));
322 /* No keyword or Vol not found, ask user to select */
323 if (!select_media_dbr(ua, &omr)) {
327 /* Require Volume to be Purged or Recycled */
329 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
330 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
331 omr.VolumeName, omr.VolStatus);
336 /* Check for volume=NewVolume */
337 i = find_arg_with_value(ua, "volume");
339 pm_strcpy(ua->cmd, ua->argv[i]);
343 /* Get a new Volume name */
345 media_record_exists = false;
346 if (!get_cmd(ua, _("Enter new Volume name: "))) {
350 if (!is_volume_name_legal(ua, ua->cmd)) {
354 memset(&mr, 0, sizeof(mr));
355 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
356 /* If VolBytes are zero the Volume is not labeled */
357 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
358 if (mr.VolBytes != 0) {
359 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
363 media_record_exists = true;
368 /* If autochanger, request slot */
369 if (store->autochanger) {
370 i = find_arg_with_value(ua, "slot");
372 mr.Slot = atoi(ua->argv[i]);
373 } else if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
376 mr.Slot = ua->pint32_val;
378 mr.InChanger = 1; /* assumed if we are labeling it */
380 mr.StorageId = store->StorageId;
382 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
384 /* Must select Pool if not already done */
385 if (pr.PoolId == 0) {
386 memset(&pr, 0, sizeof(pr));
387 if (!select_pool_dbr(ua, &pr)) {
392 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
395 sd = ua->jcr->store_bsock;
397 /* Delete the old media record */
398 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
399 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
400 omr.VolumeName, db_strerror(ua->db));
402 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
404 /* Update the number of Volumes in the pool */
406 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
407 bsendmsg(ua, "%s", db_strerror(ua->db));
412 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
413 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
414 bash_spaces(dev_name);
415 bnet_fsend(sd, "mount %s", dev_name);
416 unbash_spaces(dev_name);
417 while (bnet_recv(sd) >= 0) {
418 bsendmsg(ua, "%s", sd->msg);
420 * 3001 OK mount. Device=xxx or
421 * 3001 Mounted Volume vvvv
422 * 3906 is cannot mount non-tape
423 * So for those, no need to print a reminder
425 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
426 strncmp(sd->msg, "3906 ", 5) == 0) {
427 print_reminder = false;
432 if (print_reminder) {
433 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
441 * Request SD to send us the slot:barcodes, then wiffle
442 * through them all labeling them.
444 static void label_from_barcodes(UAContext *ua)
446 STORE *store = ua->jcr->store;
449 vol_list_t *vl, *vol_list = NULL;
450 bool media_record_exists;
455 max_slots = get_num_slots_from_SD(ua);
456 if (max_slots <= 0) {
457 bsendmsg(ua, _("No slots in changer to scan.\n"));
460 slot_list = (char *)malloc(max_slots+1);
461 if (!get_user_slot_list(ua, slot_list, max_slots)) {
465 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
468 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
472 /* Display list of Volumes and ask if he really wants to proceed */
473 bsendmsg(ua, _("The following Volumes will be labeled:\n"
475 "==============\n"));
476 for (vl=vol_list; vl; vl=vl->next) {
477 if (!vl->VolName || !slot_list[vl->Slot]) {
480 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
482 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
483 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
487 memset(&pr, 0, sizeof(pr));
488 if (!select_pool_dbr(ua, &pr)) {
491 memset(&omr, 0, sizeof(omr));
493 /* Fire off the label requests */
494 for (vl=vol_list; vl; vl=vl->next) {
495 if (!vl->VolName || !slot_list[vl->Slot]) {
498 memset(&mr, 0, sizeof(mr));
499 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
500 media_record_exists = false;
501 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
502 if (mr.VolBytes != 0) {
503 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
504 vl->Slot, mr.VolumeName);
507 mr.StorageId = store->StorageId;
508 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
509 bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
513 media_record_exists = true;
516 mr.StorageId = store->StorageId;
518 * Deal with creating cleaning tape here. Normal tapes created in
519 * send_label_request() below
521 if (is_cleaning_tape(ua, &mr, &pr)) {
522 if (media_record_exists) { /* we update it */
524 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
525 bsendmsg(ua, "%s", db_strerror(ua->db));
527 } else { /* create the media record */
528 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
529 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
530 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
532 pr.NumVols++; /* this is a bit suspect */
533 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
534 bsendmsg(ua, "%s", db_strerror(ua->db));
537 bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
540 continue; /* done, go handle next volume */
542 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
545 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
551 free_vol_list(vol_list);
558 * Check if the Volume name has legal characters
559 * If ua is non-NULL send the message
561 bool is_volume_name_legal(UAContext *ua, const char *name)
565 const char *accept = ":.-_";
567 /* Restrict the characters permitted in the Volume name */
568 for (p=name; *p; p++) {
569 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
573 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
578 if (len >= MAX_NAME_LENGTH) {
580 bsendmsg(ua, _("Volume name too long.\n"));
586 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
594 * NOTE! This routine opens the SD socket but leaves it open
596 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
597 POOL_DBR *pr, int relabel, bool media_record_exists)
600 char dev_name[MAX_NAME_LENGTH];
603 if (!(sd=open_sd_bsock(ua))) {
606 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
607 bash_spaces(dev_name);
608 bash_spaces(mr->VolumeName);
609 bash_spaces(mr->MediaType);
610 bash_spaces(pr->Name);
612 bash_spaces(omr->VolumeName);
613 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d",
614 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
615 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
616 omr->VolumeName, mr->VolumeName);
618 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
619 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
620 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
621 mr->VolumeName, mr->Slot);
622 Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n",
623 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
626 while (bnet_recv(sd) >= 0) {
627 bsendmsg(ua, "%s", sd->msg);
628 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
632 unbash_spaces(mr->VolumeName);
633 unbash_spaces(mr->MediaType);
634 unbash_spaces(pr->Name);
635 mr->LabelDate = time(NULL);
636 mr->set_label_date = true;
638 if (media_record_exists) { /* we update it */
641 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
642 bsendmsg(ua, "%s", db_strerror(ua->db));
645 } else { /* create the media record */
646 set_pool_dbr_defaults_in_media_dbr(mr, pr);
647 mr->VolBytes = 1; /* flag indicating Volume labeled */
649 if (db_create_media_record(ua->jcr, ua->db, mr)) {
650 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
651 mr->VolumeName, mr->Slot);
652 /* Update number of volumes in pool */
654 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
655 bsendmsg(ua, "%s", db_strerror(ua->db));
658 bsendmsg(ua, "%s", db_strerror(ua->db));
663 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
668 static BSOCK *open_sd_bsock(UAContext *ua)
670 STORE *store = ua->jcr->store;
672 if (!ua->jcr->store_bsock) {
673 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
674 store->hdr.name, store->address, store->SDport);
675 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
676 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
680 return ua->jcr->store_bsock;
683 static void close_sd_bsock(UAContext *ua)
685 if (ua->jcr->store_bsock) {
686 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
687 bnet_close(ua->jcr->store_bsock);
688 ua->jcr->store_bsock = NULL;
692 static char *get_volume_name_from_SD(UAContext *ua, int Slot)
694 STORE *store = ua->jcr->store;
696 char dev_name[MAX_NAME_LENGTH];
697 char *VolName = NULL;
700 if (!(sd=open_sd_bsock(ua))) {
701 bsendmsg(ua, _("Could not open SD socket.\n"));
704 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
705 bash_spaces(dev_name);
706 /* Ask for autochanger list of volumes */
707 bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
708 Dmsg1(100, "Sent: %s", sd->msg);
710 /* Get Volume name in this Slot */
711 while (bnet_recv(sd) >= 0) {
712 bsendmsg(ua, "%s", sd->msg);
713 Dmsg1(100, "Got: %s", sd->msg);
714 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
715 VolName = (char *)malloc(sd->msglen);
716 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
724 Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
729 * We get the slot list from the Storage daemon.
730 * If scan is set, we return all slots found,
731 * otherwise, we return only slots with valid barcodes (Volume names)
733 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
735 STORE *store = ua->jcr->store;
736 char dev_name[MAX_NAME_LENGTH];
739 vol_list_t *vol_list = NULL;
742 if (!(sd=open_sd_bsock(ua))) {
746 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
747 bash_spaces(dev_name);
748 /* Ask for autochanger list of volumes */
749 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
751 /* Read and organize list of Volumes */
752 while (bnet_recv(sd) >= 0) {
755 strip_trailing_junk(sd->msg);
757 /* Check for returned SD messages */
758 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
759 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
761 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
765 /* Validate Slot: if scanning, otherwise Slot:Barcode */
766 p = strchr(sd->msg, ':');
768 /* Scanning -- require only valid slot */
769 Slot = atoi(sd->msg);
773 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
778 if (p && strlen(p) > 1) {
780 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
783 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
789 if (!is_volume_name_legal(ua, p)) {
792 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
797 /* Add Slot and VolumeName to list */
798 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
802 p++; /* skip separator */
804 vl->VolName = bstrdup(p);
808 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
813 /* Add new entry to end of list */
814 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
827 static void free_vol_list(vol_list_t *vol_list)
832 for (vl=vol_list; vl; ) {
844 * We get the number of slots in the changer from the SD
846 static int get_num_slots_from_SD(UAContext *ua)
848 STORE *store = ua->jcr->store;
849 char dev_name[MAX_NAME_LENGTH];
854 if (!(sd=open_sd_bsock(ua))) {
858 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
859 bash_spaces(dev_name);
860 /* Ask for autochanger list of volumes */
861 bnet_fsend(sd, _("autochanger slots %s \n"), dev_name);
863 while (bnet_recv(sd) >= 0) {
864 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
867 bsendmsg(ua, "%s", sd->msg);
871 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
878 * Check if this is a cleaning tape by comparing the Volume name
879 * with the Cleaning Prefix. If they match, this is a cleaning
882 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
884 /* Find Pool resource */
885 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
886 if (!ua->jcr->pool) {
887 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
890 if (ua->jcr->pool->cleaning_prefix == NULL) {
893 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
894 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
895 strlen(ua->jcr->pool->cleaning_prefix),
896 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
897 strlen(ua->jcr->pool->cleaning_prefix)));
898 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
899 strlen(ua->jcr->pool->cleaning_prefix)) == 0;