From a67a0fc0804c92921068ab9ff916df094618899c Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Tue, 25 Jun 2002 10:00:12 +0000 Subject: [PATCH] Basic Restore bootstrap implemented -- kes25Jun02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@49 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/baconfig.h | 4 +- bacula/src/console/console_conf.c | 17 +++- bacula/src/dird/dird_conf.c | 38 ++++++-- bacula/src/dird/dird_conf.h | 1 + bacula/src/dird/fd_cmds.c | 1 + bacula/src/dird/job.c | 10 ++ bacula/src/dird/restore.c | 134 ++++++++++++++++++-------- bacula/src/dird/ua_output.c | 8 +- bacula/src/dird/ua_run.c | 73 ++++++++++---- bacula/src/filed/filed.c | 3 +- bacula/src/filed/filed_conf.c | 15 ++- bacula/src/filed/job.c | 88 ++++++++++++++++- bacula/src/jcr.h | 16 ++-- bacula/src/lib/lex.c | 70 +++++++++----- bacula/src/lib/lex.h | 14 +++ bacula/src/lib/parse_conf.c | 2 +- bacula/src/lib/parse_conf.h | 71 ++++++-------- bacula/src/lib/protos.h | 2 +- bacula/src/stored/Makefile.in | 4 +- bacula/src/stored/bextract.c | 129 +++++++++++++++++++------ bacula/src/stored/bls.c | 54 +++++++---- bacula/src/stored/bsr.h | 53 ++++++----- bacula/src/stored/fd_cmds.c | 71 +++++++++++--- bacula/src/stored/job.c | 9 ++ bacula/src/stored/match_bsr.c | 8 +- bacula/src/stored/parse_bsr.c | 152 +++++++++++++++++++++++++++++- bacula/src/stored/protos.h | 152 +++++++++++++++--------------- bacula/src/stored/read.c | 73 +++++++------- bacula/src/stored/stored.c | 2 +- bacula/src/stored/stored_conf.c | 15 ++- bacula/src/version.h | 4 +- 31 files changed, 931 insertions(+), 362 deletions(-) diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index 11261ed7f7..4262b4a050 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -30,8 +30,6 @@ /* Bacula common configuration defines */ -#define DEBUG 1 /* turn on debug code */ - #define TRUE 1 #define FALSE 0 @@ -48,7 +46,7 @@ jcr[0] = 0; } /* Allow printing of NULL pointers */ -#define NPRT(x) (x)?(x):"(NULL)" +#define NPRT(x) (x)?(x):"*None*" #ifdef ENABLE_NLS #include diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c index 202d750ae3..f0d30810f1 100644 --- a/bacula/src/console/console_conf.c +++ b/bacula/src/console/console_conf.c @@ -243,11 +243,18 @@ void save_resource(int type, struct res_items *items, int pass) } /* Common */ if (!error) { - res = (URES *) malloc(size); + res = (URES *)malloc(size); memcpy(res, &res_all, size); - res->res_dir.hdr.next = resources[rindex].res_head; - resources[rindex].res_head = (RES *)res; - Dmsg1(90, "dir_conf: inserting res: %s\n", res->res_dir.hdr.name); + if (!resources[rindex].res_head) { + resources[rindex].res_head = (RES *)res; /* store first entry */ + } else { + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) + { } + next->next = (RES *)res; + Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), + res->res_dir.hdr.name); + } } - } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index a8087e9a35..1535331327 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -170,6 +170,8 @@ static struct res_items job_items[] = { {"pool", store_res, ITEM(res_job.pool), R_POOL, 0, 0}, {"client", store_res, ITEM(res_job.client), R_CLIENT, 0, 0}, {"fileset", store_res, ITEM(res_job.fs), R_FILESET, 0, 0}, + {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0}, + {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0}, {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0}, {"maxstartdelay", store_time,ITEM(res_job.MaxStartDelay), 0, 0, 0}, {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0}, @@ -301,6 +303,7 @@ static struct s_kw RestoreFields[] = { {"jobid", 'J'}, /* JobId to restore */ {"where", 'W'}, /* root of restore */ {"replace", 'R'}, /* replacement options */ + {"bootstrap", 'B'}, /* bootstrap file */ {NULL, 0} }; @@ -444,7 +447,10 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock); } if (res->res_job.RestoreWhere) { - sendit(sock, " --> Where=%s\n", res->res_job.RestoreWhere); + sendit(sock, " --> Where=%s\n", NPRT(res->res_job.RestoreWhere)); + } + if (res->res_job.RestoreBootstrap) { + sendit(sock, " --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap)); } if (res->res_job.storage) { sendit(sock, " --> "); @@ -670,6 +676,9 @@ void free_resource(int type) if (res->res_job.RestoreWhere) { free(res->res_job.RestoreWhere); } + if (res->res_job.RestoreBootstrap) { + free(res->res_job.RestoreBootstrap); + } break; case R_MSGS: if (res->res_msgs.mail_cmd) @@ -851,12 +860,18 @@ void save_resource(int type, struct res_items *items, int pass) if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); - res->res_dir.hdr.next = resources[rindex].res_head; - resources[rindex].res_head = (RES *)res; - Dmsg2(90, "dir_conf: inserting %s res: %s\n", res_to_str(type), - res->res_dir.hdr.name); + if (!resources[rindex].res_head) { + resources[rindex].res_head = (RES *)res; /* store first entry */ + } else { + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) + { } + next->next = (RES *)res; + Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), + res->res_dir.hdr.name); + } } - } /* @@ -996,7 +1011,7 @@ static void store_backup(LEX *lc, struct res_items *item, int index, int pass) /* * Store restore info for Job record * - * Restore = JobId= Where= Replace= + * Restore = JobId= Where= Replace= Bootstrap= * */ static void store_restore(LEX *lc, struct res_items *item, int index, int pass) @@ -1027,6 +1042,15 @@ static void store_restore(LEX *lc, struct res_items *item, int index, int pass) token = lex_get_token(lc, T_ALL); Dmsg1(190, "Restore value=%s\n", lc->str); switch (RestoreFields[i].token) { + case 'B': + /* Bootstrap */ + if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { + scan_err1(lc, "Expected a Restore bootstrap file, got: %s", lc->str); + } + if (pass == 1) { + res_all.res_job.RestoreBootstrap = bstrdup(lc->str); + } + break; case 'C': /* Find Client Resource */ if (pass == 2) { diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 94a1e05038..862e7c3579 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -154,6 +154,7 @@ struct s_res_job { int level; /* default backup/verify level */ int RestoreJobId; /* What -- JobId to restore */ char *RestoreWhere; /* Where on disk to restore -- directory */ + char *RestoreBootstrap; /* Bootstrap file */ int RestoreOptions; /* How (overwrite, ..) */ btime_t MaxRunTime; /* max run time in seconds */ btime_t MaxStartDelay; /* max start delay in seconds */ diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 08e4f1147b..85f990c2af 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -125,6 +125,7 @@ int send_include_list(JCR *jcr) Dmsg1(20, "dird>filed: include file: %s\n", fileset->include_array[i]); fd->msg = fileset->include_array[i]; if (!bnet_send(fd)) { + fd->msg = msgsave; Emsg0(M_FATAL, 0, _(">filed: write error on socket\n")); jcr->JobStatus = JS_ErrorTerminated; return 0; diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index fbb76047e9..e2ce5d2906 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -307,6 +307,9 @@ void dird_free_jcr(JCR *jcr) if (jcr->RestoreWhere) { free(jcr->RestoreWhere); } + if (jcr->RestoreBootstrap) { + free(jcr->RestoreBootstrap); + } Dmsg0(200, "End dird free_jcr\n"); } @@ -333,6 +336,13 @@ void set_jcr_defaults(JCR *jcr, JOB *job) jcr->catalog = job->client->catalog; jcr->fileset = job->fs; jcr->msgs = job->messages; + if (jcr->RestoreBootstrap) { + free(jcr->RestoreBootstrap); + } + /* This can be overridden by Console program */ + if (job->RestoreBootstrap) { + jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap); + } /* If no default level given, set one */ if (jcr->JobLevel == 0) { switch (jcr->JobType) { diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index f92efb0e2d..bd510d8e0e 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -52,9 +52,11 @@ static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n"; static char OKrestore[] = "2000 OK restore\n"; static char OKstore[] = "2000 OK storage\n"; static char OKsession[] = "2000 OK session\n"; +static char OKbootstrap[] = "2000 OK bootstrap\n"; /* Forward referenced functions */ static void restore_cleanup(JCR *jcr, int status); +static int send_bootstrap_file(JCR *jcr); /* External functions */ @@ -89,37 +91,39 @@ int do_restore(JCR *jcr) Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId); - /* - * Find Job Record for Files to be restored - */ - if (jcr->RestoreJobId != 0) { - rjr.JobId = jcr->RestoreJobId; /* specified by UA */ - } else { - rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */ - } - if (!db_get_job_record(jcr->db, &rjr)) { - Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId, - db_strerror(jcr->db)); - restore_cleanup(jcr, JS_ErrorTerminated); - return 0; - } - Dmsg3(20, "Got JobId=%d VolSessId=%ld, VolSesTime=%ld\n", - rjr.JobId, rjr.VolSessionId, rjr.VolSessionTime); - Dmsg4(20, "StartFile=%ld, EndFile=%ld StartBlock=%ld EndBlock=%ld\n", - rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock); - - /* - * Now find the Volumes we will need for the Restore + /* + * The following code is kept temporarily for compatibility. + * It is the predecessor to the Bootstrap file. */ - jcr->VolumeName[0] = 0; - if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) || - jcr->VolumeName[0] == 0) { - Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), - rjr.JobId, db_strerror(jcr->db)); - restore_cleanup(jcr, JS_ErrorTerminated); - return 0; + if (!jcr->RestoreBootstrap) { + /* + * Find Job Record for Files to be restored + */ + if (jcr->RestoreJobId != 0) { + rjr.JobId = jcr->RestoreJobId; /* specified by UA */ + } else { + rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */ + } + if (!db_get_job_record(jcr->db, &rjr)) { + Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId, + db_strerror(jcr->db)); + restore_cleanup(jcr, JS_ErrorTerminated); + return 0; + } + + /* + * Now find the Volumes we will need for the Restore + */ + jcr->VolumeName[0] = 0; + if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) || + jcr->VolumeName[0] == 0) { + Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), + rjr.JobId, db_strerror(jcr->db)); + restore_cleanup(jcr, JS_ErrorTerminated); + return 0; + } + Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName); } - Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName); /* Print Job Start message */ @@ -180,6 +184,7 @@ int do_restore(JCR *jcr) return 0; } + /* * send Storage daemon address to the File daemon, * then wait for File daemon to make connection @@ -197,26 +202,39 @@ int do_restore(JCR *jcr) } jcr->JobStatus = JS_Running; - /* - * Pass the VolSessionId, VolSessionTime, Start and - * end File and Blocks on the session command. + /* + * Send the bootstrap file -- what Volumes/files to restore */ - bnet_fsend(fd, sessioncmd, - jcr->VolumeName, - rjr.VolSessionId, rjr.VolSessionTime, - rjr.StartFile, rjr.EndFile, rjr.StartBlock, - rjr.EndBlock); - if (!response(fd, OKsession, "Session")) { + if (!send_bootstrap_file(jcr)) { restore_cleanup(jcr, JS_ErrorTerminated); return 0; } + /* + * The following code is deprecated + */ + if (!jcr->RestoreBootstrap) { + /* + * Pass the VolSessionId, VolSessionTime, Start and + * end File and Blocks on the session command. + */ + bnet_fsend(fd, sessioncmd, + jcr->VolumeName, + rjr.VolSessionId, rjr.VolSessionTime, + rjr.StartFile, rjr.EndFile, rjr.StartBlock, + rjr.EndBlock); + if (!response(fd, OKsession, "Session")) { + restore_cleanup(jcr, JS_ErrorTerminated); + return 0; + } + } + /* Send restore command */ if (jcr->RestoreWhere) { bnet_fsend(fd, restorecmd, jcr->RestoreWhere); } else { - bnet_fsend(fd, restorecmd, - jcr->job->RestoreWhere==NULL ? "" : jcr->job->RestoreWhere); + bnet_fsend(fd, restorecmd, + jcr->job->RestoreWhere ? jcr->job->RestoreWhere : ""); } if (!response(fd, OKrestore, "Restore")) { restore_cleanup(jcr, JS_ErrorTerminated); @@ -224,7 +242,7 @@ int do_restore(JCR *jcr) } /* Wait for Job Termination */ - /*** ****FIXME**** get job termination data */ + /*** ****FIXME**** get job termination status */ Dmsg0(20, "wait for job termination\n"); while (bget_msg(fd, 0) > 0) { Dmsg1(0, "dirdmsg); @@ -254,3 +272,37 @@ static void restore_cleanup(JCR *jcr, int status) Dmsg0(20, "Leaving restore_cleanup\n"); } + +static int send_bootstrap_file(JCR *jcr) +{ + FILE *bs; + char buf[1000]; + BSOCK *fd = jcr->file_bsock; + char *bootstrap = "bootstrap\n"; + + Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap); + if (!jcr->RestoreBootstrap) { + return 1; + } + bs = fopen(jcr->RestoreBootstrap, "r"); + if (!bs) { + Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), + jcr->RestoreBootstrap, strerror(errno)); + jcr->JobStatus = JS_ErrorTerminated; + return 0; + } + strcpy(fd->msg, bootstrap); + fd->msglen = strlen(fd->msg); + bnet_send(fd); + while (fgets(buf, sizeof(buf), bs)) { + fd->msglen = Mmsg(&fd->msg, "%s", buf); + bnet_send(fd); + } + bnet_sig(fd, BNET_EOF); + fclose(bs); + if (!response(fd, OKbootstrap, "Bootstrap")) { + jcr->JobStatus = JS_ErrorTerminated; + return 0; + } + return 1; +} diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index 1da05280c9..494120d07a 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -242,7 +242,7 @@ int listcmd(UAContext *ua, char *cmd) for (j=i+1; jargc; j++) { if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) { - strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH); + strncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.Job[MAX_NAME_LENGTH-1] = 0; jr.JobId = 0; db_get_job_record(ua->db, &jr); @@ -262,7 +262,7 @@ int listcmd(UAContext *ua, char *cmd) int done = FALSE; for (j=i+1; jargc; j++) { if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) { - strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH); + strncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.Job[MAX_NAME_LENGTH-1] = 0; jr.JobId = 0; db_get_job_record(ua->db, &jr); @@ -290,7 +290,7 @@ int listcmd(UAContext *ua, char *cmd) int done = FALSE; for (j=i+1; jargc; j++) { if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) { - strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH); + strncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.Job[MAX_NAME_LENGTH-1] = 0; jr.JobId = 0; db_get_job_record(ua->db, &jr); @@ -315,7 +315,7 @@ int listcmd(UAContext *ua, char *cmd) db_list_media_records(ua->db, &mr, prtit, ua); } } else { - bsendmsg(ua, _("Unknown list keyword: %s\n"), ua->argk[i]); + bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i])); } } return 1; diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 913743d543..be8dfc4659 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -50,7 +50,7 @@ int runcmd(UAContext *ua, char *cmd) JOB *job; JCR *jcr; char *job_name, *level_name, *jid, *store_name; - char *where, *fileset_name, *client_name; + char *where, *fileset_name, *client_name, *bootstrap; int i, j, found; STORE *store; CLIENT *client; @@ -63,6 +63,7 @@ int runcmd(UAContext *ua, char *cmd) N_("level"), N_("storage"), N_("where"), + N_("bootstrap"), NULL}; if (!open_db(ua)) { @@ -146,6 +147,14 @@ int runcmd(UAContext *ua, char *cmd) where = ua->argv[i]; break; found = True; + case 7: /* bootstrap */ + if (bootstrap) { + bsendmsg(ua, _("Bootstrap specified twice.\n")); + return 1; + } + bootstrap = ua->argv[i]; + break; + found = True; default: break; } @@ -205,6 +214,7 @@ int runcmd(UAContext *ua, char *cmd) try_again: Dmsg1(20, "JobType=%c\n", jcr->JobType); switch (jcr->JobType) { + char ec1[30]; case JT_BACKUP: case JT_VERIFY: if (level_name) { @@ -239,7 +249,7 @@ Storage: %s\n"), jcr->store->hdr.name); break; case JT_RESTORE: - if (jcr->RestoreJobId == 0) { + if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) { if (jid) { jcr->RestoreJobId = atoi(jid); } else { @@ -250,23 +260,25 @@ Storage: %s\n"), jcr->RestoreJobId = atoi(ua->cmd); } } - jcr->JobLevel = 'F'; /* ***FIXME*** */ + jcr->JobLevel = 'F'; /* default level */ Dmsg1(20, "JobId to restore=%d\n", jcr->RestoreJobId); bsendmsg(ua, _("Run Restore job\n\ JobName: %s\n\ +Bootstrap: %s\n\ Where: %s\n\ -RestoreId: %d\n\ Level: %s\n\ FileSet: %s\n\ Client: %s\n\ -Storage: %s\n"), +Storage: %s\n\ +JobId: %s\n"), job->hdr.name, - jcr->RestoreWhere?jcr->RestoreWhere:job->RestoreWhere, - jcr->RestoreJobId, + NPRT(jcr->RestoreBootstrap), + jcr->RestoreWhere?jcr->RestoreWhere:NPRT(job->RestoreWhere), level_to_str(jcr->JobLevel), jcr->fileset->hdr.name, jcr->client->hdr.name, - jcr->store->hdr.name); + jcr->store->hdr.name, + jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1)); break; default: bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType); @@ -278,15 +290,18 @@ Storage: %s\n"), return 1; } if (strcasecmp(ua->cmd, _("mod")) == 0) { + FILE *fd; + start_prompt(ua, _("Parameters to modify:\n")); - add_prompt(ua, _("Job")); - add_prompt(ua, _("Level")); - add_prompt(ua, _("FileSet")); - add_prompt(ua, _("Client")); - add_prompt(ua, _("Storage")); + add_prompt(ua, _("Job")); /* 0 */ + add_prompt(ua, _("Level")); /* 1 */ + add_prompt(ua, _("FileSet")); /* 2 */ + add_prompt(ua, _("Client")); /* 3 */ + add_prompt(ua, _("Storage")); /* 4 */ if (jcr->JobType == JT_RESTORE) { - add_prompt(ua, _("Where")); - add_prompt(ua, _("JobId")); + add_prompt(ua, _("Bootstrap")); /* 5 */ + add_prompt(ua, _("Where")); /* 6 */ + add_prompt(ua, _("JobId")); /* 7 */ } switch (do_prompt(ua, _("Select parameter to modify"), NULL)) { case 0: @@ -375,10 +390,33 @@ Storage: %s\n"), } break; case 5: + /* Bootstrap */ + if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) { + break; + } + if (jcr->RestoreBootstrap) { + free(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + } + if (ua->cmd[0] != 0) { + jcr->RestoreBootstrap = bstrdup(ua->cmd); + fd = fopen(jcr->RestoreBootstrap, "r"); + if (!fd) { + bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"), + jcr->RestoreBootstrap, strerror(errno)); + free(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + } else { + fclose(fd); + } + } + goto try_again; + case 6: /* Where */ if (!get_cmd(ua, _("Please enter path prefix (where) for restore: "))) { break; } + /* ***FIXME*** allow drive:/ for Windows */ if (ua->cmd[0] != '/') { bsendmsg(ua, _("Prefix must begin with a /\n")); } else { @@ -388,10 +426,13 @@ Storage: %s\n"), jcr->RestoreWhere = bstrdup(ua->cmd); } goto try_again; - case 6: + case 7: /* JobId */ jid = NULL; /* force reprompt */ jcr->RestoreJobId = 0; + if (jcr->RestoreBootstrap) { + bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n")); + } goto try_again; default: goto try_again; diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 4124f8c4be..bbd95ba5c8 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -50,7 +50,8 @@ int win32_client = 0; static char *configfile = NULL; static int foreground = 0; static workq_t dir_workq; /* queue of work from Director */ -static CLIENT *me; /* my resource */ + +CLIENT *me; /* my resource */ static void usage() { diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 315163e706..1c9c2da759 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -286,9 +286,16 @@ void save_resource(int type, struct res_items *items, int pass) if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); - res->res_dir.hdr.next = resources[rindex].res_head; - resources[rindex].res_head = (RES *)res; - Dmsg1(90, "dir_conf: inserting res: %s\n", res->res_dir.hdr.name); + if (!resources[rindex].res_head) { + resources[rindex].res_head = (RES *)res; /* store first entry */ + } else { + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) + { } + next->next = (RES *)res; + Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), + res->res_dir.hdr.name); + } } - } diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index b797bc3481..c0c704fad5 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -30,12 +30,14 @@ #include "filed.h" extern char my_name[]; +extern CLIENT *me; /* our client resource */ /* Imported functions */ extern int status_cmd(JCR *jcr); /* Forward referenced functions */ static int backup_cmd(JCR *jcr); +static int bootstrap_cmd(JCR *jcr); static int cancel_cmd(JCR *jcr); static int setdebug_cmd(JCR *jcr); static int estimate_cmd(JCR *jcr); @@ -51,6 +53,7 @@ static int session_cmd(JCR *jcr); static int response(BSOCK *sd, char *resp, char *cmd); static void filed_free_jcr(JCR *jcr); static int open_sd_read_session(JCR *jcr); +static int send_bootstrap_file(JCR *jcr); /* Exported functions */ @@ -78,6 +81,7 @@ static struct s_cmds cmds[] = { {"status", status_cmd}, {"storage ", storage_cmd}, {"verify", verify_cmd}, + {"bootstrap",bootstrap_cmd}, {NULL, NULL} /* list terminator */ }; @@ -96,6 +100,7 @@ static char OKest[] = "2000 OK estimate files=%ld bytes=%ld\n"; static char OKexc[] = "2000 OK exclude\n"; static char OKlevel[] = "2000 OK level\n"; static char OKbackup[] = "2000 OK backup\n"; +static char OKbootstrap[] = "2000 OK bootstrap\n"; static char OKverify[] = "2000 OK verify\n"; static char OKrestore[] = "2000 OK restore\n"; static char OKsession[] = "2000 OK session\n"; @@ -109,6 +114,7 @@ static char OK_end[] = "3000 OK end\n"; static char OK_open[] = "3000 OK open ticket = %d\n"; static char OK_data[] = "3000 OK data\n"; static char OK_append[] = "3000 OK append data\n"; +static char OKSDbootstrap[] = "3000 OK bootstrap\n"; /* Commands sent to Storage Daemon */ @@ -141,7 +147,7 @@ void *handle_client_request(void *dirp) { int i, found, quit; JCR *jcr; - BSOCK *dir = (BSOCK *) dirp; + BSOCK *dir = (BSOCK *)dirp; jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */ jcr->dir_bsock = dir; @@ -262,9 +268,9 @@ static int estimate_cmd(JCR *jcr) static int job_cmd(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; - char *sd_auth_key; + POOLMEM *sd_auth_key; - sd_auth_key = (char *) get_memory(dir->msglen); + sd_auth_key = get_memory(dir->msglen); if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job, &jcr->VolSessionId, &jcr->VolSessionTime, sd_auth_key) != 5) { @@ -323,6 +329,40 @@ static int exclude_cmd(JCR *jcr) return bnet_fsend(dir, OKexc); } + +static int bootstrap_cmd(JCR *jcr) +{ + BSOCK *dir = jcr->dir_bsock; + POOLMEM *fname = get_pool_memory(PM_FNAME); + FILE *bs; + + if (jcr->RestoreBootstrap) { + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + } + Mmsg(&fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name, + jcr->Job); + Dmsg1(400, "bootstrap=%s\n", fname); + jcr->RestoreBootstrap = fname; + bs = fopen(fname, "a+"); /* create file */ + if (!bs) { + Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"), + jcr->RestoreBootstrap, strerror(errno)); + free_pool_memory(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + return 0; + } + + while (bnet_recv(dir) > 0) { + Dmsg1(200, "filedmsg); + fputs(dir->msg, bs); + } + fclose(bs); + + return bnet_fsend(dir, OKbootstrap); +} + + /* * Get backup level from Director * @@ -670,6 +710,10 @@ static int open_sd_read_session(JCR *jcr) return 0; } + if (!send_bootstrap_file(jcr)) { + return 0; + } + /* * Start read of data with Storage daemon */ @@ -697,6 +741,10 @@ static void filed_free_jcr(JCR *jcr) if (jcr->where) { free_pool_memory(jcr->where); } + if (jcr->RestoreBootstrap) { + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + } if (jcr->last_fname) { free_pool_memory(jcr->last_fname); } @@ -733,3 +781,37 @@ int response(BSOCK *sd, char *resp, char *cmd) } return 0; } + +static int send_bootstrap_file(JCR *jcr) +{ + FILE *bs; + char buf[1000]; + BSOCK *sd = jcr->store_bsock; + char *bootstrap = "bootstrap\n"; + + Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap); + if (!jcr->RestoreBootstrap) { + return 1; + } + bs = fopen(jcr->RestoreBootstrap, "r"); + if (!bs) { + Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), + jcr->RestoreBootstrap, strerror(errno)); + jcr->JobStatus = JS_ErrorTerminated; + return 0; + } + strcpy(sd->msg, bootstrap); + sd->msglen = strlen(sd->msg); + bnet_send(sd); + while (fgets(buf, sizeof(buf), bs)) { + sd->msglen = Mmsg(&sd->msg, "%s", buf); + bnet_send(sd); + } + bnet_sig(sd, BNET_EOF); + fclose(bs); + if (!response(sd, OKSDbootstrap, "Bootstrap")) { + jcr->JobStatus = JS_ErrorTerminated; + return 0; + } + return 1; +} diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 3b7139621d..d88b54df1e 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -103,6 +103,7 @@ struct s_jcr { time_t end_time; /* job end time */ POOLMEM *VolumeName; /* Volume name desired -- pool_memory */ POOLMEM *client_name; /* client name */ + char *RestoreBootstrap; /* Bootstrap file to restore */ char *sd_auth_key; /* SD auth key */ MSGS *msgs; /* Message resource */ @@ -151,7 +152,7 @@ struct s_jcr { char *big_buf; /* I/O buffer */ POOLMEM *compress_buf; /* Compression buffer */ int32_t compress_buf_size; /* Length of compression buffer */ - char *where; /* Root where to restore */ + POOLMEM *where; /* Root where to restore */ int buf_size; /* length of buffer */ FF_PKT *ff; /* Find Files packet */ char stored_addr[MAX_NAME_LENGTH]; /* storage daemon address */ @@ -167,12 +168,13 @@ struct s_jcr { int type; DEVRES *device; /* device to use */ VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */ - POOLMEM *job_name; /* base Job name (not unique) */ - POOLMEM *fileset_name; /* FileSet */ - POOLMEM *pool_name; /* pool to use */ - POOLMEM *pool_type; /* pool type to use */ - POOLMEM *media_type; /* media type */ - POOLMEM *dev_name; /* device name */ + POOLMEM *job_name; /* base Job name (not unique) */ + POOLMEM *fileset_name; /* FileSet */ + POOLMEM *pool_name; /* pool to use */ + POOLMEM *pool_type; /* pool type to use */ + POOLMEM *media_type; /* media type */ + POOLMEM *dev_name; /* device name */ + VOL_LIST *VolList; /* list to read */ long NumVolumes; /* number of volumes used */ long CurVolume; /* current volume number */ int mode; /* manual/auto run */ diff --git a/bacula/src/lib/lex.c b/bacula/src/lib/lex.c index 322181ad4e..ce92ce3c0c 100644 --- a/bacula/src/lib/lex.c +++ b/bacula/src/lib/lex.c @@ -47,7 +47,7 @@ void scan_to_eol(LEX *lc) /* * Format a scanner error message */ -void s_err(char *file, int line, LEX *lc, char *msg, ...) +static void s_err(char *file, int line, LEX *lc, char *msg, ...) { va_list arg_ptr; char buf[MAXSTRING]; @@ -103,7 +103,8 @@ lex_close_file(LEX *lf) * */ LEX * -lex_open_file(LEX *lf, char *filename) +lex_open_file(LEX *lf, char *filename, LEX_ERROR_HANDLER *scan_error) + { LEX *nf; FILE *fd; @@ -128,6 +129,11 @@ lex_open_file(LEX *lf, char *filename) lf->fname = fname; lf->state = lex_none; lf->ch = L_EOL; + if (scan_error) { + lf->scan_error = scan_error; + } else { + lf->scan_error = s_err; + } Dmsg1(29, "Return lex=%x\n", lf); return lf; } @@ -421,7 +427,7 @@ lex_get_token(LEX *lf, int expect) if (ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' || ch == ';' || ch == ',' || ch == '"' || ch == '#') { lf->state = lex_none; - lf = lex_open_file(lf, lf->str); + lf = lex_open_file(lf, lf->str, NULL); break; } add_str(lf, ch); @@ -453,7 +459,10 @@ lex_get_token(LEX *lf, int expect) } else { char *p = strchr(lf->str, '-'); if (!p) { - scan_err1(lf, "expected an integer or a range, got: %s", lf->str); + scan_err2(lf, "expected an integer or a range, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; + break; } *p++ = 0; /* terminate first half of range */ lf->pint32_val = scan_pint(lf, lf->str); @@ -464,46 +473,63 @@ lex_get_token(LEX *lf, int expect) case T_INT32: if (token != T_NUMBER || !is_a_number(lf->str)) { - scan_err1(lf, "expected an integer number, got: %s", lf->str); + scan_err2(lf, "expected an integer number, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; + break; + } + errno = 0; + lf->int32_val = (int32_t)strtod(lf->str, NULL); + if (errno != 0) { + scan_err2(lf, "expected an integer number, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; } else { - errno = 0; - lf->int32_val = (int32_t)strtod(lf->str, NULL); - if (errno != 0) { - scan_err1(lf, "expected an integer number, got: %s", lf->str); - } + token = T_INT32; } - token = T_INT32; break; case T_INT64: Dmsg2(400, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL)); if (token != T_NUMBER || !is_a_number(lf->str)) { - scan_err1(lf, "expected an integer number, got: %s", lf->str); + scan_err2(lf, "expected an integer number, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; + break; + } + errno = 0; + lf->int64_val = (int64_t)strtod(lf->str, NULL); + if (errno != 0) { + scan_err2(lf, "expected an integer number, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; } else { - errno = 0; - lf->int64_val = (int64_t)strtod(lf->str, NULL); - if (errno != 0) { - scan_err1(lf, "expected an integer number, got: %s", lf->str); - } + token = T_INT64; } - token = T_INT64; break; case T_NAME: if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { - scan_err1(lf, "expected a name: %s", lf->str); + scan_err2(lf, "expected a name, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; } else if (lf->str_len > MAX_RES_NAME_LENGTH) { scan_err3(lf, "name %s length %d too long, max is %d\n", lf->str, lf->str_len, MAX_RES_NAME_LENGTH); + token = T_ERROR; + } else { + token = T_NAME; } - token = T_NAME; break; case T_STRING: if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { - scan_err1(lf, "expected a name: %s", lf->str); + scan_err2(lf, "expected a name, got %s: %s", + lex_tok_to_str(token), lf->str); + token = T_ERROR; + } else { + token = T_STRING; } - token = T_STRING; break; diff --git a/bacula/src/lib/lex.h b/bacula/src/lib/lex.h index 795d31cbcf..d52542ac3c 100644 --- a/bacula/src/lib/lex.h +++ b/bacula/src/lib/lex.h @@ -98,6 +98,20 @@ typedef struct s_lex_context { uint32_t pint32_val2; int32_t int32_val; int64_t int64_val; + void (*scan_error)(char *file, int line, struct s_lex_context *lc, char *msg, ...); } LEX; +typedef void (LEX_ERROR_HANDLER)(char *file, int line, LEX *lc, char *msg, ...); + +/* Lexical scanning errors in parsing conf files */ +#define scan_err0(lc, msg) lc->scan_error(__FILE__, __LINE__, lc, msg) +#define scan_err1(lc, msg, a1) lc->scan_error(__FILE__, __LINE__, lc, msg, a1) +#define scan_err2(lc, msg, a1, a2) lc->scan_error(__FILE__, __LINE__, lc, msg, a1, a2) +#define scan_err3(lc, msg, a1, a2, a3) lc->scan_error(__FILE__, __LINE__, lc, msg, a1, a2, a3) +#define scan_err4(lc, msg, a1, a2, a3, a4) lc->scan_error(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4) +#define scan_err5(lc, msg, a1, a2, a3, a4, a5) lc->scan_error(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5) +#define scan_err6(lc, msg, a1, a2, a3, a4, a5, a6) lc->scan_error(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5, a6) + +void scan_to_eol(LEX *lc); + #endif /* _LEX_H */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 03d76235da..e4d43a9747 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -669,7 +669,7 @@ parse_config(char *cf) Dmsg0(200, "Enter parse_config()\n"); for (pass=1; pass <= 2; pass++) { Dmsg1(200, "parse_config pass %d\n", pass); - lc = lex_open_file(lc, cf); + lc = lex_open_file(lc, cf, NULL); while ((token=lex_get_token(lc, T_ALL)) != T_EOF) { Dmsg1(150, "parse got token=%s\n", lex_tok_to_str(token)); switch (state) { diff --git a/bacula/src/lib/parse_conf.h b/bacula/src/lib/parse_conf.h index f1503b73d9..a666970af8 100644 --- a/bacula/src/lib/parse_conf.h +++ b/bacula/src/lib/parse_conf.h @@ -21,7 +21,7 @@ */ -struct res_items; /* Declare forward referenced structure */ +struct res_items; /* Declare forward referenced structure */ typedef void (MSG_RES_HANDLER)(LEX *lc, struct res_items *item, int index, int pass); /* This is the structure that defines @@ -30,30 +30,30 @@ typedef void (MSG_RES_HANDLER)(LEX *lc, struct res_items *item, int index, int p * tables. */ struct res_items { - char *name; /* Resource name i.e. Director, ... */ - MSG_RES_HANDLER *handler; /* Routine storing the resource item */ - void **value; /* Where to store the item */ - int code; /* item code/additional info */ - int flags; /* flags: default, required, ... */ - int default_value; /* default value */ + char *name; /* Resource name i.e. Director, ... */ + MSG_RES_HANDLER *handler; /* Routine storing the resource item */ + void **value; /* Where to store the item */ + int code; /* item code/additional info */ + int flags; /* flags: default, required, ... */ + int default_value; /* default value */ }; /* For storing name_addr items in res_items table */ #define ITEM(x) ((void **)&res_all.x) -#define MAX_RES_ITEMS 32 /* maximum resource items per RES */ +#define MAX_RES_ITEMS 32 /* maximum resource items per RES */ /* This is the universal header that is * at the beginning of every resource * record. */ struct s_reshdr { - char *name; /* resource name */ - char *desc; /* resource description */ - int rcode; /* resource id or type */ - int refcnt; /* reference count for releasing */ + struct s_reshdr *next; /* pointer to next resource of this type */ + char *name; /* resource name */ + char *desc; /* resource description */ + int rcode; /* resource id or type */ + int refcnt; /* reference count for releasing */ char item_present[MAX_RES_ITEMS]; /* set if item is present in conf file */ - struct s_reshdr *next; /* pointer to next resource of this type */ }; typedef struct s_reshdr RES; @@ -63,26 +63,26 @@ typedef struct s_reshdr RES; * This is the structure that defines the * resources that are available to this daemon. */ -struct s_res { - char *name; /* resource name */ - struct res_items *items; /* list of resource keywords */ - int rcode; /* code if needed */ - RES *res_head; /* where to store it */ +struct s_res { + char *name; /* resource name */ + struct res_items *items; /* list of resource keywords */ + int rcode; /* code if needed */ + RES *res_head; /* where to store it */ }; /* Common Resource definitions */ -#define MAX_RES_NAME_LENGTH MAX_NAME_LENGTH-1 /* maximum resource name length */ +#define MAX_RES_NAME_LENGTH MAX_NAME_LENGTH-1 /* maximum resource name length */ -#define ITEM_REQUIRED 0x1 /* item required */ -#define ITEM_DEFAULT 0x2 /* default supplied */ +#define ITEM_REQUIRED 0x1 /* item required */ +#define ITEM_DEFAULT 0x2 /* default supplied */ /* Message Resource */ struct s_res_msgs { - RES hdr; - char *mail_cmd; /* mail command */ - char *operator_cmd; /* Operator command */ - DEST *dest_chain; /* chain of destinations */ + RES hdr; + char *mail_cmd; /* mail command */ + char *operator_cmd; /* Operator command */ + DEST *dest_chain; /* chain of destinations */ char send_msg[nbytes_for_bits(M_MAX+1)]; /* bit array of types */ }; typedef struct s_res_msgs MSGS; @@ -92,7 +92,7 @@ typedef struct s_res_msgs MSGS; * resource structure definitions. */ union cu_res { - struct s_res_msgs res_msgs; + struct s_res_msgs res_msgs; RES hdr; }; @@ -100,8 +100,8 @@ typedef union cu_res CURES; /* Configuration routines */ -void parse_config __PROTO((char *cf)); -void free_config_resources __PROTO(()); +void parse_config(char *cf); +void free_config_resources(void); /* Resource routines */ RES *GetResWithName(int rcode, char *name); @@ -112,10 +112,6 @@ void dump_resource(int type, RES *res, void sendmsg(void *sock, char *fmt, ...), void free_resource(int type); void init_resource(int type, struct res_items *item); void save_resource(int type, struct res_items *item, int pass); - - -void scan_error(LEX *lc, char *msg, ...); /* old way, do not use */ -void scan_to_eol(LEX *lc); char *res_to_str(int rcode); void store_str(LEX *lc, struct res_items *item, int index, int pass); @@ -131,14 +127,3 @@ void store_int64(LEX *lc, struct res_items *item, int index, int pass); void store_yesno(LEX *lc, struct res_items *item, int index, int pass); void store_time(LEX *lc, struct res_items *item, int index, int pass); void store_size(LEX *lc, struct res_items *item, int index, int pass); - -/* Lexical scanning errors in parsing conf files */ -#define scan_err0(lc, msg) s_err(__FILE__, __LINE__, lc, msg) -#define scan_err1(lc, msg, a1) s_err(__FILE__, __LINE__, lc, msg, a1) -#define scan_err2(lc, msg, a1, a2) s_err(__FILE__, __LINE__, lc, msg, a1, a2) -#define scan_err3(lc, msg, a1, a2, a3) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3) -#define scan_err4(lc, msg, a1, a2, a3, a4) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4) -#define scan_err5(lc, msg, a1, a2, a3, a4, a5) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5) -#define scan_err6(lc, msg, a1, a2, a3, a4, a5, a6) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5, a6) - -void s_err(char *file, int line, LEX *lc, char *msg,...); diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 43926b72d5..37c0f188df 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -84,7 +84,7 @@ void daemon_start (); /* lex.c */ LEX * lex_close_file (LEX *lf); -LEX * lex_open_file (LEX *lf, char *fname); +LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); int lex_get_char (LEX *lf); void lex_unget_char (LEX *lf); char * lex_tok_to_str (int token); diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 35ea4a20bf..6dac0c8b7b 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -39,9 +39,9 @@ TAPESRCS = btape.c block.c dev.c device.c askdir.c label.c \ TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \ record.o stored_conf.o -BLSOBJS = bls.o block.o device.o dev.o askdir.o label.o record.o +BLSOBJS = bls.o block.o device.o dev.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 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 d0e77f947a..418a6e6c23 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -44,7 +44,6 @@ static FF_PKT my_ff; static FF_PKT *ff = &my_ff; static BSR *bsr = NULL; -static SESSION_LABEL sesrec; static void usage() { @@ -63,6 +62,7 @@ static void my_free_jcr(JCR *jcr) return; } + int main (int argc, char *argv[]) { int ch; @@ -138,7 +138,10 @@ int main (int argc, char *argv[]) jcr = new_jcr(sizeof(JCR), my_free_jcr); jcr->VolSessionId = 1; jcr->VolSessionTime = (uint32_t)time(NULL); - jcr->NumVolumes = 1; + jcr->bsr = bsr; + strcpy(jcr->Job, "bextract"); + jcr->dev_name = get_pool_memory(PM_FNAME); + strcpy(jcr->dev_name, argv[0]); do_extract(argv[0], argv[1]); @@ -166,6 +169,7 @@ static void do_extract(char *devname, char *where) POOLMEM *ofile; /* output name with prefix */ POOLMEM *lname; /* link name */ int wherelen; /* prefix length */ + SESSION_LABEL sessrec; if (strncmp(devname, "/dev/", 5) != 0) { /* Try stripping file part */ @@ -178,19 +182,20 @@ static void do_extract(char *devname, char *where) *p = 0; } } + strcpy(jcr->VolumeName, VolName); dev = init_dev(NULL, devname); if (!dev || !open_device(dev)) { - Emsg1(M_ABORT, 0, "Cannot open %s\n", devname); + Emsg1(M_ERROR_TERM, 0, "Cannot open %s\n", devname); } Dmsg0(90, "Device opened for read.\n"); if (stat(where, &statp) < 0) { - Emsg2(M_ABORT, 0, "Cannot stat %s. It must exist. ERR=%s\n", + Emsg2(M_ERROR_TERM, 0, "Cannot stat %s. It must exist. ERR=%s\n", where, strerror(errno)); } if (!S_ISDIR(statp.st_mode)) { - Emsg1(M_ABORT, 0, "%s must be a directory.\n", where); + Emsg1(M_ERROR_TERM, 0, "%s must be a directory.\n", where); } wherelen = strlen(where); @@ -200,11 +205,17 @@ static void do_extract(char *devname, char *where) block = new_block(dev); - strcpy(jcr->VolumeName, VolName); - Dmsg1(100, "Volume=%s\n", jcr->VolumeName); + create_vol_list(jcr); + Dmsg1(20, "Found %d volumes names to restore.\n", jcr->NumVolumes); + + /* + * Ready device for reading, and read records + */ if (!acquire_device_for_read(jcr, dev, block)) { - Emsg1(M_ABORT, 0, "Cannot open %s\n", devname); + free_block(block); + free_vol_list(jcr); + return; } memset(&rec, 0, sizeof(rec)); @@ -215,11 +226,46 @@ static void do_extract(char *devname, char *where) for ( ;; ) { int ok; + DEV_RECORD *record; /* for reading label of multi-volumes */ if (!read_record(dev, block, &rec)) { uint32_t status; + Dmsg1(500, "Main read record failed. rem=%d\n", rec.remainder); if (dev->state & ST_EOT) { - break; + if (rec.remainder) { + Dmsg0(500, "Not end of record.\n"); + } + Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); + /* + * End Of Tape -- mount next Volume (if another specified) + */ + if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) { + VOL_LIST *vol = jcr->VolList; + /* Find next Volume */ + jcr->CurVolume++; + for (int i=1; iCurVolume; i++) { + vol = vol->next; + } + strcpy(jcr->VolumeName, vol->VolumeName); + Dmsg1(400, "There is another volume %s.\n", jcr->VolumeName); + + close_dev(dev); + dev->state &= ~ST_READ; + if (!acquire_device_for_read(jcr, dev, block)) { + Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), + jcr->VolumeName); + ok = FALSE; + break; + } + record = new_record(); + Dmsg1(500, "read record after new tape. rem=%d\n", record->remainder); + read_record(dev, block, record); /* read vol label */ + dump_label_record(dev, record, 0); + free_record(record); + continue; + } + Dmsg0(90, "End of Device reached.\n"); + break; /* End of Tape */ } if (dev->state & ST_EOF) { continue; /* try again */ @@ -228,17 +274,17 @@ static void do_extract(char *devname, char *where) status_dev(dev, &status); Dmsg1(20, "Device status: %x\n", status); if (status & MT_EOD) - Emsg0(M_ABORT, 0, "Unexpected End of Data\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n"); else if (status & MT_EOT) - Emsg0(M_ABORT, 0, "Unexpected End of Tape\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n"); else if (status & MT_EOF) - Emsg0(M_ABORT, 0, "Unexpected End of File\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n"); else if (status & MT_DR_OPEN) - Emsg0(M_ABORT, 0, "Tape Door is Open\n"); + Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n"); else if (!(status & MT_ONLINE)) - Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n"); else - Emsg3(M_ABORT, 0, "Read error %d on Record Header %s: %s\n", n, dev_name(dev), strerror(errno)); + Emsg3(M_ERROR_TERM, 0, "Read error %d on Record Header %s: %s\n", n, dev_name(dev), strerror(errno)); } @@ -254,6 +300,7 @@ static void do_extract(char *devname, char *where) */ if (rec.FileIndex < 0) { char *rtype; + memset(&sessrec, 0, sizeof(sessrec)); switch (rec.FileIndex) { case PRE_LABEL: rtype = "Fresh Volume Label"; @@ -264,7 +311,7 @@ static void do_extract(char *devname, char *where) break; case SOS_LABEL: rtype = "Begin Session"; - unser_session_label(&sesrec, &rec); + unser_session_label(&sessrec, &rec); break; case EOS_LABEL: rtype = "End Session"; @@ -280,6 +327,17 @@ static void do_extract(char *devname, char *where) printf("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", rtype, rec.VolSessionId, rec.VolSessionTime, rec.Stream, rec.data_len); } + + Dmsg1(40, "Got label = %d\n", rec.FileIndex); + if (rec.FileIndex == EOM_LABEL) { /* end of tape? */ + Dmsg0(40, "Get EOM LABEL\n"); + break; /* yes, get out */ + } + continue; /* ignore other labels */ + } /* end if label record */ + + /* Is this the file we want? */ + if (bsr && !match_bsr(bsr, &rec, &dev->VolHdr, &sessrec)) { continue; } @@ -292,7 +350,7 @@ static void do_extract(char *devname, char *where) */ if (extract) { if (ofd < 0) { - Emsg0(M_ABORT, 0, "Logic error output file should be open\n"); + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); } close(ofd); ofd = -1; @@ -323,7 +381,7 @@ static void do_extract(char *devname, char *where) */ sscanf(rec.data, "%ld %d", &record_file_index, &type); if (record_file_index != rec.FileIndex) - Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n", + 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 */ @@ -348,14 +406,8 @@ static void do_extract(char *devname, char *where) *lname = 0; } - /* Is this the file we want? */ - 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)) { + if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { decode_stat(ap, &statp); /* @@ -393,7 +445,7 @@ static void do_extract(char *devname, char *where) 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_ABORT, 0, "Write error: %s\n", strerror(errno)); + Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno)); } } @@ -405,13 +457,13 @@ static void do_extract(char *devname, char *where) compress_len = compress_buf_size; if (uncompress((Bytef *)compress_buf, &compress_len, (const Bytef *)rec.data, (uLong)rec.data_len) != Z_OK) { - Emsg0(M_ABORT, 0, _("Uncompression error.\n")); + 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) { Dmsg0(0, "===Write error===\n"); - Emsg2(M_ABORT, 0, "Write error on %s: %s\n", ofile, strerror(errno)); + 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, @@ -419,7 +471,7 @@ static void do_extract(char *devname, char *where) } #else if (extract) { - Emsg0(M_ABORT, 0, "GZIP data stream found, but GZIP not configured!\n"); + Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n"); } #endif @@ -427,7 +479,7 @@ static void do_extract(char *devname, char *where) /* If extracting, wierd stream (not 1 or 2), close output file anyway */ } else if (extract) { if (ofd < 0) { - Emsg0(M_ABORT, 0, "Logic error output file should be open\n"); + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); } close(ofd); ofd = -1; @@ -492,3 +544,20 @@ static void print_ls_output(char *fname, char *link, int type, struct stat *stat *p = 0; fputs(buf, stdout); } + +/* Dummies to replace askdir.c */ +int dir_get_volume_info(JCR *jcr) { return 1;} +int dir_find_next_appendable_volume(JCR *jcr) { return 1;} +int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; } +int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} +int dir_send_job_status(JCR *jcr) {return 1;} + + +int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) +{ + fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ", + jcr->VolumeName, dev_name(dev)); + getchar(); + return 1; +} diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 69aca0f40c..5224a86e9d 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -202,11 +202,13 @@ static void do_setup(char *infname) Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName); dev = init_dev(NULL, infname); if (!dev) { - Emsg1(M_ABORT, 0, "Cannot open %s\n", infname); + Emsg1(M_FATAL, 0, "Cannot open %s\n", infname); + exit(1); } /* ***FIXME**** init capabilities */ if (!open_device(dev)) { - Emsg1(M_ABORT, 0, "Cannot open %s\n", infname); + Emsg1(M_FATAL, 0, "Cannot open %s\n", infname); + exit(1); } Dmsg0(90, "Device opened for read.\n"); @@ -252,16 +254,15 @@ static int mount_next_volume(char *infname) CurVolume++; Dmsg1(20, "There is another volume %s.\n", p); VolName = p; - close_dev(dev); jcr->VolumeName = check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1); strcpy(jcr->VolumeName, VolName); - printf("Mount Volume %s on device %s and press return when ready.", - VolName, infname); - getchar(); - block->binbuf = 0; /* consumed all bytes */ - if (!ready_dev_for_read(jcr, dev, block)) { - Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName); + + close_dev(dev); + dev->state &= ~ST_READ; + if (!acquire_device_for_read(jcr, dev, block)) { + Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName); + exit(1); } return 1; /* Next volume mounted */ } @@ -280,17 +281,17 @@ static void display_error_status() status_dev(dev, &status); Dmsg1(20, "Device status: %x\n", status); if (status & MT_EOD) - Emsg0(M_ABORT, 0, "Unexpected End of Data\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n"); else if (status & MT_EOT) - Emsg0(M_ABORT, 0, "Unexpected End of Tape\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n"); else if (status & MT_EOF) - Emsg0(M_ABORT, 0, "Unexpected End of File\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n"); else if (status & MT_DR_OPEN) - Emsg0(M_ABORT, 0, "Tape Door is Open\n"); + Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n"); else if (!(status & MT_ONLINE)) - Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n"); + Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n"); else - Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno)); + Emsg2(M_ERROR_TERM, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno)); } @@ -385,7 +386,7 @@ Warning, this Volume is a continuation of Volume %s\n", * NOTE: this no longer exists */ if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) { - Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n"); + Emsg0(M_ERROR_TERM, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n"); } /* @@ -456,7 +457,7 @@ Warning, this Volume is a continuation of Volume %s\n", * NOTE: this no longer exists */ if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) { - Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n"); + Emsg0(M_ERROR_TERM, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n"); } /* @@ -473,7 +474,7 @@ Warning, this Volume is a continuation of Volume %s\n", char *ap; sscanf(rec->data, "%ld %d %s", &record_file_index, &type, fname); if (record_file_index != rec->FileIndex) { - Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n", + Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", rec->FileIndex, record_file_index); } ap = rec->data; @@ -529,3 +530,20 @@ static void print_ls_output(char *fname, char *link, int type, struct stat *stat *p = 0; fputs(buf, stdout); } + +/* Dummies to replace askdir.c */ +int dir_get_volume_info(JCR *jcr) { return 1;} +int dir_find_next_appendable_volume(JCR *jcr) { return 1;} +int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; } +int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} +int dir_send_job_status(JCR *jcr) {return 1;} + + +int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) +{ + fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ", + jcr->VolumeName, dev_name(dev)); + getchar(); + return 1; +} diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h index be8ef84d37..98228c906f 100644 --- a/bacula/src/stored/bsr.h +++ b/bacula/src/stored/bsr.h @@ -32,18 +32,29 @@ #include "findlib/find.h" +/* + * List of Volume names to be read by Storage daemon. + * Formed by Storage daemon from BSR + */ +struct s_vol_list { + struct s_vol_list *next; + char VolumeName[MAX_NAME_LENGTH]; +}; +typedef struct s_vol_list VOL_LIST; + + /* * !!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * !!! !!! - * !!! All records must have a pointer to !!! - * !!! the next item as the first item defined. !!! - * !!! !!! + * !!! !!! + * !!! 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; + char ClientName[MAX_NAME_LENGTH]; } BSR_CLIENT; typedef struct s_bsr_sessid { @@ -61,15 +72,15 @@ typedef struct s_bsr_sesstime { typedef struct s_bsr_volfile { struct s_bsr_volfile *next; - uint32_t sfile; /* start file */ - uint32_t efile; /* end file */ + uint32_t sfile; /* start file */ + uint32_t efile; /* end file */ int found; } BSR_VOLFILE; typedef struct s_bsr_findex { struct s_bsr_findex *next; - int32_t findex; /* start file index */ - int32_t findex2; /* end file index */ + int32_t findex; /* start file index */ + int32_t findex2; /* end file index */ int found; } BSR_FINDEX; @@ -92,25 +103,25 @@ typedef struct s_bsr_joblevel { typedef struct s_bsr_job { struct s_bsr_job *next; - char *Job; + char Job[MAX_NAME_LENGTH]; 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_VOLFILE *volfile; + struct s_bsr *next; /* pointer to next one */ + int done; /* set when everything found */ + char *VolumeName; + BSR_VOLFILE *volfile; BSR_SESSTIME *sesstime; - BSR_SESSID *sessid; - BSR_JOBID *JobId; - BSR_JOB *job; - BSR_CLIENT *client; - BSR_FINDEX *FileIndex; - BSR_JOBTYPE *JobType; + BSR_SESSID *sessid; + BSR_JOBID *JobId; + BSR_JOB *job; + BSR_CLIENT *client; + BSR_FINDEX *FileIndex; + BSR_JOBTYPE *JobType; BSR_JOBLEVEL *JobLevel; - FF_PKT *ff; /* include/exclude */ + FF_PKT *ff; /* include/exclude */ } BSR; diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c index af1867c75a..e770c719a6 100644 --- a/bacula/src/stored/fd_cmds.c +++ b/bacula/src/stored/fd_cmds.c @@ -34,6 +34,7 @@ #include "stored.h" /* Imported variables */ +extern STORES *me; /* Static variables */ static char ferrmsg[] = "3900 Invalid command\n"; @@ -53,6 +54,7 @@ static int append_end_session(JCR *jcr); static int read_open_session(JCR *jcr); static int read_data_cmd(JCR *jcr); static int read_close_session(JCR *jcr); +static int bootstrap_cmd(JCR *jcr); struct s_cmds { char *cmd; @@ -70,26 +72,28 @@ static struct s_cmds fd_cmds[] = { {"read open", read_open_session}, {"read data", read_data_cmd}, {"read close", read_close_session}, + {"bootstrap", bootstrap_cmd}, {NULL, NULL} /* list terminator */ }; /* Commands from the File daemon that require additional scanning */ -/* static char append_open[] = "append open session\n"; */ -static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n"; +static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n"; /* Responses sent to the File daemon */ -static char NO_open[] = "3901 Error session already open\n"; -static char NOT_opened[] = "3902 Error session not opened\n"; -static char OK_end[] = "3000 OK end\n"; -static char OK_close[] = "3000 OK close Volumes = %d\n"; -static char OK_open[] = "3000 OK open ticket = %d\n"; -static char OK_append[] = "3000 OK append data\n"; -static char ERROR_append[] = "3903 Error append data\n"; +static char NO_open[] = "3901 Error session already open\n"; +static char NOT_opened[] = "3902 Error session not opened\n"; +static char OK_end[] = "3000 OK end\n"; +static char OK_close[] = "3000 OK close Volumes = %d\n"; +static char OK_open[] = "3000 OK open ticket = %d\n"; +static char OK_append[] = "3000 OK append data\n"; +static char ERROR_append[] = "3903 Error append data\n"; +static char OK_bootstrap[] = "3000 OK bootstrap\n"; +static char ERROR_bootstrap[] = "3904 Error bootstrap\n"; /* Information sent to the Director */ static char Job_start[] = "3010 Job %s start\n"; static char Job_end[] = - "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%" lld "\n"; + "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n"; /* * Run a File daemon Job -- File daemon already authorized @@ -104,6 +108,7 @@ void run_job(JCR *jcr) int i, found, quit; BSOCK *fd = jcr->file_bsock; BSOCK *dir = jcr->dir_bsock; + char ec1[30]; Dmsg1(20, "Start run Job=%s\n", jcr->Job); @@ -141,7 +146,7 @@ void run_job(JCR *jcr) jcr->JobStatus = JS_Terminated; } bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, - jcr->JobBytes); + edit_uint64(jcr->JobBytes, ec1)); bnet_sig(dir, BNET_EOF); /* send EOF to Director daemon */ return; @@ -303,6 +308,50 @@ static int read_open_session(JCR *jcr) return 1; } +static int bootstrap_cmd(JCR *jcr) +{ + BSOCK *fd = jcr->file_bsock; + POOLMEM *fname = get_pool_memory(PM_FNAME); + FILE *bs; + + if (jcr->RestoreBootstrap) { + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + } + Mmsg(&fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name, + jcr->Job); + Dmsg1(400, "bootstrap=%s\n", fname); + jcr->RestoreBootstrap = fname; + bs = fopen(fname, "a+"); /* create file */ + if (!bs) { + Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"), + jcr->RestoreBootstrap, strerror(errno)); + goto bail_out; + } + while (bnet_recv(fd) > 0) { + Dmsg1(200, "storedmsg); + fputs(fd->msg, bs); + } + fclose(bs); + jcr->bsr = parse_bsr(jcr->RestoreBootstrap); + if (!jcr->bsr) { + goto bail_out; + } + if (debug_level > 20) { + dump_bsr(jcr->bsr); + } + return bnet_fsend(fd, OK_bootstrap); + +bail_out: + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + bnet_fsend(fd, ERROR_bootstrap); + return 0; + +} + + /* * Read Close session command * Close the read session diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index ee5e63e588..c462f58348 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -327,5 +327,14 @@ void stored_free_jcr(JCR *jcr) if (jcr->fileset_name) { free_memory(jcr->fileset_name); } + if (jcr->bsr) { + free_bsr(jcr->bsr); + } + if (jcr->RestoreBootstrap) { + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + } + return; } diff --git a/bacula/src/stored/match_bsr.c b/bacula/src/stored/match_bsr.c index 3eb5387ca7..21d5a19420 100755 --- a/bacula/src/stored/match_bsr.c +++ b/bacula/src/stored/match_bsr.c @@ -157,7 +157,7 @@ static int match_jobid(BSR_JOBID *jobid, SESSION_LABEL *sessrec) if (!jobid) { return 1; /* no specification matches all */ } - if (jobid->JobId >= sessrec->JobId && jobid->JobId2 <= sessrec->JobId) { + if (jobid->JobId <= sessrec->JobId && jobid->JobId2 >= sessrec->JobId) { jobid->found++; return 1; } @@ -173,7 +173,7 @@ static int match_volfile(BSR_VOLFILE *volfile, DEV_RECORD *rec) if (!volfile) { return 1; /* no specification matches all */ } - if (volfile->sfile >= rec->File && volfile->efile <= rec->File) { + if (volfile->sfile <= rec->File && volfile->efile >= rec->File) { volfile->found++; return 1; } @@ -189,7 +189,7 @@ static int match_findex(BSR_FINDEX *findex, DEV_RECORD *rec) if (!findex) { return 1; /* no specification matches all */ } - if (findex->findex >= rec->FileIndex && findex->findex2 <= rec->FileIndex) { + if (findex->findex <= rec->FileIndex && findex->findex2 >= rec->FileIndex) { findex->found++; return 1; } @@ -205,7 +205,7 @@ static int match_sessid(BSR_SESSID *sessid, DEV_RECORD *rec) if (!sessid) { return 1; /* no specification matches all */ } - if (sessid->sessid >= rec->VolSessionId && sessid->sessid2 <= rec->VolSessionId) { + if (sessid->sessid <= rec->VolSessionId && sessid->sessid2 >= rec->VolSessionId) { sessid->found++; return 1; } diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index 91ee185c11..522b19b05a 100755 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -73,6 +73,24 @@ static BSR *new_bsr() return bsr; } +/* + * Format a scanner error message + */ +static 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_FATAL, 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); +} + + /********************************************************************* * * Parse Bootstrap file @@ -86,7 +104,7 @@ BSR *parse_bsr(char *cf) BSR *bsr = root_bsr; Dmsg0(200, "Enter parse_bsf()\n"); - lc = lex_open_file(lc, cf); + lc = lex_open_file(lc, cf, s_err); while ((token=lex_get_token(lc, T_ALL)) != T_EOF) { Dmsg1(150, "parse got token=%s\n", lex_tok_to_str(token)); if (token == T_EOL) { @@ -98,6 +116,8 @@ BSR *parse_bsr(char *cf) 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); + bsr = NULL; + break; } Dmsg1(100, "calling handler for %s\n", items[i].name); /* Call item handler */ @@ -109,11 +129,18 @@ BSR *parse_bsr(char *cf) if (i >= 0) { Dmsg1(150, "Keyword = %s\n", lc->str); scan_err1(lc, "Keyword %s not found", lc->str); + break; + } + if (!bsr) { + break; } - } lc = lex_close_file(lc); Dmsg0(200, "Leave parse_bsf()\n"); + if (!bsr) { + free_bsr(root_bsr); + root_bsr = NULL; + } return root_bsr; } @@ -122,6 +149,9 @@ static BSR *store_vol(LEX *lc, BSR *bsr) int token; token = lex_get_token(lc, T_NAME); + if (token == T_ERROR) { + return NULL; + } if (bsr->VolumeName) { bsr->next = new_bsr(); bsr = bsr->next; @@ -138,9 +168,12 @@ static BSR *store_client(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_NAME); + if (token == T_ERROR) { + return NULL; + } client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT)); memset(client, 0, sizeof(BSR_CLIENT)); - client->ClientName = bstrdup(lc->str); + strcpy(client->ClientName, lc->str); /* Add it to the end of the client chain */ if (!bsr->client) { bsr->client = client; @@ -165,9 +198,12 @@ static BSR *store_job(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_NAME); + if (token == T_ERROR) { + return NULL; + } job = (BSR_JOB *)malloc(sizeof(BSR_JOB)); memset(job, 0, sizeof(BSR_JOB)); - job->Job = bstrdup(lc->str); + strcpy(job->Job, lc->str); /* Add it to the end of the client chain */ if (!bsr->job) { bsr->job = job; @@ -193,6 +229,9 @@ static BSR *store_findex(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_PINT32_RANGE); + if (token == T_ERROR) { + return NULL; + } findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX)); memset(findex, 0, sizeof(BSR_FINDEX)); findex->findex = lc->pint32_val; @@ -223,6 +262,9 @@ static BSR *store_jobid(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_PINT32_RANGE); + if (token == T_ERROR) { + return NULL; + } jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID)); memset(jobid, 0, sizeof(BSR_JOBID)); jobid->JobId = lc->pint32_val; @@ -273,6 +315,9 @@ static BSR *store_volfile(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_PINT32_RANGE); + if (token == T_ERROR) { + return NULL; + } volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE)); memset(volfile, 0, sizeof(BSR_VOLFILE)); volfile->sfile = lc->pint32_val; @@ -304,6 +349,9 @@ static BSR *store_sessid(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_PINT32_RANGE); + if (token == T_ERROR) { + return NULL; + } sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID)); memset(sid, 0, sizeof(BSR_SESSID)); sid->sessid = lc->pint32_val; @@ -333,6 +381,9 @@ static BSR *store_sesstime(LEX *lc, BSR *bsr) for (;;) { token = lex_get_token(lc, T_PINT32); + if (token == T_ERROR) { + return NULL; + } stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME)); memset(stime, 0, sizeof(BSR_SESSTIME)); stime->sesstime = lc->pint32_val; @@ -498,3 +549,96 @@ void free_bsr(BSR *bsr) free_bsr(bsr->next); free(bsr); } + +/***************************************************************** + * Routines for handling volumes + */ +VOL_LIST *new_vol() +{ + VOL_LIST *vol; + vol = (VOL_LIST *)malloc(sizeof(VOL_LIST)); + memset(vol, 0, sizeof(VOL_LIST)); + return vol; +} + +/* + * Add current volume to end of list, only if the Volume + * is not already in the list. + * + * returns: 1 if volume added + * 0 if volume already in list + */ +int add_vol(JCR *jcr, VOL_LIST *vol) +{ + VOL_LIST *next = jcr->VolList; + + if (!next) { /* list empty ? */ + jcr->VolList = vol; /* yes, add volume */ + } else { + for ( ; next->next; next=next->next) { + if (strcmp(vol->VolumeName, next->VolumeName) == 0) { + return 0; /* already in list */ + } + } + if (strcmp(vol->VolumeName, next->VolumeName) == 0) { + return 0; /* already in list */ + } + next->next = vol; /* add volume */ + } + return 1; +} + +void free_vol_list(JCR *jcr) +{ + VOL_LIST *next = jcr->VolList; + VOL_LIST *tmp; + + for ( ; next; ) { + tmp = next->next; + free(next); + next = tmp; + } +} + +void create_vol_list(JCR *jcr) +{ + char *p, *n; + VOL_LIST *vol; + + /* + * Build a list of volume to be processed + */ + jcr->NumVolumes = 0; + jcr->CurVolume = 1; + if (jcr->bsr) { + BSR *bsr = jcr->bsr; + strcpy(jcr->VolumeName, bsr->VolumeName); /* setup first volume */ + for ( ; bsr; bsr=bsr->next) { + vol = new_vol(); + strcpy(vol->VolumeName, bsr->VolumeName); + if (add_vol(jcr, vol)) { + jcr->NumVolumes++; + Dmsg1(400, "Added volume %s\n", vol->VolumeName); + } else { + Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName); + free((char *)vol); + } + } + } else { + /* This is the old way -- deprecated */ + for (p = jcr->VolumeName; p && *p; ) { + n = strchr(p, '|'); /* volume name separator */ + if (n) { + *n++ = 0; /* Terminate name */ + } + vol = new_vol(); + strcpy(vol->VolumeName, p); + if (add_vol(jcr, vol)) { + jcr->NumVolumes++; + } else { + free((char *)vol); + } + p = n; + } + } +} diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 38ac7c0818..ec564adc6a 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -28,115 +28,119 @@ 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); + 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); +extern VOL_LIST *new_vol(); +extern int add_vol(JCR *jcr, VOL_LIST *vol); +extern void free_vol_list(JCR *jcr); +extern void create_vol_list(JCR *jcr); /* 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/read.c b/bacula/src/stored/read.c index d956494a10..baf57f549d 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -1,5 +1,6 @@ /* * Read code for Storage daemon + * * Kern Sibbald, November MM * * Version $Id$ @@ -42,6 +43,7 @@ extern int FiledDataChan; /* File daemon data channel (port) */ static char OK_data[] = "3000 OK data\n"; static char rec_header[] = "rechdr %ld %ld %ld %ld %ld"; + /* * Read Data and send to File Daemon * Returns: 0 on failure @@ -55,12 +57,13 @@ int do_read_data(JCR *jcr) DEVICE *dev; DEV_RECORD rec; DEV_BLOCK *block; - char *hdr, *p; - + POOLMEM *hdr; + SESSION_LABEL sessrec; /* session record */ Dmsg0(20, "Start read data.\n"); dev = jcr->device->dev; + memset(&sessrec, 0, sizeof(sessrec)); /* Tell File daemon we will send data */ bnet_fsend(fd_sock, OK_data); @@ -77,17 +80,7 @@ int do_read_data(JCR *jcr) block = new_block(dev); - /* Find out if we were passed multiple volumes */ - jcr->NumVolumes = 1; - jcr->CurVolume = 1; - /* Scan through VolumeNames terminating them and counting them */ - for (p = jcr->VolumeName; p && *p; ) { - p = strchr(p, '|'); /* volume name separator */ - if (p) { - *p++ = 0; /* Terminate name */ - jcr->NumVolumes++; - } - } + create_vol_list(jcr); Dmsg1(20, "Found %d volumes names to restore.\n", jcr->NumVolumes); @@ -96,20 +89,20 @@ int do_read_data(JCR *jcr) */ if (!acquire_device_for_read(jcr, dev, block)) { free_block(block); + free_vol_list(jcr); return 0; } memset(&rec, 0, sizeof(rec)); rec.data = ds->msg; /* use socket message buffer */ - hdr = (char *) get_pool_memory(PM_MESSAGE); + hdr = get_pool_memory(PM_MESSAGE); /* - * ****FIXME**** enhance this to look for - * more things than just a session. + * Read records, apply BSR filtering, and return any that are + * matched. */ for ( ;ok; ) { DEV_RECORD *record; /* for reading label of multi-volumes */ - SESSION_LABEL sessrec; /* session record */ if (job_cancelled(jcr)) { ok = FALSE; @@ -124,16 +117,21 @@ int do_read_data(JCR *jcr) Dmsg0(500, "Not end of record.\n"); } Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); + /* + * End Of Tape -- mount next Volume (if another specified) + */ if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) { + VOL_LIST *vol = jcr->VolList; close_dev(dev); - for (p=jcr->VolumeName; *p++; ) /* skip to next volume name */ - { } jcr->CurVolume++; - Dmsg1(20, "There is another volume %s.\n", p); - strcpy(jcr->VolumeName, p); + for (int i=1; iCurVolume; i++) { + vol = vol->next; + } + strcpy(jcr->VolumeName, vol->VolumeName); + Dmsg1(000, "There is another volume %s.\n", jcr->VolumeName); dev->state &= ~ST_READ; if (!acquire_device_for_read(jcr, dev, block)) { - Emsg2(M_ERROR, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), p); + Emsg2(M_ERROR, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName); ok = FALSE; break; } @@ -152,12 +150,15 @@ int do_read_data(JCR *jcr) continue; /* End of File */ } - Emsg2(M_ABORT, 0, "Read error on Record Header %s ERR=%s\n", dev_name(dev), strerror(errno)); + Jmsg2(jcr, M_FATAL, 0, "Read error on Record Header %s ERR=%s\n", dev_name(dev), strerror(errno)); + ok = FALSE; + break; } /* Some sort of label? */ if (rec.FileIndex < 0) { char *rtype; + memset(&sessrec, 0, sizeof(sessrec)); switch (rec.FileIndex) { case PRE_LABEL: rtype = "Fresh Volume Label"; @@ -191,18 +192,21 @@ int do_read_data(JCR *jcr) break; /* yes, get out */ } continue; /* ignore other labels */ - } - - /* ****FIXME***** make sure we REALLY have a session record */ - if (jcr->bsr && !match_bsr(jcr->bsr, &rec, &dev->VolHdr, &sessrec)) { - Dmsg0(50, "BSR rejected record\n"); - continue; - } + } /* end if label record */ - if (rec.VolSessionId != jcr->read_VolSessionId || - rec.VolSessionTime != jcr->read_VolSessionTime) { - Dmsg0(50, "Ignore record ids not equal\n"); - continue; /* ignore */ + if (jcr->bsr) { + /* Match BSR against current record */ + if (!match_bsr(jcr->bsr, &rec, &dev->VolHdr, &sessrec)) { + Dmsg0(50, "BSR rejected record\n"); + continue; + } + } else { + /* Old way, deprecated */ + if (rec.VolSessionId != jcr->read_VolSessionId || + rec.VolSessionTime != jcr->read_VolSessionTime) { + Dmsg0(50, "Ignore record ids not equal\n"); + continue; /* ignore */ + } } /* Generate Header parameters and send to File daemon @@ -240,6 +244,7 @@ int do_read_data(JCR *jcr) } free_pool_memory(hdr); free_block(block); + free_vol_list(jcr); Dmsg0(30, "Done reading.\n"); return ok ? 1 : 0; } diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 9b151b0fd7..568ad16e73 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -51,7 +51,7 @@ BSHM bshm; /* shared memory control packet */ /* This is our own global resource */ -static STORES *me; +STORES *me; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static uint32_t VolSessionId = 0; diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 1220202d55..c034df374a 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -363,9 +363,18 @@ void save_resource(int type, struct res_items *items, int pass) } /* Common */ if (!error) { - res = (URES *) malloc(size); + res = (URES *)malloc(size); memcpy(res, &res_all, size); - res->res_dir.hdr.next = resources[rindex].res_head; - resources[rindex].res_head = (RES *)res; + if (!resources[rindex].res_head) { + resources[rindex].res_head = (RES *)res; /* store first entry */ + } else { + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) + { } + next->next = (RES *)res; + Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), + res->res_dir.hdr.name); + } } } diff --git a/bacula/src/version.h b/bacula/src/version.h index c6485ed68b..24fd1d157e 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.22" #define VSTRING "1" -#define DATE "22 June 2002" -#define LSMDATE "22Jun02" +#define DATE "25 June 2002" +#define LSMDATE "25Jun02" /* Debug flags */ #define DEBUG 1 -- 2.39.5