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.
28 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 extern char my_name[];
32 extern CLIENT *me; /* our client resource */
34 int enable_vss = 0; /* set to use vss */
36 /* Imported functions */
37 extern int status_cmd(JCR *jcr);
38 extern int qstatus_cmd(JCR *jcr);
40 /* Forward referenced functions */
41 static int backup_cmd(JCR *jcr);
42 static int bootstrap_cmd(JCR *jcr);
43 static int cancel_cmd(JCR *jcr);
44 static int setdebug_cmd(JCR *jcr);
45 static int estimate_cmd(JCR *jcr);
46 static int hello_cmd(JCR *jcr);
47 static int job_cmd(JCR *jcr);
48 static int fileset_cmd(JCR *jcr);
49 static int level_cmd(JCR *jcr);
50 static int verify_cmd(JCR *jcr);
51 static int restore_cmd(JCR *jcr);
52 static int storage_cmd(JCR *jcr);
53 static int session_cmd(JCR *jcr);
54 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
55 static void filed_free_jcr(JCR *jcr);
56 static int open_sd_read_session(JCR *jcr);
57 static int send_bootstrap_file(JCR *jcr);
58 static int runscript_cmd(JCR *jcr);
59 static int runbefore_cmd(JCR *jcr);
60 static int runafter_cmd(JCR *jcr);
61 static int runbeforenow_cmd(JCR *jcr);
62 static void set_options(findFOPTS *fo, const char *opts);
65 /* Exported functions */
70 int monitoraccess; /* specify if monitors have access to this function */
74 * The following are the recognized commands from the Director.
76 static struct s_cmds cmds[] = {
77 {"backup", backup_cmd, 0},
78 {"cancel", cancel_cmd, 0},
79 {"setdebug=", setdebug_cmd, 0},
80 {"estimate", estimate_cmd, 0},
81 {"Hello", hello_cmd, 1},
82 {"fileset", fileset_cmd, 0},
83 {"JobId=", job_cmd, 0},
84 {"level = ", level_cmd, 0},
85 {"restore", restore_cmd, 0},
86 {"session", session_cmd, 0},
87 {"status", status_cmd, 1},
88 {".status", qstatus_cmd, 1},
89 {"storage ", storage_cmd, 0},
90 {"verify", verify_cmd, 0},
91 {"bootstrap", bootstrap_cmd, 0},
92 {"RunBeforeNow", runbeforenow_cmd, 0},
93 {"RunBeforeJob", runbefore_cmd, 0},
94 {"RunAfterJob", runafter_cmd, 0},
95 {"Run", runscript_cmd, 0},
96 {NULL, NULL} /* list terminator */
99 /* Commands received from director that need scanning */
100 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
101 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
102 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
103 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
104 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
105 static char verifycmd[] = "verify level=%30s\n";
106 static char estimatecmd[] = "estimate listing=%d\n";
107 static char runbefore[] = "RunBeforeJob %s\n";
108 static char runafter[] = "RunAfterJob %s\n";
109 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
110 /* Responses sent to Director */
111 static char errmsg[] = "2999 Invalid command\n";
112 static char no_auth[] = "2998 No Authorization\n";
113 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
114 static char OKinc[] = "2000 OK include\n";
115 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
116 static char OKlevel[] = "2000 OK level\n";
117 static char OKbackup[] = "2000 OK backup\n";
118 static char OKbootstrap[] = "2000 OK bootstrap\n";
119 static char OKverify[] = "2000 OK verify\n";
120 static char OKrestore[] = "2000 OK restore\n";
121 static char OKsession[] = "2000 OK session\n";
122 static char OKstore[] = "2000 OK storage\n";
123 static char OKjob[] = "2000 OK Job %s,%s,%s";
124 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
125 static char BADjob[] = "2901 Bad Job\n";
126 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
127 static char OKRunBefore[] = "2000 OK RunBefore\n";
128 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
129 static char OKRunAfter[] = "2000 OK RunAfter\n";
130 static char OKRunScript[] = "2000 OK RunScript\n";
133 /* Responses received from Storage Daemon */
134 static char OK_end[] = "3000 OK end\n";
135 static char OK_close[] = "3000 OK close Status = %d\n";
136 static char OK_open[] = "3000 OK open ticket = %d\n";
137 static char OK_data[] = "3000 OK data\n";
138 static char OK_append[] = "3000 OK append data\n";
139 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
142 /* Commands sent to Storage Daemon */
143 static char append_open[] = "append open session\n";
144 static char append_data[] = "append data %d\n";
145 static char append_end[] = "append end session %d\n";
146 static char append_close[] = "append close session %d\n";
147 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
148 static char read_data[] = "read data %d\n";
149 static char read_close[] = "read close session %d\n";
152 * Accept requests from a Director
154 * NOTE! We are running as a separate thread
156 * Send output one line
157 * at a time followed by a zero length transmission.
159 * Return when the connection is terminated or there
162 * Basic task here is:
163 * Authenticate Director (during Hello command).
164 * Accept commands one at a time from the Director
168 void *handle_client_request(void *dirp)
173 BSOCK *dir = (BSOCK *)dirp;
175 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
176 jcr->dir_bsock = dir;
177 jcr->ff = init_find_files();
178 jcr->start_time = time(NULL);
179 jcr->RunScripts = New(alist(10, not_owned_by_alist));
180 jcr->last_fname = get_pool_memory(PM_FNAME);
181 jcr->last_fname[0] = 0;
182 jcr->client_name = get_memory(strlen(my_name) + 1);
183 pm_strcpy(jcr->client_name, my_name);
184 jcr->pki_sign = me->pki_sign;
185 jcr->pki_encrypt = me->pki_encrypt;
186 jcr->pki_keypair = me->pki_keypair;
187 jcr->pki_signers = me->pki_signers;
188 jcr->pki_recipients = me->pki_recipients;
190 enable_backup_privileges(NULL, 1 /* ignore_errors */);
192 /**********FIXME******* add command handler error code */
194 for (quit=false; !quit;) {
197 if (bnet_recv(dir) < 0) {
198 break; /* connection terminated */
200 dir->msg[dir->msglen] = 0;
201 Dmsg1(100, "<dird: %s", dir->msg);
203 for (i=0; cmds[i].cmd; i++) {
204 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
205 found = true; /* indicate command found */
206 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
207 bnet_fsend(dir, no_auth);
208 bnet_sig(dir, BNET_EOD);
211 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
212 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
213 bnet_fsend(dir, illegal_cmd);
214 bnet_sig(dir, BNET_EOD);
217 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
218 if (!cmds[i].func(jcr)) { /* do command */
219 quit = true; /* error or fully terminated, get out */
220 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
225 if (!found) { /* command not found */
226 bnet_fsend(dir, errmsg);
232 /* Inform Storage daemon that we are done */
233 if (jcr->store_bsock) {
234 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
238 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
240 generate_daemon_event(jcr, "JobEnd");
242 dequeue_messages(jcr); /* send any queued messages */
244 /* Inform Director that we are done */
245 bnet_sig(dir, BNET_TERMINATE);
247 /* Clean up fileset */
248 FF_PKT *ff = jcr->ff;
249 findFILESET *fileset = ff->fileset;
252 /* Delete FileSet Include lists */
253 for (i=0; i<fileset->include_list.size(); i++) {
254 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
255 for (j=0; j<incexe->opts_list.size(); j++) {
256 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
257 for (k=0; k<fo->regex.size(); k++) {
258 regfree((regex_t *)fo->regex.get(k));
261 fo->regexdir.destroy();
262 fo->regexfile.destroy();
264 fo->wilddir.destroy();
265 fo->wildfile.destroy();
267 fo->fstype.destroy();
275 incexe->opts_list.destroy();
276 incexe->name_list.destroy();
278 fileset->include_list.destroy();
280 /* Delete FileSet Exclude lists */
281 for (i=0; i<fileset->exclude_list.size(); i++) {
282 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
283 for (j=0; j<incexe->opts_list.size(); j++) {
284 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
286 fo->regexdir.destroy();
287 fo->regexfile.destroy();
289 fo->wilddir.destroy();
290 fo->wildfile.destroy();
292 fo->fstype.destroy();
294 incexe->opts_list.destroy();
295 incexe->name_list.destroy();
297 fileset->exclude_list.destroy();
301 Dmsg0(100, "Calling term_find_files\n");
302 term_find_files(jcr->ff);
304 Dmsg0(100, "Done with term_find_files\n");
305 free_jcr(jcr); /* destroy JCR record */
306 Dmsg0(100, "Done with free_jcr\n");
311 * Hello from Director he must identify himself and provide his
314 static int hello_cmd(JCR *jcr)
316 Dmsg0(120, "Calling Authenticate\n");
317 if (!authenticate_director(jcr)) {
320 Dmsg0(120, "OK Authenticate\n");
321 jcr->authenticated = true;
328 static int cancel_cmd(JCR *jcr)
330 BSOCK *dir = jcr->dir_bsock;
331 char Job[MAX_NAME_LENGTH];
334 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
335 if (!(cjcr=get_jcr_by_full_name(Job))) {
336 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
338 if (cjcr->store_bsock) {
339 cjcr->store_bsock->timed_out = 1;
340 cjcr->store_bsock->terminated = 1;
341 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
343 set_jcr_job_status(cjcr, JS_Canceled);
345 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
348 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
350 bnet_sig(dir, BNET_EOD);
356 * Set debug level as requested by the Director
359 static int setdebug_cmd(JCR *jcr)
361 BSOCK *dir = jcr->dir_bsock;
362 int level, trace_flag;
364 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
365 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
366 pm_strcpy(jcr->errmsg, dir->msg);
367 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
371 set_trace(trace_flag);
372 return bnet_fsend(dir, OKsetdebug, level);
376 static int estimate_cmd(JCR *jcr)
378 BSOCK *dir = jcr->dir_bsock;
381 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
382 pm_strcpy(jcr->errmsg, dir->msg);
383 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
384 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
388 bnet_fsend(dir, OKest, jcr->num_files_examined,
389 edit_uint64_with_commas(jcr->JobBytes, ed2));
390 bnet_sig(dir, BNET_EOD);
395 * Get JobId and Storage Daemon Authorization key from Director
397 static int job_cmd(JCR *jcr)
399 BSOCK *dir = jcr->dir_bsock;
400 POOLMEM *sd_auth_key;
402 sd_auth_key = get_memory(dir->msglen);
403 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
404 &jcr->VolSessionId, &jcr->VolSessionTime,
406 pm_strcpy(jcr->errmsg, dir->msg);
407 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
408 bnet_fsend(dir, BADjob);
409 free_pool_memory(sd_auth_key);
412 jcr->sd_auth_key = bstrdup(sd_auth_key);
413 free_pool_memory(sd_auth_key);
414 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
415 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
418 static int runbefore_cmd(JCR *jcr)
421 BSOCK *dir = jcr->dir_bsock;
422 POOLMEM *cmd = get_memory(dir->msglen+1);
425 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
426 if (sscanf(dir->msg, runbefore, cmd) != 1) {
427 pm_strcpy(jcr->errmsg, dir->msg);
428 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
429 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
435 /* Run the command now */
436 script = new_runscript();
437 script->set_command(cmd);
438 script->when = SCRIPT_Before;
439 ok = script->run(jcr, "ClientRunBeforeJob");
440 free_runscript(script);
444 bnet_fsend(dir, OKRunBefore);
447 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
452 static int runbeforenow_cmd(JCR *jcr)
454 BSOCK *dir = jcr->dir_bsock;
456 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
457 return bnet_fsend(dir, OKRunBeforeNow);
460 static int runafter_cmd(JCR *jcr)
462 BSOCK *dir = jcr->dir_bsock;
463 POOLMEM *msg = get_memory(dir->msglen+1);
466 Dmsg1(100, "runafter_cmd: %s", dir->msg);
467 if (sscanf(dir->msg, runafter, msg) != 1) {
468 pm_strcpy(jcr->errmsg, dir->msg);
469 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
470 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
476 cmd = new_runscript();
477 cmd->set_command(msg);
478 cmd->on_success = true;
479 cmd->on_failure = false;
480 cmd->when = SCRIPT_After;
482 jcr->RunScripts->append(cmd);
484 free_pool_memory(msg);
485 return bnet_fsend(dir, OKRunAfter);
488 static int runscript_cmd(JCR *jcr)
490 BSOCK *dir = jcr->dir_bsock;
491 POOLMEM *msg = get_memory(dir->msglen+1);
493 RUNSCRIPT *cmd = new_runscript() ;
495 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
496 if (sscanf(dir->msg, runscript, &cmd->on_success,
498 &cmd->abort_on_error,
501 pm_strcpy(jcr->errmsg, dir->msg);
502 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
503 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
510 cmd->set_command(msg);
512 jcr->RunScripts->append(cmd);
514 free_pool_memory(msg);
515 return bnet_fsend(dir, OKRunScript);
519 static bool init_fileset(JCR *jcr)
522 findFILESET *fileset;
531 fileset = (findFILESET *)malloc(sizeof(findFILESET));
532 memset(fileset, 0, sizeof(findFILESET));
533 ff->fileset = fileset;
534 fileset->state = state_none;
535 fileset->include_list.init(1, true);
536 fileset->exclude_list.init(1, true);
540 static findFOPTS *start_options(FF_PKT *ff)
542 int state = ff->fileset->state;
543 findINCEXE *incexe = ff->fileset->incexe;
545 if (state != state_options) {
546 ff->fileset->state = state_options;
547 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
548 memset(fo, 0, sizeof(findFOPTS));
549 fo->regex.init(1, true);
550 fo->regexdir.init(1, true);
551 fo->regexfile.init(1, true);
552 fo->wild.init(1, true);
553 fo->wilddir.init(1, true);
554 fo->wildfile.init(1, true);
555 fo->base.init(1, true);
556 fo->fstype.init(1, true);
557 incexe->current_opts = fo;
558 incexe->opts_list.append(fo);
560 return incexe->current_opts;
565 * Add fname to include/exclude fileset list. First check for
566 * | and < and if necessary perform command.
568 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
582 p++; /* skip over | */
583 fn = get_pool_memory(PM_FNAME);
584 fn = edit_job_codes(jcr, fn, p, "");
585 bpipe = open_bpipe(fn, 0, "r");
586 free_pool_memory(fn);
588 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
592 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
593 strip_trailing_junk(buf);
594 fileset->incexe->name_list.append(bstrdup(buf));
596 if ((stat=close_bpipe(bpipe)) != 0) {
597 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
598 p, stat, strerror(errno));
603 Dmsg0(100, "Doing < include on client.\n");
604 p++; /* skip over < */
605 if ((ffd = fopen(p, "rb")) == NULL) {
607 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
611 while (fgets(buf, sizeof(buf), ffd)) {
612 strip_trailing_junk(buf);
613 Dmsg1(100, "%s\n", buf);
614 fileset->incexe->name_list.append(bstrdup(buf));
619 fileset->incexe->name_list.append(bstrdup(fname));
625 static void add_fileset(JCR *jcr, const char *item)
627 FF_PKT *ff = jcr->ff;
628 findFILESET *fileset = ff->fileset;
629 int state = fileset->state;
630 findFOPTS *current_opts;
632 /* Get code, optional subcode, and position item past the dividing space */
633 Dmsg1(100, "%s\n", item);
638 int subcode = ' '; /* A space is always a valid subcode */
639 if (item[0] != '\0' && item[0] != ' ') {
647 /* Skip all lines we receive after an error */
648 if (state == state_error) {
653 * The switch tests the code for validity.
654 * The subcode is always good if it is a space, otherwise we must confirm.
655 * We set state to state_error first assuming the subcode is invalid,
656 * requiring state to be set in cases below that handle subcodes.
658 if (subcode != ' ') {
664 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
665 memset(fileset->incexe, 0, sizeof(findINCEXE));
666 fileset->incexe->opts_list.init(1, true);
667 fileset->incexe->name_list.init(1, true);
668 fileset->include_list.append(fileset->incexe);
672 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
673 memset(fileset->incexe, 0, sizeof(findINCEXE));
674 fileset->incexe->opts_list.init(1, true);
675 fileset->incexe->name_list.init(1, true);
676 fileset->exclude_list.append(fileset->incexe);
682 /* File item to either include/include list */
683 state = state_include;
684 add_file_to_fileset(jcr, item, fileset);
687 current_opts = start_options(ff);
691 preg = (regex_t *)malloc(sizeof(regex_t));
692 if (current_opts->flags & FO_IGNORECASE) {
693 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
695 rc = regcomp(preg, item, REG_EXTENDED);
698 regerror(rc, preg, prbuf, sizeof(prbuf));
701 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
705 state = state_options;
706 if (subcode == ' ') {
707 current_opts->regex.append(preg);
708 } else if (subcode == 'D') {
709 current_opts->regexdir.append(preg);
710 } else if (subcode == 'F') {
711 current_opts->regexfile.append(preg);
717 current_opts = start_options(ff);
718 current_opts->base.append(bstrdup(item));
719 state = state_options;
722 current_opts = start_options(ff);
723 current_opts->fstype.append(bstrdup(item));
724 state = state_options;
727 current_opts = start_options(ff);
728 state = state_options;
729 if (subcode == ' ') {
730 current_opts->wild.append(bstrdup(item));
731 } else if (subcode == 'D') {
732 current_opts->wilddir.append(bstrdup(item));
733 } else if (subcode == 'F') {
734 current_opts->wildfile.append(bstrdup(item));
740 current_opts = start_options(ff);
741 set_options(current_opts, item);
742 state = state_options;
745 current_opts = start_options(ff);
746 current_opts->reader = bstrdup(item);
747 state = state_options;
750 current_opts = start_options(ff);
751 current_opts->writer = bstrdup(item);
752 state = state_options;
755 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
759 ff->fileset->state = state;
762 static bool term_fileset(JCR *jcr)
764 FF_PKT *ff = jcr->ff;
767 findFILESET *fileset = ff->fileset;
770 for (i=0; i<fileset->include_list.size(); i++) {
771 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
773 for (j=0; j<incexe->opts_list.size(); j++) {
774 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
775 for (k=0; k<fo->regex.size(); k++) {
776 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
778 for (k=0; k<fo->regexdir.size(); k++) {
779 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
781 for (k=0; k<fo->regexfile.size(); k++) {
782 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
784 for (k=0; k<fo->wild.size(); k++) {
785 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
787 for (k=0; k<fo->wilddir.size(); k++) {
788 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
790 for (k=0; k<fo->wildfile.size(); k++) {
791 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
793 for (k=0; k<fo->base.size(); k++) {
794 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
796 for (k=0; k<fo->fstype.size(); k++) {
797 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
800 Dmsg1(400, "D %s\n", fo->reader);
803 Dmsg1(400, "T %s\n", fo->writer);
806 for (j=0; j<incexe->name_list.size(); j++) {
807 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
810 for (i=0; i<fileset->exclude_list.size(); i++) {
811 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
813 for (j=0; j<incexe->opts_list.size(); j++) {
814 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
815 for (k=0; k<fo->regex.size(); k++) {
816 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
818 for (k=0; k<fo->regexdir.size(); k++) {
819 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
821 for (k=0; k<fo->regexfile.size(); k++) {
822 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
824 for (k=0; k<fo->wild.size(); k++) {
825 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
827 for (k=0; k<fo->wilddir.size(); k++) {
828 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
830 for (k=0; k<fo->wildfile.size(); k++) {
831 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
833 for (k=0; k<fo->base.size(); k++) {
834 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
836 for (k=0; k<fo->fstype.size(); k++) {
837 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
840 for (j=0; j<incexe->name_list.size(); j++) {
841 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
845 return ff->fileset->state != state_error;
850 * As an optimization, we should do this during
851 * "compile" time in filed/job.c, and keep only a bit mask
852 * and the Verify options.
854 static void set_options(findFOPTS *fo, const char *opts)
859 for (p=opts; *p; p++) {
861 case 'a': /* alway replace */
862 case '0': /* no option */
865 fo->flags |= FO_EXCLUDE;
868 fo->flags |= FO_MULTIFS;
870 case 'h': /* no recursion */
871 fo->flags |= FO_NO_RECURSION;
873 case 'H': /* no hard link handling */
874 fo->flags |= FO_NO_HARDLINK;
877 fo->flags |= FO_IGNORECASE;
883 fo->flags |= FO_NOREPLACE;
885 case 'p': /* use portable data format */
886 fo->flags |= FO_PORTABLE;
888 case 'R': /* Resource forks and Finder Info */
889 fo->flags |= FO_HFSPLUS;
890 case 'r': /* read fifo */
891 fo->flags |= FO_READFIFO;
896 /* Old director did not specify SHA variant */
897 fo->flags |= FO_SHA1;
900 fo->flags |= FO_SHA1;
905 fo->flags |= FO_SHA256;
909 fo->flags |= FO_SHA512;
914 /* Automatically downgrade to SHA-1 if an unsupported
915 * SHA variant is specified */
916 fo->flags |= FO_SHA1;
922 fo->flags |= FO_SPARSE;
925 fo->flags |= FO_MTIMEONLY;
928 fo->flags |= FO_KEEPATIME;
933 case 'V': /* verify options */
934 /* Copy Verify Options */
935 for (j=0; *p && *p != ':'; p++) {
936 fo->VerifyOpts[j] = *p;
937 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
941 fo->VerifyOpts[j] = 0;
944 fo->flags |= FO_IF_NEWER;
946 case 'Z': /* gzip compression */
947 fo->flags |= FO_GZIP;
948 fo->GZIP_level = *++p - '0';
949 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
952 fo->flags |= FO_NOATIME;
955 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
963 * Director is passing his Fileset
965 static int fileset_cmd(JCR *jcr)
967 BSOCK *dir = jcr->dir_bsock;
970 sscanf(dir->msg, "fileset vss=%d", &vss);
973 if (!init_fileset(jcr)) {
976 while (bnet_recv(dir) >= 0) {
977 strip_trailing_junk(dir->msg);
978 Dmsg1(500, "Fileset: %s\n", dir->msg);
979 add_fileset(jcr, dir->msg);
981 if (!term_fileset(jcr)) {
984 return bnet_fsend(dir, OKinc);
987 static void free_bootstrap(JCR *jcr)
989 if (jcr->RestoreBootstrap) {
990 unlink(jcr->RestoreBootstrap);
991 free_pool_memory(jcr->RestoreBootstrap);
992 jcr->RestoreBootstrap = NULL;
998 * The Director sends us the bootstrap file, which
999 * we will in turn pass to the SD.
1001 static int bootstrap_cmd(JCR *jcr)
1003 BSOCK *dir = jcr->dir_bsock;
1004 POOLMEM *fname = get_pool_memory(PM_FNAME);
1007 free_bootstrap(jcr);
1008 Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
1010 Dmsg1(400, "bootstrap=%s\n", fname);
1011 jcr->RestoreBootstrap = fname;
1012 bs = fopen(fname, "a+b"); /* create file */
1015 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1016 jcr->RestoreBootstrap, be.strerror());
1018 * Suck up what he is sending to us so that he will then
1019 * read our error message.
1021 while (bnet_recv(dir) >= 0)
1023 free_bootstrap(jcr);
1024 set_jcr_job_status(jcr, JS_ErrorTerminated);
1028 while (bnet_recv(dir) >= 0) {
1029 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1030 fputs(dir->msg, bs);
1034 * Note, do not free the bootstrap yet -- it needs to be
1037 return bnet_fsend(dir, OKbootstrap);
1042 * Get backup level from Director
1045 static int level_cmd(JCR *jcr)
1047 BSOCK *dir = jcr->dir_bsock;
1048 POOLMEM *level, *buf = NULL;
1051 level = get_memory(dir->msglen+1);
1052 Dmsg1(110, "level_cmd: %s", dir->msg);
1053 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1056 /* Base backup requested? */
1057 if (strcmp(level, "base") == 0) {
1058 jcr->JobLevel = L_BASE;
1059 /* Full backup requested? */
1060 } else if (strcmp(level, "full") == 0) {
1061 jcr->JobLevel = L_FULL;
1062 } else if (strcmp(level, "differential") == 0) {
1063 jcr->JobLevel = L_DIFFERENTIAL;
1066 } else if (strcmp(level, "incremental") == 0) {
1067 jcr->JobLevel = L_INCREMENTAL;
1071 * We get his UTC since time, then sync the clocks and correct it
1072 * to agree with our clock.
1074 } else if (strcmp(level, "since_utime") == 0) {
1075 buf = get_memory(dir->msglen+1);
1076 utime_t since_time, adj;
1077 btime_t his_time, bt_start, rt=0, bt_adj=0;
1078 if (jcr->JobLevel == L_NONE) {
1079 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1081 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1082 buf, &mtime_only) != 2) {
1085 since_time = str_to_uint64(buf); /* this is the since time */
1086 Dmsg1(100, "since_time=%d\n", (int)since_time);
1087 char ed1[50], ed2[50];
1089 * Sync clocks by polling him for the time. We take
1090 * 10 samples of his time throwing out the first two.
1092 for (int i=0; i<10; i++) {
1093 bt_start = get_current_btime();
1094 bnet_sig(dir, BNET_BTIME); /* poll for time */
1095 if (bnet_recv(dir) <= 0) { /* get response */
1098 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1101 if (i < 2) { /* toss first two results */
1104 his_time = str_to_uint64(buf);
1105 rt = get_current_btime() - bt_start; /* compute round trip time */
1106 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1107 edit_uint64(bt_start, ed2));
1108 bt_adj += bt_start - his_time - rt/2;
1109 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1112 bt_adj = bt_adj / 8; /* compute average time */
1113 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1114 adj = btime_to_utime(bt_adj);
1115 since_time += adj; /* adjust for clock difference */
1117 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1119 bnet_sig(dir, BNET_EOD);
1121 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1122 jcr->incremental = 1; /* set incremental or decremental backup */
1123 jcr->mtime = (time_t)since_time; /* set since time */
1125 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1133 return bnet_fsend(dir, OKlevel);
1136 pm_strcpy(jcr->errmsg, dir->msg);
1137 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1146 * Get session parameters from Director -- this is for a Restore command
1148 static int session_cmd(JCR *jcr)
1150 BSOCK *dir = jcr->dir_bsock;
1152 Dmsg1(100, "SessionCmd: %s", dir->msg);
1153 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1154 &jcr->VolSessionId, &jcr->VolSessionTime,
1155 &jcr->StartFile, &jcr->EndFile,
1156 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1157 pm_strcpy(jcr->errmsg, dir->msg);
1158 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1162 return bnet_fsend(dir, OKsession);
1166 * Get address of storage daemon from Director
1169 static int storage_cmd(JCR *jcr)
1171 int stored_port; /* storage daemon port */
1172 int enable_ssl; /* enable ssl to sd */
1173 BSOCK *dir = jcr->dir_bsock;
1174 BSOCK *sd; /* storage daemon bsock */
1176 Dmsg1(100, "StorageCmd: %s", dir->msg);
1177 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1178 pm_strcpy(jcr->errmsg, dir->msg);
1179 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1182 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1183 /* Open command communications with Storage daemon */
1184 /* Try to connect for 1 hour at 10 second intervals */
1185 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1186 jcr->stored_addr, NULL, stored_port, 1);
1188 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1189 jcr->stored_addr, stored_port);
1190 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1191 jcr->stored_addr, stored_port);
1194 Dmsg0(110, "Connection OK to SD.\n");
1196 jcr->store_bsock = sd;
1198 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1199 if (!authenticate_storagedaemon(jcr)) {
1200 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1203 Dmsg0(110, "Authenticated with SD.\n");
1205 /* Send OK to Director */
1206 return bnet_fsend(dir, OKstore);
1211 * Do a backup. For now, we handle only Full and Incremental.
1213 static int backup_cmd(JCR *jcr)
1215 BSOCK *dir = jcr->dir_bsock;
1216 BSOCK *sd = jcr->store_bsock;
1219 char ed1[50], ed2[50];
1222 // capture state here, if client is backed up by multiple directors
1223 // and one enables vss and the other does not then enable_vss can change
1224 // between here and where its evaluated after the job completes.
1225 bool bDoVSS = false;
1227 bDoVSS = g_pVSSClient && enable_vss;
1229 /* Run only one at a time */
1233 set_jcr_job_status(jcr, JS_Blocked);
1234 jcr->JobType = JT_BACKUP;
1235 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1238 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1242 bnet_fsend(dir, OKbackup);
1243 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1246 * Send Append Open Session to Storage daemon
1248 bnet_fsend(sd, append_open);
1249 Dmsg1(110, ">stored: %s", sd->msg);
1251 * Expect to receive back the Ticket number
1253 if (bget_msg(sd) >= 0) {
1254 Dmsg1(110, "<stored: %s", sd->msg);
1255 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1256 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1259 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1261 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1266 * Send Append data command to Storage daemon
1268 bnet_fsend(sd, append_data, jcr->Ticket);
1269 Dmsg1(110, ">stored: %s", sd->msg);
1272 * Expect to get OK data
1274 Dmsg1(110, "<stored: %s", sd->msg);
1275 if (!response(jcr, sd, OK_data, "Append Data")) {
1279 generate_daemon_event(jcr, "JobStart");
1282 /* START VSS ON WIN 32 */
1284 if (g_pVSSClient->InitializeForBackup()) {
1285 /* tell vss which drives to snapshot */
1286 char szWinDriveLetters[27];
1287 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1288 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1289 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1290 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1293 /* tell user if snapshot creation of a specific drive failed */
1295 for (i=0; i<strlen (szWinDriveLetters); i++) {
1296 if (islower(szWinDriveLetters[i])) {
1297 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1301 /* inform user about writer states */
1302 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1303 if (g_pVSSClient->GetWriterState(i) < 1) {
1304 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1309 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1313 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1319 * Send Files to Storage daemon
1321 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1322 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1323 set_jcr_job_status(jcr, JS_ErrorTerminated);
1324 bnet_suppress_error_messages(sd, 1);
1325 bget_msg(sd); /* Read final response from append_data */
1326 Dmsg0(110, "Error in blast_data.\n");
1328 set_jcr_job_status(jcr, JS_Terminated);
1330 /* run shortly after end of data transmission */
1331 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1333 if (jcr->JobStatus != JS_Terminated) {
1334 bnet_suppress_error_messages(sd, 1);
1335 goto cleanup; /* bail out now */
1338 * Expect to get response to append_data from Storage daemon
1340 if (!response(jcr, sd, OK_append, "Append Data")) {
1341 set_jcr_job_status(jcr, JS_ErrorTerminated);
1346 * Send Append End Data to Storage daemon
1348 bnet_fsend(sd, append_end, jcr->Ticket);
1350 if (!response(jcr, sd, OK_end, "Append End")) {
1351 set_jcr_job_status(jcr, JS_ErrorTerminated);
1356 * Send Append Close to Storage daemon
1358 bnet_fsend(sd, append_close, jcr->Ticket);
1359 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1360 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1362 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1366 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1369 if (SDJobStatus != JS_Terminated) {
1370 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1377 /* STOP VSS ON WIN 32 */
1378 /* tell vss to close the backup session */
1380 if (g_pVSSClient->CloseBackup()) {
1381 /* inform user about writer states */
1382 for (size_t i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1383 int msg_type = M_INFO;
1384 if (g_pVSSClient->GetWriterState(i) < 1) {
1385 msg_type = M_WARNING;
1388 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1395 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1396 edit_uint64(jcr->ReadBytes, ed1),
1397 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1398 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1400 return 0; /* return and stop command loop */
1404 * Do a Verify for Director
1407 static int verify_cmd(JCR *jcr)
1409 BSOCK *dir = jcr->dir_bsock;
1410 BSOCK *sd = jcr->store_bsock;
1411 char level[100], ed1[50], ed2[50];
1413 jcr->JobType = JT_VERIFY;
1414 if (sscanf(dir->msg, verifycmd, level) != 1) {
1415 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1419 if (strcasecmp(level, "init") == 0) {
1420 jcr->JobLevel = L_VERIFY_INIT;
1421 } else if (strcasecmp(level, "catalog") == 0){
1422 jcr->JobLevel = L_VERIFY_CATALOG;
1423 } else if (strcasecmp(level, "volume") == 0){
1424 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1425 } else if (strcasecmp(level, "data") == 0){
1426 jcr->JobLevel = L_VERIFY_DATA;
1427 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1428 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1430 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1434 bnet_fsend(dir, OKverify);
1436 generate_daemon_event(jcr, "JobStart");
1438 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1440 switch (jcr->JobLevel) {
1442 case L_VERIFY_CATALOG:
1445 case L_VERIFY_VOLUME_TO_CATALOG:
1446 if (!open_sd_read_session(jcr)) {
1449 start_dir_heartbeat(jcr);
1450 do_verify_volume(jcr);
1451 stop_dir_heartbeat(jcr);
1453 * Send Close session command to Storage daemon
1455 bnet_fsend(sd, read_close, jcr->Ticket);
1456 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1458 /* ****FIXME**** check response */
1459 bget_msg(sd); /* get OK */
1461 /* Inform Storage daemon that we are done */
1462 bnet_sig(sd, BNET_TERMINATE);
1465 case L_VERIFY_DISK_TO_CATALOG:
1469 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1473 bnet_sig(dir, BNET_EOD);
1475 /* Send termination status back to Dir */
1476 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1477 edit_uint64(jcr->ReadBytes, ed1),
1478 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1480 /* Inform Director that we are done */
1481 bnet_sig(dir, BNET_TERMINATE);
1482 return 0; /* return and terminate command loop */
1486 * Do a Restore for Director
1489 static int restore_cmd(JCR *jcr)
1491 BSOCK *dir = jcr->dir_bsock;
1492 BSOCK *sd = jcr->store_bsock;
1496 char ed1[50], ed2[50];
1499 * Scan WHERE (base directory for restore) from command
1501 Dmsg0(150, "restore command\n");
1502 /* Pickup where string */
1503 where = get_memory(dir->msglen+1);
1506 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1507 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1508 pm_strcpy(jcr->errmsg, dir->msg);
1509 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1514 /* Turn / into nothing */
1515 if (where[0] == '/' && where[1] == 0) {
1519 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1520 unbash_spaces(where);
1521 jcr->where = bstrdup(where);
1522 free_pool_memory(where);
1523 jcr->replace = replace;
1524 jcr->prefix_links = prefix_links;
1526 bnet_fsend(dir, OKrestore);
1527 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1529 jcr->JobType = JT_RESTORE;
1531 set_jcr_job_status(jcr, JS_Blocked);
1533 if (!open_sd_read_session(jcr)) {
1534 set_jcr_job_status(jcr, JS_ErrorTerminated);
1538 set_jcr_job_status(jcr, JS_Running);
1541 * Do restore of files and data
1543 start_dir_heartbeat(jcr);
1544 generate_daemon_event(jcr, "JobStart");
1546 stop_dir_heartbeat(jcr);
1548 set_jcr_job_status(jcr, JS_Terminated);
1549 if (jcr->JobStatus != JS_Terminated) {
1550 bnet_suppress_error_messages(sd, 1);
1554 * Send Close session command to Storage daemon
1556 bnet_fsend(sd, read_close, jcr->Ticket);
1557 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1559 bget_msg(sd); /* get OK */
1561 /* Inform Storage daemon that we are done */
1562 bnet_sig(sd, BNET_TERMINATE);
1567 set_jcr_job_status(jcr, JS_ErrorTerminated);
1569 /* Send termination status back to Dir */
1570 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1571 edit_uint64(jcr->ReadBytes, ed1),
1572 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1574 /* Inform Director that we are done */
1575 bnet_sig(dir, BNET_TERMINATE);
1577 Dmsg0(130, "Done in job.c\n");
1578 return 0; /* return and terminate command loop */
1581 static int open_sd_read_session(JCR *jcr)
1583 BSOCK *sd = jcr->store_bsock;
1586 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1589 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1590 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1591 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1593 * Open Read Session with Storage daemon
1595 bnet_fsend(sd, read_open, "DummyVolume",
1596 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1597 jcr->StartBlock, jcr->EndBlock);
1598 Dmsg1(110, ">stored: %s", sd->msg);
1603 if (bget_msg(sd) >= 0) {
1604 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1605 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1606 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1609 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1611 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1615 if (!send_bootstrap_file(jcr)) {
1620 * Start read of data with Storage daemon
1622 bnet_fsend(sd, read_data, jcr->Ticket);
1623 Dmsg1(110, ">stored: %s", sd->msg);
1628 if (!response(jcr, sd, OK_data, "Read Data")) {
1635 * Destroy the Job Control Record and associated
1636 * resources (sockets).
1638 static void filed_free_jcr(JCR *jcr)
1640 if (jcr->store_bsock) {
1641 bnet_close(jcr->store_bsock);
1643 free_bootstrap(jcr);
1644 if (jcr->last_fname) {
1645 free_pool_memory(jcr->last_fname);
1647 free_runscripts(jcr->RunScripts);
1648 delete jcr->RunScripts;
1654 * Get response from Storage daemon to a command we
1655 * sent. Check that the response is OK.
1657 * Returns: 0 on failure
1660 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1665 if (bget_msg(sd) > 0) {
1666 Dmsg0(110, sd->msg);
1667 if (strcmp(sd->msg, resp) == 0) {
1671 if (job_canceled(jcr)) {
1672 return 0; /* if canceled avoid useless error messages */
1674 if (is_bnet_error(sd)) {
1675 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1676 cmd, bnet_strerror(sd));
1678 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1679 cmd, resp, sd->msg);
1684 static int send_bootstrap_file(JCR *jcr)
1688 BSOCK *sd = jcr->store_bsock;
1689 const char *bootstrap = "bootstrap\n";
1692 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1693 if (!jcr->RestoreBootstrap) {
1696 bs = fopen(jcr->RestoreBootstrap, "rb");
1699 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1700 jcr->RestoreBootstrap, be.strerror());
1701 set_jcr_job_status(jcr, JS_ErrorTerminated);
1704 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1706 while (fgets(buf, sizeof(buf), bs)) {
1707 sd->msglen = Mmsg(sd->msg, "%s", buf);
1710 bnet_sig(sd, BNET_EOD);
1712 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1713 set_jcr_job_status(jcr, JS_ErrorTerminated);
1719 free_bootstrap(jcr);