2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Copyright (C) 2000-2005 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 ammended 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.
31 extern char my_name[];
32 extern CLIENT *me; /* our client resource */
34 /* Imported functions */
35 extern int status_cmd(JCR *jcr);
36 extern int qstatus_cmd(JCR *jcr);
38 /* Forward referenced functions */
39 static int backup_cmd(JCR *jcr);
40 static int bootstrap_cmd(JCR *jcr);
41 static int cancel_cmd(JCR *jcr);
42 static int setdebug_cmd(JCR *jcr);
43 static int estimate_cmd(JCR *jcr);
44 static int hello_cmd(JCR *jcr);
45 static int job_cmd(JCR *jcr);
46 static int fileset_cmd(JCR *jcr);
47 static int level_cmd(JCR *jcr);
48 static int verify_cmd(JCR *jcr);
49 static int restore_cmd(JCR *jcr);
50 static int storage_cmd(JCR *jcr);
51 static int session_cmd(JCR *jcr);
52 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
53 static void filed_free_jcr(JCR *jcr);
54 static int open_sd_read_session(JCR *jcr);
55 static int send_bootstrap_file(JCR *jcr);
56 static int runbefore_cmd(JCR *jcr);
57 static int runafter_cmd(JCR *jcr);
58 static bool run_cmd(JCR *jcr, char *cmd, const char *name);
59 static void set_options(findFOPTS *fo, const char *opts);
62 /* Exported functions */
67 int monitoraccess; /* specify if monitors have access to this function */
71 * The following are the recognized commands from the Director.
73 static struct s_cmds cmds[] = {
74 {"backup", backup_cmd, 0},
75 {"cancel", cancel_cmd, 0},
76 {"setdebug=", setdebug_cmd, 0},
77 {"estimate", estimate_cmd, 0},
78 {"Hello", hello_cmd, 1},
79 {"fileset", fileset_cmd, 0},
80 {"JobId=", job_cmd, 0},
81 {"level = ", level_cmd, 0},
82 {"restore", restore_cmd, 0},
83 {"session", session_cmd, 0},
84 {"status", status_cmd, 1},
85 {".status", qstatus_cmd, 1},
86 {"storage ", storage_cmd, 0},
87 {"verify", verify_cmd, 0},
88 {"bootstrap", bootstrap_cmd, 0},
89 {"RunBeforeJob", runbefore_cmd, 0},
90 {"RunAfterJob", runafter_cmd, 0},
91 {NULL, NULL} /* list terminator */
94 /* Commands received from director that need scanning */
95 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
96 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
97 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
98 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
99 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
100 static char verifycmd[] = "verify level=%30s\n";
101 static char estimatecmd[] = "estimate listing=%d\n";
102 static char runbefore[] = "RunBeforeJob %s\n";
103 static char runafter[] = "RunAfterJob %s\n";
105 /* Responses sent to Director */
106 static char errmsg[] = "2999 Invalid command\n";
107 static char no_auth[] = "2998 No Authorization\n";
108 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
109 static char OKinc[] = "2000 OK include\n";
110 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
111 static char OKlevel[] = "2000 OK level\n";
112 static char OKbackup[] = "2000 OK backup\n";
113 static char OKbootstrap[] = "2000 OK bootstrap\n";
114 static char OKverify[] = "2000 OK verify\n";
115 static char OKrestore[] = "2000 OK restore\n";
116 static char OKsession[] = "2000 OK session\n";
117 static char OKstore[] = "2000 OK storage\n";
118 static char OKjob[] = "2000 OK Job %s,%s,%s";
119 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
120 static char BADjob[] = "2901 Bad Job\n";
121 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
122 static char OKRunBefore[] = "2000 OK RunBefore\n";
123 static char OKRunAfter[] = "2000 OK RunAfter\n";
125 /* Responses received from Storage Daemon */
126 static char OK_end[] = "3000 OK end\n";
127 static char OK_close[] = "3000 OK close Status = %d\n";
128 static char OK_open[] = "3000 OK open ticket = %d\n";
129 static char OK_data[] = "3000 OK data\n";
130 static char OK_append[] = "3000 OK append data\n";
131 static char OKSDbootstrap[] = "3000 OK bootstrap\n";
134 /* Commands sent to Storage Daemon */
135 static char append_open[] = "append open session\n";
136 static char append_data[] = "append data %d\n";
137 static char append_end[] = "append end session %d\n";
138 static char append_close[] = "append close session %d\n";
139 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
140 static char read_data[] = "read data %d\n";
141 static char read_close[] = "read close session %d\n";
144 * Accept requests from a Director
146 * NOTE! We are running as a separate thread
148 * Send output one line
149 * at a time followed by a zero length transmission.
151 * Return when the connection is terminated or there
154 * Basic task here is:
155 * Authenticate Director (during Hello command).
156 * Accept commands one at a time from the Director
160 void *handle_client_request(void *dirp)
165 BSOCK *dir = (BSOCK *)dirp;
167 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
168 jcr->dir_bsock = dir;
169 jcr->ff = init_find_files();
170 jcr->start_time = time(NULL);
171 jcr->last_fname = get_pool_memory(PM_FNAME);
172 jcr->last_fname[0] = 0;
173 jcr->client_name = get_memory(strlen(my_name) + 1);
174 pm_strcpy(jcr->client_name, my_name);
176 enable_backup_privileges(NULL, 1 /* ignore_errors */);
178 /**********FIXME******* add command handler error code */
180 for (quit=false; !quit;) {
183 if (bnet_recv(dir) < 0) {
184 break; /* connection terminated */
186 dir->msg[dir->msglen] = 0;
187 Dmsg1(100, "<dird: %s", dir->msg);
189 for (i=0; cmds[i].cmd; i++) {
190 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
191 found = true; /* indicate command found */
192 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
193 bnet_fsend(dir, no_auth);
194 bnet_sig(dir, BNET_EOD);
197 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
198 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
199 bnet_fsend(dir, illegal_cmd);
200 bnet_sig(dir, BNET_EOD);
203 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
204 if (!cmds[i].func(jcr)) { /* do command */
205 quit = true; /* error or fully terminated, get out */
206 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
211 if (!found) { /* command not found */
212 bnet_fsend(dir, errmsg);
218 /* Inform Storage daemon that we are done */
219 if (jcr->store_bsock) {
220 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
223 if (jcr->RunAfterJob && !job_canceled(jcr)) {
224 run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob");
226 generate_daemon_event(jcr, "JobEnd");
228 dequeue_messages(jcr); /* send any queued messages */
230 /* Inform Director that we are done */
231 bnet_sig(dir, BNET_TERMINATE);
233 /* Clean up fileset */
234 FF_PKT *ff = (FF_PKT *)jcr->ff;
235 findFILESET *fileset = ff->fileset;
238 /* Delete FileSet Include lists */
239 for (i=0; i<fileset->include_list.size(); i++) {
240 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
241 for (j=0; j<incexe->opts_list.size(); j++) {
242 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
243 for (k=0; k<fo->regex.size(); k++) {
244 regfree((regex_t *)fo->regex.get(k));
247 fo->regexdir.destroy();
248 fo->regexfile.destroy();
250 fo->wilddir.destroy();
251 fo->wildfile.destroy();
253 fo->fstype.destroy();
261 incexe->opts_list.destroy();
262 incexe->name_list.destroy();
264 fileset->include_list.destroy();
266 /* Delete FileSet Exclude lists */
267 for (i=0; i<fileset->exclude_list.size(); i++) {
268 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
269 for (j=0; j<incexe->opts_list.size(); j++) {
270 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
272 fo->regexdir.destroy();
273 fo->regexfile.destroy();
275 fo->wilddir.destroy();
276 fo->wildfile.destroy();
278 fo->fstype.destroy();
280 incexe->opts_list.destroy();
281 incexe->name_list.destroy();
283 fileset->exclude_list.destroy();
287 Dmsg0(100, "Calling term_find_files\n");
288 term_find_files((FF_PKT *)jcr->ff);
290 Dmsg0(100, "Done with term_find_files\n");
291 free_jcr(jcr); /* destroy JCR record */
292 Dmsg0(100, "Done with free_jcr\n");
297 * Hello from Director he must identify himself and provide his
300 static int hello_cmd(JCR *jcr)
302 Dmsg0(120, "Calling Authenticate\n");
303 if (!authenticate_director(jcr)) {
306 Dmsg0(120, "OK Authenticate\n");
307 jcr->authenticated = true;
314 static int cancel_cmd(JCR *jcr)
316 BSOCK *dir = jcr->dir_bsock;
317 char Job[MAX_NAME_LENGTH];
320 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
321 if (!(cjcr=get_jcr_by_full_name(Job))) {
322 bnet_fsend(dir, "2901 Job %s not found.\n", Job);
324 if (cjcr->store_bsock) {
326 cjcr->store_bsock->timed_out = 1;
327 cjcr->store_bsock->terminated = 1;
329 * #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
331 #if !defined(HAVE_CYGWIN)
332 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
336 set_jcr_job_status(cjcr, JS_Canceled);
338 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
341 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
343 bnet_sig(dir, BNET_EOD);
349 * Set debug level as requested by the Director
352 static int setdebug_cmd(JCR *jcr)
354 BSOCK *dir = jcr->dir_bsock;
355 int level, trace_flag;
357 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
358 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
359 pm_strcpy(jcr->errmsg, dir->msg);
360 bnet_fsend(dir, "2991 Bad setdebug command: %s\n", jcr->errmsg);
364 set_trace(trace_flag);
365 return bnet_fsend(dir, OKsetdebug, level);
369 static int estimate_cmd(JCR *jcr)
371 BSOCK *dir = jcr->dir_bsock;
374 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
375 pm_strcpy(jcr->errmsg, dir->msg);
376 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
377 bnet_fsend(dir, "2992 Bad estimate command.\n");
381 bnet_fsend(dir, OKest, jcr->num_files_examined,
382 edit_uint64_with_commas(jcr->JobBytes, ed2));
383 bnet_sig(dir, BNET_EOD);
388 * Get JobId and Storage Daemon Authorization key from Director
390 static int job_cmd(JCR *jcr)
392 BSOCK *dir = jcr->dir_bsock;
393 POOLMEM *sd_auth_key;
395 sd_auth_key = get_memory(dir->msglen);
396 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
397 &jcr->VolSessionId, &jcr->VolSessionTime,
399 pm_strcpy(jcr->errmsg, dir->msg);
400 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
401 bnet_fsend(dir, BADjob);
402 free_pool_memory(sd_auth_key);
405 jcr->sd_auth_key = bstrdup(sd_auth_key);
406 free_pool_memory(sd_auth_key);
407 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
408 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
411 static int runbefore_cmd(JCR *jcr)
414 BSOCK *dir = jcr->dir_bsock;
415 POOLMEM *cmd = get_memory(dir->msglen+1);
417 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
418 if (sscanf(dir->msg, runbefore, cmd) != 1) {
419 pm_strcpy(jcr->errmsg, dir->msg);
420 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
421 bnet_fsend(dir, "2905 Bad RunBeforeJob command.\n");
427 /* Run the command now */
428 ok = run_cmd(jcr, cmd, "ClientRunBeforeJob");
431 bnet_fsend(dir, OKRunBefore);
434 bnet_fsend(dir, "2905 Bad RunBeforeJob command.\n");
439 static int runafter_cmd(JCR *jcr)
441 BSOCK *dir = jcr->dir_bsock;
442 POOLMEM *msg = get_memory(dir->msglen+1);
444 Dmsg1(100, "runafter_cmd: %s", dir->msg);
445 if (sscanf(dir->msg, runafter, msg) != 1) {
446 pm_strcpy(jcr->errmsg, dir->msg);
447 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
448 bnet_fsend(dir, "2905 Bad RunAfterJob command.\n");
453 if (jcr->RunAfterJob) {
454 free_pool_memory(jcr->RunAfterJob);
456 jcr->RunAfterJob = get_pool_memory(PM_FNAME);
457 pm_strcpy(jcr->RunAfterJob, msg);
458 free_pool_memory(msg);
459 return bnet_fsend(dir, OKRunAfter);
462 static bool run_cmd(JCR *jcr, char *cmd, const char *name)
464 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
467 char line[MAXSTRING];
469 ecmd = edit_job_codes(jcr, ecmd, cmd, "");
470 bpipe = open_bpipe(ecmd, 0, "r");
471 free_pool_memory(ecmd);
474 Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name,
478 while (fgets(line, sizeof(line), bpipe->rfd)) {
479 int len = strlen(line);
480 if (len > 0 && line[len-1] == '\n') {
483 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
485 status = close_bpipe(bpipe);
488 Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
489 status, be.strerror(status));
495 static bool init_fileset(JCR *jcr)
498 findFILESET *fileset;
503 ff = (FF_PKT *)jcr->ff;
507 fileset = (findFILESET *)malloc(sizeof(findFILESET));
508 memset(fileset, 0, sizeof(findFILESET));
509 ff->fileset = fileset;
510 fileset->state = state_none;
511 fileset->include_list.init(1, true);
512 fileset->exclude_list.init(1, true);
516 static findFOPTS *start_options(FF_PKT *ff)
518 int state = ff->fileset->state;
519 findINCEXE *incexe = ff->fileset->incexe;
521 if (state != state_options) {
522 ff->fileset->state = state_options;
523 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
524 memset(fo, 0, sizeof(findFOPTS));
525 fo->regex.init(1, true);
526 fo->regexdir.init(1, true);
527 fo->regexfile.init(1, true);
528 fo->wild.init(1, true);
529 fo->wilddir.init(1, true);
530 fo->wildfile.init(1, true);
531 fo->base.init(1, true);
532 fo->fstype.init(1, true);
533 incexe->current_opts = fo;
534 incexe->opts_list.append(fo);
536 return incexe->current_opts;
541 * Add fname to include/exclude fileset list. First check for
542 * | and < and if necessary perform command.
544 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
558 p++; /* skip over | */
559 fn = get_pool_memory(PM_FNAME);
560 fn = edit_job_codes(jcr, fn, p, "");
561 bpipe = open_bpipe(fn, 0, "r");
562 free_pool_memory(fn);
564 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
568 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
569 strip_trailing_junk(buf);
570 fileset->incexe->name_list.append(bstrdup(buf));
572 if ((stat=close_bpipe(bpipe)) != 0) {
573 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
574 p, stat, strerror(errno));
579 Dmsg0(100, "Doing < include on client.\n");
580 p++; /* skip over < */
581 if ((ffd = fopen(p, "r")) == NULL) {
583 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
587 while (fgets(buf, sizeof(buf), ffd)) {
588 strip_trailing_junk(buf);
589 Dmsg1(100, "%s\n", buf);
590 fileset->incexe->name_list.append(bstrdup(buf));
595 fileset->incexe->name_list.append(bstrdup(fname));
601 static void add_fileset(JCR *jcr, const char *item)
603 FF_PKT *ff = (FF_PKT *)jcr->ff;
604 findFILESET *fileset = ff->fileset;
605 int state = fileset->state;
606 findFOPTS *current_opts;
608 /* Get code, optional subcode, and position item past the dividing space */
609 Dmsg1(100, "%s\n", item);
614 int subcode = ' '; /* A space is always a valid subcode */
615 if (item[0] != '\0' && item[0] != ' ') {
623 /* Skip all lines we receive after an error */
624 if (state == state_error) {
629 * The switch tests the code for validity.
630 * The subcode is always good if it is a space, otherwise we must confirm.
631 * We set state to state_error first assuming the subcode is invalid,
632 * requiring state to be set in cases below that handle subcodes.
634 if (subcode != ' ') {
640 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
641 memset(fileset->incexe, 0, sizeof(findINCEXE));
642 fileset->incexe->opts_list.init(1, true);
643 fileset->incexe->name_list.init(1, true);
644 fileset->include_list.append(fileset->incexe);
648 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
649 memset(fileset->incexe, 0, sizeof(findINCEXE));
650 fileset->incexe->opts_list.init(1, true);
651 fileset->incexe->name_list.init(1, true);
652 fileset->exclude_list.append(fileset->incexe);
658 /* File item to either include/include list */
659 state = state_include;
660 add_file_to_fileset(jcr, item, fileset);
663 current_opts = start_options(ff);
667 preg = (regex_t *)malloc(sizeof(regex_t));
668 if (current_opts->flags & FO_IGNORECASE) {
669 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
671 rc = regcomp(preg, item, REG_EXTENDED);
674 regerror(rc, preg, prbuf, sizeof(prbuf));
677 Jmsg(jcr, M_FATAL, 0, "REGEX %s compile error. ERR=%s\n", item, prbuf);
681 state = state_options;
682 if (subcode == ' ') {
683 current_opts->regex.append(preg);
684 } else if (subcode == 'D') {
685 current_opts->regexdir.append(preg);
686 } else if (subcode == 'F') {
687 current_opts->regexfile.append(preg);
693 current_opts = start_options(ff);
694 current_opts->base.append(bstrdup(item));
695 state = state_options;
698 current_opts = start_options(ff);
699 current_opts->fstype.append(bstrdup(item));
700 state = state_options;
703 current_opts = start_options(ff);
704 state = state_options;
705 if (subcode == ' ') {
706 current_opts->wild.append(bstrdup(item));
707 } else if (subcode == 'D') {
708 current_opts->wilddir.append(bstrdup(item));
709 } else if (subcode == 'F') {
710 current_opts->wildfile.append(bstrdup(item));
716 current_opts = start_options(ff);
717 set_options(current_opts, item);
718 state = state_options;
721 current_opts = start_options(ff);
722 current_opts->reader = bstrdup(item);
723 state = state_options;
726 current_opts = start_options(ff);
727 current_opts->writer = bstrdup(item);
728 state = state_options;
731 Jmsg(jcr, M_FATAL, 0, "Invalid FileSet command: %s\n", item);
735 ff->fileset->state = state;
738 static bool term_fileset(JCR *jcr)
740 FF_PKT *ff = (FF_PKT *)jcr->ff;
741 findFILESET *fileset = ff->fileset;
744 for (i=0; i<fileset->include_list.size(); i++) {
745 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
747 for (j=0; j<incexe->opts_list.size(); j++) {
748 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
749 for (k=0; k<fo->regex.size(); k++) {
750 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
752 for (k=0; k<fo->regexdir.size(); k++) {
753 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
755 for (k=0; k<fo->regexfile.size(); k++) {
756 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
758 for (k=0; k<fo->wild.size(); k++) {
759 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
761 for (k=0; k<fo->wilddir.size(); k++) {
762 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
764 for (k=0; k<fo->wildfile.size(); k++) {
765 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
767 for (k=0; k<fo->base.size(); k++) {
768 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
770 for (k=0; k<fo->fstype.size(); k++) {
771 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
774 Dmsg1(400, "D %s\n", fo->reader);
777 Dmsg1(400, "T %s\n", fo->writer);
780 for (j=0; j<incexe->name_list.size(); j++) {
781 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
784 for (i=0; i<fileset->exclude_list.size(); i++) {
785 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
787 for (j=0; j<incexe->opts_list.size(); j++) {
788 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
789 for (k=0; k<fo->regex.size(); k++) {
790 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
792 for (k=0; k<fo->regexdir.size(); k++) {
793 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
795 for (k=0; k<fo->regexfile.size(); k++) {
796 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
798 for (k=0; k<fo->wild.size(); k++) {
799 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
801 for (k=0; k<fo->wilddir.size(); k++) {
802 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
804 for (k=0; k<fo->wildfile.size(); k++) {
805 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
807 for (k=0; k<fo->base.size(); k++) {
808 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
810 for (k=0; k<fo->fstype.size(); k++) {
811 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
814 for (j=0; j<incexe->name_list.size(); j++) {
815 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
818 return ff->fileset->state != state_error;
823 * As an optimization, we should do this during
824 * "compile" time in filed/job.c, and keep only a bit mask
825 * and the Verify options.
827 static void set_options(findFOPTS *fo, const char *opts)
832 for (p=opts; *p; p++) {
834 case 'a': /* alway replace */
835 case '0': /* no option */
838 fo->flags |= FO_EXCLUDE;
841 fo->flags |= FO_MULTIFS;
843 case 'h': /* no recursion */
844 fo->flags |= FO_NO_RECURSION;
846 case 'H': /* no hard link handling */
847 fo->flags |= FO_NO_HARDLINK;
850 fo->flags |= FO_IGNORECASE;
856 fo->flags |= FO_NOREPLACE;
858 case 'p': /* use portable data format */
859 fo->flags |= FO_PORTABLE;
861 case 'R': /* Resource forks and Finder Info */
862 fo->flags |= FO_HFSPLUS;
863 case 'r': /* read fifo */
864 fo->flags |= FO_READFIFO;
867 fo->flags |= FO_SHA1;
870 fo->flags |= FO_SPARSE;
873 fo->flags |= FO_MTIMEONLY;
876 fo->flags |= FO_KEEPATIME;
881 case 'V': /* verify options */
882 /* Copy Verify Options */
883 for (j=0; *p && *p != ':'; p++) {
884 fo->VerifyOpts[j] = *p;
885 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
889 fo->VerifyOpts[j] = 0;
892 fo->flags |= FO_IF_NEWER;
894 case 'Z': /* gzip compression */
895 fo->flags |= FO_GZIP;
896 fo->GZIP_level = *++p - '0';
897 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
900 Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p);
908 * Director is passing his Fileset
910 static int fileset_cmd(JCR *jcr)
912 BSOCK *dir = jcr->dir_bsock;
914 if (!init_fileset(jcr)) {
917 while (bnet_recv(dir) >= 0) {
918 strip_trailing_junk(dir->msg);
919 Dmsg1(400, "Fileset: %s\n", dir->msg);
920 add_fileset(jcr, dir->msg);
922 if (!term_fileset(jcr)) {
925 return bnet_fsend(dir, OKinc);
930 * The Director sends us the bootstrap file, which
931 * we will in turn pass to the SD.
933 static int bootstrap_cmd(JCR *jcr)
935 BSOCK *dir = jcr->dir_bsock;
936 POOLMEM *fname = get_pool_memory(PM_FNAME);
939 if (jcr->RestoreBootstrap) {
940 unlink(jcr->RestoreBootstrap);
941 free_pool_memory(jcr->RestoreBootstrap);
943 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
945 Dmsg1(400, "bootstrap=%s\n", fname);
946 jcr->RestoreBootstrap = fname;
947 bs = fopen(fname, "a+"); /* create file */
951 * Suck up what he is sending to us so that he will then
952 * read our error message.
954 while (bnet_recv(dir) >= 0)
957 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
958 jcr->RestoreBootstrap, be.strerror());
959 free_pool_memory(jcr->RestoreBootstrap);
960 jcr->RestoreBootstrap = NULL;
961 set_jcr_job_status(jcr, JS_ErrorTerminated);
965 while (bnet_recv(dir) >= 0) {
966 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
971 return bnet_fsend(dir, OKbootstrap);
976 * Get backup level from Director
979 static int level_cmd(JCR *jcr)
981 BSOCK *dir = jcr->dir_bsock;
982 POOLMEM *level, *buf = NULL;
985 level = get_memory(dir->msglen+1);
986 Dmsg1(110, "level_cmd: %s", dir->msg);
987 if (sscanf(dir->msg, "level = %s ", level) != 1) {
990 /* Base backup requested? */
991 if (strcmp(level, "base") == 0) {
992 jcr->JobLevel = L_BASE;
993 /* Full backup requested? */
994 } else if (strcmp(level, "full") == 0) {
995 jcr->JobLevel = L_FULL;
996 } else if (strcmp(level, "differential") == 0) {
997 jcr->JobLevel = L_DIFFERENTIAL;
1000 } else if (strcmp(level, "incremental") == 0) {
1001 jcr->JobLevel = L_INCREMENTAL;
1005 * We get his UTC since time, then sync the clocks and correct it
1006 * to agree with our clock.
1008 } else if (strcmp(level, "since_utime") == 0) {
1009 buf = get_memory(dir->msglen+1);
1010 utime_t since_time, adj;
1011 btime_t his_time, bt_start, rt=0, bt_adj=0;
1012 if (jcr->JobLevel == L_NONE) {
1013 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1015 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1016 buf, &mtime_only) != 2) {
1019 since_time = str_to_uint64(buf); /* this is the since time */
1020 char ed1[50], ed2[50];
1022 * Sync clocks by polling him for the time. We take
1023 * 10 samples of his time throwing out the first two.
1025 for (int i=0; i<10; i++) {
1026 bt_start = get_current_btime();
1027 bnet_sig(dir, BNET_BTIME); /* poll for time */
1028 if (bnet_recv(dir) <= 0) { /* get response */
1031 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1034 if (i < 2) { /* toss first two results */
1037 his_time = str_to_uint64(buf);
1038 rt = get_current_btime() - bt_start; /* compute round trip time */
1039 bt_adj -= his_time - bt_start - rt/2;
1040 Dmsg2(200, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1043 bt_adj = bt_adj / 8; /* compute average time */
1044 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1045 adj = btime_to_utime(bt_adj);
1046 since_time += adj; /* adjust for clock difference */
1048 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1050 bnet_sig(dir, BNET_EOD);
1052 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1053 jcr->incremental = 1; /* set incremental or decremental backup */
1054 jcr->mtime = (time_t)since_time; /* set since time */
1056 Jmsg1(jcr, M_FATAL, 0, "Unknown backup level: %s\n", level);
1064 return bnet_fsend(dir, OKlevel);
1067 pm_strcpy(jcr->errmsg, dir->msg);
1068 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1077 * Get session parameters from Director -- this is for a Restore command
1079 static int session_cmd(JCR *jcr)
1081 BSOCK *dir = jcr->dir_bsock;
1083 Dmsg1(100, "SessionCmd: %s", dir->msg);
1084 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1085 &jcr->VolSessionId, &jcr->VolSessionTime,
1086 &jcr->StartFile, &jcr->EndFile,
1087 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1088 pm_strcpy(jcr->errmsg, dir->msg);
1089 Jmsg(jcr, M_FATAL, 0, "Bad session command: %s", jcr->errmsg);
1093 return bnet_fsend(dir, OKsession);
1097 * Get address of storage daemon from Director
1100 static int storage_cmd(JCR *jcr)
1102 int stored_port; /* storage daemon port */
1103 int enable_ssl; /* enable ssl to sd */
1104 BSOCK *dir = jcr->dir_bsock;
1105 BSOCK *sd; /* storage daemon bsock */
1107 Dmsg1(100, "StorageCmd: %s", dir->msg);
1108 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1109 pm_strcpy(jcr->errmsg, dir->msg);
1110 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1113 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1114 /* Open command communications with Storage daemon */
1115 /* Try to connect for 1 hour at 10 second intervals */
1116 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1117 jcr->stored_addr, NULL, stored_port, 1);
1119 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1120 jcr->stored_addr, stored_port);
1121 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1122 jcr->stored_addr, stored_port);
1125 Dmsg0(110, "Connection OK to SD.\n");
1127 jcr->store_bsock = sd;
1129 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1130 if (!authenticate_storagedaemon(jcr)) {
1131 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1134 Dmsg0(110, "Authenticated with SD.\n");
1136 /* Send OK to Director */
1137 return bnet_fsend(dir, OKstore);
1142 * Do a backup. For now, we handle only Full and Incremental.
1144 static int backup_cmd(JCR *jcr)
1146 BSOCK *dir = jcr->dir_bsock;
1147 BSOCK *sd = jcr->store_bsock;
1150 char ed1[50], ed2[50];
1152 set_jcr_job_status(jcr, JS_Blocked);
1153 jcr->JobType = JT_BACKUP;
1154 Dmsg1(100, "begin backup ff=%p\n", (FF_PKT *)jcr->ff);
1157 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1161 bnet_fsend(dir, OKbackup);
1162 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1165 * Send Append Open Session to Storage daemon
1167 bnet_fsend(sd, append_open);
1168 Dmsg1(110, ">stored: %s", sd->msg);
1170 * Expect to receive back the Ticket number
1172 if (bget_msg(sd) >= 0) {
1173 Dmsg1(110, "<stored: %s", sd->msg);
1174 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1175 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1178 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1180 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1185 * Send Append data command to Storage daemon
1187 bnet_fsend(sd, append_data, jcr->Ticket);
1188 Dmsg1(110, ">stored: %s", sd->msg);
1191 * Expect to get OK data
1193 Dmsg1(110, "<stored: %s", sd->msg);
1194 if (!response(jcr, sd, OK_data, "Append Data")) {
1198 generate_daemon_event(jcr, "JobStart");
1201 /* START VSS ON WIN 32 */
1203 if (g_pVSSClient->InitializeForBackup()) {
1204 /* tell vss which drives to snapshot */
1205 char szWinDriveLetters[27];
1206 if (get_win32_driveletters((FF_PKT *)jcr->ff, szWinDriveLetters)) {
1207 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=%s, Drive(s)=%s\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1209 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1210 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed\n"));
1213 for (int i=0; i<strlen (szWinDriveLetters); i++) {
1214 if (islower(szWinDriveLetters[i]))
1215 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive %c: failed\n"), szWinDriveLetters[i]);
1220 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled."));
1226 * Send Files to Storage daemon
1228 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1229 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1230 set_jcr_job_status(jcr, JS_ErrorTerminated);
1231 bnet_suppress_error_messages(sd, 1);
1232 bget_msg(sd); /* Read final response from append_data */
1233 Dmsg0(110, "Error in blast_data.\n");
1235 set_jcr_job_status(jcr, JS_Terminated);
1236 if (jcr->JobStatus != JS_Terminated) {
1237 bnet_suppress_error_messages(sd, 1);
1238 goto cleanup; /* bail out now */
1241 * Expect to get response to append_data from Storage daemon
1243 if (!response(jcr, sd, OK_append, "Append Data")) {
1244 set_jcr_job_status(jcr, JS_ErrorTerminated);
1249 * Send Append End Data to Storage daemon
1251 bnet_fsend(sd, append_end, jcr->Ticket);
1253 if (!response(jcr, sd, OK_end, "Append End")) {
1254 set_jcr_job_status(jcr, JS_ErrorTerminated);
1259 * Send Append Close to Storage daemon
1261 bnet_fsend(sd, append_close, jcr->Ticket);
1262 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1263 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1265 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1269 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1272 if (SDJobStatus != JS_Terminated) {
1273 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1280 /* tell vss to close the backup session */
1282 g_pVSSClient->CloseBackup();
1285 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1286 edit_uint64(jcr->ReadBytes, ed1),
1287 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1288 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1290 /* STOP VSS ON WIN 32 */
1291 return 0; /* return and stop command loop */
1295 * Do a Verify for Director
1298 static int verify_cmd(JCR *jcr)
1300 BSOCK *dir = jcr->dir_bsock;
1301 BSOCK *sd = jcr->store_bsock;
1302 char level[100], ed1[50], ed2[50];
1304 jcr->JobType = JT_VERIFY;
1305 if (sscanf(dir->msg, verifycmd, level) != 1) {
1306 bnet_fsend(dir, "2994 Bad verify command: %s\n", dir->msg);
1310 if (strcasecmp(level, "init") == 0) {
1311 jcr->JobLevel = L_VERIFY_INIT;
1312 } else if (strcasecmp(level, "catalog") == 0){
1313 jcr->JobLevel = L_VERIFY_CATALOG;
1314 } else if (strcasecmp(level, "volume") == 0){
1315 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1316 } else if (strcasecmp(level, "data") == 0){
1317 jcr->JobLevel = L_VERIFY_DATA;
1318 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1319 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1321 bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
1325 bnet_fsend(dir, OKverify);
1327 generate_daemon_event(jcr, "JobStart");
1329 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1331 switch (jcr->JobLevel) {
1333 case L_VERIFY_CATALOG:
1336 case L_VERIFY_VOLUME_TO_CATALOG:
1337 if (!open_sd_read_session(jcr)) {
1340 start_dir_heartbeat(jcr);
1341 do_verify_volume(jcr);
1342 stop_dir_heartbeat(jcr);
1344 * Send Close session command to Storage daemon
1346 bnet_fsend(sd, read_close, jcr->Ticket);
1347 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1349 /* ****FIXME**** check response */
1350 bget_msg(sd); /* get OK */
1352 /* Inform Storage daemon that we are done */
1353 bnet_sig(sd, BNET_TERMINATE);
1356 case L_VERIFY_DISK_TO_CATALOG:
1360 bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
1364 bnet_sig(dir, BNET_EOD);
1366 /* Send termination status back to Dir */
1367 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1368 edit_uint64(jcr->ReadBytes, ed1),
1369 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1371 /* Inform Director that we are done */
1372 bnet_sig(dir, BNET_TERMINATE);
1373 return 0; /* return and terminate command loop */
1377 * Do a Restore for Director
1380 static int restore_cmd(JCR *jcr)
1382 BSOCK *dir = jcr->dir_bsock;
1383 BSOCK *sd = jcr->store_bsock;
1387 char ed1[50], ed2[50];
1390 * Scan WHERE (base directory for restore) from command
1392 Dmsg0(150, "restore command\n");
1393 /* Pickup where string */
1394 where = get_memory(dir->msglen+1);
1397 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1398 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1399 pm_strcpy(jcr->errmsg, dir->msg);
1400 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1405 /* Turn / into nothing */
1406 if (where[0] == '/' && where[1] == 0) {
1410 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1411 unbash_spaces(where);
1412 jcr->where = bstrdup(where);
1413 free_pool_memory(where);
1414 jcr->replace = replace;
1415 jcr->prefix_links = prefix_links;
1417 bnet_fsend(dir, OKrestore);
1418 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1420 jcr->JobType = JT_RESTORE;
1422 set_jcr_job_status(jcr, JS_Blocked);
1424 if (!open_sd_read_session(jcr)) {
1425 set_jcr_job_status(jcr, JS_ErrorTerminated);
1429 set_jcr_job_status(jcr, JS_Running);
1432 * Do restore of files and data
1434 start_dir_heartbeat(jcr);
1435 generate_daemon_event(jcr, "JobStart");
1437 stop_dir_heartbeat(jcr);
1439 set_jcr_job_status(jcr, JS_Terminated);
1440 if (jcr->JobStatus != JS_Terminated) {
1441 bnet_suppress_error_messages(sd, 1);
1445 * Send Close session command to Storage daemon
1447 bnet_fsend(sd, read_close, jcr->Ticket);
1448 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1450 bget_msg(sd); /* get OK */
1452 /* Inform Storage daemon that we are done */
1453 bnet_sig(sd, BNET_TERMINATE);
1458 set_jcr_job_status(jcr, JS_ErrorTerminated);
1460 /* Send termination status back to Dir */
1461 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1462 edit_uint64(jcr->ReadBytes, ed1),
1463 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1465 /* Inform Director that we are done */
1466 bnet_sig(dir, BNET_TERMINATE);
1468 Dmsg0(130, "Done in job.c\n");
1469 return 0; /* return and terminate command loop */
1472 static int open_sd_read_session(JCR *jcr)
1474 BSOCK *sd = jcr->store_bsock;
1477 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1480 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1481 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1482 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1484 * Open Read Session with Storage daemon
1486 bnet_fsend(sd, read_open, jcr->VolumeName,
1487 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1488 jcr->StartBlock, jcr->EndBlock);
1489 Dmsg1(110, ">stored: %s", sd->msg);
1494 if (bget_msg(sd) >= 0) {
1495 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1496 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1497 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1500 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1502 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1506 if (!send_bootstrap_file(jcr)) {
1511 * Start read of data with Storage daemon
1513 bnet_fsend(sd, read_data, jcr->Ticket);
1514 Dmsg1(110, ">stored: %s", sd->msg);
1519 if (!response(jcr, sd, OK_data, "Read Data")) {
1526 * Destroy the Job Control Record and associated
1527 * resources (sockets).
1529 static void filed_free_jcr(JCR *jcr)
1531 if (jcr->store_bsock) {
1532 bnet_close(jcr->store_bsock);
1534 if (jcr->RestoreBootstrap) {
1535 unlink(jcr->RestoreBootstrap);
1536 free_pool_memory(jcr->RestoreBootstrap);
1537 jcr->RestoreBootstrap = NULL;
1539 if (jcr->last_fname) {
1540 free_pool_memory(jcr->last_fname);
1542 if (jcr->RunAfterJob) {
1543 free_pool_memory(jcr->RunAfterJob);
1551 * Get response from Storage daemon to a command we
1552 * sent. Check that the response is OK.
1554 * Returns: 0 on failure
1557 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1562 if (bget_msg(sd) > 0) {
1563 Dmsg0(110, sd->msg);
1564 if (strcmp(sd->msg, resp) == 0) {
1568 if (job_canceled(jcr)) {
1569 return 0; /* if canceled avoid useless error messages */
1571 if (is_bnet_error(sd)) {
1572 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1573 cmd, bnet_strerror(sd));
1575 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1576 cmd, resp, sd->msg);
1581 static int send_bootstrap_file(JCR *jcr)
1585 BSOCK *sd = jcr->store_bsock;
1586 const char *bootstrap = "bootstrap\n";
1589 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1590 if (!jcr->RestoreBootstrap) {
1593 bs = fopen(jcr->RestoreBootstrap, "r");
1596 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1597 jcr->RestoreBootstrap, be.strerror());
1598 set_jcr_job_status(jcr, JS_ErrorTerminated);
1601 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1603 while (fgets(buf, sizeof(buf), bs)) {
1604 sd->msglen = Mmsg(sd->msg, "%s", buf);
1607 bnet_sig(sd, BNET_EOD);
1609 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1610 set_jcr_job_status(jcr, JS_ErrorTerminated);
1616 if (jcr->RestoreBootstrap) {
1617 unlink(jcr->RestoreBootstrap);
1618 free_pool_memory(jcr->RestoreBootstrap);
1619 jcr->RestoreBootstrap = NULL;