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 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.
30 extern char my_name[];
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 runbefore_cmd(JCR *jcr);
58 static int runafter_cmd(JCR *jcr);
59 static bool run_cmd(JCR *jcr, char *cmd, const char *name);
60 static void set_options(findFOPTS *fo, const char *opts);
63 /* Exported functions */
68 int monitoraccess; /* specify if monitors have access to this function */
72 * The following are the recognized commands from the Director.
74 static struct s_cmds cmds[] = {
75 {"backup", backup_cmd, 0},
76 {"cancel", cancel_cmd, 0},
77 {"setdebug=", setdebug_cmd, 0},
78 {"estimate", estimate_cmd, 0},
79 {"Hello", hello_cmd, 1},
80 {"fileset", fileset_cmd, 0},
81 {"JobId=", job_cmd, 0},
82 {"level = ", level_cmd, 0},
83 {"restore", restore_cmd, 0},
84 {"session", session_cmd, 0},
85 {"status", status_cmd, 1},
86 {".status", qstatus_cmd, 1},
87 {"storage ", storage_cmd, 0},
88 {"verify", verify_cmd, 0},
89 {"bootstrap", bootstrap_cmd, 0},
90 {"RunBeforeJob", runbefore_cmd, 0},
91 {"RunAfterJob", runafter_cmd, 0},
92 {NULL, NULL} /* list terminator */
95 /* Commands received from director that need scanning */
96 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
97 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
98 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
99 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
100 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
101 static char verifycmd[] = "verify level=%30s\n";
102 static char estimatecmd[] = "estimate listing=%d\n";
103 static char runbefore[] = "RunBeforeJob %s\n";
104 static char runafter[] = "RunAfterJob %s\n";
106 /* Responses sent to Director */
107 static char errmsg[] = "2999 Invalid command\n";
108 static char no_auth[] = "2998 No Authorization\n";
109 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
110 static char OKinc[] = "2000 OK include\n";
111 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
112 static char OKlevel[] = "2000 OK level\n";
113 static char OKbackup[] = "2000 OK backup\n";
114 static char OKbootstrap[] = "2000 OK bootstrap\n";
115 static char OKverify[] = "2000 OK verify\n";
116 static char OKrestore[] = "2000 OK restore\n";
117 static char OKsession[] = "2000 OK session\n";
118 static char OKstore[] = "2000 OK storage\n";
119 static char OKjob[] = "2000 OK Job %s,%s,%s";
120 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
121 static char BADjob[] = "2901 Bad Job\n";
122 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
123 static char OKRunBefore[] = "2000 OK RunBefore\n";
124 static char OKRunAfter[] = "2000 OK RunAfter\n";
126 /* Responses received from Storage Daemon */
127 static char OK_end[] = "3000 OK end\n";
128 static char OK_close[] = "3000 OK close Status = %d\n";
129 static char OK_open[] = "3000 OK open ticket = %d\n";
130 static char OK_data[] = "3000 OK data\n";
131 static char OK_append[] = "3000 OK append data\n";
132 static char OKSDbootstrap[] = "3000 OK bootstrap\n";
135 /* Commands sent to Storage Daemon */
136 static char append_open[] = "append open session\n";
137 static char append_data[] = "append data %d\n";
138 static char append_end[] = "append end session %d\n";
139 static char append_close[] = "append close session %d\n";
140 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
141 static char read_data[] = "read data %d\n";
142 static char read_close[] = "read close session %d\n";
145 * Accept requests from a Director
147 * NOTE! We are running as a separate thread
149 * Send output one line
150 * at a time followed by a zero length transmission.
152 * Return when the connection is terminated or there
155 * Basic task here is:
156 * Authenticate Director (during Hello command).
157 * Accept commands one at a time from the Director
161 void *handle_client_request(void *dirp)
166 BSOCK *dir = (BSOCK *)dirp;
168 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
169 jcr->dir_bsock = dir;
170 jcr->ff = init_find_files();
171 jcr->start_time = time(NULL);
172 jcr->last_fname = get_pool_memory(PM_FNAME);
173 jcr->last_fname[0] = 0;
174 jcr->client_name = get_memory(strlen(my_name) + 1);
175 pm_strcpy(jcr->client_name, my_name);
177 enable_backup_privileges(NULL, 1 /* ignore_errors */);
179 /**********FIXME******* add command handler error code */
181 for (quit=false; !quit;) {
184 if (bnet_recv(dir) < 0) {
185 break; /* connection terminated */
187 dir->msg[dir->msglen] = 0;
188 Dmsg1(100, "<dird: %s", dir->msg);
190 for (i=0; cmds[i].cmd; i++) {
191 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
192 found = true; /* indicate command found */
193 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
194 bnet_fsend(dir, no_auth);
195 bnet_sig(dir, BNET_EOD);
198 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
199 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
200 bnet_fsend(dir, illegal_cmd);
201 bnet_sig(dir, BNET_EOD);
204 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
205 if (!cmds[i].func(jcr)) { /* do command */
206 quit = true; /* error or fully terminated, get out */
207 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
212 if (!found) { /* command not found */
213 bnet_fsend(dir, errmsg);
219 /* Inform Storage daemon that we are done */
220 if (jcr->store_bsock) {
221 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
224 if (jcr->RunAfterJob && !job_canceled(jcr)) {
225 run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob");
227 generate_daemon_event(jcr, "JobEnd");
229 dequeue_messages(jcr); /* send any queued messages */
231 /* Inform Director that we are done */
232 bnet_sig(dir, BNET_TERMINATE);
234 /* Clean up fileset */
235 FF_PKT *ff = jcr->ff;
236 findFILESET *fileset = ff->fileset;
239 /* Delete FileSet Include lists */
240 for (i=0; i<fileset->include_list.size(); i++) {
241 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
242 for (j=0; j<incexe->opts_list.size(); j++) {
243 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
244 for (k=0; k<fo->regex.size(); k++) {
245 regfree((regex_t *)fo->regex.get(k));
248 fo->regexdir.destroy();
249 fo->regexfile.destroy();
251 fo->wilddir.destroy();
252 fo->wildfile.destroy();
254 fo->fstype.destroy();
262 incexe->opts_list.destroy();
263 incexe->name_list.destroy();
265 fileset->include_list.destroy();
267 /* Delete FileSet Exclude lists */
268 for (i=0; i<fileset->exclude_list.size(); i++) {
269 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
270 for (j=0; j<incexe->opts_list.size(); j++) {
271 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
273 fo->regexdir.destroy();
274 fo->regexfile.destroy();
276 fo->wilddir.destroy();
277 fo->wildfile.destroy();
279 fo->fstype.destroy();
281 incexe->opts_list.destroy();
282 incexe->name_list.destroy();
284 fileset->exclude_list.destroy();
288 Dmsg0(100, "Calling term_find_files\n");
289 term_find_files(jcr->ff);
291 Dmsg0(100, "Done with term_find_files\n");
292 free_jcr(jcr); /* destroy JCR record */
293 Dmsg0(100, "Done with free_jcr\n");
298 * Hello from Director he must identify himself and provide his
301 static int hello_cmd(JCR *jcr)
303 Dmsg0(120, "Calling Authenticate\n");
304 if (!authenticate_director(jcr)) {
307 Dmsg0(120, "OK Authenticate\n");
308 jcr->authenticated = true;
315 static int cancel_cmd(JCR *jcr)
317 BSOCK *dir = jcr->dir_bsock;
318 char Job[MAX_NAME_LENGTH];
321 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
322 if (!(cjcr=get_jcr_by_full_name(Job))) {
323 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
325 if (cjcr->store_bsock) {
327 cjcr->store_bsock->timed_out = 1;
328 cjcr->store_bsock->terminated = 1;
330 * #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
332 #if !defined(HAVE_CYGWIN)
333 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
337 set_jcr_job_status(cjcr, JS_Canceled);
339 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
342 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
344 bnet_sig(dir, BNET_EOD);
350 * Set debug level as requested by the Director
353 static int setdebug_cmd(JCR *jcr)
355 BSOCK *dir = jcr->dir_bsock;
356 int level, trace_flag;
358 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
359 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
360 pm_strcpy(jcr->errmsg, dir->msg);
361 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
365 set_trace(trace_flag);
366 return bnet_fsend(dir, OKsetdebug, level);
370 static int estimate_cmd(JCR *jcr)
372 BSOCK *dir = jcr->dir_bsock;
375 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
376 pm_strcpy(jcr->errmsg, dir->msg);
377 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
378 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
382 bnet_fsend(dir, OKest, jcr->num_files_examined,
383 edit_uint64_with_commas(jcr->JobBytes, ed2));
384 bnet_sig(dir, BNET_EOD);
389 * Get JobId and Storage Daemon Authorization key from Director
391 static int job_cmd(JCR *jcr)
393 BSOCK *dir = jcr->dir_bsock;
394 POOLMEM *sd_auth_key;
396 sd_auth_key = get_memory(dir->msglen);
397 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
398 &jcr->VolSessionId, &jcr->VolSessionTime,
400 pm_strcpy(jcr->errmsg, dir->msg);
401 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
402 bnet_fsend(dir, BADjob);
403 free_pool_memory(sd_auth_key);
406 jcr->sd_auth_key = bstrdup(sd_auth_key);
407 free_pool_memory(sd_auth_key);
408 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
409 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
412 static int runbefore_cmd(JCR *jcr)
415 BSOCK *dir = jcr->dir_bsock;
416 POOLMEM *cmd = get_memory(dir->msglen+1);
418 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
419 if (sscanf(dir->msg, runbefore, cmd) != 1) {
420 pm_strcpy(jcr->errmsg, dir->msg);
421 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
422 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
428 /* Run the command now */
429 ok = run_cmd(jcr, cmd, "ClientRunBeforeJob");
432 bnet_fsend(dir, OKRunBefore);
435 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
440 static int runafter_cmd(JCR *jcr)
442 BSOCK *dir = jcr->dir_bsock;
443 POOLMEM *msg = get_memory(dir->msglen+1);
445 Dmsg1(100, "runafter_cmd: %s", dir->msg);
446 if (sscanf(dir->msg, runafter, msg) != 1) {
447 pm_strcpy(jcr->errmsg, dir->msg);
448 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
449 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
454 if (jcr->RunAfterJob) {
455 free_pool_memory(jcr->RunAfterJob);
457 jcr->RunAfterJob = get_pool_memory(PM_FNAME);
458 pm_strcpy(jcr->RunAfterJob, msg);
459 free_pool_memory(msg);
460 return bnet_fsend(dir, OKRunAfter);
463 static bool run_cmd(JCR *jcr, char *cmd, const char *name)
465 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
468 char line[MAXSTRING];
470 ecmd = edit_job_codes(jcr, ecmd, cmd, "");
471 bpipe = open_bpipe(ecmd, 0, "r");
472 free_pool_memory(ecmd);
475 Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name,
479 while (fgets(line, sizeof(line), bpipe->rfd)) {
480 int len = strlen(line);
481 if (len > 0 && line[len-1] == '\n') {
484 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
486 status = close_bpipe(bpipe);
489 Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
490 status, be.strerror(status));
496 static bool init_fileset(JCR *jcr)
499 findFILESET *fileset;
508 fileset = (findFILESET *)malloc(sizeof(findFILESET));
509 memset(fileset, 0, sizeof(findFILESET));
510 ff->fileset = fileset;
511 fileset->state = state_none;
512 fileset->include_list.init(1, true);
513 fileset->exclude_list.init(1, true);
517 static findFOPTS *start_options(FF_PKT *ff)
519 int state = ff->fileset->state;
520 findINCEXE *incexe = ff->fileset->incexe;
522 if (state != state_options) {
523 ff->fileset->state = state_options;
524 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
525 memset(fo, 0, sizeof(findFOPTS));
526 fo->regex.init(1, true);
527 fo->regexdir.init(1, true);
528 fo->regexfile.init(1, true);
529 fo->wild.init(1, true);
530 fo->wilddir.init(1, true);
531 fo->wildfile.init(1, true);
532 fo->base.init(1, true);
533 fo->fstype.init(1, true);
534 incexe->current_opts = fo;
535 incexe->opts_list.append(fo);
537 return incexe->current_opts;
542 * Add fname to include/exclude fileset list. First check for
543 * | and < and if necessary perform command.
545 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
559 p++; /* skip over | */
560 fn = get_pool_memory(PM_FNAME);
561 fn = edit_job_codes(jcr, fn, p, "");
562 bpipe = open_bpipe(fn, 0, "r");
563 free_pool_memory(fn);
565 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
569 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
570 strip_trailing_junk(buf);
571 fileset->incexe->name_list.append(bstrdup(buf));
573 if ((stat=close_bpipe(bpipe)) != 0) {
574 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
575 p, stat, strerror(errno));
580 Dmsg0(100, "Doing < include on client.\n");
581 p++; /* skip over < */
582 if ((ffd = fopen(p, "r")) == NULL) {
584 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
588 while (fgets(buf, sizeof(buf), ffd)) {
589 strip_trailing_junk(buf);
590 Dmsg1(100, "%s\n", buf);
591 fileset->incexe->name_list.append(bstrdup(buf));
596 fileset->incexe->name_list.append(bstrdup(fname));
602 static void add_fileset(JCR *jcr, const char *item)
604 FF_PKT *ff = jcr->ff;
605 findFILESET *fileset = ff->fileset;
606 int state = fileset->state;
607 findFOPTS *current_opts;
609 /* Get code, optional subcode, and position item past the dividing space */
610 Dmsg1(100, "%s\n", item);
615 int subcode = ' '; /* A space is always a valid subcode */
616 if (item[0] != '\0' && item[0] != ' ') {
624 /* Skip all lines we receive after an error */
625 if (state == state_error) {
630 * The switch tests the code for validity.
631 * The subcode is always good if it is a space, otherwise we must confirm.
632 * We set state to state_error first assuming the subcode is invalid,
633 * requiring state to be set in cases below that handle subcodes.
635 if (subcode != ' ') {
641 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
642 memset(fileset->incexe, 0, sizeof(findINCEXE));
643 fileset->incexe->opts_list.init(1, true);
644 fileset->incexe->name_list.init(1, true);
645 fileset->include_list.append(fileset->incexe);
649 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
650 memset(fileset->incexe, 0, sizeof(findINCEXE));
651 fileset->incexe->opts_list.init(1, true);
652 fileset->incexe->name_list.init(1, true);
653 fileset->exclude_list.append(fileset->incexe);
659 /* File item to either include/include list */
660 state = state_include;
661 add_file_to_fileset(jcr, item, fileset);
664 current_opts = start_options(ff);
668 preg = (regex_t *)malloc(sizeof(regex_t));
669 if (current_opts->flags & FO_IGNORECASE) {
670 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
672 rc = regcomp(preg, item, REG_EXTENDED);
675 regerror(rc, preg, prbuf, sizeof(prbuf));
678 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
682 state = state_options;
683 if (subcode == ' ') {
684 current_opts->regex.append(preg);
685 } else if (subcode == 'D') {
686 current_opts->regexdir.append(preg);
687 } else if (subcode == 'F') {
688 current_opts->regexfile.append(preg);
694 current_opts = start_options(ff);
695 current_opts->base.append(bstrdup(item));
696 state = state_options;
699 current_opts = start_options(ff);
700 current_opts->fstype.append(bstrdup(item));
701 state = state_options;
704 current_opts = start_options(ff);
705 state = state_options;
706 if (subcode == ' ') {
707 current_opts->wild.append(bstrdup(item));
708 } else if (subcode == 'D') {
709 current_opts->wilddir.append(bstrdup(item));
710 } else if (subcode == 'F') {
711 current_opts->wildfile.append(bstrdup(item));
717 current_opts = start_options(ff);
718 set_options(current_opts, item);
719 state = state_options;
722 current_opts = start_options(ff);
723 current_opts->reader = bstrdup(item);
724 state = state_options;
727 current_opts = start_options(ff);
728 current_opts->writer = bstrdup(item);
729 state = state_options;
732 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
736 ff->fileset->state = state;
739 static bool term_fileset(JCR *jcr)
741 FF_PKT *ff = jcr->ff;
742 findFILESET *fileset = ff->fileset;
745 for (i=0; i<fileset->include_list.size(); i++) {
746 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
748 for (j=0; j<incexe->opts_list.size(); j++) {
749 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
750 for (k=0; k<fo->regex.size(); k++) {
751 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
753 for (k=0; k<fo->regexdir.size(); k++) {
754 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
756 for (k=0; k<fo->regexfile.size(); k++) {
757 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
759 for (k=0; k<fo->wild.size(); k++) {
760 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
762 for (k=0; k<fo->wilddir.size(); k++) {
763 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
765 for (k=0; k<fo->wildfile.size(); k++) {
766 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
768 for (k=0; k<fo->base.size(); k++) {
769 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
771 for (k=0; k<fo->fstype.size(); k++) {
772 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
775 Dmsg1(400, "D %s\n", fo->reader);
778 Dmsg1(400, "T %s\n", fo->writer);
781 for (j=0; j<incexe->name_list.size(); j++) {
782 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
785 for (i=0; i<fileset->exclude_list.size(); i++) {
786 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
788 for (j=0; j<incexe->opts_list.size(); j++) {
789 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
790 for (k=0; k<fo->regex.size(); k++) {
791 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
793 for (k=0; k<fo->regexdir.size(); k++) {
794 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
796 for (k=0; k<fo->regexfile.size(); k++) {
797 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
799 for (k=0; k<fo->wild.size(); k++) {
800 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
802 for (k=0; k<fo->wilddir.size(); k++) {
803 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
805 for (k=0; k<fo->wildfile.size(); k++) {
806 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
808 for (k=0; k<fo->base.size(); k++) {
809 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
811 for (k=0; k<fo->fstype.size(); k++) {
812 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
815 for (j=0; j<incexe->name_list.size(); j++) {
816 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
819 return ff->fileset->state != state_error;
824 * As an optimization, we should do this during
825 * "compile" time in filed/job.c, and keep only a bit mask
826 * and the Verify options.
828 static void set_options(findFOPTS *fo, const char *opts)
833 for (p=opts; *p; p++) {
835 case 'a': /* alway replace */
836 case '0': /* no option */
839 fo->flags |= FO_EXCLUDE;
842 fo->flags |= FO_MULTIFS;
844 case 'h': /* no recursion */
845 fo->flags |= FO_NO_RECURSION;
847 case 'H': /* no hard link handling */
848 fo->flags |= FO_NO_HARDLINK;
851 fo->flags |= FO_IGNORECASE;
857 fo->flags |= FO_NOREPLACE;
859 case 'p': /* use portable data format */
860 fo->flags |= FO_PORTABLE;
862 case 'R': /* Resource forks and Finder Info */
863 fo->flags |= FO_HFSPLUS;
864 case 'r': /* read fifo */
865 fo->flags |= FO_READFIFO;
868 fo->flags |= FO_SHA1;
871 fo->flags |= FO_SPARSE;
874 fo->flags |= FO_MTIMEONLY;
877 fo->flags |= FO_KEEPATIME;
882 case 'V': /* verify options */
883 /* Copy Verify Options */
884 for (j=0; *p && *p != ':'; p++) {
885 fo->VerifyOpts[j] = *p;
886 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
890 fo->VerifyOpts[j] = 0;
893 fo->flags |= FO_IF_NEWER;
895 case 'Z': /* gzip compression */
896 fo->flags |= FO_GZIP;
897 fo->GZIP_level = *++p - '0';
898 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
901 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
909 * Director is passing his Fileset
911 static int fileset_cmd(JCR *jcr)
913 BSOCK *dir = jcr->dir_bsock;
916 sscanf(dir->msg, "fileset vss=%d", &vss);
919 if (!init_fileset(jcr)) {
922 while (bnet_recv(dir) >= 0) {
923 strip_trailing_junk(dir->msg);
924 Dmsg1(400, "Fileset: %s\n", dir->msg);
925 add_fileset(jcr, dir->msg);
927 if (!term_fileset(jcr)) {
930 return bnet_fsend(dir, OKinc);
933 static void free_bootstrap(JCR *jcr)
935 if (jcr->RestoreBootstrap) {
936 unlink(jcr->RestoreBootstrap);
937 free_pool_memory(jcr->RestoreBootstrap);
938 jcr->RestoreBootstrap = NULL;
944 * The Director sends us the bootstrap file, which
945 * we will in turn pass to the SD.
947 static int bootstrap_cmd(JCR *jcr)
949 BSOCK *dir = jcr->dir_bsock;
950 POOLMEM *fname = get_pool_memory(PM_FNAME);
954 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
956 Dmsg1(400, "bootstrap=%s\n", fname);
957 jcr->RestoreBootstrap = fname;
958 bs = fopen(fname, "a+"); /* create file */
961 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
962 jcr->RestoreBootstrap, be.strerror());
964 * Suck up what he is sending to us so that he will then
965 * read our error message.
967 while (bnet_recv(dir) >= 0)
970 set_jcr_job_status(jcr, JS_ErrorTerminated);
974 while (bnet_recv(dir) >= 0) {
975 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
980 * Note, do not free the bootstrap yet -- it needs to be
983 return bnet_fsend(dir, OKbootstrap);
988 * Get backup level from Director
991 static int level_cmd(JCR *jcr)
993 BSOCK *dir = jcr->dir_bsock;
994 POOLMEM *level, *buf = NULL;
997 level = get_memory(dir->msglen+1);
998 Dmsg1(110, "level_cmd: %s", dir->msg);
999 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1002 /* Base backup requested? */
1003 if (strcmp(level, "base") == 0) {
1004 jcr->JobLevel = L_BASE;
1005 /* Full backup requested? */
1006 } else if (strcmp(level, "full") == 0) {
1007 jcr->JobLevel = L_FULL;
1008 } else if (strcmp(level, "differential") == 0) {
1009 jcr->JobLevel = L_DIFFERENTIAL;
1012 } else if (strcmp(level, "incremental") == 0) {
1013 jcr->JobLevel = L_INCREMENTAL;
1017 * We get his UTC since time, then sync the clocks and correct it
1018 * to agree with our clock.
1020 } else if (strcmp(level, "since_utime") == 0) {
1021 buf = get_memory(dir->msglen+1);
1022 utime_t since_time, adj;
1023 btime_t his_time, bt_start, rt=0, bt_adj=0;
1024 if (jcr->JobLevel == L_NONE) {
1025 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1027 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1028 buf, &mtime_only) != 2) {
1031 since_time = str_to_uint64(buf); /* this is the since time */
1032 char ed1[50], ed2[50];
1034 * Sync clocks by polling him for the time. We take
1035 * 10 samples of his time throwing out the first two.
1037 for (int i=0; i<10; i++) {
1038 bt_start = get_current_btime();
1039 bnet_sig(dir, BNET_BTIME); /* poll for time */
1040 if (bnet_recv(dir) <= 0) { /* get response */
1043 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1046 if (i < 2) { /* toss first two results */
1049 his_time = str_to_uint64(buf);
1050 rt = get_current_btime() - bt_start; /* compute round trip time */
1051 bt_adj -= his_time - bt_start - rt/2;
1052 Dmsg2(200, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1055 bt_adj = bt_adj / 8; /* compute average time */
1056 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1057 adj = btime_to_utime(bt_adj);
1058 since_time += adj; /* adjust for clock difference */
1060 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1062 bnet_sig(dir, BNET_EOD);
1064 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1065 jcr->incremental = 1; /* set incremental or decremental backup */
1066 jcr->mtime = (time_t)since_time; /* set since time */
1068 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1076 return bnet_fsend(dir, OKlevel);
1079 pm_strcpy(jcr->errmsg, dir->msg);
1080 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1089 * Get session parameters from Director -- this is for a Restore command
1091 static int session_cmd(JCR *jcr)
1093 BSOCK *dir = jcr->dir_bsock;
1095 Dmsg1(100, "SessionCmd: %s", dir->msg);
1096 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1097 &jcr->VolSessionId, &jcr->VolSessionTime,
1098 &jcr->StartFile, &jcr->EndFile,
1099 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1100 pm_strcpy(jcr->errmsg, dir->msg);
1101 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1105 return bnet_fsend(dir, OKsession);
1109 * Get address of storage daemon from Director
1112 static int storage_cmd(JCR *jcr)
1114 int stored_port; /* storage daemon port */
1115 int enable_ssl; /* enable ssl to sd */
1116 BSOCK *dir = jcr->dir_bsock;
1117 BSOCK *sd; /* storage daemon bsock */
1119 Dmsg1(100, "StorageCmd: %s", dir->msg);
1120 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1121 pm_strcpy(jcr->errmsg, dir->msg);
1122 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1125 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1126 /* Open command communications with Storage daemon */
1127 /* Try to connect for 1 hour at 10 second intervals */
1128 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1129 jcr->stored_addr, NULL, stored_port, 1);
1131 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1132 jcr->stored_addr, stored_port);
1133 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1134 jcr->stored_addr, stored_port);
1137 Dmsg0(110, "Connection OK to SD.\n");
1139 jcr->store_bsock = sd;
1141 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1142 if (!authenticate_storagedaemon(jcr)) {
1143 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1146 Dmsg0(110, "Authenticated with SD.\n");
1148 /* Send OK to Director */
1149 return bnet_fsend(dir, OKstore);
1154 * Do a backup. For now, we handle only Full and Incremental.
1156 static int backup_cmd(JCR *jcr)
1158 BSOCK *dir = jcr->dir_bsock;
1159 BSOCK *sd = jcr->store_bsock;
1162 char ed1[50], ed2[50];
1164 set_jcr_job_status(jcr, JS_Blocked);
1165 jcr->JobType = JT_BACKUP;
1166 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1169 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1173 bnet_fsend(dir, OKbackup);
1174 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1177 * Send Append Open Session to Storage daemon
1179 bnet_fsend(sd, append_open);
1180 Dmsg1(110, ">stored: %s", sd->msg);
1182 * Expect to receive back the Ticket number
1184 if (bget_msg(sd) >= 0) {
1185 Dmsg1(110, "<stored: %s", sd->msg);
1186 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1187 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1190 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1192 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1197 * Send Append data command to Storage daemon
1199 bnet_fsend(sd, append_data, jcr->Ticket);
1200 Dmsg1(110, ">stored: %s", sd->msg);
1203 * Expect to get OK data
1205 Dmsg1(110, "<stored: %s", sd->msg);
1206 if (!response(jcr, sd, OK_data, "Append Data")) {
1210 generate_daemon_event(jcr, "JobStart");
1213 /* START VSS ON WIN 32 */
1214 if (g_pVSSClient && enable_vss) {
1215 if (g_pVSSClient->InitializeForBackup()) {
1216 /* tell vss which drives to snapshot */
1217 char szWinDriveLetters[27];
1218 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1219 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1220 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1222 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed. ERR=%s\n"),
1225 /* tell user if snapshot creation of a specific drive failed */
1227 for (i=0; i<strlen (szWinDriveLetters); i++) {
1228 if (islower(szWinDriveLetters[i])) {
1229 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed\n"), szWinDriveLetters[i]);
1232 /* inform user about writer states */
1233 for (i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1234 int msg_type = M_INFO;
1235 if (g_pVSSClient->GetWriterState(i) < 0) {
1236 msg_type = M_WARNING;
1238 Jmsg(jcr, msg_type, 0, _("VSS Writer: %s\n"), g_pVSSClient->GetWriterInfo(i));
1242 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1245 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled.\n"));
1251 * Send Files to Storage daemon
1253 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1254 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1255 set_jcr_job_status(jcr, JS_ErrorTerminated);
1256 bnet_suppress_error_messages(sd, 1);
1257 bget_msg(sd); /* Read final response from append_data */
1258 Dmsg0(110, "Error in blast_data.\n");
1260 set_jcr_job_status(jcr, JS_Terminated);
1261 if (jcr->JobStatus != JS_Terminated) {
1262 bnet_suppress_error_messages(sd, 1);
1263 goto cleanup; /* bail out now */
1266 * Expect to get response to append_data from Storage daemon
1268 if (!response(jcr, sd, OK_append, "Append Data")) {
1269 set_jcr_job_status(jcr, JS_ErrorTerminated);
1274 * Send Append End Data to Storage daemon
1276 bnet_fsend(sd, append_end, jcr->Ticket);
1278 if (!response(jcr, sd, OK_end, "Append End")) {
1279 set_jcr_job_status(jcr, JS_ErrorTerminated);
1284 * Send Append Close to Storage daemon
1286 bnet_fsend(sd, append_close, jcr->Ticket);
1287 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1288 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1290 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1294 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1297 if (SDJobStatus != JS_Terminated) {
1298 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1305 /* STOP VSS ON WIN 32 */
1306 /* tell vss to close the backup session */
1307 if (g_pVSSClient && enable_vss == 1)
1308 g_pVSSClient->CloseBackup();
1311 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1312 edit_uint64(jcr->ReadBytes, ed1),
1313 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1314 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1316 return 0; /* return and stop command loop */
1320 * Do a Verify for Director
1323 static int verify_cmd(JCR *jcr)
1325 BSOCK *dir = jcr->dir_bsock;
1326 BSOCK *sd = jcr->store_bsock;
1327 char level[100], ed1[50], ed2[50];
1329 jcr->JobType = JT_VERIFY;
1330 if (sscanf(dir->msg, verifycmd, level) != 1) {
1331 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1335 if (strcasecmp(level, "init") == 0) {
1336 jcr->JobLevel = L_VERIFY_INIT;
1337 } else if (strcasecmp(level, "catalog") == 0){
1338 jcr->JobLevel = L_VERIFY_CATALOG;
1339 } else if (strcasecmp(level, "volume") == 0){
1340 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1341 } else if (strcasecmp(level, "data") == 0){
1342 jcr->JobLevel = L_VERIFY_DATA;
1343 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1344 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1346 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1350 bnet_fsend(dir, OKverify);
1352 generate_daemon_event(jcr, "JobStart");
1354 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1356 switch (jcr->JobLevel) {
1358 case L_VERIFY_CATALOG:
1361 case L_VERIFY_VOLUME_TO_CATALOG:
1362 if (!open_sd_read_session(jcr)) {
1365 start_dir_heartbeat(jcr);
1366 do_verify_volume(jcr);
1367 stop_dir_heartbeat(jcr);
1369 * Send Close session command to Storage daemon
1371 bnet_fsend(sd, read_close, jcr->Ticket);
1372 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1374 /* ****FIXME**** check response */
1375 bget_msg(sd); /* get OK */
1377 /* Inform Storage daemon that we are done */
1378 bnet_sig(sd, BNET_TERMINATE);
1381 case L_VERIFY_DISK_TO_CATALOG:
1385 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1389 bnet_sig(dir, BNET_EOD);
1391 /* Send termination status back to Dir */
1392 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1393 edit_uint64(jcr->ReadBytes, ed1),
1394 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1396 /* Inform Director that we are done */
1397 bnet_sig(dir, BNET_TERMINATE);
1398 return 0; /* return and terminate command loop */
1402 * Do a Restore for Director
1405 static int restore_cmd(JCR *jcr)
1407 BSOCK *dir = jcr->dir_bsock;
1408 BSOCK *sd = jcr->store_bsock;
1412 char ed1[50], ed2[50];
1415 * Scan WHERE (base directory for restore) from command
1417 Dmsg0(150, "restore command\n");
1418 /* Pickup where string */
1419 where = get_memory(dir->msglen+1);
1422 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1423 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1424 pm_strcpy(jcr->errmsg, dir->msg);
1425 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1430 /* Turn / into nothing */
1431 if (where[0] == '/' && where[1] == 0) {
1435 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1436 unbash_spaces(where);
1437 jcr->where = bstrdup(where);
1438 free_pool_memory(where);
1439 jcr->replace = replace;
1440 jcr->prefix_links = prefix_links;
1442 bnet_fsend(dir, OKrestore);
1443 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1445 jcr->JobType = JT_RESTORE;
1447 set_jcr_job_status(jcr, JS_Blocked);
1449 if (!open_sd_read_session(jcr)) {
1450 set_jcr_job_status(jcr, JS_ErrorTerminated);
1454 set_jcr_job_status(jcr, JS_Running);
1457 * Do restore of files and data
1459 start_dir_heartbeat(jcr);
1460 generate_daemon_event(jcr, "JobStart");
1462 stop_dir_heartbeat(jcr);
1464 set_jcr_job_status(jcr, JS_Terminated);
1465 if (jcr->JobStatus != JS_Terminated) {
1466 bnet_suppress_error_messages(sd, 1);
1470 * Send Close session command to Storage daemon
1472 bnet_fsend(sd, read_close, jcr->Ticket);
1473 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1475 bget_msg(sd); /* get OK */
1477 /* Inform Storage daemon that we are done */
1478 bnet_sig(sd, BNET_TERMINATE);
1483 set_jcr_job_status(jcr, JS_ErrorTerminated);
1485 /* Send termination status back to Dir */
1486 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1487 edit_uint64(jcr->ReadBytes, ed1),
1488 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1490 /* Inform Director that we are done */
1491 bnet_sig(dir, BNET_TERMINATE);
1493 Dmsg0(130, "Done in job.c\n");
1494 return 0; /* return and terminate command loop */
1497 static int open_sd_read_session(JCR *jcr)
1499 BSOCK *sd = jcr->store_bsock;
1502 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1505 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1506 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1507 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1509 * Open Read Session with Storage daemon
1511 bnet_fsend(sd, read_open, jcr->VolumeName,
1512 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1513 jcr->StartBlock, jcr->EndBlock);
1514 Dmsg1(110, ">stored: %s", sd->msg);
1519 if (bget_msg(sd) >= 0) {
1520 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1521 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1522 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1525 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1527 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1531 if (!send_bootstrap_file(jcr)) {
1536 * Start read of data with Storage daemon
1538 bnet_fsend(sd, read_data, jcr->Ticket);
1539 Dmsg1(110, ">stored: %s", sd->msg);
1544 if (!response(jcr, sd, OK_data, "Read Data")) {
1551 * Destroy the Job Control Record and associated
1552 * resources (sockets).
1554 static void filed_free_jcr(JCR *jcr)
1556 if (jcr->store_bsock) {
1557 bnet_close(jcr->store_bsock);
1559 free_bootstrap(jcr);
1560 if (jcr->last_fname) {
1561 free_pool_memory(jcr->last_fname);
1563 if (jcr->RunAfterJob) {
1564 free_pool_memory(jcr->RunAfterJob);
1572 * Get response from Storage daemon to a command we
1573 * sent. Check that the response is OK.
1575 * Returns: 0 on failure
1578 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1583 if (bget_msg(sd) > 0) {
1584 Dmsg0(110, sd->msg);
1585 if (strcmp(sd->msg, resp) == 0) {
1589 if (job_canceled(jcr)) {
1590 return 0; /* if canceled avoid useless error messages */
1592 if (is_bnet_error(sd)) {
1593 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1594 cmd, bnet_strerror(sd));
1596 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1597 cmd, resp, sd->msg);
1602 static int send_bootstrap_file(JCR *jcr)
1606 BSOCK *sd = jcr->store_bsock;
1607 const char *bootstrap = "bootstrap\n";
1610 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1611 if (!jcr->RestoreBootstrap) {
1614 bs = fopen(jcr->RestoreBootstrap, "r");
1617 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1618 jcr->RestoreBootstrap, be.strerror());
1619 set_jcr_job_status(jcr, JS_ErrorTerminated);
1622 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1624 while (fgets(buf, sizeof(buf), bs)) {
1625 sd->msglen = Mmsg(sd->msg, "%s", buf);
1628 bnet_sig(sd, BNET_EOD);
1630 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1631 set_jcr_job_status(jcr, JS_ErrorTerminated);
1637 free_bootstrap(jcr);