2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
28 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 extern CLIENT *me; /* our client resource */
33 int enable_vss = 0; /* set to use vss */
35 /* Imported functions */
36 extern int status_cmd(JCR *jcr);
37 extern int qstatus_cmd(JCR *jcr);
39 /* Forward referenced functions */
40 static int backup_cmd(JCR *jcr);
41 static int bootstrap_cmd(JCR *jcr);
42 static int cancel_cmd(JCR *jcr);
43 static int setdebug_cmd(JCR *jcr);
44 static int estimate_cmd(JCR *jcr);
45 static int hello_cmd(JCR *jcr);
46 static int job_cmd(JCR *jcr);
47 static int fileset_cmd(JCR *jcr);
48 static int level_cmd(JCR *jcr);
49 static int verify_cmd(JCR *jcr);
50 static int restore_cmd(JCR *jcr);
51 static int storage_cmd(JCR *jcr);
52 static int session_cmd(JCR *jcr);
53 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
54 static void filed_free_jcr(JCR *jcr);
55 static int open_sd_read_session(JCR *jcr);
56 static int send_bootstrap_file(JCR *jcr);
57 static int runscript_cmd(JCR *jcr);
58 static int runbefore_cmd(JCR *jcr);
59 static int runafter_cmd(JCR *jcr);
60 static int runbeforenow_cmd(JCR *jcr);
61 static void set_options(findFOPTS *fo, const char *opts);
64 /* Exported functions */
69 int monitoraccess; /* specify if monitors have access to this function */
73 * The following are the recognized commands from the Director.
75 static struct s_cmds cmds[] = {
76 {"backup", backup_cmd, 0},
77 {"cancel", cancel_cmd, 0},
78 {"setdebug=", setdebug_cmd, 0},
79 {"estimate", estimate_cmd, 0},
80 {"Hello", hello_cmd, 1},
81 {"fileset", fileset_cmd, 0},
82 {"JobId=", job_cmd, 0},
83 {"level = ", level_cmd, 0},
84 {"restore", restore_cmd, 0},
85 {"session", session_cmd, 0},
86 {"status", status_cmd, 1},
87 {".status", qstatus_cmd, 1},
88 {"storage ", storage_cmd, 0},
89 {"verify", verify_cmd, 0},
90 {"bootstrap", bootstrap_cmd, 0},
91 {"RunBeforeNow", runbeforenow_cmd, 0},
92 {"RunBeforeJob", runbefore_cmd, 0},
93 {"RunAfterJob", runafter_cmd, 0},
94 {"Run", runscript_cmd, 0},
95 {NULL, NULL} /* list terminator */
98 /* Commands received from director that need scanning */
99 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
100 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
101 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
102 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
103 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
104 static char verifycmd[] = "verify level=%30s\n";
105 static char estimatecmd[] = "estimate listing=%d\n";
106 static char runbefore[] = "RunBeforeJob %s\n";
107 static char runafter[] = "RunAfterJob %s\n";
108 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
109 /* Responses sent to Director */
110 static char errmsg[] = "2999 Invalid command\n";
111 static char no_auth[] = "2998 No Authorization\n";
112 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
113 static char OKinc[] = "2000 OK include\n";
114 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
115 static char OKlevel[] = "2000 OK level\n";
116 static char OKbackup[] = "2000 OK backup\n";
117 static char OKbootstrap[] = "2000 OK bootstrap\n";
118 static char OKverify[] = "2000 OK verify\n";
119 static char OKrestore[] = "2000 OK restore\n";
120 static char OKsession[] = "2000 OK session\n";
121 static char OKstore[] = "2000 OK storage\n";
122 static char OKjob[] = "2000 OK Job %s,%s,%s";
123 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
124 static char BADjob[] = "2901 Bad Job\n";
125 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
126 static char OKRunBefore[] = "2000 OK RunBefore\n";
127 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
128 static char OKRunAfter[] = "2000 OK RunAfter\n";
129 static char OKRunScript[] = "2000 OK RunScript\n";
132 /* Responses received from Storage Daemon */
133 static char OK_end[] = "3000 OK end\n";
134 static char OK_close[] = "3000 OK close Status = %d\n";
135 static char OK_open[] = "3000 OK open ticket = %d\n";
136 static char OK_data[] = "3000 OK data\n";
137 static char OK_append[] = "3000 OK append data\n";
138 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
141 /* Commands sent to Storage Daemon */
142 static char append_open[] = "append open session\n";
143 static char append_data[] = "append data %d\n";
144 static char append_end[] = "append end session %d\n";
145 static char append_close[] = "append close session %d\n";
146 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
147 static char read_data[] = "read data %d\n";
148 static char read_close[] = "read close session %d\n";
151 * Accept requests from a Director
153 * NOTE! We are running as a separate thread
155 * Send output one line
156 * at a time followed by a zero length transmission.
158 * Return when the connection is terminated or there
161 * Basic task here is:
162 * Authenticate Director (during Hello command).
163 * Accept commands one at a time from the Director
167 void *handle_client_request(void *dirp)
172 BSOCK *dir = (BSOCK *)dirp;
174 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
175 jcr->dir_bsock = dir;
176 jcr->ff = init_find_files();
177 jcr->start_time = time(NULL);
178 jcr->RunScripts = New(alist(10, not_owned_by_alist));
179 jcr->last_fname = get_pool_memory(PM_FNAME);
180 jcr->last_fname[0] = 0;
181 jcr->client_name = get_memory(strlen(my_name) + 1);
182 pm_strcpy(jcr->client_name, my_name);
183 jcr->pki_sign = me->pki_sign;
184 jcr->pki_encrypt = me->pki_encrypt;
185 jcr->pki_keypair = me->pki_keypair;
186 jcr->pki_signers = me->pki_signers;
187 jcr->pki_recipients = me->pki_recipients;
189 enable_backup_privileges(NULL, 1 /* ignore_errors */);
191 /**********FIXME******* add command handler error code */
193 for (quit=false; !quit;) {
196 if (bnet_recv(dir) < 0) {
197 break; /* connection terminated */
199 dir->msg[dir->msglen] = 0;
200 Dmsg1(100, "<dird: %s", dir->msg);
202 for (i=0; cmds[i].cmd; i++) {
203 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
204 found = true; /* indicate command found */
205 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
206 bnet_fsend(dir, no_auth);
207 bnet_sig(dir, BNET_EOD);
210 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
211 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
212 bnet_fsend(dir, illegal_cmd);
213 bnet_sig(dir, BNET_EOD);
216 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
217 if (!cmds[i].func(jcr)) { /* do command */
218 quit = true; /* error or fully terminated, get out */
219 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
224 if (!found) { /* command not found */
225 bnet_fsend(dir, errmsg);
231 /* Inform Storage daemon that we are done */
232 if (jcr->store_bsock) {
233 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
237 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
239 generate_daemon_event(jcr, "JobEnd");
241 dequeue_messages(jcr); /* send any queued messages */
243 /* Inform Director that we are done */
244 bnet_sig(dir, BNET_TERMINATE);
246 /* Clean up fileset */
247 FF_PKT *ff = jcr->ff;
248 findFILESET *fileset = ff->fileset;
251 /* Delete FileSet Include lists */
252 for (i=0; i<fileset->include_list.size(); i++) {
253 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
254 for (j=0; j<incexe->opts_list.size(); j++) {
255 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
256 for (k=0; k<fo->regex.size(); k++) {
257 regfree((regex_t *)fo->regex.get(k));
260 fo->regexdir.destroy();
261 fo->regexfile.destroy();
263 fo->wilddir.destroy();
264 fo->wildfile.destroy();
266 fo->fstype.destroy();
274 incexe->opts_list.destroy();
275 incexe->name_list.destroy();
277 fileset->include_list.destroy();
279 /* Delete FileSet Exclude lists */
280 for (i=0; i<fileset->exclude_list.size(); i++) {
281 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
282 for (j=0; j<incexe->opts_list.size(); j++) {
283 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
285 fo->regexdir.destroy();
286 fo->regexfile.destroy();
288 fo->wilddir.destroy();
289 fo->wildfile.destroy();
291 fo->fstype.destroy();
293 incexe->opts_list.destroy();
294 incexe->name_list.destroy();
296 fileset->exclude_list.destroy();
300 Dmsg0(100, "Calling term_find_files\n");
301 term_find_files(jcr->ff);
303 Dmsg0(100, "Done with term_find_files\n");
304 free_jcr(jcr); /* destroy JCR record */
305 Dmsg0(100, "Done with free_jcr\n");
310 * Hello from Director he must identify himself and provide his
313 static int hello_cmd(JCR *jcr)
315 Dmsg0(120, "Calling Authenticate\n");
316 if (!authenticate_director(jcr)) {
319 Dmsg0(120, "OK Authenticate\n");
320 jcr->authenticated = true;
327 static int cancel_cmd(JCR *jcr)
329 BSOCK *dir = jcr->dir_bsock;
330 char Job[MAX_NAME_LENGTH];
333 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
334 if (!(cjcr=get_jcr_by_full_name(Job))) {
335 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
337 if (cjcr->store_bsock) {
338 cjcr->store_bsock->timed_out = 1;
339 cjcr->store_bsock->terminated = 1;
340 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
342 set_jcr_job_status(cjcr, JS_Canceled);
344 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
347 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
349 bnet_sig(dir, BNET_EOD);
355 * Set debug level as requested by the Director
358 static int setdebug_cmd(JCR *jcr)
360 BSOCK *dir = jcr->dir_bsock;
361 int level, trace_flag;
363 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
364 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
365 pm_strcpy(jcr->errmsg, dir->msg);
366 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
370 set_trace(trace_flag);
371 return bnet_fsend(dir, OKsetdebug, level);
375 static int estimate_cmd(JCR *jcr)
377 BSOCK *dir = jcr->dir_bsock;
380 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
381 pm_strcpy(jcr->errmsg, dir->msg);
382 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
383 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
387 bnet_fsend(dir, OKest, jcr->num_files_examined,
388 edit_uint64_with_commas(jcr->JobBytes, ed2));
389 bnet_sig(dir, BNET_EOD);
394 * Get JobId and Storage Daemon Authorization key from Director
396 static int job_cmd(JCR *jcr)
398 BSOCK *dir = jcr->dir_bsock;
399 POOLMEM *sd_auth_key;
401 sd_auth_key = get_memory(dir->msglen);
402 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
403 &jcr->VolSessionId, &jcr->VolSessionTime,
405 pm_strcpy(jcr->errmsg, dir->msg);
406 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
407 bnet_fsend(dir, BADjob);
408 free_pool_memory(sd_auth_key);
411 jcr->sd_auth_key = bstrdup(sd_auth_key);
412 free_pool_memory(sd_auth_key);
413 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
414 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
417 static int runbefore_cmd(JCR *jcr)
420 BSOCK *dir = jcr->dir_bsock;
421 POOLMEM *cmd = get_memory(dir->msglen+1);
424 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
425 if (sscanf(dir->msg, runbefore, cmd) != 1) {
426 pm_strcpy(jcr->errmsg, dir->msg);
427 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
428 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
434 /* Run the command now */
435 script = new_runscript();
436 script->set_command(cmd);
437 script->when = SCRIPT_Before;
438 ok = script->run(jcr, "ClientRunBeforeJob");
439 free_runscript(script);
443 bnet_fsend(dir, OKRunBefore);
446 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
451 static int runbeforenow_cmd(JCR *jcr)
453 BSOCK *dir = jcr->dir_bsock;
455 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
456 return bnet_fsend(dir, OKRunBeforeNow);
459 static int runafter_cmd(JCR *jcr)
461 BSOCK *dir = jcr->dir_bsock;
462 POOLMEM *msg = get_memory(dir->msglen+1);
465 Dmsg1(100, "runafter_cmd: %s", dir->msg);
466 if (sscanf(dir->msg, runafter, msg) != 1) {
467 pm_strcpy(jcr->errmsg, dir->msg);
468 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
469 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
475 cmd = new_runscript();
476 cmd->set_command(msg);
477 cmd->on_success = true;
478 cmd->on_failure = false;
479 cmd->when = SCRIPT_After;
481 jcr->RunScripts->append(cmd);
483 free_pool_memory(msg);
484 return bnet_fsend(dir, OKRunAfter);
487 static int runscript_cmd(JCR *jcr)
489 BSOCK *dir = jcr->dir_bsock;
490 POOLMEM *msg = get_memory(dir->msglen+1);
492 RUNSCRIPT *cmd = new_runscript() ;
494 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
495 if (sscanf(dir->msg, runscript, &cmd->on_success,
497 &cmd->abort_on_error,
500 pm_strcpy(jcr->errmsg, dir->msg);
501 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
502 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
509 cmd->set_command(msg);
511 jcr->RunScripts->append(cmd);
513 free_pool_memory(msg);
514 return bnet_fsend(dir, OKRunScript);
518 static bool init_fileset(JCR *jcr)
521 findFILESET *fileset;
530 fileset = (findFILESET *)malloc(sizeof(findFILESET));
531 memset(fileset, 0, sizeof(findFILESET));
532 ff->fileset = fileset;
533 fileset->state = state_none;
534 fileset->include_list.init(1, true);
535 fileset->exclude_list.init(1, true);
539 static findFOPTS *start_options(FF_PKT *ff)
541 int state = ff->fileset->state;
542 findINCEXE *incexe = ff->fileset->incexe;
544 if (state != state_options) {
545 ff->fileset->state = state_options;
546 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
547 memset(fo, 0, sizeof(findFOPTS));
548 fo->regex.init(1, true);
549 fo->regexdir.init(1, true);
550 fo->regexfile.init(1, true);
551 fo->wild.init(1, true);
552 fo->wilddir.init(1, true);
553 fo->wildfile.init(1, true);
554 fo->base.init(1, true);
555 fo->fstype.init(1, true);
556 incexe->current_opts = fo;
557 incexe->opts_list.append(fo);
559 return incexe->current_opts;
564 * Add fname to include/exclude fileset list. First check for
565 * | and < and if necessary perform command.
567 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
581 p++; /* skip over | */
582 fn = get_pool_memory(PM_FNAME);
583 fn = edit_job_codes(jcr, fn, p, "");
584 bpipe = open_bpipe(fn, 0, "r");
585 free_pool_memory(fn);
587 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
591 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
592 strip_trailing_junk(buf);
593 fileset->incexe->name_list.append(bstrdup(buf));
595 if ((stat=close_bpipe(bpipe)) != 0) {
596 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
597 p, stat, strerror(errno));
602 Dmsg0(100, "Doing < include on client.\n");
603 p++; /* skip over < */
604 if ((ffd = fopen(p, "rb")) == NULL) {
606 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
610 while (fgets(buf, sizeof(buf), ffd)) {
611 strip_trailing_junk(buf);
612 Dmsg1(100, "%s\n", buf);
613 fileset->incexe->name_list.append(bstrdup(buf));
618 fileset->incexe->name_list.append(bstrdup(fname));
624 static void add_fileset(JCR *jcr, const char *item)
626 FF_PKT *ff = jcr->ff;
627 findFILESET *fileset = ff->fileset;
628 int state = fileset->state;
629 findFOPTS *current_opts;
631 /* Get code, optional subcode, and position item past the dividing space */
632 Dmsg1(100, "%s\n", item);
637 int subcode = ' '; /* A space is always a valid subcode */
638 if (item[0] != '\0' && item[0] != ' ') {
646 /* Skip all lines we receive after an error */
647 if (state == state_error) {
652 * The switch tests the code for validity.
653 * The subcode is always good if it is a space, otherwise we must confirm.
654 * We set state to state_error first assuming the subcode is invalid,
655 * requiring state to be set in cases below that handle subcodes.
657 if (subcode != ' ') {
663 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
664 memset(fileset->incexe, 0, sizeof(findINCEXE));
665 fileset->incexe->opts_list.init(1, true);
666 fileset->incexe->name_list.init(1, true);
667 fileset->include_list.append(fileset->incexe);
671 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
672 memset(fileset->incexe, 0, sizeof(findINCEXE));
673 fileset->incexe->opts_list.init(1, true);
674 fileset->incexe->name_list.init(1, true);
675 fileset->exclude_list.append(fileset->incexe);
681 /* File item to either include/include list */
682 state = state_include;
683 add_file_to_fileset(jcr, item, fileset);
686 current_opts = start_options(ff);
690 preg = (regex_t *)malloc(sizeof(regex_t));
691 if (current_opts->flags & FO_IGNORECASE) {
692 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
694 rc = regcomp(preg, item, REG_EXTENDED);
697 regerror(rc, preg, prbuf, sizeof(prbuf));
700 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
704 state = state_options;
705 if (subcode == ' ') {
706 current_opts->regex.append(preg);
707 } else if (subcode == 'D') {
708 current_opts->regexdir.append(preg);
709 } else if (subcode == 'F') {
710 current_opts->regexfile.append(preg);
716 current_opts = start_options(ff);
717 current_opts->base.append(bstrdup(item));
718 state = state_options;
721 current_opts = start_options(ff);
722 current_opts->fstype.append(bstrdup(item));
723 state = state_options;
726 current_opts = start_options(ff);
727 state = state_options;
728 if (subcode == ' ') {
729 current_opts->wild.append(bstrdup(item));
730 } else if (subcode == 'D') {
731 current_opts->wilddir.append(bstrdup(item));
732 } else if (subcode == 'F') {
733 current_opts->wildfile.append(bstrdup(item));
739 current_opts = start_options(ff);
740 set_options(current_opts, item);
741 state = state_options;
744 current_opts = start_options(ff);
745 current_opts->reader = bstrdup(item);
746 state = state_options;
749 current_opts = start_options(ff);
750 current_opts->writer = bstrdup(item);
751 state = state_options;
754 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
758 ff->fileset->state = state;
761 static bool term_fileset(JCR *jcr)
763 FF_PKT *ff = jcr->ff;
766 findFILESET *fileset = ff->fileset;
769 for (i=0; i<fileset->include_list.size(); i++) {
770 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
772 for (j=0; j<incexe->opts_list.size(); j++) {
773 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
774 for (k=0; k<fo->regex.size(); k++) {
775 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
777 for (k=0; k<fo->regexdir.size(); k++) {
778 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
780 for (k=0; k<fo->regexfile.size(); k++) {
781 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
783 for (k=0; k<fo->wild.size(); k++) {
784 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
786 for (k=0; k<fo->wilddir.size(); k++) {
787 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
789 for (k=0; k<fo->wildfile.size(); k++) {
790 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
792 for (k=0; k<fo->base.size(); k++) {
793 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
795 for (k=0; k<fo->fstype.size(); k++) {
796 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
799 Dmsg1(400, "D %s\n", fo->reader);
802 Dmsg1(400, "T %s\n", fo->writer);
805 for (j=0; j<incexe->name_list.size(); j++) {
806 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
809 for (i=0; i<fileset->exclude_list.size(); i++) {
810 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
812 for (j=0; j<incexe->opts_list.size(); j++) {
813 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
814 for (k=0; k<fo->regex.size(); k++) {
815 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
817 for (k=0; k<fo->regexdir.size(); k++) {
818 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
820 for (k=0; k<fo->regexfile.size(); k++) {
821 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
823 for (k=0; k<fo->wild.size(); k++) {
824 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
826 for (k=0; k<fo->wilddir.size(); k++) {
827 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
829 for (k=0; k<fo->wildfile.size(); k++) {
830 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
832 for (k=0; k<fo->base.size(); k++) {
833 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
835 for (k=0; k<fo->fstype.size(); k++) {
836 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
839 for (j=0; j<incexe->name_list.size(); j++) {
840 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
844 return ff->fileset->state != state_error;
849 * As an optimization, we should do this during
850 * "compile" time in filed/job.c, and keep only a bit mask
851 * and the Verify options.
853 static void set_options(findFOPTS *fo, const char *opts)
858 for (p=opts; *p; p++) {
860 case 'a': /* alway replace */
861 case '0': /* no option */
864 fo->flags |= FO_EXCLUDE;
867 fo->flags |= FO_MULTIFS;
869 case 'h': /* no recursion */
870 fo->flags |= FO_NO_RECURSION;
872 case 'H': /* no hard link handling */
873 fo->flags |= FO_NO_HARDLINK;
876 fo->flags |= FO_IGNORECASE;
882 fo->flags |= FO_NOREPLACE;
884 case 'p': /* use portable data format */
885 fo->flags |= FO_PORTABLE;
887 case 'R': /* Resource forks and Finder Info */
888 fo->flags |= FO_HFSPLUS;
889 case 'r': /* read fifo */
890 fo->flags |= FO_READFIFO;
895 /* Old director did not specify SHA variant */
896 fo->flags |= FO_SHA1;
899 fo->flags |= FO_SHA1;
904 fo->flags |= FO_SHA256;
908 fo->flags |= FO_SHA512;
913 /* Automatically downgrade to SHA-1 if an unsupported
914 * SHA variant is specified */
915 fo->flags |= FO_SHA1;
921 fo->flags |= FO_SPARSE;
924 fo->flags |= FO_MTIMEONLY;
927 fo->flags |= FO_KEEPATIME;
932 case 'V': /* verify options */
933 /* Copy Verify Options */
934 for (j=0; *p && *p != ':'; p++) {
935 fo->VerifyOpts[j] = *p;
936 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
940 fo->VerifyOpts[j] = 0;
943 fo->flags |= FO_IF_NEWER;
945 case 'Z': /* gzip compression */
946 fo->flags |= FO_GZIP;
947 fo->GZIP_level = *++p - '0';
948 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
951 fo->flags |= FO_NOATIME;
954 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
962 * Director is passing his Fileset
964 static int fileset_cmd(JCR *jcr)
966 BSOCK *dir = jcr->dir_bsock;
969 sscanf(dir->msg, "fileset vss=%d", &vss);
972 if (!init_fileset(jcr)) {
975 while (bnet_recv(dir) >= 0) {
976 strip_trailing_junk(dir->msg);
977 Dmsg1(500, "Fileset: %s\n", dir->msg);
978 add_fileset(jcr, dir->msg);
980 if (!term_fileset(jcr)) {
983 return bnet_fsend(dir, OKinc);
986 static void free_bootstrap(JCR *jcr)
988 if (jcr->RestoreBootstrap) {
989 unlink(jcr->RestoreBootstrap);
990 free_pool_memory(jcr->RestoreBootstrap);
991 jcr->RestoreBootstrap = NULL;
997 * The Director sends us the bootstrap file, which
998 * we will in turn pass to the SD.
1000 static int bootstrap_cmd(JCR *jcr)
1002 BSOCK *dir = jcr->dir_bsock;
1003 POOLMEM *fname = get_pool_memory(PM_FNAME);
1006 free_bootstrap(jcr);
1007 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
1009 Dmsg1(400, "bootstrap=%s\n", fname);
1010 jcr->RestoreBootstrap = fname;
1011 bs = fopen(fname, "a+b"); /* create file */
1014 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1015 jcr->RestoreBootstrap, be.strerror());
1017 * Suck up what he is sending to us so that he will then
1018 * read our error message.
1020 while (bnet_recv(dir) >= 0)
1022 free_bootstrap(jcr);
1023 set_jcr_job_status(jcr, JS_ErrorTerminated);
1027 while (bnet_recv(dir) >= 0) {
1028 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1029 fputs(dir->msg, bs);
1033 * Note, do not free the bootstrap yet -- it needs to be
1036 return bnet_fsend(dir, OKbootstrap);
1041 * Get backup level from Director
1044 static int level_cmd(JCR *jcr)
1046 BSOCK *dir = jcr->dir_bsock;
1047 POOLMEM *level, *buf = NULL;
1050 level = get_memory(dir->msglen+1);
1051 Dmsg1(110, "level_cmd: %s", dir->msg);
1052 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1055 /* Base backup requested? */
1056 if (strcmp(level, "base") == 0) {
1057 jcr->JobLevel = L_BASE;
1058 /* Full backup requested? */
1059 } else if (strcmp(level, "full") == 0) {
1060 jcr->JobLevel = L_FULL;
1061 } else if (strcmp(level, "differential") == 0) {
1062 jcr->JobLevel = L_DIFFERENTIAL;
1065 } else if (strcmp(level, "incremental") == 0) {
1066 jcr->JobLevel = L_INCREMENTAL;
1070 * We get his UTC since time, then sync the clocks and correct it
1071 * to agree with our clock.
1073 } else if (strcmp(level, "since_utime") == 0) {
1074 buf = get_memory(dir->msglen+1);
1075 utime_t since_time, adj;
1076 btime_t his_time, bt_start, rt=0, bt_adj=0;
1077 if (jcr->JobLevel == L_NONE) {
1078 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1080 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1081 buf, &mtime_only) != 2) {
1084 since_time = str_to_uint64(buf); /* this is the since time */
1085 Dmsg1(100, "since_time=%d\n", (int)since_time);
1086 char ed1[50], ed2[50];
1088 * Sync clocks by polling him for the time. We take
1089 * 10 samples of his time throwing out the first two.
1091 for (int i=0; i<10; i++) {
1092 bt_start = get_current_btime();
1093 bnet_sig(dir, BNET_BTIME); /* poll for time */
1094 if (bnet_recv(dir) <= 0) { /* get response */
1097 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1100 if (i < 2) { /* toss first two results */
1103 his_time = str_to_uint64(buf);
1104 rt = get_current_btime() - bt_start; /* compute round trip time */
1105 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1106 edit_uint64(bt_start, ed2));
1107 bt_adj += bt_start - his_time - rt/2;
1108 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1111 bt_adj = bt_adj / 8; /* compute average time */
1112 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1113 adj = btime_to_utime(bt_adj);
1114 since_time += adj; /* adjust for clock difference */
1116 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1118 bnet_sig(dir, BNET_EOD);
1120 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1121 jcr->incremental = 1; /* set incremental or decremental backup */
1122 jcr->mtime = (time_t)since_time; /* set since time */
1124 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1132 return bnet_fsend(dir, OKlevel);
1135 pm_strcpy(jcr->errmsg, dir->msg);
1136 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1145 * Get session parameters from Director -- this is for a Restore command
1147 static int session_cmd(JCR *jcr)
1149 BSOCK *dir = jcr->dir_bsock;
1151 Dmsg1(100, "SessionCmd: %s", dir->msg);
1152 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1153 &jcr->VolSessionId, &jcr->VolSessionTime,
1154 &jcr->StartFile, &jcr->EndFile,
1155 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1156 pm_strcpy(jcr->errmsg, dir->msg);
1157 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1161 return bnet_fsend(dir, OKsession);
1165 * Get address of storage daemon from Director
1168 static int storage_cmd(JCR *jcr)
1170 int stored_port; /* storage daemon port */
1171 int enable_ssl; /* enable ssl to sd */
1172 BSOCK *dir = jcr->dir_bsock;
1173 BSOCK *sd; /* storage daemon bsock */
1175 Dmsg1(100, "StorageCmd: %s", dir->msg);
1176 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1177 pm_strcpy(jcr->errmsg, dir->msg);
1178 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1181 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1182 /* Open command communications with Storage daemon */
1183 /* Try to connect for 1 hour at 10 second intervals */
1184 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1185 jcr->stored_addr, NULL, stored_port, 1);
1187 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1188 jcr->stored_addr, stored_port);
1189 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1190 jcr->stored_addr, stored_port);
1193 Dmsg0(110, "Connection OK to SD.\n");
1195 jcr->store_bsock = sd;
1197 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1198 if (!authenticate_storagedaemon(jcr)) {
1199 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1202 Dmsg0(110, "Authenticated with SD.\n");
1204 /* Send OK to Director */
1205 return bnet_fsend(dir, OKstore);
1210 * Do a backup. For now, we handle only Full and Incremental.
1212 static int backup_cmd(JCR *jcr)
1214 BSOCK *dir = jcr->dir_bsock;
1215 BSOCK *sd = jcr->store_bsock;
1218 char ed1[50], ed2[50];
1221 // capture state here, if client is backed up by multiple directors
1222 // and one enables vss and the other does not then enable_vss can change
1223 // between here and where its evaluated after the job completes.
1224 bool bDoVSS = false;
1226 bDoVSS = g_pVSSClient && enable_vss;
1228 /* Run only one at a time */
1232 set_jcr_job_status(jcr, JS_Blocked);
1233 jcr->JobType = JT_BACKUP;
1234 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1237 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1241 bnet_fsend(dir, OKbackup);
1242 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1245 * Send Append Open Session to Storage daemon
1247 bnet_fsend(sd, append_open);
1248 Dmsg1(110, ">stored: %s", sd->msg);
1250 * Expect to receive back the Ticket number
1252 if (bget_msg(sd) >= 0) {
1253 Dmsg1(110, "<stored: %s", sd->msg);
1254 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1255 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1258 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1260 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1265 * Send Append data command to Storage daemon
1267 bnet_fsend(sd, append_data, jcr->Ticket);
1268 Dmsg1(110, ">stored: %s", sd->msg);
1271 * Expect to get OK data
1273 Dmsg1(110, "<stored: %s", sd->msg);
1274 if (!response(jcr, sd, OK_data, "Append Data")) {
1278 generate_daemon_event(jcr, "JobStart");
1281 /* START VSS ON WIN 32 */
1283 if (g_pVSSClient->InitializeForBackup()) {
1284 /* tell vss which drives to snapshot */
1285 char szWinDriveLetters[27];
1286 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1287 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1288 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1289 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1292 /* tell user if snapshot creation of a specific drive failed */
1294 for (i=0; i < strlen(szWinDriveLetters); i++) {
1295 if (islower(szWinDriveLetters[i])) {
1296 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1300 /* inform user about writer states */
1301 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1302 if (g_pVSSClient->GetWriterState(i) < 1) {
1303 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1308 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1312 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1318 * Send Files to Storage daemon
1320 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1321 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1322 set_jcr_job_status(jcr, JS_ErrorTerminated);
1323 bnet_suppress_error_messages(sd, 1);
1324 bget_msg(sd); /* Read final response from append_data */
1325 Dmsg0(110, "Error in blast_data.\n");
1327 set_jcr_job_status(jcr, JS_Terminated);
1329 /* run shortly after end of data transmission */
1330 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1332 if (jcr->JobStatus != JS_Terminated) {
1333 bnet_suppress_error_messages(sd, 1);
1334 goto cleanup; /* bail out now */
1337 * Expect to get response to append_data from Storage daemon
1339 if (!response(jcr, sd, OK_append, "Append Data")) {
1340 set_jcr_job_status(jcr, JS_ErrorTerminated);
1345 * Send Append End Data to Storage daemon
1347 bnet_fsend(sd, append_end, jcr->Ticket);
1349 if (!response(jcr, sd, OK_end, "Append End")) {
1350 set_jcr_job_status(jcr, JS_ErrorTerminated);
1355 * Send Append Close to Storage daemon
1357 bnet_fsend(sd, append_close, jcr->Ticket);
1358 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1359 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1361 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1365 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1368 if (SDJobStatus != JS_Terminated) {
1369 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1376 /* STOP VSS ON WIN 32 */
1377 /* tell vss to close the backup session */
1379 if (g_pVSSClient->CloseBackup()) {
1380 /* inform user about writer states */
1381 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1382 int msg_type = M_INFO;
1383 if (g_pVSSClient->GetWriterState(i) < 1) {
1384 msg_type = M_WARNING;
1387 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1394 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1395 edit_uint64(jcr->ReadBytes, ed1),
1396 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1397 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1399 return 0; /* return and stop command loop */
1403 * Do a Verify for Director
1406 static int verify_cmd(JCR *jcr)
1408 BSOCK *dir = jcr->dir_bsock;
1409 BSOCK *sd = jcr->store_bsock;
1410 char level[100], ed1[50], ed2[50];
1412 jcr->JobType = JT_VERIFY;
1413 if (sscanf(dir->msg, verifycmd, level) != 1) {
1414 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1418 if (strcasecmp(level, "init") == 0) {
1419 jcr->JobLevel = L_VERIFY_INIT;
1420 } else if (strcasecmp(level, "catalog") == 0){
1421 jcr->JobLevel = L_VERIFY_CATALOG;
1422 } else if (strcasecmp(level, "volume") == 0){
1423 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1424 } else if (strcasecmp(level, "data") == 0){
1425 jcr->JobLevel = L_VERIFY_DATA;
1426 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1427 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1429 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1433 bnet_fsend(dir, OKverify);
1435 generate_daemon_event(jcr, "JobStart");
1437 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1439 switch (jcr->JobLevel) {
1441 case L_VERIFY_CATALOG:
1444 case L_VERIFY_VOLUME_TO_CATALOG:
1445 if (!open_sd_read_session(jcr)) {
1448 start_dir_heartbeat(jcr);
1449 do_verify_volume(jcr);
1450 stop_dir_heartbeat(jcr);
1452 * Send Close session command to Storage daemon
1454 bnet_fsend(sd, read_close, jcr->Ticket);
1455 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1457 /* ****FIXME**** check response */
1458 bget_msg(sd); /* get OK */
1460 /* Inform Storage daemon that we are done */
1461 bnet_sig(sd, BNET_TERMINATE);
1464 case L_VERIFY_DISK_TO_CATALOG:
1468 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1472 bnet_sig(dir, BNET_EOD);
1474 /* Send termination status back to Dir */
1475 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1476 edit_uint64(jcr->ReadBytes, ed1),
1477 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1479 /* Inform Director that we are done */
1480 bnet_sig(dir, BNET_TERMINATE);
1481 return 0; /* return and terminate command loop */
1485 * Do a Restore for Director
1488 static int restore_cmd(JCR *jcr)
1490 BSOCK *dir = jcr->dir_bsock;
1491 BSOCK *sd = jcr->store_bsock;
1495 char ed1[50], ed2[50];
1498 * Scan WHERE (base directory for restore) from command
1500 Dmsg0(150, "restore command\n");
1501 /* Pickup where string */
1502 where = get_memory(dir->msglen+1);
1505 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1506 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1507 pm_strcpy(jcr->errmsg, dir->msg);
1508 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1513 /* Turn / into nothing */
1514 if (where[0] == '/' && where[1] == 0) {
1518 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1519 unbash_spaces(where);
1520 jcr->where = bstrdup(where);
1521 free_pool_memory(where);
1522 jcr->replace = replace;
1523 jcr->prefix_links = prefix_links;
1525 bnet_fsend(dir, OKrestore);
1526 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1528 jcr->JobType = JT_RESTORE;
1530 set_jcr_job_status(jcr, JS_Blocked);
1532 if (!open_sd_read_session(jcr)) {
1533 set_jcr_job_status(jcr, JS_ErrorTerminated);
1537 set_jcr_job_status(jcr, JS_Running);
1540 * Do restore of files and data
1542 start_dir_heartbeat(jcr);
1543 generate_daemon_event(jcr, "JobStart");
1545 stop_dir_heartbeat(jcr);
1547 set_jcr_job_status(jcr, JS_Terminated);
1548 if (jcr->JobStatus != JS_Terminated) {
1549 bnet_suppress_error_messages(sd, 1);
1553 * Send Close session command to Storage daemon
1555 bnet_fsend(sd, read_close, jcr->Ticket);
1556 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1558 bget_msg(sd); /* get OK */
1560 /* Inform Storage daemon that we are done */
1561 bnet_sig(sd, BNET_TERMINATE);
1566 set_jcr_job_status(jcr, JS_ErrorTerminated);
1568 /* Send termination status back to Dir */
1569 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1570 edit_uint64(jcr->ReadBytes, ed1),
1571 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1573 /* Inform Director that we are done */
1574 bnet_sig(dir, BNET_TERMINATE);
1576 Dmsg0(130, "Done in job.c\n");
1577 return 0; /* return and terminate command loop */
1580 static int open_sd_read_session(JCR *jcr)
1582 BSOCK *sd = jcr->store_bsock;
1585 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1588 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1589 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1590 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1592 * Open Read Session with Storage daemon
1594 bnet_fsend(sd, read_open, "DummyVolume",
1595 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1596 jcr->StartBlock, jcr->EndBlock);
1597 Dmsg1(110, ">stored: %s", sd->msg);
1602 if (bget_msg(sd) >= 0) {
1603 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1604 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1605 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1608 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1610 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1614 if (!send_bootstrap_file(jcr)) {
1619 * Start read of data with Storage daemon
1621 bnet_fsend(sd, read_data, jcr->Ticket);
1622 Dmsg1(110, ">stored: %s", sd->msg);
1627 if (!response(jcr, sd, OK_data, "Read Data")) {
1634 * Destroy the Job Control Record and associated
1635 * resources (sockets).
1637 static void filed_free_jcr(JCR *jcr)
1639 if (jcr->store_bsock) {
1640 bnet_close(jcr->store_bsock);
1642 free_bootstrap(jcr);
1643 if (jcr->last_fname) {
1644 free_pool_memory(jcr->last_fname);
1646 free_runscripts(jcr->RunScripts);
1647 delete jcr->RunScripts;
1653 * Get response from Storage daemon to a command we
1654 * sent. Check that the response is OK.
1656 * Returns: 0 on failure
1659 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1664 if (bget_msg(sd) > 0) {
1665 Dmsg0(110, sd->msg);
1666 if (strcmp(sd->msg, resp) == 0) {
1670 if (job_canceled(jcr)) {
1671 return 0; /* if canceled avoid useless error messages */
1673 if (is_bnet_error(sd)) {
1674 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1675 cmd, bnet_strerror(sd));
1677 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1678 cmd, resp, sd->msg);
1683 static int send_bootstrap_file(JCR *jcr)
1687 BSOCK *sd = jcr->store_bsock;
1688 const char *bootstrap = "bootstrap\n";
1691 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1692 if (!jcr->RestoreBootstrap) {
1695 bs = fopen(jcr->RestoreBootstrap, "rb");
1698 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1699 jcr->RestoreBootstrap, be.strerror());
1700 set_jcr_job_status(jcr, JS_ErrorTerminated);
1703 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1705 while (fgets(buf, sizeof(buf), bs)) {
1706 sd->msglen = Mmsg(sd->msg, "%s", buf);
1709 bnet_sig(sd, BNET_EOD);
1711 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1712 set_jcr_job_status(jcr, JS_ErrorTerminated);
1718 free_bootstrap(jcr);