From 8956c9dd0d61a7e86de7a833939380a7df5bff7f Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 15 Jun 2002 13:19:51 +0000 Subject: [PATCH] kes15Jun02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@42 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/cats/sql_create.c | 8 +- bacula/src/dird/catreq.c | 4 +- bacula/src/filed/restore.c | 10 +- bacula/src/lib/lex.c | 32 +++ bacula/src/lib/message.c | 26 +- bacula/src/lib/message.h | 98 +++++--- bacula/src/lib/parse_conf.c | 43 +--- bacula/src/lib/signal.c | 2 +- bacula/src/stored/Makefile.in | 9 +- bacula/src/stored/bextract.c | 47 +++- bacula/src/stored/block.c | 10 +- bacula/src/stored/bls.c | 10 +- bacula/src/stored/bsr.h | 108 +++++++++ bacula/src/stored/dev.c | 11 + bacula/src/stored/dev.h | 149 ++++++------ bacula/src/stored/device.c | 6 + bacula/src/stored/match_bsr.c | 211 +++++++++++++++++ bacula/src/stored/parse_bsr.c | 430 ++++++++++++++++++++++++++++++++++ bacula/src/stored/protos.h | 155 ++++++------ bacula/src/stored/stored.h | 1 + bacula/src/version.h | 6 +- 21 files changed, 1111 insertions(+), 265 deletions(-) create mode 100644 bacula/src/stored/bsr.h create mode 100755 bacula/src/stored/match_bsr.c create mode 100755 bacula/src/stored/parse_bsr.c diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 5d63af7577..04768c3234 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -134,9 +134,11 @@ JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId); /* Must create it */ Mmsg(&mdb->cmd, -"INSERT INTO JobMedia (JobId, MediaId, FirstIndex, LastIndex) \ -VALUES (%d, %d, %u, %u)", - jm->JobId, jm->MediaId, jm->FirstIndex, jm->LastIndex); +"INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,\ +StartFile,EndFile,StartBlock,EndBlock) \ +VALUES (%u,%u,%u,%u,%u,%u,%u,%u)", + jm->JobId, jm->MediaId, jm->FirstIndex, jm->LastIndex, + jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock); Dmsg0(30, mdb->cmd); if (!INSERT_DB(mdb, mdb->cmd)) { diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index f8f9965f65..d8b8dc3b33 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -180,8 +180,8 @@ MediaType=%s\n", mr.PoolId, jcr->PoolId, mr.VolStatus, mr.MediaType); * Otherwise, record the fact that this job used this Volume */ if (!relabel) { - Dmsg4(100, "create_jobmedia JobId=%d MediaId=%d FI=%d LI=%d\n", - jm.JobId, jm.MediaId, jm.FirstIndex, jm.LastIndex); + Dmsg6(100, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n", + jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex); if(!db_create_jobmedia_record(jcr->db, &jm)) { Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"), db_strerror(jcr->db)); diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 3c53741cf6..c892bff19a 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -300,8 +300,8 @@ extern char *getgroup(gid_t gid); */ static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct stat *statp) { - /* ********FIXME******** make memory pool */ - char buf[1000]; + char buf[2000]; + char ec1[30]; char *p, *f; int n; @@ -310,12 +310,12 @@ static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct p += n; n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid)); p += n; - n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size); + n = sprintf(p, "%8.8s ", edit_uint64(statp->st_size, ec1)); p += n; p = encode_time(statp->st_ctime, p); *p++ = ' '; *p++ = ' '; - for (f=fname; *f; ) + for (f=fname; *f && (p-buf) < (int)sizeof(buf); ) *p++ = *f++; if (type == FT_LNK) { *p++ = ' '; @@ -323,7 +323,7 @@ static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct *p++ = '>'; *p++ = ' '; /* Copy link name */ - for (f=lname; *f; ) + for (f=lname; *f && (p-buf) < (int)sizeof(buf); ) *p++ = *f++; } *p++ = '\n'; diff --git a/bacula/src/lib/lex.c b/bacula/src/lib/lex.c index 9e07c6a518..c25697fc30 100644 --- a/bacula/src/lib/lex.c +++ b/bacula/src/lib/lex.c @@ -30,6 +30,38 @@ extern int debug_level; +/* + * Scan to "logical" end of line. I.e. end of line, + * or semicolon. + */ +void scan_to_eol(LEX *lc) +{ + int token; + Dmsg0(150, "start scan to eof\n"); + while ((token = lex_get_token(lc)) != T_EOL) { + } + Dmsg0(150, "done scan to eof\n"); +} + + +/* + * Format a scanner error message + */ +void s_err(char *file, int line, LEX *lc, char *msg, ...) +{ + va_list arg_ptr; + char buf[MAXSTRING]; + + va_start(arg_ptr, msg); + bvsnprintf(buf, sizeof(buf), msg, arg_ptr); + va_end(arg_ptr); + + e_msg(file, line, M_ERROR_TERM, 0, "Config error: %s,\n\ + : Line %d, col %d of file %s\n%s\n", + buf, lc->line_no, lc->col_no, lc->fname, lc->line); +} + + /* * Free the current file, and retrieve the contents * of the previous packet if any. diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 42953586c7..83be2975e9 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -196,7 +196,7 @@ void init_console_msg(char *wd) sprintf(con_fname, "%s/%s.conmsg", wd, my_name); fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600); if (fd == -1) { - Emsg2(M_TERM, 0, "Could not open console message file %s: ERR=%s\n", + Emsg2(M_ERROR_TERM, 0, "Could not open console message file %s: ERR=%s\n", con_fname, strerror(errno)); } if (lseek(fd, 0, SEEK_END) > 0) { @@ -645,7 +645,7 @@ void dispatch_message(void *vjcr, int type, int level, char *msg) Dmsg2(200, "Enter dispatch_msg type=%d msg=%s\n", type, msg); - if (type == M_ABORT || type == M_TERM) { + if (type == M_ABORT || type == M_ERROR_TERM) { fprintf(stdout, msg); /* print this here to INSURE that it is printed */ } @@ -755,7 +755,7 @@ void dispatch_message(void *vjcr, int type, int level, char *msg) break; case MD_STDOUT: Dmsg1(200, "STDOUT for following err: %s\n", msg); - if (type != M_ABORT && type != M_TERM) /* already printed */ + if (type != M_ABORT && type != M_ERROR_TERM) /* already printed */ fprintf(stdout, msg); break; case MD_STDERR: @@ -829,9 +829,9 @@ e_msg(char *file, int line, int type, int level, char *fmt,...) /* * Check if we have a message destination defined. - * We always report M_ABORT and M_TERM + * We always report M_ABORT and M_ERROR_TERM */ - if (!daemon_msgs || ((type != M_ABORT && type != M_TERM) && + if (!daemon_msgs || ((type != M_ABORT && type != M_ERROR_TERM) && !bit_is_set(type, daemon_msgs->send_msg))) return; /* no destination */ switch (type) { @@ -839,8 +839,8 @@ e_msg(char *file, int line, int type, int level, char *fmt,...) sprintf(buf, "%s ABORTING due to ERROR in %s:%d\n", my_name, file, line); break; - case M_TERM: - sprintf(buf, "%s TERMINATING due to ERROR in %s:%d\n", + case M_ERROR_TERM: + sprintf(buf, "%s ERROR TERMINATING at %s:%d\n", my_name, file, line); break; case M_FATAL: @@ -874,7 +874,7 @@ e_msg(char *file, int line, int type, int level, char *fmt,...) char *p = 0; p[0] = 0; /* generate segmentation violation */ } - if (type == M_TERM) { + if (type == M_ERROR_TERM) { _exit(1); } } @@ -915,9 +915,9 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) buf = rbuf; /* we are the Director */ /* * Check if we have a message destination defined. - * We always report M_ABORT and M_TERM + * We always report M_ABORT and M_ERROR_TERM */ - if ((type != M_ABORT && type != M_TERM) && msgs && !bit_is_set(type, msgs->send_msg)) { + if ((type != M_ABORT && type != M_ERROR_TERM) && msgs && !bit_is_set(type, msgs->send_msg)) { Dmsg1(200, "No bit set for type %d\n", type); return; /* no destination */ } @@ -925,8 +925,8 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) case M_ABORT: sprintf(buf, "%s ABORTING due to ERROR\n", my_name); break; - case M_TERM: - sprintf(buf, "%s TERMINATING due to ERROR\n", my_name); + case M_ERROR_TERM: + sprintf(buf, "%s ERROR TERMINATING\n", my_name); break; case M_FATAL: sprintf(buf, "%s: Job %s Fatal error: ", my_name, job); @@ -962,7 +962,7 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) char *p = 0; p[0] = 0; /* generate segmentation violation */ } - if (type == M_TERM) { + if (type == M_ERROR_TERM) { _exit(1); } } diff --git a/bacula/src/lib/message.h b/bacula/src/lib/message.h index 432c21b592..4f8200e0b3 100644 --- a/bacula/src/lib/message.h +++ b/bacula/src/lib/message.h @@ -26,53 +26,79 @@ #include "bits.h" -#undef M_DEBUG -#undef M_ABORT -#undef M_FATAL -#undef M_ERROR -#undef M_WARNING -#undef M_INFO -#undef M_MOUNT -#undef M_TERM +#undef M_DEBUG +#undef M_ABORT +#undef M_FATAL +#undef M_ERROR +#undef M_WARNING +#undef M_INFO +#undef M_MOUNT +#undef M_ERROR_TERM +#undef M_TERM -#define M_DEBUG 1 /* debug message */ -#define M_ABORT 2 /* MUST abort immediately */ -#define M_FATAL 3 /* Fatal error, stopping job */ -#define M_ERROR 4 /* Error, but recoverable */ -#define M_WARNING 5 /* Warning message */ -#define M_INFO 6 /* Informational message */ -#define M_SAVED 7 /* Info on saved file */ -#define M_NOTSAVED 8 /* Info on notsaved file */ -#define M_SKIPPED 9 /* File skipped by option setting */ -#define M_MOUNT 10 /* Mount requests */ -#define M_TERM 11 /* Termination request */ +/* + * Most of these message levels are more or less obvious. + * They have evolved somewhat during the development of Bacula, + * and here are some of the details of where I am trying to + * head (in the process of changing the code) as of 15 June 2002. + * + * M_ABORT Bacula immediately aborts and tries to produce a traceback + * This is for really serious errors like segmentation fault. + * M_ERROR_TERM Bacula immediately terminates but no dump. This is for + * "obvious" serious errors like daemon already running or + * cannot open critical file, ... where a dump is not wanted. + * M_TERM Bacula daemon shutting down because of request (SIGTERM). + * + * The remaining apply to Jobs rather than the daemon. + * + * M_FATAL Bacula detected a fatal Job error. The Job will be killed, + * but Bacula continues running. + * M_ERROR Bacula detected a Job error. The Job will continue running + * but the termination status will be error. + * M_WARNING Job warning message. + * M_INFO Job information message. + * + */ + +#define M_DEBUG 1 /* debug message */ +#define M_ABORT 2 /* MUST abort immediately */ +#define M_FATAL 3 /* Fatal error, stopping job */ +#define M_ERROR 4 /* Error, but recoverable */ +#define M_WARNING 5 /* Warning message */ +#define M_INFO 6 /* Informational message */ +#define M_SAVED 7 /* Info on saved file */ +#define M_NOTSAVED 8 /* Info on notsaved file */ +#define M_SKIPPED 9 /* File skipped by option setting */ +#define M_MOUNT 10 /* Mount requests */ +#define M_ERROR_TERM 11 /* Error termination request (no dump) */ +#define M_TERM 12 /* Terminating daemon */ -#define M_MAX M_TERM /* keep this updated ! */ +#define M_MAX M_TERM /* keep this updated ! */ /* Define message destination structure */ /* *** FIXME **** where should be extended to handle multiple values */ typedef struct s_dest { struct s_dest *next; - int dest_code; /* destination (one of the MD_ codes) */ - int max_len; /* max mail line length */ - FILE *fd; /* file descriptor */ + int dest_code; /* destination (one of the MD_ codes) */ + int max_len; /* max mail line length */ + FILE *fd; /* file descriptor */ char msg_types[nbytes_for_bits(M_MAX+1)]; /* message type mask */ - char *where; /* filename/program name */ - char *mail_cmd; /* mail command */ - POOLMEM *mail_filename; /* unique mail filename */ + char *where; /* filename/program name */ + char *mail_cmd; /* mail command */ + POOLMEM *mail_filename; /* unique mail filename */ } DEST; /* Message Destination values for dest field of DEST */ -#define MD_SYSLOG 1 /* send msg to syslog */ -#define MD_MAIL 2 /* email group of messages */ -#define MD_FILE 3 /* write messages to a file */ -#define MD_APPEND 4 /* append messages to a file */ -#define MD_STDOUT 5 /* print messages */ -#define MD_STDERR 6 /* print messages to stderr */ -#define MD_DIRECTOR 7 /* send message to the Director */ -#define MD_OPERATOR 8 /* email a single message to the operator */ -#define MD_CONSOLE 9 /* send msg to UserAgent or console */ -#define MD_MAIL_ON_ERROR 10 /* email messages if job errors */ +#define MD_SYSLOG 1 /* send msg to syslog */ +#define MD_MAIL 2 /* email group of messages */ +#define MD_FILE 3 /* write messages to a file */ +#define MD_APPEND 4 /* append messages to a file */ +#define MD_STDOUT 5 /* print messages */ +#define MD_STDERR 6 /* print messages to stderr */ +#define MD_DIRECTOR 7 /* send message to the Director */ +#define MD_OPERATOR 8 /* email a single message to the operator */ +#define MD_CONSOLE 9 /* send msg to UserAgent or console */ +#define MD_MAIL_ON_ERROR 10 /* email messages if job errors */ void d_msg(char *file, int line, int level, char *fmt,...); diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 77590b139b..61f7d7eadc 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -174,7 +174,7 @@ void init_resource(int type, struct res_items *items) } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { - Emsg1(M_ABORT, 0, _("Too many items in %s resource\n"), resources[rindex]); + Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]); } } } @@ -634,12 +634,11 @@ void store_yesno(LEX *lc, struct res_items *item, int index, int pass) int token; token = lex_get_token(lc); - lcase(lc->str); if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) { scan_err1(lc, "expected an identifier or string, got: %s", lc->str); - } else if (strcmp(lc->str, "yes") == 0) { + } else if (strcasecmp(lc->str, "yes") == 0) { *(int *)(item->value) |= item->code; - } else if (strcmp(lc->str, "no") == 0) { + } else if (strcasecmp(lc->str, "no") == 0) { *(int *)(item->value) &= ~(item->code); } else { scan_err1(lc, "Expect a YES or NO, got: %s", lc->str); @@ -649,36 +648,6 @@ void store_yesno(LEX *lc, struct res_items *item, int index, int pass) } -/* - * Scan to "logical" end of line. I.e. end of line, - * or semicolon. - */ -void scan_to_eol(LEX *lc) -{ - int token; - Dmsg0(150, "start scan to eof\n"); - while ((token = lex_get_token(lc)) != T_EOL) { - } - Dmsg0(150, "done scan to eof\n"); -} - - -/* - * Format a scanner error message - */ -void s_err(char *file, int line, LEX *lc, char *msg, ...) -{ - va_list arg_ptr; - char buf[MAXSTRING]; - - va_start(arg_ptr, msg); - bvsnprintf(buf, sizeof(buf), msg, arg_ptr); - va_end(arg_ptr); - - e_msg(file, line, M_ABORT, 0, "Config error: %s,\n\ - : Line %d, col %d of file %s\n%s\n", - buf, lc->line_no, lc->col_no, lc->fname, lc->line); -} void LockRes() { @@ -775,9 +744,8 @@ parse_config(char *cf) if (token != T_IDENTIFIER) { scan_err1(lc, "Expected a Resource name identifier, got: %s", lc->str); } - lcase(lc->str); for (i=0; resources[i].name; i++) - if (strcmp(resources[i].name, lc->str) == 0) { + if (strcasecmp(resources[i].name, lc->str) == 0) { state = p_resource; items = resources[i].items; res_type = resources[i].rcode; @@ -797,9 +765,8 @@ parse_config(char *cf) if (level != 1) { scan_err1(lc, "not in resource definition: %s", lc->str); } - lcase(lc->str); for (i=0; items[i].name; i++) { - if (strcmp(items[i].name, lc->str) == 0) { + if (strcasecmp(items[i].name, lc->str) == 0) { token = lex_get_token(lc); Dmsg1 (150, "in T_IDENT got token=%s\n", lex_tok_to_str(token)); if (token != T_EQUALS) { diff --git a/bacula/src/lib/signal.c b/bacula/src/lib/signal.c index deefdb0401..0b9fe5bc79 100644 --- a/bacula/src/lib/signal.c +++ b/bacula/src/lib/signal.c @@ -68,7 +68,7 @@ static void signal_handler(int sig) } already_dead = sig; if (sig == SIGTERM) { - Emsg1(M_INFO, -1, "Shutting down Bacula service: %s ...\n", my_name); + Emsg1(M_TERM, -1, "Shutting down Bacula service: %s ...\n", my_name); } else { Emsg2(M_FATAL, -1, "Interrupted by signal %d: %s\n", sig, sig_names[sig]); } diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 8e479dd01b..21dad53ec7 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -20,10 +20,12 @@ dummy: # SVRSRCS = stored.c append.c askdir.c authenticate.c block.c dev.c \ device.c dircmd.c fd_cmds.c fdmsg.c job.c \ - label.c read.c record.c stored_conf.c + label.c match_bsr.c parse_bsr.c \ + read.c record.c stored_conf.c SVROBJS = stored.o append.o askdir.o authenticate.o block.o dev.o \ device.o dircmd.o fd_cmds.o fdmsg.o job.o \ - label.o read.o record.o stored_conf.o + label.o match_bsr.o parse_bsr.o \ + read.o record.o stored_conf.o # bpool is depricated #POOLSRCS = bpool.c block.c dev.c device.c askdir.c label.c \ @@ -39,7 +41,8 @@ TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \ BLSOBJS = bls.o block.o device.o dev.o askdir.o label.o record.o -BEXTOBJS = bextract.o block.o device.o dev.o askdir.o label.o record.o +BEXTOBJS = bextract.o block.o device.o dev.o askdir.o label.o record.o \ + match_bsr.o parse_bsr.o SCNOBJS = bscan.o block.o device.o dev.o askdir.o label.o record.o diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index 66834f6f12..d0e77f947a 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -31,8 +31,9 @@ #include "stored.h" #include "findlib/find.h" + static void do_extract(char *fname, char *prefix); -static void print_ls_output(char *fname, struct stat *statp); +static void print_ls_output(char *fname, char *link, int type, struct stat *statp); static DEVICE *dev = NULL; @@ -42,10 +43,14 @@ static JCR *jcr; static FF_PKT my_ff; static FF_PKT *ff = &my_ff; +static BSR *bsr = NULL; +static SESSION_LABEL sesrec; + static void usage() { fprintf(stderr, "Usage: bextract [-d debug_level] \n" +" -b specify a bootstrap file\n" " -dnn set debug level to nn\n" " -e exclude list\n" " -i include list\n" @@ -71,8 +76,13 @@ int main (int argc, char *argv[]) memset(ff, 0, sizeof(FF_PKT)); init_include_exclude_files(ff); - while ((ch = getopt(argc, argv, "d:e:i:?")) != -1) { + while ((ch = getopt(argc, argv, "b:d:e:i:?")) != -1) { switch (ch) { + case 'b': /* bootstrap file */ + bsr = parse_bsr(optarg); + dump_bsr(bsr); + break; + case 'd': /* debug level */ debug_level = atoi(optarg); if (debug_level <= 0) @@ -133,6 +143,9 @@ int main (int argc, char *argv[]) do_extract(argv[0], argv[1]); free_jcr(jcr); + if (bsr) { + free_bsr(bsr); + } return 0; } @@ -201,6 +214,7 @@ static void do_extract(char *devname, char *where) POOLMEM *compress_buf = get_memory(compress_buf_size); for ( ;; ) { + int ok; if (!read_record(dev, block, &rec)) { uint32_t status; @@ -246,9 +260,11 @@ static void do_extract(char *devname, char *where) break; case VOL_LABEL: rtype = "Volume Label"; + unser_volume_label(dev, &rec); break; case SOS_LABEL: rtype = "Begin Session"; + unser_session_label(&sesrec, &rec); break; case EOS_LABEL: rtype = "End Session"; @@ -333,7 +349,13 @@ static void do_extract(char *devname, char *where) } /* Is this the file we want? */ - if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { + if (bsr) { + ok = match_bsr(bsr, &rec, &dev->VolHdr, &sesrec); + } else { + ok = TRUE; + } + + if (ok && file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { decode_stat(ap, &statp); /* @@ -361,7 +383,7 @@ static void do_extract(char *devname, char *where) extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd); if (extract) { - print_ls_output(ofile, &statp); + print_ls_output(ofile, lname, type, &statp); } } @@ -437,9 +459,10 @@ static void do_extract(char *devname, char *where) extern char *getuser(uid_t uid); extern char *getgroup(gid_t gid); -static void print_ls_output(char *fname, struct stat *statp) +static void print_ls_output(char *fname, char *link, int type, struct stat *statp) { char buf[1000]; + char ec1[30]; char *p, *f; int n; @@ -448,13 +471,23 @@ static void print_ls_output(char *fname, struct stat *statp) p += n; n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid)); p += n; - n = sprintf(p, "%8lld ", (uint64_t)statp->st_size); + n = sprintf(p, "%8.8s ", edit_uint64(statp->st_size, ec1)); p += n; p = encode_time(statp->st_ctime, p); *p++ = ' '; *p++ = ' '; - for (f=fname; *f; ) + /* Copy file name */ + for (f=fname; *f && (p-buf) < (int)sizeof(buf); ) *p++ = *f++; + if (type == FT_LNK) { + *p++ = ' '; + *p++ = '-'; + *p++ = '>'; + *p++ = ' '; + /* Copy link name */ + for (f=link; *f && (p-buf) < (int)sizeof(buf); ) + *p++ = *f++; + } *p++ = '\n'; *p = 0; fputs(buf, stdout); diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index c0a218a244..7615f39208 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -299,7 +299,7 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block) block->BlockNumber = dev->block_num; ser_block_header(block); - /* dump_block(block, "after ser_hdr"); */ + /* Limit maximum Volume size to value specified by user */ if ((dev->max_volume_size > 0) && ((int64_t) (dev->VolCatInfo.VolCatBytes + block->binbuf)) >= dev->max_volume_size) { dev->state |= ST_WEOT; @@ -341,6 +341,14 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block) } 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) { + weof_dev, 1); /* write end of file */ + } + Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num, wlen); empty_block(block); diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 48ba910934..69aca0f40c 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -496,6 +496,7 @@ extern char *getgroup(gid_t gid); static void print_ls_output(char *fname, char *link, int type, struct stat *statp) { char buf[1000]; + char ec1[30]; char *p, *f; int n; @@ -507,24 +508,21 @@ static void print_ls_output(char *fname, char *link, int type, struct stat *stat p += n; n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid)); p += n; - n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size); + n = sprintf(p, "%8.8s ", edit_uint64(statp->st_size, ec1)); p += n; p = encode_time(statp->st_ctime, p); *p++ = ' '; *p++ = ' '; /* Copy file name */ - for (f=fname; *f; ) + for (f=fname; *f && (p-buf) < (int)sizeof(buf); ) *p++ = *f++; - if (type == FT_DIR) { - *p++ = '/'; - } if (type == FT_LNK) { *p++ = ' '; *p++ = '-'; *p++ = '>'; *p++ = ' '; /* Copy link name */ - for (f=link; *f; ) + for (f=link; *f && (p-buf) < (int)sizeof(buf); ) *p++ = *f++; } *p++ = '\n'; diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h new file mode 100644 index 0000000000..c6728e17fd --- /dev/null +++ b/bacula/src/stored/bsr.h @@ -0,0 +1,108 @@ +/* + * BootStrap record definition -- for restoring files. + * + * Kern Sibbald, June 2002 + * + * 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. + + */ + + +#ifndef __BSR_H +#define __BSR_H 1 + +#include "findlib/find.h" + +/* + * !!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !!! !!! + * !!! All records must have a pointer to !!! + * !!! the next item as the first item defined. !!! + * !!! !!! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +typedef struct s_bsr_client { + struct s_bsr_client *next; + char *ClientName; +} BSR_CLIENT; + +typedef struct s_bsr_sessid { + struct s_bsr_sessid *next; + int type; + uint32_t sessid1; + uint32_t sessid2; + int found; +} BSR_SESSID; + +typedef struct s_bsr_sesstime { + struct s_bsr_sesstime *next; + uint32_t sesstime; + int found; +} BSR_SESSTIME; + +typedef struct s_bsr_findex { + struct s_bsr_findex *next; + int32_t FileIndex; + int found; +} BSR_FINDEX; + +typedef struct s_bsr_jobid { + struct s_bsr_jobid *next; + uint32_t JobId; + int found; +} BSR_JOBID; + +typedef struct s_bsr_jobtype { + struct s_bsr_jobtype *next; + uint32_t JobType; +} BSR_JOBTYPE; + +typedef struct s_bsr_joblevel { + struct s_bsr_joblevel *next; + uint32_t JobLevel; +} BSR_JOBLEVEL; + +typedef struct s_bsr_job { + struct s_bsr_job *next; + char *Job; + int found; +} BSR_JOB; + + +typedef struct s_bsr { + struct s_bsr *next; /* pointer to next one */ + int done; /* set when everything found */ + char *VolumeName; + BSR_CLIENT *client; + BSR_JOB *job; + BSR_SESSID *sessid; + BSR_SESSTIME *sesstime; + BSR_FINDEX *FileIndex; + BSR_JOBID *JobId; + BSR_JOBTYPE *JobType; + BSR_JOBLEVEL *JobLevel; + FF_PKT *ff; /* include/exclude */ +} BSR; + + +#endif diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index d4e4380ad7..0d451a7962 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -269,6 +269,7 @@ int rewind_dev(DEVICE *dev) } dev->state &= ~(ST_APPEND|ST_READ|ST_EOT | ST_EOF | ST_WEOT); /* remove EOF/EOT flags */ dev->block_num = dev->file = 0; + dev->file_bytes = 0; if (dev->state & ST_TAPE) { mt_com.mt_op = MTREW; mt_com.mt_count = 1; @@ -323,6 +324,7 @@ eod_dev(DEVICE *dev) } dev->state &= ~(ST_EOF); /* remove EOF flags */ 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) { @@ -395,6 +397,7 @@ int update_pos_dev(DEVICE *dev) /* Find out where we are */ if (!(dev->state & ST_TAPE)) { dev->file = 0; + dev->file_bytes - 0; pos = lseek(dev->fd, 0, SEEK_CUR); if (pos < 0) { Dmsg1(200, "Seek error: ERR=%s\n", strerror(dev->dev_errno)); @@ -535,6 +538,7 @@ int load_dev(DEVICE *dev) #else dev->block_num = dev->file = 0; + dev->file_bytes = 0; mt_com.mt_op = MTLOAD; mt_com.mt_count = 1; if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) { @@ -566,6 +570,7 @@ int offline_dev(DEVICE *dev) } dev->block_num = dev->file = 0; + dev->file_bytes = 0; mt_com.mt_op = MTOFFL; mt_com.mt_count = 1; if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) { @@ -640,6 +645,7 @@ fsf_dev(DEVICE *dev, int num) } else { dev->state |= ST_EOF; dev->file++; + dev->file_bytes = 0; continue; } } else { /* Got data */ @@ -659,6 +665,7 @@ fsf_dev(DEVICE *dev, int num) } else { dev->state |= ST_EOF; /* just read EOF */ dev->file++; + dev->file_bytes = 0; } } @@ -710,6 +717,7 @@ bsf_dev(DEVICE *dev, int num) Dmsg0(29, "bsf_dev\n"); dev->state &= ~(ST_EOT|ST_EOF); dev->file -= num; + dev->file_bytes = 0; mt_com.mt_op = MTBSF; mt_com.mt_count = num; stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); @@ -755,6 +763,7 @@ fsr_dev(DEVICE *dev, int num) } else { dev->state |= ST_EOF; /* assume EOF */ dev->file++; + dev->file_bytes = 0; } clrerror_dev(dev, MTFSR); Mmsg2(&dev->errmsg, _("ioctl MTFSR error on %s. ERR=%s.\n"), @@ -827,6 +836,7 @@ weof_dev(DEVICE *dev, int num) stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); if (stat == 0) { dev->file++; + dev->file_bytes = 0; } else { clrerror_dev(dev, MTWEOF); Mmsg2(&dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"), @@ -934,6 +944,7 @@ static void do_close(DEVICE *dev) dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF); dev->block_num = 0; dev->file = 0; + dev->file_bytes = 0; dev->LastBlockNumWritten = 0; memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index cb9845b5fa..f01b928f52 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -34,49 +34,49 @@ #define READ_ONLY 1 /* Generic status bits returned from status_dev() */ -#define MT_TAPE (1<<0) /* is tape device */ -#define MT_EOF (1<<1) /* just read EOF */ -#define MT_BOT (1<<2) /* at beginning of tape */ -#define MT_EOT (1<<3) /* end of tape reached */ -#define MT_SM (1<<4) /* DDS setmark */ -#define MT_EOD (1<<5) /* DDS at end of data */ -#define MT_WR_PROT (1<<6) /* tape write protected */ -#define MT_ONLINE (1<<7) /* tape online */ -#define MT_DR_OPEN (1<<8) /* tape door open */ -#define MT_IM_REP_EN (1<<9) /* immediate report enabled */ +#define MT_TAPE (1<<0) /* is tape device */ +#define MT_EOF (1<<1) /* just read EOF */ +#define MT_BOT (1<<2) /* at beginning of tape */ +#define MT_EOT (1<<3) /* end of tape reached */ +#define MT_SM (1<<4) /* DDS setmark */ +#define MT_EOD (1<<5) /* DDS at end of data */ +#define MT_WR_PROT (1<<6) /* tape write protected */ +#define MT_ONLINE (1<<7) /* tape online */ +#define MT_DR_OPEN (1<<8) /* tape door open */ +#define MT_IM_REP_EN (1<<9) /* immediate report enabled */ /* Bits for device capabilities */ -#define CAP_EOF 0x001 /* has MTWEOF */ -#define CAP_BSR 0x002 /* has MTBSR */ -#define CAP_BSF 0x004 /* has MTBSF */ -#define CAP_FSR 0x008 /* has MTFSR */ -#define CAP_FSF 0x010 /* has MTFSF */ -#define CAP_EOM 0x020 /* has MTEOM */ -#define CAP_REM 0x040 /* is removable media */ -#define CAP_RACCESS 0x080 /* is random access device */ -#define CAP_AUTOMOUNT 0x100 /* Read device at start to see what is there */ -#define CAP_LABEL 0x200 /* Label blank tapes */ -#define CAP_ANONVOLS 0x400 /* Mount without knowing volume name */ -#define CAP_ALWAYSOPEN 0x800 /* always keep device open */ +#define CAP_EOF 0x001 /* has MTWEOF */ +#define CAP_BSR 0x002 /* has MTBSR */ +#define CAP_BSF 0x004 /* has MTBSF */ +#define CAP_FSR 0x008 /* has MTFSR */ +#define CAP_FSF 0x010 /* has MTFSF */ +#define CAP_EOM 0x020 /* has MTEOM */ +#define CAP_REM 0x040 /* is removable media */ +#define CAP_RACCESS 0x080 /* is random access device */ +#define CAP_AUTOMOUNT 0x100 /* Read device at start to see what is there */ +#define CAP_LABEL 0x200 /* Label blank tapes */ +#define CAP_ANONVOLS 0x400 /* Mount without knowing volume name */ +#define CAP_ALWAYSOPEN 0x800 /* always keep device open */ /* Tape state bits */ -#define ST_OPENED 0x001 /* set when device opened */ -#define ST_TAPE 0x002 /* is a tape device */ -#define ST_LABEL 0x004 /* label found */ +#define ST_OPENED 0x001 /* set when device opened */ +#define ST_TAPE 0x002 /* is a tape device */ +#define ST_LABEL 0x004 /* label found */ #define ST_MALLOC 0x008 /* dev packet malloc'ed in init_dev() */ -#define ST_APPEND 0x010 /* ready for Bacula append */ -#define ST_READ 0x020 /* ready for Bacula read */ -#define ST_EOT 0x040 /* at end of tape */ -#define ST_WEOT 0x080 /* Got EOT on write */ -#define ST_EOF 0x100 /* Read EOF i.e. zero bytes */ -#define ST_NEXTVOL 0x200 /* Start writing on next volume */ -#define ST_SHORT 0x400 /* Short block read */ +#define ST_APPEND 0x010 /* ready for Bacula append */ +#define ST_READ 0x020 /* ready for Bacula read */ +#define ST_EOT 0x040 /* at end of tape */ +#define ST_WEOT 0x080 /* Got EOT on write */ +#define ST_EOF 0x100 /* Read EOF i.e. zero bytes */ +#define ST_NEXTVOL 0x200 /* Start writing on next volume */ +#define ST_SHORT 0x400 /* Short block read */ /* dev_blocked states (mutually exclusive) */ #define BST_NOT_BLOCKED 0 /* not blocked */ -#define BST_UNMOUNTED 1 /* User unmounted device */ +#define BST_UNMOUNTED 1 /* User unmounted device */ #define BST_WAITING_FOR_SYSOP 2 /* Waiting for operator to mount tape */ #define BST_DOING_ACQUIRE 3 /* Opening/validating/moving tape */ #define BST_WRITING_LABEL 4 /* Labeling a tape */ @@ -85,55 +85,56 @@ /* Volume Catalog Information structure definition */ typedef struct s_volume_catalog_info { /* Media info for the current Volume */ - uint32_t VolCatJobs; /* number of jobs on this Volume */ - uint32_t VolCatFiles; /* Number of files */ - uint32_t VolCatBlocks; /* Number of blocks */ - uint64_t VolCatBytes; /* Number of bytes written */ - uint32_t VolCatMounts; /* Number of mounts this volume */ - uint32_t VolCatErrors; /* Number of errors this volume */ - uint32_t VolCatWrites; /* Number of writes this volume */ - uint32_t VolCatReads; /* Number of reads this volume */ - uint32_t VolCatRecycles; /* Number of recycles this volume */ - uint64_t VolCatMaxBytes; /* max bytes to write */ + uint32_t VolCatJobs; /* number of jobs on this Volume */ + uint32_t VolCatFiles; /* Number of files */ + uint32_t VolCatBlocks; /* Number of blocks */ + uint64_t VolCatBytes; /* Number of bytes written */ + uint32_t VolCatMounts; /* Number of mounts this volume */ + uint32_t VolCatErrors; /* Number of errors this volume */ + uint32_t VolCatWrites; /* Number of writes this volume */ + uint32_t VolCatReads; /* Number of reads this volume */ + uint32_t VolCatRecycles; /* Number of recycles this volume */ + uint64_t VolCatMaxBytes; /* max bytes to write */ uint64_t VolCatCapacityBytes; /* capacity estimate */ - char VolCatStatus[20]; /* Volume status */ + char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ } VOLUME_CAT_INFO; /* Device structure definition */ typedef struct s_device { - struct s_device *next; /* pointer to next open device */ - pthread_mutex_t mutex; /* access control */ - pthread_cond_t wait; /* thread wait variable */ + struct s_device *next; /* pointer to next open device */ + pthread_mutex_t mutex; /* access control */ + pthread_cond_t wait; /* thread wait variable */ pthread_cond_t wait_next_vol; /* wait for tape to be mounted */ - pthread_t no_wait_id; /* this thread must not wait */ - int dev_blocked; /* set if we must wait (i.e. change tape) */ - int num_waiting; /* number of threads waiting */ - int num_writers; /* number of writing threads */ - int use_count; /* usage count on this device */ - int fd; /* file descriptor */ - int capabilities; /* capabilities mask */ - int state; /* state mask */ - int dev_errno; /* Our own errno */ - int mode; /* read/write modes */ - char *dev_name; /* device name */ - char *errmsg; /* nicely edited error message */ - uint32_t block_num; /* current block number base 0 */ - uint32_t file; /* current file number base 0 */ + pthread_t no_wait_id; /* this thread must not wait */ + int dev_blocked; /* set if we must wait (i.e. change tape) */ + int num_waiting; /* number of threads waiting */ + int num_writers; /* number of writing threads */ + int use_count; /* usage count on this device */ + int fd; /* file descriptor */ + int capabilities; /* capabilities mask */ + int state; /* state mask */ + int dev_errno; /* Our own errno */ + int mode; /* read/write modes */ + char *dev_name; /* device name */ + 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 */ uint32_t LastBlockNumWritten; /* last block written */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ - uint32_t max_volume_jobs; /* max jobs to put on one volume */ - int64_t max_volume_files; /* max files to put on one volume */ - int64_t max_volume_size; /* max bytes to put on one volume */ - int64_t max_file_size; /* max file size in bytes */ - int64_t volume_capacity; /* advisory capacity */ - uint32_t max_rewind_wait; /* max secs to allow for rewind */ - void *device; /* pointer to Device Resource */ - - VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ - struct Volume_Label VolHdr; /* Actual volume label */ + uint32_t min_block_size; /* min block size */ + uint32_t max_block_size; /* max block size */ + uint32_t max_volume_jobs; /* max jobs to put on one volume */ + uint64_t max_volume_files; /* max files to put on one volume */ + uint64_t max_volume_size; /* max bytes to put on one volume */ + uint64_t max_file_size; /* max file size to put in one file on volume */ + uint64_t volume_capacity; /* advisory capacity */ + uint32_t max_rewind_wait; /* max secs to allow for rewind */ + void *device; /* pointer to Device Resource */ + + VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ + VOLUME_LABEL VolHdr; /* Actual volume label */ } DEVICE; @@ -172,7 +173,7 @@ typedef struct s_device { * dependent. Arrgggg! */ #ifndef MTEOM -#ifdef MTSEOD +#ifdef MTSEOD #define MTEOM MTSEOD #endif #ifdef MTEOD diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 90f0979534..26038854ef 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -562,6 +562,9 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) strcpy(dev->VolCatInfo.VolCatStatus, "Full"); Dmsg0(90, "Call update_vol_info\n"); + /* Update position counters */ + jcr->end_block = dev->block_num; + jcr->end_file = dev->file; if (!dir_update_volume_info(jcr, &dev->VolCatInfo, 0)) { /* send Volume info to Director */ Jmsg(jcr, M_ERROR, 0, _("Could not update Volume info Volume=%s Job=%s\n"), dev->VolCatInfo.VolCatName, jcr->Job); @@ -624,6 +627,9 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) jcr->NumVolumes++; Dmsg0(90, "Wake up any waiting threads.\n"); free_block(label_blk); + /* Set new start/end positions */ + jcr->start_block = dev->block_num; + jcr->start_file = dev->file; unblock_device(dev); jcr->run_time += time(NULL) - wait_time; /* correct run time */ return 1; /* device locked */ diff --git a/bacula/src/stored/match_bsr.c b/bacula/src/stored/match_bsr.c new file mode 100755 index 0000000000..2bdcbcb8ae --- /dev/null +++ b/bacula/src/stored/match_bsr.c @@ -0,0 +1,211 @@ +/* + * Match Bootstrap Records (used for restores) against + * Volume Records + * + * Kern Sibbald, June MMII + * + * Version $Id$ + */ + +/* + Copyright (C) 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" + +/* Forward references */ +static int match_sesstime(BSR_SESSTIME *sesstime, DEV_RECORD *rec); +static int match_sessid(BSR_SESSID *sessid, DEV_RECORD *rec); +static int match_client(BSR_CLIENT *client, SESSION_LABEL *sesrec); +static int match_job(BSR_JOB *job, SESSION_LABEL *sesrec); +static int match_job_type(BSR_JOBTYPE *job_type, SESSION_LABEL *sesrec); +static int match_job_level(BSR_JOBLEVEL *job_level, SESSION_LABEL *sesrec); +static int match_jobid(BSR_JOBID *jobid, SESSION_LABEL *sesrec); +static int match_file_index(BSR_FINDEX *findex, DEV_RECORD *rec); +static int match_one_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sesrec); + +/********************************************************************* + * + * Match Bootstrap records + * + */ +int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sesrec) +{ + if (!bsr) { + return 0; + } + if (match_one_bsr(bsr, rec, volrec, sesrec)) { + return 1; + } + return match_bsr(bsr->next, rec, volrec, sesrec); +} + +static int match_one_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sesrec) +{ + if (strcmp(bsr->VolumeName, volrec->VolName) != 0) { + return 0; + } + if (!match_client(bsr->client, sesrec)) { + return 0; + } + if (!match_sessid(bsr->sessid, rec)) { + return 0; + } + if (!match_sesstime(bsr->sesstime, rec)) { + return 0; + } + if (!match_job(bsr->job, sesrec)) { + return 0; + } + if (!match_file_index(bsr->FileIndex, rec)) { + return 0; + } + if (!match_job_type(bsr->JobType, sesrec)) { + return 0; + } + if (!match_job_level(bsr->JobLevel, sesrec)) { + return 0; + } + if (!match_jobid(bsr->JobId, sesrec)) { + return 0; + } + return 1; +} + +static int match_client(BSR_CLIENT *client, SESSION_LABEL *sesrec) +{ + if (!client) { + return 1; /* no specification matches all */ + } + if (strcmp(client->ClientName, sesrec->ClientName) == 0) { + return 1; + } + if (client->next) { + return match_client(client->next, sesrec); + } + return 0; +} + +static int match_job(BSR_JOB *job, SESSION_LABEL *sesrec) +{ + if (!job) { + return 1; /* no specification matches all */ + } + if (strcmp(job->Job, sesrec->Job) == 0) { + job->found++; + return 1; + } + if (job->next) { + return match_job(job->next, sesrec); + } + return 0; +} + + +static int match_job_type(BSR_JOBTYPE *job_type, SESSION_LABEL *sesrec) +{ + if (!job_type) { + return 1; /* no specification matches all */ + } + if (job_type->JobType == sesrec->JobType) { + return 1; + } + if (job_type->next) { + return match_job_type(job_type->next, sesrec); + } + return 0; +} + +static int match_job_level(BSR_JOBLEVEL *job_level, SESSION_LABEL *sesrec) +{ + if (!job_level) { + return 1; /* no specification matches all */ + } + if (job_level->JobLevel == sesrec->JobLevel) { + return 1; + } + if (job_level->next) { + return match_job_level(job_level->next, sesrec); + } + return 0; +} + +static int match_jobid(BSR_JOBID *jobid, SESSION_LABEL *sesrec) +{ + if (!jobid) { + return 1; /* no specification matches all */ + } + if (jobid->JobId == sesrec->JobId) { + jobid->found++; + return 1; + } + if (jobid->next) { + return match_jobid(jobid->next, sesrec); + } + return 0; +} + + +static int match_file_index(BSR_FINDEX *findex, DEV_RECORD *rec) +{ + if (!findex) { + return 1; /* no specification matches all */ + } + if (findex->FileIndex == rec->FileIndex) { + findex->found++; + return 1; + } + if (findex->next) { + return match_file_index(findex->next, rec); + } + return 0; +} + + +static int match_sessid(BSR_SESSID *sessid, DEV_RECORD *rec) +{ + if (!sessid) { + return 1; /* no specification matches all */ + } + if (sessid->sessid1 == rec->VolSessionId) { + sessid->found++; + return 1; + } + if (sessid->next) { + return match_sessid(sessid->next, rec); + } + return 0; +} + +static int match_sesstime(BSR_SESSTIME *sesstime, DEV_RECORD *rec) +{ + if (!sesstime) { + return 1; /* no specification matches all */ + } + if (sesstime->sesstime == rec->VolSessionTime) { + sesstime->found++; + return 1; + } + if (sesstime->next) { + return match_sesstime(sesstime->next, rec); + } + return 0; +} diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c new file mode 100755 index 0000000000..e26ad8af47 --- /dev/null +++ b/bacula/src/stored/parse_bsr.c @@ -0,0 +1,430 @@ +/* + * Parse a Bootstrap Records (used for restores) + * + * Kern Sibbald, June MMII + * + * Version $Id$ + */ + +/* + Copyright (C) 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" + +typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr); + +static BSR *store_vol(LEX *lc, BSR *bsr); +static BSR *store_client(LEX *lc, BSR *bsr); +static BSR *store_job(LEX *lc, BSR *bsr); +static BSR *store_jobid(LEX *lc, BSR *bsr); +static BSR *store_jobtype(LEX *lc, BSR *bsr); +static BSR *store_joblevel(LEX *lc, BSR *bsr); +static BSR *store_file_index(LEX *lc, BSR *bsr); +static BSR *store_sessid(LEX *lc, BSR *bsr); +static BSR *store_sesstime(LEX *lc, BSR *bsr); +static BSR *store_include(LEX *lc, BSR *bsr); +static BSR *store_exclude(LEX *lc, BSR *bsr); + +struct kw_items { + char *name; + ITEM_HANDLER *handler; +}; + +struct kw_items items[] = { + {"volume", store_vol}, + {"client", store_client}, + {"job", store_job}, + {"jobid", store_jobid}, + {"fileindex", store_file_index}, + {"jobtype", store_jobtype}, + {"joblevel", store_joblevel}, + {"volsessionid", store_sessid}, + {"volsessiontime", store_sesstime}, + {"include", store_include}, + {"exclude", store_exclude}, + {NULL, NULL} + +}; + +static BSR *new_bsr() +{ + BSR *bsr = (BSR *)malloc(sizeof(BSR)); + memset(bsr, 0, sizeof(BSR)); + return bsr; +} + +/********************************************************************* + * + * Parse Bootstrap file + * + */ +BSR *parse_bsr(char *cf) +{ + LEX *lc = NULL; + int token, i; + BSR *root_bsr = new_bsr(); + BSR *bsr = root_bsr; + + Dmsg0(200, "Enter parse_bsf()\n"); + lc = lex_open_file(lc, cf); + while ((token=lex_get_token(lc)) != T_EOF) { + Dmsg1(150, "parse got token=%s\n", lex_tok_to_str(token)); + if (token == T_EOL) { + continue; + } + if (token != T_IDENTIFIER) { + scan_err1(lc, "Expected a keyword identifier, got: %s", lc->str); + } + for (i=0; items[i].name; i++) { + if (strcasecmp(items[i].name, lc->str) == 0) { + token = lex_get_token(lc); + Dmsg1 (150, "in T_IDENT got token=%s\n", lex_tok_to_str(token)); + if (token != T_EQUALS) { + scan_err1(lc, "expected an equals, got: %s", lc->str); + } + Dmsg1(150, "calling handler for %s\n", items[i].name); + /* Call item handler */ + bsr = items[i].handler(lc, bsr); + i = -1; + break; + } + } + if (i >= 0) { + Dmsg1(150, "Keyword = %s\n", lc->str); + scan_err1(lc, "Keyword %s not found", lc->str); + } + + } + lc = lex_close_file(lc); + Dmsg0(200, "Leave parse_bsf()\n"); + return root_bsr; +} + +static BSR *store_vol(LEX *lc, BSR *bsr) +{ + int token; + + token = lex_get_token(lc); + if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) { + scan_err1(lc, "expected an identifier or string, got: %s", lc->str); + } else if (lc->str_len > MAX_RES_NAME_LENGTH) { + scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, + lc->str_len, MAX_RES_NAME_LENGTH); + } else { + if (bsr->VolumeName) { + bsr->next = new_bsr(); + bsr = bsr->next; + } + bsr->VolumeName = bstrdup(lc->str); + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_client(LEX *lc, BSR *bsr) +{ + int token; + BSR_CLIENT *client; + + token = lex_get_token(lc); + if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) { + scan_err1(lc, "expected an identifier or string, got: %s", lc->str); + } else if (lc->str_len > MAX_RES_NAME_LENGTH) { + scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, + lc->str_len, MAX_RES_NAME_LENGTH); + } else { + client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT)); + memset(client, 0, sizeof(BSR_CLIENT)); + client->ClientName = bstrdup(lc->str); + /* Add it to the end of the client chain */ + if (!bsr->client) { + bsr->client = client; + } else { + BSR_CLIENT *bc = bsr->client; + for ( ;; ) { + if (bc->next) { + bc = bc->next; + } else { + bc->next = client; + break; + } + } + } + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_job(LEX *lc, BSR *bsr) +{ + int token; + BSR_JOB *job; + + token = lex_get_token(lc); + if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) { + scan_err1(lc, "expected an identifier or string, got: %s", lc->str); + } else if (lc->str_len > MAX_RES_NAME_LENGTH) { + scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, + lc->str_len, MAX_RES_NAME_LENGTH); + } else { + job = (BSR_JOB *)malloc(sizeof(BSR_JOB)); + memset(job, 0, sizeof(BSR_JOB)); + job->Job = bstrdup(lc->str); + /* Add it to the end of the client chain */ + if (!bsr->job) { + bsr->job = job; + } else { + /* Add to end of chain */ + BSR_JOB *bc = bsr->job; + for ( ;bc->next; bc=bc->next) + { } + bc->next = job; + } + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_file_index(LEX *lc, BSR *bsr) +{ + int token; + int32_t FileIndex; + BSR_FINDEX *findex; + + + token = lex_get_token(lc); + if (token != T_NUMBER || !is_a_number(lc->str)) { + scan_err1(lc, "expected a positive integer number, got: %s", lc->str); + } else { + errno = 0; + FileIndex = strtoul(lc->str, NULL, 10); + if (errno != 0) { + scan_err1(lc, "expected a integer number, got: %s", lc->str); + } + findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX)); + memset(findex, 0, sizeof(BSR_FINDEX)); + findex->FileIndex = FileIndex; + /* Add it to the end of the chain */ + if (!bsr->FileIndex) { + bsr->FileIndex = findex; + } else { + /* Add to end of chain */ + BSR_FINDEX *bs = bsr->FileIndex; + for ( ;bs->next; bs=bs->next) + { } + bs->next = findex; + } + } + scan_to_eol(lc); + return bsr; +} + + +static BSR *store_jobid(LEX *lc, BSR *bsr) +{ + int token; + uint32_t JobId; + BSR_JOBID *jobid; + + + token = lex_get_token(lc); + if (token != T_NUMBER || !is_a_number(lc->str)) { + scan_err1(lc, "expected a positive integer number, got: %s", lc->str); + } else { + errno = 0; + JobId = strtoul(lc->str, NULL, 10); + if (errno != 0) { + scan_err1(lc, "expected a integer number, got: %s", lc->str); + } + jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID)); + memset(jobid, 0, sizeof(BSR_JOBID)); + jobid->JobId = JobId; + /* Add it to the end of the chain */ + if (!bsr->JobId) { + bsr->JobId = jobid; + } else { + /* Add to end of chain */ + BSR_JOBID *bs = bsr->JobId; + for ( ;bs->next; bs=bs->next) + { } + bs->next = jobid; + } + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_jobtype(LEX *lc, BSR *bsr) +{ + /* *****FIXME****** */ + Dmsg0(-1, "JobType not yet implemented\n"); + return bsr; +} + + +static BSR *store_joblevel(LEX *lc, BSR *bsr) +{ + /* *****FIXME****** */ + Dmsg0(-1, "JobLevel not yet implemented\n"); + return bsr; +} + + + +static BSR *store_sessid(LEX *lc, BSR *bsr) +{ + int token; + uint32_t sessid1; + BSR_SESSID *sid; + + + token = lex_get_token(lc); + if (token != T_NUMBER || !is_a_number(lc->str)) { + scan_err1(lc, "expected a positive integer number, got: %s", lc->str); + } else { + errno = 0; + sessid1 = strtoul(lc->str, NULL, 10); + if (errno != 0) { + scan_err1(lc, "expected a integer number, got: %s", lc->str); + } + sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID)); + memset(sid, 0, sizeof(BSR_SESSID)); + sid->sessid1 = sessid1; + /* Add it to the end of the chain */ + if (!bsr->sessid) { + bsr->sessid = sid; + } else { + /* Add to end of chain */ + BSR_SESSID *bs = bsr->sessid; + for ( ;bs->next; bs=bs->next) + { } + bs->next = sid; + } + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_sesstime(LEX *lc, BSR *bsr) +{ + int token; + uint32_t sesstime; + BSR_SESSTIME *stime; + + + token = lex_get_token(lc); + if (token != T_NUMBER || !is_a_number(lc->str)) { + scan_err1(lc, "expected a positive integer number, got: %s", lc->str); + } else { + errno = 0; + sesstime = strtoul(lc->str, NULL, 10); + if (errno != 0) { + scan_err1(lc, "expected a integer number, got: %s", lc->str); + } + stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME)); + memset(stime, 0, sizeof(BSR_SESSTIME)); + stime->sesstime = sesstime; + /* Add it to the end of the chain */ + if (!bsr->sesstime) { + bsr->sesstime = stime; + } else { + /* Add to end of chain */ + BSR_SESSTIME *bs = bsr->sesstime; + for ( ;bs->next; bs=bs->next) + { } + bs->next = stime; + } + } + scan_to_eol(lc); + return bsr; +} + +static BSR *store_include(LEX *lc, BSR *bsr) +{ + scan_to_eol(lc); + return bsr; +} + +static BSR *store_exclude(LEX *lc, BSR *bsr) +{ + scan_to_eol(lc); + return bsr; +} + +void dump_bsr(BSR *bsr) +{ + if (!bsr) { + Dmsg0(-1, "BSR is NULL\n"); + return; + } + Dmsg8(-1, +"Next : 0x%x\n" +"VolumeName : %s\n" +"Client : %s\n" +"Job : %s\n" +"JobId : %u\n" +"SessId : %u\n" +"SessTime : %u\n" +"FileIndex : %d\n", + bsr->next, + bsr->VolumeName ? bsr->VolumeName : "*None*", + bsr->client ? bsr->client->ClientName : "*None*", + bsr->job ? bsr->job->Job : "*None*", + bsr->JobId ? bsr->JobId->JobId : 0, + bsr->sessid ? bsr->sessid->sessid1 : 0, + bsr->sesstime ? bsr->sesstime->sesstime : 0, + bsr->FileIndex ? bsr->FileIndex->FileIndex : 0); + if (bsr->next) { + Dmsg0(-1, "\n"); + dump_bsr(bsr->next); + } +} + + +/********************************************************************* + * + * Free bsr resources + */ + +static void free_bsr_item(BSR *bsr) +{ + if (!bsr) { + return; + } + free_bsr_item(bsr->next); + free(bsr); +} + +void free_bsr(BSR *bsr) +{ + if (!bsr) { + return; + } + free_bsr_item((BSR *)bsr->client); + free_bsr_item((BSR *)bsr->sessid); + free_bsr_item((BSR *)bsr->sesstime); + if (bsr->VolumeName) { + free(bsr->VolumeName); + } + free_bsr(bsr->next); + free(bsr); +} diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 7fffbc952c..38ac7c0818 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -28,106 +28,115 @@ uint32_t new_VolSessionId(); /* From askdir.c */ -int dir_get_volume_info(JCR *jcr); -int dir_find_next_appendable_volume(JCR *jcr); -int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel); -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev); -int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev); -int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec); -int dir_send_job_status(JCR *jcr); +int dir_get_volume_info(JCR *jcr); +int dir_find_next_appendable_volume(JCR *jcr); +int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel); +int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev); +int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev); +int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec); +int dir_send_job_status(JCR *jcr); /* authenticate.c */ -int authenticate_director(JCR *jcr); -int authenticate_filed(JCR *jcr); +int authenticate_director(JCR *jcr); +int authenticate_filed(JCR *jcr); /* From block.c */ -void dump_block(DEV_BLOCK *b, char *msg); +void dump_block(DEV_BLOCK *b, char *msg); DEV_BLOCK *new_block(DEVICE *dev); -void init_block_write(DEV_BLOCK *block); -void empty_block(DEV_BLOCK *block); -void free_block(DEV_BLOCK *block); -int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block); -int read_block_from_device(DEVICE *dev, DEV_BLOCK *block); -int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block); +void init_block_write(DEV_BLOCK *block); +void empty_block(DEV_BLOCK *block); +void free_block(DEV_BLOCK *block); +int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block); +int read_block_from_device(DEVICE *dev, DEV_BLOCK *block); +int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block); /* From dev.c */ -DEVICE *init_dev(DEVICE *dev, char *device); -int open_dev(DEVICE *dev, char *VolName, int mode); -void close_dev(DEVICE *dev); -void force_close_dev(DEVICE *dev); -int truncate_dev(DEVICE *dev); -void term_dev(DEVICE *dev); -char * strerror_dev(DEVICE *dev); -void clrerror_dev(DEVICE *dev, int func); -int update_pos_dev(DEVICE *dev); -int rewind_dev(DEVICE *dev); -int load_dev(DEVICE *dev); -int offline_dev(DEVICE *dev); -int flush_dev(DEVICE *dev); -int weof_dev(DEVICE *dev, int num); -int write_block(DEVICE *dev); -int write_dev(DEVICE *dev, char *buf, size_t len); -int read_dev(DEVICE *dev, char *buf, size_t len); -int status_dev(DEVICE *dev, uint32_t *status); -int eod_dev(DEVICE *dev); -int fsf_dev(DEVICE *dev, int num); -int fsr_dev(DEVICE *dev, int num); -int bsf_dev(DEVICE *dev, int num); -int bsr_dev(DEVICE *dev, int num); +DEVICE *init_dev(DEVICE *dev, char *device); +int open_dev(DEVICE *dev, char *VolName, int mode); +void close_dev(DEVICE *dev); +void force_close_dev(DEVICE *dev); +int truncate_dev(DEVICE *dev); +void term_dev(DEVICE *dev); +char * strerror_dev(DEVICE *dev); +void clrerror_dev(DEVICE *dev, int func); +int update_pos_dev(DEVICE *dev); +int rewind_dev(DEVICE *dev); +int load_dev(DEVICE *dev); +int offline_dev(DEVICE *dev); +int flush_dev(DEVICE *dev); +int weof_dev(DEVICE *dev, int num); +int write_block(DEVICE *dev); +int write_dev(DEVICE *dev, char *buf, size_t len); +int read_dev(DEVICE *dev, char *buf, size_t len); +int status_dev(DEVICE *dev, uint32_t *status); +int eod_dev(DEVICE *dev); +int fsf_dev(DEVICE *dev, int num); +int fsr_dev(DEVICE *dev, int num); +int bsf_dev(DEVICE *dev, int num); +int bsr_dev(DEVICE *dev, int num); /* Get info about device */ -char * dev_name(DEVICE *dev); -char * dev_vol_name(DEVICE *dev); +char * dev_name(DEVICE *dev); +char * dev_vol_name(DEVICE *dev); uint32_t dev_block(DEVICE *dev); uint32_t dev_file(DEVICE *dev); -int dev_is_tape(DEVICE *dev); +int dev_is_tape(DEVICE *dev); /* From device.c */ -int open_device(DEVICE *dev); -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); -void block_device(DEVICE *dev, int state); -void unblock_device(DEVICE *dev); -void lock_device(DEVICE *dev); -void unlock_device(DEVICE *dev); -int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int open_device(DEVICE *dev); +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); +void block_device(DEVICE *dev, int state); +void unblock_device(DEVICE *dev); +void lock_device(DEVICE *dev); +void unlock_device(DEVICE *dev); +int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); /* From dircmd.c */ -void connection_request(void *arg); +void connection_request(void *arg); /* From fd_cmds.c */ -void run_job(JCR *jcr); +void run_job(JCR *jcr); /* From fdmsg.c */ -int bget_msg(BSOCK *sock); +int bget_msg(BSOCK *sock); /* From job.c */ -void stored_free_jcr(JCR *jcr); -void connection_from_filed(void *arg); -void handle_filed_connection(BSOCK *fd, char *job_name); +void stored_free_jcr(JCR *jcr); +void connection_from_filed(void *arg); +void handle_filed_connection(BSOCK *fd, char *job_name); /* From label.c */ -int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -void create_session_label(JCR *jcr, DEV_RECORD *rec, int label); -int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName); -int write_session_label(JCR *jcr, DEV_BLOCK *block, int label); -int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -void dump_volume_label(DEVICE *dev); -void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose); -int unser_volume_label(DEVICE *dev, DEV_RECORD *rec); -int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); +int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +void create_session_label(JCR *jcr, DEV_RECORD *rec, int label); +int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName); +int write_session_label(JCR *jcr, DEV_BLOCK *block, int label); +int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +void dump_volume_label(DEVICE *dev); +void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose); +int unser_volume_label(DEVICE *dev, DEV_RECORD *rec); +int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); + +/* From match_bsr.c */ +int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, + SESSION_LABEL *sesrec); + +/* From parse_bsr.c */ +extern BSR *parse_bsr(char *lf); +extern void dump_bsr(BSR *bsr); +extern void free_bsr(BSR *bsr); /* From record.c */ char *FI_to_ascii(int fi); char *stream_to_ascii(int stream); -int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); -int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); +int 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); -int read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record); -int write_record_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record); +void free_record(DEV_RECORD *rec); +int read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record); +int write_record_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record); diff --git a/bacula/src/stored/stored.h b/bacula/src/stored/stored.h index 285aa5b5ce..91d274510d 100644 --- a/bacula/src/stored/stored.h +++ b/bacula/src/stored/stored.h @@ -32,6 +32,7 @@ #include "dev.h" #include "stored_conf.h" #include "jcr.h" +#include "bsr.h" #include "protos.h" #ifdef HAVE_LIBZ #include /* compression headers */ diff --git a/bacula/src/version.h b/bacula/src/version.h index e1b57fda6f..9125719d82 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ -#define VERSION "1.21" +#define VERSION "1.22" #define VSTRING "1" -#define DATE "12 June 2002" -#define LSMDATE "12Jun02" +#define DATE "15 June 2002" +#define LSMDATE "15Jun02" /* Debug flags */ #define DEBUG 1 -- 2.39.5