From: Kern Sibbald Date: Thu, 5 Sep 2002 13:14:26 +0000 (+0000) Subject: More SD tools cleanup X-Git-Tag: Release-1.26~22 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=021cd0d8f0f96f6200c1beba839b58b9f93519aa;p=bacula%2Fbacula More SD tools cleanup git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@149 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index c9af692fba..330dd0211e 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -42,14 +42,16 @@ TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \ acquire.o mount.o record.o stored_conf.o BLSOBJS = bls.o block.o device.o dev.o label.o match_bsr.o \ - acquire.o mount.o parse_bsr.o record.o butil.o + acquire.o mount.o parse_bsr.o record.o butil.o \ + read_record.o BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ - acquire.o mount.o match_bsr.o parse_bsr.o butil.o + acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ + read_record.o SCNOBJS = bscan.o block.o device.o dev.o label.o \ acquire.o mount.o record.o match_bsr.o parse_bsr.o \ - butil.o + butil.o read_record.o diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index cea55c1cde..65aefaa607 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -142,7 +142,7 @@ int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) * the device remains open. * */ -int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +int release_device(JCR *jcr, DEVICE *dev) { P(dev->mutex); Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk"); diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 225b9cf86e..a9152b9380 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -231,7 +231,7 @@ int do_append_data(JCR *jcr) } /* Release the device */ - if (!release_device(jcr, dev, block)) { + if (!release_device(jcr, dev)) { Pmsg0(000, "Error in release_device\n"); ok = FALSE; } diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index 7df654bc1e..3d7ffa0f48 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -38,20 +38,29 @@ int win32_client = 0; #endif -static void do_extract(char *fname, char *prefix); -static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); +static void do_extract(char *fname); +static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec); static DEVICE *dev = NULL; static int ofd = -1; - static JCR *jcr; static FF_PKT my_ff; static FF_PKT *ff = &my_ff; - static BSR *bsr = NULL; - -static DEV_RECORD *rec; static DEV_BLOCK *block; +static int extract = FALSE; +static long record_file_index; +static long total = 0; +static POOLMEM *fname; /* original file name */ +static POOLMEM *ofile; /* output name with prefix */ +static POOLMEM *lname; /* link name */ +static char *where; +static int wherelen; /* prefix length */ +static uint32_t num_files = 0; +static struct stat statp; +static uint32_t compress_buf_size = 70000; +static POOLMEM *compress_buf; +static int type; static void usage() { @@ -139,8 +148,8 @@ int main (int argc, char *argv[]) add_fname_to_include_list(ff, 0, "/"); /* include everything */ } - - do_extract(argv[0], argv[1]); + where = argv[1]; + do_extract(argv[0]); if (bsr) { free_bsr(bsr); @@ -148,44 +157,8 @@ int main (int argc, char *argv[]) return 0; } -/* - * Device got an error, attempt to analyse it - */ -static void display_error_status() +static void do_extract(char *devname) { - uint32_t status; - - Emsg0(M_ERROR, 0, dev->errmsg); - status_dev(dev, &status); - Dmsg1(20, "Device status: %x\n", status); - if (status & MT_EOD) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n"); - else if (status & MT_EOT) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n"); - else if (status & MT_EOF) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n"); - else if (status & MT_DR_OPEN) - Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n"); - else if (!(status & MT_ONLINE)) - Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n"); - else - Emsg2(M_ERROR_TERM, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno)); -} - - -static void do_extract(char *devname, char *where) -{ - struct stat statp; - int extract = FALSE; - int type; - long record_file_index; - long total = 0; - POOLMEM *fname; /* original file name */ - POOLMEM *ofile; /* output name with prefix */ - POOLMEM *lname; /* link name */ - int wherelen; /* prefix length */ - SESSION_LABEL sessrec; - uint32_t num_files = 0; jcr = setup_jcr("bextract", devname, bsr); dev = setup_to_read_device(jcr); @@ -207,287 +180,211 @@ static void do_extract(char *devname, char *where) ofile = get_pool_memory(PM_FNAME); lname = get_pool_memory(PM_FNAME); - block = new_block(dev); - rec = new_record(); - free_pool_memory(rec->data); - rec->data = get_memory(70000); /* get a big block for reading */ - uint32_t compress_buf_size = 70000; - POOLMEM *compress_buf = get_memory(compress_buf_size); - for ( ;; ) { - if (!read_block_from_device(dev, block)) { - Dmsg1(500, "Main read record failed. rem=%d\n", rec->remainder); - if (dev->state & ST_EOT) { - DEV_RECORD *record; - if (!mount_next_read_volume(jcr, dev, block)) { - break; - } - record = new_record(); - read_block_from_device(dev, block); - read_record_from_block(block, record); - get_session_record(dev, record, &sessrec); - free_record(record); - goto next_record; - } - if (dev->state & ST_EOF) { - continue; /* try again */ - } - if (dev->state & ST_SHORT) { - continue; - } - display_error_status(); - } + compress_buf = get_memory(compress_buf_size); -next_record: - for (rec->state=0; !is_block_empty(rec); ) { - if (!read_record_from_block(block, rec)) { - break; - } + read_records(jcr, dev, record_cb, mount_next_read_volume); + /* If output file is still open, it was the last one in the + * archive since we just hit an end of file, so close the file. + */ + if (ofd >= 0) { + close(ofd); + set_statp(jcr, fname, ofile, lname, type, &statp); + } + release_device(jcr, dev); - if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ - Dmsg0(40, "Get EOM LABEL\n"); - rec->remainder = 0; - break; /* yes, get out */ - } + free_pool_memory(fname); + free_pool_memory(ofile); + free_pool_memory(lname); + free_pool_memory(compress_buf); + term_dev(dev); + free_jcr(jcr); + printf("%u files restored.\n", num_files); + return; +} + +/* + * Called here for each record from read_records() + */ +static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) +{ + if (rec->FileIndex < 0) { + return; /* we don't want labels */ + } - /* Some sort of label? */ - if (rec->FileIndex < 0) { - get_session_record(dev, rec, &sessrec); - continue; - } /* end if label record */ + /* File Attributes stream */ + if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { + char *ap, *lp, *fp; - /* Is this the file we want? */ - if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &sessrec)) { - rec->remainder = 0; - continue; - } - if (is_partial_record(rec)) { - break; + /* If extracting, it was from previous stream, so + * close the output file. + */ + if (extract) { + if (ofd < 0) { + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); } + close(ofd); + ofd = -1; + extract = FALSE; + set_statp(jcr, fname, ofile, lname, type, &statp); + } - /* File Attributes stream */ - if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { - char *ap, *lp, *fp; + if (sizeof_pool_memory(fname) < rec->data_len) { + fname = realloc_pool_memory(fname, rec->data_len + 1); + } + if (sizeof_pool_memory(ofile) < rec->data_len + wherelen + 1) { + ofile = realloc_pool_memory(ofile, rec->data_len + wherelen + 1); + } + if (sizeof_pool_memory(lname) < rec->data_len) { + lname = realloc_pool_memory(lname, rec->data_len + wherelen + 1); + } + *fname = 0; + *lname = 0; + + /* + * An Attributes record consists of: + * File_index + * Type (FT_types) + * Filename + * Attributes + * Link name (if file linked i.e. FT_LNK) + * + */ + sscanf(rec->data, "%ld %d", &record_file_index, &type); + if (record_file_index != rec->FileIndex) + Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", + rec->FileIndex, record_file_index); + ap = rec->data; + while (*ap++ != ' ') /* skip record file index */ + ; + while (*ap++ != ' ') /* skip type */ + ; + /* Save filename and position to attributes */ + fp = fname; + while (*ap != 0) { + *fp++ = *ap++; + } + *fp = *ap++; /* terminate filename & point to attribs */ - /* If extracting, it was from previous stream, so - * close the output file. - */ - if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); - } - close(ofd); - ofd = -1; - extract = FALSE; - set_statp(jcr, fname, ofile, lname, type, &statp); - } + /* Skip to Link name */ + if (type == FT_LNK || type == FT_LNKSAVED) { + lp = ap; + while (*lp++ != 0) { + ; + } + } else { + lp = ""; + } - if (sizeof_pool_memory(fname) < rec->data_len) { - fname = realloc_pool_memory(fname, rec->data_len + 1); - } - if (sizeof_pool_memory(ofile) < rec->data_len + wherelen + 1) { - ofile = realloc_pool_memory(ofile, rec->data_len + wherelen + 1); - } - if (sizeof_pool_memory(lname) < rec->data_len) { - lname = realloc_pool_memory(lname, rec->data_len + wherelen + 1); - } - *fname = 0; - *lname = 0; - - /* - * An Attributes record consists of: - * File_index - * Type (FT_types) - * Filename - * Attributes - * Link name (if file linked i.e. FT_LNK) - * - */ - sscanf(rec->data, "%ld %d", &record_file_index, &type); - if (record_file_index != rec->FileIndex) - Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", - rec->FileIndex, record_file_index); - ap = rec->data; - while (*ap++ != ' ') /* skip record file index */ - ; - while (*ap++ != ' ') /* skip type */ - ; - /* Save filename and position to attributes */ - fp = fname; - while (*ap != 0) { - *fp++ = *ap++; + + if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { + + decode_stat(ap, &statp); + /* + * Prepend the where directory so that the + * files are put where the user wants. + * + * We do a little jig here to handle Win32 files with + * a drive letter. + * If where is null and we are running on a win32 client, + * change nothing. + * Otherwise, if the second character of the filename is a + * colon (:), change it into a slash (/) -- this creates + * a reasonable pathname on most systems. + */ + if (where[0] == 0 && win32_client) { + strcpy(ofile, fname); + strcpy(lname, lp); + } else { + strcpy(ofile, where); + if (fname[1] == ':') { + fname[1] = '/'; + strcat(ofile, fname); + fname[1] = ':'; + } else { + strcat(ofile, fname); } - *fp = *ap++; /* terminate filename & point to attribs */ - - /* Skip to Link name */ + /* Fixup link name */ if (type == FT_LNK || type == FT_LNKSAVED) { - lp = ap; - while (*lp++ != 0) { - ; + if (lp[0] == '/') { /* if absolute path */ + strcpy(lname, where); + } + /* ***FIXME**** we shouldn't have links on Windoz */ + if (lp[1] == ':') { + lp[1] = '/'; + strcat(lname, lp); + lp[1] = ':'; + } else { + strcat(lname, lp); } - } else { - lp = ""; } + } - - if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { - - decode_stat(ap, &statp); - /* - * Prepend the where directory so that the - * files are put where the user wants. - * - * We do a little jig here to handle Win32 files with - * a drive letter. - * If where is null and we are running on a win32 client, - * change nothing. - * Otherwise, if the second character of the filename is a - * colon (:), change it into a slash (/) -- this creates - * a reasonable pathname on most systems. - */ - if (where[0] == 0 && win32_client) { - strcpy(ofile, fname); - strcpy(lname, lp); - } else { - strcpy(ofile, where); - if (fname[1] == ':') { - fname[1] = '/'; - strcat(ofile, fname); - fname[1] = ':'; - } else { - strcat(ofile, fname); - } - /* Fixup link name */ - if (type == FT_LNK || type == FT_LNKSAVED) { - if (lp[0] == '/') { /* if absolute path */ - strcpy(lname, where); - } - /* ***FIXME**** we shouldn't have links on Windoz */ - if (lp[1] == ':') { - lp[1] = '/'; - strcat(lname, lp); - lp[1] = ':'; - } else { - strcat(lname, lp); - } - } - } + /* Pmsg1(000, "Restoring: %s\n", ofile); */ - /* Pmsg1(000, "Restoring: %s\n", ofile); */ + extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd); + num_files++; - extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd); - num_files++; + if (extract) { + print_ls_output(ofile, lname, type, &statp); + } + } - if (extract) { - print_ls_output(ofile, lname, type, &statp); - } - } + /* Data stream and extracting */ + } else if (rec->Stream == STREAM_FILE_DATA) { + if (extract) { + total += rec->data_len; + Dmsg2(8, "Write %ld bytes, total=%ld\n", rec->data_len, total); + if ((uint32_t)write(ofd, rec->data, rec->data_len) != rec->data_len) { + Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno)); + } + } - /* Data stream and extracting */ - } else if (rec->Stream == STREAM_FILE_DATA) { - if (extract) { - total += rec->data_len; - Dmsg2(8, "Write %ld bytes, total=%ld\n", rec->data_len, total); - if ((uint32_t)write(ofd, rec->data, rec->data_len) != rec->data_len) { - Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno)); - } - } - - } else if (rec->Stream == STREAM_GZIP_DATA) { + } else if (rec->Stream == STREAM_GZIP_DATA) { #ifdef HAVE_LIBZ - if (extract) { - uLongf compress_len; + if (extract) { + uLongf compress_len; - compress_len = compress_buf_size; - if (uncompress((Bytef *)compress_buf, &compress_len, - (const Bytef *)rec->data, (uLong)rec->data_len) != Z_OK) { - Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n")); - } + compress_len = compress_buf_size; + if (uncompress((Bytef *)compress_buf, &compress_len, + (const Bytef *)rec->data, (uLong)rec->data_len) != Z_OK) { + Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n")); + } - Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); - if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) { - Pmsg0(0, "===Write error===\n"); - Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno)); - } - total += compress_len; - Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, - compress_len); - } + Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); + if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) { + Pmsg0(0, "===Write error===\n"); + Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno)); + } + total += compress_len; + Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, + compress_len); + } #else - if (extract) { - Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n"); - } + if (extract) { + Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n"); + } #endif - /* If extracting, wierd stream (not 1 or 2), close output file anyway */ - } else if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); - } - close(ofd); - ofd = -1; - extract = FALSE; - set_statp(jcr, fname, ofile, lname, type, &statp); - } else if (rec->Stream != STREAM_MD5_SIGNATURE) { - Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data); - } + /* If extracting, wierd stream (not 1 or 2), close output file anyway */ + } else if (extract) { + if (ofd < 0) { + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); } - } - - - /* If output file is still open, it was the last one in the - * archive since we just hit an end of file, so close the file. - */ - if (ofd >= 0) { close(ofd); + ofd = -1; + extract = FALSE; set_statp(jcr, fname, ofile, lname, type, &statp); + } else if (rec->Stream != STREAM_MD5_SIGNATURE) { + Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data); } - release_device(jcr, dev, block); - - free_pool_memory(fname); - free_pool_memory(ofile); - free_pool_memory(lname); - free_pool_memory(compress_buf); - term_dev(dev); - free_block(block); - free_record(rec); - free_jcr(jcr); - printf("%u files restored.\n", num_files); - return; } -static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec) -{ - char *rtype; - memset(sessrec, 0, sizeof(sessrec)); - switch (rec->FileIndex) { - case PRE_LABEL: - rtype = "Fresh Volume Label"; - break; - case VOL_LABEL: - rtype = "Volume Label"; - unser_volume_label(dev, rec); - break; - case SOS_LABEL: - rtype = "Begin Session"; - unser_session_label(sessrec, rec); - break; - case EOS_LABEL: - rtype = "End Session"; - break; - case EOM_LABEL: - rtype = "End of Media"; - break; - default: - rtype = "Unknown"; - break; - } - Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); -} + + /* Dummies to replace askdir.c */ int dir_get_volume_info(JCR *jcr) { return 1;} diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index fc5eb8b8e1..11373023cb 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -31,8 +31,9 @@ static void do_blocks(char *infname); static void do_jobs(char *infname); static void do_ls(char *fname); -static void do_close(); +static void do_close(JCR *jcr); static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); +static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec); static DEVICE *dev; static int default_tape = FALSE; @@ -44,7 +45,8 @@ static DEV_RECORD *rec; static DEV_BLOCK *block; static JCR *jcr; static SESSION_LABEL sessrec; - +static uint32_t num_files = 0; +static long record_file_index; extern char BaculaId[]; @@ -70,32 +72,6 @@ static void usage() exit(1); } -static char *rec_state_to_str(DEV_RECORD *rec) -{ - static char buf[200]; - buf[0] = 0; - if (rec->state & REC_NO_HEADER) { - strcat(buf, "Nohdr,"); - } - if (is_partial_record(rec)) { - strcat(buf, "partial,"); - } - if (rec->state & REC_BLOCK_EMPTY) { - strcat(buf, "empty,"); - } - if (rec->state & REC_NO_MATCH) { - strcat(buf, "Nomatch,"); - } - if (rec->state & REC_CONTINUATION) { - strcat(buf, "cont,"); - } - if (buf[0]) { - buf[strlen(buf)-1] = 0; - } - return buf; -} - - int main (int argc, char *argv[]) { @@ -201,6 +177,16 @@ int main (int argc, char *argv[]) } rec = new_record(); block = new_block(dev); + /* + * Assume that we have already read the volume label. + * If on second or subsequent volume, adjust buffer pointer + */ + if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */ + Pmsg1(0, "\n\ +Warning, this Volume is a continuation of Volume %s\n", + dev->VolHdr.PrevVolName); + } + if (list_blocks) { do_blocks(argv[i]); } else if (list_jobs) { @@ -208,7 +194,7 @@ int main (int argc, char *argv[]) } else { do_ls(argv[i]); } - do_close(); + do_close(jcr); } if (bsr) { free_bsr(bsr); @@ -217,8 +203,9 @@ int main (int argc, char *argv[]) } -static void do_close() +static void do_close(JCR *jcr) { + release_device(jcr, dev); term_dev(dev); free_record(rec); free_block(block); @@ -226,46 +213,12 @@ static void do_close() } -/* - * Device got an error, attempt to analyse it - */ -static void display_error_status() -{ - uint32_t status; - - Emsg0(M_ERROR, 0, dev->errmsg); - status_dev(dev, &status); - Dmsg1(20, "Device status: %x\n", status); - if (status & MT_EOD) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n"); - else if (status & MT_EOT) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n"); - else if (status & MT_EOF) - Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n"); - else if (status & MT_DR_OPEN) - Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n"); - else if (!(status & MT_ONLINE)) - Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n"); - else - Emsg2(M_ERROR_TERM, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno)); -} - - /* List just block information */ static void do_blocks(char *infname) { dump_volume_label(dev); - /* Assume that we have already read the volume label. - * If on second or subsequent volume, adjust buffer pointer - */ - if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */ - Pmsg1(0, "\n\ -Warning, this Volume is a continuation of Volume %s\n", - dev->VolHdr.PrevVolName); - } - if (verbose) { rec = new_record(); } @@ -295,7 +248,7 @@ Warning, this Volume is a continuation of Volume %s\n", Emsg0(M_INFO, 0, dev->errmsg); continue; } - display_error_status(); + display_error_status(dev); break; } @@ -314,230 +267,75 @@ Warning, this Volume is a continuation of Volume %s\n", return; } +/* + * We are only looking for labels or in particula Job Session records + */ +static void jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) +{ + if (rec->FileIndex < 0) { + dump_label_record(dev, rec, verbose); + } + rec->remainder = 0; +} + /* Do list job records */ static void do_jobs(char *infname) { + read_records(jcr, dev, jobs_cb, mount_next_read_volume); +} - /* Assume that we have already read the volume label. - * If on second or subsequent volume, adjust buffer pointer - */ - if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */ - Pmsg1(0, "\n\ -Warning, this Volume is a continuation of Volume %s\n", - dev->VolHdr.PrevVolName); +/* Do an ls type listing of an archive */ +static void do_ls(char *infname) +{ + if (dump_label) { + dump_volume_label(dev); + return; } - - for ( ;; ) { - if (!read_block_from_device(dev, block)) { - Dmsg0(20, "!read_block()\n"); - if (dev->state & ST_EOT) { - DEV_RECORD *record; - if (!mount_next_read_volume(jcr, dev, block)) { - printf("Got EOF on device %s\n", dev_name(dev)); - break; - } - record = new_record(); - read_block_from_device(dev, block); - read_record_from_block(block, record); - get_session_record(dev, record, &sessrec); - free_record(record); - printf("Volume %s mounted.\n", jcr->VolumeName); - continue; - } - if (dev->state & ST_EOF) { - Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev)); - Dmsg0(20, "read_record got eof. try again\n"); - continue; - } - if (dev->state & ST_SHORT) { - Pmsg0(000, "Got short block.\n"); - Emsg0(M_INFO, 0, dev->errmsg); - continue; - } - display_error_status(); - break; - } - while (read_record_from_block(block, rec)) { - if (debug_level >= 30) { - Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId, - FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), - rec->data_len); - } - - /* - * Check for End of File record (all zeros) - * NOTE: this no longer exists - */ - if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) { - Emsg0(M_ERROR_TERM, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n"); - } - - /* - * Check for Start or End of Session Record - * - */ - if (rec->FileIndex < 0) { - dump_label_record(dev, rec, verbose); - continue; - } - } - rec->remainder = 0; - } - return; + read_records(jcr, dev, record_cb, mount_next_read_volume); } -/* Do an ls type listing of an archive */ -static void do_ls(char *infname) +/* + * Called here for each record from read_records() + */ +static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) { char fname[2000]; struct stat statp; int type; - long record_file_index; - uint32_t num_files = 0; - int record; - if (dump_label) { - dump_volume_label(dev); + if (rec->FileIndex < 0) { + get_session_record(dev, rec, &sessrec); return; } - - /* Assume that we have already read the volume label. - * If on second or subsequent volume, adjust buffer pointer - */ - if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */ - Pmsg1(0, "\n\ -Warning, this Volume is a continuation of Volume %s\n", - dev->VolHdr.PrevVolName); - } - - for ( ;; ) { - - if (!read_block_from_device(dev, block)) { - Dmsg0(20, "!read_record()\n"); - if (dev->state & ST_EOT) { - DEV_RECORD *record; - Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), - block->BlockNumber, rec->remainder); - if (!mount_next_read_volume(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); - break; - } - Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), - block->BlockNumber, rec->remainder); - record = new_record(); - read_block_from_device(dev, block); - read_record_from_block(block, record); - get_session_record(dev, record, &sessrec); - free_record(record); - goto next_record; - } - if (dev->state & ST_EOF) { - Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev)); - Dmsg0(20, "read_record got eof. try again\n"); - continue; - } - if (dev->state & ST_SHORT) { - Emsg0(M_INFO, 0, dev->errmsg); - continue; - } - display_error_status(); - break; + /* File Attributes stream */ + if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { + char *ap, *fp; + sscanf(rec->data, "%ld %d", &record_file_index, &type); + if (record_file_index != rec->FileIndex) { + Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", + rec->FileIndex, record_file_index); } - if (verbose) { - Dmsg2(10, "Block: %d blen=%d\n", block->BlockNumber, block->block_len); + ap = rec->data; + + while (*ap++ != ' ') /* skip record file index */ + ; + while (*ap++ != ' ') /* skip type */ + ; + /* Save filename and position to attributes */ + fp = fname; + while (*ap != 0) { + *fp++ = *ap++; } - -next_record: - record = 0; - for (rec->state=0; !is_block_empty(rec); ) { - if (!read_record_from_block(block, rec)) { - Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), - block->BlockNumber, rec->remainder); - break; - } - Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), - block->BlockNumber, rec->remainder); - /* - * At this point, we have at least a record header. - * Now decide if we want this record or not, but remember - * before accessing the record, we may need to read again to - * get all the data. - */ - record++; - if (verbose) { - Dmsg6(30, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, - rec_state_to_str(rec), block->BlockNumber, - rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); - } - if (debug_level >= 30) { - Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId, - FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), - rec->data_len); - } - - if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ - Dmsg0(40, "Get EOM LABEL\n"); - rec->remainder = 0; - break; /* yes, get out */ - } - - /* Some sort of label? */ - if (rec->FileIndex < 0) { - get_session_record(dev, rec, &sessrec); - continue; - } /* end if label record */ - - /* - * Apply BSR filter - */ - if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &sessrec)) { - if (verbose) { - Dmsg5(10, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n", - record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, - rec->FileIndex); - } - rec->remainder = 0; - continue; /* we don't want record, read next one */ - } - if (is_partial_record(rec)) { - Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, - rec_state_to_str(rec), block->BlockNumber, - rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); - break; /* read second part of record */ - } - - /* File Attributes stream */ - if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { - char *ap, *fp; - sscanf(rec->data, "%ld %d", &record_file_index, &type); - if (record_file_index != rec->FileIndex) { - Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", - rec->FileIndex, record_file_index); - } - ap = rec->data; - - while (*ap++ != ' ') /* skip record file index */ - ; - while (*ap++ != ' ') /* skip type */ - ; - /* Save filename and position to attributes */ - fp = fname; - while (*ap != 0) { - *fp++ = *ap++; - } - *fp = *ap++; /* terminate filename & point to attribs */ - - decode_stat(ap, &statp); - /* Skip to link name */ - while (*ap++ != 0) - ; - if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) { - print_ls_output(fname, ap, type, &statp); - num_files++; - } - } + *fp = *ap++; /* terminate filename & point to attribs */ + + decode_stat(ap, &statp); + /* Skip to link name */ + while (*ap++ != 0) + ; + if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) { + print_ls_output(fname, ap, type, &statp); + num_files++; } } if (verbose) { diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 8b86ec39c3..56f83ff40b 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -347,7 +347,7 @@ static void do_scan(char *devname) } } - release_device(jcr, dev, block); + release_device(jcr, dev); free_pool_memory(fname); free_pool_memory(ofile); diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 58136a523f..b55b162737 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -31,7 +31,7 @@ uint32_t new_VolSessionId(); int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int release_device(JCR *jcr, DEVICE *dev); /* From askdir.c */ int dir_get_volume_info(JCR *jcr); @@ -62,6 +62,7 @@ int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block); void print_ls_output(char *fname, char *link, int type, struct stat *statp); JCR *setup_jcr(char *name, char *device, BSR *bsr); DEVICE *setup_to_read_device(JCR *jcr); +void display_error_status(DEVICE *dev); /* From dev.c */ @@ -169,3 +170,8 @@ int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); DEV_RECORD *new_record(); void free_record(DEV_RECORD *rec); + +/* From read_record.c */ +int read_records(JCR *jcr, DEVICE *dev, + void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec), + int mount_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)); diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 52cc6ad58e..f4fa27b31d 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -215,7 +215,7 @@ int do_read_data(JCR *jcr) /* Send end of data to FD */ bnet_sig(ds, BNET_EOD); - if (!release_device(jcr, dev, block)) { + if (!release_device(jcr, dev)) { ok = FALSE; } free_pool_memory(hdr); diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c new file mode 100644 index 0000000000..e78a2ee3c5 --- /dev/null +++ b/bacula/src/stored/read_record.c @@ -0,0 +1,221 @@ +/* + * + * This routine provides a routine that will handle all + * the gory little details of reading a record from a Bacula + * archive. It uses a callback to pass you each record in turn, + * as well as a callback for mounting the next tape. It takes + * care of reading blocks, applying the bsr, ... + * + * Version $Id$ + */ +/* + Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "stored.h" + +static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); +static char *rec_state_to_str(DEV_RECORD *rec); + + +int read_records(JCR *jcr, DEVICE *dev, + void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec), + int mount_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)) +{ + DEV_BLOCK *block; + DEV_RECORD *rec; + uint32_t record, num_files = 0; + int verbose = FALSE; + int ok = TRUE; + SESSION_LABEL sessrec; + + block = new_block(dev); + rec = new_record(); + for ( ;ok; ) { + if (job_cancelled(jcr)) { + ok = FALSE; + break; + } + if (!read_block_from_device(dev, block)) { + Dmsg0(20, "!read_record()\n"); + if (dev->state & ST_EOT) { + DEV_RECORD *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; + break; + } + Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), + block->BlockNumber, rec->remainder); + record = new_record(); + read_block_from_device(dev, block); + read_record_from_block(block, record); + get_session_record(dev, record, &sessrec); + record_cb(jcr, dev, block, record); + free_record(record); + goto next_record; + } + if (dev->state & ST_EOF) { + Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev)); + Dmsg0(20, "read_record got eof. try again\n"); + continue; + } + if (dev->state & ST_SHORT) { + Emsg0(M_INFO, 0, dev->errmsg); + continue; + } +// display_error_status(); + ok = FALSE; + break; + } + if (verbose) { + Dmsg2(10, "Block: %d blen=%d\n", block->BlockNumber, block->block_len); + } + +next_record: + record = 0; + for (rec->state=0; !is_block_empty(rec); ) { + if (!read_record_from_block(block, rec)) { + Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), + block->BlockNumber, rec->remainder); + break; + } + Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), + block->BlockNumber, rec->remainder); + /* + * At this point, we have at least a record header. + * Now decide if we want this record or not, but remember + * before accessing the record, we may need to read again to + * get all the data. + */ + record++; + if (verbose) { + Dmsg6(30, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, + rec_state_to_str(rec), block->BlockNumber, + rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); + } + if (debug_level >= 30) { + Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId, + FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), + rec->data_len); + } + + if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ + Dmsg0(40, "Get EOM LABEL\n"); + rec->remainder = 0; + break; /* yes, get out */ + } + + /* Some sort of label? */ + if (rec->FileIndex < 0) { + get_session_record(dev, rec, &sessrec); + record_cb(jcr, dev, block, rec); + continue; + } /* end if label record */ + + /* + * Apply BSR filter + */ + if (jcr->bsr && !match_bsr(jcr->bsr, rec, &dev->VolHdr, &sessrec)) { + if (verbose) { + Dmsg5(10, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n", + record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, + rec->FileIndex); + } + rec->remainder = 0; + continue; /* we don't want record, read next one */ + } + if (is_partial_record(rec)) { + Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, + rec_state_to_str(rec), block->BlockNumber, + rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); + break; /* read second part of record */ + } + record_cb(jcr, dev, block, rec); + + } + } + if (verbose) { + printf("%u files found.\n", num_files); + } + free_record(rec); + free_block(block); + return ok; +} + + +static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec) +{ + char *rtype; + memset(sessrec, 0, sizeof(sessrec)); + switch (rec->FileIndex) { + case PRE_LABEL: + rtype = "Fresh Volume Label"; + break; + case VOL_LABEL: + rtype = "Volume Label"; + unser_volume_label(dev, rec); + break; + case SOS_LABEL: + rtype = "Begin Session"; + unser_session_label(sessrec, rec); + break; + case EOS_LABEL: + rtype = "End Session"; + break; + case EOM_LABEL: + rtype = "End of Media"; + break; + default: + rtype = "Unknown"; + break; + } + Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", + rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); +} + +static char *rec_state_to_str(DEV_RECORD *rec) +{ + static char buf[200]; + buf[0] = 0; + if (rec->state & REC_NO_HEADER) { + strcat(buf, "Nohdr,"); + } + if (is_partial_record(rec)) { + strcat(buf, "partial,"); + } + if (rec->state & REC_BLOCK_EMPTY) { + strcat(buf, "empty,"); + } + if (rec->state & REC_NO_MATCH) { + strcat(buf, "Nomatch,"); + } + if (rec->state & REC_CONTINUATION) { + strcat(buf, "cont,"); + } + if (buf[0]) { + buf[strlen(buf)-1] = 0; + } + return buf; +} +