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);
176 jcr->pki_sign = me->pki_sign;
177 jcr->pki_encrypt = me->pki_encrypt;
178 jcr->pki_keypair = me->pki_keypair;
179 jcr->pki_signers = me->pki_signers;
181 enable_backup_privileges(NULL, 1 /* ignore_errors */);
183 /**********FIXME******* add command handler error code */
185 for (quit=false; !quit;) {
188 if (bnet_recv(dir) < 0) {
189 break; /* connection terminated */
191 dir->msg[dir->msglen] = 0;
192 Dmsg1(100, "<dird: %s", dir->msg);
194 for (i=0; cmds[i].cmd; i++) {
195 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
196 found = true; /* indicate command found */
197 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
198 bnet_fsend(dir, no_auth);
199 bnet_sig(dir, BNET_EOD);
202 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
203 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
204 bnet_fsend(dir, illegal_cmd);
205 bnet_sig(dir, BNET_EOD);
208 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
209 if (!cmds[i].func(jcr)) { /* do command */
210 quit = true; /* error or fully terminated, get out */
211 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
216 if (!found) { /* command not found */
217 bnet_fsend(dir, errmsg);
223 /* Inform Storage daemon that we are done */
224 if (jcr->store_bsock) {
225 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
228 if (jcr->RunAfterJob && !job_canceled(jcr)) {
229 run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob");
231 generate_daemon_event(jcr, "JobEnd");
233 dequeue_messages(jcr); /* send any queued messages */
235 /* Inform Director that we are done */
236 bnet_sig(dir, BNET_TERMINATE);
238 /* Clean up fileset */
239 FF_PKT *ff = jcr->ff;
240 findFILESET *fileset = ff->fileset;
243 /* Delete FileSet Include lists */
244 for (i=0; i<fileset->include_list.size(); i++) {
245 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
246 for (j=0; j<incexe->opts_list.size(); j++) {
247 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
248 for (k=0; k<fo->regex.size(); k++) {
249 regfree((regex_t *)fo->regex.get(k));
252 fo->regexdir.destroy();
253 fo->regexfile.destroy();
255 fo->wilddir.destroy();
256 fo->wildfile.destroy();
258 fo->fstype.destroy();
266 incexe->opts_list.destroy();
267 incexe->name_list.destroy();
269 fileset->include_list.destroy();
271 /* Delete FileSet Exclude lists */
272 for (i=0; i<fileset->exclude_list.size(); i++) {
273 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
274 for (j=0; j<incexe->opts_list.size(); j++) {
275 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
277 fo->regexdir.destroy();
278 fo->regexfile.destroy();
280 fo->wilddir.destroy();
281 fo->wildfile.destroy();
283 fo->fstype.destroy();
285 incexe->opts_list.destroy();
286 incexe->name_list.destroy();
288 fileset->exclude_list.destroy();
292 Dmsg0(100, "Calling term_find_files\n");
293 term_find_files(jcr->ff);
295 Dmsg0(100, "Done with term_find_files\n");
296 free_jcr(jcr); /* destroy JCR record */
297 Dmsg0(100, "Done with free_jcr\n");
302 * Hello from Director he must identify himself and provide his
305 static int hello_cmd(JCR *jcr)
307 Dmsg0(120, "Calling Authenticate\n");
308 if (!authenticate_director(jcr)) {
311 Dmsg0(120, "OK Authenticate\n");
312 jcr->authenticated = true;
319 static int cancel_cmd(JCR *jcr)
321 BSOCK *dir = jcr->dir_bsock;
322 char Job[MAX_NAME_LENGTH];
325 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
326 if (!(cjcr=get_jcr_by_full_name(Job))) {
327 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
329 if (cjcr->store_bsock) {
331 cjcr->store_bsock->timed_out = 1;
332 cjcr->store_bsock->terminated = 1;
334 * #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
336 #if !defined(HAVE_CYGWIN)
337 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
341 set_jcr_job_status(cjcr, JS_Canceled);
343 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
346 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
348 bnet_sig(dir, BNET_EOD);
354 * Set debug level as requested by the Director
357 static int setdebug_cmd(JCR *jcr)
359 BSOCK *dir = jcr->dir_bsock;
360 int level, trace_flag;
362 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
363 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
364 pm_strcpy(jcr->errmsg, dir->msg);
365 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
369 set_trace(trace_flag);
370 return bnet_fsend(dir, OKsetdebug, level);
374 static int estimate_cmd(JCR *jcr)
376 BSOCK *dir = jcr->dir_bsock;
379 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
380 pm_strcpy(jcr->errmsg, dir->msg);
381 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
382 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
386 bnet_fsend(dir, OKest, jcr->num_files_examined,
387 edit_uint64_with_commas(jcr->JobBytes, ed2));
388 bnet_sig(dir, BNET_EOD);
393 * Get JobId and Storage Daemon Authorization key from Director
395 static int job_cmd(JCR *jcr)
397 BSOCK *dir = jcr->dir_bsock;
398 POOLMEM *sd_auth_key;
400 sd_auth_key = get_memory(dir->msglen);
401 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
402 &jcr->VolSessionId, &jcr->VolSessionTime,
404 pm_strcpy(jcr->errmsg, dir->msg);
405 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
406 bnet_fsend(dir, BADjob);
407 free_pool_memory(sd_auth_key);
410 jcr->sd_auth_key = bstrdup(sd_auth_key);
411 free_pool_memory(sd_auth_key);
412 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
413 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
416 static int runbefore_cmd(JCR *jcr)
419 BSOCK *dir = jcr->dir_bsock;
420 POOLMEM *cmd = get_memory(dir->msglen+1);
422 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
423 if (sscanf(dir->msg, runbefore, cmd) != 1) {
424 pm_strcpy(jcr->errmsg, dir->msg);
425 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
426 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
432 /* Run the command now */
433 ok = run_cmd(jcr, cmd, "ClientRunBeforeJob");
436 bnet_fsend(dir, OKRunBefore);
439 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
444 static int runafter_cmd(JCR *jcr)
446 BSOCK *dir = jcr->dir_bsock;
447 POOLMEM *msg = get_memory(dir->msglen+1);
449 Dmsg1(100, "runafter_cmd: %s", dir->msg);
450 if (sscanf(dir->msg, runafter, msg) != 1) {
451 pm_strcpy(jcr->errmsg, dir->msg);
452 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
453 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
458 if (jcr->RunAfterJob) {
459 free_pool_memory(jcr->RunAfterJob);
461 jcr->RunAfterJob = get_pool_memory(PM_FNAME);
462 pm_strcpy(jcr->RunAfterJob, msg);
463 free_pool_memory(msg);
464 return bnet_fsend(dir, OKRunAfter);
467 static bool run_cmd(JCR *jcr, char *cmd, const char *name)
469 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
472 char line[MAXSTRING];
474 ecmd = edit_job_codes(jcr, ecmd, cmd, "");
475 bpipe = open_bpipe(ecmd, 0, "r");
476 free_pool_memory(ecmd);
479 Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name,
483 while (fgets(line, sizeof(line), bpipe->rfd)) {
484 int len = strlen(line);
485 if (len > 0 && line[len-1] == '\n') {
488 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
490 status = close_bpipe(bpipe);
493 Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
494 status, be.strerror(status));
500 static bool init_fileset(JCR *jcr)
503 findFILESET *fileset;
512 fileset = (findFILESET *)malloc(sizeof(findFILESET));
513 memset(fileset, 0, sizeof(findFILESET));
514 ff->fileset = fileset;
515 fileset->state = state_none;
516 fileset->include_list.init(1, true);
517 fileset->exclude_list.init(1, true);
521 static findFOPTS *start_options(FF_PKT *ff)
523 int state = ff->fileset->state;
524 findINCEXE *incexe = ff->fileset->incexe;
526 if (state != state_options) {
527 ff->fileset->state = state_options;
528 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
529 memset(fo, 0, sizeof(findFOPTS));
530 fo->regex.init(1, true);
531 fo->regexdir.init(1, true);
532 fo->regexfile.init(1, true);
533 fo->wild.init(1, true);
534 fo->wilddir.init(1, true);
535 fo->wildfile.init(1, true);
536 fo->base.init(1, true);
537 fo->fstype.init(1, true);
538 incexe->current_opts = fo;
539 incexe->opts_list.append(fo);
541 return incexe->current_opts;
546 * Add fname to include/exclude fileset list. First check for
547 * | and < and if necessary perform command.
549 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
563 p++; /* skip over | */
564 fn = get_pool_memory(PM_FNAME);
565 fn = edit_job_codes(jcr, fn, p, "");
566 bpipe = open_bpipe(fn, 0, "r");
567 free_pool_memory(fn);
569 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
573 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
574 strip_trailing_junk(buf);
575 fileset->incexe->name_list.append(bstrdup(buf));
577 if ((stat=close_bpipe(bpipe)) != 0) {
578 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
579 p, stat, strerror(errno));
584 Dmsg0(100, "Doing < include on client.\n");
585 p++; /* skip over < */
586 if ((ffd = fopen(p, "r")) == NULL) {
588 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
592 while (fgets(buf, sizeof(buf), ffd)) {
593 strip_trailing_junk(buf);
594 Dmsg1(100, "%s\n", buf);
595 fileset->incexe->name_list.append(bstrdup(buf));
600 fileset->incexe->name_list.append(bstrdup(fname));
606 static void add_fileset(JCR *jcr, const char *item)
608 FF_PKT *ff = jcr->ff;
609 findFILESET *fileset = ff->fileset;
610 int state = fileset->state;
611 findFOPTS *current_opts;
613 /* Get code, optional subcode, and position item past the dividing space */
614 Dmsg1(100, "%s\n", item);
619 int subcode = ' '; /* A space is always a valid subcode */
620 if (item[0] != '\0' && item[0] != ' ') {
628 /* Skip all lines we receive after an error */
629 if (state == state_error) {
634 * The switch tests the code for validity.
635 * The subcode is always good if it is a space, otherwise we must confirm.
636 * We set state to state_error first assuming the subcode is invalid,
637 * requiring state to be set in cases below that handle subcodes.
639 if (subcode != ' ') {
645 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
646 memset(fileset->incexe, 0, sizeof(findINCEXE));
647 fileset->incexe->opts_list.init(1, true);
648 fileset->incexe->name_list.init(1, true);
649 fileset->include_list.append(fileset->incexe);
653 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
654 memset(fileset->incexe, 0, sizeof(findINCEXE));
655 fileset->incexe->opts_list.init(1, true);
656 fileset->incexe->name_list.init(1, true);
657 fileset->exclude_list.append(fileset->incexe);
663 /* File item to either include/include list */
664 state = state_include;
665 add_file_to_fileset(jcr, item, fileset);
668 current_opts = start_options(ff);
672 preg = (regex_t *)malloc(sizeof(regex_t));
673 if (current_opts->flags & FO_IGNORECASE) {
674 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
676 rc = regcomp(preg, item, REG_EXTENDED);
679 regerror(rc, preg, prbuf, sizeof(prbuf));
682 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
686 state = state_options;
687 if (subcode == ' ') {
688 current_opts->regex.append(preg);
689 } else if (subcode == 'D') {
690 current_opts->regexdir.append(preg);
691 } else if (subcode == 'F') {
692 current_opts->regexfile.append(preg);
698 current_opts = start_options(ff);
699 current_opts->base.append(bstrdup(item));
700 state = state_options;
703 current_opts = start_options(ff);
704 current_opts->fstype.append(bstrdup(item));
705 state = state_options;
708 current_opts = start_options(ff);
709 state = state_options;
710 if (subcode == ' ') {
711 current_opts->wild.append(bstrdup(item));
712 } else if (subcode == 'D') {
713 current_opts->wilddir.append(bstrdup(item));
714 } else if (subcode == 'F') {
715 current_opts->wildfile.append(bstrdup(item));
721 current_opts = start_options(ff);
722 set_options(current_opts, item);
723 state = state_options;
726 current_opts = start_options(ff);
727 current_opts->reader = bstrdup(item);
728 state = state_options;
731 current_opts = start_options(ff);
732 current_opts->writer = bstrdup(item);
733 state = state_options;
736 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
740 ff->fileset->state = state;
743 static bool term_fileset(JCR *jcr)
745 FF_PKT *ff = jcr->ff;
746 findFILESET *fileset = ff->fileset;
749 for (i=0; i<fileset->include_list.size(); i++) {
750 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
752 for (j=0; j<incexe->opts_list.size(); j++) {
753 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
754 for (k=0; k<fo->regex.size(); k++) {
755 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
757 for (k=0; k<fo->regexdir.size(); k++) {
758 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
760 for (k=0; k<fo->regexfile.size(); k++) {
761 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
763 for (k=0; k<fo->wild.size(); k++) {
764 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
766 for (k=0; k<fo->wilddir.size(); k++) {
767 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
769 for (k=0; k<fo->wildfile.size(); k++) {
770 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
772 for (k=0; k<fo->base.size(); k++) {
773 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
775 for (k=0; k<fo->fstype.size(); k++) {
776 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
779 Dmsg1(400, "D %s\n", fo->reader);
782 Dmsg1(400, "T %s\n", fo->writer);
785 for (j=0; j<incexe->name_list.size(); j++) {
786 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
789 for (i=0; i<fileset->exclude_list.size(); i++) {
790 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
792 for (j=0; j<incexe->opts_list.size(); j++) {
793 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
794 for (k=0; k<fo->regex.size(); k++) {
795 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
797 for (k=0; k<fo->regexdir.size(); k++) {
798 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
800 for (k=0; k<fo->regexfile.size(); k++) {
801 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
803 for (k=0; k<fo->wild.size(); k++) {
804 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
806 for (k=0; k<fo->wilddir.size(); k++) {
807 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
809 for (k=0; k<fo->wildfile.size(); k++) {
810 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
812 for (k=0; k<fo->base.size(); k++) {
813 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
815 for (k=0; k<fo->fstype.size(); k++) {
816 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
819 for (j=0; j<incexe->name_list.size(); j++) {
820 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
823 return ff->fileset->state != state_error;
828 * As an optimization, we should do this during
829 * "compile" time in filed/job.c, and keep only a bit mask
830 * and the Verify options.
832 static void set_options(findFOPTS *fo, const char *opts)
837 for (p=opts; *p; p++) {
839 case 'a': /* alway replace */
840 case '0': /* no option */
843 fo->flags |= FO_EXCLUDE;
846 fo->flags |= FO_MULTIFS;
848 case 'h': /* no recursion */
849 fo->flags |= FO_NO_RECURSION;
851 case 'H': /* no hard link handling */
852 fo->flags |= FO_NO_HARDLINK;
855 fo->flags |= FO_IGNORECASE;
861 fo->flags |= FO_NOREPLACE;
863 case 'p': /* use portable data format */
864 fo->flags |= FO_PORTABLE;
866 case 'R': /* Resource forks and Finder Info */
867 fo->flags |= FO_HFSPLUS;
868 case 'r': /* read fifo */
869 fo->flags |= FO_READFIFO;
874 /* Old director did not specify SHA variant */
875 fo->flags |= FO_SHA1;
878 fo->flags |= FO_SHA1;
883 fo->flags |= FO_SHA256;
887 fo->flags |= FO_SHA512;
892 /* Automatically downgrade to SHA-1 if an unsupported
893 * SHA variant is specified */
894 fo->flags |= FO_SHA1;
900 fo->flags |= FO_SPARSE;
903 fo->flags |= FO_MTIMEONLY;
906 fo->flags |= FO_KEEPATIME;
911 case 'V': /* verify options */
912 /* Copy Verify Options */
913 for (j=0; *p && *p != ':'; p++) {
914 fo->VerifyOpts[j] = *p;
915 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
919 fo->VerifyOpts[j] = 0;
922 fo->flags |= FO_IF_NEWER;
924 case 'Z': /* gzip compression */
925 fo->flags |= FO_GZIP;
926 fo->GZIP_level = *++p - '0';
927 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
930 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
938 * Director is passing his Fileset
940 static int fileset_cmd(JCR *jcr)
942 BSOCK *dir = jcr->dir_bsock;
945 sscanf(dir->msg, "fileset vss=%d", &vss);
948 if (!init_fileset(jcr)) {
951 while (bnet_recv(dir) >= 0) {
952 strip_trailing_junk(dir->msg);
953 Dmsg1(400, "Fileset: %s\n", dir->msg);
954 add_fileset(jcr, dir->msg);
956 if (!term_fileset(jcr)) {
959 return bnet_fsend(dir, OKinc);
962 static void free_bootstrap(JCR *jcr)
964 if (jcr->RestoreBootstrap) {
965 unlink(jcr->RestoreBootstrap);
966 free_pool_memory(jcr->RestoreBootstrap);
967 jcr->RestoreBootstrap = NULL;
973 * The Director sends us the bootstrap file, which
974 * we will in turn pass to the SD.
976 static int bootstrap_cmd(JCR *jcr)
978 BSOCK *dir = jcr->dir_bsock;
979 POOLMEM *fname = get_pool_memory(PM_FNAME);
983 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
985 Dmsg1(400, "bootstrap=%s\n", fname);
986 jcr->RestoreBootstrap = fname;
987 bs = fopen(fname, "a+"); /* create file */
990 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
991 jcr->RestoreBootstrap, be.strerror());
993 * Suck up what he is sending to us so that he will then
994 * read our error message.
996 while (bnet_recv(dir) >= 0)
999 set_jcr_job_status(jcr, JS_ErrorTerminated);
1003 while (bnet_recv(dir) >= 0) {
1004 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1005 fputs(dir->msg, bs);
1009 * Note, do not free the bootstrap yet -- it needs to be
1012 return bnet_fsend(dir, OKbootstrap);
1017 * Get backup level from Director
1020 static int level_cmd(JCR *jcr)
1022 BSOCK *dir = jcr->dir_bsock;
1023 POOLMEM *level, *buf = NULL;
1026 level = get_memory(dir->msglen+1);
1027 Dmsg1(110, "level_cmd: %s", dir->msg);
1028 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1031 /* Base backup requested? */
1032 if (strcmp(level, "base") == 0) {
1033 jcr->JobLevel = L_BASE;
1034 /* Full backup requested? */
1035 } else if (strcmp(level, "full") == 0) {
1036 jcr->JobLevel = L_FULL;
1037 } else if (strcmp(level, "differential") == 0) {
1038 jcr->JobLevel = L_DIFFERENTIAL;
1041 } else if (strcmp(level, "incremental") == 0) {
1042 jcr->JobLevel = L_INCREMENTAL;
1046 * We get his UTC since time, then sync the clocks and correct it
1047 * to agree with our clock.
1049 } else if (strcmp(level, "since_utime") == 0) {
1050 buf = get_memory(dir->msglen+1);
1051 utime_t since_time, adj;
1052 btime_t his_time, bt_start, rt=0, bt_adj=0;
1053 if (jcr->JobLevel == L_NONE) {
1054 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1056 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1057 buf, &mtime_only) != 2) {
1060 since_time = str_to_uint64(buf); /* this is the since time */
1061 char ed1[50], ed2[50];
1063 * Sync clocks by polling him for the time. We take
1064 * 10 samples of his time throwing out the first two.
1066 for (int i=0; i<10; i++) {
1067 bt_start = get_current_btime();
1068 bnet_sig(dir, BNET_BTIME); /* poll for time */
1069 if (bnet_recv(dir) <= 0) { /* get response */
1072 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1075 if (i < 2) { /* toss first two results */
1078 his_time = str_to_uint64(buf);
1079 rt = get_current_btime() - bt_start; /* compute round trip time */
1080 bt_adj -= his_time - bt_start - rt/2;
1081 Dmsg2(200, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1084 bt_adj = bt_adj / 8; /* compute average time */
1085 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1086 adj = btime_to_utime(bt_adj);
1087 since_time += adj; /* adjust for clock difference */
1089 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1091 bnet_sig(dir, BNET_EOD);
1093 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1094 jcr->incremental = 1; /* set incremental or decremental backup */
1095 jcr->mtime = (time_t)since_time; /* set since time */
1097 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1105 return bnet_fsend(dir, OKlevel);
1108 pm_strcpy(jcr->errmsg, dir->msg);
1109 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1118 * Get session parameters from Director -- this is for a Restore command
1120 static int session_cmd(JCR *jcr)
1122 BSOCK *dir = jcr->dir_bsock;
1124 Dmsg1(100, "SessionCmd: %s", dir->msg);
1125 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1126 &jcr->VolSessionId, &jcr->VolSessionTime,
1127 &jcr->StartFile, &jcr->EndFile,
1128 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1129 pm_strcpy(jcr->errmsg, dir->msg);
1130 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1134 return bnet_fsend(dir, OKsession);
1138 * Get address of storage daemon from Director
1141 static int storage_cmd(JCR *jcr)
1143 int stored_port; /* storage daemon port */
1144 int enable_ssl; /* enable ssl to sd */
1145 BSOCK *dir = jcr->dir_bsock;
1146 BSOCK *sd; /* storage daemon bsock */
1148 Dmsg1(100, "StorageCmd: %s", dir->msg);
1149 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1150 pm_strcpy(jcr->errmsg, dir->msg);
1151 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1154 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1155 /* Open command communications with Storage daemon */
1156 /* Try to connect for 1 hour at 10 second intervals */
1157 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1158 jcr->stored_addr, NULL, stored_port, 1);
1160 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1161 jcr->stored_addr, stored_port);
1162 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1163 jcr->stored_addr, stored_port);
1166 Dmsg0(110, "Connection OK to SD.\n");
1168 jcr->store_bsock = sd;
1170 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1171 if (!authenticate_storagedaemon(jcr)) {
1172 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1175 Dmsg0(110, "Authenticated with SD.\n");
1177 /* Send OK to Director */
1178 return bnet_fsend(dir, OKstore);
1183 * Do a backup. For now, we handle only Full and Incremental.
1185 static int backup_cmd(JCR *jcr)
1187 BSOCK *dir = jcr->dir_bsock;
1188 BSOCK *sd = jcr->store_bsock;
1191 char ed1[50], ed2[50];
1193 set_jcr_job_status(jcr, JS_Blocked);
1194 jcr->JobType = JT_BACKUP;
1195 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1198 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1202 bnet_fsend(dir, OKbackup);
1203 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1206 * Send Append Open Session to Storage daemon
1208 bnet_fsend(sd, append_open);
1209 Dmsg1(110, ">stored: %s", sd->msg);
1211 * Expect to receive back the Ticket number
1213 if (bget_msg(sd) >= 0) {
1214 Dmsg1(110, "<stored: %s", sd->msg);
1215 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1216 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1219 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1221 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1226 * Send Append data command to Storage daemon
1228 bnet_fsend(sd, append_data, jcr->Ticket);
1229 Dmsg1(110, ">stored: %s", sd->msg);
1232 * Expect to get OK data
1234 Dmsg1(110, "<stored: %s", sd->msg);
1235 if (!response(jcr, sd, OK_data, "Append Data")) {
1239 generate_daemon_event(jcr, "JobStart");
1242 /* START VSS ON WIN 32 */
1243 if (g_pVSSClient && enable_vss) {
1244 if (g_pVSSClient->InitializeForBackup()) {
1245 /* tell vss which drives to snapshot */
1246 char szWinDriveLetters[27];
1247 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1248 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1249 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1251 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed. ERR=%s\n"),
1254 /* tell user if snapshot creation of a specific drive failed */
1256 for (i=0; i<strlen (szWinDriveLetters); i++) {
1257 if (islower(szWinDriveLetters[i])) {
1258 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed\n"), szWinDriveLetters[i]);
1261 /* inform user about writer states */
1262 for (i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1263 int msg_type = M_INFO;
1264 if (g_pVSSClient->GetWriterState(i) < 0) {
1265 msg_type = M_WARNING;
1267 Jmsg(jcr, msg_type, 0, _("VSS Writer: %s\n"), g_pVSSClient->GetWriterInfo(i));
1271 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1274 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled.\n"));
1280 * Send Files to Storage daemon
1282 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1283 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1284 set_jcr_job_status(jcr, JS_ErrorTerminated);
1285 bnet_suppress_error_messages(sd, 1);
1286 bget_msg(sd); /* Read final response from append_data */
1287 Dmsg0(110, "Error in blast_data.\n");
1289 set_jcr_job_status(jcr, JS_Terminated);
1290 if (jcr->JobStatus != JS_Terminated) {
1291 bnet_suppress_error_messages(sd, 1);
1292 goto cleanup; /* bail out now */
1295 * Expect to get response to append_data from Storage daemon
1297 if (!response(jcr, sd, OK_append, "Append Data")) {
1298 set_jcr_job_status(jcr, JS_ErrorTerminated);
1303 * Send Append End Data to Storage daemon
1305 bnet_fsend(sd, append_end, jcr->Ticket);
1307 if (!response(jcr, sd, OK_end, "Append End")) {
1308 set_jcr_job_status(jcr, JS_ErrorTerminated);
1313 * Send Append Close to Storage daemon
1315 bnet_fsend(sd, append_close, jcr->Ticket);
1316 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1317 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1319 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1323 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1326 if (SDJobStatus != JS_Terminated) {
1327 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1334 /* STOP VSS ON WIN 32 */
1335 /* tell vss to close the backup session */
1336 if (g_pVSSClient && enable_vss == 1)
1337 g_pVSSClient->CloseBackup();
1340 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1341 edit_uint64(jcr->ReadBytes, ed1),
1342 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1343 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1345 return 0; /* return and stop command loop */
1349 * Do a Verify for Director
1352 static int verify_cmd(JCR *jcr)
1354 BSOCK *dir = jcr->dir_bsock;
1355 BSOCK *sd = jcr->store_bsock;
1356 char level[100], ed1[50], ed2[50];
1358 jcr->JobType = JT_VERIFY;
1359 if (sscanf(dir->msg, verifycmd, level) != 1) {
1360 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1364 if (strcasecmp(level, "init") == 0) {
1365 jcr->JobLevel = L_VERIFY_INIT;
1366 } else if (strcasecmp(level, "catalog") == 0){
1367 jcr->JobLevel = L_VERIFY_CATALOG;
1368 } else if (strcasecmp(level, "volume") == 0){
1369 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1370 } else if (strcasecmp(level, "data") == 0){
1371 jcr->JobLevel = L_VERIFY_DATA;
1372 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1373 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1375 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1379 bnet_fsend(dir, OKverify);
1381 generate_daemon_event(jcr, "JobStart");
1383 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1385 switch (jcr->JobLevel) {
1387 case L_VERIFY_CATALOG:
1390 case L_VERIFY_VOLUME_TO_CATALOG:
1391 if (!open_sd_read_session(jcr)) {
1394 start_dir_heartbeat(jcr);
1395 do_verify_volume(jcr);
1396 stop_dir_heartbeat(jcr);
1398 * Send Close session command to Storage daemon
1400 bnet_fsend(sd, read_close, jcr->Ticket);
1401 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1403 /* ****FIXME**** check response */
1404 bget_msg(sd); /* get OK */
1406 /* Inform Storage daemon that we are done */
1407 bnet_sig(sd, BNET_TERMINATE);
1410 case L_VERIFY_DISK_TO_CATALOG:
1414 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1418 bnet_sig(dir, BNET_EOD);
1420 /* Send termination status back to Dir */
1421 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1422 edit_uint64(jcr->ReadBytes, ed1),
1423 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1425 /* Inform Director that we are done */
1426 bnet_sig(dir, BNET_TERMINATE);
1427 return 0; /* return and terminate command loop */
1431 * Do a Restore for Director
1434 static int restore_cmd(JCR *jcr)
1436 BSOCK *dir = jcr->dir_bsock;
1437 BSOCK *sd = jcr->store_bsock;
1441 char ed1[50], ed2[50];
1444 * Scan WHERE (base directory for restore) from command
1446 Dmsg0(150, "restore command\n");
1447 /* Pickup where string */
1448 where = get_memory(dir->msglen+1);
1451 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1452 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1453 pm_strcpy(jcr->errmsg, dir->msg);
1454 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1459 /* Turn / into nothing */
1460 if (where[0] == '/' && where[1] == 0) {
1464 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1465 unbash_spaces(where);
1466 jcr->where = bstrdup(where);
1467 free_pool_memory(where);
1468 jcr->replace = replace;
1469 jcr->prefix_links = prefix_links;
1471 bnet_fsend(dir, OKrestore);
1472 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1474 jcr->JobType = JT_RESTORE;
1476 set_jcr_job_status(jcr, JS_Blocked);
1478 if (!open_sd_read_session(jcr)) {
1479 set_jcr_job_status(jcr, JS_ErrorTerminated);
1483 set_jcr_job_status(jcr, JS_Running);
1486 * Do restore of files and data
1488 start_dir_heartbeat(jcr);
1489 generate_daemon_event(jcr, "JobStart");
1491 stop_dir_heartbeat(jcr);
1493 set_jcr_job_status(jcr, JS_Terminated);
1494 if (jcr->JobStatus != JS_Terminated) {
1495 bnet_suppress_error_messages(sd, 1);
1499 * Send Close session command to Storage daemon
1501 bnet_fsend(sd, read_close, jcr->Ticket);
1502 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1504 bget_msg(sd); /* get OK */
1506 /* Inform Storage daemon that we are done */
1507 bnet_sig(sd, BNET_TERMINATE);
1512 set_jcr_job_status(jcr, JS_ErrorTerminated);
1514 /* Send termination status back to Dir */
1515 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1516 edit_uint64(jcr->ReadBytes, ed1),
1517 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1519 /* Inform Director that we are done */
1520 bnet_sig(dir, BNET_TERMINATE);
1522 Dmsg0(130, "Done in job.c\n");
1523 return 0; /* return and terminate command loop */
1526 static int open_sd_read_session(JCR *jcr)
1528 BSOCK *sd = jcr->store_bsock;
1531 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1534 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1535 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1536 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1538 * Open Read Session with Storage daemon
1540 bnet_fsend(sd, read_open, "DummyVolume",
1541 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1542 jcr->StartBlock, jcr->EndBlock);
1543 Dmsg1(110, ">stored: %s", sd->msg);
1548 if (bget_msg(sd) >= 0) {
1549 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1550 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1551 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1554 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1556 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1560 if (!send_bootstrap_file(jcr)) {
1565 * Start read of data with Storage daemon
1567 bnet_fsend(sd, read_data, jcr->Ticket);
1568 Dmsg1(110, ">stored: %s", sd->msg);
1573 if (!response(jcr, sd, OK_data, "Read Data")) {
1580 * Destroy the Job Control Record and associated
1581 * resources (sockets).
1583 static void filed_free_jcr(JCR *jcr)
1585 if (jcr->store_bsock) {
1586 bnet_close(jcr->store_bsock);
1588 free_bootstrap(jcr);
1589 if (jcr->last_fname) {
1590 free_pool_memory(jcr->last_fname);
1592 if (jcr->RunAfterJob) {
1593 free_pool_memory(jcr->RunAfterJob);
1601 * Get response from Storage daemon to a command we
1602 * sent. Check that the response is OK.
1604 * Returns: 0 on failure
1607 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1612 if (bget_msg(sd) > 0) {
1613 Dmsg0(110, sd->msg);
1614 if (strcmp(sd->msg, resp) == 0) {
1618 if (job_canceled(jcr)) {
1619 return 0; /* if canceled avoid useless error messages */
1621 if (is_bnet_error(sd)) {
1622 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1623 cmd, bnet_strerror(sd));
1625 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1626 cmd, resp, sd->msg);
1631 static int send_bootstrap_file(JCR *jcr)
1635 BSOCK *sd = jcr->store_bsock;
1636 const char *bootstrap = "bootstrap\n";
1639 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1640 if (!jcr->RestoreBootstrap) {
1643 bs = fopen(jcr->RestoreBootstrap, "r");
1646 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1647 jcr->RestoreBootstrap, be.strerror());
1648 set_jcr_job_status(jcr, JS_ErrorTerminated);
1651 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1653 while (fgets(buf, sizeof(buf), bs)) {
1654 sd->msglen = Mmsg(sd->msg, "%s", buf);
1657 bnet_sig(sd, BNET_EOD);
1659 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1660 set_jcr_job_status(jcr, JS_ErrorTerminated);
1666 free_bootstrap(jcr);