3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
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, char *cmd, int relabel);
43 static void label_from_barcodes(UAContext *ua);
44 static int 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 int 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);
57 * label storage=xxx volume=vvv
59 int label_cmd(UAContext *ua, char *cmd)
61 return do_label(ua, cmd, 0); /* standard label */
64 int relabel_cmd(UAContext *ua, char *cmd)
66 return do_label(ua, cmd, 1); /* relabel tape */
69 #define MAX_SLOTS 5000
71 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
76 for (int i=0; i<num_slots; i++) {
79 i = find_arg_with_value(ua, "slots");
81 /* scan slot list in ua->argv[i] */
85 strip_trailing_junk(ua->argv[i]);
86 for (p=ua->argv[i]; p && *p; p=e) {
93 h = strchr(p, '-'); /* range? */
95 msg = _("Negative numbers not permitted\n");
100 if (!is_an_integer(h)) {
101 msg = _("Range end is not integer.\n");
105 if (!is_an_integer(p)) {
106 msg = _("Range start is not an integer.\n");
112 msg = _("Range end not bigger than start.\n");
117 if (!is_an_integer(p)) {
118 msg = _("Input value is not an integer.\n");
123 if (beg <= 0 || end <= 0) {
124 msg = _("Values must be be greater than zero.\n");
127 if (end >= num_slots) {
128 msg = _("Slot too large.\n");
131 for (i=beg; i<=end; i++) {
132 slot_list[i] = 1; /* Turn on specified range */
136 /* Turn everything on */
137 for (i=0; i<num_slots; i++) {
142 printf("Slots turned on:\n");
143 for (i=1; i<num_slots; i++) {
156 * Update Slots corresponding to Volumes in autochanger
158 int update_slots(UAContext *ua)
161 vol_list_t *vl, *vol_list = NULL;
169 store = get_storage_resource(ua, 1);
173 ua->jcr->store = store;
175 scan = find_arg(ua, _("scan")) >= 0;
177 slot_list = (char *)malloc(MAX_SLOTS);
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 /* Check if user wants us to look at this slot */
193 if (!slot_list[vl->Slot]) {
196 /* If scanning, we read the label rather than the barcode */
202 vl->VolName = get_volume_name_from_SD(ua, vl->Slot);
207 memset(&mr, 0, sizeof(mr));
208 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
210 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
211 if (mr.Slot != vl->Slot || !mr.InChanger) {
214 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
215 bsendmsg(ua, _("%s\n"), db_strerror(ua->db));
218 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
219 mr.VolumeName, mr.Slot);
222 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
228 bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
237 free_vol_list(vol_list);
246 * Common routine for both label and relabel
248 static int do_label(UAContext *ua, char *cmd, int relabel)
252 char dev_name[MAX_NAME_LENGTH];
255 bool print_reminder = true;
258 bool media_record_exists = false;
259 static char *barcode_keyword[] = {
265 memset(&pr, 0, sizeof(pr));
269 store = get_storage_resource(ua, 1);
273 ua->jcr->store = store;
275 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
276 label_from_barcodes(ua);
280 /* If relabel get name of Volume to relabel */
282 /* Check for oldvolume=name */
283 i = find_arg_with_value(ua, "oldvolume");
285 memset(&omr, 0, sizeof(omr));
286 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
287 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
290 bsendmsg(ua, "%s", db_strerror(ua->db));
292 /* No keyword or Vol not found, ask user to select */
293 if (!select_media_dbr(ua, &omr)) {
297 /* Require Volume to be Purged or Recycled */
299 if (strcmp(omr.VolStatus, "Purged") != 0 || strcmp(omr.VolStatus, "Recycle") != 0) {
300 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
301 omr.VolumeName, omr.VolStatus);
306 /* Check for volume=NewVolume */
307 i = find_arg_with_value(ua, "volume");
309 pm_strcpy(&ua->cmd, ua->argv[i]);
313 /* Get a new Volume name */
315 media_record_exists = false;
316 if (!get_cmd(ua, _("Enter new Volume name: "))) {
320 if (!is_volume_name_legal(ua, ua->cmd)) {
324 memset(&mr, 0, sizeof(mr));
325 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
326 /* If VolBytes are zero the Volume is not labeled */
327 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
328 if (mr.VolBytes != 0) {
329 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
333 media_record_exists = true;
338 /* If autochanger, request slot */
339 if (store->autochanger) {
340 i = find_arg_with_value(ua, "slot");
342 mr.Slot = atoi(ua->argv[i]);
343 } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
346 mr.Slot = ua->pint32_val;
348 mr.InChanger = 1; /* assumed if we are labeling it */
351 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
353 /* Must select Pool if not already done */
354 if (pr.PoolId == 0) {
355 memset(&pr, 0, sizeof(pr));
356 if (!select_pool_dbr(ua, &pr)) {
362 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
365 sd = ua->jcr->store_bsock;
367 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
368 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
369 omr.VolumeName, db_strerror(ua->db));
371 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
376 bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
377 bsendmsg(ua, _("Requesting to mount %s ...\n"), dev_name);
378 bash_spaces(dev_name);
379 bnet_fsend(sd, "mount %s", dev_name);
380 unbash_spaces(dev_name);
381 while (bnet_recv(sd) >= 0) {
382 bsendmsg(ua, "%s", sd->msg);
384 * 3001 OK mount. Device=xxx or
385 * 3001 Mounted Volume vvvv
386 * 3906 is cannot mount non-tape
387 * So for those, no need to print a reminder
389 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
390 strncmp(sd->msg, "3906 ", 5) == 0) {
391 print_reminder = false;
396 if (print_reminder) {
397 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
405 * Request SD to send us the slot:barcodes, then wiffle
406 * through them all labeling them.
408 static void label_from_barcodes(UAContext *ua)
410 STORE *store = ua->jcr->store;
413 vol_list_t *vl, *vol_list = NULL;
414 bool media_record_exists;
417 slot_list = (char *)malloc(MAX_SLOTS);
418 if (!get_user_slot_list(ua, slot_list, MAX_SLOTS)) {
423 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
426 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
430 /* Display list of Volumes and ask if he really wants to proceed */
431 bsendmsg(ua, _("The following Volumes will be labeled:\n"
433 "==============\n"));
434 for (vl=vol_list; vl; vl=vl->next) {
435 if (!vl->VolName || !slot_list[vl->Slot]) {
438 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
440 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
441 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
445 memset(&pr, 0, sizeof(pr));
446 if (!select_pool_dbr(ua, &pr)) {
449 memset(&omr, 0, sizeof(omr));
451 /* Fire off the label requests */
452 for (vl=vol_list; vl; vl=vl->next) {
453 if (!vl->VolName || !slot_list[vl->Slot]) {
456 memset(&mr, 0, sizeof(mr));
457 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
458 media_record_exists = false;
459 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
460 if (mr.VolBytes != 0) {
461 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
462 vl->Slot, mr.VolumeName);
465 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
466 bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
471 media_record_exists = true;
475 * Deal with creating cleaning tape here. Normal tapes created in
476 * send_label_request() below
478 if (is_cleaning_tape(ua, &mr, &pr)) {
479 if (media_record_exists) { /* we update it */
481 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
482 bsendmsg(ua, "%s", db_strerror(ua->db));
484 } else { /* create the media record */
485 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
486 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
487 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
490 bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
493 continue; /* done, go handle next volume */
495 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
498 if (!send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists)) {
505 free_vol_list(vol_list);
512 * Check if the Volume name has legal characters
513 * If ua is non-NULL send the message
515 int is_volume_name_legal(UAContext *ua, char *name)
519 char *accept = ":.-_";
521 /* Restrict the characters permitted in the Volume name */
522 for (p=name; *p; p++) {
523 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
527 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
532 if (len >= MAX_NAME_LENGTH) {
534 bsendmsg(ua, _("Volume name too long.\n"));
540 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
547 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
548 POOL_DBR *pr, int relabel, bool media_record_exists)
551 char dev_name[MAX_NAME_LENGTH];
554 if (!(sd=open_sd_bsock(ua))) {
557 bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
558 bash_spaces(dev_name);
559 bash_spaces(mr->VolumeName);
560 bash_spaces(mr->MediaType);
561 bash_spaces(pr->Name);
563 bash_spaces(omr->VolumeName);
564 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d",
565 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
566 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
567 omr->VolumeName, mr->VolumeName);
569 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
570 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
571 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
572 mr->VolumeName, mr->Slot);
573 Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n",
574 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
577 while (bnet_recv(sd) >= 0) {
578 bsendmsg(ua, "%s", sd->msg);
579 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
583 unbash_spaces(mr->VolumeName);
584 unbash_spaces(mr->MediaType);
585 unbash_spaces(pr->Name);
586 mr->LabelDate = time(NULL);
588 if (media_record_exists) { /* we update it */
591 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
592 bsendmsg(ua, "%s", db_strerror(ua->db));
595 } else { /* create the media record */
596 set_pool_dbr_defaults_in_media_dbr(mr, pr);
597 mr->VolBytes = 1; /* flag indicating Volume labeled */
599 if (db_create_media_record(ua->jcr, ua->db, mr)) {
600 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
601 mr->VolumeName, mr->Slot);
603 bsendmsg(ua, "%s", db_strerror(ua->db));
608 bsendmsg(ua, _("Label command failed.\n"));
613 static BSOCK *open_sd_bsock(UAContext *ua)
615 STORE *store = ua->jcr->store;
617 if (!ua->jcr->store_bsock) {
618 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
619 store->hdr.name, store->address, store->SDport);
620 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
621 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
625 return ua->jcr->store_bsock;
628 static void close_sd_bsock(UAContext *ua)
630 if (ua->jcr->store_bsock) {
631 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
632 bnet_close(ua->jcr->store_bsock);
633 ua->jcr->store_bsock = NULL;
637 static char *get_volume_name_from_SD(UAContext *ua, int Slot)
639 STORE *store = ua->jcr->store;
641 char dev_name[MAX_NAME_LENGTH];
642 char *VolName = NULL;
645 if (!(sd=open_sd_bsock(ua))) {
648 bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
649 bash_spaces(dev_name);
650 /* Ask for autochanger list of volumes */
651 bnet_fsend(sd, _("readlabel %s Slot=%d\n"), dev_name, Slot);
652 Dmsg1(100, "Sent: %s", sd->msg);
654 /* Get Volume name in this Slot */
655 while (bnet_recv(sd) >= 0) {
656 bsendmsg(ua, "%s", sd->msg);
657 if (strncmp(sd->msg, "3001 Volume=", 12) == 0) {
658 VolName = (char *)malloc(sd->msglen);
659 if (sscanf(sd->msg, "3001 Volume=%s Slot=%d", VolName, &rtn_slot) == 2) {
666 Dmsg1(200, "get_vol_name=%s\n", NPRT(VolName));
671 * We get the slot list from the Storage daemon.
672 * If scan is set, we return all slots found,
673 * otherwise, we return only slots with valid barcodes (Volume names)
675 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
677 STORE *store = ua->jcr->store;
678 char dev_name[MAX_NAME_LENGTH];
681 vol_list_t *vol_list = NULL;
684 if (!(sd=open_sd_bsock(ua))) {
688 bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
689 bash_spaces(dev_name);
690 /* Ask for autochanger list of volumes */
691 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
693 /* Read and organize list of Volumes */
694 while (bnet_recv(sd) >= 0) {
697 strip_trailing_junk(sd->msg);
699 /* Check for returned SD messages */
700 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
701 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
703 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
707 /* Validate Slot: if scanning, otherwise Slot:Barcode */
708 p = strchr(sd->msg, ':');
710 /* Scanning -- require only valid slot */
711 Slot = atoi(sd->msg);
715 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
720 if (p && strlen(p) > 1) {
722 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
725 bsendmsg(ua, _("Invalid Slot number: %s\n"), sd->msg);
731 if (!is_volume_name_legal(ua, p)) {
734 bsendmsg(ua, _("Invalid Volume name: %s\n"), sd->msg);
739 /* Add Slot and VolumeName to list */
740 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
743 vl->VolName = bstrdup(p);
751 /* Add new entry to end of list */
752 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
765 static void free_vol_list(vol_list_t *vol_list)
769 for (vl=vol_list; vl; ) {
782 * Check if this is a cleaning tape by comparing the Volume name
783 * with the Cleaning Prefix. If they match, this is a cleaning
786 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
788 if (!ua->jcr->pool) {
789 /* Find Pool resource */
790 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
791 if (!ua->jcr->pool) {
792 bsendmsg(ua, _("Pool %s resource not found!\n"), pr->Name);
796 if (ua->jcr->pool->cleaning_prefix == NULL) {
799 Dmsg4(200, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
800 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
801 strlen(ua->jcr->pool->cleaning_prefix),
802 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
803 strlen(ua->jcr->pool->cleaning_prefix)));
804 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
805 strlen(ua->jcr->pool->cleaning_prefix)) == 0;