2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 #if defined(WIN32_VSS)
43 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
44 static int enable_vss;
47 extern CLIENT *me; /* our client resource */
49 /* Imported functions */
50 extern int status_cmd(JCR *jcr);
51 extern int qstatus_cmd(JCR *jcr);
53 /* Forward referenced functions */
54 static int backup_cmd(JCR *jcr);
55 static int bootstrap_cmd(JCR *jcr);
56 static int cancel_cmd(JCR *jcr);
57 static int setdebug_cmd(JCR *jcr);
58 static int estimate_cmd(JCR *jcr);
59 static int hello_cmd(JCR *jcr);
60 static int job_cmd(JCR *jcr);
61 static int fileset_cmd(JCR *jcr);
62 static int level_cmd(JCR *jcr);
63 static int verify_cmd(JCR *jcr);
64 static int restore_cmd(JCR *jcr);
65 static int storage_cmd(JCR *jcr);
66 static int session_cmd(JCR *jcr);
67 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
68 static void filed_free_jcr(JCR *jcr);
69 static int open_sd_read_session(JCR *jcr);
70 static int send_bootstrap_file(JCR *jcr);
71 static int runscript_cmd(JCR *jcr);
72 static int runbefore_cmd(JCR *jcr);
73 static int runafter_cmd(JCR *jcr);
74 static int runbeforenow_cmd(JCR *jcr);
75 static void set_options(findFOPTS *fo, const char *opts);
78 /* Exported functions */
83 int monitoraccess; /* specify if monitors have access to this function */
87 * The following are the recognized commands from the Director.
89 static struct s_cmds cmds[] = {
90 {"backup", backup_cmd, 0},
91 {"cancel", cancel_cmd, 0},
92 {"setdebug=", setdebug_cmd, 0},
93 {"estimate", estimate_cmd, 0},
94 {"Hello", hello_cmd, 1},
95 {"fileset", fileset_cmd, 0},
96 {"JobId=", job_cmd, 0},
97 {"level = ", level_cmd, 0},
98 {"restore", restore_cmd, 0},
99 {"session", session_cmd, 0},
100 {"status", status_cmd, 1},
101 {".status", qstatus_cmd, 1},
102 {"storage ", storage_cmd, 0},
103 {"verify", verify_cmd, 0},
104 {"bootstrap", bootstrap_cmd, 0},
105 {"RunBeforeNow", runbeforenow_cmd, 0},
106 {"RunBeforeJob", runbefore_cmd, 0},
107 {"RunAfterJob", runafter_cmd, 0},
108 {"Run", runscript_cmd, 0},
109 {NULL, NULL} /* list terminator */
112 /* Commands received from director that need scanning */
113 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
114 static char storaddr[] = "storage address=%s port=%d ssl=%d";
115 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
116 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
117 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
118 static char verifycmd[] = "verify level=%30s";
119 static char estimatecmd[] = "estimate listing=%d";
120 static char runbefore[] = "RunBeforeJob %s";
121 static char runafter[] = "RunAfterJob %s";
122 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s";
124 /* Responses sent to Director */
125 static char errmsg[] = "2999 Invalid command\n";
126 static char no_auth[] = "2998 No Authorization\n";
127 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
128 static char OKinc[] = "2000 OK include\n";
129 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
130 static char OKlevel[] = "2000 OK level\n";
131 static char OKbackup[] = "2000 OK backup\n";
132 static char OKbootstrap[] = "2000 OK bootstrap\n";
133 static char OKverify[] = "2000 OK verify\n";
134 static char OKrestore[] = "2000 OK restore\n";
135 static char OKsession[] = "2000 OK session\n";
136 static char OKstore[] = "2000 OK storage\n";
137 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
138 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
139 static char BADjob[] = "2901 Bad Job\n";
140 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
141 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
142 static char OKRunBefore[] = "2000 OK RunBefore\n";
143 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
144 static char OKRunAfter[] = "2000 OK RunAfter\n";
145 static char OKRunScript[] = "2000 OK RunScript\n";
148 /* Responses received from Storage Daemon */
149 static char OK_end[] = "3000 OK end\n";
150 static char OK_close[] = "3000 OK close Status = %d\n";
151 static char OK_open[] = "3000 OK open ticket = %d\n";
152 static char OK_data[] = "3000 OK data\n";
153 static char OK_append[] = "3000 OK append data\n";
154 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
157 /* Commands sent to Storage Daemon */
158 static char append_open[] = "append open session\n";
159 static char append_data[] = "append data %d\n";
160 static char append_end[] = "append end session %d\n";
161 static char append_close[] = "append close session %d\n";
162 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
163 static char read_data[] = "read data %d\n";
164 static char read_close[] = "read close session %d\n";
167 * Accept requests from a Director
169 * NOTE! We are running as a separate thread
171 * Send output one line
172 * at a time followed by a zero length transmission.
174 * Return when the connection is terminated or there
177 * Basic task here is:
178 * Authenticate Director (during Hello command).
179 * Accept commands one at a time from the Director
183 void *handle_client_request(void *dirp)
188 BSOCK *dir = (BSOCK *)dirp;
190 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
191 jcr->dir_bsock = dir;
192 jcr->ff = init_find_files();
193 jcr->start_time = time(NULL);
194 jcr->RunScripts = New(alist(10, not_owned_by_alist));
195 jcr->last_fname = get_pool_memory(PM_FNAME);
196 jcr->last_fname[0] = 0;
197 jcr->client_name = get_memory(strlen(my_name) + 1);
198 pm_strcpy(jcr->client_name, my_name);
199 jcr->pki_sign = me->pki_sign;
200 jcr->pki_encrypt = me->pki_encrypt;
201 jcr->pki_keypair = me->pki_keypair;
202 jcr->pki_signers = me->pki_signers;
203 jcr->pki_recipients = me->pki_recipients;
205 enable_backup_privileges(NULL, 1 /* ignore_errors */);
207 /**********FIXME******* add command handler error code */
209 for (quit=false; !quit;) {
212 if (bnet_recv(dir) < 0) {
213 break; /* connection terminated */
215 dir->msg[dir->msglen] = 0;
216 Dmsg1(100, "<dird: %s", dir->msg);
218 for (i=0; cmds[i].cmd; i++) {
219 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
220 found = true; /* indicate command found */
221 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
222 bnet_fsend(dir, no_auth);
223 bnet_sig(dir, BNET_EOD);
226 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
227 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
228 bnet_fsend(dir, invalid_cmd);
229 bnet_sig(dir, BNET_EOD);
232 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
233 if (!cmds[i].func(jcr)) { /* do command */
234 quit = true; /* error or fully terminated, get out */
235 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
240 if (!found) { /* command not found */
241 bnet_fsend(dir, errmsg);
247 if (!jcr->runscript_after) {
248 jcr->runscript_after=1;
249 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
252 /* Inform Storage daemon that we are done */
253 if (jcr->store_bsock) {
254 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
257 generate_daemon_event(jcr, "JobEnd");
259 dequeue_messages(jcr); /* send any queued messages */
261 /* Inform Director that we are done */
262 bnet_sig(dir, BNET_TERMINATE);
264 /* Clean up fileset */
265 FF_PKT *ff = jcr->ff;
266 findFILESET *fileset = ff->fileset;
269 /* Delete FileSet Include lists */
270 for (i=0; i<fileset->include_list.size(); i++) {
271 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
272 for (j=0; j<incexe->opts_list.size(); j++) {
273 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
274 for (k=0; k<fo->regex.size(); k++) {
275 regfree((regex_t *)fo->regex.get(k));
278 fo->regexdir.destroy();
279 fo->regexfile.destroy();
281 fo->wilddir.destroy();
282 fo->wildfile.destroy();
283 fo->wildbase.destroy();
285 fo->fstype.destroy();
286 fo->drivetype.destroy();
294 incexe->opts_list.destroy();
295 incexe->name_list.destroy();
297 fileset->include_list.destroy();
299 /* Delete FileSet Exclude lists */
300 for (i=0; i<fileset->exclude_list.size(); i++) {
301 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
302 for (j=0; j<incexe->opts_list.size(); j++) {
303 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
305 fo->regexdir.destroy();
306 fo->regexfile.destroy();
308 fo->wilddir.destroy();
309 fo->wildfile.destroy();
310 fo->wildbase.destroy();
312 fo->fstype.destroy();
313 fo->drivetype.destroy();
315 incexe->opts_list.destroy();
316 incexe->name_list.destroy();
318 fileset->exclude_list.destroy();
322 Dmsg0(100, "Calling term_find_files\n");
323 term_find_files(jcr->ff);
325 Dmsg0(100, "Done with term_find_files\n");
326 free_jcr(jcr); /* destroy JCR record */
327 Dmsg0(100, "Done with free_jcr\n");
332 * Hello from Director he must identify himself and provide his
335 static int hello_cmd(JCR *jcr)
337 Dmsg0(120, "Calling Authenticate\n");
338 if (!authenticate_director(jcr)) {
341 Dmsg0(120, "OK Authenticate\n");
342 jcr->authenticated = true;
349 static int cancel_cmd(JCR *jcr)
351 BSOCK *dir = jcr->dir_bsock;
352 char Job[MAX_NAME_LENGTH];
355 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
356 if (!(cjcr=get_jcr_by_full_name(Job))) {
357 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
359 if (cjcr->store_bsock) {
360 cjcr->store_bsock->timed_out = 1;
361 cjcr->store_bsock->terminated = 1;
362 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
364 set_jcr_job_status(cjcr, JS_Canceled);
366 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
369 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
371 bnet_sig(dir, BNET_EOD);
377 * Set debug level as requested by the Director
380 static int setdebug_cmd(JCR *jcr)
382 BSOCK *dir = jcr->dir_bsock;
383 int level, trace_flag;
385 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
386 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
387 pm_strcpy(jcr->errmsg, dir->msg);
388 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
392 set_trace(trace_flag);
393 return bnet_fsend(dir, OKsetdebug, level);
397 static int estimate_cmd(JCR *jcr)
399 BSOCK *dir = jcr->dir_bsock;
402 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
403 pm_strcpy(jcr->errmsg, dir->msg);
404 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
405 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
409 bnet_fsend(dir, OKest, jcr->num_files_examined,
410 edit_uint64_with_commas(jcr->JobBytes, ed2));
411 bnet_sig(dir, BNET_EOD);
416 * Get JobId and Storage Daemon Authorization key from Director
418 static int job_cmd(JCR *jcr)
420 BSOCK *dir = jcr->dir_bsock;
421 POOLMEM *sd_auth_key;
423 sd_auth_key = get_memory(dir->msglen);
424 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
425 &jcr->VolSessionId, &jcr->VolSessionTime,
427 pm_strcpy(jcr->errmsg, dir->msg);
428 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
429 bnet_fsend(dir, BADjob);
430 free_pool_memory(sd_auth_key);
433 jcr->sd_auth_key = bstrdup(sd_auth_key);
434 free_pool_memory(sd_auth_key);
435 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
436 return bnet_fsend(dir, OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
439 static int runbefore_cmd(JCR *jcr)
442 BSOCK *dir = jcr->dir_bsock;
443 POOLMEM *cmd = get_memory(dir->msglen+1);
446 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
447 if (sscanf(dir->msg, runbefore, cmd) != 1) {
448 pm_strcpy(jcr->errmsg, dir->msg);
449 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
450 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
456 /* Run the command now */
457 script = new_runscript();
458 script->set_command(cmd);
459 script->when = SCRIPT_Before;
460 ok = script->run(jcr, "ClientRunBeforeJob");
461 free_runscript(script);
465 bnet_fsend(dir, OKRunBefore);
468 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
473 static int runbeforenow_cmd(JCR *jcr)
475 BSOCK *dir = jcr->dir_bsock;
477 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
478 if (job_canceled(jcr)) {
479 return bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
481 return bnet_fsend(dir, OKRunBeforeNow);
485 static int runafter_cmd(JCR *jcr)
487 BSOCK *dir = jcr->dir_bsock;
488 POOLMEM *msg = get_memory(dir->msglen+1);
491 Dmsg1(100, "runafter_cmd: %s", dir->msg);
492 if (sscanf(dir->msg, runafter, msg) != 1) {
493 pm_strcpy(jcr->errmsg, dir->msg);
494 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
495 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
501 cmd = new_runscript();
502 cmd->set_command(msg);
503 cmd->on_success = true;
504 cmd->on_failure = false;
505 cmd->when = SCRIPT_After;
507 jcr->RunScripts->append(cmd);
509 free_pool_memory(msg);
510 return bnet_fsend(dir, OKRunAfter);
513 static int runscript_cmd(JCR *jcr)
515 BSOCK *dir = jcr->dir_bsock;
516 POOLMEM *msg = get_memory(dir->msglen+1);
518 RUNSCRIPT *cmd = new_runscript() ;
520 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
521 if (sscanf(dir->msg, runscript, &cmd->on_success,
523 &cmd->abort_on_error,
526 pm_strcpy(jcr->errmsg, dir->msg);
527 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
528 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
535 cmd->set_command(msg);
537 jcr->RunScripts->append(cmd);
539 free_pool_memory(msg);
540 return bnet_fsend(dir, OKRunScript);
544 static bool init_fileset(JCR *jcr)
547 findFILESET *fileset;
556 fileset = (findFILESET *)malloc(sizeof(findFILESET));
557 memset(fileset, 0, sizeof(findFILESET));
558 ff->fileset = fileset;
559 fileset->state = state_none;
560 fileset->include_list.init(1, true);
561 fileset->exclude_list.init(1, true);
565 static findFOPTS *start_options(FF_PKT *ff)
567 int state = ff->fileset->state;
568 findINCEXE *incexe = ff->fileset->incexe;
570 if (state != state_options) {
571 ff->fileset->state = state_options;
572 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
573 memset(fo, 0, sizeof(findFOPTS));
574 fo->regex.init(1, true);
575 fo->regexdir.init(1, true);
576 fo->regexfile.init(1, true);
577 fo->wild.init(1, true);
578 fo->wilddir.init(1, true);
579 fo->wildfile.init(1, true);
580 fo->wildbase.init(1, true);
581 fo->base.init(1, true);
582 fo->fstype.init(1, true);
583 fo->drivetype.init(1, true);
584 incexe->current_opts = fo;
585 incexe->opts_list.append(fo);
587 return incexe->current_opts;
592 * Add fname to include/exclude fileset list. First check for
593 * | and < and if necessary perform command.
595 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
609 p++; /* skip over | */
610 fn = get_pool_memory(PM_FNAME);
611 fn = edit_job_codes(jcr, fn, p, "");
612 bpipe = open_bpipe(fn, 0, "r");
615 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
617 free_pool_memory(fn);
620 free_pool_memory(fn);
621 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
622 strip_trailing_junk(buf);
623 fileset->incexe->name_list.append(bstrdup(buf));
625 if ((stat=close_bpipe(bpipe)) != 0) {
627 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
628 p, be.code(stat), be.strerror(stat));
633 Dmsg0(100, "Doing < include on client.\n");
634 p++; /* skip over < */
635 if ((ffd = fopen(p, "rb")) == NULL) {
637 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
641 while (fgets(buf, sizeof(buf), ffd)) {
642 strip_trailing_junk(buf);
643 Dmsg1(100, "%s\n", buf);
644 fileset->incexe->name_list.append(bstrdup(buf));
649 fileset->incexe->name_list.append(bstrdup(fname));
655 static void add_fileset(JCR *jcr, const char *item)
657 FF_PKT *ff = jcr->ff;
658 findFILESET *fileset = ff->fileset;
659 int state = fileset->state;
660 findFOPTS *current_opts;
662 /* Get code, optional subcode, and position item past the dividing space */
663 Dmsg1(100, "%s\n", item);
668 int subcode = ' '; /* A space is always a valid subcode */
669 if (item[0] != '\0' && item[0] != ' ') {
677 /* Skip all lines we receive after an error */
678 if (state == state_error) {
683 * The switch tests the code for validity.
684 * The subcode is always good if it is a space, otherwise we must confirm.
685 * We set state to state_error first assuming the subcode is invalid,
686 * requiring state to be set in cases below that handle subcodes.
688 if (subcode != ' ') {
694 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
695 memset(fileset->incexe, 0, sizeof(findINCEXE));
696 fileset->incexe->opts_list.init(1, true);
697 fileset->incexe->name_list.init(1, true);
698 fileset->include_list.append(fileset->incexe);
702 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
703 memset(fileset->incexe, 0, sizeof(findINCEXE));
704 fileset->incexe->opts_list.init(1, true);
705 fileset->incexe->name_list.init(1, true);
706 fileset->exclude_list.append(fileset->incexe);
712 /* File item to either include/include list */
713 state = state_include;
714 add_file_to_fileset(jcr, item, fileset);
717 current_opts = start_options(ff);
721 preg = (regex_t *)malloc(sizeof(regex_t));
722 if (current_opts->flags & FO_IGNORECASE) {
723 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
725 rc = regcomp(preg, item, REG_EXTENDED);
728 regerror(rc, preg, prbuf, sizeof(prbuf));
731 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
735 state = state_options;
736 if (subcode == ' ') {
737 current_opts->regex.append(preg);
738 } else if (subcode == 'D') {
739 current_opts->regexdir.append(preg);
740 } else if (subcode == 'F') {
741 current_opts->regexfile.append(preg);
747 current_opts = start_options(ff);
748 current_opts->base.append(bstrdup(item));
749 state = state_options;
752 current_opts = start_options(ff);
753 state = state_options;
754 if (subcode == ' ') {
755 current_opts->fstype.append(bstrdup(item));
756 } else if (subcode == 'D') {
757 current_opts->drivetype.append(bstrdup(item));
763 current_opts = start_options(ff);
764 state = state_options;
765 if (subcode == ' ') {
766 current_opts->wild.append(bstrdup(item));
767 } else if (subcode == 'D') {
768 current_opts->wilddir.append(bstrdup(item));
769 } else if (subcode == 'F') {
770 current_opts->wildfile.append(bstrdup(item));
771 } else if (subcode == 'B') {
772 current_opts->wildbase.append(bstrdup(item));
778 current_opts = start_options(ff);
779 set_options(current_opts, item);
780 state = state_options;
783 current_opts = start_options(ff);
784 current_opts->reader = bstrdup(item);
785 state = state_options;
788 current_opts = start_options(ff);
789 current_opts->writer = bstrdup(item);
790 state = state_options;
793 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
797 ff->fileset->state = state;
800 static bool term_fileset(JCR *jcr)
802 FF_PKT *ff = jcr->ff;
805 findFILESET *fileset = ff->fileset;
808 for (i=0; i<fileset->include_list.size(); i++) {
809 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
811 for (j=0; j<incexe->opts_list.size(); j++) {
812 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
813 for (k=0; k<fo->regex.size(); k++) {
814 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
816 for (k=0; k<fo->regexdir.size(); k++) {
817 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
819 for (k=0; k<fo->regexfile.size(); k++) {
820 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
822 for (k=0; k<fo->wild.size(); k++) {
823 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
825 for (k=0; k<fo->wilddir.size(); k++) {
826 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
828 for (k=0; k<fo->wildfile.size(); k++) {
829 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
831 for (k=0; k<fo->wildbase.size(); k++) {
832 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
834 for (k=0; k<fo->base.size(); k++) {
835 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
837 for (k=0; k<fo->fstype.size(); k++) {
838 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
840 for (k=0; k<fo->drivetype.size(); k++) {
841 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
844 Dmsg1(400, "D %s\n", fo->reader);
847 Dmsg1(400, "T %s\n", fo->writer);
850 for (j=0; j<incexe->name_list.size(); j++) {
851 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
854 for (i=0; i<fileset->exclude_list.size(); i++) {
855 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
857 for (j=0; j<incexe->opts_list.size(); j++) {
858 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
859 for (k=0; k<fo->regex.size(); k++) {
860 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
862 for (k=0; k<fo->regexdir.size(); k++) {
863 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
865 for (k=0; k<fo->regexfile.size(); k++) {
866 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
868 for (k=0; k<fo->wild.size(); k++) {
869 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
871 for (k=0; k<fo->wilddir.size(); k++) {
872 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
874 for (k=0; k<fo->wildfile.size(); k++) {
875 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
877 for (k=0; k<fo->wildbase.size(); k++) {
878 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
880 for (k=0; k<fo->base.size(); k++) {
881 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
883 for (k=0; k<fo->fstype.size(); k++) {
884 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
886 for (k=0; k<fo->drivetype.size(); k++) {
887 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
890 for (j=0; j<incexe->name_list.size(); j++) {
891 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
895 return ff->fileset->state != state_error;
900 * As an optimization, we should do this during
901 * "compile" time in filed/job.c, and keep only a bit mask
902 * and the Verify options.
904 static void set_options(findFOPTS *fo, const char *opts)
909 for (p=opts; *p; p++) {
911 case 'a': /* alway replace */
912 case '0': /* no option */
915 fo->flags |= FO_EXCLUDE;
918 fo->flags |= FO_MULTIFS;
920 case 'h': /* no recursion */
921 fo->flags |= FO_NO_RECURSION;
923 case 'H': /* no hard link handling */
924 fo->flags |= FO_NO_HARDLINK;
927 fo->flags |= FO_IGNORECASE;
933 fo->flags |= FO_NOREPLACE;
935 case 'p': /* use portable data format */
936 fo->flags |= FO_PORTABLE;
938 case 'R': /* Resource forks and Finder Info */
939 fo->flags |= FO_HFSPLUS;
940 case 'r': /* read fifo */
941 fo->flags |= FO_READFIFO;
946 /* Old director did not specify SHA variant */
947 fo->flags |= FO_SHA1;
950 fo->flags |= FO_SHA1;
955 fo->flags |= FO_SHA256;
959 fo->flags |= FO_SHA512;
964 /* Automatically downgrade to SHA-1 if an unsupported
965 * SHA variant is specified */
966 fo->flags |= FO_SHA1;
972 fo->flags |= FO_SPARSE;
975 fo->flags |= FO_MTIMEONLY;
978 fo->flags |= FO_KEEPATIME;
983 case 'V': /* verify options */
984 /* Copy Verify Options */
985 for (j=0; *p && *p != ':'; p++) {
986 fo->VerifyOpts[j] = *p;
987 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
991 fo->VerifyOpts[j] = 0;
994 fo->flags |= FO_IF_NEWER;
997 fo->flags |= FO_ENHANCEDWILD;
999 case 'Z': /* gzip compression */
1000 fo->flags |= FO_GZIP;
1001 fo->GZIP_level = *++p - '0';
1002 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
1005 fo->flags |= FO_NOATIME;
1008 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1016 * Director is passing his Fileset
1018 static int fileset_cmd(JCR *jcr)
1020 BSOCK *dir = jcr->dir_bsock;
1022 #if defined(WIN32_VSS)
1025 sscanf(dir->msg, "fileset vss=%d", &vss);
1029 if (!init_fileset(jcr)) {
1032 while (bnet_recv(dir) >= 0) {
1033 strip_trailing_junk(dir->msg);
1034 Dmsg1(500, "Fileset: %s\n", dir->msg);
1035 add_fileset(jcr, dir->msg);
1037 if (!term_fileset(jcr)) {
1040 return bnet_fsend(dir, OKinc);
1043 static void free_bootstrap(JCR *jcr)
1045 if (jcr->RestoreBootstrap) {
1046 unlink(jcr->RestoreBootstrap);
1047 free_pool_memory(jcr->RestoreBootstrap);
1048 jcr->RestoreBootstrap = NULL;
1053 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1054 static uint32_t bsr_uniq = 0;
1057 * The Director sends us the bootstrap file, which
1058 * we will in turn pass to the SD.
1060 static int bootstrap_cmd(JCR *jcr)
1062 BSOCK *dir = jcr->dir_bsock;
1063 POOLMEM *fname = get_pool_memory(PM_FNAME);
1066 free_bootstrap(jcr);
1069 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1070 jcr->Job, bsr_uniq);
1072 Dmsg1(400, "bootstrap=%s\n", fname);
1073 jcr->RestoreBootstrap = fname;
1074 bs = fopen(fname, "a+b"); /* create file */
1077 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1078 jcr->RestoreBootstrap, be.strerror());
1080 * Suck up what he is sending to us so that he will then
1081 * read our error message.
1083 while (bnet_recv(dir) >= 0)
1085 free_bootstrap(jcr);
1086 set_jcr_job_status(jcr, JS_ErrorTerminated);
1090 while (bnet_recv(dir) >= 0) {
1091 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1092 fputs(dir->msg, bs);
1096 * Note, do not free the bootstrap yet -- it needs to be
1099 return bnet_fsend(dir, OKbootstrap);
1104 * Get backup level from Director
1107 static int level_cmd(JCR *jcr)
1109 BSOCK *dir = jcr->dir_bsock;
1110 POOLMEM *level, *buf = NULL;
1113 level = get_memory(dir->msglen+1);
1114 Dmsg1(110, "level_cmd: %s", dir->msg);
1115 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1118 /* Base backup requested? */
1119 if (strcmp(level, "base") == 0) {
1120 jcr->JobLevel = L_BASE;
1121 /* Full backup requested? */
1122 } else if (strcmp(level, "full") == 0) {
1123 jcr->JobLevel = L_FULL;
1124 } else if (strcmp(level, "differential") == 0) {
1125 jcr->JobLevel = L_DIFFERENTIAL;
1128 } else if (strcmp(level, "incremental") == 0) {
1129 jcr->JobLevel = L_INCREMENTAL;
1133 * We get his UTC since time, then sync the clocks and correct it
1134 * to agree with our clock.
1136 } else if (strcmp(level, "since_utime") == 0) {
1137 buf = get_memory(dir->msglen+1);
1138 utime_t since_time, adj;
1139 btime_t his_time, bt_start, rt=0, bt_adj=0;
1140 if (jcr->JobLevel == L_NONE) {
1141 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1143 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1144 buf, &mtime_only) != 2) {
1147 since_time = str_to_uint64(buf); /* this is the since time */
1148 Dmsg1(100, "since_time=%d\n", (int)since_time);
1149 char ed1[50], ed2[50];
1151 * Sync clocks by polling him for the time. We take
1152 * 10 samples of his time throwing out the first two.
1154 for (int i=0; i<10; i++) {
1155 bt_start = get_current_btime();
1156 bnet_sig(dir, BNET_BTIME); /* poll for time */
1157 if (bnet_recv(dir) <= 0) { /* get response */
1160 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1163 if (i < 2) { /* toss first two results */
1166 his_time = str_to_uint64(buf);
1167 rt = get_current_btime() - bt_start; /* compute round trip time */
1168 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1169 edit_uint64(bt_start, ed2));
1170 bt_adj += bt_start - his_time - rt/2;
1171 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1174 bt_adj = bt_adj / 8; /* compute average time */
1175 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1176 adj = btime_to_utime(bt_adj);
1177 since_time += adj; /* adjust for clock difference */
1179 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1181 bnet_sig(dir, BNET_EOD);
1183 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1184 jcr->incremental = 1; /* set incremental or decremental backup */
1185 jcr->mtime = (time_t)since_time; /* set since time */
1187 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1195 return bnet_fsend(dir, OKlevel);
1198 pm_strcpy(jcr->errmsg, dir->msg);
1199 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1208 * Get session parameters from Director -- this is for a Restore command
1210 static int session_cmd(JCR *jcr)
1212 BSOCK *dir = jcr->dir_bsock;
1214 Dmsg1(100, "SessionCmd: %s", dir->msg);
1215 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1216 &jcr->VolSessionId, &jcr->VolSessionTime,
1217 &jcr->StartFile, &jcr->EndFile,
1218 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1219 pm_strcpy(jcr->errmsg, dir->msg);
1220 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1224 return bnet_fsend(dir, OKsession);
1228 * Get address of storage daemon from Director
1231 static int storage_cmd(JCR *jcr)
1233 int stored_port; /* storage daemon port */
1234 int enable_ssl; /* enable ssl to sd */
1235 BSOCK *dir = jcr->dir_bsock;
1236 BSOCK *sd; /* storage daemon bsock */
1238 Dmsg1(100, "StorageCmd: %s", dir->msg);
1239 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1240 pm_strcpy(jcr->errmsg, dir->msg);
1241 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1244 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1245 /* Open command communications with Storage daemon */
1246 /* Try to connect for 1 hour at 10 second intervals */
1247 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1248 jcr->stored_addr, NULL, stored_port, 1);
1250 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1251 jcr->stored_addr, stored_port);
1252 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1253 jcr->stored_addr, stored_port);
1256 Dmsg0(110, "Connection OK to SD.\n");
1258 jcr->store_bsock = sd;
1260 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1261 if (!authenticate_storagedaemon(jcr)) {
1262 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1265 Dmsg0(110, "Authenticated with SD.\n");
1267 /* Send OK to Director */
1268 return bnet_fsend(dir, OKstore);
1275 static int backup_cmd(JCR *jcr)
1277 BSOCK *dir = jcr->dir_bsock;
1278 BSOCK *sd = jcr->store_bsock;
1281 char ed1[50], ed2[50];
1282 bool bDoVSS = false;
1284 #if defined(WIN32_VSS)
1285 // capture state here, if client is backed up by multiple directors
1286 // and one enables vss and the other does not then enable_vss can change
1287 // between here and where its evaluated after the job completes.
1288 bDoVSS = g_pVSSClient && enable_vss;
1290 /* Run only one at a time */
1295 set_jcr_job_status(jcr, JS_Blocked);
1296 jcr->JobType = JT_BACKUP;
1297 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1300 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1304 bnet_fsend(dir, OKbackup);
1305 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1308 * Send Append Open Session to Storage daemon
1310 bnet_fsend(sd, append_open);
1311 Dmsg1(110, ">stored: %s", sd->msg);
1313 * Expect to receive back the Ticket number
1315 if (bget_msg(sd) >= 0) {
1316 Dmsg1(110, "<stored: %s", sd->msg);
1317 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1318 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1321 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1323 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1328 * Send Append data command to Storage daemon
1330 bnet_fsend(sd, append_data, jcr->Ticket);
1331 Dmsg1(110, ">stored: %s", sd->msg);
1334 * Expect to get OK data
1336 Dmsg1(110, "<stored: %s", sd->msg);
1337 if (!response(jcr, sd, OK_data, "Append Data")) {
1341 generate_daemon_event(jcr, "JobStart");
1343 #if defined(WIN32_VSS)
1344 /* START VSS ON WIN 32 */
1346 if (g_pVSSClient->InitializeForBackup()) {
1347 /* tell vss which drives to snapshot */
1348 char szWinDriveLetters[27];
1349 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1350 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1351 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1352 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1355 /* tell user if snapshot creation of a specific drive failed */
1357 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1358 if (islower(szWinDriveLetters[i])) {
1359 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1363 /* inform user about writer states */
1364 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1365 if (g_pVSSClient->GetWriterState(i) < 1) {
1366 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1371 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1375 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1381 * Send Files to Storage daemon
1383 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1384 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1385 set_jcr_job_status(jcr, JS_ErrorTerminated);
1386 bnet_suppress_error_messages(sd, 1);
1387 bget_msg(sd); /* Read final response from append_data */
1388 Dmsg0(110, "Error in blast_data.\n");
1389 /* run shortly after end of data transmission */
1390 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1391 jcr->runscript_after=1;
1394 set_jcr_job_status(jcr, JS_Terminated);
1396 /* run shortly after end of data transmission */
1397 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1398 jcr->runscript_after=1;
1400 if (jcr->JobStatus != JS_Terminated) {
1401 bnet_suppress_error_messages(sd, 1);
1402 goto cleanup; /* bail out now */
1405 * Expect to get response to append_data from Storage daemon
1407 if (!response(jcr, sd, OK_append, "Append Data")) {
1408 set_jcr_job_status(jcr, JS_ErrorTerminated);
1413 * Send Append End Data to Storage daemon
1415 bnet_fsend(sd, append_end, jcr->Ticket);
1417 if (!response(jcr, sd, OK_end, "Append End")) {
1418 set_jcr_job_status(jcr, JS_ErrorTerminated);
1423 * Send Append Close to Storage daemon
1425 bnet_fsend(sd, append_close, jcr->Ticket);
1426 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1427 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1429 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1433 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1436 if (SDJobStatus != JS_Terminated) {
1437 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1443 #if defined(WIN32_VSS)
1444 /* STOP VSS ON WIN 32 */
1445 /* tell vss to close the backup session */
1447 if (g_pVSSClient->CloseBackup()) {
1448 /* inform user about writer states */
1449 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1450 int msg_type = M_INFO;
1451 if (g_pVSSClient->GetWriterState(i) < 1) {
1452 msg_type = M_WARNING;
1455 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1462 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1463 edit_uint64(jcr->ReadBytes, ed1),
1464 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, (int)bDoVSS,
1466 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1468 return 0; /* return and stop command loop */
1472 * Do a Verify for Director
1475 static int verify_cmd(JCR *jcr)
1477 BSOCK *dir = jcr->dir_bsock;
1478 BSOCK *sd = jcr->store_bsock;
1479 char level[100], ed1[50], ed2[50];
1481 jcr->JobType = JT_VERIFY;
1482 if (sscanf(dir->msg, verifycmd, level) != 1) {
1483 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1487 if (strcasecmp(level, "init") == 0) {
1488 jcr->JobLevel = L_VERIFY_INIT;
1489 } else if (strcasecmp(level, "catalog") == 0){
1490 jcr->JobLevel = L_VERIFY_CATALOG;
1491 } else if (strcasecmp(level, "volume") == 0){
1492 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1493 } else if (strcasecmp(level, "data") == 0){
1494 jcr->JobLevel = L_VERIFY_DATA;
1495 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1496 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1498 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1502 bnet_fsend(dir, OKverify);
1504 generate_daemon_event(jcr, "JobStart");
1506 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1508 switch (jcr->JobLevel) {
1510 case L_VERIFY_CATALOG:
1513 case L_VERIFY_VOLUME_TO_CATALOG:
1514 if (!open_sd_read_session(jcr)) {
1517 start_dir_heartbeat(jcr);
1518 do_verify_volume(jcr);
1519 stop_dir_heartbeat(jcr);
1521 * Send Close session command to Storage daemon
1523 bnet_fsend(sd, read_close, jcr->Ticket);
1524 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1526 /* ****FIXME**** check response */
1527 bget_msg(sd); /* get OK */
1529 /* Inform Storage daemon that we are done */
1530 bnet_sig(sd, BNET_TERMINATE);
1533 case L_VERIFY_DISK_TO_CATALOG:
1537 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1541 bnet_sig(dir, BNET_EOD);
1543 /* Send termination status back to Dir */
1544 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1545 edit_uint64(jcr->ReadBytes, ed1),
1546 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1548 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1550 /* Inform Director that we are done */
1551 bnet_sig(dir, BNET_TERMINATE);
1552 return 0; /* return and terminate command loop */
1556 * Do a Restore for Director
1559 static int restore_cmd(JCR *jcr)
1561 BSOCK *dir = jcr->dir_bsock;
1562 BSOCK *sd = jcr->store_bsock;
1566 char ed1[50], ed2[50];
1569 * Scan WHERE (base directory for restore) from command
1571 Dmsg0(150, "restore command\n");
1572 /* Pickup where string */
1573 where = get_memory(dir->msglen+1);
1576 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1577 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1578 pm_strcpy(jcr->errmsg, dir->msg);
1579 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1584 /* Turn / into nothing */
1585 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1589 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1590 unbash_spaces(where);
1591 jcr->where = bstrdup(where);
1592 free_pool_memory(where);
1593 jcr->replace = replace;
1594 jcr->prefix_links = prefix_links;
1596 bnet_fsend(dir, OKrestore);
1597 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1599 jcr->JobType = JT_RESTORE;
1601 set_jcr_job_status(jcr, JS_Blocked);
1603 if (!open_sd_read_session(jcr)) {
1604 set_jcr_job_status(jcr, JS_ErrorTerminated);
1608 set_jcr_job_status(jcr, JS_Running);
1611 * Do restore of files and data
1613 start_dir_heartbeat(jcr);
1614 generate_daemon_event(jcr, "JobStart");
1616 stop_dir_heartbeat(jcr);
1618 set_jcr_job_status(jcr, JS_Terminated);
1619 if (jcr->JobStatus != JS_Terminated) {
1620 bnet_suppress_error_messages(sd, 1);
1624 * Send Close session command to Storage daemon
1626 bnet_fsend(sd, read_close, jcr->Ticket);
1627 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1629 bget_msg(sd); /* get OK */
1631 /* Inform Storage daemon that we are done */
1632 bnet_sig(sd, BNET_TERMINATE);
1637 set_jcr_job_status(jcr, JS_ErrorTerminated);
1639 /* Send termination status back to Dir */
1640 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1641 edit_uint64(jcr->ReadBytes, ed1),
1642 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1644 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1646 /* Inform Director that we are done */
1647 bnet_sig(dir, BNET_TERMINATE);
1649 Dmsg0(130, "Done in job.c\n");
1650 return 0; /* return and terminate command loop */
1653 static int open_sd_read_session(JCR *jcr)
1655 BSOCK *sd = jcr->store_bsock;
1658 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1661 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1662 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1663 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1665 * Open Read Session with Storage daemon
1667 bnet_fsend(sd, read_open, "DummyVolume",
1668 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1669 jcr->StartBlock, jcr->EndBlock);
1670 Dmsg1(110, ">stored: %s", sd->msg);
1675 if (bget_msg(sd) >= 0) {
1676 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1677 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1678 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1681 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1683 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1687 if (!send_bootstrap_file(jcr)) {
1692 * Start read of data with Storage daemon
1694 bnet_fsend(sd, read_data, jcr->Ticket);
1695 Dmsg1(110, ">stored: %s", sd->msg);
1700 if (!response(jcr, sd, OK_data, "Read Data")) {
1707 * Destroy the Job Control Record and associated
1708 * resources (sockets).
1710 static void filed_free_jcr(JCR *jcr)
1712 if (jcr->store_bsock) {
1713 bnet_close(jcr->store_bsock);
1715 free_bootstrap(jcr);
1716 if (jcr->last_fname) {
1717 free_pool_memory(jcr->last_fname);
1719 free_runscripts(jcr->RunScripts);
1720 delete jcr->RunScripts;
1726 * Get response from Storage daemon to a command we
1727 * sent. Check that the response is OK.
1729 * Returns: 0 on failure
1732 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1737 if (bget_msg(sd) > 0) {
1738 Dmsg0(110, sd->msg);
1739 if (strcmp(sd->msg, resp) == 0) {
1743 if (job_canceled(jcr)) {
1744 return 0; /* if canceled avoid useless error messages */
1746 if (is_bnet_error(sd)) {
1747 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1748 cmd, bnet_strerror(sd));
1750 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1751 cmd, resp, sd->msg);
1756 static int send_bootstrap_file(JCR *jcr)
1760 BSOCK *sd = jcr->store_bsock;
1761 const char *bootstrap = "bootstrap\n";
1764 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1765 if (!jcr->RestoreBootstrap) {
1768 bs = fopen(jcr->RestoreBootstrap, "rb");
1771 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1772 jcr->RestoreBootstrap, be.strerror());
1773 set_jcr_job_status(jcr, JS_ErrorTerminated);
1776 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1778 while (fgets(buf, sizeof(buf), bs)) {
1779 sd->msglen = Mmsg(sd->msg, "%s", buf);
1782 bnet_sig(sd, BNET_EOD);
1784 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1785 set_jcr_job_status(jcr, JS_ErrorTerminated);
1791 free_bootstrap(jcr);