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);
236 generate_daemon_event(jcr, "JobEnd");
238 dequeue_messages(jcr); /* send any queued messages */
240 /* Inform Director that we are done */
241 bnet_sig(dir, BNET_TERMINATE);
243 /* Clean up fileset */
244 FF_PKT *ff = jcr->ff;
245 findFILESET *fileset = ff->fileset;
248 /* Delete FileSet Include lists */
249 for (i=0; i<fileset->include_list.size(); i++) {
250 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
251 for (j=0; j<incexe->opts_list.size(); j++) {
252 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
253 for (k=0; k<fo->regex.size(); k++) {
254 regfree((regex_t *)fo->regex.get(k));
257 fo->regexdir.destroy();
258 fo->regexfile.destroy();
260 fo->wilddir.destroy();
261 fo->wildfile.destroy();
263 fo->fstype.destroy();
271 incexe->opts_list.destroy();
272 incexe->name_list.destroy();
274 fileset->include_list.destroy();
276 /* Delete FileSet Exclude lists */
277 for (i=0; i<fileset->exclude_list.size(); i++) {
278 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
279 for (j=0; j<incexe->opts_list.size(); j++) {
280 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
282 fo->regexdir.destroy();
283 fo->regexfile.destroy();
285 fo->wilddir.destroy();
286 fo->wildfile.destroy();
288 fo->fstype.destroy();
290 incexe->opts_list.destroy();
291 incexe->name_list.destroy();
293 fileset->exclude_list.destroy();
297 Dmsg0(100, "Calling term_find_files\n");
298 term_find_files(jcr->ff);
300 Dmsg0(100, "Done with term_find_files\n");
301 free_jcr(jcr); /* destroy JCR record */
302 Dmsg0(100, "Done with free_jcr\n");
307 * Hello from Director he must identify himself and provide his
310 static int hello_cmd(JCR *jcr)
312 Dmsg0(120, "Calling Authenticate\n");
313 if (!authenticate_director(jcr)) {
316 Dmsg0(120, "OK Authenticate\n");
317 jcr->authenticated = true;
324 static int cancel_cmd(JCR *jcr)
326 BSOCK *dir = jcr->dir_bsock;
327 char Job[MAX_NAME_LENGTH];
330 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
331 if (!(cjcr=get_jcr_by_full_name(Job))) {
332 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
334 if (cjcr->store_bsock) {
335 cjcr->store_bsock->timed_out = 1;
336 cjcr->store_bsock->terminated = 1;
337 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
339 set_jcr_job_status(cjcr, JS_Canceled);
341 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
344 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
346 bnet_sig(dir, BNET_EOD);
352 * Set debug level as requested by the Director
355 static int setdebug_cmd(JCR *jcr)
357 BSOCK *dir = jcr->dir_bsock;
358 int level, trace_flag;
360 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
361 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
362 pm_strcpy(jcr->errmsg, dir->msg);
363 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
367 set_trace(trace_flag);
368 return bnet_fsend(dir, OKsetdebug, level);
372 static int estimate_cmd(JCR *jcr)
374 BSOCK *dir = jcr->dir_bsock;
377 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
378 pm_strcpy(jcr->errmsg, dir->msg);
379 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
380 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
384 bnet_fsend(dir, OKest, jcr->num_files_examined,
385 edit_uint64_with_commas(jcr->JobBytes, ed2));
386 bnet_sig(dir, BNET_EOD);
391 * Get JobId and Storage Daemon Authorization key from Director
393 static int job_cmd(JCR *jcr)
395 BSOCK *dir = jcr->dir_bsock;
396 POOLMEM *sd_auth_key;
398 sd_auth_key = get_memory(dir->msglen);
399 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
400 &jcr->VolSessionId, &jcr->VolSessionTime,
402 pm_strcpy(jcr->errmsg, dir->msg);
403 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
404 bnet_fsend(dir, BADjob);
405 free_pool_memory(sd_auth_key);
408 jcr->sd_auth_key = bstrdup(sd_auth_key);
409 free_pool_memory(sd_auth_key);
410 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
411 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
414 static int runbefore_cmd(JCR *jcr)
417 BSOCK *dir = jcr->dir_bsock;
418 POOLMEM *cmd = get_memory(dir->msglen+1);
421 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
422 if (sscanf(dir->msg, runbefore, cmd) != 1) {
423 pm_strcpy(jcr->errmsg, dir->msg);
424 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
425 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
431 /* Run the command now */
432 script = new_runscript();
433 script->set_command(cmd);
434 script->when = SCRIPT_Before;
435 ok = script->run(jcr, "ClientRunBeforeJob");
436 free_runscript(script);
440 bnet_fsend(dir, OKRunBefore);
443 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
448 static int runbeforenow_cmd(JCR *jcr)
450 BSOCK *dir = jcr->dir_bsock;
452 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
453 return bnet_fsend(dir, OKRunBeforeNow);
456 static int runafter_cmd(JCR *jcr)
458 BSOCK *dir = jcr->dir_bsock;
459 POOLMEM *msg = get_memory(dir->msglen+1);
462 Dmsg1(100, "runafter_cmd: %s", dir->msg);
463 if (sscanf(dir->msg, runafter, msg) != 1) {
464 pm_strcpy(jcr->errmsg, dir->msg);
465 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
466 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
472 cmd = new_runscript();
473 cmd->set_command(msg);
474 cmd->on_success = true;
475 cmd->on_failure = false;
476 cmd->when = SCRIPT_After;
478 jcr->RunScripts->append(cmd);
480 free_pool_memory(msg);
481 return bnet_fsend(dir, OKRunAfter);
484 static int runscript_cmd(JCR *jcr)
486 BSOCK *dir = jcr->dir_bsock;
487 POOLMEM *msg = get_memory(dir->msglen+1);
489 RUNSCRIPT *cmd = new_runscript() ;
491 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
492 if (sscanf(dir->msg, runscript, &cmd->on_success,
494 &cmd->abort_on_error,
497 pm_strcpy(jcr->errmsg, dir->msg);
498 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
499 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
506 cmd->set_command(msg);
508 jcr->RunScripts->append(cmd);
510 free_pool_memory(msg);
511 return bnet_fsend(dir, OKRunScript);
515 static bool init_fileset(JCR *jcr)
518 findFILESET *fileset;
527 fileset = (findFILESET *)malloc(sizeof(findFILESET));
528 memset(fileset, 0, sizeof(findFILESET));
529 ff->fileset = fileset;
530 fileset->state = state_none;
531 fileset->include_list.init(1, true);
532 fileset->exclude_list.init(1, true);
536 static findFOPTS *start_options(FF_PKT *ff)
538 int state = ff->fileset->state;
539 findINCEXE *incexe = ff->fileset->incexe;
541 if (state != state_options) {
542 ff->fileset->state = state_options;
543 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
544 memset(fo, 0, sizeof(findFOPTS));
545 fo->regex.init(1, true);
546 fo->regexdir.init(1, true);
547 fo->regexfile.init(1, true);
548 fo->wild.init(1, true);
549 fo->wilddir.init(1, true);
550 fo->wildfile.init(1, true);
551 fo->base.init(1, true);
552 fo->fstype.init(1, true);
553 incexe->current_opts = fo;
554 incexe->opts_list.append(fo);
556 return incexe->current_opts;
561 * Add fname to include/exclude fileset list. First check for
562 * | and < and if necessary perform command.
564 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
578 p++; /* skip over | */
579 fn = get_pool_memory(PM_FNAME);
580 fn = edit_job_codes(jcr, fn, p, "");
581 bpipe = open_bpipe(fn, 0, "r");
582 free_pool_memory(fn);
584 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
588 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
589 strip_trailing_junk(buf);
590 fileset->incexe->name_list.append(bstrdup(buf));
592 if ((stat=close_bpipe(bpipe)) != 0) {
593 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
594 p, stat, strerror(errno));
599 Dmsg0(100, "Doing < include on client.\n");
600 p++; /* skip over < */
601 if ((ffd = fopen(p, "rb")) == NULL) {
603 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
607 while (fgets(buf, sizeof(buf), ffd)) {
608 strip_trailing_junk(buf);
609 Dmsg1(100, "%s\n", buf);
610 fileset->incexe->name_list.append(bstrdup(buf));
615 fileset->incexe->name_list.append(bstrdup(fname));
621 static void add_fileset(JCR *jcr, const char *item)
623 FF_PKT *ff = jcr->ff;
624 findFILESET *fileset = ff->fileset;
625 int state = fileset->state;
626 findFOPTS *current_opts;
628 /* Get code, optional subcode, and position item past the dividing space */
629 Dmsg1(100, "%s\n", item);
634 int subcode = ' '; /* A space is always a valid subcode */
635 if (item[0] != '\0' && item[0] != ' ') {
643 /* Skip all lines we receive after an error */
644 if (state == state_error) {
649 * The switch tests the code for validity.
650 * The subcode is always good if it is a space, otherwise we must confirm.
651 * We set state to state_error first assuming the subcode is invalid,
652 * requiring state to be set in cases below that handle subcodes.
654 if (subcode != ' ') {
660 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
661 memset(fileset->incexe, 0, sizeof(findINCEXE));
662 fileset->incexe->opts_list.init(1, true);
663 fileset->incexe->name_list.init(1, true);
664 fileset->include_list.append(fileset->incexe);
668 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
669 memset(fileset->incexe, 0, sizeof(findINCEXE));
670 fileset->incexe->opts_list.init(1, true);
671 fileset->incexe->name_list.init(1, true);
672 fileset->exclude_list.append(fileset->incexe);
678 /* File item to either include/include list */
679 state = state_include;
680 add_file_to_fileset(jcr, item, fileset);
683 current_opts = start_options(ff);
687 preg = (regex_t *)malloc(sizeof(regex_t));
688 if (current_opts->flags & FO_IGNORECASE) {
689 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
691 rc = regcomp(preg, item, REG_EXTENDED);
694 regerror(rc, preg, prbuf, sizeof(prbuf));
697 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
701 state = state_options;
702 if (subcode == ' ') {
703 current_opts->regex.append(preg);
704 } else if (subcode == 'D') {
705 current_opts->regexdir.append(preg);
706 } else if (subcode == 'F') {
707 current_opts->regexfile.append(preg);
713 current_opts = start_options(ff);
714 current_opts->base.append(bstrdup(item));
715 state = state_options;
718 current_opts = start_options(ff);
719 current_opts->fstype.append(bstrdup(item));
720 state = state_options;
723 current_opts = start_options(ff);
724 state = state_options;
725 if (subcode == ' ') {
726 current_opts->wild.append(bstrdup(item));
727 } else if (subcode == 'D') {
728 current_opts->wilddir.append(bstrdup(item));
729 } else if (subcode == 'F') {
730 current_opts->wildfile.append(bstrdup(item));
736 current_opts = start_options(ff);
737 set_options(current_opts, item);
738 state = state_options;
741 current_opts = start_options(ff);
742 current_opts->reader = bstrdup(item);
743 state = state_options;
746 current_opts = start_options(ff);
747 current_opts->writer = bstrdup(item);
748 state = state_options;
751 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
755 ff->fileset->state = state;
758 static bool term_fileset(JCR *jcr)
760 FF_PKT *ff = jcr->ff;
763 findFILESET *fileset = ff->fileset;
766 for (i=0; i<fileset->include_list.size(); i++) {
767 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
769 for (j=0; j<incexe->opts_list.size(); j++) {
770 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
771 for (k=0; k<fo->regex.size(); k++) {
772 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
774 for (k=0; k<fo->regexdir.size(); k++) {
775 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
777 for (k=0; k<fo->regexfile.size(); k++) {
778 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
780 for (k=0; k<fo->wild.size(); k++) {
781 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
783 for (k=0; k<fo->wilddir.size(); k++) {
784 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
786 for (k=0; k<fo->wildfile.size(); k++) {
787 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
789 for (k=0; k<fo->base.size(); k++) {
790 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
792 for (k=0; k<fo->fstype.size(); k++) {
793 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
796 Dmsg1(400, "D %s\n", fo->reader);
799 Dmsg1(400, "T %s\n", fo->writer);
802 for (j=0; j<incexe->name_list.size(); j++) {
803 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
806 for (i=0; i<fileset->exclude_list.size(); i++) {
807 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
809 for (j=0; j<incexe->opts_list.size(); j++) {
810 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
811 for (k=0; k<fo->regex.size(); k++) {
812 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
814 for (k=0; k<fo->regexdir.size(); k++) {
815 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
817 for (k=0; k<fo->regexfile.size(); k++) {
818 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
820 for (k=0; k<fo->wild.size(); k++) {
821 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
823 for (k=0; k<fo->wilddir.size(); k++) {
824 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
826 for (k=0; k<fo->wildfile.size(); k++) {
827 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
829 for (k=0; k<fo->base.size(); k++) {
830 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
832 for (k=0; k<fo->fstype.size(); k++) {
833 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
836 for (j=0; j<incexe->name_list.size(); j++) {
837 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
841 return ff->fileset->state != state_error;
846 * As an optimization, we should do this during
847 * "compile" time in filed/job.c, and keep only a bit mask
848 * and the Verify options.
850 static void set_options(findFOPTS *fo, const char *opts)
855 for (p=opts; *p; p++) {
857 case 'a': /* alway replace */
858 case '0': /* no option */
861 fo->flags |= FO_EXCLUDE;
864 fo->flags |= FO_MULTIFS;
866 case 'h': /* no recursion */
867 fo->flags |= FO_NO_RECURSION;
869 case 'H': /* no hard link handling */
870 fo->flags |= FO_NO_HARDLINK;
873 fo->flags |= FO_IGNORECASE;
879 fo->flags |= FO_NOREPLACE;
881 case 'p': /* use portable data format */
882 fo->flags |= FO_PORTABLE;
884 case 'R': /* Resource forks and Finder Info */
885 fo->flags |= FO_HFSPLUS;
886 case 'r': /* read fifo */
887 fo->flags |= FO_READFIFO;
892 /* Old director did not specify SHA variant */
893 fo->flags |= FO_SHA1;
896 fo->flags |= FO_SHA1;
901 fo->flags |= FO_SHA256;
905 fo->flags |= FO_SHA512;
910 /* Automatically downgrade to SHA-1 if an unsupported
911 * SHA variant is specified */
912 fo->flags |= FO_SHA1;
918 fo->flags |= FO_SPARSE;
921 fo->flags |= FO_MTIMEONLY;
924 fo->flags |= FO_KEEPATIME;
929 case 'V': /* verify options */
930 /* Copy Verify Options */
931 for (j=0; *p && *p != ':'; p++) {
932 fo->VerifyOpts[j] = *p;
933 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
937 fo->VerifyOpts[j] = 0;
940 fo->flags |= FO_IF_NEWER;
942 case 'Z': /* gzip compression */
943 fo->flags |= FO_GZIP;
944 fo->GZIP_level = *++p - '0';
945 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
948 fo->flags |= FO_NOATIME;
951 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
959 * Director is passing his Fileset
961 static int fileset_cmd(JCR *jcr)
963 BSOCK *dir = jcr->dir_bsock;
966 sscanf(dir->msg, "fileset vss=%d", &vss);
969 if (!init_fileset(jcr)) {
972 while (bnet_recv(dir) >= 0) {
973 strip_trailing_junk(dir->msg);
974 Dmsg1(500, "Fileset: %s\n", dir->msg);
975 add_fileset(jcr, dir->msg);
977 if (!term_fileset(jcr)) {
980 return bnet_fsend(dir, OKinc);
983 static void free_bootstrap(JCR *jcr)
985 if (jcr->RestoreBootstrap) {
986 unlink(jcr->RestoreBootstrap);
987 free_pool_memory(jcr->RestoreBootstrap);
988 jcr->RestoreBootstrap = NULL;
993 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
994 static uint32_t bsr_uniq = 0;
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);
1009 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1010 jcr->Job, bsr_uniq);
1012 Dmsg1(400, "bootstrap=%s\n", fname);
1013 jcr->RestoreBootstrap = fname;
1014 bs = fopen(fname, "a+b"); /* create file */
1017 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1018 jcr->RestoreBootstrap, be.strerror());
1020 * Suck up what he is sending to us so that he will then
1021 * read our error message.
1023 while (bnet_recv(dir) >= 0)
1025 free_bootstrap(jcr);
1026 set_jcr_job_status(jcr, JS_ErrorTerminated);
1030 while (bnet_recv(dir) >= 0) {
1031 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1032 fputs(dir->msg, bs);
1036 * Note, do not free the bootstrap yet -- it needs to be
1039 return bnet_fsend(dir, OKbootstrap);
1044 * Get backup level from Director
1047 static int level_cmd(JCR *jcr)
1049 BSOCK *dir = jcr->dir_bsock;
1050 POOLMEM *level, *buf = NULL;
1053 level = get_memory(dir->msglen+1);
1054 Dmsg1(110, "level_cmd: %s", dir->msg);
1055 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1058 /* Base backup requested? */
1059 if (strcmp(level, "base") == 0) {
1060 jcr->JobLevel = L_BASE;
1061 /* Full backup requested? */
1062 } else if (strcmp(level, "full") == 0) {
1063 jcr->JobLevel = L_FULL;
1064 } else if (strcmp(level, "differential") == 0) {
1065 jcr->JobLevel = L_DIFFERENTIAL;
1068 } else if (strcmp(level, "incremental") == 0) {
1069 jcr->JobLevel = L_INCREMENTAL;
1073 * We get his UTC since time, then sync the clocks and correct it
1074 * to agree with our clock.
1076 } else if (strcmp(level, "since_utime") == 0) {
1077 buf = get_memory(dir->msglen+1);
1078 utime_t since_time, adj;
1079 btime_t his_time, bt_start, rt=0, bt_adj=0;
1080 if (jcr->JobLevel == L_NONE) {
1081 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1083 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1084 buf, &mtime_only) != 2) {
1087 since_time = str_to_uint64(buf); /* this is the since time */
1088 Dmsg1(100, "since_time=%d\n", (int)since_time);
1089 char ed1[50], ed2[50];
1091 * Sync clocks by polling him for the time. We take
1092 * 10 samples of his time throwing out the first two.
1094 for (int i=0; i<10; i++) {
1095 bt_start = get_current_btime();
1096 bnet_sig(dir, BNET_BTIME); /* poll for time */
1097 if (bnet_recv(dir) <= 0) { /* get response */
1100 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1103 if (i < 2) { /* toss first two results */
1106 his_time = str_to_uint64(buf);
1107 rt = get_current_btime() - bt_start; /* compute round trip time */
1108 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1109 edit_uint64(bt_start, ed2));
1110 bt_adj += bt_start - his_time - rt/2;
1111 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1114 bt_adj = bt_adj / 8; /* compute average time */
1115 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1116 adj = btime_to_utime(bt_adj);
1117 since_time += adj; /* adjust for clock difference */
1119 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1121 bnet_sig(dir, BNET_EOD);
1123 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1124 jcr->incremental = 1; /* set incremental or decremental backup */
1125 jcr->mtime = (time_t)since_time; /* set since time */
1127 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1135 return bnet_fsend(dir, OKlevel);
1138 pm_strcpy(jcr->errmsg, dir->msg);
1139 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1148 * Get session parameters from Director -- this is for a Restore command
1150 static int session_cmd(JCR *jcr)
1152 BSOCK *dir = jcr->dir_bsock;
1154 Dmsg1(100, "SessionCmd: %s", dir->msg);
1155 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1156 &jcr->VolSessionId, &jcr->VolSessionTime,
1157 &jcr->StartFile, &jcr->EndFile,
1158 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1159 pm_strcpy(jcr->errmsg, dir->msg);
1160 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1164 return bnet_fsend(dir, OKsession);
1168 * Get address of storage daemon from Director
1171 static int storage_cmd(JCR *jcr)
1173 int stored_port; /* storage daemon port */
1174 int enable_ssl; /* enable ssl to sd */
1175 BSOCK *dir = jcr->dir_bsock;
1176 BSOCK *sd; /* storage daemon bsock */
1178 Dmsg1(100, "StorageCmd: %s", dir->msg);
1179 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1180 pm_strcpy(jcr->errmsg, dir->msg);
1181 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1184 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1185 /* Open command communications with Storage daemon */
1186 /* Try to connect for 1 hour at 10 second intervals */
1187 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1188 jcr->stored_addr, NULL, stored_port, 1);
1190 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1191 jcr->stored_addr, stored_port);
1192 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1193 jcr->stored_addr, stored_port);
1196 Dmsg0(110, "Connection OK to SD.\n");
1198 jcr->store_bsock = sd;
1200 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1201 if (!authenticate_storagedaemon(jcr)) {
1202 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1205 Dmsg0(110, "Authenticated with SD.\n");
1207 /* Send OK to Director */
1208 return bnet_fsend(dir, OKstore);
1213 * Do a backup. For now, we handle only Full and Incremental.
1215 static int backup_cmd(JCR *jcr)
1217 BSOCK *dir = jcr->dir_bsock;
1218 BSOCK *sd = jcr->store_bsock;
1221 char ed1[50], ed2[50];
1224 // capture state here, if client is backed up by multiple directors
1225 // and one enables vss and the other does not then enable_vss can change
1226 // between here and where its evaluated after the job completes.
1227 bool bDoVSS = false;
1229 bDoVSS = g_pVSSClient && enable_vss;
1231 /* Run only one at a time */
1235 set_jcr_job_status(jcr, JS_Blocked);
1236 jcr->JobType = JT_BACKUP;
1237 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1240 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1244 bnet_fsend(dir, OKbackup);
1245 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1248 * Send Append Open Session to Storage daemon
1250 bnet_fsend(sd, append_open);
1251 Dmsg1(110, ">stored: %s", sd->msg);
1253 * Expect to receive back the Ticket number
1255 if (bget_msg(sd) >= 0) {
1256 Dmsg1(110, "<stored: %s", sd->msg);
1257 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1258 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1261 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1263 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1268 * Send Append data command to Storage daemon
1270 bnet_fsend(sd, append_data, jcr->Ticket);
1271 Dmsg1(110, ">stored: %s", sd->msg);
1274 * Expect to get OK data
1276 Dmsg1(110, "<stored: %s", sd->msg);
1277 if (!response(jcr, sd, OK_data, "Append Data")) {
1281 generate_daemon_event(jcr, "JobStart");
1284 /* START VSS ON WIN 32 */
1286 if (g_pVSSClient->InitializeForBackup()) {
1287 /* tell vss which drives to snapshot */
1288 char szWinDriveLetters[27];
1289 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1290 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1291 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1292 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1295 /* tell user if snapshot creation of a specific drive failed */
1297 for (i=0; i < strlen(szWinDriveLetters); i++) {
1298 if (islower(szWinDriveLetters[i])) {
1299 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1303 /* inform user about writer states */
1304 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1305 if (g_pVSSClient->GetWriterState(i) < 1) {
1306 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1311 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1315 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1321 * Send Files to Storage daemon
1323 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1324 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1325 set_jcr_job_status(jcr, JS_ErrorTerminated);
1326 bnet_suppress_error_messages(sd, 1);
1327 bget_msg(sd); /* Read final response from append_data */
1328 Dmsg0(110, "Error in blast_data.\n");
1329 /* run shortly after end of data transmission */
1330 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1333 set_jcr_job_status(jcr, JS_Terminated);
1335 /* run shortly after end of data transmission */
1336 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
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);