3 * Bacula Tape manipulation program
5 * Has various tape manipulation commands -- mostly for
6 * use in determining how tapes really work.
8 * Kern Sibbald, April MM
10 * Note, this program reads stored.conf, and will only
11 * talk to devices that are configured.
17 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
19 This program is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License as
21 published by the Free Software Foundation; either version 2 of
22 the License, or (at your option) any later version.
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received a copy of the GNU General Public
30 License along with this program; if not, write to the Free
31 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
40 /* External subroutines */
41 extern void free_config_resources();
43 /* Exported variables */
46 int bsize = TAPE_BSIZE;
50 DEVRES *device = NULL;
53 /* Forward referenced subroutines */
54 static void do_tape_cmds();
55 static void helpcmd();
56 static void scancmd();
57 static void rewindcmd();
58 static void clearcmd();
61 static void fillcmd();
62 static void unfillcmd();
63 static int flush_block(DEV_BLOCK *block, int dump);
64 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
65 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
68 /* Static variables */
69 #define CONFIG_FILE "bacula-sd.conf"
72 static BSR *bsr = NULL;
73 static char cmd[1000];
74 static int signals = TRUE;
77 static uint64_t vol_size;
78 static uint64_t VolBytes;
81 static long file_index;
82 static int verbose = 0;
83 static int end_of_tape = 0;
84 static uint32_t LastBlock = 0;
85 static uint32_t eot_block;
86 static uint32_t eot_block_len;
87 static uint32_t eot_FileIndex;
88 static int dumped = 0;
90 static char *VolumeName = NULL;
92 static JCR *jcr = NULL;
96 static void terminate_btape(int sig);
97 int get_cmd(char *prompt);
100 int write_dev(DEVICE *dev, char *buf, size_t len)
102 Emsg0(M_ABORT, 0, "write_dev not implemented.\n");
106 int read_dev(DEVICE *dev, char *buf, size_t len)
108 Emsg0(M_ABORT, 0, "read_dev not implemented.\n");
113 /*********************************************************************
115 * Main Bacula Pool Creation Program
118 int main(int argc, char *argv[])
123 if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
124 Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
125 TAPE_BSIZE, DEV_BSIZE);
127 if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
128 Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
131 printf("Tape block granularity is %d bytes.\n", TAPE_BSIZE);
133 working_directory = "/tmp";
134 my_name_is(argc, argv, "btape");
135 init_msg(NULL, NULL);
137 while ((ch = getopt(argc, argv, "b:c:d:sv?")) != -1) {
139 case 'b': /* bootstrap file */
140 bsr = parse_bsr(NULL, optarg);
144 case 'c': /* specify config file */
145 if (configfile != NULL) {
148 configfile = bstrdup(optarg);
151 case 'd': /* set debug level */
152 debug_level = atoi(optarg);
153 if (debug_level <= 0) {
179 init_signals(terminate_btape);
182 if (configfile == NULL) {
183 configfile = bstrdup(CONFIG_FILE);
186 daemon_start_time = time(NULL);
188 parse_config(configfile);
191 /* See if we can open a device */
193 Pmsg0(000, "No archive name specified.\n");
196 } else if (argc != 1) {
197 Pmsg0(000, "Improper number of arguments specified.\n");
202 jcr = setup_jcr("btape", argv[0], bsr);
203 dev = setup_to_access_device(jcr, 0); /* acquire for write */
208 Dmsg0(200, "Do tape commands\n");
215 static void terminate_btape(int stat)
218 sm_check(__FILE__, __LINE__, False);
222 free_config_resources();
228 if (debug_level > 10)
229 print_memory_pool_stats();
239 close_memory_pool(); /* free memory in pool */
251 * Write a label to the tape
253 static void labelcmd()
259 for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
260 if (strcmp(device->device_name, dev->dev_name) == 0) {
261 jcr->device = device; /* Arggg a bit of duplication here */
263 dev->device = device;
270 Pmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
275 strcpy(cmd, VolumeName);
277 if (!get_cmd("Enter Volume Name: ")) {
282 if (!(dev->state & ST_OPENED)) {
283 if (!open_device(dev)) {
284 Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
287 write_volume_label_to_dev(jcr, device, cmd, "Default");
291 * Read the tape label
293 static void readlabelcmd()
295 int save_debug_level = debug_level;
299 block = new_block(dev);
300 stat = read_dev_volume_label(jcr, dev, block);
303 Pmsg0(0, "Volume has no label.\n");
306 Pmsg0(0, "Volume label read correctly.\n");
309 Pmsg1(0, "I/O error on device: ERR=%s", strerror_dev(dev));
312 Pmsg0(0, "Volume name error\n");
314 case VOL_CREATE_ERROR:
315 Pmsg1(0, "Error creating label. ERR=%s", strerror_dev(dev));
317 case VOL_VERSION_ERROR:
318 Pmsg0(0, "Volume version error.\n");
320 case VOL_LABEL_ERROR:
321 Pmsg0(0, "Bad Volume label type.\n");
324 Pmsg0(0, "Unknown error.\n");
329 dump_volume_label(dev);
330 debug_level = save_debug_level;
336 * Load the tape should have prevously been taken
337 * off line, otherwise this command is not necessary.
339 static void loadcmd()
342 if (!load_dev(dev)) {
343 Pmsg1(0, "Bad status from load. ERR=%s\n", strerror_dev(dev));
345 Pmsg1(0, "Loaded %s\n", dev_name(dev));
351 static void rewindcmd()
353 if (!rewind_dev(dev)) {
354 Pmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
355 clrerror_dev(dev, -1);
357 Pmsg1(0, "Rewound %s\n", dev_name(dev));
362 * Clear any tape error
364 static void clearcmd()
366 clrerror_dev(dev, -1);
370 * Write and end of file on the tape
372 static void weofcmd()
376 if ((stat = weof_dev(dev, 1)) < 0) {
377 Pmsg2(0, "Bad status from weof %d. ERR=%s\n", stat, strerror_dev(dev));
380 Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
385 /* Go to the end of the medium -- raw command
386 * The idea was orginally that the end of the Bacula
387 * medium would be flagged differently. This is not
388 * currently the case. So, this is identical to the
394 Pmsg1(0, "Bad status from eod. ERR=%s\n", strerror_dev(dev));
397 Pmsg0(0, "Moved to end of media\n");
402 * Go to the end of the media (either hardware determined
403 * or defined by two eofs.
417 if ((stat=bsf_dev(dev, 1)) < 0) {
418 Pmsg1(0, "Bad status from bsf. ERR=%s\n", strerror(errno));
420 Pmsg0(0, "Back spaced one file.\n");
431 if ((stat=bsr_dev(dev, 1)) < 0) {
432 Pmsg1(0, "Bad status from bsr. ERR=%s\n", strerror(errno));
434 Pmsg0(0, "Back spaced one record.\n");
439 * List device capabilities as defined in the
444 Pmsg0(0, "Device capabilities: ");
445 printf("%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
446 printf("%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
447 printf("%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
448 printf("%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
449 printf("%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
450 printf("%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
451 printf("%sREM ", dev->capabilities & CAP_REM ? "" : "!");
452 printf("%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
453 printf("%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
454 printf("%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
455 printf("%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
456 printf("%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
461 * Test writting larger and larger records.
462 * This is a torture test for records.
464 static void rectestcmd()
470 Pmsg0(0, "Test writting larger and larger records.\n\
471 This is a torture test for records.\nI am going to write\n\
472 larger and larger records. It will stop when the record size\n\
473 plus the header exceeds the block size (by default about 64K\n");
476 get_cmd("Do you want to continue? (y/n): ");
478 Pmsg0(000, "Command aborted.\n");
482 sm_check(__FILE__, __LINE__, False);
483 block = new_block(dev);
486 for (i=1; i<500000; i++) {
487 rec->data = check_pool_memory_size(rec->data, i);
488 memset(rec->data, i & 0xFF, i);
490 sm_check(__FILE__, __LINE__, False);
491 if (write_record_to_block(block, rec)) {
494 Pmsg2(0, "Block %d i=%d\n", blkno, i);
498 sm_check(__FILE__, __LINE__, False);
502 sm_check(__FILE__, __LINE__, False);
506 * This is a general test of Bacula's functions
507 * needed to read and write the tape.
509 static void testcmd()
511 Pmsg0(0, "Append files test.\n\n\
512 I'm going to write one record in file 0,\n\
513 two records in file 1,\n\
514 and three records in file 2\n\n");
517 weofcmd(); /* end file 0 */
520 weofcmd(); /* end file 1 */
524 weofcmd(); /* end file 2 */
527 Pmsg0(0, "Now moving to end of media.\n");
529 Pmsg2(0, "End Append files test.\n\
530 We should be in file 3. I am at file %d. This is %s\n\n",
531 dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
533 Pmsg0(0, "\nNow I am going to attempt to append to the tape.\n");
539 Pmsg0(0, "End Append to the tape test.\n\
540 The above scan should have four files of:\n\
541 One record, two records, three records, and one record respectively.\n\n");
544 Pmsg0(0, "Append block test.\n\
545 I'm going to write a block, an EOF, rewind, go to EOM,\n\
546 then backspace over the EOF and attempt to append a second\n\
547 block in the first file.\n\n");
554 Pmsg2(0, "We should be at file 1. I am at EOM File=%d. This is %s\n",
555 dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
556 Pmsg0(0, "Doing backspace file.\n");
558 Pmsg0(0, "Write second block, hoping to append to first file.\n");
562 Pmsg0(0, "Done writing, scanning results\n");
564 Pmsg0(0, "The above should have one file of two blocks.\n");
572 if ((stat=fsf_dev(dev, 1)) < 0) {
573 Pmsg2(0, "Bad status from fsf %d. ERR=%s\n", stat, strerror_dev(dev));
576 Pmsg0(0, "Forward spaced one file.\n");
583 if ((stat=fsr_dev(dev, 1)) < 0) {
584 Pmsg2(0, "Bad status from fsr %d. ERR=%s\n", stat, strerror_dev(dev));
587 Pmsg0(0, "Forward spaced one record.\n");
595 if (!read_dev(dev, buf, 512*126)) {
596 Pmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
599 Pmsg1(10, "Read %d bytes\n", stat);
601 printf("Rdcmd no longer implemented.\n");
612 sm_check(__FILE__, __LINE__, False);
613 block = new_block(dev);
615 dump_block(block, "test");
617 i = block->buf_len - 100;
619 rec->data = check_pool_memory_size(rec->data, i);
620 memset(rec->data, i & 0xFF, i);
622 sm_check(__FILE__, __LINE__, False);
623 if (!write_record_to_block(block, rec)) {
624 Pmsg0(0, "Error writing record to block.\n");
627 if (!write_block_to_dev(dev, block)) {
628 Pmsg0(0, "Error writing block to device.\n");
631 Pmsg1(0, "Wrote one record of %d bytes.\n",
632 ((i+TAPE_BSIZE-1)/TAPE_BSIZE) * TAPE_BSIZE);
634 Pmsg0(0, "Wrote block to device.\n");
637 sm_check(__FILE__, __LINE__, False);
640 sm_check(__FILE__, __LINE__, False);
645 * Scan tape by reading block by block. Report what is
648 static void scancmd()
651 int blocks, tot_blocks, tot_files;
656 blocks = block_size = tot_blocks = 0;
658 if (dev->state & ST_EOT) {
659 Pmsg0(0, "End of tape\n");
663 tot_files = dev->file;
665 if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) {
666 clrerror_dev(dev, -1);
667 Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
668 dev->dev_name, strerror(dev->dev_errno));
669 Pmsg2(0, "Bad status from read %d. ERR=%s\n", stat, strerror_dev(dev));
671 printf("%d block%s of %d bytes in file %d\n",
672 blocks, blocks>1?"s":"", block_size, dev->file);
675 Dmsg1(200, "read status = %d\n", stat);
677 if (stat != block_size) {
680 printf("%d block%s of %d bytes in file %d\n",
681 blocks, blocks>1?"s":"", block_size, dev->file);
686 if (stat == 0) { /* EOF */
688 printf("End of File mark.\n");
689 /* Two reads of zero means end of tape */
690 if (dev->state & ST_EOF)
691 dev->state |= ST_EOT;
693 dev->state |= ST_EOF;
696 if (dev->state & ST_EOT) {
697 printf("End of tape\n");
700 } else { /* Got data */
701 dev->state &= ~ST_EOF;
708 tot_files = dev->file - tot_files;
709 printf("Total files=%d, blocks=%d, bytes = %" lld "\n", tot_files, tot_blocks, bytes);
712 static void statcmd()
720 if (!status_dev(dev, &status)) {
721 Pmsg2(0, "Bad status from status %d. ERR=%s\n", stat, strerror_dev(dev));
724 dump_volume_label(dev);
731 * First we label the tape, then we fill
732 * it with data get a new tape and write a few blocks.
734 static void fillcmd()
745 This command simulates Bacula writing to a tape.\n\
746 It command requires two blank tapes, which it\n\
747 will label and write. It will print a status approximately\n\
748 every 322 MB, and write an EOF every 3.2 GB. When the first tape\n\
749 fills, it will ask for a second, and after writing a few \n\
750 blocks, it will stop. Then it will begin re-reading the\n\
751 This may take a long time. I.e. hours! ...\n\n");
753 get_cmd("Insert a blank tape then answer. Do you wish to continue? (y/n): ");
755 Pmsg0(000, "Command aborted.\n");
759 VolumeName = "TestVolume1";
764 Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
766 block = new_block(dev);
769 * Acquire output device for writing. Note, after acquiring a
770 * device, we MUST release it, which is done at the end of this
773 Dmsg0(100, "just before acquire_device\n");
774 if (!acquire_device_for_append(jcr, dev, block)) {
775 jcr->JobStatus = JS_Cancelled;
780 Dmsg0(100, "Just after acquire_device_for_append\n");
782 * Write Begin Session Record
784 if (!write_session_label(jcr, block, SOS_LABEL)) {
785 jcr->JobStatus = JS_Cancelled;
786 Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
791 memset(&rec, 0, sizeof(rec));
792 rec.data = get_memory(100000); /* max record size */
794 * Fill write buffer with random data
796 #define REC_SIZE 32768
798 for (int i=0; i < REC_SIZE; ) {
799 makeSessionKey(p, NULL, 0);
803 rec.data_len = REC_SIZE;
806 * Get Data from File daemon, write to device
808 jcr->VolFirstFile = 0;
809 time(&jcr->run_time); /* start counting time for rates */
810 for (file_index = 0; ok && !job_cancelled(jcr); ) {
812 rec.VolSessionId = jcr->VolSessionId;
813 rec.VolSessionTime = jcr->VolSessionTime;
814 rec.FileIndex = ++file_index;
815 rec.Stream = STREAM_FILE_DATA;
816 /* Write file_index at beginning of buffer */
817 lp = (uint64_t *)rec.data;
818 *lp = (uint64_t)file_index;
820 Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
821 rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex),
824 if (!write_record_to_block(block, &rec)) {
825 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
828 /* Write block to tape */
829 if (!flush_block(block, 1)) {
833 /* Every 5000 blocks (approx 322MB) report where we are.
835 if ((block->BlockNumber % 5000) == 0) {
837 now -= jcr->run_time;
841 kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
842 Pmsg3(000, "Wrote block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
843 edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
845 /* Every 50000 blocks (approx 3.2MB) write an eof.
847 if ((block->BlockNumber % 50000) == 0) {
848 Pmsg0(000, "Flush block, write EOF\n");
849 flush_block(block, 0);
851 /* The weof resets the block number */
854 if (block->BlockNumber > 10 && stop) { /* get out */
859 Pmsg0(000, "Not OK\n");
862 jcr->JobBytes += rec.data_len; /* increment bytes this job */
863 Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
864 FI_to_ascii(rec.FileIndex), rec.VolSessionId,
865 stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len);
867 Dmsg0(000, "Write_end_session_label()\n");
868 /* Create Job status for end of session label */
869 if (!job_cancelled(jcr) && ok) {
870 jcr->JobStatus = JS_Terminated;
872 jcr->JobStatus = JS_ErrorTerminated;
874 if (!write_session_label(jcr, block, EOS_LABEL)) {
875 Pmsg1(000, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev));
878 /* Write out final block of this session */
879 if (!write_block_to_device(jcr, dev, block)) {
880 Pmsg0(000, "Set ok=FALSE after write_block_to_device.\n");
884 /* Release the device */
885 if (!release_device(jcr, dev)) {
886 Pmsg0(000, "Error in release_device\n");
891 free_memory(rec.data);
892 Pmsg0(000, "Done with fill command. Now beginning re-read of tapes...\n");
898 * Read two tapes written by the "fill" command and ensure
899 * that the data is valid.
901 static void unfillcmd()
908 block = new_block(dev);
910 dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */
911 dev->capabilities &= ~CAP_LABEL; /* don't label anything here */
914 get_cmd("Mount first of two tapes. Press enter when ready: ");
916 pm_strcpy(&jcr->VolumeName, "TestVolume1");
918 dev->state &= ~ST_READ;
919 if (!acquire_device_for_read(jcr, dev, block)) {
920 Pmsg0(000, dev->errmsg);
924 time(&jcr->run_time); /* start counting time for rates */
927 read_records(jcr, dev, record_cb, my_mount_next_read_volume);
930 Pmsg0(000, "Done with unfillcmd.\n");
935 * We are called here from "unfill" for each record on the
938 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
942 if (stop > 1) { /* on second tape */
943 Pmsg4(000, "Blk: FileIndex=%d: block=%u size=%d vol=%s\n",
944 rec->FileIndex, block->BlockNumber, block->block_len, dev->VolHdr.VolName);
945 Pmsg6(000, " Rec: VId=%d VT=%d FI=%s Strm=%s len=%d state=%x\n",
946 rec->VolSessionId, rec->VolSessionTime,
947 FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream, rec->FileIndex),
948 rec->data_len, rec->state);
952 dump_block(block, "Block not written to previous tape");
955 if (rec->FileIndex < 0) {
957 dump_label_record(dev, rec, 1);
959 switch (rec->FileIndex) {
961 Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n");
964 unser_volume_label(dev, rec);
965 Pmsg3(000, "VOL_LABEL: block=%u size=%d vol=%s\n", block->BlockNumber,
966 block->block_len, dev->VolHdr.VolName);
970 unser_session_label(&label, rec);
971 Pmsg1(000, "SOS_LABEL: JobId=%u\n", label.JobId);
974 unser_session_label(&label, rec);
975 Pmsg2(000, "EOS_LABEL: block=%u JobId=%u\n", block->BlockNumber,
979 Pmsg0(000, "EOM_LABEL:\n");
981 case EOT_LABEL: /* end of all tapes */
984 if (LastBlock != block->BlockNumber) {
985 VolBytes += block->block_len;
987 LastBlock = block->BlockNumber;
989 now -= jcr->run_time;
993 kbs = (double)VolBytes / (1000 * now);
994 Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
995 edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
997 Pmsg0(000, "End of all tapes.\n");
1005 if (LastBlock != block->BlockNumber) {
1006 VolBytes += block->block_len;
1008 if ((block->BlockNumber != LastBlock) && (block->BlockNumber % 50000) == 0) {
1011 now -= jcr->run_time;
1015 kbs = (double)VolBytes / (1000 * now);
1016 Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1017 edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1019 LastBlock = block->BlockNumber;
1021 Pmsg1(000, "End of all blocks. Block=%u\n", block->BlockNumber);
1028 * Write current block to tape regardless of whether or
1029 * not it is full. If the tape fills, attempt to
1030 * acquire another tape.
1032 static int flush_block(DEV_BLOCK *block, int dump)
1036 if (!write_block_to_dev(dev, block)) {
1037 Pmsg0(000, strerror_dev(dev));
1038 Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n",
1039 (unsigned)file_index, block->BlockNumber, block->block_len);
1041 dump_block(block, "Block not written");
1044 eot_block = block->BlockNumber;
1045 eot_block_len = block->block_len;
1046 eot_FileIndex = file_index;
1049 now -= jcr->run_time;
1053 kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
1054 vol_size = dev->VolCatInfo.VolCatBytes;
1055 Pmsg2(000, "End of tape. VolumeCapacity=%s. Write rate = %.1f KB/s\n",
1056 edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
1057 if (!fixup_device_block_write_error(jcr, dev, block)) {
1058 Pmsg1(000, _("Cannot fixup device error. %s\n"), strerror_dev(dev));
1065 return 1; /* write one more block to next tape then stop */
1072 struct cmdstruct { char *key; void (*func)(); char *help; };
1073 static struct cmdstruct commands[] = {
1074 {"bsf", bsfcmd, "backspace file"},
1075 {"bsr", bsrcmd, "backspace record"},
1076 {"cap", capcmd, "list device capabilities"},
1077 {"clear", clearcmd, "clear tape errors"},
1078 {"eod", eodcmd, "go to end of Bacula data for append"},
1079 {"test", testcmd, "General test Bacula tape functions"},
1080 {"eom", eomcmd, "go to the physical end of medium"},
1081 {"fill", fillcmd, "fill tape, write onto second volume"},
1082 {"unfill", unfillcmd, "read filled tape"},
1083 {"fsf", fsfcmd, "forward space a file"},
1084 {"fsr", fsrcmd, "forward space a record"},
1085 {"help", helpcmd, "print this command"},
1086 {"label", labelcmd, "write a Bacula label to the tape"},
1087 {"load", loadcmd, "load a tape"},
1088 {"quit", quitcmd, "quit btape"},
1089 {"rd", rdcmd, "read tape"},
1090 {"readlabel", readlabelcmd, "read and print the Bacula tape label"},
1091 {"rectest", rectestcmd, "test record handling functions"},
1092 {"rewind", rewindcmd, "rewind the tape"},
1093 {"scan", scancmd, "read tape block by block to EOT and report"},
1094 {"status", statcmd, "print tape status"},
1095 {"weof", weofcmd, "write an EOF on the tape"},
1096 {"wr", wrcmd, "write a single record of 2048 bytes"},
1098 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
1106 while (get_cmd("*")) {
1107 sm_check(__FILE__, __LINE__, False);
1109 for (i=0; i<comsize; i++) /* search for command */
1110 if (fstrsch(cmd, commands[i].key)) {
1111 (*commands[i].func)(); /* go execute command */
1116 Pmsg1(0, "%s is an illegal command\n", cmd);
1122 static void helpcmd()
1126 printf(" Command Description\n ======= ===========\n");
1127 for (i=0; i<comsize; i++)
1128 printf(" %-10s %s\n", commands[i].key, commands[i].help);
1135 "\nVersion: " VERSION " (" DATE ")\n\n"
1136 "Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
1137 " -c <file> set configuration file to file\n"
1138 " -dnn set debug level to nn\n"
1139 " -s turn off signals\n"
1140 " -t open the default tape device\n"
1141 " -? print this message.\n"
1147 * Get next input command from terminal. This
1148 * routine is REALLY primitive, and should be enhanced
1149 * to have correct backspacing, etc.
1152 get_cmd(char *prompt)
1156 fprintf(stdout, prompt);
1158 /* We really should turn off echoing and pretty this
1162 while ((ch = fgetc(stdin)) != EOF) {
1164 strip_trailing_junk(cmd);
1166 } else if (ch == 4 || ch == 0xd3 || ch == 0x8) {
1179 /* Dummies to replace askdir.c */
1180 int dir_get_volume_info(JCR *jcr, int writing) { return 1;}
1181 int dir_find_next_appendable_volume(JCR *jcr) { return 1;}
1182 int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
1183 int dir_create_jobmedia_record(JCR *jcr) { return 1; }
1184 int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
1185 int dir_send_job_status(JCR *jcr) {return 1;}
1188 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
1190 Pmsg0(000, dev->errmsg); /* print reason */
1191 fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
1192 jcr->VolumeName, dev_name(dev));
1197 int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
1199 fprintf(stderr, "Mount next Volume on device %s and press return when ready: ",
1202 VolumeName = "TestVolume2";
1208 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
1212 Pmsg1(000, "End of Volume \"%s\"\n", jcr->VolumeName);
1214 if (LastBlock != block->BlockNumber) {
1215 VolBytes += block->block_len;
1217 LastBlock = block->BlockNumber;
1219 now -= jcr->run_time;
1223 kbs = (double)VolBytes / (1000 * now);
1224 Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1225 edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1227 if (strcmp(jcr->VolumeName, "TestVolume2") == 0) {
1231 pm_strcpy(&jcr->VolumeName, "TestVolume2");
1233 dev->state &= ~ST_READ;
1234 if (!acquire_device_for_read(jcr, dev, block)) {
1235 Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName);
1238 return 1; /* next volume mounted */