/* Bacula common configuration defines */
-#define DEBUG 1 /* turn on debug code */
-
#define TRUE 1
#define FALSE 0
jcr[0] = 0; }
/* Allow printing of NULL pointers */
-#define NPRT(x) (x)?(x):"(NULL)"
+#define NPRT(x) (x)?(x):"*None*"
#ifdef ENABLE_NLS
#include <libintl.h>
}
/* 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);
+ }
}
-
}
{"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},
{"jobid", 'J'}, /* JobId to restore */
{"where", 'W'}, /* root of restore */
{"replace", 'R'}, /* replacement options */
+ {"bootstrap", 'B'}, /* bootstrap file */
{NULL, 0}
};
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, " --> ");
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)
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);
+ }
}
-
}
/*
/*
* Store restore info for Job record
*
- * Restore = JobId=<job-id> Where=<root-directory> Replace=<options>
+ * Restore = JobId=<job-id> Where=<root-directory> Replace=<options> Bootstrap=<file>
*
*/
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) {
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 */
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;
if (jcr->RestoreWhere) {
free(jcr->RestoreWhere);
}
+ if (jcr->RestoreBootstrap) {
+ free(jcr->RestoreBootstrap);
+ }
Dmsg0(200, "End dird free_jcr\n");
}
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) {
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 */
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 */
return 0;
}
+
/*
* send Storage daemon address to the File daemon,
* then wait for File daemon to make connection
}
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);
}
/* 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, "dird<filed: %s\n", fd->msg);
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;
+}
for (j=i+1; j<ua->argc; 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);
int done = FALSE;
for (j=i+1; j<ua->argc; 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);
int done = FALSE;
for (j=i+1; j<ua->argc; 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);
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;
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;
N_("level"),
N_("storage"),
N_("where"),
+ N_("bootstrap"),
NULL};
if (!open_db(ua)) {
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;
}
try_again:
Dmsg1(20, "JobType=%c\n", jcr->JobType);
switch (jcr->JobType) {
+ char ec1[30];
case JT_BACKUP:
case JT_VERIFY:
if (level_name) {
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 {
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);
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:
}
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 {
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;
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()
{
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);
+ }
}
-
}
#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);
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 */
{"status", status_cmd},
{"storage ", storage_cmd},
{"verify", verify_cmd},
+ {"bootstrap",bootstrap_cmd},
{NULL, NULL} /* list terminator */
};
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";
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 */
{
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;
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) {
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, "filed<dird: bootstrap file %s\n", dir->msg);
+ fputs(dir->msg, bs);
+ }
+ fclose(bs);
+
+ return bnet_fsend(dir, OKbootstrap);
+}
+
+
/*
* Get backup level from Director
*
return 0;
}
+ if (!send_bootstrap_file(jcr)) {
+ return 0;
+ }
+
/*
* Start read of data with Storage daemon
*/
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);
}
}
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;
+}
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 */
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 */
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 */
/*
* 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];
*
*/
LEX *
-lex_open_file(LEX *lf, char *filename)
+lex_open_file(LEX *lf, char *filename, LEX_ERROR_HANDLER *scan_error)
+
{
LEX *nf;
FILE *fd;
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;
}
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);
} 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);
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;
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 */
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) {
*/
-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
* 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;
* 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;
* resource structure definitions.
*/
union cu_res {
- struct s_res_msgs res_msgs;
+ struct s_res_msgs res_msgs;
RES hdr;
};
/* 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);
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);
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,...);
/* 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);
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
static FF_PKT *ff = &my_ff;
static BSR *bsr = NULL;
-static SESSION_LABEL sesrec;
static void usage()
{
return;
}
+
int main (int argc, char *argv[])
{
int ch;
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]);
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 */
*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);
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));
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; i<jcr->CurVolume; 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 */
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));
}
*/
if (rec.FileIndex < 0) {
char *rtype;
+ memset(&sessrec, 0, sizeof(sessrec));
switch (rec.FileIndex) {
case PRE_LABEL:
rtype = "Fresh Volume Label";
break;
case SOS_LABEL:
rtype = "Begin Session";
- unser_session_label(&sesrec, &rec);
+ unser_session_label(&sessrec, &rec);
break;
case EOS_LABEL:
rtype = "End Session";
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;
}
*/
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;
*/
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 */
*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);
/*
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));
}
}
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,
}
#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
/* 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;
*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;
+}
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");
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 */
}
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));
}
* 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");
}
/*
* 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");
}
/*
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;
*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;
+}
#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 {
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;
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;
#include "stored.h"
/* Imported variables */
+extern STORES *me;
/* Static variables */
static char ferrmsg[] = "3900 Invalid command\n";
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;
{"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
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);
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;
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, "stored<filed: bootstrap file %s\n", fd->msg);
+ 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
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;
}
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;
}
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;
}
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;
}
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;
}
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
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) {
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 */
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;
}
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;
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;
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;
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;
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;
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;
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;
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;
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;
+ }
+ }
+}
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);
/*
* Read code for Storage daemon
+ *
* Kern Sibbald, November MM
*
* Version $Id$
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
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);
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);
*/
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;
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; i<jcr->CurVolume; 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;
}
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";
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
}
free_pool_memory(hdr);
free_block(block);
+ free_vol_list(jcr);
Dmsg0(30, "Done reading.\n");
return ok ? 1 : 0;
}
/* This is our own global resource */
-static STORES *me;
+STORES *me;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static uint32_t VolSessionId = 0;
}
/* 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);
+ }
}
}
/* */
#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