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 char my_name[];
32 extern CLIENT *me; /* our client resource */
34 int enable_vss = 0; /* set to use vss */
36 /* Imported functions */
37 extern int status_cmd(JCR *jcr);
38 extern int qstatus_cmd(JCR *jcr);
40 /* Forward referenced functions */
41 static int backup_cmd(JCR *jcr);
42 static int bootstrap_cmd(JCR *jcr);
43 static int cancel_cmd(JCR *jcr);
44 static int setdebug_cmd(JCR *jcr);
45 static int estimate_cmd(JCR *jcr);
46 static int hello_cmd(JCR *jcr);
47 static int job_cmd(JCR *jcr);
48 static int fileset_cmd(JCR *jcr);
49 static int level_cmd(JCR *jcr);
50 static int verify_cmd(JCR *jcr);
51 static int restore_cmd(JCR *jcr);
52 static int storage_cmd(JCR *jcr);
53 static int session_cmd(JCR *jcr);
54 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
55 static void filed_free_jcr(JCR *jcr);
56 static int open_sd_read_session(JCR *jcr);
57 static int send_bootstrap_file(JCR *jcr);
58 static int runscript_cmd(JCR *jcr);
59 static int runbefore_cmd(JCR *jcr);
60 static int runafter_cmd(JCR *jcr);
61 static int runbeforenow_cmd(JCR *jcr);
62 static void set_options(findFOPTS *fo, const char *opts);
65 /* Exported functions */
70 int monitoraccess; /* specify if monitors have access to this function */
74 * The following are the recognized commands from the Director.
76 static struct s_cmds cmds[] = {
77 {"backup", backup_cmd, 0},
78 {"cancel", cancel_cmd, 0},
79 {"setdebug=", setdebug_cmd, 0},
80 {"estimate", estimate_cmd, 0},
81 {"Hello", hello_cmd, 1},
82 {"fileset", fileset_cmd, 0},
83 {"JobId=", job_cmd, 0},
84 {"level = ", level_cmd, 0},
85 {"restore", restore_cmd, 0},
86 {"session", session_cmd, 0},
87 {"status", status_cmd, 1},
88 {".status", qstatus_cmd, 1},
89 {"storage ", storage_cmd, 0},
90 {"verify", verify_cmd, 0},
91 {"bootstrap", bootstrap_cmd, 0},
92 {"RunBeforeNow", runbeforenow_cmd, 0},
93 {"RunBeforeJob", runbefore_cmd, 0},
94 {"RunAfterJob", runafter_cmd, 0},
95 {"Run", runscript_cmd, 0},
96 {NULL, NULL} /* list terminator */
99 /* Commands received from director that need scanning */
100 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
101 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
102 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
103 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
104 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
105 static char verifycmd[] = "verify level=%30s\n";
106 static char estimatecmd[] = "estimate listing=%d\n";
107 static char runbefore[] = "RunBeforeJob %s\n";
108 static char runafter[] = "RunAfterJob %s\n";
109 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
110 /* Responses sent to Director */
111 static char errmsg[] = "2999 Invalid command\n";
112 static char no_auth[] = "2998 No Authorization\n";
113 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
114 static char OKinc[] = "2000 OK include\n";
115 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
116 static char OKlevel[] = "2000 OK level\n";
117 static char OKbackup[] = "2000 OK backup\n";
118 static char OKbootstrap[] = "2000 OK bootstrap\n";
119 static char OKverify[] = "2000 OK verify\n";
120 static char OKrestore[] = "2000 OK restore\n";
121 static char OKsession[] = "2000 OK session\n";
122 static char OKstore[] = "2000 OK storage\n";
123 static char OKjob[] = "2000 OK Job %s,%s,%s";
124 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
125 static char BADjob[] = "2901 Bad Job\n";
126 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
127 static char OKRunBefore[] = "2000 OK RunBefore\n";
128 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
129 static char OKRunAfter[] = "2000 OK RunAfter\n";
130 static char OKRunScript[] = "2000 OK RunScript\n";
133 /* Responses received from Storage Daemon */
134 static char OK_end[] = "3000 OK end\n";
135 static char OK_close[] = "3000 OK close Status = %d\n";
136 static char OK_open[] = "3000 OK open ticket = %d\n";
137 static char OK_data[] = "3000 OK data\n";
138 static char OK_append[] = "3000 OK append data\n";
139 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
142 /* Commands sent to Storage Daemon */
143 static char append_open[] = "append open session\n";
144 static char append_data[] = "append data %d\n";
145 static char append_end[] = "append end session %d\n";
146 static char append_close[] = "append close session %d\n";
147 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
148 static char read_data[] = "read data %d\n";
149 static char read_close[] = "read close session %d\n";
152 * Accept requests from a Director
154 * NOTE! We are running as a separate thread
156 * Send output one line
157 * at a time followed by a zero length transmission.
159 * Return when the connection is terminated or there
162 * Basic task here is:
163 * Authenticate Director (during Hello command).
164 * Accept commands one at a time from the Director
168 void *handle_client_request(void *dirp)
173 BSOCK *dir = (BSOCK *)dirp;
175 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
176 jcr->dir_bsock = dir;
177 jcr->ff = init_find_files();
178 jcr->start_time = time(NULL);
179 jcr->RunScripts = New(alist(10, not_owned_by_alist));
180 jcr->last_fname = get_pool_memory(PM_FNAME);
181 jcr->last_fname[0] = 0;
182 jcr->client_name = get_memory(strlen(my_name) + 1);
183 pm_strcpy(jcr->client_name, my_name);
184 jcr->pki_sign = me->pki_sign;
185 jcr->pki_encrypt = me->pki_encrypt;
186 jcr->pki_keypair = me->pki_keypair;
187 jcr->pki_signers = me->pki_signers;
188 jcr->pki_recipients = me->pki_recipients;
190 enable_backup_privileges(NULL, 1 /* ignore_errors */);
192 /**********FIXME******* add command handler error code */
194 for (quit=false; !quit;) {
197 if (bnet_recv(dir) < 0) {
198 break; /* connection terminated */
200 dir->msg[dir->msglen] = 0;
201 Dmsg1(100, "<dird: %s", dir->msg);
203 for (i=0; cmds[i].cmd; i++) {
204 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
205 found = true; /* indicate command found */
206 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
207 bnet_fsend(dir, no_auth);
208 bnet_sig(dir, BNET_EOD);
211 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
212 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
213 bnet_fsend(dir, illegal_cmd);
214 bnet_sig(dir, BNET_EOD);
217 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
218 if (!cmds[i].func(jcr)) { /* do command */
219 quit = true; /* error or fully terminated, get out */
220 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
225 if (!found) { /* command not found */
226 bnet_fsend(dir, errmsg);
232 /* Inform Storage daemon that we are done */
233 if (jcr->store_bsock) {
234 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
238 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
240 generate_daemon_event(jcr, "JobEnd");
242 dequeue_messages(jcr); /* send any queued messages */
244 /* Inform Director that we are done */
245 bnet_sig(dir, BNET_TERMINATE);
247 /* Clean up fileset */
248 FF_PKT *ff = jcr->ff;
249 findFILESET *fileset = ff->fileset;
252 /* Delete FileSet Include lists */
253 for (i=0; i<fileset->include_list.size(); i++) {
254 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
255 for (j=0; j<incexe->opts_list.size(); j++) {
256 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
257 for (k=0; k<fo->regex.size(); k++) {
258 regfree((regex_t *)fo->regex.get(k));
261 fo->regexdir.destroy();
262 fo->regexfile.destroy();
264 fo->wilddir.destroy();
265 fo->wildfile.destroy();
267 fo->fstype.destroy();
275 incexe->opts_list.destroy();
276 incexe->name_list.destroy();
278 fileset->include_list.destroy();
280 /* Delete FileSet Exclude lists */
281 for (i=0; i<fileset->exclude_list.size(); i++) {
282 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
283 for (j=0; j<incexe->opts_list.size(); j++) {
284 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
286 fo->regexdir.destroy();
287 fo->regexfile.destroy();
289 fo->wilddir.destroy();
290 fo->wildfile.destroy();
292 fo->fstype.destroy();
294 incexe->opts_list.destroy();
295 incexe->name_list.destroy();
297 fileset->exclude_list.destroy();
301 Dmsg0(100, "Calling term_find_files\n");
302 term_find_files(jcr->ff);
304 Dmsg0(100, "Done with term_find_files\n");
305 free_jcr(jcr); /* destroy JCR record */
306 Dmsg0(100, "Done with free_jcr\n");
311 * Hello from Director he must identify himself and provide his
314 static int hello_cmd(JCR *jcr)
316 Dmsg0(120, "Calling Authenticate\n");
317 if (!authenticate_director(jcr)) {
320 Dmsg0(120, "OK Authenticate\n");
321 jcr->authenticated = true;
328 static int cancel_cmd(JCR *jcr)
330 BSOCK *dir = jcr->dir_bsock;
331 char Job[MAX_NAME_LENGTH];
334 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
335 if (!(cjcr=get_jcr_by_full_name(Job))) {
336 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
338 if (cjcr->store_bsock) {
339 cjcr->store_bsock->timed_out = 1;
340 cjcr->store_bsock->terminated = 1;
341 #if !defined(HAVE_CYGWIN)
342 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
345 set_jcr_job_status(cjcr, JS_Canceled);
347 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
350 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
352 bnet_sig(dir, BNET_EOD);
358 * Set debug level as requested by the Director
361 static int setdebug_cmd(JCR *jcr)
363 BSOCK *dir = jcr->dir_bsock;
364 int level, trace_flag;
366 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
367 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
368 pm_strcpy(jcr->errmsg, dir->msg);
369 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
373 set_trace(trace_flag);
374 return bnet_fsend(dir, OKsetdebug, level);
378 static int estimate_cmd(JCR *jcr)
380 BSOCK *dir = jcr->dir_bsock;
383 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
384 pm_strcpy(jcr->errmsg, dir->msg);
385 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
386 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
390 bnet_fsend(dir, OKest, jcr->num_files_examined,
391 edit_uint64_with_commas(jcr->JobBytes, ed2));
392 bnet_sig(dir, BNET_EOD);
397 * Get JobId and Storage Daemon Authorization key from Director
399 static int job_cmd(JCR *jcr)
401 BSOCK *dir = jcr->dir_bsock;
402 POOLMEM *sd_auth_key;
404 sd_auth_key = get_memory(dir->msglen);
405 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
406 &jcr->VolSessionId, &jcr->VolSessionTime,
408 pm_strcpy(jcr->errmsg, dir->msg);
409 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
410 bnet_fsend(dir, BADjob);
411 free_pool_memory(sd_auth_key);
414 jcr->sd_auth_key = bstrdup(sd_auth_key);
415 free_pool_memory(sd_auth_key);
416 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
417 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
420 static int runbefore_cmd(JCR *jcr)
423 BSOCK *dir = jcr->dir_bsock;
424 POOLMEM *cmd = get_memory(dir->msglen+1);
427 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
428 if (sscanf(dir->msg, runbefore, cmd) != 1) {
429 pm_strcpy(jcr->errmsg, dir->msg);
430 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
431 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
437 /* Run the command now */
438 script = new_runscript();
439 script->set_command(cmd);
440 script->when = SCRIPT_Before;
441 ok = script->run(jcr, "ClientRunBeforeJob");
442 free_runscript(script);
446 bnet_fsend(dir, OKRunBefore);
449 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
454 static int runbeforenow_cmd(JCR *jcr)
456 BSOCK *dir = jcr->dir_bsock;
458 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
459 return bnet_fsend(dir, OKRunBeforeNow);
462 static int runafter_cmd(JCR *jcr)
464 BSOCK *dir = jcr->dir_bsock;
465 POOLMEM *msg = get_memory(dir->msglen+1);
468 Dmsg1(100, "runafter_cmd: %s", dir->msg);
469 if (sscanf(dir->msg, runafter, msg) != 1) {
470 pm_strcpy(jcr->errmsg, dir->msg);
471 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
472 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
478 cmd = new_runscript();
479 cmd->set_command(msg);
480 cmd->on_success = true;
481 cmd->on_failure = false;
482 cmd->when = SCRIPT_After;
484 jcr->RunScripts->append(cmd);
486 free_pool_memory(msg);
487 return bnet_fsend(dir, OKRunAfter);
490 static int runscript_cmd(JCR *jcr)
492 BSOCK *dir = jcr->dir_bsock;
493 POOLMEM *msg = get_memory(dir->msglen+1);
495 RUNSCRIPT *cmd = new_runscript() ;
497 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
498 if (sscanf(dir->msg, runscript, &cmd->on_success,
500 &cmd->abort_on_error,
503 pm_strcpy(jcr->errmsg, dir->msg);
504 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
505 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
512 cmd->set_command(msg);
514 jcr->RunScripts->append(cmd);
516 free_pool_memory(msg);
517 return bnet_fsend(dir, OKRunScript);
521 static bool init_fileset(JCR *jcr)
524 findFILESET *fileset;
533 fileset = (findFILESET *)malloc(sizeof(findFILESET));
534 memset(fileset, 0, sizeof(findFILESET));
535 ff->fileset = fileset;
536 fileset->state = state_none;
537 fileset->include_list.init(1, true);
538 fileset->exclude_list.init(1, true);
542 static findFOPTS *start_options(FF_PKT *ff)
544 int state = ff->fileset->state;
545 findINCEXE *incexe = ff->fileset->incexe;
547 if (state != state_options) {
548 ff->fileset->state = state_options;
549 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
550 memset(fo, 0, sizeof(findFOPTS));
551 fo->regex.init(1, true);
552 fo->regexdir.init(1, true);
553 fo->regexfile.init(1, true);
554 fo->wild.init(1, true);
555 fo->wilddir.init(1, true);
556 fo->wildfile.init(1, true);
557 fo->base.init(1, true);
558 fo->fstype.init(1, true);
559 incexe->current_opts = fo;
560 incexe->opts_list.append(fo);
562 return incexe->current_opts;
567 * Add fname to include/exclude fileset list. First check for
568 * | and < and if necessary perform command.
570 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
584 p++; /* skip over | */
585 fn = get_pool_memory(PM_FNAME);
586 fn = edit_job_codes(jcr, fn, p, "");
587 bpipe = open_bpipe(fn, 0, "r");
588 free_pool_memory(fn);
590 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
594 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
595 strip_trailing_junk(buf);
596 fileset->incexe->name_list.append(bstrdup(buf));
598 if ((stat=close_bpipe(bpipe)) != 0) {
599 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
600 p, stat, strerror(errno));
605 Dmsg0(100, "Doing < include on client.\n");
606 p++; /* skip over < */
607 if ((ffd = fopen(p, "r")) == NULL) {
609 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
613 while (fgets(buf, sizeof(buf), ffd)) {
614 strip_trailing_junk(buf);
615 Dmsg1(100, "%s\n", buf);
616 fileset->incexe->name_list.append(bstrdup(buf));
621 fileset->incexe->name_list.append(bstrdup(fname));
627 static void add_fileset(JCR *jcr, const char *item)
629 FF_PKT *ff = jcr->ff;
630 findFILESET *fileset = ff->fileset;
631 int state = fileset->state;
632 findFOPTS *current_opts;
634 /* Get code, optional subcode, and position item past the dividing space */
635 Dmsg1(100, "%s\n", item);
640 int subcode = ' '; /* A space is always a valid subcode */
641 if (item[0] != '\0' && item[0] != ' ') {
649 /* Skip all lines we receive after an error */
650 if (state == state_error) {
655 * The switch tests the code for validity.
656 * The subcode is always good if it is a space, otherwise we must confirm.
657 * We set state to state_error first assuming the subcode is invalid,
658 * requiring state to be set in cases below that handle subcodes.
660 if (subcode != ' ') {
666 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
667 memset(fileset->incexe, 0, sizeof(findINCEXE));
668 fileset->incexe->opts_list.init(1, true);
669 fileset->incexe->name_list.init(1, true);
670 fileset->include_list.append(fileset->incexe);
674 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
675 memset(fileset->incexe, 0, sizeof(findINCEXE));
676 fileset->incexe->opts_list.init(1, true);
677 fileset->incexe->name_list.init(1, true);
678 fileset->exclude_list.append(fileset->incexe);
684 /* File item to either include/include list */
685 state = state_include;
686 add_file_to_fileset(jcr, item, fileset);
689 current_opts = start_options(ff);
693 preg = (regex_t *)malloc(sizeof(regex_t));
694 if (current_opts->flags & FO_IGNORECASE) {
695 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
697 rc = regcomp(preg, item, REG_EXTENDED);
700 regerror(rc, preg, prbuf, sizeof(prbuf));
703 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
707 state = state_options;
708 if (subcode == ' ') {
709 current_opts->regex.append(preg);
710 } else if (subcode == 'D') {
711 current_opts->regexdir.append(preg);
712 } else if (subcode == 'F') {
713 current_opts->regexfile.append(preg);
719 current_opts = start_options(ff);
720 current_opts->base.append(bstrdup(item));
721 state = state_options;
724 current_opts = start_options(ff);
725 current_opts->fstype.append(bstrdup(item));
726 state = state_options;
729 current_opts = start_options(ff);
730 state = state_options;
731 if (subcode == ' ') {
732 current_opts->wild.append(bstrdup(item));
733 } else if (subcode == 'D') {
734 current_opts->wilddir.append(bstrdup(item));
735 } else if (subcode == 'F') {
736 current_opts->wildfile.append(bstrdup(item));
742 current_opts = start_options(ff);
743 set_options(current_opts, item);
744 state = state_options;
747 current_opts = start_options(ff);
748 current_opts->reader = bstrdup(item);
749 state = state_options;
752 current_opts = start_options(ff);
753 current_opts->writer = bstrdup(item);
754 state = state_options;
757 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
761 ff->fileset->state = state;
764 static bool term_fileset(JCR *jcr)
766 FF_PKT *ff = jcr->ff;
769 findFILESET *fileset = ff->fileset;
772 for (i=0; i<fileset->include_list.size(); i++) {
773 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
775 for (j=0; j<incexe->opts_list.size(); j++) {
776 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
777 for (k=0; k<fo->regex.size(); k++) {
778 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
780 for (k=0; k<fo->regexdir.size(); k++) {
781 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
783 for (k=0; k<fo->regexfile.size(); k++) {
784 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
786 for (k=0; k<fo->wild.size(); k++) {
787 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
789 for (k=0; k<fo->wilddir.size(); k++) {
790 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
792 for (k=0; k<fo->wildfile.size(); k++) {
793 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
795 for (k=0; k<fo->base.size(); k++) {
796 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
798 for (k=0; k<fo->fstype.size(); k++) {
799 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
802 Dmsg1(400, "D %s\n", fo->reader);
805 Dmsg1(400, "T %s\n", fo->writer);
808 for (j=0; j<incexe->name_list.size(); j++) {
809 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
812 for (i=0; i<fileset->exclude_list.size(); i++) {
813 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
815 for (j=0; j<incexe->opts_list.size(); j++) {
816 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
817 for (k=0; k<fo->regex.size(); k++) {
818 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
820 for (k=0; k<fo->regexdir.size(); k++) {
821 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
823 for (k=0; k<fo->regexfile.size(); k++) {
824 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
826 for (k=0; k<fo->wild.size(); k++) {
827 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
829 for (k=0; k<fo->wilddir.size(); k++) {
830 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
832 for (k=0; k<fo->wildfile.size(); k++) {
833 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
835 for (k=0; k<fo->base.size(); k++) {
836 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
838 for (k=0; k<fo->fstype.size(); k++) {
839 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
842 for (j=0; j<incexe->name_list.size(); j++) {
843 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
847 return ff->fileset->state != state_error;
852 * As an optimization, we should do this during
853 * "compile" time in filed/job.c, and keep only a bit mask
854 * and the Verify options.
856 static void set_options(findFOPTS *fo, const char *opts)
861 for (p=opts; *p; p++) {
863 case 'a': /* alway replace */
864 case '0': /* no option */
867 fo->flags |= FO_EXCLUDE;
870 fo->flags |= FO_MULTIFS;
872 case 'h': /* no recursion */
873 fo->flags |= FO_NO_RECURSION;
875 case 'H': /* no hard link handling */
876 fo->flags |= FO_NO_HARDLINK;
879 fo->flags |= FO_IGNORECASE;
885 fo->flags |= FO_NOREPLACE;
887 case 'p': /* use portable data format */
888 fo->flags |= FO_PORTABLE;
890 case 'R': /* Resource forks and Finder Info */
891 fo->flags |= FO_HFSPLUS;
892 case 'r': /* read fifo */
893 fo->flags |= FO_READFIFO;
898 /* Old director did not specify SHA variant */
899 fo->flags |= FO_SHA1;
902 fo->flags |= FO_SHA1;
907 fo->flags |= FO_SHA256;
911 fo->flags |= FO_SHA512;
916 /* Automatically downgrade to SHA-1 if an unsupported
917 * SHA variant is specified */
918 fo->flags |= FO_SHA1;
924 fo->flags |= FO_SPARSE;
927 fo->flags |= FO_MTIMEONLY;
930 fo->flags |= FO_KEEPATIME;
935 case 'V': /* verify options */
936 /* Copy Verify Options */
937 for (j=0; *p && *p != ':'; p++) {
938 fo->VerifyOpts[j] = *p;
939 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
943 fo->VerifyOpts[j] = 0;
946 fo->flags |= FO_IF_NEWER;
948 case 'Z': /* gzip compression */
949 fo->flags |= FO_GZIP;
950 fo->GZIP_level = *++p - '0';
951 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
954 fo->flags |= FO_NOATIME;
957 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
965 * Director is passing his Fileset
967 static int fileset_cmd(JCR *jcr)
969 BSOCK *dir = jcr->dir_bsock;
972 sscanf(dir->msg, "fileset vss=%d", &vss);
975 if (!init_fileset(jcr)) {
978 while (bnet_recv(dir) >= 0) {
979 strip_trailing_junk(dir->msg);
980 Dmsg1(500, "Fileset: %s\n", dir->msg);
981 add_fileset(jcr, dir->msg);
983 if (!term_fileset(jcr)) {
986 return bnet_fsend(dir, OKinc);
989 static void free_bootstrap(JCR *jcr)
991 if (jcr->RestoreBootstrap) {
992 unlink(jcr->RestoreBootstrap);
993 free_pool_memory(jcr->RestoreBootstrap);
994 jcr->RestoreBootstrap = NULL;
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);
1010 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
1012 Dmsg1(400, "bootstrap=%s\n", fname);
1013 jcr->RestoreBootstrap = fname;
1014 bs = fopen(fname, "a+"); /* 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");
1330 set_jcr_job_status(jcr, JS_Terminated);
1332 /* run shortly after end of data transmission */
1333 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1335 if (jcr->JobStatus != JS_Terminated) {
1336 bnet_suppress_error_messages(sd, 1);
1337 goto cleanup; /* bail out now */
1340 * Expect to get response to append_data from Storage daemon
1342 if (!response(jcr, sd, OK_append, "Append Data")) {
1343 set_jcr_job_status(jcr, JS_ErrorTerminated);
1348 * Send Append End Data to Storage daemon
1350 bnet_fsend(sd, append_end, jcr->Ticket);
1352 if (!response(jcr, sd, OK_end, "Append End")) {
1353 set_jcr_job_status(jcr, JS_ErrorTerminated);
1358 * Send Append Close to Storage daemon
1360 bnet_fsend(sd, append_close, jcr->Ticket);
1361 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1362 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1364 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1368 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1371 if (SDJobStatus != JS_Terminated) {
1372 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1379 /* STOP VSS ON WIN 32 */
1380 /* tell vss to close the backup session */
1382 if (g_pVSSClient->CloseBackup()) {
1383 /* inform user about writer states */
1384 for (size_t i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1385 int msg_type = M_INFO;
1386 if (g_pVSSClient->GetWriterState(i) < 1) {
1387 msg_type = M_WARNING;
1390 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1397 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1398 edit_uint64(jcr->ReadBytes, ed1),
1399 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1400 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1402 return 0; /* return and stop command loop */
1406 * Do a Verify for Director
1409 static int verify_cmd(JCR *jcr)
1411 BSOCK *dir = jcr->dir_bsock;
1412 BSOCK *sd = jcr->store_bsock;
1413 char level[100], ed1[50], ed2[50];
1415 jcr->JobType = JT_VERIFY;
1416 if (sscanf(dir->msg, verifycmd, level) != 1) {
1417 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1421 if (strcasecmp(level, "init") == 0) {
1422 jcr->JobLevel = L_VERIFY_INIT;
1423 } else if (strcasecmp(level, "catalog") == 0){
1424 jcr->JobLevel = L_VERIFY_CATALOG;
1425 } else if (strcasecmp(level, "volume") == 0){
1426 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1427 } else if (strcasecmp(level, "data") == 0){
1428 jcr->JobLevel = L_VERIFY_DATA;
1429 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1430 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1432 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1436 bnet_fsend(dir, OKverify);
1438 generate_daemon_event(jcr, "JobStart");
1440 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1442 switch (jcr->JobLevel) {
1444 case L_VERIFY_CATALOG:
1447 case L_VERIFY_VOLUME_TO_CATALOG:
1448 if (!open_sd_read_session(jcr)) {
1451 start_dir_heartbeat(jcr);
1452 do_verify_volume(jcr);
1453 stop_dir_heartbeat(jcr);
1455 * Send Close session command to Storage daemon
1457 bnet_fsend(sd, read_close, jcr->Ticket);
1458 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1460 /* ****FIXME**** check response */
1461 bget_msg(sd); /* get OK */
1463 /* Inform Storage daemon that we are done */
1464 bnet_sig(sd, BNET_TERMINATE);
1467 case L_VERIFY_DISK_TO_CATALOG:
1471 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1475 bnet_sig(dir, BNET_EOD);
1477 /* Send termination status back to Dir */
1478 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1479 edit_uint64(jcr->ReadBytes, ed1),
1480 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1482 /* Inform Director that we are done */
1483 bnet_sig(dir, BNET_TERMINATE);
1484 return 0; /* return and terminate command loop */
1488 * Do a Restore for Director
1491 static int restore_cmd(JCR *jcr)
1493 BSOCK *dir = jcr->dir_bsock;
1494 BSOCK *sd = jcr->store_bsock;
1498 char ed1[50], ed2[50];
1501 * Scan WHERE (base directory for restore) from command
1503 Dmsg0(150, "restore command\n");
1504 /* Pickup where string */
1505 where = get_memory(dir->msglen+1);
1508 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1509 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1510 pm_strcpy(jcr->errmsg, dir->msg);
1511 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1516 /* Turn / into nothing */
1517 if (where[0] == '/' && where[1] == 0) {
1521 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1522 unbash_spaces(where);
1523 jcr->where = bstrdup(where);
1524 free_pool_memory(where);
1525 jcr->replace = replace;
1526 jcr->prefix_links = prefix_links;
1528 bnet_fsend(dir, OKrestore);
1529 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1531 jcr->JobType = JT_RESTORE;
1533 set_jcr_job_status(jcr, JS_Blocked);
1535 if (!open_sd_read_session(jcr)) {
1536 set_jcr_job_status(jcr, JS_ErrorTerminated);
1540 set_jcr_job_status(jcr, JS_Running);
1543 * Do restore of files and data
1545 start_dir_heartbeat(jcr);
1546 generate_daemon_event(jcr, "JobStart");
1548 stop_dir_heartbeat(jcr);
1550 set_jcr_job_status(jcr, JS_Terminated);
1551 if (jcr->JobStatus != JS_Terminated) {
1552 bnet_suppress_error_messages(sd, 1);
1556 * Send Close session command to Storage daemon
1558 bnet_fsend(sd, read_close, jcr->Ticket);
1559 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1561 bget_msg(sd); /* get OK */
1563 /* Inform Storage daemon that we are done */
1564 bnet_sig(sd, BNET_TERMINATE);
1569 set_jcr_job_status(jcr, JS_ErrorTerminated);
1571 /* Send termination status back to Dir */
1572 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1573 edit_uint64(jcr->ReadBytes, ed1),
1574 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1576 /* Inform Director that we are done */
1577 bnet_sig(dir, BNET_TERMINATE);
1579 Dmsg0(130, "Done in job.c\n");
1580 return 0; /* return and terminate command loop */
1583 static int open_sd_read_session(JCR *jcr)
1585 BSOCK *sd = jcr->store_bsock;
1588 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1591 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1592 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1593 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1595 * Open Read Session with Storage daemon
1597 bnet_fsend(sd, read_open, "DummyVolume",
1598 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1599 jcr->StartBlock, jcr->EndBlock);
1600 Dmsg1(110, ">stored: %s", sd->msg);
1605 if (bget_msg(sd) >= 0) {
1606 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1607 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1608 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1611 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1613 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1617 if (!send_bootstrap_file(jcr)) {
1622 * Start read of data with Storage daemon
1624 bnet_fsend(sd, read_data, jcr->Ticket);
1625 Dmsg1(110, ">stored: %s", sd->msg);
1630 if (!response(jcr, sd, OK_data, "Read Data")) {
1637 * Destroy the Job Control Record and associated
1638 * resources (sockets).
1640 static void filed_free_jcr(JCR *jcr)
1642 if (jcr->store_bsock) {
1643 bnet_close(jcr->store_bsock);
1645 free_bootstrap(jcr);
1646 if (jcr->last_fname) {
1647 free_pool_memory(jcr->last_fname);
1649 free_runscripts(jcr->RunScripts);
1650 delete jcr->RunScripts;
1656 * Get response from Storage daemon to a command we
1657 * sent. Check that the response is OK.
1659 * Returns: 0 on failure
1662 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1667 if (bget_msg(sd) > 0) {
1668 Dmsg0(110, sd->msg);
1669 if (strcmp(sd->msg, resp) == 0) {
1673 if (job_canceled(jcr)) {
1674 return 0; /* if canceled avoid useless error messages */
1676 if (is_bnet_error(sd)) {
1677 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1678 cmd, bnet_strerror(sd));
1680 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1681 cmd, resp, sd->msg);
1686 static int send_bootstrap_file(JCR *jcr)
1690 BSOCK *sd = jcr->store_bsock;
1691 const char *bootstrap = "bootstrap\n";
1694 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1695 if (!jcr->RestoreBootstrap) {
1698 bs = fopen(jcr->RestoreBootstrap, "r");
1701 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1702 jcr->RestoreBootstrap, be.strerror());
1703 set_jcr_job_status(jcr, JS_ErrorTerminated);
1706 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1708 while (fgets(buf, sizeof(buf), bs)) {
1709 sd->msglen = Mmsg(sd->msg, "%s", buf);
1712 bnet_sig(sd, BNET_EOD);
1714 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1715 set_jcr_job_status(jcr, JS_ErrorTerminated);
1721 free_bootstrap(jcr);