From: Kern Sibbald Date: Sun, 6 Oct 2002 10:20:03 +0000 (+0000) Subject: Vacation updates -- see kes06Oct02 X-Git-Tag: Release-1.26~7 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=61985ad10389ae63b92bba34b35e095347520a5c;hp=6addd2c0541a270fc5ea2fa1b7c9900aea4cde8a;p=bacula%2Fbacula Vacation updates -- see kes06Oct02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@164 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/README b/bacula/README index d028fe86f6..5c5d9b113c 100644 --- a/bacula/README +++ b/bacula/README @@ -15,7 +15,8 @@ the manual, which can be found in Barring reading the manual, you might try the following: -CFLAGS="-g -Wall" \ +To Configure it: + ./configure \ --sbindir=$HOME/bacula/bin \ --sysconfdir=$HOME/bacula/bin \ @@ -26,11 +27,10 @@ CFLAGS="-g -Wall" \ --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 @@ -39,3 +39,19 @@ Build Bacula 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. diff --git a/bacula/kernstodo b/bacula/kernstodo index fb7a6ed653..b1cdb068c4 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -27,6 +27,7 @@ From Chuck: 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". @@ -609,4 +610,3 @@ Done: (see kernsdone for more) Another try with tape mounted and Job hung in Director. - Write updated bootstrap after every Job. - diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index d7d61ed4c1..a76333b92f 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -240,6 +240,7 @@ extern void _v(char *file, int line, pthread_mutex_t *m); #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 */ diff --git a/bacula/src/cats/drop_bacula_tables.in b/bacula/src/cats/drop_bacula_tables.in index 658d290940..ebfb0be8a1 100755 --- a/bacula/src/cats/drop_bacula_tables.in +++ b/bacula/src/cats/drop_bacula_tables.in @@ -5,6 +5,8 @@ # 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 diff --git a/bacula/src/cats/make_bacula_tables.in b/bacula/src/cats/make_bacula_tables.in index 726c8ff58a..b4f5d19ad6 100755 --- a/bacula/src/cats/make_bacula_tables.in +++ b/bacula/src/cats/make_bacula_tables.in @@ -4,7 +4,9 @@ # 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 diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index af4690131f..66e63aea3a 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -314,11 +314,13 @@ int db_get_job_record(B_DB *mdb, JOB_DBR *jr) 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); } @@ -343,6 +345,8 @@ 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); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index dc4d775ba1..fd5c472363 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -192,10 +192,11 @@ struct s_jcr { 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 */ diff --git a/bacula/src/lib/btime.c b/bacula/src/lib/btime.c index dbd7cd8e1a..3ad074a8b1 100644 --- a/bacula/src/lib/btime.c +++ b/bacula/src/lib/btime.c @@ -55,6 +55,11 @@ void get_current_time(struct date_time *dt) #endif } +btime_t get_current_btime() +{ + return (btime_t)time(NULL); +} + /* date_encode -- Encode civil date as a Julian day number. */ diff --git a/bacula/src/lib/btime.h b/bacula/src/lib/btime.h index 3a324d1881..ced7cae2cc 100644 --- a/bacula/src/lib/btime.h +++ b/bacula/src/lib/btime.h @@ -83,4 +83,6 @@ extern void tm_encode(struct date_time *dt, struct tm *tm); 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 */ diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 911a7a2e47..1f746a32d7 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -739,7 +739,7 @@ void dispatch_message(void *vjcr, int type, int level, char *msg) 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; diff --git a/bacula/src/lib/serial.c b/bacula/src/lib/serial.c index 1b2b021937..b11e5a50a3 100644 --- a/bacula/src/lib/serial.c +++ b/bacula/src/lib/serial.c @@ -120,6 +120,27 @@ void serial_uint64(uint8_t * * const ptr, const uint64_t v) } +/* 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 @@ -196,53 +217,54 @@ uint32_t unserial_uint32(uint8_t * * const ptr) 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 diff --git a/bacula/src/lib/serial.h b/bacula/src/lib/serial.h index f3adaab0d8..a7a5c52572 100644 --- a/bacula/src/lib/serial.h +++ b/bacula/src/lib/serial.h @@ -31,6 +31,7 @@ extern void serial_int32(uint8_t * * ptr, int32_t v); 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); @@ -39,6 +40,7 @@ extern int32_t unserial_int32(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); @@ -97,6 +99,9 @@ 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) @@ -135,6 +140,9 @@ extern int unserial_string(uint8_t * ptr, char * str); /* 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) diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 92ba70d363..4c9e03e6b3 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -36,7 +36,7 @@ */ /* - * 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 */ @@ -76,6 +76,9 @@ int string_to_btime(char *str, btime_t *value) } +/* + * Edit a btime "duration" into ASCII + */ char *edit_btime(btime_t val, char *buf) { char mybuf[30]; diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index a9152b9380..70e97574d9 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -27,9 +27,6 @@ #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"; @@ -211,14 +208,17 @@ int do_append_data(JCR *jcr) } } /* - *******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)); diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index c7eb7e43ab..73120bf44b 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -183,8 +183,8 @@ int dir_create_jobmedia_record(JCR *jcr) 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"); diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index ea1335509c..cd6a0a1064 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -48,14 +48,25 @@ void dump_block(DEV_BLOCK *b, char *msg) 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); @@ -67,20 +78,21 @@ void dump_block(DEV_BLOCK *b, char *msg) 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; } - } /* @@ -113,6 +125,7 @@ DEV_BLOCK *new_block(DEVICE *dev) return NULL; } empty_block(block); + block->BlockVer = BLOCK_VER; /* default write version */ Dmsg1(90, "Returning new block=%x\n", block); return block; } @@ -131,7 +144,7 @@ void free_block(DEV_BLOCK *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; @@ -149,19 +162,22 @@ static void ser_block_header(DEV_BLOCK *block) 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 */ } /* @@ -179,22 +195,39 @@ static int unser_block_header(DEVICE *dev, DEV_BLOCK *block) 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 */ @@ -205,13 +238,13 @@ static int unser_block_header(DEVICE *dev, DEV_BLOCK *block) } 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; @@ -256,7 +289,7 @@ int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) */ 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 @@ -267,12 +300,12 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block) /* 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; } /* @@ -318,7 +351,8 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block) } 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 @@ -344,15 +378,17 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block) 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); @@ -368,10 +404,8 @@ int read_block_from_device(DEVICE *dev, DEV_BLOCK *block) { 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; @@ -384,10 +418,12 @@ int read_block_from_device(DEVICE *dev, DEV_BLOCK *block) */ 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. @@ -401,6 +437,7 @@ int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block) 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; @@ -415,7 +452,7 @@ int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block) } /* 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 */ @@ -448,14 +485,19 @@ int read_block_from_dev(DEVICE *dev, DEV_BLOCK *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", diff --git a/bacula/src/stored/block.h b/bacula/src/stored/block.h index b6b620689f..ca265dea7c 100644 --- a/bacula/src/stored/block.h +++ b/bacula/src/stored/block.h @@ -34,21 +34,43 @@ #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. @@ -70,6 +92,9 @@ typedef struct s_dev_block { 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 diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index aa2bc563dc..61da289ae2 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -48,8 +48,6 @@ static SESSION_LABEL sessrec; static uint32_t num_files = 0; static long record_file_index; -extern char BaculaId[]; - static FF_PKT ff; static BSR *bsr = NULL; @@ -60,6 +58,7 @@ static void usage() "\nVersion: " VERSION " (" DATE ")\n\n" "Usage: bls [-d debug_level] \n" " -b specify a bootstrap file\n" +" -d specify debug level\n" " -e exclude list\n" " -i include list\n" " -j list jobs\n" @@ -225,7 +224,7 @@ static void do_blocks(char *infname) } 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"); @@ -252,14 +251,18 @@ static void do_blocks(char *infname) 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); } diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index de17a011c0..678718ae74 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -37,24 +37,26 @@ /* 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; @@ -68,6 +70,7 @@ static JOB_DBR jr; static CLIENT_DBR cr; static FILESET_DBR fsr; static ATTR_DBR ar; +static FILE_DBR fr; static SESSION_LABEL label; static SESSION_LABEL elabel; @@ -77,6 +80,8 @@ static char *db_password = ""; 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() { @@ -85,9 +90,11 @@ static void usage() "Usage: bscan [-d debug_level] \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" @@ -103,7 +110,7 @@ int main (int argc, char *argv[]) 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); @@ -114,6 +121,10 @@ int main (int argc, char *argv[]) debug_level = 1; break; + case 'm': + update_vol_info = 1; + break; + case 'n': db_name = optarg; break; @@ -126,6 +137,10 @@ int main (int argc, char *argv[]) db_password = optarg; break; + case 'r': + list_records = 1; + break; + case 's': update_db = 1; break; @@ -154,7 +169,7 @@ int main (int argc, char *argv[]) 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")); @@ -169,7 +184,7 @@ int main (int argc, char *argv[]) do_scan(argv[0]); - free_jcr(jcr); + free_jcr(bjcr); return 0; } @@ -177,7 +192,7 @@ int main (int argc, char *argv[]) static void do_scan(char *devname) { - dev = setup_to_read_device(jcr); + dev = setup_to_read_device(bjcr); if (!dev) { exit(1); } @@ -191,11 +206,12 @@ static void do_scan(char *devname) 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); @@ -203,13 +219,26 @@ static void do_scan(char *devname) 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); @@ -249,6 +278,9 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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); @@ -263,42 +295,56 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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, @@ -326,27 +372,57 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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; } @@ -404,18 +480,51 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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); } @@ -449,21 +558,11 @@ static void dird_free_jcr(JCR *jcr) * 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; @@ -475,12 +574,18 @@ static int create_file_attributes_record(B_DB *db, char *fname, char *lname, int 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); } @@ -494,9 +599,7 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) { 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; @@ -507,6 +610,11 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) 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; @@ -516,21 +624,42 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) 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; @@ -566,12 +695,19 @@ static int create_fileset_record(B_DB *db, FILESET_DBR *fsr) 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; } @@ -581,17 +717,13 @@ static int create_fileset_record(B_DB *db, FILESET_DBR *fsr) * 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; @@ -607,24 +739,28 @@ static int create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label, 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; } /* @@ -638,9 +774,6 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, 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"), @@ -652,20 +785,81 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, 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; @@ -675,18 +869,23 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr) { 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)); @@ -699,11 +898,44 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr) 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. @@ -720,6 +952,7 @@ static void create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) jobjcr->VolSessionTime = rec->VolSessionTime; jobjcr->ClientId = jr->ClientId; attach_jcr_to_device(dev, jobjcr); + return jobjcr; } /* Dummies to replace askdir.c */ @@ -744,8 +977,8 @@ int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) 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); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index d1e4807859..1ed4cf398b 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -315,7 +315,7 @@ int rewind_dev(DEVICE *dev) 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)); @@ -336,7 +336,7 @@ eod_dev(DEVICE *dev) 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) { @@ -346,8 +346,9 @@ eod_dev(DEVICE *dev) 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; @@ -404,7 +405,7 @@ int update_pos_dev(DEVICE *dev) #ifdef xxxx struct mtget mt_stat; #endif - int64_t pos; + off_t pos; int stat = 0; if (dev->fd < 0) { @@ -418,15 +419,15 @@ int update_pos_dev(DEVICE *dev) 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; } diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 7f9025ae5d..83e794c1b2 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -147,7 +147,7 @@ typedef struct s_device { 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 */ diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index ecb5f189ea..e4cfe076b7 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -92,8 +92,8 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) 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); @@ -165,8 +165,8 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) 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 */ } diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 1570709b0a..bf7281b198 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -37,11 +37,6 @@ static void create_volume_label_record(JCR *jcr, DEVICE *dev, DEV_RECORD *rec); 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 * @@ -65,6 +60,7 @@ int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) { 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); @@ -100,13 +96,20 @@ int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* 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); @@ -118,7 +121,8 @@ because:\n %s"), dev_name(dev), strerror_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; @@ -191,10 +195,15 @@ int unser_volume_label(DEVICE *dev, DEV_RECORD *rec) 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)); @@ -264,15 +273,22 @@ static void create_volume_label_record(JCR *jcr, DEVICE *dev, DEV_RECORD *rec) 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)); @@ -326,9 +342,15 @@ static int create_volume_label(DEVICE *dev, char *VolName) 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); @@ -374,7 +396,7 @@ int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *Poo 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; @@ -427,9 +449,14 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label) 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); @@ -444,11 +471,13 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label) 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); @@ -467,12 +496,12 @@ int write_session_label(JCR *jcr, DEV_BLOCK *block, int label) 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); @@ -519,12 +548,13 @@ remainder=%d\n", jcr->JobId, 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: @@ -542,6 +572,8 @@ void dump_volume_label(DEVICE *dev) case EOS_LABEL: LabelType = "EOS_LABEL"; break; + case EOT_LABEL: + goto bail_out; default: LabelType = buf; sprintf(buf, "Unknown %d", dev->VolHdr.LabelType); @@ -549,8 +581,6 @@ void dump_volume_label(DEVICE *dev) } - dbl = debug_level; - debug_level = 1; Pmsg11(-1, "\nVolume Label:\n\ Id : %s\ VerNo : %d\n\ @@ -570,12 +600,20 @@ HostName : %s\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; } @@ -587,13 +625,17 @@ int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec) 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); @@ -602,11 +644,16 @@ int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec) 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; } @@ -620,18 +667,18 @@ static void dump_session_label(DEV_RECORD *rec, char *type) 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) { @@ -644,7 +691,7 @@ JobLevel : %c\n\ } if (rec->FileIndex == EOS_LABEL) { - Pmsg7(-1, "\ + Pmsg8(-1, "\ JobFiles : %s\n\ JobBytes : %s\n\ StartBlock : %s\n\ @@ -652,21 +699,29 @@ EndBlock : %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; } @@ -680,22 +735,25 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose) 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) { @@ -712,17 +770,38 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int 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; } diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index 4720fce987..90f508be80 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -56,13 +56,24 @@ int read_records(JCR *jcr, DEVICE *dev, 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), @@ -72,10 +83,10 @@ int read_records(JCR *jcr, DEVICE *dev, * 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; @@ -105,6 +116,7 @@ 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); /* @@ -157,7 +169,6 @@ next_record: break; /* read second part of record */ } record_cb(jcr, dev, block, rec); - } } if (verbose) { diff --git a/bacula/src/stored/record.c b/bacula/src/stored/record.c index 34dd68c6e8..991cc7ad9c 100644 --- a/bacula/src/stored/record.c +++ b/bacula/src/stored/record.c @@ -154,21 +154,25 @@ rem=%d remainder=%d\n", */ 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; } @@ -188,9 +192,14 @@ rem=%d remainder=%d\n", * 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 */ @@ -200,14 +209,13 @@ rem=%d remainder=%d\n", 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); @@ -269,8 +277,8 @@ int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec) 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; @@ -302,8 +310,10 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) 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; @@ -312,21 +322,32 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) * 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 @@ -359,7 +380,7 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) 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); diff --git a/bacula/src/stored/record.h b/bacula/src/stored/record.h index 601e9ee590..2f300b1e6e 100644 --- a/bacula/src/stored/record.h +++ b/bacula/src/stored/record.h @@ -40,20 +40,24 @@ #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 */ @@ -85,7 +89,7 @@ typedef struct s_dev_rec { 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; @@ -100,11 +104,15 @@ typedef struct s_dev_rec { #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 @@ -121,8 +129,15 @@ struct Volume_Label { 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 */ @@ -155,7 +170,13 @@ struct Session_Label { 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 */ @@ -169,11 +190,12 @@ struct Session_Label { /* 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; diff --git a/bacula/src/version.h b/bacula/src/version.h index e566b7bb3c..c2761e8a41 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #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