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);
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 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
423 * 3906 is cannot mount non-tape
424 * So for those, no need to print a reminder
426 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
427 strncmp(sd->msg, "3002 ", 5) == 0 ||
428 strncmp(sd->msg, "3906 ", 5) == 0) {
429 print_reminder = false;
434 if (print_reminder) {
435 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
443 * Request SD to send us the slot:barcodes, then wiffle
444 * through them all labeling them.
446 static void label_from_barcodes(UAContext *ua)
448 STORE *store = ua->jcr->store;
451 vol_list_t *vl, *vol_list = NULL;
452 bool media_record_exists;
457 max_slots = get_num_slots_from_SD(ua);
458 if (max_slots <= 0) {
459 bsendmsg(ua, _("No slots in changer to scan.\n"));
462 slot_list = (char *)malloc(max_slots+1);
463 if (!get_user_slot_list(ua, slot_list, max_slots)) {
467 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
470 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
474 /* Display list of Volumes and ask if he really wants to proceed */
475 bsendmsg(ua, _("The following Volumes will be labeled:\n"
477 "==============\n"));
478 for (vl=vol_list; vl; vl=vl->next) {
479 if (!vl->VolName || !slot_list[vl->Slot]) {
482 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
484 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
485 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
489 memset(&pr, 0, sizeof(pr));
490 if (!select_pool_dbr(ua, &pr)) {
493 memset(&omr, 0, sizeof(omr));
495 /* Fire off the label requests */
496 for (vl=vol_list; vl; vl=vl->next) {
497 if (!vl->VolName || !slot_list[vl->Slot]) {
500 memset(&mr, 0, sizeof(mr));
501 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
502 media_record_exists = false;
503 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
504 if (mr.VolBytes != 0) {
505 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
506 vl->Slot, mr.VolumeName);
509 mr.StorageId = store->StorageId;
510 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
511 bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
515 media_record_exists = true;
518 mr.StorageId = store->StorageId;
520 * Deal with creating cleaning tape here. Normal tapes created in
521 * send_label_request() below
523 if (is_cleaning_tape(ua, &mr, &pr)) {
524 if (media_record_exists) { /* we update it */
526 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
528 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
529 bsendmsg(ua, "%s", db_strerror(ua->db));
531 } else { /* create the media record */
532 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
533 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
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;