X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=bacula%2Fsrc%2Fstored%2Fbtape.c;h=f0649111835a67f081249b0ab163b32519978599;hb=908d0c5a7c352c4473409fd01cab16d968c41b43;hp=fd9338b9ad2f2a03f896855c48675f1b8acae367;hpb=46bce52552eae85045a274ed9a223149b6c1b9f5;p=bacula%2Fbacula diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index fd9338b9ad..f064911183 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * * Bacula Tape manipulation program @@ -13,26 +40,17 @@ * Version $Id$ * */ -/* - Copyright (C) 2000-2006 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as amended with additional clauses defined in the - file LICENSE in the main source directory. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - the file LICENSE for additional details. - - */ #include "bacula.h" #include "stored.h" +#ifdef USE_VTAPE +#include "vtape.h" +#endif + /* Dummy functions */ int generate_daemon_event(JCR *jcr, const char *event) { return 1; } +extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code); /* External subroutines */ extern void free_config_resources(); @@ -66,6 +84,7 @@ static void rewindcmd(); static void clearcmd(); static void wrcmd(); static void rrcmd(); +static void rbcmd(); static void eodcmd(); static void fillcmd(); static void qfillcmd(); @@ -78,13 +97,13 @@ static bool my_mount_next_read_volume(DCR *dcr); static void scan_blocks(); static void set_volume_name(const char *VolName, int volnum); static void rawfill_cmd(); -static void bfill_cmd(); static bool open_the_device(); static void autochangercmd(); static void do_unfill(); /* Static variables */ +static CONFIG *config; #define CONFIG_FILE "bacula-sd.conf" char *configfile = NULL; @@ -96,6 +115,7 @@ static char *argv[MAX_CMD_ARGS]; static int argc; static int quickie_count = 0; +static uint64_t write_count = 0; static BSR *bsr = NULL; static int signals = TRUE; static bool ok; @@ -151,6 +171,7 @@ int main(int margc, char *margv[]) setlocale(LC_ALL, ""); bindtextdomain("bacula", LOCALEDIR); textdomain("bacula"); + init_stack_dump(); /* Sanity checks */ if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) { @@ -160,13 +181,13 @@ int main(int margc, char *margv[]) if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) { Emsg1(M_ABORT, 0, _("Tape block size (%d) is not a power of 2\n"), TAPE_BSIZE); } - if (sizeof(off_t) < 8) { - Pmsg1(-1, _("\n\n!!!! Warning large disk addressing disabled. off_t=%d should be 8 or more !!!!!\n\n\n"), - sizeof(off_t)); + if (sizeof(boffset_t) < 8) { + Pmsg1(-1, _("\n\n!!!! Warning large disk addressing disabled. boffset_t=%d should be 8 or more !!!!!\n\n\n"), + sizeof(boffset_t)); } x32 = 123456789; bsnprintf(buf, sizeof(buf), "%u", x32); - i = bsscanf(buf, "%u", &y32); + i = bsscanf(buf, "%lu", &y32); if (i != 1 || x32 != y32) { Pmsg3(-1, _("32 bit printf/scanf problem. i=%d x32=%u y32=%u\n"), i, x32, y32); exit(1); @@ -177,7 +198,8 @@ int main(int margc, char *margv[]) bsnprintf(buf, sizeof(buf), "%" llu, x64); i = bsscanf(buf, "%llu", &y64); if (i != 1 || x64 != y64) { - Pmsg3(-1, _("64 bit printf/scanf problem. i=%d x64=%" llu " y64=%" llu "\n"), i, x64, y64); + Pmsg3(-1, _("64 bit printf/scanf problem. i=%d x64=%" llu " y64=%" llu "\n"), + i, x64, y64); exit(1); } @@ -187,6 +209,8 @@ int main(int margc, char *margv[]) my_name_is(margc, margv, "btape"); init_msg(NULL, NULL); + OSDependentInit(); + while ((ch = getopt(margc, margv, "b:c:d:psv?")) != -1) { switch (ch) { case 'b': /* bootstrap file */ @@ -202,9 +226,13 @@ int main(int margc, char *margv[]) break; case 'd': /* set debug level */ - debug_level = atoi(optarg); - if (debug_level <= 0) { - debug_level = 1; + if (*optarg == 't') { + dbg_timestamp = true; + } else { + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } } break; @@ -243,8 +271,8 @@ int main(int margc, char *margv[]) daemon_start_time = time(NULL); - parse_config(configfile); - + config = new_config_parser(); + parse_sd_config(config, configfile, M_ERROR_TERM); /* See if we can open a device */ if (margc == 0) { @@ -265,6 +293,16 @@ int main(int margc, char *margv[]) if (!dev) { exit(1); } + if (dev->is_dvd()) { + Pmsg0(000, _("btape does not work with DVD storage.\n")); + usage(); + exit(1); + } + if (!dev->is_tape()) { + Pmsg0(000, _("btape only works with tape storage.\n")); + usage(); + exit(1); + } dcr = jcr->dcr; if (!open_the_device()) { goto terminate; @@ -285,7 +323,11 @@ static void terminate_btape(int stat) if (configfile) { free(configfile); } - free_config_resources(); + if (config) { + config->free_resources(); + free(config); + config = NULL; + } if (args) { free_pool_memory(args); args = NULL; @@ -306,6 +348,8 @@ static void terminate_btape(int stat) dev->term(); } + free_volume_list(); + if (debug_level > 10) print_memory_pool_stats(); @@ -325,21 +369,23 @@ static void terminate_btape(int stat) static bool open_the_device() { DEV_BLOCK *block; + bool ok = true; block = new_block(dev); - lock_device(dev); + dev->r_dlock(); Dmsg1(200, "Opening device %s\n", dcr->VolumeName); if (dev->open(dcr, OPEN_READ_WRITE) < 0) { Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg); - unlock_device(dev); - free_block(block); - return false; + ok = false; + goto bail_out; } Pmsg1(000, _("open device %s: OK\n"), dev->print_name()); dev->set_append(); /* put volume in append mode */ - unlock_device(dev); + +bail_out: + dev->dunlock(); free_block(block); - return true; + return ok; } @@ -367,7 +413,8 @@ static void labelcmd() } } dev->rewind(dcr); - write_new_volume_label_to_dev(dcr, cmd, "Default"); + dev->weof(1); + write_new_volume_label_to_dev(dcr, cmd, "Default", false,/*no relabel*/ true /* label dvd now */); Pmsg1(-1, _("Wrote Volume label for volume \"%s\".\n"), cmd); } @@ -482,7 +529,7 @@ static void weofcmd() */ static void eomcmd() { - if (!dev->eod()) { + if (!dev->eod(dcr)) { Pmsg1(0, "%s", dev->bstrerror()); return; } else { @@ -695,14 +742,14 @@ static int re_read_block_test() Pmsg1(0, _("Wrote third record of %d bytes.\n"), rec->data_len); } weofcmd(); - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } if (!dev->bsf(1)) { Pmsg1(0, _("Backspace file failed! ERR=%s\n"), dev->bstrerror()); goto bail_out; } - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { if (!dev->bsf(1)) { Pmsg1(0, _("Backspace file failed! ERR=%s\n"), dev->bstrerror()); goto bail_out; @@ -716,13 +763,13 @@ static int re_read_block_test() Pmsg0(0, _("Backspace record OK.\n")); if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { berrno be; - Pmsg1(0, _("Read block failed! ERR=%s\n"), be.strerror(dev->dev_errno)); + Pmsg1(0, _("Read block failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(block, rec)) { + if (!read_record_from_block(dcr, block, rec)) { berrno be; - Pmsg1(0, _("Read block failed! ERR=%s\n"), be.strerror(dev->dev_errno)); + Pmsg1(0, _("Read block failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); goto bail_out; } for (int i=0; idata_len); weofcmd(); - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } if (!dev->rewind(dcr)) { @@ -828,13 +875,13 @@ read_again: goto read_again; } } - Pmsg2(0, _("Read block %d failed! ERR=%s\n"), i, be.strerror(dev->dev_errno)); + Pmsg2(0, _("Read block %d failed! ERR=%s\n"), i, be.bstrerror(dev->dev_errno)); goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(block, rec)) { + if (!read_record_from_block(dcr, block, rec)) { berrno be; - Pmsg2(0, _("Read record failed. Block %d! ERR=%s\n"), i, be.strerror(dev->dev_errno)); + Pmsg2(0, _("Read record failed. Block %d! ERR=%s\n"), i, be.bstrerror(dev->dev_errno)); goto bail_out; } p = (int *)rec->data; @@ -921,7 +968,7 @@ static int position_test() } Pmsg1(0, _("Wrote 1000 blocks of %d bytes.\n"), rec->data_len); weofcmd(); - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } if (!dev->rewind(dcr)) { @@ -969,7 +1016,7 @@ static int position_test() continue; } Pmsg2(-1, _("Reposition to file:block %d:%d\n"), file, blk); - if (!dev->reposition(file, blk)) { + if (!dev->reposition(dcr, file, blk)) { Pmsg0(0, _("Reposition error.\n")); goto bail_out; } @@ -984,7 +1031,7 @@ read_again: } } Pmsg4(0, _("Read block %d failed! file=%d blk=%d. ERR=%s\n\n"), - recno, file, blk, be.strerror(dev->dev_errno)); + recno, file, blk, be.bstrerror(dev->dev_errno)); Pmsg0(0, _("This may be because the tape drive block size is not\n" " set to variable blocking as normally used by Bacula.\n" " Please see the Tape Testing chapter in the manual and \n" @@ -999,9 +1046,9 @@ read_again: goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(block, rec)) { + if (!read_record_from_block(dcr, block, rec)) { berrno be; - Pmsg1(0, _("Read record failed! ERR=%s\n"), be.strerror(dev->dev_errno)); + Pmsg1(0, _("Read record failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); goto bail_out; } p = (int *)rec->data; @@ -1049,7 +1096,7 @@ static int append_test() wrcmd(); wrcmd(); weofcmd(); /* end file 2 */ - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } dev->close(); /* release device */ @@ -1069,7 +1116,7 @@ static int append_test() Pmsg0(-1, _("\nNow the important part, I am going to attempt to append to the tape.\n\n")); wrcmd(); weofcmd(); - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } rewindcmd(); @@ -1098,7 +1145,7 @@ static int autochanger_test() int sleep_time = 0; Dmsg1(100, "Max changer wait = %d sec\n", timeout); - if (!dev_cap(dev, CAP_AUTOCHANGER)) { + if (!dev->has_cap(CAP_AUTOCHANGER)) { return 1; } if (!(dcr->device && dcr->device->changer_name && dcr->device->changer_command)) { @@ -1135,7 +1182,7 @@ try_again: } else { berrno be; Pmsg1(-1, _("3991 Bad autochanger command: %s\n"), changer); - Pmsg2(-1, _("3991 result=\"%s\": ERR=%s\n"), results, be.strerror(status)); + Pmsg2(-1, _("3991 result=\"%s\": ERR=%s\n"), results, be.bstrerror(status)); goto bail_out; } if (loaded) { @@ -1157,7 +1204,7 @@ try_again: if (status != 0) { berrno be; Pmsg1(-1, _("3992 Bad autochanger command: %s\n"), changer); - Pmsg2(-1, _("3992 result=\"%s\": ERR=%s\n"), results, be.strerror(status)); + Pmsg2(-1, _("3992 result=\"%s\": ERR=%s\n"), results, be.bstrerror(status)); } } @@ -1180,7 +1227,7 @@ try_again: } else { berrno be; Pmsg1(-1, _("3993 Bad autochanger command: %s\n"), changer); - Pmsg2(-1, _("3993 result=\"%s\": ERR=%s\n"), results, be.strerror(status)); + Pmsg2(-1, _("3993 result=\"%s\": ERR=%s\n"), results, be.bstrerror(status)); goto bail_out; } @@ -1265,7 +1312,7 @@ static int fsf_test() weofcmd(); /* end file 3 */ wrcmd(); weofcmd(); /* end file 4 */ - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } @@ -1328,10 +1375,10 @@ test_again: bail_out: Pmsg0(-1, _("\nThe forward space file test failed.\n")); - if (dev_cap(dev, CAP_FASTFSF)) { + if (dev->has_cap(CAP_FASTFSF)) { Pmsg0(-1, _("You have Fast Forward Space File enabled.\n" "I am turning it off then retrying the test.\n")); - dev->capabilities &= ~CAP_FASTFSF; + dev->clear_cap(CAP_FASTFSF); set_off = true; goto test_again; } @@ -1366,13 +1413,13 @@ static void testcmd() goto all_done; } if (stat == -1) { /* first test failed */ - if (dev_cap(dev, CAP_EOM) || dev_cap(dev, CAP_FASTFSF)) { + if (dev->has_cap(CAP_EOM) || dev->has_cap(CAP_FASTFSF)) { Pmsg0(-1, _("\nAppend test failed. Attempting again.\n" "Setting \"Hardware End of Medium = no\n" " and \"Fast Forward Space File = no\n" "and retrying append test.\n\n")); - dev->capabilities &= ~CAP_EOM; /* turn off eom */ - dev->capabilities &= ~CAP_FASTFSF; /* turn off fast fsf */ + dev->clear_cap(CAP_EOM); /* turn off eom */ + dev->clear_cap(CAP_FASTFSF); /* turn off fast fsf */ stat = append_test(); if (stat == 1) { Pmsg0(-1, _("\n\nIt looks like the test worked this time, please add:\n\n" @@ -1496,6 +1543,14 @@ static void fsrcmd() } } +/* + * Read a Bacula block from the tape + */ +static void rbcmd() +{ + dev->open(dcr, OPEN_READ_ONLY); + read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK); +} /* * Write a Bacula block to the tape @@ -1506,6 +1561,9 @@ static void wrcmd() DEV_RECORD *rec = dcr->rec; int i; + if (!dev->is_open()) { + open_the_device(); + } sm_check(__FILE__, __LINE__, false); empty_block(block); if (verbose > 1) { @@ -1552,13 +1610,13 @@ static void rrcmd() len = 1024; } buf = (char *)malloc(len); - stat = read(dev->fd, buf, len); + stat = read(dev->fd(), buf, len); if (stat > 0 && stat <= len) { errno = 0; } berrno be; Pmsg3(0, _("Read of %d bytes gives stat=%d. ERR=%s\n"), - len, stat, be.strerror()); + len, stat, be.bstrerror()); free(buf); } @@ -1583,15 +1641,15 @@ static void scancmd() Pmsg0(0, _("End of tape\n")); return; } - update_pos_dev(dev); + dev->update_pos(dcr); tot_files = dev->file; Pmsg1(0, _("Starting scan at file %u\n"), dev->file); for (;;) { - if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) { + if ((stat = read(dev->fd(), buf, sizeof(buf))) < 0) { berrno be; dev->clrerror(-1); Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"), - dev->dev_name, be.strerror()); + dev->dev_name, be.bstrerror()); Pmsg2(0, _("Bad status from read %d. ERR=%s\n"), stat, dev->bstrerror()); if (blocks > 0) { if (blocks==1) { @@ -1606,7 +1664,7 @@ static void scancmd() Dmsg1(200, "read status = %d\n", stat); /* sleep(1); */ if (stat != block_size) { - update_pos_dev(dev); + dev->update_pos(dcr); if (blocks > 0) { if (blocks==1) { printf(_("1 block of %d bytes in file %d\n"), block_size, dev->file); @@ -1619,7 +1677,7 @@ static void scancmd() block_size = stat; } if (stat == 0) { /* EOF */ - update_pos_dev(dev); + dev->update_pos(dcr); printf(_("End of File mark.\n")); /* Two reads of zero means end of tape */ if (dev->state & ST_EOF) @@ -1639,7 +1697,7 @@ static void scancmd() bytes += stat; } } - update_pos_dev(dev); + dev->update_pos(dcr); tot_files = dev->file - tot_files; printf(_("Total files=%d, blocks=%d, bytes = %s\n"), tot_files, tot_blocks, edit_uint64_with_commas(bytes, ec1)); @@ -1665,7 +1723,7 @@ static void scan_blocks() bytes = 0; empty_block(block); - update_pos_dev(dev); + dev->update_pos(dcr); tot_files = dev->file; for (;;) { if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { @@ -1731,7 +1789,7 @@ static void scan_blocks() block->VolSessionId, block->VolSessionTime); if (verbose == 1) { DEV_RECORD *rec = new_record(); - read_record_from_block(block, rec); + read_record_from_block(dcr, block, rec); Pmsg8(-1, _("Blk_block: %u dev_blk=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"), block->BlockNumber, dev->block_num, block->block_len, FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, rec->VolSessionTime, @@ -1821,14 +1879,7 @@ static void fillcmd() min_block_size = dev->min_block_size; dev->min_block_size = dev->max_block_size; set_volume_name("TestVolume1", 1); - - if (!dev->rewind(dcr)) { - Pmsg0(000, _("Rewind failed.\n")); - } - if (!dev->weof(1)) { - Pmsg0(000, _("Write EOF failed.\n")); - } - labelcmd(); + dir_ask_sysop_to_create_appendable_volume(dcr); dev->set_append(); /* force volume to be relabeled */ /* @@ -1865,7 +1916,7 @@ static void fillcmd() * Put some random data in the record */ fd = open("/dev/urandom", O_RDONLY); - if (fd) { + if (fd != -1) { read(fd, rec.data, rec.data_len); close(fd); } else { @@ -1881,8 +1932,8 @@ static void fillcmd() */ jcr->dcr->VolFirstIndex = 0; time(&jcr->run_time); /* start counting time for rates */ - localtime_r(&jcr->run_time, &tm); - strftime(buf1, sizeof(buf1), "%T", &tm); + (void)localtime_r(&jcr->run_time, &tm); + strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm); if (simple) { Pmsg1(-1, _("%s Begin writing Bacula records to tape ...\n"), buf1); } else { @@ -1935,8 +1986,8 @@ static void fillcmd() */ if ((block->BlockNumber % 32000) == 0) { now = time(NULL); - localtime_r(&now, &tm); - strftime(buf1, sizeof(buf1), "%T", &tm); + (void)localtime_r(&now, &tm); + strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm); Pmsg1(-1, _("%s Flush block, write EOF\n"), buf1); flush_block(block, 0); dev->weof(1); @@ -1958,7 +2009,9 @@ static void fillcmd() /* Get out after writing 10 blocks to the second tape */ if (BlockNumber > 10 && stop != 0) { /* get out */ - Pmsg0(-1, "Done writing ...\n"); + char ed1[50]; + Pmsg1(-1, "Done writing %s records ...\n", + edit_uint64_with_commas(write_count, ed1)); break; } } @@ -2008,12 +2061,12 @@ static void fillcmd() } else { berrno be; Pmsg2(-1, _("Could not create state file: %s ERR=%s\n"), buf, - be.strerror()); + be.bstrerror()); } now = time(NULL); - localtime_r(&now, &tm); - strftime(buf1, sizeof(buf1), "%T", &tm); + (void)localtime_r(&now, &tm); + strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm); if (simple) { Pmsg3(-1, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"), buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num); @@ -2065,7 +2118,7 @@ static void unfillcmd() } else { berrno be; Pmsg2(-1, _("\nCould not find the state file: %s ERR=%s\n" - "You must redo the fill command.\n"), buf, be.strerror()); + "You must redo the fill command.\n"), buf, be.bstrerror()); return; } do_unfill(); @@ -2075,15 +2128,15 @@ static void unfillcmd() static void do_unfill() { DEV_BLOCK *block = dcr->block; - bool autochanger; + int autochanger; dumped = 0; VolBytes = 0; LastBlock = 0; Dmsg0(20, "Enter do_unfill\n"); - dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */ - dev->capabilities &= ~CAP_LABEL; /* don't label anything here */ + dev->set_cap(CAP_ANONVOLS); /* allow reading any volume */ + dev->clear_cap(CAP_LABEL); /* don't label anything here */ end_of_tape = 0; @@ -2092,33 +2145,43 @@ static void do_unfill() file_index = 0; if (last_block) { free_block(last_block); + last_block = NULL; } last_block_num = last_block_num1; last_file = last_file1; last_block = last_block1; + free_restore_volume_list(jcr); + jcr->bsr = NULL; + bstrncpy(dcr->VolumeName, "TestVolume1|TestVolume2", sizeof(dcr->VolumeName)); + create_restore_volume_list(jcr); + if (jcr->VolList != NULL) { + jcr->VolList->Slot = 1; + if (jcr->VolList->next != NULL) { + jcr->VolList->next->Slot = 2; + } + } + + set_volume_name("TestVolume1", 1); + if (!simple) { /* Multiple Volume tape */ /* Close device so user can use autochanger if desired */ - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + if (dev->has_cap(CAP_OFFLINEUNMOUNT)) { dev->offline(); } autochanger = autoload_device(dcr, 1, NULL); - if (!autochanger) { + if (autochanger != 1) { dev->close(); get_cmd(_("Mount first tape. Press enter when ready: ")); } - free_restore_volume_list(jcr); - jcr->dcr = new_dcr(jcr, dev); - set_volume_name("TestVolume1", 1); - jcr->bsr = NULL; - create_restore_volume_list(jcr); - dev->close(); - dev->num_writers = 0; - if (!acquire_device_for_read(dcr)) { - Pmsg1(-1, "%s", dev->errmsg); - goto bail_out; - } + } + + dev->close(); + dev->num_writers = 0; + if (!acquire_device_for_read(dcr)) { + Pmsg1(-1, "%s", dev->errmsg); + goto bail_out; } /* * We now have the first tape mounted. @@ -2136,7 +2199,7 @@ static void do_unfill() read_records(dcr, quickie_cb, my_mount_next_read_volume); Pmsg4(-1, _("Reposition from %u:%u to %u:%u\n"), dev->file, dev->block_num, last_file, last_block_num); - if (!dev->reposition(last_file, last_block_num)) { + if (!dev->reposition(dcr, last_file, last_block_num)) { Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } @@ -2163,16 +2226,14 @@ static void do_unfill() /* Multiple Volume tape */ /* Close device so user can use autochanger if desired */ - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + if (dev->has_cap(CAP_OFFLINEUNMOUNT)) { dev->offline(); } - free_restore_volume_list(jcr); set_volume_name("TestVolume2", 2); - jcr->bsr = NULL; - create_restore_volume_list(jcr); + autochanger = autoload_device(dcr, 1, NULL); - if (!autochanger) { + if (autochanger != 1) { dev->close(); get_cmd(_("Mount second tape. Press enter when ready: ")); } @@ -2187,7 +2248,7 @@ static void do_unfill() * on the previous tape. */ Pmsg2(-1, _("Reposition from %u:%u to 0:1\n"), dev->file, dev->block_num); - if (!dev->reposition(0, 1)) { + if (!dev->reposition(dcr, 0, 1)) { Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } @@ -2203,7 +2264,7 @@ static void do_unfill() /* Now find and compare the last block */ Pmsg4(-1, _("Reposition from %u:%u to %u:%u\n"), dev->file, dev->block_num, last_file, last_block_num); - if (!dev->reposition(last_file, last_block_num)) { + if (!dev->reposition(dcr, last_file, last_block_num)) { Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } @@ -2283,7 +2344,7 @@ static int flush_block(DEV_BLOCK *block, int dump) DEV_BLOCK *tblock; uint32_t this_file, this_block_num; - lock_device(dev); + dev->r_dlock(); if (!this_block) { this_block = new_block(dev); } @@ -2338,12 +2399,12 @@ static int flush_block(DEV_BLOCK *block, int dump) if (!fixup_device_block_write_error(jcr->dcr)) { Pmsg1(000, _("Cannot fixup device error. %s\n"), dev->bstrerror()); ok = false; - unlock_device(dev); + dev->dunlock(); return 0; } BlockNumber = 0; /* start counting for second tape */ } - unlock_device(dev); + dev->dunlock(); return 1; /* end of tape reached */ } @@ -2362,7 +2423,7 @@ static int flush_block(DEV_BLOCK *block, int dump) last_file = this_file; last_block_num = this_block_num; - unlock_device(dev); + dev->dunlock(); return 1; } @@ -2411,7 +2472,7 @@ static void qfillcmd() } printf("\n"); weofcmd(); - if (dev_cap(dev, CAP_TWOEOF)) { + if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); } rewindcmd(); @@ -2449,7 +2510,7 @@ static void rawfill_cmd() Pmsg1(0, _("Begin writing raw blocks of %u bytes.\n"), block->buf_len); for ( ;; ) { *p = block_num; - stat = write(dev->fd, block->buf, block->buf_len); + stat = dev->d_write(dev->fd(), block->buf, block->buf_len); if (stat == (int)block->buf_len) { if ((block_num++ % 100) == 0) { printf("+"); @@ -2467,65 +2528,17 @@ static void rawfill_cmd() printf("\n"); berrno be; printf(_("Write failed at block %u. stat=%d ERR=%s\n"), block_num, stat, - be.strerror(my_errno)); + be.bstrerror(my_errno)); weofcmd(); } -/* - * Fill a tape using Bacula block writes - */ -static void bfill_cmd() -{ - DEV_BLOCK *block = dcr->block; - uint32_t block_num = 0; - uint32_t *p; - int my_errno; - int fd; - uint32_t i; - - fd = open("/dev/urandom", O_RDONLY); - if (fd) { - read(fd, block->buf, block->buf_len); - close(fd); - } else { - uint32_t *p = (uint32_t *)block->buf; - srandom(time(NULL)); - for (i=0; ibuf_len/sizeof(uint32_t); i++) { - p[i] = random(); - } - } - p = (uint32_t *)block->buf; - Pmsg1(0, _("Begin writing Bacula blocks of %u bytes.\n"), block->buf_len); - for ( ;; ) { - *p = block_num; - block->binbuf = block->buf_len; - block->bufp = block->buf + block->binbuf; - if (!write_block_to_dev(dcr)) { - break; - } - if ((block_num++ % 100) == 0) { - printf("+"); - fflush(stdout); - } - p[0] += p[13]; - for (i=1; i<(block->buf_len/sizeof(uint32_t)-1); i++) { - p[i] += p[i-1]; - } - } - my_errno = errno; - printf("\n"); - printf(_("Write failed at block %u.\n"), block_num); - weofcmd(); -} - struct cmdstruct { const char *key; void (*func)(); const char *help; }; static struct cmdstruct commands[] = { {NT_("autochanger"),autochangercmd, _("test autochanger")}, {NT_("bsf"), bsfcmd, _("backspace file")}, {NT_("bsr"), bsrcmd, _("backspace record")}, - {NT_("bfill"), bfill_cmd, _("fill tape using Bacula writes")}, {NT_("cap"), capcmd, _("list device capabilities")}, {NT_("clear"), clearcmd, _("clear tape errors")}, {NT_("eod"), eodcmd, _("go to end of Bacula data for append")}, @@ -2549,6 +2562,7 @@ static struct cmdstruct commands[] = { {NT_("weof"), weofcmd, _("write an EOF on the tape")}, {NT_("wr"), wrcmd, _("write a single Bacula block")}, {NT_("rr"), rrcmd, _("read a single record")}, + {NT_("rb"), rbcmd, _("read a single Bacula block")}, {NT_("qfill"), qfillcmd, _("quick fill command")} }; #define comsize (sizeof(commands)/sizeof(struct cmdstruct)) @@ -2559,7 +2573,7 @@ do_tape_cmds() unsigned int i; bool found; - while (get_cmd("*")) { + while (!quit && get_cmd("*")) { sm_check(__FILE__, __LINE__, false); found = false; parse_args(cmd, &args, &argc, argk, argv, MAX_CMD_ARGS); @@ -2569,10 +2583,9 @@ do_tape_cmds() found = true; break; } - if (!found) - Pmsg1(0, _("%s is an illegal command\n"), cmd); - if (quit) - break; + if (!found) { + Pmsg1(0, _("\"%s\" is an invalid command\n"), cmd); + } } } @@ -2590,17 +2603,18 @@ static void helpcmd() static void usage() { fprintf(stderr, _( -"Copyright (C) 2000-2005 Kern Sibbald.\n" +PROG_COPYRIGHT "\nVersion: %s (%s)\n\n" "Usage: btape \n" " -b specify bootstrap file\n" " -c set configuration file to file\n" -" -d set debug level to nn\n" +" -d set debug level to \n" +" -dt print timestamp in debug output\n" " -p proceed inspite of I/O errors\n" " -s turn off signals\n" " -v be verbose\n" " -? print this message.\n" -"\n"), VERSION, BDATE); +"\n"), 2000, VERSION, BDATE); } @@ -2641,7 +2655,7 @@ get_cmd(const char *prompt) bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} -bool dir_update_volume_info(DCR *dcr, bool relabel) +bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } @@ -2667,14 +2681,13 @@ bool dir_find_next_appendable_volume(DCR *dcr) return dcr->VolumeName[0] != 0; } -bool dir_ask_sysop_to_mount_volume(DCR *dcr) +bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /* mode */) { DEVICE *dev = dcr->dev; Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n"); if (dcr->VolumeName[0] == 0) { return dir_ask_sysop_to_create_appendable_volume(dcr); } - dev->close(); Pmsg1(-1, "%s", dev->errmsg); /* print reason */ if (dcr->VolumeName[0] == 0 || strcmp(dcr->VolumeName, "TestVolume2") == 0) { fprintf(stderr, _("Mount second Volume on device %s and press return when ready: "), @@ -2683,13 +2696,14 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "), dcr->VolumeName, dev->print_name()); } + dev->close(); getchar(); return true; } bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { - bool autochanger; + int autochanger; DEVICE *dev = dcr->dev; Dmsg0(20, "Enter dir_ask_sysop_to_create_appendable_volume\n"); if (stop == 0) { @@ -2698,17 +2712,16 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) set_volume_name("TestVolume2", 2); } /* Close device so user can use autochanger if desired */ - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + if (dev->has_cap(CAP_OFFLINEUNMOUNT)) { dev->offline(); } autochanger = autoload_device(dcr, 1, NULL); - if (!autochanger) { - dev->close(); + if (autochanger != 1) { fprintf(stderr, _("Mount blank Volume on device %s and press return when ready: "), dev->print_name()); + dev->close(); getchar(); } - open_device(dcr); labelcmd(); VolumeName = NULL; BlockNumber = 0; @@ -2722,8 +2735,10 @@ static bool my_mount_next_read_volume(DCR *dcr) DEV_BLOCK *block = dcr->block; Dmsg0(20, "Enter my_mount_next_read_volume\n"); - Pmsg1(000, _("End of Volume \"%s\"\n"), dcr->VolumeName); + Pmsg2(000, _("End of Volume \"%s\" %d records.\n"), dcr->VolumeName, + quickie_count); + volume_unused(dcr); /* release current volume */ if (LastBlock != block->BlockNumber) { VolBytes += block->block_len; } @@ -2742,10 +2757,8 @@ static bool my_mount_next_read_volume(DCR *dcr) return false; } - free_restore_volume_list(jcr); set_volume_name("TestVolume2", 2); - jcr->bsr = NULL; - create_restore_volume_list(jcr); + dev->close(); if (!acquire_device_for_read(dcr)) { Pmsg2(0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(), dcr->VolumeName); @@ -2763,4 +2776,5 @@ static void set_volume_name(const char *VolName, int volnum) bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName)); bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); dcr->VolCatInfo.Slot = volnum; + dcr->VolCatInfo.InChanger = true; }