2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
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;
180 jcr->pki_recipients = me->pki_recipients;
182 enable_backup_privileges(NULL, 1 /* ignore_errors */);
184 /**********FIXME******* add command handler error code */
186 for (quit=false; !quit;) {
189 if (bnet_recv(dir) < 0) {
190 break; /* connection terminated */
192 dir->msg[dir->msglen] = 0;
193 Dmsg1(100, "<dird: %s", dir->msg);
195 for (i=0; cmds[i].cmd; i++) {
196 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
197 found = true; /* indicate command found */
198 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
199 bnet_fsend(dir, no_auth);
200 bnet_sig(dir, BNET_EOD);
203 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
204 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
205 bnet_fsend(dir, illegal_cmd);
206 bnet_sig(dir, BNET_EOD);
209 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
210 if (!cmds[i].func(jcr)) { /* do command */
211 quit = true; /* error or fully terminated, get out */
212 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
217 if (!found) { /* command not found */
218 bnet_fsend(dir, errmsg);
224 /* Inform Storage daemon that we are done */
225 if (jcr->store_bsock) {
226 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
229 if (jcr->RunAfterJob && !job_canceled(jcr)) {
230 run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob");
232 generate_daemon_event(jcr, "JobEnd");
234 dequeue_messages(jcr); /* send any queued messages */
236 /* Inform Director that we are done */
237 bnet_sig(dir, BNET_TERMINATE);
239 /* Clean up fileset */
240 FF_PKT *ff = jcr->ff;
241 findFILESET *fileset = ff->fileset;
244 /* Delete FileSet Include lists */
245 for (i=0; i<fileset->include_list.size(); i++) {
246 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
247 for (j=0; j<incexe->opts_list.size(); j++) {
248 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
249 for (k=0; k<fo->regex.size(); k++) {
250 regfree((regex_t *)fo->regex.get(k));
253 fo->regexdir.destroy();
254 fo->regexfile.destroy();
256 fo->wilddir.destroy();
257 fo->wildfile.destroy();
259 fo->fstype.destroy();
267 incexe->opts_list.destroy();
268 incexe->name_list.destroy();
270 fileset->include_list.destroy();
272 /* Delete FileSet Exclude lists */
273 for (i=0; i<fileset->exclude_list.size(); i++) {
274 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
275 for (j=0; j<incexe->opts_list.size(); j++) {
276 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
278 fo->regexdir.destroy();
279 fo->regexfile.destroy();
281 fo->wilddir.destroy();
282 fo->wildfile.destroy();
284 fo->fstype.destroy();
286 incexe->opts_list.destroy();
287 incexe->name_list.destroy();
289 fileset->exclude_list.destroy();
293 Dmsg0(100, "Calling term_find_files\n");
294 term_find_files(jcr->ff);
296 Dmsg0(100, "Done with term_find_files\n");
297 free_jcr(jcr); /* destroy JCR record */
298 Dmsg0(100, "Done with free_jcr\n");
303 * Hello from Director he must identify himself and provide his
306 static int hello_cmd(JCR *jcr)
308 Dmsg0(120, "Calling Authenticate\n");
309 if (!authenticate_director(jcr)) {
312 Dmsg0(120, "OK Authenticate\n");
313 jcr->authenticated = true;
320 static int cancel_cmd(JCR *jcr)
322 BSOCK *dir = jcr->dir_bsock;
323 char Job[MAX_NAME_LENGTH];
326 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
327 if (!(cjcr=get_jcr_by_full_name(Job))) {
328 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
330 if (cjcr->store_bsock) {
332 cjcr->store_bsock->timed_out = 1;
333 cjcr->store_bsock->terminated = 1;
335 * #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
337 #if !defined(HAVE_CYGWIN)
338 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
342 set_jcr_job_status(cjcr, JS_Canceled);
344 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
347 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
349 bnet_sig(dir, BNET_EOD);
355 * Set debug level as requested by the Director
358 static int setdebug_cmd(JCR *jcr)
360 BSOCK *dir = jcr->dir_bsock;
361 int level, trace_flag;
363 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
364 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
365 pm_strcpy(jcr->errmsg, dir->msg);
366 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
370 set_trace(trace_flag);
371 return bnet_fsend(dir, OKsetdebug, level);
375 static int estimate_cmd(JCR *jcr)
377 BSOCK *dir = jcr->dir_bsock;
380 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
381 pm_strcpy(jcr->errmsg, dir->msg);
382 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
383 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
387 bnet_fsend(dir, OKest, jcr->num_files_examined,
388 edit_uint64_with_commas(jcr->JobBytes, ed2));
389 bnet_sig(dir, BNET_EOD);
394 * Get JobId and Storage Daemon Authorization key from Director
396 static int job_cmd(JCR *jcr)
398 BSOCK *dir = jcr->dir_bsock;
399 POOLMEM *sd_auth_key;
401 sd_auth_key = get_memory(dir->msglen);
402 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
403 &jcr->VolSessionId, &jcr->VolSessionTime,
405 pm_strcpy(jcr->errmsg, dir->msg);
406 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
407 bnet_fsend(dir, BADjob);
408 free_pool_memory(sd_auth_key);
411 jcr->sd_auth_key = bstrdup(sd_auth_key);
412 free_pool_memory(sd_auth_key);
413 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
414 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
417 static int runbefore_cmd(JCR *jcr)
420 BSOCK *dir = jcr->dir_bsock;
421 POOLMEM *cmd = get_memory(dir->msglen+1);
423 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
424 if (sscanf(dir->msg, runbefore, cmd) != 1) {
425 pm_strcpy(jcr->errmsg, dir->msg);
426 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
427 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
433 /* Run the command now */
434 ok = run_cmd(jcr, cmd, "ClientRunBeforeJob");
437 bnet_fsend(dir, OKRunBefore);
440 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
445 static int runafter_cmd(JCR *jcr)
447 BSOCK *dir = jcr->dir_bsock;
448 POOLMEM *msg = get_memory(dir->msglen+1);
450 Dmsg1(100, "runafter_cmd: %s", dir->msg);
451 if (sscanf(dir->msg, runafter, msg) != 1) {
452 pm_strcpy(jcr->errmsg, dir->msg);
453 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
454 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
459 if (jcr->RunAfterJob) {
460 free_pool_memory(jcr->RunAfterJob);
462 jcr->RunAfterJob = get_pool_memory(PM_FNAME);
463 pm_strcpy(jcr->RunAfterJob, msg);
464 free_pool_memory(msg);
465 return bnet_fsend(dir, OKRunAfter);
468 static bool run_cmd(JCR *jcr, char *cmd, const char *name)
470 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
473 char line[MAXSTRING];
475 ecmd = edit_job_codes(jcr, ecmd, cmd, "");
476 bpipe = open_bpipe(ecmd, 0, "r");
477 free_pool_memory(ecmd);
480 Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name,
484 while (fgets(line, sizeof(line), bpipe->rfd)) {
485 int len = strlen(line);
486 if (len > 0 && line[len-1] == '\n') {
489 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
491 status = close_bpipe(bpipe);
494 Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
495 status, be.strerror(status));
501 static bool init_fileset(JCR *jcr)
504 findFILESET *fileset;
513 fileset = (findFILESET *)malloc(sizeof(findFILESET));
514 memset(fileset, 0, sizeof(findFILESET));
515 ff->fileset = fileset;
516 fileset->state = state_none;
517 fileset->include_list.init(1, true);
518 fileset->exclude_list.init(1, true);
522 static findFOPTS *start_options(FF_PKT *ff)
524 int state = ff->fileset->state;
525 findINCEXE *incexe = ff->fileset->incexe;
527 if (state != state_options) {
528 ff->fileset->state = state_options;
529 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
530 memset(fo, 0, sizeof(findFOPTS));
531 fo->regex.init(1, true);
532 fo->regexdir.init(1, true);
533 fo->regexfile.init(1, true);
534 fo->wild.init(1, true);
535 fo->wilddir.init(1, true);
536 fo->wildfile.init(1, true);
537 fo->base.init(1, true);
538 fo->fstype.init(1, true);
539 incexe->current_opts = fo;
540 incexe->opts_list.append(fo);
542 return incexe->current_opts;
547 * Add fname to include/exclude fileset list. First check for
548 * | and < and if necessary perform command.
550 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
564 p++; /* skip over | */
565 fn = get_pool_memory(PM_FNAME);
566 fn = edit_job_codes(jcr, fn, p, "");
567 bpipe = open_bpipe(fn, 0, "r");
568 free_pool_memory(fn);
570 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
574 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
575 strip_trailing_junk(buf);
576 fileset->incexe->name_list.append(bstrdup(buf));
578 if ((stat=close_bpipe(bpipe)) != 0) {
579 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
580 p, stat, strerror(errno));
585 Dmsg0(100, "Doing < include on client.\n");
586 p++; /* skip over < */
587 if ((ffd = fopen(p, "r")) == NULL) {
589 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
593 while (fgets(buf, sizeof(buf), ffd)) {
594 strip_trailing_junk(buf);
595 Dmsg1(100, "%s\n", buf);
596 fileset->incexe->name_list.append(bstrdup(buf));
601 fileset->incexe->name_list.append(bstrdup(fname));
607 static void add_fileset(JCR *jcr, const char *item)
609 FF_PKT *ff = jcr->ff;
610 findFILESET *fileset = ff->fileset;
611 int state = fileset->state;
612 findFOPTS *current_opts;
614 /* Get code, optional subcode, and position item past the dividing space */
615 Dmsg1(100, "%s\n", item);
620 int subcode = ' '; /* A space is always a valid subcode */
621 if (item[0] != '\0' && item[0] != ' ') {
629 /* Skip all lines we receive after an error */
630 if (state == state_error) {
635 * The switch tests the code for validity.
636 * The subcode is always good if it is a space, otherwise we must confirm.
637 * We set state to state_error first assuming the subcode is invalid,
638 * requiring state to be set in cases below that handle subcodes.
640 if (subcode != ' ') {
646 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
647 memset(fileset->incexe, 0, sizeof(findINCEXE));
648 fileset->incexe->opts_list.init(1, true);
649 fileset->incexe->name_list.init(1, true);
650 fileset->include_list.append(fileset->incexe);
654 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
655 memset(fileset->incexe, 0, sizeof(findINCEXE));
656 fileset->incexe->opts_list.init(1, true);
657 fileset->incexe->name_list.init(1, true);
658 fileset->exclude_list.append(fileset->incexe);
664 /* File item to either include/include list */
665 state = state_include;
666 add_file_to_fileset(jcr, item, fileset);
669 current_opts = start_options(ff);
673 preg = (regex_t *)malloc(sizeof(regex_t));
674 if (current_opts->flags & FO_IGNORECASE) {
675 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
677 rc = regcomp(preg, item, REG_EXTENDED);
680 regerror(rc, preg, prbuf, sizeof(prbuf));
683 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
687 state = state_options;
688 if (subcode == ' ') {
689 current_opts->regex.append(preg);
690 } else if (subcode == 'D') {
691 current_opts->regexdir.append(preg);
692 } else if (subcode == 'F') {
693 current_opts->regexfile.append(preg);
699 current_opts = start_options(ff);
700 current_opts->base.append(bstrdup(item));
701 state = state_options;
704 current_opts = start_options(ff);
705 current_opts->fstype.append(bstrdup(item));
706 state = state_options;
709 current_opts = start_options(ff);
710 state = state_options;
711 if (subcode == ' ') {
712 current_opts->wild.append(bstrdup(item));
713 } else if (subcode == 'D') {
714 current_opts->wilddir.append(bstrdup(item));
715 } else if (subcode == 'F') {
716 current_opts->wildfile.append(bstrdup(item));
722 current_opts = start_options(ff);
723 set_options(current_opts, item);
724 state = state_options;
727 current_opts = start_options(ff);
728 current_opts->reader = bstrdup(item);
729 state = state_options;
732 current_opts = start_options(ff);
733 current_opts->writer = bstrdup(item);
734 state = state_options;
737 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
741 ff->fileset->state = state;
744 static bool term_fileset(JCR *jcr)
746 FF_PKT *ff = jcr->ff;
747 findFILESET *fileset = ff->fileset;
750 for (i=0; i<fileset->include_list.size(); i++) {
751 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
753 for (j=0; j<incexe->opts_list.size(); j++) {
754 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
755 for (k=0; k<fo->regex.size(); k++) {
756 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
758 for (k=0; k<fo->regexdir.size(); k++) {
759 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
761 for (k=0; k<fo->regexfile.size(); k++) {
762 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
764 for (k=0; k<fo->wild.size(); k++) {
765 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
767 for (k=0; k<fo->wilddir.size(); k++) {
768 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
770 for (k=0; k<fo->wildfile.size(); k++) {
771 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
773 for (k=0; k<fo->base.size(); k++) {
774 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
776 for (k=0; k<fo->fstype.size(); k++) {
777 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
780 Dmsg1(400, "D %s\n", fo->reader);
783 Dmsg1(400, "T %s\n", fo->writer);
786 for (j=0; j<incexe->name_list.size(); j++) {
787 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
790 for (i=0; i<fileset->exclude_list.size(); i++) {
791 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
793 for (j=0; j<incexe->opts_list.size(); j++) {
794 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
795 for (k=0; k<fo->regex.size(); k++) {
796 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
798 for (k=0; k<fo->regexdir.size(); k++) {
799 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
801 for (k=0; k<fo->regexfile.size(); k++) {
802 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
804 for (k=0; k<fo->wild.size(); k++) {
805 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
807 for (k=0; k<fo->wilddir.size(); k++) {
808 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
810 for (k=0; k<fo->wildfile.size(); k++) {
811 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
813 for (k=0; k<fo->base.size(); k++) {
814 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
816 for (k=0; k<fo->fstype.size(); k++) {
817 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
820 for (j=0; j<incexe->name_list.size(); j++) {
821 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
824 return ff->fileset->state != state_error;
829 * As an optimization, we should do this during
830 * "compile" time in filed/job.c, and keep only a bit mask
831 * and the Verify options.
833 static void set_options(findFOPTS *fo, const char *opts)
838 for (p=opts; *p; p++) {
840 case 'a': /* alway replace */
841 case '0': /* no option */
844 fo->flags |= FO_EXCLUDE;
847 fo->flags |= FO_MULTIFS;
849 case 'h': /* no recursion */
850 fo->flags |= FO_NO_RECURSION;
852 case 'H': /* no hard link handling */
853 fo->flags |= FO_NO_HARDLINK;
856 fo->flags |= FO_IGNORECASE;
862 fo->flags |= FO_NOREPLACE;
864 case 'p': /* use portable data format */
865 fo->flags |= FO_PORTABLE;
867 case 'R': /* Resource forks and Finder Info */
868 fo->flags |= FO_HFSPLUS;
869 case 'r': /* read fifo */
870 fo->flags |= FO_READFIFO;
875 /* Old director did not specify SHA variant */
876 fo->flags |= FO_SHA1;
879 fo->flags |= FO_SHA1;
884 fo->flags |= FO_SHA256;
888 fo->flags |= FO_SHA512;
893 /* Automatically downgrade to SHA-1 if an unsupported
894 * SHA variant is specified */
895 fo->flags |= FO_SHA1;
901 fo->flags |= FO_SPARSE;
904 fo->flags |= FO_MTIMEONLY;
907 fo->flags |= FO_KEEPATIME;
912 case 'V': /* verify options */
913 /* Copy Verify Options */
914 for (j=0; *p && *p != ':'; p++) {
915 fo->VerifyOpts[j] = *p;
916 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
920 fo->VerifyOpts[j] = 0;
923 fo->flags |= FO_IF_NEWER;
925 case 'Z': /* gzip compression */
926 fo->flags |= FO_GZIP;
927 fo->GZIP_level = *++p - '0';
928 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
931 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
939 * Director is passing his Fileset
941 static int fileset_cmd(JCR *jcr)
943 BSOCK *dir = jcr->dir_bsock;
946 sscanf(dir->msg, "fileset vss=%d", &vss);
949 if (!init_fileset(jcr)) {
952 while (bnet_recv(dir) >= 0) {
953 strip_trailing_junk(dir->msg);
954 Dmsg1(400, "Fileset: %s\n", dir->msg);
955 add_fileset(jcr, dir->msg);
957 if (!term_fileset(jcr)) {
960 return bnet_fsend(dir, OKinc);
963 static void free_bootstrap(JCR *jcr)
965 if (jcr->RestoreBootstrap) {
966 unlink(jcr->RestoreBootstrap);
967 free_pool_memory(jcr->RestoreBootstrap);
968 jcr->RestoreBootstrap = NULL;
974 * The Director sends us the bootstrap file, which
975 * we will in turn pass to the SD.
977 static int bootstrap_cmd(JCR *jcr)
979 BSOCK *dir = jcr->dir_bsock;
980 POOLMEM *fname = get_pool_memory(PM_FNAME);
984 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
986 Dmsg1(400, "bootstrap=%s\n", fname);
987 jcr->RestoreBootstrap = fname;
988 bs = fopen(fname, "a+"); /* create file */
991 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
992 jcr->RestoreBootstrap, be.strerror());
994 * Suck up what he is sending to us so that he will then
995 * read our error message.
997 while (bnet_recv(dir) >= 0)
1000 set_jcr_job_status(jcr, JS_ErrorTerminated);
1004 while (bnet_recv(dir) >= 0) {
1005 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1006 fputs(dir->msg, bs);
1010 * Note, do not free the bootstrap yet -- it needs to be
1013 return bnet_fsend(dir, OKbootstrap);
1018 * Get backup level from Director
1021 static int level_cmd(JCR *jcr)
1023 BSOCK *dir = jcr->dir_bsock;
1024 POOLMEM *level, *buf = NULL;
1027 level = get_memory(dir->msglen+1);
1028 Dmsg1(110, "level_cmd: %s", dir->msg);
1029 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1032 /* Base backup requested? */
1033 if (strcmp(level, "base") == 0) {
1034 jcr->JobLevel = L_BASE;
1035 /* Full backup requested? */
1036 } else if (strcmp(level, "full") == 0) {
1037 jcr->JobLevel = L_FULL;
1038 } else if (strcmp(level, "differential") == 0) {
1039 jcr->JobLevel = L_DIFFERENTIAL;
1042 } else if (strcmp(level, "incremental") == 0) {
1043 jcr->JobLevel = L_INCREMENTAL;
1047 * We get his UTC since time, then sync the clocks and correct it
1048 * to agree with our clock.
1050 } else if (strcmp(level, "since_utime") == 0) {
1051 buf = get_memory(dir->msglen+1);
1052 utime_t since_time, adj;
1053 btime_t his_time, bt_start, rt=0, bt_adj=0;
1054 if (jcr->JobLevel == L_NONE) {
1055 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1057 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1058 buf, &mtime_only) != 2) {
1061 since_time = str_to_uint64(buf); /* this is the since time */
1062 char ed1[50], ed2[50];
1064 * Sync clocks by polling him for the time. We take
1065 * 10 samples of his time throwing out the first two.
1067 for (int i=0; i<10; i++) {
1068 bt_start = get_current_btime();
1069 bnet_sig(dir, BNET_BTIME); /* poll for time */
1070 if (bnet_recv(dir) <= 0) { /* get response */
1073 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1076 if (i < 2) { /* toss first two results */
1079 his_time = str_to_uint64(buf);
1080 rt = get_current_btime() - bt_start; /* compute round trip time */
1081 bt_adj -= his_time - bt_start - rt/2;
1082 Dmsg2(200, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1085 bt_adj = bt_adj / 8; /* compute average time */
1086 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1087 adj = btime_to_utime(bt_adj);
1088 since_time += adj; /* adjust for clock difference */
1090 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1092 bnet_sig(dir, BNET_EOD);
1094 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1095 jcr->incremental = 1; /* set incremental or decremental backup */
1096 jcr->mtime = (time_t)since_time; /* set since time */
1098 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1106 return bnet_fsend(dir, OKlevel);
1109 pm_strcpy(jcr->errmsg, dir->msg);
1110 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1119 * Get session parameters from Director -- this is for a Restore command
1121 static int session_cmd(JCR *jcr)
1123 BSOCK *dir = jcr->dir_bsock;
1125 Dmsg1(100, "SessionCmd: %s", dir->msg);
1126 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1127 &jcr->VolSessionId, &jcr->VolSessionTime,
1128 &jcr->StartFile, &jcr->EndFile,
1129 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1130 pm_strcpy(jcr->errmsg, dir->msg);
1131 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1135 return bnet_fsend(dir, OKsession);
1139 * Get address of storage daemon from Director
1142 static int storage_cmd(JCR *jcr)
1144 int stored_port; /* storage daemon port */
1145 int enable_ssl; /* enable ssl to sd */
1146 BSOCK *dir = jcr->dir_bsock;
1147 BSOCK *sd; /* storage daemon bsock */
1149 Dmsg1(100, "StorageCmd: %s", dir->msg);
1150 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1151 pm_strcpy(jcr->errmsg, dir->msg);
1152 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1155 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1156 /* Open command communications with Storage daemon */
1157 /* Try to connect for 1 hour at 10 second intervals */
1158 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1159 jcr->stored_addr, NULL, stored_port, 1);
1161 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1162 jcr->stored_addr, stored_port);
1163 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1164 jcr->stored_addr, stored_port);
1167 Dmsg0(110, "Connection OK to SD.\n");
1169 jcr->store_bsock = sd;
1171 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1172 if (!authenticate_storagedaemon(jcr)) {
1173 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1176 Dmsg0(110, "Authenticated with SD.\n");
1178 /* Send OK to Director */
1179 return bnet_fsend(dir, OKstore);
1184 * Do a backup. For now, we handle only Full and Incremental.
1186 static int backup_cmd(JCR *jcr)
1188 BSOCK *dir = jcr->dir_bsock;
1189 BSOCK *sd = jcr->store_bsock;
1192 char ed1[50], ed2[50];
1194 set_jcr_job_status(jcr, JS_Blocked);
1195 jcr->JobType = JT_BACKUP;
1196 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1199 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1203 bnet_fsend(dir, OKbackup);
1204 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1207 * Send Append Open Session to Storage daemon
1209 bnet_fsend(sd, append_open);
1210 Dmsg1(110, ">stored: %s", sd->msg);
1212 * Expect to receive back the Ticket number
1214 if (bget_msg(sd) >= 0) {
1215 Dmsg1(110, "<stored: %s", sd->msg);
1216 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1217 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1220 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1222 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1227 * Send Append data command to Storage daemon
1229 bnet_fsend(sd, append_data, jcr->Ticket);
1230 Dmsg1(110, ">stored: %s", sd->msg);
1233 * Expect to get OK data
1235 Dmsg1(110, "<stored: %s", sd->msg);
1236 if (!response(jcr, sd, OK_data, "Append Data")) {
1240 generate_daemon_event(jcr, "JobStart");
1243 /* START VSS ON WIN 32 */
1244 if (g_pVSSClient && enable_vss) {
1245 if (g_pVSSClient->InitializeForBackup()) {
1246 /* tell vss which drives to snapshot */
1247 char szWinDriveLetters[27];
1248 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1249 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1250 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1252 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed. ERR=%s\n"),
1255 /* tell user if snapshot creation of a specific drive failed */
1257 for (i=0; i<strlen (szWinDriveLetters); i++) {
1258 if (islower(szWinDriveLetters[i])) {
1259 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed\n"), szWinDriveLetters[i]);
1262 /* inform user about writer states */
1263 for (i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1264 int msg_type = M_INFO;
1265 if (g_pVSSClient->GetWriterState(i) < 0) {
1266 msg_type = M_WARNING;
1268 Jmsg(jcr, msg_type, 0, _("VSS Writer: %s\n"), g_pVSSClient->GetWriterInfo(i));
1272 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1275 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled.\n"));
1281 * Send Files to Storage daemon
1283 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1284 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1285 set_jcr_job_status(jcr, JS_ErrorTerminated);
1286 bnet_suppress_error_messages(sd, 1);
1287 bget_msg(sd); /* Read final response from append_data */
1288 Dmsg0(110, "Error in blast_data.\n");
1290 set_jcr_job_status(jcr, JS_Terminated);
1291 if (jcr->JobStatus != JS_Terminated) {
1292 bnet_suppress_error_messages(sd, 1);
1293 goto cleanup; /* bail out now */
1296 * Expect to get response to append_data from Storage daemon
1298 if (!response(jcr, sd, OK_append, "Append Data")) {
1299 set_jcr_job_status(jcr, JS_ErrorTerminated);
1304 * Send Append End Data to Storage daemon
1306 bnet_fsend(sd, append_end, jcr->Ticket);
1308 if (!response(jcr, sd, OK_end, "Append End")) {
1309 set_jcr_job_status(jcr, JS_ErrorTerminated);
1314 * Send Append Close to Storage daemon
1316 bnet_fsend(sd, append_close, jcr->Ticket);
1317 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1318 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1320 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1324 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1327 if (SDJobStatus != JS_Terminated) {
1328 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1335 /* STOP VSS ON WIN 32 */
1336 /* tell vss to close the backup session */
1337 if (g_pVSSClient && enable_vss == 1)
1338 g_pVSSClient->CloseBackup();
1341 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1342 edit_uint64(jcr->ReadBytes, ed1),
1343 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1344 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1346 return 0; /* return and stop command loop */
1350 * Do a Verify for Director
1353 static int verify_cmd(JCR *jcr)
1355 BSOCK *dir = jcr->dir_bsock;
1356 BSOCK *sd = jcr->store_bsock;
1357 char level[100], ed1[50], ed2[50];
1359 jcr->JobType = JT_VERIFY;
1360 if (sscanf(dir->msg, verifycmd, level) != 1) {
1361 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1365 if (strcasecmp(level, "init") == 0) {
1366 jcr->JobLevel = L_VERIFY_INIT;
1367 } else if (strcasecmp(level, "catalog") == 0){
1368 jcr->JobLevel = L_VERIFY_CATALOG;
1369 } else if (strcasecmp(level, "volume") == 0){
1370 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1371 } else if (strcasecmp(level, "data") == 0){
1372 jcr->JobLevel = L_VERIFY_DATA;
1373 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1374 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1376 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1380 bnet_fsend(dir, OKverify);
1382 generate_daemon_event(jcr, "JobStart");
1384 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1386 switch (jcr->JobLevel) {
1388 case L_VERIFY_CATALOG:
1391 case L_VERIFY_VOLUME_TO_CATALOG:
1392 if (!open_sd_read_session(jcr)) {
1395 start_dir_heartbeat(jcr);
1396 do_verify_volume(jcr);
1397 stop_dir_heartbeat(jcr);
1399 * Send Close session command to Storage daemon
1401 bnet_fsend(sd, read_close, jcr->Ticket);
1402 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1404 /* ****FIXME**** check response */
1405 bget_msg(sd); /* get OK */
1407 /* Inform Storage daemon that we are done */
1408 bnet_sig(sd, BNET_TERMINATE);
1411 case L_VERIFY_DISK_TO_CATALOG:
1415 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1419 bnet_sig(dir, BNET_EOD);
1421 /* Send termination status back to Dir */
1422 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1423 edit_uint64(jcr->ReadBytes, ed1),
1424 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1426 /* Inform Director that we are done */
1427 bnet_sig(dir, BNET_TERMINATE);
1428 return 0; /* return and terminate command loop */
1432 * Do a Restore for Director
1435 static int restore_cmd(JCR *jcr)
1437 BSOCK *dir = jcr->dir_bsock;
1438 BSOCK *sd = jcr->store_bsock;
1442 char ed1[50], ed2[50];
1445 * Scan WHERE (base directory for restore) from command
1447 Dmsg0(150, "restore command\n");
1448 /* Pickup where string */
1449 where = get_memory(dir->msglen+1);
1452 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1453 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1454 pm_strcpy(jcr->errmsg, dir->msg);
1455 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1460 /* Turn / into nothing */
1461 if (where[0] == '/' && where[1] == 0) {
1465 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1466 unbash_spaces(where);
1467 jcr->where = bstrdup(where);
1468 free_pool_memory(where);
1469 jcr->replace = replace;
1470 jcr->prefix_links = prefix_links;
1472 bnet_fsend(dir, OKrestore);
1473 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1475 jcr->JobType = JT_RESTORE;
1477 set_jcr_job_status(jcr, JS_Blocked);
1479 if (!open_sd_read_session(jcr)) {
1480 set_jcr_job_status(jcr, JS_ErrorTerminated);
1484 set_jcr_job_status(jcr, JS_Running);
1487 * Do restore of files and data
1489 start_dir_heartbeat(jcr);
1490 generate_daemon_event(jcr, "JobStart");
1492 stop_dir_heartbeat(jcr);
1494 set_jcr_job_status(jcr, JS_Terminated);
1495 if (jcr->JobStatus != JS_Terminated) {
1496 bnet_suppress_error_messages(sd, 1);
1500 * Send Close session command to Storage daemon
1502 bnet_fsend(sd, read_close, jcr->Ticket);
1503 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1505 bget_msg(sd); /* get OK */
1507 /* Inform Storage daemon that we are done */
1508 bnet_sig(sd, BNET_TERMINATE);
1513 set_jcr_job_status(jcr, JS_ErrorTerminated);
1515 /* Send termination status back to Dir */
1516 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1517 edit_uint64(jcr->ReadBytes, ed1),
1518 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1520 /* Inform Director that we are done */
1521 bnet_sig(dir, BNET_TERMINATE);
1523 Dmsg0(130, "Done in job.c\n");
1524 return 0; /* return and terminate command loop */
1527 static int open_sd_read_session(JCR *jcr)
1529 BSOCK *sd = jcr->store_bsock;
1532 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1535 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1536 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1537 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1539 * Open Read Session with Storage daemon
1541 bnet_fsend(sd, read_open, "DummyVolume",
1542 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1543 jcr->StartBlock, jcr->EndBlock);
1544 Dmsg1(110, ">stored: %s", sd->msg);
1549 if (bget_msg(sd) >= 0) {
1550 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1551 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1552 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1555 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1557 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1561 if (!send_bootstrap_file(jcr)) {
1566 * Start read of data with Storage daemon
1568 bnet_fsend(sd, read_data, jcr->Ticket);
1569 Dmsg1(110, ">stored: %s", sd->msg);
1574 if (!response(jcr, sd, OK_data, "Read Data")) {
1581 * Destroy the Job Control Record and associated
1582 * resources (sockets).
1584 static void filed_free_jcr(JCR *jcr)
1586 if (jcr->store_bsock) {
1587 bnet_close(jcr->store_bsock);
1589 free_bootstrap(jcr);
1590 if (jcr->last_fname) {
1591 free_pool_memory(jcr->last_fname);
1593 if (jcr->RunAfterJob) {
1594 free_pool_memory(jcr->RunAfterJob);
1602 * Get response from Storage daemon to a command we
1603 * sent. Check that the response is OK.
1605 * Returns: 0 on failure
1608 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1613 if (bget_msg(sd) > 0) {
1614 Dmsg0(110, sd->msg);
1615 if (strcmp(sd->msg, resp) == 0) {
1619 if (job_canceled(jcr)) {
1620 return 0; /* if canceled avoid useless error messages */
1622 if (is_bnet_error(sd)) {
1623 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1624 cmd, bnet_strerror(sd));
1626 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1627 cmd, resp, sd->msg);
1632 static int send_bootstrap_file(JCR *jcr)
1636 BSOCK *sd = jcr->store_bsock;
1637 const char *bootstrap = "bootstrap\n";
1640 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1641 if (!jcr->RestoreBootstrap) {
1644 bs = fopen(jcr->RestoreBootstrap, "r");
1647 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1648 jcr->RestoreBootstrap, be.strerror());
1649 set_jcr_job_status(jcr, JS_ErrorTerminated);
1652 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1654 while (fgets(buf, sizeof(buf), bs)) {
1655 sd->msglen = Mmsg(sd->msg, "%s", buf);
1658 bnet_sig(sd, BNET_EOD);
1660 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1661 set_jcr_job_status(jcr, JS_ErrorTerminated);
1667 free_bootstrap(jcr);