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.
27 #if defined(WIN32_VSS)
30 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 static int enable_vss;
34 extern CLIENT *me; /* our client resource */
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";
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";
106 static char estimatecmd[] = "estimate listing=%d";
107 static char runbefore[] = "RunBeforeJob %s";
108 static char runafter[] = "RunAfterJob %s";
109 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s";
111 /* Responses sent to Director */
112 static char errmsg[] = "2999 Invalid command\n";
113 static char no_auth[] = "2998 No Authorization\n";
114 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
115 static char OKinc[] = "2000 OK include\n";
116 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
117 static char OKlevel[] = "2000 OK level\n";
118 static char OKbackup[] = "2000 OK backup\n";
119 static char OKbootstrap[] = "2000 OK bootstrap\n";
120 static char OKverify[] = "2000 OK verify\n";
121 static char OKrestore[] = "2000 OK restore\n";
122 static char OKsession[] = "2000 OK session\n";
123 static char OKstore[] = "2000 OK storage\n";
124 static char OKjob[] = "2000 OK Job %s,%s,%s";
125 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
126 static char BADjob[] = "2901 Bad Job\n";
127 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
128 static char OKRunBefore[] = "2000 OK RunBefore\n";
129 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
130 static char OKRunAfter[] = "2000 OK RunAfter\n";
131 static char OKRunScript[] = "2000 OK RunScript\n";
134 /* Responses received from Storage Daemon */
135 static char OK_end[] = "3000 OK end\n";
136 static char OK_close[] = "3000 OK close Status = %d\n";
137 static char OK_open[] = "3000 OK open ticket = %d\n";
138 static char OK_data[] = "3000 OK data\n";
139 static char OK_append[] = "3000 OK append data\n";
140 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
143 /* Commands sent to Storage Daemon */
144 static char append_open[] = "append open session\n";
145 static char append_data[] = "append data %d\n";
146 static char append_end[] = "append end session %d\n";
147 static char append_close[] = "append close session %d\n";
148 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
149 static char read_data[] = "read data %d\n";
150 static char read_close[] = "read close session %d\n";
153 * Accept requests from a Director
155 * NOTE! We are running as a separate thread
157 * Send output one line
158 * at a time followed by a zero length transmission.
160 * Return when the connection is terminated or there
163 * Basic task here is:
164 * Authenticate Director (during Hello command).
165 * Accept commands one at a time from the Director
169 void *handle_client_request(void *dirp)
174 BSOCK *dir = (BSOCK *)dirp;
176 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
177 jcr->dir_bsock = dir;
178 jcr->ff = init_find_files();
179 jcr->start_time = time(NULL);
180 jcr->RunScripts = New(alist(10, not_owned_by_alist));
181 jcr->last_fname = get_pool_memory(PM_FNAME);
182 jcr->last_fname[0] = 0;
183 jcr->client_name = get_memory(strlen(my_name) + 1);
184 pm_strcpy(jcr->client_name, my_name);
185 jcr->pki_sign = me->pki_sign;
186 jcr->pki_encrypt = me->pki_encrypt;
187 jcr->pki_keypair = me->pki_keypair;
188 jcr->pki_signers = me->pki_signers;
189 jcr->pki_recipients = me->pki_recipients;
191 enable_backup_privileges(NULL, 1 /* ignore_errors */);
193 /**********FIXME******* add command handler error code */
195 for (quit=false; !quit;) {
198 if (bnet_recv(dir) < 0) {
199 break; /* connection terminated */
201 dir->msg[dir->msglen] = 0;
202 Dmsg1(100, "<dird: %s", dir->msg);
204 for (i=0; cmds[i].cmd; i++) {
205 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
206 found = true; /* indicate command found */
207 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
208 bnet_fsend(dir, no_auth);
209 bnet_sig(dir, BNET_EOD);
212 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
213 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
214 bnet_fsend(dir, illegal_cmd);
215 bnet_sig(dir, BNET_EOD);
218 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
219 if (!cmds[i].func(jcr)) { /* do command */
220 quit = true; /* error or fully terminated, get out */
221 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
226 if (!found) { /* command not found */
227 bnet_fsend(dir, errmsg);
233 if (!jcr->runscript_after) {
234 jcr->runscript_after=1;
235 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
238 /* Inform Storage daemon that we are done */
239 if (jcr->store_bsock) {
240 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
243 generate_daemon_event(jcr, "JobEnd");
245 dequeue_messages(jcr); /* send any queued messages */
247 /* Inform Director that we are done */
248 bnet_sig(dir, BNET_TERMINATE);
250 /* Clean up fileset */
251 FF_PKT *ff = jcr->ff;
252 findFILESET *fileset = ff->fileset;
255 /* Delete FileSet Include lists */
256 for (i=0; i<fileset->include_list.size(); i++) {
257 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
258 for (j=0; j<incexe->opts_list.size(); j++) {
259 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
260 for (k=0; k<fo->regex.size(); k++) {
261 regfree((regex_t *)fo->regex.get(k));
264 fo->regexdir.destroy();
265 fo->regexfile.destroy();
267 fo->wilddir.destroy();
268 fo->wildfile.destroy();
269 fo->wildbase.destroy();
271 fo->fstype.destroy();
272 fo->drivetype.destroy();
280 incexe->opts_list.destroy();
281 incexe->name_list.destroy();
283 fileset->include_list.destroy();
285 /* Delete FileSet Exclude lists */
286 for (i=0; i<fileset->exclude_list.size(); i++) {
287 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
288 for (j=0; j<incexe->opts_list.size(); j++) {
289 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
291 fo->regexdir.destroy();
292 fo->regexfile.destroy();
294 fo->wilddir.destroy();
295 fo->wildfile.destroy();
296 fo->wildbase.destroy();
298 fo->fstype.destroy();
299 fo->drivetype.destroy();
301 incexe->opts_list.destroy();
302 incexe->name_list.destroy();
304 fileset->exclude_list.destroy();
308 Dmsg0(100, "Calling term_find_files\n");
309 term_find_files(jcr->ff);
311 Dmsg0(100, "Done with term_find_files\n");
312 free_jcr(jcr); /* destroy JCR record */
313 Dmsg0(100, "Done with free_jcr\n");
318 * Hello from Director he must identify himself and provide his
321 static int hello_cmd(JCR *jcr)
323 Dmsg0(120, "Calling Authenticate\n");
324 if (!authenticate_director(jcr)) {
327 Dmsg0(120, "OK Authenticate\n");
328 jcr->authenticated = true;
335 static int cancel_cmd(JCR *jcr)
337 BSOCK *dir = jcr->dir_bsock;
338 char Job[MAX_NAME_LENGTH];
341 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
342 if (!(cjcr=get_jcr_by_full_name(Job))) {
343 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
345 if (cjcr->store_bsock) {
346 cjcr->store_bsock->timed_out = 1;
347 cjcr->store_bsock->terminated = 1;
348 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
350 set_jcr_job_status(cjcr, JS_Canceled);
352 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
355 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
357 bnet_sig(dir, BNET_EOD);
363 * Set debug level as requested by the Director
366 static int setdebug_cmd(JCR *jcr)
368 BSOCK *dir = jcr->dir_bsock;
369 int level, trace_flag;
371 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
372 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
373 pm_strcpy(jcr->errmsg, dir->msg);
374 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
378 set_trace(trace_flag);
379 return bnet_fsend(dir, OKsetdebug, level);
383 static int estimate_cmd(JCR *jcr)
385 BSOCK *dir = jcr->dir_bsock;
388 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
389 pm_strcpy(jcr->errmsg, dir->msg);
390 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
391 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
395 bnet_fsend(dir, OKest, jcr->num_files_examined,
396 edit_uint64_with_commas(jcr->JobBytes, ed2));
397 bnet_sig(dir, BNET_EOD);
402 * Get JobId and Storage Daemon Authorization key from Director
404 static int job_cmd(JCR *jcr)
406 BSOCK *dir = jcr->dir_bsock;
407 POOLMEM *sd_auth_key;
409 sd_auth_key = get_memory(dir->msglen);
410 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
411 &jcr->VolSessionId, &jcr->VolSessionTime,
413 pm_strcpy(jcr->errmsg, dir->msg);
414 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
415 bnet_fsend(dir, BADjob);
416 free_pool_memory(sd_auth_key);
419 jcr->sd_auth_key = bstrdup(sd_auth_key);
420 free_pool_memory(sd_auth_key);
421 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
422 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
425 static int runbefore_cmd(JCR *jcr)
428 BSOCK *dir = jcr->dir_bsock;
429 POOLMEM *cmd = get_memory(dir->msglen+1);
432 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
433 if (sscanf(dir->msg, runbefore, cmd) != 1) {
434 pm_strcpy(jcr->errmsg, dir->msg);
435 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
436 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
442 /* Run the command now */
443 script = new_runscript();
444 script->set_command(cmd);
445 script->when = SCRIPT_Before;
446 ok = script->run(jcr, "ClientRunBeforeJob");
447 free_runscript(script);
451 bnet_fsend(dir, OKRunBefore);
454 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
459 static int runbeforenow_cmd(JCR *jcr)
461 BSOCK *dir = jcr->dir_bsock;
463 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
464 if (job_canceled(jcr)) {
465 return bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
467 return bnet_fsend(dir, OKRunBeforeNow);
471 static int runafter_cmd(JCR *jcr)
473 BSOCK *dir = jcr->dir_bsock;
474 POOLMEM *msg = get_memory(dir->msglen+1);
477 Dmsg1(100, "runafter_cmd: %s", dir->msg);
478 if (sscanf(dir->msg, runafter, msg) != 1) {
479 pm_strcpy(jcr->errmsg, dir->msg);
480 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
481 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
487 cmd = new_runscript();
488 cmd->set_command(msg);
489 cmd->on_success = true;
490 cmd->on_failure = false;
491 cmd->when = SCRIPT_After;
493 jcr->RunScripts->append(cmd);
495 free_pool_memory(msg);
496 return bnet_fsend(dir, OKRunAfter);
499 static int runscript_cmd(JCR *jcr)
501 BSOCK *dir = jcr->dir_bsock;
502 POOLMEM *msg = get_memory(dir->msglen+1);
504 RUNSCRIPT *cmd = new_runscript() ;
506 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
507 if (sscanf(dir->msg, runscript, &cmd->on_success,
509 &cmd->abort_on_error,
512 pm_strcpy(jcr->errmsg, dir->msg);
513 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
514 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
521 cmd->set_command(msg);
523 jcr->RunScripts->append(cmd);
525 free_pool_memory(msg);
526 return bnet_fsend(dir, OKRunScript);
530 static bool init_fileset(JCR *jcr)
533 findFILESET *fileset;
542 fileset = (findFILESET *)malloc(sizeof(findFILESET));
543 memset(fileset, 0, sizeof(findFILESET));
544 ff->fileset = fileset;
545 fileset->state = state_none;
546 fileset->include_list.init(1, true);
547 fileset->exclude_list.init(1, true);
551 static findFOPTS *start_options(FF_PKT *ff)
553 int state = ff->fileset->state;
554 findINCEXE *incexe = ff->fileset->incexe;
556 if (state != state_options) {
557 ff->fileset->state = state_options;
558 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
559 memset(fo, 0, sizeof(findFOPTS));
560 fo->regex.init(1, true);
561 fo->regexdir.init(1, true);
562 fo->regexfile.init(1, true);
563 fo->wild.init(1, true);
564 fo->wilddir.init(1, true);
565 fo->wildfile.init(1, true);
566 fo->wildbase.init(1, true);
567 fo->base.init(1, true);
568 fo->fstype.init(1, true);
569 fo->drivetype.init(1, true);
570 incexe->current_opts = fo;
571 incexe->opts_list.append(fo);
573 return incexe->current_opts;
578 * Add fname to include/exclude fileset list. First check for
579 * | and < and if necessary perform command.
581 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
595 p++; /* skip over | */
596 fn = get_pool_memory(PM_FNAME);
597 fn = edit_job_codes(jcr, fn, p, "");
598 bpipe = open_bpipe(fn, 0, "r");
601 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
603 free_pool_memory(fn);
606 free_pool_memory(fn);
607 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
608 strip_trailing_junk(buf);
609 fileset->incexe->name_list.append(bstrdup(buf));
611 if ((stat=close_bpipe(bpipe)) != 0) {
613 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
614 p, be.code(stat), be.strerror(stat));
619 Dmsg0(100, "Doing < include on client.\n");
620 p++; /* skip over < */
621 if ((ffd = fopen(p, "rb")) == NULL) {
623 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
627 while (fgets(buf, sizeof(buf), ffd)) {
628 strip_trailing_junk(buf);
629 Dmsg1(100, "%s\n", buf);
630 fileset->incexe->name_list.append(bstrdup(buf));
635 fileset->incexe->name_list.append(bstrdup(fname));
641 static void add_fileset(JCR *jcr, const char *item)
643 FF_PKT *ff = jcr->ff;
644 findFILESET *fileset = ff->fileset;
645 int state = fileset->state;
646 findFOPTS *current_opts;
648 /* Get code, optional subcode, and position item past the dividing space */
649 Dmsg1(100, "%s\n", item);
654 int subcode = ' '; /* A space is always a valid subcode */
655 if (item[0] != '\0' && item[0] != ' ') {
663 /* Skip all lines we receive after an error */
664 if (state == state_error) {
669 * The switch tests the code for validity.
670 * The subcode is always good if it is a space, otherwise we must confirm.
671 * We set state to state_error first assuming the subcode is invalid,
672 * requiring state to be set in cases below that handle subcodes.
674 if (subcode != ' ') {
680 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
681 memset(fileset->incexe, 0, sizeof(findINCEXE));
682 fileset->incexe->opts_list.init(1, true);
683 fileset->incexe->name_list.init(1, true);
684 fileset->include_list.append(fileset->incexe);
688 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
689 memset(fileset->incexe, 0, sizeof(findINCEXE));
690 fileset->incexe->opts_list.init(1, true);
691 fileset->incexe->name_list.init(1, true);
692 fileset->exclude_list.append(fileset->incexe);
698 /* File item to either include/include list */
699 state = state_include;
700 add_file_to_fileset(jcr, item, fileset);
703 current_opts = start_options(ff);
707 preg = (regex_t *)malloc(sizeof(regex_t));
708 if (current_opts->flags & FO_IGNORECASE) {
709 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
711 rc = regcomp(preg, item, REG_EXTENDED);
714 regerror(rc, preg, prbuf, sizeof(prbuf));
717 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
721 state = state_options;
722 if (subcode == ' ') {
723 current_opts->regex.append(preg);
724 } else if (subcode == 'D') {
725 current_opts->regexdir.append(preg);
726 } else if (subcode == 'F') {
727 current_opts->regexfile.append(preg);
733 current_opts = start_options(ff);
734 current_opts->base.append(bstrdup(item));
735 state = state_options;
738 current_opts = start_options(ff);
739 state = state_options;
740 if (subcode == ' ') {
741 current_opts->fstype.append(bstrdup(item));
742 } else if (subcode == 'D') {
743 current_opts->drivetype.append(bstrdup(item));
749 current_opts = start_options(ff);
750 state = state_options;
751 if (subcode == ' ') {
752 current_opts->wild.append(bstrdup(item));
753 } else if (subcode == 'D') {
754 current_opts->wilddir.append(bstrdup(item));
755 } else if (subcode == 'F') {
756 current_opts->wildfile.append(bstrdup(item));
757 } else if (subcode == 'B') {
758 current_opts->wildbase.append(bstrdup(item));
764 current_opts = start_options(ff);
765 set_options(current_opts, item);
766 state = state_options;
769 current_opts = start_options(ff);
770 current_opts->reader = bstrdup(item);
771 state = state_options;
774 current_opts = start_options(ff);
775 current_opts->writer = bstrdup(item);
776 state = state_options;
779 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
783 ff->fileset->state = state;
786 static bool term_fileset(JCR *jcr)
788 FF_PKT *ff = jcr->ff;
791 findFILESET *fileset = ff->fileset;
794 for (i=0; i<fileset->include_list.size(); i++) {
795 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
797 for (j=0; j<incexe->opts_list.size(); j++) {
798 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
799 for (k=0; k<fo->regex.size(); k++) {
800 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
802 for (k=0; k<fo->regexdir.size(); k++) {
803 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
805 for (k=0; k<fo->regexfile.size(); k++) {
806 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
808 for (k=0; k<fo->wild.size(); k++) {
809 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
811 for (k=0; k<fo->wilddir.size(); k++) {
812 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
814 for (k=0; k<fo->wildfile.size(); k++) {
815 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
817 for (k=0; k<fo->wildbase.size(); k++) {
818 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
820 for (k=0; k<fo->base.size(); k++) {
821 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
823 for (k=0; k<fo->fstype.size(); k++) {
824 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
826 for (k=0; k<fo->drivetype.size(); k++) {
827 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
830 Dmsg1(400, "D %s\n", fo->reader);
833 Dmsg1(400, "T %s\n", fo->writer);
836 for (j=0; j<incexe->name_list.size(); j++) {
837 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
840 for (i=0; i<fileset->exclude_list.size(); i++) {
841 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
843 for (j=0; j<incexe->opts_list.size(); j++) {
844 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
845 for (k=0; k<fo->regex.size(); k++) {
846 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
848 for (k=0; k<fo->regexdir.size(); k++) {
849 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
851 for (k=0; k<fo->regexfile.size(); k++) {
852 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
854 for (k=0; k<fo->wild.size(); k++) {
855 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
857 for (k=0; k<fo->wilddir.size(); k++) {
858 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
860 for (k=0; k<fo->wildfile.size(); k++) {
861 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
863 for (k=0; k<fo->wildbase.size(); k++) {
864 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
866 for (k=0; k<fo->base.size(); k++) {
867 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
869 for (k=0; k<fo->fstype.size(); k++) {
870 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
872 for (k=0; k<fo->drivetype.size(); k++) {
873 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
876 for (j=0; j<incexe->name_list.size(); j++) {
877 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
881 return ff->fileset->state != state_error;
886 * As an optimization, we should do this during
887 * "compile" time in filed/job.c, and keep only a bit mask
888 * and the Verify options.
890 static void set_options(findFOPTS *fo, const char *opts)
895 for (p=opts; *p; p++) {
897 case 'a': /* alway replace */
898 case '0': /* no option */
901 fo->flags |= FO_EXCLUDE;
904 fo->flags |= FO_MULTIFS;
906 case 'h': /* no recursion */
907 fo->flags |= FO_NO_RECURSION;
909 case 'H': /* no hard link handling */
910 fo->flags |= FO_NO_HARDLINK;
913 fo->flags |= FO_IGNORECASE;
919 fo->flags |= FO_NOREPLACE;
921 case 'p': /* use portable data format */
922 fo->flags |= FO_PORTABLE;
924 case 'R': /* Resource forks and Finder Info */
925 fo->flags |= FO_HFSPLUS;
926 case 'r': /* read fifo */
927 fo->flags |= FO_READFIFO;
932 /* Old director did not specify SHA variant */
933 fo->flags |= FO_SHA1;
936 fo->flags |= FO_SHA1;
941 fo->flags |= FO_SHA256;
945 fo->flags |= FO_SHA512;
950 /* Automatically downgrade to SHA-1 if an unsupported
951 * SHA variant is specified */
952 fo->flags |= FO_SHA1;
958 fo->flags |= FO_SPARSE;
961 fo->flags |= FO_MTIMEONLY;
964 fo->flags |= FO_KEEPATIME;
969 case 'V': /* verify options */
970 /* Copy Verify Options */
971 for (j=0; *p && *p != ':'; p++) {
972 fo->VerifyOpts[j] = *p;
973 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
977 fo->VerifyOpts[j] = 0;
980 fo->flags |= FO_IF_NEWER;
983 fo->flags |= FO_ENHANCEDWILD;
985 case 'Z': /* gzip compression */
986 fo->flags |= FO_GZIP;
987 fo->GZIP_level = *++p - '0';
988 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
991 fo->flags |= FO_NOATIME;
994 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1002 * Director is passing his Fileset
1004 static int fileset_cmd(JCR *jcr)
1006 BSOCK *dir = jcr->dir_bsock;
1008 #if defined(WIN32_VSS)
1011 sscanf(dir->msg, "fileset vss=%d", &vss);
1015 if (!init_fileset(jcr)) {
1018 while (bnet_recv(dir) >= 0) {
1019 strip_trailing_junk(dir->msg);
1020 Dmsg1(500, "Fileset: %s\n", dir->msg);
1021 add_fileset(jcr, dir->msg);
1023 if (!term_fileset(jcr)) {
1026 return bnet_fsend(dir, OKinc);
1029 static void free_bootstrap(JCR *jcr)
1031 if (jcr->RestoreBootstrap) {
1032 unlink(jcr->RestoreBootstrap);
1033 free_pool_memory(jcr->RestoreBootstrap);
1034 jcr->RestoreBootstrap = NULL;
1039 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1040 static uint32_t bsr_uniq = 0;
1043 * The Director sends us the bootstrap file, which
1044 * we will in turn pass to the SD.
1046 static int bootstrap_cmd(JCR *jcr)
1048 BSOCK *dir = jcr->dir_bsock;
1049 POOLMEM *fname = get_pool_memory(PM_FNAME);
1052 free_bootstrap(jcr);
1055 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1056 jcr->Job, bsr_uniq);
1058 Dmsg1(400, "bootstrap=%s\n", fname);
1059 jcr->RestoreBootstrap = fname;
1060 bs = fopen(fname, "a+b"); /* create file */
1063 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1064 jcr->RestoreBootstrap, be.strerror());
1066 * Suck up what he is sending to us so that he will then
1067 * read our error message.
1069 while (bnet_recv(dir) >= 0)
1071 free_bootstrap(jcr);
1072 set_jcr_job_status(jcr, JS_ErrorTerminated);
1076 while (bnet_recv(dir) >= 0) {
1077 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1078 fputs(dir->msg, bs);
1082 * Note, do not free the bootstrap yet -- it needs to be
1085 return bnet_fsend(dir, OKbootstrap);
1090 * Get backup level from Director
1093 static int level_cmd(JCR *jcr)
1095 BSOCK *dir = jcr->dir_bsock;
1096 POOLMEM *level, *buf = NULL;
1099 level = get_memory(dir->msglen+1);
1100 Dmsg1(110, "level_cmd: %s", dir->msg);
1101 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1104 /* Base backup requested? */
1105 if (strcmp(level, "base") == 0) {
1106 jcr->JobLevel = L_BASE;
1107 /* Full backup requested? */
1108 } else if (strcmp(level, "full") == 0) {
1109 jcr->JobLevel = L_FULL;
1110 } else if (strcmp(level, "differential") == 0) {
1111 jcr->JobLevel = L_DIFFERENTIAL;
1114 } else if (strcmp(level, "incremental") == 0) {
1115 jcr->JobLevel = L_INCREMENTAL;
1119 * We get his UTC since time, then sync the clocks and correct it
1120 * to agree with our clock.
1122 } else if (strcmp(level, "since_utime") == 0) {
1123 buf = get_memory(dir->msglen+1);
1124 utime_t since_time, adj;
1125 btime_t his_time, bt_start, rt=0, bt_adj=0;
1126 if (jcr->JobLevel == L_NONE) {
1127 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1129 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1130 buf, &mtime_only) != 2) {
1133 since_time = str_to_uint64(buf); /* this is the since time */
1134 Dmsg1(100, "since_time=%d\n", (int)since_time);
1135 char ed1[50], ed2[50];
1137 * Sync clocks by polling him for the time. We take
1138 * 10 samples of his time throwing out the first two.
1140 for (int i=0; i<10; i++) {
1141 bt_start = get_current_btime();
1142 bnet_sig(dir, BNET_BTIME); /* poll for time */
1143 if (bnet_recv(dir) <= 0) { /* get response */
1146 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1149 if (i < 2) { /* toss first two results */
1152 his_time = str_to_uint64(buf);
1153 rt = get_current_btime() - bt_start; /* compute round trip time */
1154 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1155 edit_uint64(bt_start, ed2));
1156 bt_adj += bt_start - his_time - rt/2;
1157 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1160 bt_adj = bt_adj / 8; /* compute average time */
1161 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1162 adj = btime_to_utime(bt_adj);
1163 since_time += adj; /* adjust for clock difference */
1165 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1167 bnet_sig(dir, BNET_EOD);
1169 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1170 jcr->incremental = 1; /* set incremental or decremental backup */
1171 jcr->mtime = (time_t)since_time; /* set since time */
1173 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1181 return bnet_fsend(dir, OKlevel);
1184 pm_strcpy(jcr->errmsg, dir->msg);
1185 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1194 * Get session parameters from Director -- this is for a Restore command
1196 static int session_cmd(JCR *jcr)
1198 BSOCK *dir = jcr->dir_bsock;
1200 Dmsg1(100, "SessionCmd: %s", dir->msg);
1201 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1202 &jcr->VolSessionId, &jcr->VolSessionTime,
1203 &jcr->StartFile, &jcr->EndFile,
1204 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1205 pm_strcpy(jcr->errmsg, dir->msg);
1206 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1210 return bnet_fsend(dir, OKsession);
1214 * Get address of storage daemon from Director
1217 static int storage_cmd(JCR *jcr)
1219 int stored_port; /* storage daemon port */
1220 int enable_ssl; /* enable ssl to sd */
1221 BSOCK *dir = jcr->dir_bsock;
1222 BSOCK *sd; /* storage daemon bsock */
1224 Dmsg1(100, "StorageCmd: %s", dir->msg);
1225 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1226 pm_strcpy(jcr->errmsg, dir->msg);
1227 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1230 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1231 /* Open command communications with Storage daemon */
1232 /* Try to connect for 1 hour at 10 second intervals */
1233 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1234 jcr->stored_addr, NULL, stored_port, 1);
1236 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1237 jcr->stored_addr, stored_port);
1238 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1239 jcr->stored_addr, stored_port);
1242 Dmsg0(110, "Connection OK to SD.\n");
1244 jcr->store_bsock = sd;
1246 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1247 if (!authenticate_storagedaemon(jcr)) {
1248 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1251 Dmsg0(110, "Authenticated with SD.\n");
1253 /* Send OK to Director */
1254 return bnet_fsend(dir, OKstore);
1259 * Do a backup. For now, we handle only Full and Incremental.
1261 static int backup_cmd(JCR *jcr)
1263 BSOCK *dir = jcr->dir_bsock;
1264 BSOCK *sd = jcr->store_bsock;
1267 char ed1[50], ed2[50];
1269 #if defined(WIN32_VSS)
1270 // capture state here, if client is backed up by multiple directors
1271 // and one enables vss and the other does not then enable_vss can change
1272 // between here and where its evaluated after the job completes.
1273 bool bDoVSS = false;
1275 bDoVSS = g_pVSSClient && enable_vss;
1277 /* Run only one at a time */
1281 set_jcr_job_status(jcr, JS_Blocked);
1282 jcr->JobType = JT_BACKUP;
1283 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1286 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1290 bnet_fsend(dir, OKbackup);
1291 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1294 * Send Append Open Session to Storage daemon
1296 bnet_fsend(sd, append_open);
1297 Dmsg1(110, ">stored: %s", sd->msg);
1299 * Expect to receive back the Ticket number
1301 if (bget_msg(sd) >= 0) {
1302 Dmsg1(110, "<stored: %s", sd->msg);
1303 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1304 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1307 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1309 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1314 * Send Append data command to Storage daemon
1316 bnet_fsend(sd, append_data, jcr->Ticket);
1317 Dmsg1(110, ">stored: %s", sd->msg);
1320 * Expect to get OK data
1322 Dmsg1(110, "<stored: %s", sd->msg);
1323 if (!response(jcr, sd, OK_data, "Append Data")) {
1327 generate_daemon_event(jcr, "JobStart");
1329 #if defined(WIN32_VSS)
1330 /* START VSS ON WIN 32 */
1332 if (g_pVSSClient->InitializeForBackup()) {
1333 /* tell vss which drives to snapshot */
1334 char szWinDriveLetters[27];
1335 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1336 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1337 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1338 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1341 /* tell user if snapshot creation of a specific drive failed */
1343 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1344 if (islower(szWinDriveLetters[i])) {
1345 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1349 /* inform user about writer states */
1350 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1351 if (g_pVSSClient->GetWriterState(i) < 1) {
1352 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1357 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1361 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1367 * Send Files to Storage daemon
1369 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1370 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1371 set_jcr_job_status(jcr, JS_ErrorTerminated);
1372 bnet_suppress_error_messages(sd, 1);
1373 bget_msg(sd); /* Read final response from append_data */
1374 Dmsg0(110, "Error in blast_data.\n");
1375 /* run shortly after end of data transmission */
1376 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1377 jcr->runscript_after=1;
1380 set_jcr_job_status(jcr, JS_Terminated);
1382 /* run shortly after end of data transmission */
1383 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1384 jcr->runscript_after=1;
1386 if (jcr->JobStatus != JS_Terminated) {
1387 bnet_suppress_error_messages(sd, 1);
1388 goto cleanup; /* bail out now */
1391 * Expect to get response to append_data from Storage daemon
1393 if (!response(jcr, sd, OK_append, "Append Data")) {
1394 set_jcr_job_status(jcr, JS_ErrorTerminated);
1399 * Send Append End Data to Storage daemon
1401 bnet_fsend(sd, append_end, jcr->Ticket);
1403 if (!response(jcr, sd, OK_end, "Append End")) {
1404 set_jcr_job_status(jcr, JS_ErrorTerminated);
1409 * Send Append Close to Storage daemon
1411 bnet_fsend(sd, append_close, jcr->Ticket);
1412 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1413 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1415 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1419 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1422 if (SDJobStatus != JS_Terminated) {
1423 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1429 #if defined(WIN32_VSS)
1430 /* STOP VSS ON WIN 32 */
1431 /* tell vss to close the backup session */
1433 if (g_pVSSClient->CloseBackup()) {
1434 /* inform user about writer states */
1435 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1436 int msg_type = M_INFO;
1437 if (g_pVSSClient->GetWriterState(i) < 1) {
1438 msg_type = M_WARNING;
1441 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1448 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1449 edit_uint64(jcr->ReadBytes, ed1),
1450 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1451 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1453 return 0; /* return and stop command loop */
1457 * Do a Verify for Director
1460 static int verify_cmd(JCR *jcr)
1462 BSOCK *dir = jcr->dir_bsock;
1463 BSOCK *sd = jcr->store_bsock;
1464 char level[100], ed1[50], ed2[50];
1466 jcr->JobType = JT_VERIFY;
1467 if (sscanf(dir->msg, verifycmd, level) != 1) {
1468 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1472 if (strcasecmp(level, "init") == 0) {
1473 jcr->JobLevel = L_VERIFY_INIT;
1474 } else if (strcasecmp(level, "catalog") == 0){
1475 jcr->JobLevel = L_VERIFY_CATALOG;
1476 } else if (strcasecmp(level, "volume") == 0){
1477 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1478 } else if (strcasecmp(level, "data") == 0){
1479 jcr->JobLevel = L_VERIFY_DATA;
1480 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1481 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1483 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1487 bnet_fsend(dir, OKverify);
1489 generate_daemon_event(jcr, "JobStart");
1491 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1493 switch (jcr->JobLevel) {
1495 case L_VERIFY_CATALOG:
1498 case L_VERIFY_VOLUME_TO_CATALOG:
1499 if (!open_sd_read_session(jcr)) {
1502 start_dir_heartbeat(jcr);
1503 do_verify_volume(jcr);
1504 stop_dir_heartbeat(jcr);
1506 * Send Close session command to Storage daemon
1508 bnet_fsend(sd, read_close, jcr->Ticket);
1509 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1511 /* ****FIXME**** check response */
1512 bget_msg(sd); /* get OK */
1514 /* Inform Storage daemon that we are done */
1515 bnet_sig(sd, BNET_TERMINATE);
1518 case L_VERIFY_DISK_TO_CATALOG:
1522 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1526 bnet_sig(dir, BNET_EOD);
1528 /* Send termination status back to Dir */
1529 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1530 edit_uint64(jcr->ReadBytes, ed1),
1531 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1533 /* Inform Director that we are done */
1534 bnet_sig(dir, BNET_TERMINATE);
1535 return 0; /* return and terminate command loop */
1539 * Do a Restore for Director
1542 static int restore_cmd(JCR *jcr)
1544 BSOCK *dir = jcr->dir_bsock;
1545 BSOCK *sd = jcr->store_bsock;
1549 char ed1[50], ed2[50];
1552 * Scan WHERE (base directory for restore) from command
1554 Dmsg0(150, "restore command\n");
1555 /* Pickup where string */
1556 where = get_memory(dir->msglen+1);
1559 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1560 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1561 pm_strcpy(jcr->errmsg, dir->msg);
1562 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1567 /* Turn / into nothing */
1568 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1572 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1573 unbash_spaces(where);
1574 jcr->where = bstrdup(where);
1575 free_pool_memory(where);
1576 jcr->replace = replace;
1577 jcr->prefix_links = prefix_links;
1579 bnet_fsend(dir, OKrestore);
1580 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1582 jcr->JobType = JT_RESTORE;
1584 set_jcr_job_status(jcr, JS_Blocked);
1586 if (!open_sd_read_session(jcr)) {
1587 set_jcr_job_status(jcr, JS_ErrorTerminated);
1591 set_jcr_job_status(jcr, JS_Running);
1594 * Do restore of files and data
1596 start_dir_heartbeat(jcr);
1597 generate_daemon_event(jcr, "JobStart");
1599 stop_dir_heartbeat(jcr);
1601 set_jcr_job_status(jcr, JS_Terminated);
1602 if (jcr->JobStatus != JS_Terminated) {
1603 bnet_suppress_error_messages(sd, 1);
1607 * Send Close session command to Storage daemon
1609 bnet_fsend(sd, read_close, jcr->Ticket);
1610 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1612 bget_msg(sd); /* get OK */
1614 /* Inform Storage daemon that we are done */
1615 bnet_sig(sd, BNET_TERMINATE);
1620 set_jcr_job_status(jcr, JS_ErrorTerminated);
1622 /* Send termination status back to Dir */
1623 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1624 edit_uint64(jcr->ReadBytes, ed1),
1625 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1627 /* Inform Director that we are done */
1628 bnet_sig(dir, BNET_TERMINATE);
1630 Dmsg0(130, "Done in job.c\n");
1631 return 0; /* return and terminate command loop */
1634 static int open_sd_read_session(JCR *jcr)
1636 BSOCK *sd = jcr->store_bsock;
1639 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1642 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1643 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1644 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1646 * Open Read Session with Storage daemon
1648 bnet_fsend(sd, read_open, "DummyVolume",
1649 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1650 jcr->StartBlock, jcr->EndBlock);
1651 Dmsg1(110, ">stored: %s", sd->msg);
1656 if (bget_msg(sd) >= 0) {
1657 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1658 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1659 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1662 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1664 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1668 if (!send_bootstrap_file(jcr)) {
1673 * Start read of data with Storage daemon
1675 bnet_fsend(sd, read_data, jcr->Ticket);
1676 Dmsg1(110, ">stored: %s", sd->msg);
1681 if (!response(jcr, sd, OK_data, "Read Data")) {
1688 * Destroy the Job Control Record and associated
1689 * resources (sockets).
1691 static void filed_free_jcr(JCR *jcr)
1693 if (jcr->store_bsock) {
1694 bnet_close(jcr->store_bsock);
1696 free_bootstrap(jcr);
1697 if (jcr->last_fname) {
1698 free_pool_memory(jcr->last_fname);
1700 free_runscripts(jcr->RunScripts);
1701 delete jcr->RunScripts;
1707 * Get response from Storage daemon to a command we
1708 * sent. Check that the response is OK.
1710 * Returns: 0 on failure
1713 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1718 if (bget_msg(sd) > 0) {
1719 Dmsg0(110, sd->msg);
1720 if (strcmp(sd->msg, resp) == 0) {
1724 if (job_canceled(jcr)) {
1725 return 0; /* if canceled avoid useless error messages */
1727 if (is_bnet_error(sd)) {
1728 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1729 cmd, bnet_strerror(sd));
1731 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1732 cmd, resp, sd->msg);
1737 static int send_bootstrap_file(JCR *jcr)
1741 BSOCK *sd = jcr->store_bsock;
1742 const char *bootstrap = "bootstrap\n";
1745 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1746 if (!jcr->RestoreBootstrap) {
1749 bs = fopen(jcr->RestoreBootstrap, "rb");
1752 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1753 jcr->RestoreBootstrap, be.strerror());
1754 set_jcr_job_status(jcr, JS_ErrorTerminated);
1757 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1759 while (fgets(buf, sizeof(buf), bs)) {
1760 sd->msglen = Mmsg(sd->msg, "%s", buf);
1763 bnet_sig(sd, BNET_EOD);
1765 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1766 set_jcr_job_status(jcr, JS_ErrorTerminated);
1772 free_bootstrap(jcr);