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) {
331 cjcr->store_bsock->timed_out = 1;
332 cjcr->store_bsock->terminated = 1;
333 #if !defined(HAVE_CYGWIN)
334 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;
870 /* Old director did not specify SHA variant */
871 fo->flags |= FO_SHA1;
874 fo->flags |= FO_SHA1;
879 fo->flags |= FO_SHA256;
883 fo->flags |= FO_SHA512;
888 /* Automatically downgrade to SHA-1 if an unsupported
889 * SHA variant is specified */
890 fo->flags |= FO_SHA1;
896 fo->flags |= FO_SPARSE;
899 fo->flags |= FO_MTIMEONLY;
902 fo->flags |= FO_KEEPATIME;
907 case 'V': /* verify options */
908 /* Copy Verify Options */
909 for (j=0; *p && *p != ':'; p++) {
910 fo->VerifyOpts[j] = *p;
911 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
915 fo->VerifyOpts[j] = 0;
918 fo->flags |= FO_IF_NEWER;
920 case 'Z': /* gzip compression */
921 fo->flags |= FO_GZIP;
922 fo->GZIP_level = *++p - '0';
923 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
926 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
934 * Director is passing his Fileset
936 static int fileset_cmd(JCR *jcr)
938 BSOCK *dir = jcr->dir_bsock;
941 sscanf(dir->msg, "fileset vss=%d", &vss);
944 if (!init_fileset(jcr)) {
947 while (bnet_recv(dir) >= 0) {
948 strip_trailing_junk(dir->msg);
949 Dmsg1(400, "Fileset: %s\n", dir->msg);
950 add_fileset(jcr, dir->msg);
952 if (!term_fileset(jcr)) {
955 return bnet_fsend(dir, OKinc);
958 static void free_bootstrap(JCR *jcr)
960 if (jcr->RestoreBootstrap) {
961 unlink(jcr->RestoreBootstrap);
962 free_pool_memory(jcr->RestoreBootstrap);
963 jcr->RestoreBootstrap = NULL;
969 * The Director sends us the bootstrap file, which
970 * we will in turn pass to the SD.
972 static int bootstrap_cmd(JCR *jcr)
974 BSOCK *dir = jcr->dir_bsock;
975 POOLMEM *fname = get_pool_memory(PM_FNAME);
979 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
981 Dmsg1(400, "bootstrap=%s\n", fname);
982 jcr->RestoreBootstrap = fname;
983 bs = fopen(fname, "a+"); /* create file */
986 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
987 jcr->RestoreBootstrap, be.strerror());
989 * Suck up what he is sending to us so that he will then
990 * read our error message.
992 while (bnet_recv(dir) >= 0)
995 set_jcr_job_status(jcr, JS_ErrorTerminated);
999 while (bnet_recv(dir) >= 0) {
1000 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1001 fputs(dir->msg, bs);
1005 * Note, do not free the bootstrap yet -- it needs to be
1008 return bnet_fsend(dir, OKbootstrap);
1013 * Get backup level from Director
1016 static int level_cmd(JCR *jcr)
1018 BSOCK *dir = jcr->dir_bsock;
1019 POOLMEM *level, *buf = NULL;
1022 level = get_memory(dir->msglen+1);
1023 Dmsg1(110, "level_cmd: %s", dir->msg);
1024 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1027 /* Base backup requested? */
1028 if (strcmp(level, "base") == 0) {
1029 jcr->JobLevel = L_BASE;
1030 /* Full backup requested? */
1031 } else if (strcmp(level, "full") == 0) {
1032 jcr->JobLevel = L_FULL;
1033 } else if (strcmp(level, "differential") == 0) {
1034 jcr->JobLevel = L_DIFFERENTIAL;
1037 } else if (strcmp(level, "incremental") == 0) {
1038 jcr->JobLevel = L_INCREMENTAL;
1042 * We get his UTC since time, then sync the clocks and correct it
1043 * to agree with our clock.
1045 } else if (strcmp(level, "since_utime") == 0) {
1046 buf = get_memory(dir->msglen+1);
1047 utime_t since_time, adj;
1048 btime_t his_time, bt_start, rt=0, bt_adj=0;
1049 if (jcr->JobLevel == L_NONE) {
1050 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1052 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1053 buf, &mtime_only) != 2) {
1056 since_time = str_to_uint64(buf); /* this is the since time */
1057 char ed1[50], ed2[50];
1059 * Sync clocks by polling him for the time. We take
1060 * 10 samples of his time throwing out the first two.
1062 for (int i=0; i<10; i++) {
1063 bt_start = get_current_btime();
1064 bnet_sig(dir, BNET_BTIME); /* poll for time */
1065 if (bnet_recv(dir) <= 0) { /* get response */
1068 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1071 if (i < 2) { /* toss first two results */
1074 his_time = str_to_uint64(buf);
1075 rt = get_current_btime() - bt_start; /* compute round trip time */
1076 bt_adj -= his_time - bt_start - rt/2;
1077 Dmsg2(200, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1080 bt_adj = bt_adj / 8; /* compute average time */
1081 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1082 adj = btime_to_utime(bt_adj);
1083 since_time += adj; /* adjust for clock difference */
1085 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1087 bnet_sig(dir, BNET_EOD);
1089 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1090 jcr->incremental = 1; /* set incremental or decremental backup */
1091 jcr->mtime = (time_t)since_time; /* set since time */
1093 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1101 return bnet_fsend(dir, OKlevel);
1104 pm_strcpy(jcr->errmsg, dir->msg);
1105 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1114 * Get session parameters from Director -- this is for a Restore command
1116 static int session_cmd(JCR *jcr)
1118 BSOCK *dir = jcr->dir_bsock;
1120 Dmsg1(100, "SessionCmd: %s", dir->msg);
1121 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1122 &jcr->VolSessionId, &jcr->VolSessionTime,
1123 &jcr->StartFile, &jcr->EndFile,
1124 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1125 pm_strcpy(jcr->errmsg, dir->msg);
1126 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1130 return bnet_fsend(dir, OKsession);
1134 * Get address of storage daemon from Director
1137 static int storage_cmd(JCR *jcr)
1139 int stored_port; /* storage daemon port */
1140 int enable_ssl; /* enable ssl to sd */
1141 BSOCK *dir = jcr->dir_bsock;
1142 BSOCK *sd; /* storage daemon bsock */
1144 Dmsg1(100, "StorageCmd: %s", dir->msg);
1145 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1146 pm_strcpy(jcr->errmsg, dir->msg);
1147 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1150 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1151 /* Open command communications with Storage daemon */
1152 /* Try to connect for 1 hour at 10 second intervals */
1153 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1154 jcr->stored_addr, NULL, stored_port, 1);
1156 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1157 jcr->stored_addr, stored_port);
1158 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1159 jcr->stored_addr, stored_port);
1162 Dmsg0(110, "Connection OK to SD.\n");
1164 jcr->store_bsock = sd;
1166 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1167 if (!authenticate_storagedaemon(jcr)) {
1168 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1171 Dmsg0(110, "Authenticated with SD.\n");
1173 /* Send OK to Director */
1174 return bnet_fsend(dir, OKstore);
1179 * Do a backup. For now, we handle only Full and Incremental.
1181 static int backup_cmd(JCR *jcr)
1183 BSOCK *dir = jcr->dir_bsock;
1184 BSOCK *sd = jcr->store_bsock;
1187 char ed1[50], ed2[50];
1189 set_jcr_job_status(jcr, JS_Blocked);
1190 jcr->JobType = JT_BACKUP;
1191 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1194 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1198 bnet_fsend(dir, OKbackup);
1199 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1202 * Send Append Open Session to Storage daemon
1204 bnet_fsend(sd, append_open);
1205 Dmsg1(110, ">stored: %s", sd->msg);
1207 * Expect to receive back the Ticket number
1209 if (bget_msg(sd) >= 0) {
1210 Dmsg1(110, "<stored: %s", sd->msg);
1211 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1212 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1215 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1217 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1222 * Send Append data command to Storage daemon
1224 bnet_fsend(sd, append_data, jcr->Ticket);
1225 Dmsg1(110, ">stored: %s", sd->msg);
1228 * Expect to get OK data
1230 Dmsg1(110, "<stored: %s", sd->msg);
1231 if (!response(jcr, sd, OK_data, "Append Data")) {
1235 generate_daemon_event(jcr, "JobStart");
1238 /* START VSS ON WIN 32 */
1239 if (g_pVSSClient && enable_vss) {
1240 if (g_pVSSClient->InitializeForBackup()) {
1241 /* tell vss which drives to snapshot */
1242 char szWinDriveLetters[27];
1243 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1244 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1245 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1247 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed. ERR=%s\n"),
1250 /* tell user if snapshot creation of a specific drive failed */
1252 for (i=0; i<strlen (szWinDriveLetters); i++) {
1253 if (islower(szWinDriveLetters[i])) {
1254 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed\n"), szWinDriveLetters[i]);
1257 /* inform user about writer states */
1258 for (i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1259 int msg_type = M_INFO;
1260 if (g_pVSSClient->GetWriterState(i) < 0) {
1261 msg_type = M_WARNING;
1263 Jmsg(jcr, msg_type, 0, _("VSS Writer: %s\n"), g_pVSSClient->GetWriterInfo(i));
1267 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1270 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled.\n"));
1276 * Send Files to Storage daemon
1278 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1279 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1280 set_jcr_job_status(jcr, JS_ErrorTerminated);
1281 bnet_suppress_error_messages(sd, 1);
1282 bget_msg(sd); /* Read final response from append_data */
1283 Dmsg0(110, "Error in blast_data.\n");
1285 set_jcr_job_status(jcr, JS_Terminated);
1286 if (jcr->JobStatus != JS_Terminated) {
1287 bnet_suppress_error_messages(sd, 1);
1288 goto cleanup; /* bail out now */
1291 * Expect to get response to append_data from Storage daemon
1293 if (!response(jcr, sd, OK_append, "Append Data")) {
1294 set_jcr_job_status(jcr, JS_ErrorTerminated);
1299 * Send Append End Data to Storage daemon
1301 bnet_fsend(sd, append_end, jcr->Ticket);
1303 if (!response(jcr, sd, OK_end, "Append End")) {
1304 set_jcr_job_status(jcr, JS_ErrorTerminated);
1309 * Send Append Close to Storage daemon
1311 bnet_fsend(sd, append_close, jcr->Ticket);
1312 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1313 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1315 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1319 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1322 if (SDJobStatus != JS_Terminated) {
1323 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1330 /* STOP VSS ON WIN 32 */
1331 /* tell vss to close the backup session */
1332 if (g_pVSSClient && enable_vss == 1)
1333 g_pVSSClient->CloseBackup();
1336 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1337 edit_uint64(jcr->ReadBytes, ed1),
1338 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1339 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1341 return 0; /* return and stop command loop */
1345 * Do a Verify for Director
1348 static int verify_cmd(JCR *jcr)
1350 BSOCK *dir = jcr->dir_bsock;
1351 BSOCK *sd = jcr->store_bsock;
1352 char level[100], ed1[50], ed2[50];
1354 jcr->JobType = JT_VERIFY;
1355 if (sscanf(dir->msg, verifycmd, level) != 1) {
1356 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1360 if (strcasecmp(level, "init") == 0) {
1361 jcr->JobLevel = L_VERIFY_INIT;
1362 } else if (strcasecmp(level, "catalog") == 0){
1363 jcr->JobLevel = L_VERIFY_CATALOG;
1364 } else if (strcasecmp(level, "volume") == 0){
1365 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1366 } else if (strcasecmp(level, "data") == 0){
1367 jcr->JobLevel = L_VERIFY_DATA;
1368 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1369 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1371 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1375 bnet_fsend(dir, OKverify);
1377 generate_daemon_event(jcr, "JobStart");
1379 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1381 switch (jcr->JobLevel) {
1383 case L_VERIFY_CATALOG:
1386 case L_VERIFY_VOLUME_TO_CATALOG:
1387 if (!open_sd_read_session(jcr)) {
1390 start_dir_heartbeat(jcr);
1391 do_verify_volume(jcr);
1392 stop_dir_heartbeat(jcr);
1394 * Send Close session command to Storage daemon
1396 bnet_fsend(sd, read_close, jcr->Ticket);
1397 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1399 /* ****FIXME**** check response */
1400 bget_msg(sd); /* get OK */
1402 /* Inform Storage daemon that we are done */
1403 bnet_sig(sd, BNET_TERMINATE);
1406 case L_VERIFY_DISK_TO_CATALOG:
1410 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1414 bnet_sig(dir, BNET_EOD);
1416 /* Send termination status back to Dir */
1417 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1418 edit_uint64(jcr->ReadBytes, ed1),
1419 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1421 /* Inform Director that we are done */
1422 bnet_sig(dir, BNET_TERMINATE);
1423 return 0; /* return and terminate command loop */
1427 * Do a Restore for Director
1430 static int restore_cmd(JCR *jcr)
1432 BSOCK *dir = jcr->dir_bsock;
1433 BSOCK *sd = jcr->store_bsock;
1437 char ed1[50], ed2[50];
1440 * Scan WHERE (base directory for restore) from command
1442 Dmsg0(150, "restore command\n");
1443 /* Pickup where string */
1444 where = get_memory(dir->msglen+1);
1447 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1448 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1449 pm_strcpy(jcr->errmsg, dir->msg);
1450 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1455 /* Turn / into nothing */
1456 if (where[0] == '/' && where[1] == 0) {
1460 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1461 unbash_spaces(where);
1462 jcr->where = bstrdup(where);
1463 free_pool_memory(where);
1464 jcr->replace = replace;
1465 jcr->prefix_links = prefix_links;
1467 bnet_fsend(dir, OKrestore);
1468 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1470 jcr->JobType = JT_RESTORE;
1472 set_jcr_job_status(jcr, JS_Blocked);
1474 if (!open_sd_read_session(jcr)) {
1475 set_jcr_job_status(jcr, JS_ErrorTerminated);
1479 set_jcr_job_status(jcr, JS_Running);
1482 * Do restore of files and data
1484 start_dir_heartbeat(jcr);
1485 generate_daemon_event(jcr, "JobStart");
1487 stop_dir_heartbeat(jcr);
1489 set_jcr_job_status(jcr, JS_Terminated);
1490 if (jcr->JobStatus != JS_Terminated) {
1491 bnet_suppress_error_messages(sd, 1);
1495 * Send Close session command to Storage daemon
1497 bnet_fsend(sd, read_close, jcr->Ticket);
1498 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1500 bget_msg(sd); /* get OK */
1502 /* Inform Storage daemon that we are done */
1503 bnet_sig(sd, BNET_TERMINATE);
1508 set_jcr_job_status(jcr, JS_ErrorTerminated);
1510 /* Send termination status back to Dir */
1511 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1512 edit_uint64(jcr->ReadBytes, ed1),
1513 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1515 /* Inform Director that we are done */
1516 bnet_sig(dir, BNET_TERMINATE);
1518 Dmsg0(130, "Done in job.c\n");
1519 return 0; /* return and terminate command loop */
1522 static int open_sd_read_session(JCR *jcr)
1524 BSOCK *sd = jcr->store_bsock;
1527 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1530 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1531 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1532 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1534 * Open Read Session with Storage daemon
1536 bnet_fsend(sd, read_open, "DummyVolume",
1537 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1538 jcr->StartBlock, jcr->EndBlock);
1539 Dmsg1(110, ">stored: %s", sd->msg);
1544 if (bget_msg(sd) >= 0) {
1545 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1546 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1547 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1550 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1552 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1556 if (!send_bootstrap_file(jcr)) {
1561 * Start read of data with Storage daemon
1563 bnet_fsend(sd, read_data, jcr->Ticket);
1564 Dmsg1(110, ">stored: %s", sd->msg);
1569 if (!response(jcr, sd, OK_data, "Read Data")) {
1576 * Destroy the Job Control Record and associated
1577 * resources (sockets).
1579 static void filed_free_jcr(JCR *jcr)
1581 if (jcr->store_bsock) {
1582 bnet_close(jcr->store_bsock);
1584 free_bootstrap(jcr);
1585 if (jcr->last_fname) {
1586 free_pool_memory(jcr->last_fname);
1588 if (jcr->RunAfterJob) {
1589 free_pool_memory(jcr->RunAfterJob);
1597 * Get response from Storage daemon to a command we
1598 * sent. Check that the response is OK.
1600 * Returns: 0 on failure
1603 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1608 if (bget_msg(sd) > 0) {
1609 Dmsg0(110, sd->msg);
1610 if (strcmp(sd->msg, resp) == 0) {
1614 if (job_canceled(jcr)) {
1615 return 0; /* if canceled avoid useless error messages */
1617 if (is_bnet_error(sd)) {
1618 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1619 cmd, bnet_strerror(sd));
1621 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1622 cmd, resp, sd->msg);
1627 static int send_bootstrap_file(JCR *jcr)
1631 BSOCK *sd = jcr->store_bsock;
1632 const char *bootstrap = "bootstrap\n";
1635 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1636 if (!jcr->RestoreBootstrap) {
1639 bs = fopen(jcr->RestoreBootstrap, "r");
1642 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1643 jcr->RestoreBootstrap, be.strerror());
1644 set_jcr_job_status(jcr, JS_ErrorTerminated);
1647 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1649 while (fgets(buf, sizeof(buf), bs)) {
1650 sd->msglen = Mmsg(sd->msg, "%s", buf);
1653 bnet_sig(sd, BNET_EOD);
1655 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1656 set_jcr_job_status(jcr, JS_ErrorTerminated);
1662 free_bootstrap(jcr);