Barring reading the manual, you might try the
following:
-CFLAGS="-g -Wall" \
+To Configure it:
+
./configure \
--sbindir=$HOME/bacula/bin \
--sysconfdir=$HOME/bacula/bin \
--with-working-dir=$HOME/bacula/bin/working \
--with-dump-email=YOUR_EMAIL_ADDRESS \
--with-job-email=YOUR_EMAIL_ADDRESS \
- --with-smtp-host=YOUR_SMTP_SERVER_ADDRESS \
- --with-baseport=9101
+ --with-smtp-host=YOUR_SMTP_SERVER_ADDRESS
-Build Bacula
+Build Bacula:
make
directory in time.c or dev.c. There may also be problems in
lib/signal.c as I currently pull in all Linux signals, some of
which may not be available on your system.
+
+To creat the database:
+
+ src/make_bacula_tables
+
+To start it:
+
+ ./startit
+ ./console (or ./gnome-console)
+
+To stop it:
+
+ ./stopit
+
+Well, it is all just a bit more complicated than that,
+but you should have the idea.
I tried this and it didn't find sqlite.h
=======
+- Check if GZIP1 is working -- check speed.
- Put MaximumVolumeSize in Director.
- Document how to cancel a job that is waiting on a Volume.
Must "cancel" then "mount".
Another try with tape mounted and Job hung in Director.
- Write updated bootstrap after every Job.
-
#define Pmsg11(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) d_msg(__FILE__,__LINE__,lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#define Pmsg12(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) d_msg(__FILE__,__LINE__,lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
#define Pmsg13(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) d_msg(__FILE__,__LINE__,lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)
+#define Pmsg14(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) d_msg(__FILE__,__LINE__,lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
/* Daemon Error Messages that are delivered according to the message resource */
#
if test xsqlite = x@DB_NAME@ ; then
source ./drop_sqlite_tables
+ echo "Dropped SQLite tables"
else
source ./drop_mysql_tables
+ echo "Dropped MySQL tables"
fi
# Bacula tables for either MySQL or SQLite
#
if test xsqlite = x@DB_NAME@ ; then
+ echo "Making SQLite tables"
source ./make_sqlite_tables
else
+ echo "Making MySQL tables"
source ./make_mysql_tables
fi
db_lock(mdb);
if (jr->JobId == 0) {
Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
-PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus \
+PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
+Type,Level \
FROM Job WHERE Job='%s'", jr->Job);
} else {
Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
-PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus \
+PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
+Type,Level \
FROM Job WHERE JobId=%u", jr->JobId);
}
jr->JobTDate = (btime_t)strtod(row[7], NULL);
strcpy(jr->Job, row[8]);
jr->JobStatus = (int)*row[9];
+ jr->Type = (int)*row[10];
+ jr->Level = (int)*row[11];
sql_free_result(mdb);
db_unlock(mdb);
long Ticket; /* ticket for this job */
uint32_t VolFirstFile; /* First file index this Volume */
uint32_t FileIndex; /* Current File Index */
- uint32_t start_block; /* Start write block */
- uint32_t start_file; /* Start write file */
- uint32_t end_block; /* Ending block written */
- uint32_t end_file; /* End file written */
+ uint32_t EndFile; /* End file written */
+ uint32_t StartFile; /* Start write file */
+ uint32_t StartBlock; /* Start write block */
+ uint32_t EndBlock; /* Ending block written */
+ uint32_t FileId; /* Last file id inserted */
/* Parmaters for Open Read Session */
BSR *bsr; /* Bootstrap record -- has everything */
#endif
}
+btime_t get_current_btime()
+{
+ return (btime_t)time(NULL);
+}
+
/* date_encode -- Encode civil date as a Julian day number. */
extern void tm_decode(struct date_time *dt, struct tm *tm);
extern void get_current_time(struct date_time *dt);
+extern btime_t get_current_btime(void);
+
#endif /* __btime_INCLUDED */
void
d_msg(char *file, int line, int level, char *fmt,...)
{
- char buf[MAXSTRING];
+ char buf[2000];
int i;
va_list arg_ptr;
int details = TRUE;
}
+/* serial_btime -- Serialise an btime_t 64 bit integer. */
+
+void serial_btime(uint8_t * * const ptr, const btime_t v)
+{
+ if (htonl(1) == 1L) {
+ memcpy(*ptr, &v, sizeof(btime_t));
+ } else {
+ int i;
+ uint8_t rv[sizeof(btime_t)];
+ uint8_t *pv = (uint8_t *) &v;
+
+ for (i = 0; i < 8; i++) {
+ rv[i] = pv[7 - i];
+ }
+ memcpy(*ptr, &rv, sizeof(btime_t));
+ }
+ *ptr += sizeof(btime_t);
+}
+
+
+
/* serial_float64 -- Serialise a 64 bit IEEE floating point number.
This code assumes that the host floating point
format is IEEE and that floating point quantities
return ntohl(vo);
}
-/* unserial_int64 -- Unserialise a signed 64 bit integer. */
+/* unserial_uint64 -- Unserialise an unsigned 64 bit integer. */
-int64_t unserial_int64(uint8_t * * const ptr)
+uint64_t unserial_uint64(uint8_t * * const ptr)
{
- int64_t v;
+ uint64_t v;
if (htonl(1) == 1L) {
- memcpy(&v, *ptr, sizeof(int64_t));
+ memcpy(&v, *ptr, sizeof(uint64_t));
} else {
int i;
- uint8_t rv[sizeof(int64_t)];
+ uint8_t rv[sizeof(uint64_t)];
uint8_t *pv = (uint8_t *) &v;
- memcpy(&v, *ptr, sizeof(int64_t));
+ memcpy(&v, *ptr, sizeof(uint64_t));
for (i = 0; i < 8; i++) {
rv[i] = pv[7 - i];
}
- memcpy(&v, &rv, sizeof(int64_t));
+ memcpy(&v, &rv, sizeof(uint64_t));
}
- *ptr += sizeof(int64_t);
+ *ptr += sizeof(uint64_t);
return v;
}
-/* unserial_uint64 -- Unserialise an unsigned 64 bit integer. */
+/* unserial_btime -- Unserialise a btime_t 64 bit integer. */
-uint64_t unserial_uint64(uint8_t * * const ptr)
+uint64_t unserial_btime(uint8_t * * const ptr)
{
- uint64_t v;
+ btime_t v;
if (htonl(1) == 1L) {
- memcpy(&v, *ptr, sizeof(uint64_t));
+ memcpy(&v, *ptr, sizeof(btime_t));
} else {
int i;
- uint8_t rv[sizeof(uint64_t)];
+ uint8_t rv[sizeof(btime_t)];
uint8_t *pv = (uint8_t *) &v;
- memcpy(&v, *ptr, sizeof(uint64_t));
+ memcpy(&v, *ptr, sizeof(btime_t));
for (i = 0; i < 8; i++) {
rv[i] = pv[7 - i];
}
- memcpy(&v, &rv, sizeof(uint64_t));
+ memcpy(&v, &rv, sizeof(btime_t));
}
- *ptr += sizeof(uint64_t);
+ *ptr += sizeof(btime_t);
return v;
}
+
/* unserial_float64 -- Unserialise a 64 bit IEEE floating point number.
This code assumes that the host floating point
format is IEEE and that floating point quantities
extern void serial_uint32(uint8_t * * ptr, uint32_t v);
extern void serial_int64(uint8_t * * ptr, int64_t v);
extern void serial_uint64(uint8_t * * ptr, uint64_t v);
+extern void serial_btime(uint8_t * * ptr, btime_t v);
extern void serial_float64(uint8_t * * ptr, float64_t v);
extern int serial_string(uint8_t * ptr, char * str);
extern int16_t unserial_int16(uint8_t * * ptr);
extern uint32_t unserial_uint32(uint8_t * * ptr);
extern int64_t unserial_int64(uint8_t * * ptr);
extern uint64_t unserial_uint64(uint8_t * * ptr);
+extern btime_t unserial_btime(uint8_t * * ptr);
extern float64_t unserial_float64(uint8_t * * ptr);
extern int unserial_string(uint8_t * ptr, char * str);
/* 64 bit unsigned integer */
#define ser_uint64(x) serial_uint64(&ser_ptr, x)
+/* btime -- 64 bit unsigned integer */
+#define ser_btime(x) serial_btime(&ser_ptr, x)
+
/* 64 bit IEEE floating point number */
#define ser_float64(x) serial_float64(&ser_ptr, x)
/* 64 bit unsigned integer */
#define unser_uint64(x) (x) = unserial_uint64(&ser_ptr)
+/* btime -- 64 bit unsigned integer */
+#define unser_btime(x) (x) = unserial_btime(&ser_ptr)
+
/* 64 bit IEEE floating point number */
#define unser_float64(x)(x) = unserial_float64(&ser_ptr)
*/
/*
- * Convert a string to btime_t (64 bit seconds)
+ * Convert a string duration to btime_t (64 bit seconds)
* Returns 0: if error
1: if OK, and value stored in value
*/
}
+/*
+ * Edit a btime "duration" into ASCII
+ */
char *edit_btime(btime_t val, char *buf)
{
char mybuf[30];
#include "bacula.h"
#include "stored.h"
-extern int FiledDataChan; /* File daemon data channel (port) */
-extern int BaculaTapeVersion; /* Version number */
-extern char BaculaId[]; /* Id string */
/* Responses sent to the File daemon */
static char OK_data[] = "3000 OK data\n";
}
}
/*
- *******FIXME***** we should put the ok status in the End of
- * session label
- *
* We probably need a new flag that says "Do not attempt
* to write because there is no tape".
*/
sm_check(__FILE__, __LINE__, False);
Dmsg0(90, "Write_end_session_label()\n");
+ /* Create Job status for end of session label */
+ if (!job_cancelled(jcr) && ok) {
+ jcr->JobStatus = JS_Terminated;
+ } else if (!ok) {
+ jcr->JobStatus = JS_ErrorTerminated;
+ }
if (!write_session_label(jcr, block, EOS_LABEL)) {
Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
strerror_dev(dev));
bnet_fsend(dir, Create_job_media, jcr->Job,
jcr->VolFirstFile, jcr->JobFiles,
- jcr->start_file, jcr->end_file,
- jcr->start_block, jcr->end_block);
+ jcr->StartFile, jcr->EndFile,
+ jcr->StartBlock, jcr->EndBlock);
Dmsg1(100, "create_jobmedia(): %s", dir->msg);
if (bnet_recv(dir) <= 0) {
Dmsg0(190, "create_jobmedia error bnet_recv\n");
uint32_t VolSessionId, VolSessionTime, data_len;
int32_t FileIndex;
int32_t Stream;
+ int bhl, rhl;
- unser_begin(b->buf, BLKHDR_LENGTH);
+ unser_begin(b->buf, BLKHDR1_LENGTH);
unser_uint32(CheckSum);
unser_uint32(block_len);
unser_uint32(BlockNumber);
unser_bytes(Id, BLKHDR_ID_LENGTH);
- ASSERT(unser_length(b->buf) == BLKHDR_LENGTH);
+ ASSERT(unser_length(b->buf) == BLKHDR1_LENGTH);
Id[BLKHDR_ID_LENGTH] = 0;
+ if (Id[3] == '2') {
+ unser_uint32(VolSessionId);
+ unser_uint32(VolSessionTime);
+ bhl = BLKHDR2_LENGTH;
+ rhl = RECHDR2_LENGTH;
+ } else {
+ VolSessionId = VolSessionTime = 0;
+ bhl = BLKHDR1_LENGTH;
+ rhl = RECHDR1_LENGTH;
+ }
if (block_len > 100000) {
Dmsg3(20, "Dump block %s %s blocksize too big %d\n", msg, b, block_len);
Dmsg6(10, "Dump block %s %x: size=%d BlkNum=%d\n\
Hdrcksum=%x cksum=%x\n",
msg, b, block_len, BlockNumber, CheckSum, BlockCheckSum);
- p = b->buf + BLKHDR_LENGTH;
- while (p < (b->buf + block_len+RECHDR_LENGTH)) {
- unser_begin(p, RECHDR_LENGTH);
+ p = b->buf + bhl;
+ while (p < (b->buf + block_len+WRITE_RECHDR_LENGTH)) {
+ unser_begin(p, WRITE_RECHDR_LENGTH);
+ if (rhl == RECHDR1_LENGTH) {
unser_uint32(VolSessionId);
unser_uint32(VolSessionTime);
+ }
unser_int32(FileIndex);
unser_int32(Stream);
unser_uint32(data_len);
- Dmsg6(10, "Rec: VId=%d VT=%d FI=%s Strm=%s len=%d p=%x\n",
+ Dmsg6(10, " Rec: VId=%d VT=%d FI=%s Strm=%s len=%d p=%x\n",
VolSessionId, VolSessionTime, FI_to_ascii(FileIndex), stream_to_ascii(Stream),
data_len, p);
- p += data_len + RECHDR_LENGTH;
+ p += data_len + rhl;
}
-
}
/*
return NULL;
}
empty_block(block);
+ block->BlockVer = BLOCK_VER; /* default write version */
Dmsg1(90, "Returning new block=%x\n", block);
return block;
}
/* Empty the block -- for writing */
void empty_block(DEV_BLOCK *block)
{
- block->binbuf = BLKHDR_LENGTH;
+ block->binbuf = WRITE_BLKHDR_LENGTH;
block->bufp = block->buf + block->binbuf;
block->read_len = 0;
block->failed_write = FALSE;
uint32_t block_len = block->binbuf;
Dmsg1(190, "ser_block_header: block_len=%d\n", block_len);
- ser_begin(block->buf, BLKHDR_LENGTH);
+ ser_begin(block->buf, BLKHDR2_LENGTH);
ser_uint32(CheckSum);
ser_uint32(block_len);
ser_uint32(block->BlockNumber);
- ser_bytes(BLKHDR_ID, BLKHDR_ID_LENGTH);
- ASSERT(ser_length(block->buf) == BLKHDR_LENGTH);
+ ser_bytes(WRITE_BLKHDR_ID, BLKHDR_ID_LENGTH);
+ if (BLOCK_VER >= 2) {
+ ser_uint32(block->VolSessionId);
+ ser_uint32(block->VolSessionTime);
+ }
/* Checksum whole block except for the checksum */
CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
block_len-BLKHDR_CS_LENGTH);
Dmsg1(190, "ser_bloc_header: checksum=%x\n", CheckSum);
- ser_begin(block->buf, BLKHDR_LENGTH);
- ser_uint32(CheckSum);
+ ser_begin(block->buf, BLKHDR2_LENGTH);
+ ser_uint32(CheckSum); /* now add checksum to block header */
}
/*
uint32_t block_len;
uint32_t EndBlock;
uint32_t BlockNumber;
+ int bhl;
unser_begin(block->buf, BLKHDR_LENGTH);
unser_uint32(CheckSum);
unser_uint32(block_len);
unser_uint32(BlockNumber);
unser_bytes(Id, BLKHDR_ID_LENGTH);
- ASSERT(unser_length(block->buf) == BLKHDR_LENGTH);
+ ASSERT(unser_length(block->buf) == BLKHDR1_LENGTH);
Id[BLKHDR_ID_LENGTH] = 0;
- block->bufp = block->buf + BLKHDR_LENGTH;
- if (strncmp(Id, BLKHDR_ID, BLKHDR_ID_LENGTH) != 0) {
+ if (Id[3] == '1') {
+ bhl = BLKHDR1_LENGTH;
+ block->BlockVer = 1;
+ block->bufp = block->buf + bhl;
+ if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) {
Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
- BLKHDR_ID, Id);
+ BLKHDR1_ID, Id);
Emsg0(M_ERROR, 0, dev->errmsg);
return 0;
}
+ } else {
+ unser_uint32(block->VolSessionId);
+ unser_uint32(block->VolSessionTime);
+ bhl = BLKHDR2_LENGTH;
+ block->BlockVer = 2;
+ block->bufp = block->buf + bhl;
+ if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) {
+ Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
+ BLKHDR2_ID, Id);
+ Emsg0(M_ERROR, 0, dev->errmsg);
+ return 0;
+ }
+ }
ASSERT(block_len < MAX_BLOCK_LENGTH); /* temp sanity check */
} else {
EndBlock = block_len;
}
- block->binbuf = EndBlock - BLKHDR_LENGTH;
+ block->binbuf = EndBlock - bhl;
block->block_len = block_len;
block->BlockNumber = BlockNumber;
Dmsg3(190, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
- BLKHDR_LENGTH, block_len);
+ bhl, block_len);
if (block_len > block->buf_len) {
- Mmsg2(&dev->errmsg, _("Block length %d is greater than buffer %d\n"),
+ Mmsg2(&dev->errmsg, _("Block length %u is greater than buffer %u\n"),
block_len, block->buf_len);
Emsg0(M_ERROR, 0, dev->errmsg);
return 0;
*/
int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block)
{
- int stat = 0;
+ size_t stat = 0;
uint32_t wlen; /* length to write */
#ifdef NO_TAPE_WRITE_TEST
/* dump_block(block, "before write"); */
if (dev->state & ST_WEOT) {
- Dmsg0(90, "return write_block_to_dev with ST_WEOT\n");
+ Dmsg0(100, "return write_block_to_dev with ST_WEOT\n");
return 0;
}
wlen = block->binbuf;
- if (wlen <= BLKHDR_LENGTH) { /* Does block have data in it? */
- Dmsg0(190, "return write_block_to_dev no data to write\n");
+ if (wlen <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */
+ Dmsg0(100, "return write_block_to_dev no data to write\n");
return 1;
}
/*
}
dev->VolCatInfo.VolCatWrites++;
- if ((uint32_t) (stat=write(dev->fd, block->buf, wlen)) != wlen) {
+// Dmsg1(000, "Pos before write=%lld\n", lseek(dev->fd, (off_t)0, SEEK_CUR));
+ if ((uint32_t) (stat=write(dev->fd, block->buf, (size_t)wlen)) != wlen) {
/* We should check for errno == ENOSPC, BUT many
* devices simply report EIO when it is full.
* with a little more thought we may be able to check
weof_dev(dev, 1); /* write second eof */
return 0;
}
+// Dmsg1(000, "Pos after write=%lld\n", lseek(dev->fd, (off_t)0, SEEK_CUR));
dev->VolCatInfo.VolCatBytes += block->binbuf;
dev->VolCatInfo.VolCatBlocks++;
dev->file_bytes += block->binbuf;
/* Limit maximum File size on volume to user specified value */
- if ((dev->max_file_size > 0) &&
- dev->file_bytes >= dev->max_file_size) {
+ if (dev->state & ST_TAPE) {
+ if ((dev->max_file_size > 0) && dev->file_bytes >= dev->max_file_size) {
weof_dev(dev, 1); /* write eof */
}
+ }
Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num,
wlen);
{
int stat;
Dmsg0(90, "Enter read_block_from_device\n");
- new_lock_device(dev);
lock_device(dev);
stat = read_block_from_dev(dev, block);
- new_unlock_device(dev);
unlock_device(dev);
Dmsg0(90, "Leave read_block_from_device\n");
return stat;
*/
int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block)
{
- int stat;
+ size_t stat;
- Dmsg0(90, "Full read() in read_block_from_device()\n");
- if ((stat=read(dev->fd, block->buf, block->buf_len)) < 0) {
+ Dmsg1(100, "Full read() in read_block_from_device() len=%d\n",
+ block->buf_len);
+// Dmsg1(000, "Pos before read=%lld\n", lseek(dev->fd, (off_t)0, SEEK_CUR));
+ if ((stat=read(dev->fd, block->buf, (size_t)block->buf_len)) < 0) {
/* ***FIXME**** add code to detect buffer too small, and
reallocate buffer, backspace, and reread.
dev->dev_name, strerror(dev->dev_errno));
return 0;
}
+// Dmsg1(000, "Pos after read=%lld\n", lseek(dev->fd, (off_t)0, SEEK_CUR));
Dmsg1(90, "Read device got %d bytes\n", stat);
if (stat == 0) { /* Got EOF ! */
dev->block_num = block->read_len = 0;
}
/* Continue here for successful read */
block->read_len = stat; /* save length read */
- if (block->read_len < BLKHDR_LENGTH) {
+ if (block->read_len < BLKHDR2_LENGTH) {
Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"),
block->read_len, dev->dev_name);
dev->state |= ST_SHORT; /* set short block */
* from shuffling blocks around in the buffer. Take a
* look at this from an efficiency stand point later, but
* it should only happen once at the end of each job.
+ *
+ * I've been lseek()ing negative relative to SEEK_CUR for 30
+ * years now. However, it seems that with the new off_t definition,
+ * it is not possible to seek negative amounts, so we use two
+ * lseek(). One to get the position, then the second to do an
+ * absolute positioning -- so much for efficiency. KES Sep 02.
*/
Dmsg0(200, "At end of read block\n");
if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
-
- Dmsg3(200, "Block: %d read_len %d > %d block_len\n", dev->block_num,
-block->read_len, block->block_len);
- lseek(dev->fd, block->block_len-block->read_len, SEEK_CUR);
- Dmsg2(90, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
+ off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */
+ pos -= (block->read_len - block->block_len);
+ lseek(dev->fd, pos, SEEK_SET);
+ Dmsg2(100, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
block->read_len);
}
Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
#define DEFAULT_BLOCK_SIZE (512 * 126) /* 64,512 N.B. do not use 65,636 here */
/* Block Header definitions. */
-#define BLKHDR_ID "BB01"
+#define BLKHDR1_ID "BB01"
+#define BLKHDR2_ID "BB02"
#define BLKHDR_ID_LENGTH 4
#define BLKHDR_CS_LENGTH 4 /* checksum length */
-#define BLKHDR_LENGTH 16 /* Total length */
+#define BLKHDR1_LENGTH 16 /* Total length */
+#define BLKHDR2_LENGTH 24 /* Total length */
+
+#define WRITE_BLKHDR_ID BLKHDR1_ID
+#define WRITE_BLKHDR_LENGTH BLKHDR1_LENGTH
+#define BLOCK_VER 1
+
+/* Record header definitions */
+#define RECHDR1_LENGTH 20
+#define RECHDR2_LENGTH 12
+#define WRITE_RECHDR_LENGTH RECHDR1_LENGTH
+
+/* Tape label and version definitions */
+#define BaculaId "Bacula 0.9 mortal\n"
+#define BaculaTapeVersion 10
+#define OldCompatibleBaculaTapeVersion1 10
+#define OldCompatibleBaculaTapeVersion2 9
+
/*
* This is the Media structure for a block header
* Note, when written, it is serialized.
- */
-typedef struct s_block_hdr {
+
uint32_t CheckSum;
- uint32_t block_size;
+ uint32_t block_len;
uint32_t BlockNumber;
- char Id[BLKHDR_ID_LENGTH+1];
-} BLOCK_HDR;
+ char Id[BLKHDR_ID_LENGTH];
+
+ * for BB02 block, we also have
+
+ uint32_t VolSessionId;
+ uint32_t VolSessionTime;
+ */
/*
* DEV_BLOCK for reading and writing blocks.
uint32_t buf_len; /* max/default block length */
uint32_t BlockNumber; /* sequential block number */
uint32_t read_len; /* bytes read into buffer */
+ uint32_t VolSessionId; /* */
+ uint32_t VolSessionTime; /* */
+ int BlockVer; /* block version 1 or 2 */
int failed_write; /* set if write failed */
char *bufp; /* pointer into buffer */
POOLMEM *buf; /* actual data buffer. This is a
static uint32_t num_files = 0;
static long record_file_index;
-extern char BaculaId[];
-
static FF_PKT ff;
static BSR *bsr = NULL;
"\nVersion: " VERSION " (" DATE ")\n\n"
"Usage: bls [-d debug_level] <physical-device-name>\n"
" -b <file> specify a bootstrap file\n"
+" -d <level> specify debug level\n"
" -e <file> exclude list\n"
" -i <file> include list\n"
" -j list jobs\n"
}
for ( ;; ) {
if (!read_block_from_device(dev, block)) {
- Dmsg0(20, "!read_block()\n");
+ Dmsg1(100, "!read_block(): ERR=%s\n", strerror_dev(dev));
if (dev->state & ST_EOT) {
if (!mount_next_read_volume(jcr, dev, block)) {
printf("End of File on device\n");
display_error_status(dev);
break;
}
-
- if (verbose) {
+ Dmsg5(100, "Blk=%u blen=%u bVer=%d SessId=%d SessTim=%d\n",
+ block->BlockNumber, block->block_len, block->BlockVer,
+ block->VolSessionId, block->VolSessionTime);
+ if (verbose == 1) {
read_record_from_block(block, rec);
- Pmsg6(-1, "Block: %d blen=%d First rec FI=%s SessId=%d Strm=%s rlen=%d\n",
+ Pmsg6(-1, "Block: %u blen=%u First rec FI=%s SessId=%d Strm=%s rlen=%d\n",
block->BlockNumber, block->block_len,
FI_to_ascii(rec->FileIndex), rec->VolSessionId,
stream_to_ascii(rec->Stream), rec->data_len);
rec->remainder = 0;
+ } else if (verbose > 1) {
+ dump_block(block, "");
} else {
printf("Block: %d size=%d\n", block->BlockNumber, block->block_len);
}
/* Forward referenced functions */
static void do_scan(char *fname);
static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
-static int create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
+static int create_file_attributes_record(B_DB *db, JCR *mjcr,
+ char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec);
static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
+static int update_media_record(B_DB *db, MEDIA_DBR *mr);
static int create_pool_record(B_DB *db, POOL_DBR *pr);
-static int create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
+static JCR *create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
static int update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
DEV_RECORD *rec);
static int create_client_record(B_DB *db, CLIENT_DBR *cr);
static int create_fileset_record(B_DB *db, FILESET_DBR *fsr);
static int create_jobmedia_record(B_DB *db, JCR *jcr);
-static void create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
+static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
+static int update_MD5_record(B_DB *db, char *MD5buf, DEV_RECORD *rec);
/* Global variables */
static DEVICE *dev = NULL;
static B_DB *db;
-static JCR *jcr; /* jcr for bscan */
-static JCR *jobjcr; /* jcr for simulating running job */
+static JCR *bjcr; /* jcr for bscan */
static BSR *bsr;
static struct stat statp;
static int type;
static CLIENT_DBR cr;
static FILESET_DBR fsr;
static ATTR_DBR ar;
+static FILE_DBR fr;
static SESSION_LABEL label;
static SESSION_LABEL elabel;
static char *wd = "/tmp";
static int verbose = 0;
static int update_db = 0;
+static int update_vol_info = 0;
+static int list_records = 0;
static void usage()
{
"Usage: bscan [-d debug_level] <bacula-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -dnn set debug level to nn\n"
+" -m update media info in database\n"
" -n name specify the database name (default bacula)\n"
" -u user specify database user name (default bacula)\n"
" -p password specify database password (default none)\n"
+" -r list records\n"
" -s synchronize or store in database\n"
" -v verbose\n"
" -w dir specify working directory (default /tmp)\n"
init_msg(NULL, NULL);
- while ((ch = getopt(argc, argv, "b:d:n:p:su:vw:?")) != -1) {
+ while ((ch = getopt(argc, argv, "b:d:mn:p:rsu:vw:?")) != -1) {
switch (ch) {
case 'b':
bsr = parse_bsr(NULL, optarg);
debug_level = 1;
break;
+ case 'm':
+ update_vol_info = 1;
+ break;
+
case 'n':
db_name = optarg;
break;
db_password = optarg;
break;
+ case 'r':
+ list_records = 1;
+ break;
+
case 's':
update_db = 1;
break;
working_directory = wd;
- jcr = setup_jcr("bscan", argv[0], bsr);
+ bjcr = setup_jcr("bscan", argv[0], bsr);
if ((db=db_init_database(NULL, db_name, db_user, db_password)) == NULL) {
Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n"));
do_scan(argv[0]);
- free_jcr(jcr);
+ free_jcr(bjcr);
return 0;
}
static void do_scan(char *devname)
{
- dev = setup_to_read_device(jcr);
+ dev = setup_to_read_device(bjcr);
if (!dev) {
exit(1);
}
memset(&jr, 0, sizeof(jr));
memset(&cr, 0, sizeof(cr));
memset(&fsr, 0, sizeof(fsr));
+ memset(&fr, 0, sizeof(fr));
- detach_jcr_from_device(dev, jcr);
+ detach_jcr_from_device(dev, bjcr);
- read_records(jcr, dev, record_cb, mount_next_read_volume);
- release_device(jcr, dev);
+ read_records(bjcr, dev, record_cb, mount_next_read_volume);
+ release_device(bjcr, dev);
free_pool_memory(fname);
free_pool_memory(ofile);
term_dev(dev);
}
-static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
{
+ JCR *mjcr;
+ char ec1[30];
+
+ if (rec->data_len > 0) {
+ mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */
+ }
+ if (list_records) {
+ Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
+ rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
+ rec->Stream, rec->data_len);
+ }
+Dmsg1(000, "record_cb block=%u\n", rec->Block);
/*
* Check for Start or End of Session Record
*
*/
if (rec->FileIndex < 0) {
+ int save_update_db = update_db;
if (verbose > 1) {
dump_label_record(dev, rec, 1);
if (verbose) {
Pmsg1(000, "Media record for %s found in DB.\n", mr.VolumeName);
}
+ /* Clear out some volume statistics that will be updated */
+ mr.VolJobs = mr.VolFiles = mr.VolBlocks = 0;
+ mr.VolBytes = rec->data_len + 20;
} else {
Pmsg1(000, "VOL_LABEL: Media record not found for Volume: %s\n",
mr.VolumeName);
Pmsg1(000, "Media type \"%s\" is OK.\n", mr.MediaType);
}
/* Reset some JCR variables */
- for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
mjcr->VolFirstFile = mjcr->FileIndex = 0;
- mjcr->start_block = mjcr->end_block = 0;
- mjcr->start_file = mjcr->end_file = 0;
+ mjcr->StartBlock = mjcr->EndBlock = 0;
+ mjcr->StartFile = mjcr->EndFile = 0;
}
Pmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName);
break;
case SOS_LABEL:
+
+ mr.VolJobs++;
unser_session_label(&label, rec);
memset(&jr, 0, sizeof(jr));
jr.JobId = label.JobId;
if (db_get_job_record(db, &jr)) {
/* Job record already exists in DB */
- create_jcr(&jr, rec, jr.JobId);
- attach_jcr_to_device(dev, jobjcr);
+ update_db = 0; /* don't change db in create_job_record */
if (verbose) {
Pmsg1(000, _("SOS_LABEL: Found Job record for JobId: %d\n"), jr.JobId);
}
} else {
-
/* Must create a Job record in DB */
Pmsg1(000, "SOS_LABEL: Job record not found for JobId: %d\n",
jr.JobId);
-
- /* Create Client record */
+ }
+ /* Create Client record if not already there */
strcpy(cr.Name, label.ClientName);
create_client_record(db, &cr);
jr.ClientId = cr.ClientId;
- create_job_record(db, &jr, &label, rec);
+ /* process label, if Job record exists don't update db */
+ mjcr = create_job_record(db, &jr, &label, rec);
+ update_db = save_update_db;
+
jr.PoolId = pr.PoolId;
/* Set start positions into JCR */
- jobjcr->start_block = dev->block_num;
- jobjcr->start_file = dev->file;
- }
+ mjcr->StartBlock = dev->block_num;
+ mjcr->StartFile = dev->file;
+ mjcr->start_time = jr.StartTime;
+ mjcr->JobLevel = jr.Level;
+
+ mjcr->client_name = get_pool_memory(PM_FNAME);
+ pm_strcpy(&mjcr->client_name, label.ClientName);
+ mjcr->pool_type = get_pool_memory(PM_FNAME);
+ pm_strcpy(&mjcr->pool_type, label.PoolType);
+ mjcr->fileset_name = get_pool_memory(PM_FNAME);
+ pm_strcpy(&mjcr->fileset_name, label.FileSetName);
+ mjcr->pool_name = get_pool_memory(PM_FNAME);
+ pm_strcpy(&mjcr->pool_name, label.PoolName);
+
if (rec->VolSessionId != jr.VolSessionId) {
Pmsg3(000, "SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n",
jr.JobId,
create_fileset_record(db, &fsr);
jr.FileSetId = fsr.FileSetId;
- /* Do the final update to the Job record */
- update_job_record(db, &jr, &elabel, rec);
- /* Create JobMedia record */
- jobjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!jobjcr) {
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
rec->VolSessionId, rec->VolSessionTime);
break;
}
- jobjcr->end_block = dev->block_num;
- jobjcr->end_file = dev->file;
- create_jobmedia_record(db, jobjcr);
- detach_jcr_from_device(dev, jobjcr);
- free_jcr(jobjcr);
+ /* Do the final update to the Job record */
+ update_job_record(db, &jr, &elabel, rec);
+
+ mjcr->end_time = jr.EndTime;
+ mjcr->JobStatus = JS_Terminated;
+
+ /* Create JobMedia record */
+ create_jobmedia_record(db, mjcr);
+ detach_jcr_from_device(dev, mjcr);
+ free_jcr(mjcr);
- Pmsg1(000, "EOS_LABEL: OK for JobId=%d\n", elabel.JobId);
break;
case EOM_LABEL:
break;
+ case EOT_LABEL: /* end of all tapes */
+ /*
+ * Wiffle through all jobs still open and close
+ * them.
+ */
+ if (update_db) {
+ for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ jr.JobId = mjcr->JobId;
+ jr.JobStatus = JS_ErrorTerminated;
+ jr.JobFiles = mjcr->JobFiles;
+ jr.JobBytes = mjcr->JobBytes;
+ jr.VolSessionId = mjcr->VolSessionId;
+ jr.VolSessionTime = mjcr->VolSessionTime;
+ jr.JobTDate = (btime_t)mjcr->start_time;
+ jr.ClientId = mjcr->ClientId;
+ free_jcr(mjcr);
+ if (!db_update_job_end_record(db, &jr)) {
+ Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
+ }
+ }
+ }
+ mr.VolFiles = rec->File;
+ mr.VolBlocks = rec->Block;
+ mr.VolBytes += mr.VolBlocks * WRITE_BLKHDR_LENGTH; /* approx. */
+ mr.VolMounts++;
+ update_media_record(db, &mr);
+ Pmsg3(0, _("End of Volume. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
+ mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
+ break;
default:
break;
}
decode_stat(ap, &statp);
print_ls_output(fname, lname, type, &statp);
}
- create_file_attributes_record(db, fname, lname, type, ap, rec);
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return;
+ }
+ fr.JobId = mjcr->JobId;
+ fr.FileId = 0;
+ if (db_get_file_attributes_record(db, fname, &fr)) {
+ if (verbose > 1) {
+ Pmsg1(000, _("File record already exists for: %s\n"), fname);
+ }
+ } else {
+ create_file_attributes_record(db, mjcr, fname, lname, type, ap, rec);
+ }
+ free_jcr(mjcr);
/* Data stream and extracting */
} else if (rec->Stream == STREAM_FILE_DATA) {
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return;
+ }
+ mjcr->JobBytes += rec->data_len;
+ free_jcr(mjcr); /* done using JCR */
} else if (rec->Stream == STREAM_GZIP_DATA) {
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return;
+ }
+ mjcr->JobBytes += rec->data_len;
+ free_jcr(mjcr); /* done using JCR */
} else if (rec->Stream == STREAM_MD5_SIGNATURE) {
+ char MD5buf[30];
+ bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */
if (verbose > 1) {
- Pmsg0(000, _("Got MD5 record.\n"));
+ Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf);
}
- /* ****FIXME**** implement db_update_md5_record */
+ update_MD5_record(db, MD5buf, rec);
} else {
Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data);
}
* We got a File Attributes record on the tape. Now, lookup the Job
* record, and then create the attributes record.
*/
-static int create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
+static int create_file_attributes_record(B_DB *db, JCR *mjcr,
+ char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
- JCR *mjcr;
- if (!update_db) {
- return 1;
- }
-
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- return 0;
- }
ar.fname = fname;
ar.link = lname;
ar.ClientId = mjcr->ClientId;
mjcr->VolFirstFile = rec->FileIndex;
}
mjcr->FileIndex = rec->FileIndex;
- free_jcr(mjcr); /* done using JCR */
+ mjcr->JobFiles++;
+
+ if (!update_db) {
+ return 1;
+ }
if (!db_create_file_attributes_record(db, &ar)) {
Pmsg1(0, _("Could not create File Attributes record. ERR=%s\n"), db_strerror(db));
return 0;
}
+ mjcr->FileId = ar.FileId;
+
if (verbose > 1) {
Pmsg1(000, _("Created File record: %s\n"), fname);
}
{
struct date_time dt;
struct tm tm;
- if (!update_db) {
- return 1;
- }
+
strcpy(mr->VolStatus, "Full");
mr->VolRetention = 355 * 3600 * 24; /* 1 year */
dt.julian_day_number = vl->write_date;
dt.julian_day_fraction = vl->label_time;
tm_decode(&dt, &tm);
mr->LabelDate = mktime(&tm);
+
+ if (!update_db) {
+ return 1;
+ }
+
if (!db_create_media_record(db, mr)) {
Pmsg1(0, _("Could not create media record. ERR=%s\n"), db_strerror(db));
return 0;
return 0;
}
if (verbose) {
- Pmsg2(000, _("Created Media record for Volume: %s, JobId: %d\n"),
- mr->VolumeName, jr.JobId);
+ Pmsg1(000, _("Created Media record for Volume: %s\n"), mr->VolumeName);
}
return 1;
}
-static int create_pool_record(B_DB *db, POOL_DBR *pr)
+/*
+ * Called at end of media to update it
+ */
+static int update_media_record(B_DB *db, MEDIA_DBR *mr)
{
- if (!update_db) {
+ if (!update_db && !update_vol_info) {
return 1;
}
+
+ if (!db_update_media_record(db, mr)) {
+ Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Updated Media record at end of Volume: %s\n"), mr->VolumeName);
+ }
+ return 1;
+
+}
+
+
+static int create_pool_record(B_DB *db, POOL_DBR *pr)
+{
pr->NumVols++;
pr->UseCatalog = 1;
pr->VolRetention = 355 * 3600 * 24; /* 1 year */
+
+ if (!update_db) {
+ return 1;
+ }
if (!db_create_pool_record(db, pr)) {
Pmsg1(0, _("Could not create pool record. ERR=%s\n"), db_strerror(db));
return 0;
if (!update_db) {
return 1;
}
+ fsr->FileSetId = 0;
+ if (db_get_fileset_record(db, fsr)) {
+ if (verbose) {
+ Pmsg1(000, _("Fileset \"%s\" already exists.\n"), fsr->FileSet);
+ }
+ } else {
if (!db_create_fileset_record(db, fsr)) {
Pmsg1(0, _("Could not create FileSet record. ERR=%s\n"), db_strerror(db));
return 0;
}
if (verbose) {
- Pmsg1(000, _("Created FileSet record %s\n"), fsr->FileSet);
+ Pmsg1(000, _("Created FileSet record \"%s\"\n"), fsr->FileSet);
+ }
}
return 1;
}
* the Job record and to update it when the Job actually
* begins running.
*/
-static int create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
+static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
DEV_RECORD *rec)
{
+ JCR *mjcr;
struct date_time dt;
struct tm tm;
- if (!update_db) {
- return 1;
- }
- Pmsg1(000, _("Creating Job record for JobId: %d\n"), jr->JobId);
-
jr->JobId = label->JobId;
jr->Type = label->JobType;
jr->Level = label->JobLevel;
jr->VolSessionId = rec->VolSessionId;
jr->VolSessionTime = rec->VolSessionTime;
+ /* Now create a JCR as if starting the Job */
+ mjcr = create_jcr(jr, rec, label->JobId);
+
+ if (!update_db) {
+ return mjcr;
+ }
+
/* This creates the bare essentials */
if (!db_create_job_record(db, jr)) {
Pmsg1(0, _("Could not create job record. ERR=%s\n"), db_strerror(db));
- return 0;
+ return mjcr;
}
- /* Now create a JCR as if starting the Job */
- create_jcr(jr, rec, label->JobId);
-
/* This adds the client, StartTime, JobTDate, ... */
if (!db_update_job_start_record(db, jr)) {
Pmsg1(0, _("Could not update job start record. ERR=%s\n"), db_strerror(db));
- return 0;
+ return mjcr;
}
if (verbose) {
Pmsg1(000, _("Created Job record for JobId: %d\n"), jr->JobId);
}
- return 1;
+ return mjcr;
}
/*
struct tm tm;
JCR *mjcr;
- if (!update_db) {
- return 1;
- }
mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
if (!mjcr) {
Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
tm_decode(&dt, &tm);
jr->JobId = mjcr->JobId;
jr->JobStatus = JS_Terminated; /* ***FIXME*** need to add to EOS label */
+ mjcr->JobStatus = JS_Terminated;
jr->EndTime = mktime(&tm);
+ mjcr->end_time = jr->EndTime;
jr->JobFiles = elabel->JobFiles;
jr->JobBytes = elabel->JobBytes;
jr->VolSessionId = rec->VolSessionId;
jr->VolSessionTime = rec->VolSessionTime;
jr->JobTDate = (btime_t)mjcr->start_time;
jr->ClientId = mjcr->ClientId;
+
+ if (!update_db) {
+ free_jcr(mjcr);
+ return 1;
+ }
+
if (!db_update_job_end_record(db, jr)) {
Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
free_jcr(mjcr);
return 0;
}
if (verbose) {
- Pmsg1(000, _("Updated Job termination record for JobId: %d\n"), jr->JobId);
+ Pmsg1(000, _("Updated Job termination record for JobId: %u\n"), jr->JobId);
+ }
+ if (verbose > 1) {
+ char *term_msg;
+ static char term_code[70];
+ char sdt[50], edt[50];
+ char ec1[30], ec2[30], ec3[30];
+
+ switch (mjcr->JobStatus) {
+ case JS_Terminated:
+ term_msg = _("Backup OK");
+ break;
+ case JS_FatalError:
+ case JS_ErrorTerminated:
+ term_msg = _("*** Backup Error ***");
+ break;
+ case JS_Cancelled:
+ term_msg = _("Backup Cancelled");
+ break;
+ default:
+ term_msg = term_code;
+ sprintf(term_code, _("Job Termination code: %d"), mjcr->JobStatus);
+ break;
+ }
+ bstrftime(sdt, sizeof(sdt), mjcr->start_time);
+ bstrftime(edt, sizeof(edt), mjcr->end_time);
+ Pmsg14(000, _("%s\n\
+JobId: %d\n\
+Job: %s\n\
+FileSet: %s\n\
+Backup Level: %s\n\
+Client: %s\n\
+Start time: %s\n\
+End time: %s\n\
+Files Written: %s\n\
+Bytes Written: %s\n\
+Volume Session Id: %d\n\
+Volume Session Time: %d\n\
+Last Volume Bytes: %s\n\
+Termination: %s\n\n"),
+ edt,
+ mjcr->JobId,
+ mjcr->Job,
+ mjcr->fileset_name,
+ job_level_to_str(mjcr->JobLevel),
+ mjcr->client_name,
+ sdt,
+ edt,
+ edit_uint64_with_commas(mjcr->JobFiles, ec1),
+ edit_uint64_with_commas(mjcr->JobBytes, ec2),
+ mjcr->VolSessionId,
+ mjcr->VolSessionTime,
+ edit_uint64_with_commas(mr.VolBytes, ec3),
+ term_msg);
}
free_jcr(mjcr);
return 1;
{
JOBMEDIA_DBR jmr;
- if (!update_db) {
- return 1;
- }
+ mjcr->EndBlock = dev->block_num;
+ mjcr->EndFile = dev->file;
+
memset(&jmr, 0, sizeof(jmr));
jmr.JobId = mjcr->JobId;
jmr.MediaId = mr.MediaId;
jmr.FirstIndex = mjcr->VolFirstFile;
jmr.LastIndex = mjcr->FileIndex;
- jmr.StartFile = mjcr->start_file;
- jmr.EndFile = mjcr->end_file;
- jmr.StartBlock = mjcr->start_block;
- jmr.EndBlock = mjcr->end_block;
+ jmr.StartFile = mjcr->StartFile;
+ jmr.EndFile = mjcr->EndFile;
+ jmr.StartBlock = mjcr->StartBlock;
+ jmr.EndBlock = mjcr->EndBlock;
+
+
+ if (!update_db) {
+ return 1;
+ }
if (!db_create_jobmedia_record(db, &jmr)) {
Pmsg1(0, _("Could not create JobMedia record. ERR=%s\n"), db_strerror(db));
return 1;
}
+/*
+ * Simulate the database call that updates the MD5 record
+ */
+static int update_MD5_record(B_DB *db, char *MD5buf, DEV_RECORD *rec)
+{
+ JCR *mjcr;
+
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return 0;
+ }
+
+ if (!update_db) {
+ free_jcr(mjcr);
+ return 1;
+ }
+
+ if (!db_add_MD5_to_file_record(db, mjcr->FileId, MD5buf)) {
+ Pmsg1(0, _("Could not add MD5 to File record. ERR=%s\n"), db_strerror(db));
+ free_jcr(mjcr);
+ return 0;
+ }
+ if (verbose > 1) {
+ Pmsg0(000, _("Updated MD5 record\n"));
+ }
+ free_jcr(mjcr);
+ return 1;
+}
+
+
/*
* Create a JCR as if we are really starting the job
*/
-static void create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
+static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
{
+ JCR *jobjcr;
/*
* Transfer as much as possible to the Job JCR. Most important is
* the JobId and the ClientId.
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
attach_jcr_to_device(dev, jobjcr);
+ return jobjcr;
}
/* Dummies to replace askdir.c */
if (verbose) {
Pmsg1(000, "create JobMedia for Job %s\n", mjcr->Job);
}
- mjcr->end_block = dev->block_num;
- mjcr->end_file = dev->file;
+ mjcr->EndBlock = dev->block_num;
+ mjcr->EndFile = dev->file;
if (!create_jobmedia_record(db, mjcr)) {
Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
dev->VolCatInfo.VolCatName, mjcr->Job);
break;
}
} else {
- if (lseek(dev->fd, 0, SEEK_SET) < 0) {
+ if (lseek(dev->fd, (off_t)0, SEEK_SET) < 0) {
dev->dev_errno = errno;
Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
dev->dev_name, strerror(dev->dev_errno));
struct mtop mt_com;
struct mtget mt_stat;
int stat = 0;
- int32_t pos;
+ off_t pos;
Dmsg0(29, "eod_dev\n");
if (dev->state & ST_EOT) {
dev->block_num = dev->file = 0;
dev->file_bytes = 0;
if (!(dev->state & ST_TAPE)) {
- pos = lseek(dev->fd, 0, SEEK_END);
- if (pos > 0) {
+ pos = lseek(dev->fd, (off_t)0, SEEK_END);
+// Dmsg1(000, "====== Seek to %lld\n", pos);
+ if (pos >= 0) {
update_pos_dev(dev);
dev->state |= ST_EOT;
return 1;
#ifdef xxxx
struct mtget mt_stat;
#endif
- int64_t pos;
+ off_t pos;
int stat = 0;
if (dev->fd < 0) {
if (!(dev->state & ST_TAPE)) {
dev->file = 0;
dev->file_bytes = 0;
- pos = lseek(dev->fd, 0, SEEK_CUR);
+ pos = lseek(dev->fd, (off_t)0, SEEK_CUR);
if (pos < 0) {
- Dmsg1(200, "Seek error: ERR=%s\n", strerror(dev->dev_errno));
- pos = 0;
+ Dmsg1(000, "Seek error: ERR=%s\n", strerror(dev->dev_errno));
dev->dev_errno = errno;
Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
dev->dev_name, strerror(dev->dev_errno));
} else {
stat = 1;
+ dev->file_bytes = pos;
}
return stat;
}
char *errmsg; /* nicely edited error message */
uint32_t block_num; /* current block number base 0 */
uint32_t file; /* current file number base 0 */
- uint32_t file_bytes; /* bytes in this file */
+ uint64_t file_bytes; /* bytes in this file */
uint32_t LastBlockNumWritten; /* last block written */
uint32_t min_block_size; /* min block size */
uint32_t max_block_size; /* max block size */
Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
Dmsg1(100, "create JobMedia for Job %s\n", mjcr->Job);
- mjcr->end_block = dev->block_num;
- mjcr->end_file = dev->file;
+ mjcr->EndBlock = dev->block_num;
+ mjcr->EndFile = dev->file;
if (!dir_create_jobmedia_record(mjcr)) {
Jmsg(mjcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
dev->VolCatInfo.VolCatName, mjcr->Job);
free_block(label_blk);
for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
/* Set new start/end positions */
- mjcr->start_block = dev->block_num;
- mjcr->start_file = dev->file;
+ mjcr->StartBlock = dev->block_num;
+ mjcr->StartFile = dev->file;
mjcr->VolFirstFile = mjcr->JobFiles;
mjcr->run_time += time(NULL) - wait_time; /* correct run time */
}
extern char my_name[];
extern int debug_level;
-char BaculaId[] = "Bacula 0.9 mortal\n";
-unsigned int BaculaTapeVersion = 10;
-unsigned int OldCompatableBaculaTapeVersion = 9;
-
-
/*
* Read the volume label
*
{
char *VolName = jcr->VolumeName;
DEV_RECORD *record;
+ int ok = 0;
Dmsg2(30, "Enter read_volume_label device=%s vol=%s\n",
dev_name(dev), VolName);
/* Read the device label block */
record = new_record();
Dmsg0(90, "Big if statement in read_volume_label\n");
- if (!read_block_from_dev(dev, block) ||
- !read_record_from_block(block, record) ||
- !unser_volume_label(dev, record) ||
- strcmp(dev->VolHdr.Id, BaculaId) != 0) {
-
+ if (!read_block_from_dev(dev, block)) {
Mmsg(&jcr->errmsg, _("Volume on %s is not a Bacula labeled Volume, \
because:\n %s"), dev_name(dev), strerror_dev(dev));
+ } else if (!read_record_from_block(block, record)) {
+ Mmsg(&jcr->errmsg, _("Could not read Volume label from block.\n"));
+ } else if (!unser_volume_label(dev, record)) {
+ Mmsg(&jcr->errmsg, _("Could not unserialize Volume label: %s\n"),
+ strerror_dev(dev));
+ } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0) {
+ Mmsg(&jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
+ } else {
+ ok = 1;
+ }
+ if (!ok) {
free_record(record);
empty_block(block);
rewind_dev(dev);
rewind_dev(dev);
if (dev->VolHdr.VerNum != BaculaTapeVersion &&
- dev->VolHdr.VerNum != OldCompatableBaculaTapeVersion) {
+ dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
+ dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
Mmsg(&jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
dev_name(dev), BaculaTapeVersion, dev->VolHdr.VerNum);
return jcr->label_status = VOL_VERSION_ERROR;
unser_uint32(Fld(VerNum));
+ if (Fld(VerNum) >= 11) {
+ unser_btime(Fld(label_btime));
+ unser_btime(Fld(write_btime));
+ } else { /* old way */
unser_float64(Fld(label_date));
unser_float64(Fld(label_time));
- unser_float64(Fld(write_date));
- unser_float64(Fld(write_time));
+ }
+ unser_float64(Fld(write_date)); /* Unused with VerNum >= 11 */
+ unser_float64(Fld(write_time)); /* Unused with VerNum >= 11 */
unser_string(Fld(VolName));
unser_string(Fld(PrevVolName));
ser_uint32(Fld(VerNum));
+ if (Fld(VerNum >= 11)) {
+ ser_btime(Fld(label_btime));
+ Fld(write_btime) = get_current_btime();
+ ser_btime(Fld(write_btime));
+ Fld(write_date) = 0;
+ Fld(write_time) = 0;
+ } else {
ser_float64(Fld(label_date));
ser_float64(Fld(label_time));
-
get_current_time(&dt);
Fld(write_date) = dt.julian_day_number;
Fld(write_time) = dt.julian_day_fraction;
+ }
- ser_float64(Fld(write_date));
- ser_float64(Fld(write_time));
+ ser_float64(Fld(write_date)); /* unused if VerNum >= 11 */
+ ser_float64(Fld(write_time)); /* unused if VerNum >= 11 */
ser_string(Fld(VolName));
ser_string(Fld(PrevVolName));
strcpy(dev->VolHdr.PoolType, "Backup");
/* Put label time/date in header */
+ if (BaculaTapeVersion >= 11) {
+ dev->VolHdr.label_btime = get_current_btime();
+ dev->VolHdr.label_date = 0;
+ dev->VolHdr.label_time = 0;
+ } else {
get_current_time(&dt);
dev->VolHdr.label_date = dt.julian_day_number;
dev->VolHdr.label_time = dt.julian_day_fraction;
+ }
strcpy(dev->VolHdr.LabelProg, my_name);
sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, DATE);
block = new_block(dev);
memset(&rec, 0, sizeof(rec));
- rec.data = (char *) get_memory(SER_LENGTH_Volume_Label);
+ rec.data = get_memory(SER_LENGTH_Volume_Label);
create_volume_label_record(jcr, dev, &rec);
rec.Stream = 0;
ser_uint32(jcr->JobId);
+ if (BaculaTapeVersion >= 11) {
+ ser_btime(get_current_btime());
+ ser_float64(0);
+ } else {
get_current_time(&dt);
ser_float64(dt.julian_day_number);
ser_float64(dt.julian_day_fraction);
+ }
ser_string(jcr->pool_name);
ser_string(jcr->pool_type);
if (label == EOS_LABEL) {
ser_uint32(jcr->JobFiles);
ser_uint64(jcr->JobBytes);
- ser_uint32(jcr->start_block);
- ser_uint32(jcr->end_block);
- ser_uint32(jcr->start_file);
- ser_uint32(jcr->end_file);
+ ser_uint32(jcr->StartBlock);
+ ser_uint32(jcr->EndBlock);
+ ser_uint32(jcr->StartFile);
+ ser_uint32(jcr->EndFile);
ser_uint32(jcr->JobErrors);
+ /* Added in VerNum 11 */
+ ser_uint32(jcr->JobStatus);
}
ser_end(rec->data, SER_LENGTH_Session_Label);
rec->data_len = ser_length(rec->data);
Dmsg1(90, "session_label record=%x\n", rec);
switch (label) {
case SOS_LABEL:
- jcr->start_block = dev->block_num;
- jcr->start_file = dev->file;
+ jcr->StartBlock = dev->block_num;
+ jcr->StartFile = dev->file;
break;
case EOS_LABEL:
- jcr->end_block = dev->block_num;
- jcr->end_file = dev->file;
+ jcr->EndBlock = dev->block_num;
+ jcr->EndFile = dev->file;
break;
default:
Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
void dump_volume_label(DEVICE *dev)
{
- int dbl;
+ int dbl = debug_level;
uint32_t File;
char *LabelType, buf[30];
struct tm tm;
struct date_time dt;
+ debug_level = 1;
File = dev->file;
switch (dev->VolHdr.LabelType) {
case PRE_LABEL:
case EOS_LABEL:
LabelType = "EOS_LABEL";
break;
+ case EOT_LABEL:
+ goto bail_out;
default:
LabelType = buf;
sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
}
- dbl = debug_level;
- debug_level = 1;
Pmsg11(-1, "\nVolume Label:\n\
Id : %s\
VerNo : %d\n\
dev->VolHdr.PoolName, dev->VolHdr.MediaType,
dev->VolHdr.PoolType, dev->VolHdr.HostName);
+ if (dev->VolHdr.VerNum >= 11) {
+ char dt[50];
+ bstrftime(dt, sizeof(dt), (time_t)dev->VolHdr.label_btime);
+ Pmsg1(-1, "Date label written: %s\n", dt);
+ } else {
dt.julian_day_number = dev->VolHdr.label_date;
dt.julian_day_fraction = dev->VolHdr.label_time;
tm_decode(&dt, &tm);
Pmsg5(-1, "\
Date label written: %04d-%02d-%02d at %02d:%02d\n",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
+ }
+
+bail_out:
debug_level = dbl;
}
unser_string(label->Id);
unser_uint32(label->VerNum);
unser_uint32(label->JobId);
+ if (label->VerNum >= 11) {
+ unser_btime(label->write_btime);
+ } else {
unser_float64(label->write_date);
+ }
unser_float64(label->write_time);
unser_string(label->PoolName);
unser_string(label->PoolType);
unser_string(label->JobName);
unser_string(label->ClientName);
- if (label->VerNum > 9) {
+ if (label->VerNum >= 10) {
unser_string(label->Job); /* Unique name of this Job */
unser_string(label->FileSetName);
unser_uint32(label->JobType);
if (rec->FileIndex == EOS_LABEL) {
unser_uint32(label->JobFiles);
unser_uint64(label->JobBytes);
- unser_uint32(label->start_block);
- unser_uint32(label->end_block);
- unser_uint32(label->start_file);
- unser_uint32(label->end_file);
+ unser_uint32(label->StartBlock);
+ unser_uint32(label->EndBlock);
+ unser_uint32(label->StartFile);
+ unser_uint32(label->EndFile);
unser_uint32(label->JobErrors);
+ if (label->VerNum >= 11) {
+ unser_uint32(label->JobStatus);
+ } else {
+ label->JobStatus = JS_Terminated; /* kludge */
+ }
}
return 1;
}
SESSION_LABEL label;
char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
-
unser_session_label(&label, rec);
dbl = debug_level;
debug_level = 1;
- Pmsg6(-1, "\n%s Record:\n\
+ Pmsg7(-1, "\n%s Record:\n\
JobId : %d\n\
+VerNum : %d\n\
PoolName : %s\n\
PoolType : %s\n\
JobName : %s\n\
ClientName : %s\n\
-", type,
- label.JobId, label.PoolName, label.PoolType,
+", type, label.JobId, label.VerNum,
+ label.PoolName, label.PoolType,
label.JobName, label.ClientName);
if (label.VerNum >= 10) {
}
if (rec->FileIndex == EOS_LABEL) {
- Pmsg7(-1, "\
+ Pmsg8(-1, "\
JobFiles : %s\n\
JobBytes : %s\n\
StartBlock : %s\n\
StartFile : %s\n\
EndFile : %s\n\
JobErrors : %s\n\
+JobStatus : %c\n\
",
edit_uint64_with_commas(label.JobFiles, ec1),
edit_uint64_with_commas(label.JobBytes, ec2),
- edit_uint64_with_commas(label.start_block, ec3),
- edit_uint64_with_commas(label.end_block, ec4),
- edit_uint64_with_commas(label.start_file, ec5),
- edit_uint64_with_commas(label.end_file, ec6),
- edit_uint64_with_commas(label.JobErrors, ec7));
+ edit_uint64_with_commas(label.StartBlock, ec3),
+ edit_uint64_with_commas(label.EndBlock, ec4),
+ edit_uint64_with_commas(label.StartFile, ec5),
+ edit_uint64_with_commas(label.EndFile, ec6),
+ edit_uint64_with_commas(label.JobErrors, ec7),
+ label.JobStatus);
}
+ if (label.VerNum >= 11) {
+ char dt[50];
+ bstrftime(dt, sizeof(dt), (time_t)label.write_btime);
+ Pmsg1(-1, _("Date written : %s\n"), dt);
+ } else {
dt.julian_day_number = label.write_date;
dt.julian_day_fraction = label.write_time;
tm_decode(&dt, &tm);
- Pmsg5(-1, "\
-Date written : %04d-%02d-%02d at %02d:%02d\n",
+ Pmsg5(-1, _("\
+Date written : %04d-%02d-%02d at %02d:%02d\n"),
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
+ }
debug_level = dbl;
}
debug_level = 1;
switch (rec->FileIndex) {
case PRE_LABEL:
- type = "Fresh Volume";
+ type = _("Fresh Volume");
break;
case VOL_LABEL:
- type = "Volume";
+ type = _("Volume");
break;
case SOS_LABEL:
- type = "Begin Session";
+ type = _("Begin Session");
break;
case EOS_LABEL:
- type = "End Session";
+ type = _("End Session");
break;
case EOM_LABEL:
- type = "End of Media";
+ type = _("End of Media");
+ break;
+ case EOT_LABEL:
+ type = ("End of Tape");
break;
default:
- type = "Unknown";
+ type = _("Unknown");
break;
}
if (verbose) {
dump_session_label(rec, type);
break;
case EOM_LABEL:
- Pmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+ Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
break;
+ case EOT_LABEL:
+ Pmsg0(-1, _("End of physical tape.\n"));
+ break;
default:
- Pmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+ Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
break;
}
} else {
- Pmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+ switch (rec->FileIndex) {
+ case SOS_LABEL:
+ case EOS_LABEL:
+ SESSION_LABEL label;
+ unser_session_label(&label, rec);
+ Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c \
+Type=%c\n",
+ type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
+ label.JobLevel, label.JobType);
+ break;
+ case EOM_LABEL:
+ case PRE_LABEL:
+ case VOL_LABEL:
+ default:
+ Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+ break;
+ case EOT_LABEL:
+ break;
+ }
}
debug_level = dbl;
}
if (!read_block_from_device(dev, block)) {
Dmsg0(20, "!read_record()\n");
if (dev->state & ST_EOT) {
- DEV_RECORD *record;
+ DEV_RECORD *record = new_record();
+
Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
block->BlockNumber, rec->remainder);
if (!mount_cb(jcr, dev, block)) {
Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
block->BlockNumber, rec->remainder);
ok = FALSE;
+ /*
+ * Create EOT Label so that Media record may
+ * be properly updated because this is the last
+ * tape.
+ */
+ record->FileIndex = EOT_LABEL;
+ record->File = dev->file;
+ record->Block = rec->Block; /* return block last read */
+ record_cb(jcr, dev, block, record);
+ free_record(record);
break;
}
Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
* and pass it off to the callback routine, then continue
* most likely reading the previous record.
*/
- record = new_record();
read_block_from_device(dev, block);
read_record_from_block(block, record);
get_session_record(dev, record, &sessrec);
+ record->File = dev->file;
record_cb(jcr, dev, block, record);
free_record(record);
goto next_record;
block->BlockNumber, rec->remainder);
break;
}
+ rec->File = dev->file;
Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
block->BlockNumber, rec->remainder);
/*
break; /* read second part of record */
}
record_cb(jcr, dev, block, rec);
-
}
}
if (verbose) {
*/
if (rec->remainder == 0) {
/* Require enough room to write a full header */
- if (remlen >= RECHDR_LENGTH) {
- ser_begin(block->bufp, RECHDR_LENGTH);
+ if (remlen >= WRITE_RECHDR_LENGTH) {
+ ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
+ if (BLOCK_VER == 1) {
ser_uint32(rec->VolSessionId);
ser_uint32(rec->VolSessionTime);
+ } else {
+ block->VolSessionId = rec->VolSessionId;
+ block->VolSessionTime = rec->VolSessionTime;
+ }
ser_int32(rec->FileIndex);
ser_int32(rec->Stream);
ser_uint32(rec->data_len);
- ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf += RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += WRITE_RECHDR_LENGTH;
+ block->binbuf += WRITE_RECHDR_LENGTH;
+ remlen -= WRITE_RECHDR_LENGTH;
rec->remainder = rec->data_len;
} else {
- rec->remainder = rec->data_len + RECHDR_LENGTH;
+ rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
sm_check(__FILE__, __LINE__, False);
return 0;
}
* of a previous partially written record, we store the
* Stream as -Stream in the record header.
*/
- ser_begin(block->bufp, RECHDR_LENGTH);
+ ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
+ if (BLOCK_VER == 1) {
ser_uint32(rec->VolSessionId);
ser_uint32(rec->VolSessionTime);
+ } else {
+ block->VolSessionId = rec->VolSessionId;
+ block->VolSessionTime = rec->VolSessionTime;
+ }
ser_int32(rec->FileIndex);
if (rec->remainder > rec->data_len) {
ser_int32(rec->Stream); /* normal full header */
ser_int32(-rec->Stream); /* mark this as a continuation record */
ser_uint32(rec->remainder); /* bytes to do */
}
- ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
/* Require enough room to write a full header */
- ASSERT(remlen >= RECHDR_LENGTH);
+ ASSERT(remlen >= WRITE_RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf += RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += WRITE_RECHDR_LENGTH;
+ block->binbuf += WRITE_RECHDR_LENGTH;
+ remlen -= WRITE_RECHDR_LENGTH;
}
if (remlen == 0) {
sm_check(__FILE__, __LINE__, False);
remlen = block->buf_len - block->binbuf;
if (rec->remainder == 0) {
- if (remlen >= RECHDR_LENGTH) {
- remlen -= RECHDR_LENGTH;
+ if (remlen >= WRITE_RECHDR_LENGTH) {
+ remlen -= WRITE_RECHDR_LENGTH;
rec->remainder = rec->data_len;
} else {
return 0;
int32_t FileIndex;
int32_t Stream;
uint32_t data_bytes;
+ uint32_t rhl;
remlen = block->binbuf;
+ rec->Block = block->BlockNumber;
/* Clear state flags */
rec->state = 0;
* Get the header. There is always a full header,
* otherwise we find it in the next block.
*/
- if (remlen >= RECHDR_LENGTH) {
- Dmsg3(90, "read_record_block: remlen=%d data_len=%d rem=%d\n",
- remlen, rec->data_len, rec->remainder);
+ Dmsg3(100, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
+ block->block_len);
+ if (block->BlockVer == 1) {
+ rhl = RECHDR1_LENGTH;
+ } else {
+ rhl = RECHDR2_LENGTH;
+ }
+ if (remlen >= rhl) {
+ Dmsg4(90, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n",
+ remlen, rec->data_len, rec->remainder, block->BlockVer);
- unser_begin(block->bufp, RECHDR_LENGTH);
+ unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
+ if (block->BlockVer == 1) {
unser_uint32(VolSessionId);
unser_uint32(VolSessionTime);
+ } else {
+ VolSessionId = block->VolSessionId;
+ VolSessionTime = block->VolSessionTime;
+ }
unser_int32(FileIndex);
unser_int32(Stream);
unser_uint32(data_bytes);
- ASSERT(unser_length(block->bufp) == RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf -= RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += rhl;
+ block->binbuf -= rhl;
+ remlen -= rhl;
/* If we are looking for more (remainder!=0), we reject anything
* where the VolSessionId and VolSessionTime don't agree
rec->VolSessionTime = VolSessionTime;
rec->FileIndex = FileIndex;
- Dmsg6(90, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%d\n\
+ Dmsg6(100, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n\
remlen=%d data_len=%d\n",
FI_to_ascii(rec->FileIndex), rec->VolSessionId,
stream_to_ascii(rec->Stream), data_bytes, remlen, rec->data_len);
#define VOL_LABEL_ERROR 7 /* Bad label type */
-/* Length of Record Header (5 * 4 bytes) */
-#define RECHDR_LENGTH 20
+/* See block.h for RECHDR_LENGTH */
/*
* This is the Media structure for a record header.
* NB: when it is written it is serialized.
- */
-typedef struct s_record_hdr {
+
uint32_t VolSessionId;
uint32_t VolSessionTime;
+
+ * The above 8 bytes are only written in a BB01 block, BB02
+ * and later blocks contain these values in the block header
+ * rather than the record header.
+
int32_t FileIndex;
int32_t Stream;
uint32_t data_len;
-} RECORD_HDR;
+
+ */
/* Record state bit definitions */
#define REC_NO_HEADER 0x01 /* No header read */
uint32_t data_len; /* current record length */
uint32_t remainder; /* remaining bytes to read/write */
uint32_t state; /* state bits */
- uint8_t ser_buf[RECHDR_LENGTH]; /* serialized record header goes here */
+ uint8_t ser_buf[WRITE_RECHDR_LENGTH]; /* serialized record header goes here */
POOLMEM *data; /* Record data. This MUST be a memory pool item */
} DEV_RECORD;
#define EOM_LABEL -3 /* Writen at end of tape */
#define SOS_LABEL -4 /* Start of Session */
#define EOS_LABEL -5 /* End of Session */
-
+#define EOT_LABEL -6 /* End of physical tape (2 eofs) */
/*
- * Volume Label Record
+ * Volume Label Record. This is the in-memory definition. The
+ * tape definition is defined in the serialization code itself
+ * ser_volume_label() and unser_volume_label() and is slightly different.
*/
+
+
struct Volume_Label {
/*
* The first items in this structure are saved
uint32_t VerNum; /* Label version number */
+ /* VerNum <= 10 */
float64_t label_date; /* Date tape labeled */
float64_t label_time; /* Time tape labeled */
+
+ /* VerNum >= 11 */
+ btime_t label_btime; /* tdate tape labeled */
+ btime_t write_btime; /* tdate tape written */
+
+ /* Unused with VerNum >= 11 */
float64_t write_date; /* Date this label written */
float64_t write_time; /* Time this label written */
uint32_t JobId; /* Job id */
uint32_t VolumeIndex; /* Sequence no of volume for this job */
+ /* VerNum >= 11 */
+ btime_t write_btime; /* Tdate this label written */
+
+ /* VerNum < 11 */
float64_t write_date; /* Date this label written */
+
+ /* Unused VerNum >= 11 */
float64_t write_time; /* Time this label written */
char PoolName[MAX_NAME_LENGTH]; /* Pool name */
/* The remainder are part of EOS label only */
uint32_t JobFiles;
uint64_t JobBytes;
- uint32_t start_block;
- uint32_t end_block;
- uint32_t start_file;
- uint32_t end_file;
+ uint32_t StartBlock;
+ uint32_t EndBlock;
+ uint32_t StartFile;
+ uint32_t EndFile;
uint32_t JobErrors;
+ uint32_t JobStatus; /* Job status */
};
typedef struct Session_Label SESSION_LABEL;
/* */
#define VERSION "1.26"
#define VSTRING "1"
-#define DATE "25 September 2002"
-#define LSMDATE "25Sep02"
+#define DATE "4 October 2002"
+#define LSMDATE "04Oct02"
/* Debug flags */
#define DEBUG 1