-/*
- *
- * Bacula Tape manipulation program
- *
- * Has various tape manipulation commands -- mostly for
- * use in determining how tapes really work.
- *
- * Kern Sibbald, April MM
- *
- * Note, this program reads stored.conf, and will only
- * talk to devices that are configured.
- *
- * Version $Id$
- *
- */
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+ 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 plus additions
- that are listed in the file LICENSE.
+ 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
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Bacula® is a registered trademark of John Walker.
+ 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
+ *
+ * Has various tape manipulation commands -- mostly for
+ * use in determining how tapes really work.
+ *
+ * Kern Sibbald, April MM
+ *
+ * Note, this program reads stored.conf, and will only
+ * talk to devices that are configured.
+ *
+ * Version $Id$
+ *
+ */
#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();
/* Static variables */
+static CONFIG *config;
#define CONFIG_FILE "bacula-sd.conf"
char *configfile = NULL;
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;
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) {
if (configfile) {
free(configfile);
}
- free_config_resources();
+ if (config) {
+ config->free_resources();
+ free(config);
+ config = NULL;
+ }
if (args) {
free_pool_memory(args);
args = NULL;
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;
}
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;
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; i<len; i++) {
}
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)) {
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;
}
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)) {
}
}
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"
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;
wrcmd();
wrcmd();
weofcmd(); /* end file 2 */
- if (dev_cap(dev, CAP_TWOEOF)) {
+ if (dev->has_cap(CAP_TWOEOF)) {
weofcmd();
}
dev->close(); /* release device */
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();
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)) {
} 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) {
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));
}
}
} 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;
}
weofcmd(); /* end file 3 */
wrcmd();
weofcmd(); /* end file 4 */
- if (dev_cap(dev, CAP_TWOEOF)) {
+ if (dev->has_cap(CAP_TWOEOF)) {
weofcmd();
}
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;
}
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"
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);
}
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) {
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,
} else {
berrno be;
Pmsg2(-1, _("Could not create state file: %s ERR=%s\n"), buf,
- be.strerror());
+ be.bstrerror());
}
now = time(NULL);
} 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();
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;
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);
/* 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();
}
DEV_BLOCK *tblock;
uint32_t this_file, this_block_num;
- lock_device(dev);
+ dev->r_dlock();
if (!this_block) {
this_block = new_block(dev);
}
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 */
}
last_file = this_file;
last_block_num = this_block_num;
- unlock_device(dev);
+ dev->dunlock();
return 1;
}
}
printf("\n");
weofcmd();
- if (dev_cap(dev, CAP_TWOEOF)) {
+ if (dev->has_cap(CAP_TWOEOF)) {
weofcmd();
}
rewindcmd();
Pmsg1(0, _("Begin writing raw blocks of %u bytes.\n"), block->buf_len);
for ( ;; ) {
*p = block_num;
- if (dev->is_tape()) {
- stat = tape_write(dev->fd, block->buf, block->buf_len);
- } else {
- 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("+");
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();
}
"Usage: btape <options> <device_name>\n"
" -b <file> specify bootstrap file\n"
" -c <file> set configuration file to file\n"
-" -d <nn> set debug level to nn\n"
+" -d <nn> set debug level to <nn>\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"
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;
}
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");
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);
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;
}