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;
996 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
997 static uint32_t bsr_uniq = 0;
1000 * The Director sends us the bootstrap file, which
1001 * we will in turn pass to the SD.
1003 static int bootstrap_cmd(JCR *jcr)
1005 BSOCK *dir = jcr->dir_bsock;
1006 POOLMEM *fname = get_pool_memory(PM_FNAME);
1009 free_bootstrap(jcr);
1012 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1013 jcr->Job, bsr_uniq);
1015 Dmsg1(400, "bootstrap=%s\n", fname);
1016 jcr->RestoreBootstrap = fname;
1017 bs = fopen(fname, "a+b"); /* create file */
1020 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1021 jcr->RestoreBootstrap, be.strerror());
1023 * Suck up what he is sending to us so that he will then
1024 * read our error message.
1026 while (bnet_recv(dir) >= 0)
1028 free_bootstrap(jcr);
1029 set_jcr_job_status(jcr, JS_ErrorTerminated);
1033 while (bnet_recv(dir) >= 0) {
1034 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1035 fputs(dir->msg, bs);
1039 * Note, do not free the bootstrap yet -- it needs to be
1042 return bnet_fsend(dir, OKbootstrap);
1047 * Get backup level from Director
1050 static int level_cmd(JCR *jcr)
1052 BSOCK *dir = jcr->dir_bsock;
1053 POOLMEM *level, *buf = NULL;
1056 level = get_memory(dir->msglen+1);
1057 Dmsg1(110, "level_cmd: %s", dir->msg);
1058 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1061 /* Base backup requested? */
1062 if (strcmp(level, "base") == 0) {
1063 jcr->JobLevel = L_BASE;
1064 /* Full backup requested? */
1065 } else if (strcmp(level, "full") == 0) {
1066 jcr->JobLevel = L_FULL;
1067 } else if (strcmp(level, "differential") == 0) {
1068 jcr->JobLevel = L_DIFFERENTIAL;
1071 } else if (strcmp(level, "incremental") == 0) {
1072 jcr->JobLevel = L_INCREMENTAL;
1076 * We get his UTC since time, then sync the clocks and correct it
1077 * to agree with our clock.
1079 } else if (strcmp(level, "since_utime") == 0) {
1080 buf = get_memory(dir->msglen+1);
1081 utime_t since_time, adj;
1082 btime_t his_time, bt_start, rt=0, bt_adj=0;
1083 if (jcr->JobLevel == L_NONE) {
1084 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1086 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1087 buf, &mtime_only) != 2) {
1090 since_time = str_to_uint64(buf); /* this is the since time */
1091 Dmsg1(100, "since_time=%d\n", (int)since_time);
1092 char ed1[50], ed2[50];
1094 * Sync clocks by polling him for the time. We take
1095 * 10 samples of his time throwing out the first two.
1097 for (int i=0; i<10; i++) {
1098 bt_start = get_current_btime();
1099 bnet_sig(dir, BNET_BTIME); /* poll for time */
1100 if (bnet_recv(dir) <= 0) { /* get response */
1103 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1106 if (i < 2) { /* toss first two results */
1109 his_time = str_to_uint64(buf);
1110 rt = get_current_btime() - bt_start; /* compute round trip time */
1111 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1112 edit_uint64(bt_start, ed2));
1113 bt_adj += bt_start - his_time - rt/2;
1114 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1117 bt_adj = bt_adj / 8; /* compute average time */
1118 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1119 adj = btime_to_utime(bt_adj);
1120 since_time += adj; /* adjust for clock difference */
1122 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1124 bnet_sig(dir, BNET_EOD);
1126 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1127 jcr->incremental = 1; /* set incremental or decremental backup */
1128 jcr->mtime = (time_t)since_time; /* set since time */
1130 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1138 return bnet_fsend(dir, OKlevel);
1141 pm_strcpy(jcr->errmsg, dir->msg);
1142 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1151 * Get session parameters from Director -- this is for a Restore command
1153 static int session_cmd(JCR *jcr)
1155 BSOCK *dir = jcr->dir_bsock;
1157 Dmsg1(100, "SessionCmd: %s", dir->msg);
1158 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1159 &jcr->VolSessionId, &jcr->VolSessionTime,
1160 &jcr->StartFile, &jcr->EndFile,
1161 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1162 pm_strcpy(jcr->errmsg, dir->msg);
1163 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1167 return bnet_fsend(dir, OKsession);
1171 * Get address of storage daemon from Director
1174 static int storage_cmd(JCR *jcr)
1176 int stored_port; /* storage daemon port */
1177 int enable_ssl; /* enable ssl to sd */
1178 BSOCK *dir = jcr->dir_bsock;
1179 BSOCK *sd; /* storage daemon bsock */
1181 Dmsg1(100, "StorageCmd: %s", dir->msg);
1182 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1183 pm_strcpy(jcr->errmsg, dir->msg);
1184 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1187 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1188 /* Open command communications with Storage daemon */
1189 /* Try to connect for 1 hour at 10 second intervals */
1190 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1191 jcr->stored_addr, NULL, stored_port, 1);
1193 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1194 jcr->stored_addr, stored_port);
1195 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1196 jcr->stored_addr, stored_port);
1199 Dmsg0(110, "Connection OK to SD.\n");
1201 jcr->store_bsock = sd;
1203 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1204 if (!authenticate_storagedaemon(jcr)) {
1205 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1208 Dmsg0(110, "Authenticated with SD.\n");
1210 /* Send OK to Director */
1211 return bnet_fsend(dir, OKstore);
1216 * Do a backup. For now, we handle only Full and Incremental.
1218 static int backup_cmd(JCR *jcr)
1220 BSOCK *dir = jcr->dir_bsock;
1221 BSOCK *sd = jcr->store_bsock;
1224 char ed1[50], ed2[50];
1227 // capture state here, if client is backed up by multiple directors
1228 // and one enables vss and the other does not then enable_vss can change
1229 // between here and where its evaluated after the job completes.
1230 bool bDoVSS = false;
1232 bDoVSS = g_pVSSClient && enable_vss;
1234 /* Run only one at a time */
1238 set_jcr_job_status(jcr, JS_Blocked);
1239 jcr->JobType = JT_BACKUP;
1240 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1243 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1247 bnet_fsend(dir, OKbackup);
1248 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1251 * Send Append Open Session to Storage daemon
1253 bnet_fsend(sd, append_open);
1254 Dmsg1(110, ">stored: %s", sd->msg);
1256 * Expect to receive back the Ticket number
1258 if (bget_msg(sd) >= 0) {
1259 Dmsg1(110, "<stored: %s", sd->msg);
1260 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1261 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1264 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1266 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1271 * Send Append data command to Storage daemon
1273 bnet_fsend(sd, append_data, jcr->Ticket);
1274 Dmsg1(110, ">stored: %s", sd->msg);
1277 * Expect to get OK data
1279 Dmsg1(110, "<stored: %s", sd->msg);
1280 if (!response(jcr, sd, OK_data, "Append Data")) {
1284 generate_daemon_event(jcr, "JobStart");
1287 /* START VSS ON WIN 32 */
1289 if (g_pVSSClient->InitializeForBackup()) {
1290 /* tell vss which drives to snapshot */
1291 char szWinDriveLetters[27];
1292 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1293 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1294 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1295 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1298 /* tell user if snapshot creation of a specific drive failed */
1300 for (i=0; i < strlen(szWinDriveLetters); i++) {
1301 if (islower(szWinDriveLetters[i])) {
1302 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1306 /* inform user about writer states */
1307 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1308 if (g_pVSSClient->GetWriterState(i) < 1) {
1309 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1314 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1318 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1324 * Send Files to Storage daemon
1326 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1327 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1328 set_jcr_job_status(jcr, JS_ErrorTerminated);
1329 bnet_suppress_error_messages(sd, 1);
1330 bget_msg(sd); /* Read final response from append_data */
1331 Dmsg0(110, "Error in blast_data.\n");
1332 /* run shortly after end of data transmission */
1333 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1335 set_jcr_job_status(jcr, JS_Terminated);
1338 if (jcr->JobStatus != JS_Terminated) {
1339 bnet_suppress_error_messages(sd, 1);
1340 goto cleanup; /* bail out now */
1343 * Expect to get response to append_data from Storage daemon
1345 if (!response(jcr, sd, OK_append, "Append Data")) {
1346 set_jcr_job_status(jcr, JS_ErrorTerminated);
1351 * Send Append End Data to Storage daemon
1353 bnet_fsend(sd, append_end, jcr->Ticket);
1355 if (!response(jcr, sd, OK_end, "Append End")) {
1356 set_jcr_job_status(jcr, JS_ErrorTerminated);
1361 * Send Append Close to Storage daemon
1363 bnet_fsend(sd, append_close, jcr->Ticket);
1364 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1365 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1367 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1371 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1374 if (SDJobStatus != JS_Terminated) {
1375 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1382 /* STOP VSS ON WIN 32 */
1383 /* tell vss to close the backup session */
1385 if (g_pVSSClient->CloseBackup()) {
1386 /* inform user about writer states */
1387 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1388 int msg_type = M_INFO;
1389 if (g_pVSSClient->GetWriterState(i) < 1) {
1390 msg_type = M_WARNING;
1393 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1400 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1401 edit_uint64(jcr->ReadBytes, ed1),
1402 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1403 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1405 return 0; /* return and stop command loop */
1409 * Do a Verify for Director
1412 static int verify_cmd(JCR *jcr)
1414 BSOCK *dir = jcr->dir_bsock;
1415 BSOCK *sd = jcr->store_bsock;
1416 char level[100], ed1[50], ed2[50];
1418 jcr->JobType = JT_VERIFY;
1419 if (sscanf(dir->msg, verifycmd, level) != 1) {
1420 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1424 if (strcasecmp(level, "init") == 0) {
1425 jcr->JobLevel = L_VERIFY_INIT;
1426 } else if (strcasecmp(level, "catalog") == 0){
1427 jcr->JobLevel = L_VERIFY_CATALOG;
1428 } else if (strcasecmp(level, "volume") == 0){
1429 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1430 } else if (strcasecmp(level, "data") == 0){
1431 jcr->JobLevel = L_VERIFY_DATA;
1432 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1433 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1435 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1439 bnet_fsend(dir, OKverify);
1441 generate_daemon_event(jcr, "JobStart");
1443 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1445 switch (jcr->JobLevel) {
1447 case L_VERIFY_CATALOG:
1450 case L_VERIFY_VOLUME_TO_CATALOG:
1451 if (!open_sd_read_session(jcr)) {
1454 start_dir_heartbeat(jcr);
1455 do_verify_volume(jcr);
1456 stop_dir_heartbeat(jcr);
1458 * Send Close session command to Storage daemon
1460 bnet_fsend(sd, read_close, jcr->Ticket);
1461 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1463 /* ****FIXME**** check response */
1464 bget_msg(sd); /* get OK */
1466 /* Inform Storage daemon that we are done */
1467 bnet_sig(sd, BNET_TERMINATE);
1470 case L_VERIFY_DISK_TO_CATALOG:
1474 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1478 bnet_sig(dir, BNET_EOD);
1480 /* Send termination status back to Dir */
1481 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1482 edit_uint64(jcr->ReadBytes, ed1),
1483 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1485 /* Inform Director that we are done */
1486 bnet_sig(dir, BNET_TERMINATE);
1487 return 0; /* return and terminate command loop */
1491 * Do a Restore for Director
1494 static int restore_cmd(JCR *jcr)
1496 BSOCK *dir = jcr->dir_bsock;
1497 BSOCK *sd = jcr->store_bsock;
1501 char ed1[50], ed2[50];
1504 * Scan WHERE (base directory for restore) from command
1506 Dmsg0(150, "restore command\n");
1507 /* Pickup where string */
1508 where = get_memory(dir->msglen+1);
1511 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1512 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1513 pm_strcpy(jcr->errmsg, dir->msg);
1514 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1519 /* Turn / into nothing */
1520 if (where[0] == '/' && where[1] == 0) {
1524 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1525 unbash_spaces(where);
1526 jcr->where = bstrdup(where);
1527 free_pool_memory(where);
1528 jcr->replace = replace;
1529 jcr->prefix_links = prefix_links;
1531 bnet_fsend(dir, OKrestore);
1532 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1534 jcr->JobType = JT_RESTORE;
1536 set_jcr_job_status(jcr, JS_Blocked);
1538 if (!open_sd_read_session(jcr)) {
1539 set_jcr_job_status(jcr, JS_ErrorTerminated);
1543 set_jcr_job_status(jcr, JS_Running);
1546 * Do restore of files and data
1548 start_dir_heartbeat(jcr);
1549 generate_daemon_event(jcr, "JobStart");
1551 stop_dir_heartbeat(jcr);
1553 set_jcr_job_status(jcr, JS_Terminated);
1554 if (jcr->JobStatus != JS_Terminated) {
1555 bnet_suppress_error_messages(sd, 1);
1559 * Send Close session command to Storage daemon
1561 bnet_fsend(sd, read_close, jcr->Ticket);
1562 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1564 bget_msg(sd); /* get OK */
1566 /* Inform Storage daemon that we are done */
1567 bnet_sig(sd, BNET_TERMINATE);
1572 set_jcr_job_status(jcr, JS_ErrorTerminated);
1574 /* Send termination status back to Dir */
1575 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1576 edit_uint64(jcr->ReadBytes, ed1),
1577 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1579 /* Inform Director that we are done */
1580 bnet_sig(dir, BNET_TERMINATE);
1582 Dmsg0(130, "Done in job.c\n");
1583 return 0; /* return and terminate command loop */
1586 static int open_sd_read_session(JCR *jcr)
1588 BSOCK *sd = jcr->store_bsock;
1591 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1594 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1595 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1596 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1598 * Open Read Session with Storage daemon
1600 bnet_fsend(sd, read_open, "DummyVolume",
1601 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1602 jcr->StartBlock, jcr->EndBlock);
1603 Dmsg1(110, ">stored: %s", sd->msg);
1608 if (bget_msg(sd) >= 0) {
1609 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1610 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1611 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1614 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1616 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1620 if (!send_bootstrap_file(jcr)) {
1625 * Start read of data with Storage daemon
1627 bnet_fsend(sd, read_data, jcr->Ticket);
1628 Dmsg1(110, ">stored: %s", sd->msg);
1633 if (!response(jcr, sd, OK_data, "Read Data")) {
1640 * Destroy the Job Control Record and associated
1641 * resources (sockets).
1643 static void filed_free_jcr(JCR *jcr)
1645 if (jcr->store_bsock) {
1646 bnet_close(jcr->store_bsock);
1648 free_bootstrap(jcr);
1649 if (jcr->last_fname) {
1650 free_pool_memory(jcr->last_fname);
1652 free_runscripts(jcr->RunScripts);
1653 delete jcr->RunScripts;
1659 * Get response from Storage daemon to a command we
1660 * sent. Check that the response is OK.
1662 * Returns: 0 on failure
1665 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1670 if (bget_msg(sd) > 0) {
1671 Dmsg0(110, sd->msg);
1672 if (strcmp(sd->msg, resp) == 0) {
1676 if (job_canceled(jcr)) {
1677 return 0; /* if canceled avoid useless error messages */
1679 if (is_bnet_error(sd)) {
1680 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1681 cmd, bnet_strerror(sd));
1683 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1684 cmd, resp, sd->msg);
1689 static int send_bootstrap_file(JCR *jcr)
1693 BSOCK *sd = jcr->store_bsock;
1694 const char *bootstrap = "bootstrap\n";
1697 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1698 if (!jcr->RestoreBootstrap) {
1701 bs = fopen(jcr->RestoreBootstrap, "rb");
1704 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1705 jcr->RestoreBootstrap, be.strerror());
1706 set_jcr_job_status(jcr, JS_ErrorTerminated);
1709 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1711 while (fgets(buf, sizeof(buf), bs)) {
1712 sd->msglen = Mmsg(sd->msg, "%s", buf);
1715 bnet_sig(sd, BNET_EOD);
1717 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1718 set_jcr_job_status(jcr, JS_ErrorTerminated);
1724 free_bootstrap(jcr);