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++) {
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;
165 store = get_storage_resource(ua, 1);
169 drive = get_storage_drive(ua, store);
170 set_storage(ua->jcr, store);
172 scan = find_arg(ua, N_("scan")) >= 0;
174 max_slots = get_num_slots_from_SD(ua);
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 /* Walk through the list updating the media records */
193 for (vl=vol_list; vl; vl=vl->next) {
194 if (vl->Slot > max_slots) {
195 bsendmsg(ua, _("Slot %d larger than max %d ignored.\n"),
196 vl->Slot, max_slots);
199 /* Check if user wants us to look at this slot */
200 if (!slot_list[vl->Slot]) {
201 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
204 /* If scanning, we read the label rather than the barcode */
210 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
211 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
213 slot_list[vl->Slot] = 0; /* clear Slot */
215 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
216 memset(&mr, 0, sizeof(mr));
219 mr.StorageId = store->StorageId;
220 /* Set InChanger to zero for this Slot */
222 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
224 bsendmsg(ua, _("No VolName for Slot=%d set InChanger to zero.\n"), vl->Slot);
227 memset(&mr, 0, sizeof(mr));
228 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
230 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
231 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
234 mr.StorageId = store->StorageId;
235 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
236 bsendmsg(ua, "%s", db_strerror(ua->db));
239 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
240 mr.VolumeName, mr.Slot);
243 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
249 bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
254 memset(&mr, 0, sizeof(mr));
256 mr.StorageId = store->StorageId;
258 for (int i=1; i <= max_slots; i++) {
261 /* Set InChanger to zero for this Slot */
262 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
269 free_vol_list(vol_list);
278 * Common routine for both label and relabel
280 static int do_label(UAContext *ua, const char *cmd, int relabel)
284 char dev_name[MAX_NAME_LENGTH];
287 bool print_reminder = true;
291 bool media_record_exists = false;
292 static const char *barcode_keyword[] = {
298 memset(&pr, 0, sizeof(pr));
302 store = get_storage_resource(ua, true/*use default*/);
306 drive = get_storage_drive(ua, store);
307 set_storage(ua->jcr, store);
309 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
310 label_from_barcodes(ua, drive);
314 /* If relabel get name of Volume to relabel */
316 /* Check for oldvolume=name */
317 i = find_arg_with_value(ua, "oldvolume");
319 memset(&omr, 0, sizeof(omr));
320 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
321 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
324 bsendmsg(ua, "%s", db_strerror(ua->db));
326 /* No keyword or Vol not found, ask user to select */
327 if (!select_media_dbr(ua, &omr)) {
331 /* Require Volume to be Purged or Recycled */
333 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
334 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
335 omr.VolumeName, omr.VolStatus);
340 /* Check for volume=NewVolume */
341 i = find_arg_with_value(ua, "volume");
343 pm_strcpy(ua->cmd, ua->argv[i]);
347 /* Get a new Volume name */
349 media_record_exists = false;
350 if (!get_cmd(ua, _("Enter new Volume name: "))) {
354 if (!is_volume_name_legal(ua, ua->cmd)) {
358 memset(&mr, 0, sizeof(mr));
359 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
360 /* If VolBytes are zero the Volume is not labeled */
361 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
362 if (mr.VolBytes != 0) {
363 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
367 media_record_exists = true;
372 /* If autochanger, request slot */
373 i = find_arg_with_value(ua, "slot");
375 mr.Slot = atoi(ua->argv[i]);
376 mr.InChanger = 1; /* assumed if we are labeling it */
377 } else if (store->autochanger) {
378 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
381 mr.Slot = ua->pint32_val;
382 mr.InChanger = 1; /* assumed if we are labeling it */
384 mr.StorageId = store->StorageId;
386 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
388 /* Must select Pool if not already done */
389 if (pr.PoolId == 0) {
390 memset(&pr, 0, sizeof(pr));
391 if (!select_pool_dbr(ua, &pr)) {
396 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
399 sd = ua->jcr->store_bsock;
401 /* Delete the old media record */
402 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
403 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
404 omr.VolumeName, db_strerror(ua->db));
406 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
408 /* Update the number of Volumes in the pool */
410 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
411 bsendmsg(ua, "%s", db_strerror(ua->db));
416 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
417 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
418 bash_spaces(dev_name);
419 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
420 unbash_spaces(dev_name);
421 while (bnet_recv(sd) >= 0) {
422 bsendmsg(ua, "%s", sd->msg);
424 * 3001 OK mount. Device=xxx or
425 * 3001 Mounted Volume vvvv
426 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
427 * 3906 is cannot mount non-tape
428 * So for those, no need to print a reminder
430 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
431 strncmp(sd->msg, "3002 ", 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, int drive)
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 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
532 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
533 bsendmsg(ua, "%s", db_strerror(ua->db));
535 } else { /* create the media record */
536 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
537 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
539 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
540 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
542 pr.NumVols++; /* this is a bit suspect */
543 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
544 bsendmsg(ua, "%s", db_strerror(ua->db));
547 bsendmsg(ua, _("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
550 continue; /* done, go handle next volume */
552 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
555 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
561 free_vol_list(vol_list);
568 * Check if the Volume name has legal characters
569 * If ua is non-NULL send the message
571 bool is_volume_name_legal(UAContext *ua, const char *name)
575 const char *accept = ":.-_";
577 /* Restrict the characters permitted in the Volume name */
578 for (p=name; *p; p++) {
579 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
583 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
588 if (len >= MAX_NAME_LENGTH) {
590 bsendmsg(ua, _("Volume name too long.\n"));
596 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
604 * NOTE! This routine opens the SD socket but leaves it open
606 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
607 POOL_DBR *pr, int relabel, bool media_record_exists,
611 char dev_name[MAX_NAME_LENGTH];
614 if (!(sd=open_sd_bsock(ua))) {
617 bstrncpy(dev_name, ua->jcr->store->dev_name(), sizeof(dev_name));
618 bash_spaces(dev_name);
619 bash_spaces(mr->VolumeName);
620 bash_spaces(mr->MediaType);
621 bash_spaces(pr->Name);
623 bash_spaces(omr->VolumeName);
624 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s "
625 "MediaType=%s Slot=%d drive=%d",
626 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
627 mr->MediaType, mr->Slot, drive);
628 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
629 omr->VolumeName, mr->VolumeName);
631 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s "
633 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
635 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
636 mr->VolumeName, mr->Slot);
637 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
638 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
641 while (bnet_recv(sd) >= 0) {
642 bsendmsg(ua, "%s", sd->msg);
643 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
647 unbash_spaces(mr->VolumeName);
648 unbash_spaces(mr->MediaType);
649 unbash_spaces(pr->Name);
650 mr->LabelDate = time(NULL);
651 mr->set_label_date = true;
653 if (media_record_exists) { /* we update it */
656 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
657 bsendmsg(ua, "%s", db_strerror(ua->db));
660 } else { /* create the media record */
661 set_pool_dbr_defaults_in_media_dbr(mr, pr);
662 mr->VolBytes = 1; /* flag indicating Volume labeled */
664 if (db_create_media_record(ua->jcr, ua->db, mr)) {
665 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
666 mr->VolumeName, mr->Slot);
667 /* Update number of volumes in pool */
669 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
670 bsendmsg(ua, "%s", db_strerror(ua->db));
673 bsendmsg(ua, "%s", db_strerror(ua->db));
678 bsendmsg(ua, _("Label command failed for Volume %s.\n"), mr->VolumeName);
683 static BSOCK *open_sd_bsock(UAContext *ua)
685 STORE *store = ua->jcr->store;
687 if (!ua->jcr->store_bsock) {
688 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
689 store->hdr.name, store->address, store->SDport);
690 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
691 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
695 return ua->jcr->store_bsock;
698 static void close_sd_bsock(UAContext *ua)
700 if (ua->jcr->store_bsock) {
701 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
702 bnet_close(ua->jcr->store_bsock);
703 ua->jcr->store_bsock = NULL;
707 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
709 STORE *store = ua->jcr->store;
711 char dev_name[MAX_NAME_LENGTH];
712 char *VolName = NULL;
715 if (!(sd=open_sd_bsock(ua))) {
716 bsendmsg(ua, _("Could not open SD socket.\n"));
719 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
720 bash_spaces(dev_name);
721 /* Ask for autochanger list of volumes */
722 bnet_fsend(sd, _("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
723 Dmsg1(100, "Sent: %s", sd->msg);
725 /* Get Volume name in this Slot */
726 while (bnet_recv(sd) >= 0) {
727 bsendmsg(ua, "%s", sd->msg);
728 Dmsg1(100, "Got: %s", sd->msg);
729 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
730 VolName = (char *)malloc(sd->msglen);
731 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
739 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
744 * We get the slot list from the Storage daemon.
745 * If scan is set, we return all slots found,
746 * otherwise, we return only slots with valid barcodes (Volume names)
748 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
750 STORE *store = ua->jcr->store;
751 char dev_name[MAX_NAME_LENGTH];
754 vol_list_t *vol_list = NULL;
757 if (!(sd=open_sd_bsock(ua))) {
761 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
762 bash_spaces(dev_name);
763 /* Ask for autochanger list of volumes */
764 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
766 /* Read and organize list of Volumes */
767 while (bnet_recv(sd) >= 0) {
770 strip_trailing_junk(sd->msg);
772 /* Check for returned SD messages */
773 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
774 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
776 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
780 /* Validate Slot: if scanning, otherwise Slot:Barcode */
781 p = strchr(sd->msg, ':');
783 /* Scanning -- require only valid slot */
784 Slot = atoi(sd->msg);
788 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
793 if (p && strlen(p) > 1) {
795 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
798 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
804 if (!is_volume_name_legal(ua, p)) {
807 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
812 /* Add Slot and VolumeName to list */
813 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
817 p++; /* skip separator */
819 vl->VolName = bstrdup(p);
823 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
828 /* Add new entry to end of list */
829 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
842 static void free_vol_list(vol_list_t *vol_list)
847 for (vl=vol_list; vl; ) {
859 * We get the number of slots in the changer from the SD
861 static int get_num_slots_from_SD(UAContext *ua)
863 STORE *store = ua->jcr->store;
864 char dev_name[MAX_NAME_LENGTH];
869 if (!(sd=open_sd_bsock(ua))) {
873 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
874 bash_spaces(dev_name);
875 /* Ask for autochanger list of volumes */
876 bnet_fsend(sd, _("autochanger slots %s \n"), dev_name);
878 while (bnet_recv(sd) >= 0) {
879 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
882 bsendmsg(ua, "%s", sd->msg);
886 bsendmsg(ua, _("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
893 * Check if this is a cleaning tape by comparing the Volume name
894 * with the Cleaning Prefix. If they match, this is a cleaning
897 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
899 /* Find Pool resource */
900 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
901 if (!ua->jcr->pool) {
902 bsendmsg(ua, _("Pool \"%s\" resource not found!\n"), pr->Name);
905 if (ua->jcr->pool->cleaning_prefix == NULL) {
908 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
909 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
910 strlen(ua->jcr->pool->cleaning_prefix),
911 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
912 strlen(ua->jcr->pool->cleaning_prefix)));
913 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
914 strlen(ua->jcr->pool->cleaning_prefix)) == 0;