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 illegal_cmd[] = "2997 Illegal 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";
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 JobBytes=%s Errors=%u\n";
141 static char OKRunBefore[] = "2000 OK RunBefore\n";
142 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
143 static char OKRunAfter[] = "2000 OK RunAfter\n";
144 static char OKRunScript[] = "2000 OK RunScript\n";
147 /* Responses received from Storage Daemon */
148 static char OK_end[] = "3000 OK end\n";
149 static char OK_close[] = "3000 OK close Status = %d\n";
150 static char OK_open[] = "3000 OK open ticket = %d\n";
151 static char OK_data[] = "3000 OK data\n";
152 static char OK_append[] = "3000 OK append data\n";
153 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
156 /* Commands sent to Storage Daemon */
157 static char append_open[] = "append open session\n";
158 static char append_data[] = "append data %d\n";
159 static char append_end[] = "append end session %d\n";
160 static char append_close[] = "append close session %d\n";
161 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
162 static char read_data[] = "read data %d\n";
163 static char read_close[] = "read close session %d\n";
166 * Accept requests from a Director
168 * NOTE! We are running as a separate thread
170 * Send output one line
171 * at a time followed by a zero length transmission.
173 * Return when the connection is terminated or there
176 * Basic task here is:
177 * Authenticate Director (during Hello command).
178 * Accept commands one at a time from the Director
182 void *handle_client_request(void *dirp)
187 BSOCK *dir = (BSOCK *)dirp;
189 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
190 jcr->dir_bsock = dir;
191 jcr->ff = init_find_files();
192 jcr->start_time = time(NULL);
193 jcr->RunScripts = New(alist(10, not_owned_by_alist));
194 jcr->last_fname = get_pool_memory(PM_FNAME);
195 jcr->last_fname[0] = 0;
196 jcr->client_name = get_memory(strlen(my_name) + 1);
197 pm_strcpy(jcr->client_name, my_name);
198 jcr->pki_sign = me->pki_sign;
199 jcr->pki_encrypt = me->pki_encrypt;
200 jcr->pki_keypair = me->pki_keypair;
201 jcr->pki_signers = me->pki_signers;
202 jcr->pki_recipients = me->pki_recipients;
204 enable_backup_privileges(NULL, 1 /* ignore_errors */);
206 /**********FIXME******* add command handler error code */
208 for (quit=false; !quit;) {
211 if (bnet_recv(dir) < 0) {
212 break; /* connection terminated */
214 dir->msg[dir->msglen] = 0;
215 Dmsg1(100, "<dird: %s", dir->msg);
217 for (i=0; cmds[i].cmd; i++) {
218 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
219 found = true; /* indicate command found */
220 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
221 bnet_fsend(dir, no_auth);
222 bnet_sig(dir, BNET_EOD);
225 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
226 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
227 bnet_fsend(dir, illegal_cmd);
228 bnet_sig(dir, BNET_EOD);
231 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
232 if (!cmds[i].func(jcr)) { /* do command */
233 quit = true; /* error or fully terminated, get out */
234 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
239 if (!found) { /* command not found */
240 bnet_fsend(dir, errmsg);
246 if (!jcr->runscript_after) {
247 jcr->runscript_after=1;
248 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
251 /* Inform Storage daemon that we are done */
252 if (jcr->store_bsock) {
253 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
256 generate_daemon_event(jcr, "JobEnd");
258 dequeue_messages(jcr); /* send any queued messages */
260 /* Inform Director that we are done */
261 bnet_sig(dir, BNET_TERMINATE);
263 /* Clean up fileset */
264 FF_PKT *ff = jcr->ff;
265 findFILESET *fileset = ff->fileset;
268 /* Delete FileSet Include lists */
269 for (i=0; i<fileset->include_list.size(); i++) {
270 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
271 for (j=0; j<incexe->opts_list.size(); j++) {
272 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
273 for (k=0; k<fo->regex.size(); k++) {
274 regfree((regex_t *)fo->regex.get(k));
277 fo->regexdir.destroy();
278 fo->regexfile.destroy();
280 fo->wilddir.destroy();
281 fo->wildfile.destroy();
282 fo->wildbase.destroy();
284 fo->fstype.destroy();
285 fo->drivetype.destroy();
293 incexe->opts_list.destroy();
294 incexe->name_list.destroy();
296 fileset->include_list.destroy();
298 /* Delete FileSet Exclude lists */
299 for (i=0; i<fileset->exclude_list.size(); i++) {
300 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
301 for (j=0; j<incexe->opts_list.size(); j++) {
302 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
304 fo->regexdir.destroy();
305 fo->regexfile.destroy();
307 fo->wilddir.destroy();
308 fo->wildfile.destroy();
309 fo->wildbase.destroy();
311 fo->fstype.destroy();
312 fo->drivetype.destroy();
314 incexe->opts_list.destroy();
315 incexe->name_list.destroy();
317 fileset->exclude_list.destroy();
321 Dmsg0(100, "Calling term_find_files\n");
322 term_find_files(jcr->ff);
324 Dmsg0(100, "Done with term_find_files\n");
325 free_jcr(jcr); /* destroy JCR record */
326 Dmsg0(100, "Done with free_jcr\n");
331 * Hello from Director he must identify himself and provide his
334 static int hello_cmd(JCR *jcr)
336 Dmsg0(120, "Calling Authenticate\n");
337 if (!authenticate_director(jcr)) {
340 Dmsg0(120, "OK Authenticate\n");
341 jcr->authenticated = true;
348 static int cancel_cmd(JCR *jcr)
350 BSOCK *dir = jcr->dir_bsock;
351 char Job[MAX_NAME_LENGTH];
354 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
355 if (!(cjcr=get_jcr_by_full_name(Job))) {
356 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
358 if (cjcr->store_bsock) {
359 cjcr->store_bsock->timed_out = 1;
360 cjcr->store_bsock->terminated = 1;
361 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
363 set_jcr_job_status(cjcr, JS_Canceled);
365 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
368 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
370 bnet_sig(dir, BNET_EOD);
376 * Set debug level as requested by the Director
379 static int setdebug_cmd(JCR *jcr)
381 BSOCK *dir = jcr->dir_bsock;
382 int level, trace_flag;
384 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
385 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
386 pm_strcpy(jcr->errmsg, dir->msg);
387 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
391 set_trace(trace_flag);
392 return bnet_fsend(dir, OKsetdebug, level);
396 static int estimate_cmd(JCR *jcr)
398 BSOCK *dir = jcr->dir_bsock;
401 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
402 pm_strcpy(jcr->errmsg, dir->msg);
403 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
404 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
408 bnet_fsend(dir, OKest, jcr->num_files_examined,
409 edit_uint64_with_commas(jcr->JobBytes, ed2));
410 bnet_sig(dir, BNET_EOD);
415 * Get JobId and Storage Daemon Authorization key from Director
417 static int job_cmd(JCR *jcr)
419 BSOCK *dir = jcr->dir_bsock;
420 POOLMEM *sd_auth_key;
422 sd_auth_key = get_memory(dir->msglen);
423 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
424 &jcr->VolSessionId, &jcr->VolSessionTime,
426 pm_strcpy(jcr->errmsg, dir->msg);
427 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
428 bnet_fsend(dir, BADjob);
429 free_pool_memory(sd_auth_key);
432 jcr->sd_auth_key = bstrdup(sd_auth_key);
433 free_pool_memory(sd_auth_key);
434 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
435 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
438 static int runbefore_cmd(JCR *jcr)
441 BSOCK *dir = jcr->dir_bsock;
442 POOLMEM *cmd = get_memory(dir->msglen+1);
445 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
446 if (sscanf(dir->msg, runbefore, cmd) != 1) {
447 pm_strcpy(jcr->errmsg, dir->msg);
448 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
449 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
455 /* Run the command now */
456 script = new_runscript();
457 script->set_command(cmd);
458 script->when = SCRIPT_Before;
459 ok = script->run(jcr, "ClientRunBeforeJob");
460 free_runscript(script);
464 bnet_fsend(dir, OKRunBefore);
467 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
472 static int runbeforenow_cmd(JCR *jcr)
474 BSOCK *dir = jcr->dir_bsock;
476 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
477 if (job_canceled(jcr)) {
478 return bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
480 return bnet_fsend(dir, OKRunBeforeNow);
484 static int runafter_cmd(JCR *jcr)
486 BSOCK *dir = jcr->dir_bsock;
487 POOLMEM *msg = get_memory(dir->msglen+1);
490 Dmsg1(100, "runafter_cmd: %s", dir->msg);
491 if (sscanf(dir->msg, runafter, msg) != 1) {
492 pm_strcpy(jcr->errmsg, dir->msg);
493 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
494 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
500 cmd = new_runscript();
501 cmd->set_command(msg);
502 cmd->on_success = true;
503 cmd->on_failure = false;
504 cmd->when = SCRIPT_After;
506 jcr->RunScripts->append(cmd);
508 free_pool_memory(msg);
509 return bnet_fsend(dir, OKRunAfter);
512 static int runscript_cmd(JCR *jcr)
514 BSOCK *dir = jcr->dir_bsock;
515 POOLMEM *msg = get_memory(dir->msglen+1);
517 RUNSCRIPT *cmd = new_runscript() ;
519 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
520 if (sscanf(dir->msg, runscript, &cmd->on_success,
522 &cmd->abort_on_error,
525 pm_strcpy(jcr->errmsg, dir->msg);
526 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
527 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
534 cmd->set_command(msg);
536 jcr->RunScripts->append(cmd);
538 free_pool_memory(msg);
539 return bnet_fsend(dir, OKRunScript);
543 static bool init_fileset(JCR *jcr)
546 findFILESET *fileset;
555 fileset = (findFILESET *)malloc(sizeof(findFILESET));
556 memset(fileset, 0, sizeof(findFILESET));
557 ff->fileset = fileset;
558 fileset->state = state_none;
559 fileset->include_list.init(1, true);
560 fileset->exclude_list.init(1, true);
564 static findFOPTS *start_options(FF_PKT *ff)
566 int state = ff->fileset->state;
567 findINCEXE *incexe = ff->fileset->incexe;
569 if (state != state_options) {
570 ff->fileset->state = state_options;
571 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
572 memset(fo, 0, sizeof(findFOPTS));
573 fo->regex.init(1, true);
574 fo->regexdir.init(1, true);
575 fo->regexfile.init(1, true);
576 fo->wild.init(1, true);
577 fo->wilddir.init(1, true);
578 fo->wildfile.init(1, true);
579 fo->wildbase.init(1, true);
580 fo->base.init(1, true);
581 fo->fstype.init(1, true);
582 fo->drivetype.init(1, true);
583 incexe->current_opts = fo;
584 incexe->opts_list.append(fo);
586 return incexe->current_opts;
591 * Add fname to include/exclude fileset list. First check for
592 * | and < and if necessary perform command.
594 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
608 p++; /* skip over | */
609 fn = get_pool_memory(PM_FNAME);
610 fn = edit_job_codes(jcr, fn, p, "");
611 bpipe = open_bpipe(fn, 0, "r");
614 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
616 free_pool_memory(fn);
619 free_pool_memory(fn);
620 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
621 strip_trailing_junk(buf);
622 fileset->incexe->name_list.append(bstrdup(buf));
624 if ((stat=close_bpipe(bpipe)) != 0) {
626 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
627 p, be.code(stat), be.strerror(stat));
632 Dmsg0(100, "Doing < include on client.\n");
633 p++; /* skip over < */
634 if ((ffd = fopen(p, "rb")) == NULL) {
636 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
640 while (fgets(buf, sizeof(buf), ffd)) {
641 strip_trailing_junk(buf);
642 Dmsg1(100, "%s\n", buf);
643 fileset->incexe->name_list.append(bstrdup(buf));
648 fileset->incexe->name_list.append(bstrdup(fname));
654 static void add_fileset(JCR *jcr, const char *item)
656 FF_PKT *ff = jcr->ff;
657 findFILESET *fileset = ff->fileset;
658 int state = fileset->state;
659 findFOPTS *current_opts;
661 /* Get code, optional subcode, and position item past the dividing space */
662 Dmsg1(100, "%s\n", item);
667 int subcode = ' '; /* A space is always a valid subcode */
668 if (item[0] != '\0' && item[0] != ' ') {
676 /* Skip all lines we receive after an error */
677 if (state == state_error) {
682 * The switch tests the code for validity.
683 * The subcode is always good if it is a space, otherwise we must confirm.
684 * We set state to state_error first assuming the subcode is invalid,
685 * requiring state to be set in cases below that handle subcodes.
687 if (subcode != ' ') {
693 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
694 memset(fileset->incexe, 0, sizeof(findINCEXE));
695 fileset->incexe->opts_list.init(1, true);
696 fileset->incexe->name_list.init(1, true);
697 fileset->include_list.append(fileset->incexe);
701 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
702 memset(fileset->incexe, 0, sizeof(findINCEXE));
703 fileset->incexe->opts_list.init(1, true);
704 fileset->incexe->name_list.init(1, true);
705 fileset->exclude_list.append(fileset->incexe);
711 /* File item to either include/include list */
712 state = state_include;
713 add_file_to_fileset(jcr, item, fileset);
716 current_opts = start_options(ff);
720 preg = (regex_t *)malloc(sizeof(regex_t));
721 if (current_opts->flags & FO_IGNORECASE) {
722 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
724 rc = regcomp(preg, item, REG_EXTENDED);
727 regerror(rc, preg, prbuf, sizeof(prbuf));
730 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
734 state = state_options;
735 if (subcode == ' ') {
736 current_opts->regex.append(preg);
737 } else if (subcode == 'D') {
738 current_opts->regexdir.append(preg);
739 } else if (subcode == 'F') {
740 current_opts->regexfile.append(preg);
746 current_opts = start_options(ff);
747 current_opts->base.append(bstrdup(item));
748 state = state_options;
751 current_opts = start_options(ff);
752 state = state_options;
753 if (subcode == ' ') {
754 current_opts->fstype.append(bstrdup(item));
755 } else if (subcode == 'D') {
756 current_opts->drivetype.append(bstrdup(item));
762 current_opts = start_options(ff);
763 state = state_options;
764 if (subcode == ' ') {
765 current_opts->wild.append(bstrdup(item));
766 } else if (subcode == 'D') {
767 current_opts->wilddir.append(bstrdup(item));
768 } else if (subcode == 'F') {
769 current_opts->wildfile.append(bstrdup(item));
770 } else if (subcode == 'B') {
771 current_opts->wildbase.append(bstrdup(item));
777 current_opts = start_options(ff);
778 set_options(current_opts, item);
779 state = state_options;
782 current_opts = start_options(ff);
783 current_opts->reader = bstrdup(item);
784 state = state_options;
787 current_opts = start_options(ff);
788 current_opts->writer = bstrdup(item);
789 state = state_options;
792 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
796 ff->fileset->state = state;
799 static bool term_fileset(JCR *jcr)
801 FF_PKT *ff = jcr->ff;
804 findFILESET *fileset = ff->fileset;
807 for (i=0; i<fileset->include_list.size(); i++) {
808 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
810 for (j=0; j<incexe->opts_list.size(); j++) {
811 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
812 for (k=0; k<fo->regex.size(); k++) {
813 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
815 for (k=0; k<fo->regexdir.size(); k++) {
816 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
818 for (k=0; k<fo->regexfile.size(); k++) {
819 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
821 for (k=0; k<fo->wild.size(); k++) {
822 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
824 for (k=0; k<fo->wilddir.size(); k++) {
825 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
827 for (k=0; k<fo->wildfile.size(); k++) {
828 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
830 for (k=0; k<fo->wildbase.size(); k++) {
831 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.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));
839 for (k=0; k<fo->drivetype.size(); k++) {
840 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
843 Dmsg1(400, "D %s\n", fo->reader);
846 Dmsg1(400, "T %s\n", fo->writer);
849 for (j=0; j<incexe->name_list.size(); j++) {
850 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
853 for (i=0; i<fileset->exclude_list.size(); i++) {
854 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
856 for (j=0; j<incexe->opts_list.size(); j++) {
857 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
858 for (k=0; k<fo->regex.size(); k++) {
859 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
861 for (k=0; k<fo->regexdir.size(); k++) {
862 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
864 for (k=0; k<fo->regexfile.size(); k++) {
865 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
867 for (k=0; k<fo->wild.size(); k++) {
868 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
870 for (k=0; k<fo->wilddir.size(); k++) {
871 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
873 for (k=0; k<fo->wildfile.size(); k++) {
874 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
876 for (k=0; k<fo->wildbase.size(); k++) {
877 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
879 for (k=0; k<fo->base.size(); k++) {
880 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
882 for (k=0; k<fo->fstype.size(); k++) {
883 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
885 for (k=0; k<fo->drivetype.size(); k++) {
886 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
889 for (j=0; j<incexe->name_list.size(); j++) {
890 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
894 return ff->fileset->state != state_error;
899 * As an optimization, we should do this during
900 * "compile" time in filed/job.c, and keep only a bit mask
901 * and the Verify options.
903 static void set_options(findFOPTS *fo, const char *opts)
908 for (p=opts; *p; p++) {
910 case 'a': /* alway replace */
911 case '0': /* no option */
914 fo->flags |= FO_EXCLUDE;
917 fo->flags |= FO_MULTIFS;
919 case 'h': /* no recursion */
920 fo->flags |= FO_NO_RECURSION;
922 case 'H': /* no hard link handling */
923 fo->flags |= FO_NO_HARDLINK;
926 fo->flags |= FO_IGNORECASE;
932 fo->flags |= FO_NOREPLACE;
934 case 'p': /* use portable data format */
935 fo->flags |= FO_PORTABLE;
937 case 'R': /* Resource forks and Finder Info */
938 fo->flags |= FO_HFSPLUS;
939 case 'r': /* read fifo */
940 fo->flags |= FO_READFIFO;
945 /* Old director did not specify SHA variant */
946 fo->flags |= FO_SHA1;
949 fo->flags |= FO_SHA1;
954 fo->flags |= FO_SHA256;
958 fo->flags |= FO_SHA512;
963 /* Automatically downgrade to SHA-1 if an unsupported
964 * SHA variant is specified */
965 fo->flags |= FO_SHA1;
971 fo->flags |= FO_SPARSE;
974 fo->flags |= FO_MTIMEONLY;
977 fo->flags |= FO_KEEPATIME;
982 case 'V': /* verify options */
983 /* Copy Verify Options */
984 for (j=0; *p && *p != ':'; p++) {
985 fo->VerifyOpts[j] = *p;
986 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
990 fo->VerifyOpts[j] = 0;
993 fo->flags |= FO_IF_NEWER;
996 fo->flags |= FO_ENHANCEDWILD;
998 case 'Z': /* gzip compression */
999 fo->flags |= FO_GZIP;
1000 fo->GZIP_level = *++p - '0';
1001 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
1004 fo->flags |= FO_NOATIME;
1007 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1015 * Director is passing his Fileset
1017 static int fileset_cmd(JCR *jcr)
1019 BSOCK *dir = jcr->dir_bsock;
1021 #if defined(WIN32_VSS)
1024 sscanf(dir->msg, "fileset vss=%d", &vss);
1028 if (!init_fileset(jcr)) {
1031 while (bnet_recv(dir) >= 0) {
1032 strip_trailing_junk(dir->msg);
1033 Dmsg1(500, "Fileset: %s\n", dir->msg);
1034 add_fileset(jcr, dir->msg);
1036 if (!term_fileset(jcr)) {
1039 return bnet_fsend(dir, OKinc);
1042 static void free_bootstrap(JCR *jcr)
1044 if (jcr->RestoreBootstrap) {
1045 unlink(jcr->RestoreBootstrap);
1046 free_pool_memory(jcr->RestoreBootstrap);
1047 jcr->RestoreBootstrap = NULL;
1052 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1053 static uint32_t bsr_uniq = 0;
1056 * The Director sends us the bootstrap file, which
1057 * we will in turn pass to the SD.
1059 static int bootstrap_cmd(JCR *jcr)
1061 BSOCK *dir = jcr->dir_bsock;
1062 POOLMEM *fname = get_pool_memory(PM_FNAME);
1065 free_bootstrap(jcr);
1068 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1069 jcr->Job, bsr_uniq);
1071 Dmsg1(400, "bootstrap=%s\n", fname);
1072 jcr->RestoreBootstrap = fname;
1073 bs = fopen(fname, "a+b"); /* create file */
1076 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1077 jcr->RestoreBootstrap, be.strerror());
1079 * Suck up what he is sending to us so that he will then
1080 * read our error message.
1082 while (bnet_recv(dir) >= 0)
1084 free_bootstrap(jcr);
1085 set_jcr_job_status(jcr, JS_ErrorTerminated);
1089 while (bnet_recv(dir) >= 0) {
1090 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1091 fputs(dir->msg, bs);
1095 * Note, do not free the bootstrap yet -- it needs to be
1098 return bnet_fsend(dir, OKbootstrap);
1103 * Get backup level from Director
1106 static int level_cmd(JCR *jcr)
1108 BSOCK *dir = jcr->dir_bsock;
1109 POOLMEM *level, *buf = NULL;
1112 level = get_memory(dir->msglen+1);
1113 Dmsg1(110, "level_cmd: %s", dir->msg);
1114 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1117 /* Base backup requested? */
1118 if (strcmp(level, "base") == 0) {
1119 jcr->JobLevel = L_BASE;
1120 /* Full backup requested? */
1121 } else if (strcmp(level, "full") == 0) {
1122 jcr->JobLevel = L_FULL;
1123 } else if (strcmp(level, "differential") == 0) {
1124 jcr->JobLevel = L_DIFFERENTIAL;
1127 } else if (strcmp(level, "incremental") == 0) {
1128 jcr->JobLevel = L_INCREMENTAL;
1132 * We get his UTC since time, then sync the clocks and correct it
1133 * to agree with our clock.
1135 } else if (strcmp(level, "since_utime") == 0) {
1136 buf = get_memory(dir->msglen+1);
1137 utime_t since_time, adj;
1138 btime_t his_time, bt_start, rt=0, bt_adj=0;
1139 if (jcr->JobLevel == L_NONE) {
1140 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1142 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1143 buf, &mtime_only) != 2) {
1146 since_time = str_to_uint64(buf); /* this is the since time */
1147 Dmsg1(100, "since_time=%d\n", (int)since_time);
1148 char ed1[50], ed2[50];
1150 * Sync clocks by polling him for the time. We take
1151 * 10 samples of his time throwing out the first two.
1153 for (int i=0; i<10; i++) {
1154 bt_start = get_current_btime();
1155 bnet_sig(dir, BNET_BTIME); /* poll for time */
1156 if (bnet_recv(dir) <= 0) { /* get response */
1159 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1162 if (i < 2) { /* toss first two results */
1165 his_time = str_to_uint64(buf);
1166 rt = get_current_btime() - bt_start; /* compute round trip time */
1167 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1168 edit_uint64(bt_start, ed2));
1169 bt_adj += bt_start - his_time - rt/2;
1170 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1173 bt_adj = bt_adj / 8; /* compute average time */
1174 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1175 adj = btime_to_utime(bt_adj);
1176 since_time += adj; /* adjust for clock difference */
1178 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1180 bnet_sig(dir, BNET_EOD);
1182 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1183 jcr->incremental = 1; /* set incremental or decremental backup */
1184 jcr->mtime = (time_t)since_time; /* set since time */
1186 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1194 return bnet_fsend(dir, OKlevel);
1197 pm_strcpy(jcr->errmsg, dir->msg);
1198 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1207 * Get session parameters from Director -- this is for a Restore command
1209 static int session_cmd(JCR *jcr)
1211 BSOCK *dir = jcr->dir_bsock;
1213 Dmsg1(100, "SessionCmd: %s", dir->msg);
1214 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1215 &jcr->VolSessionId, &jcr->VolSessionTime,
1216 &jcr->StartFile, &jcr->EndFile,
1217 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1218 pm_strcpy(jcr->errmsg, dir->msg);
1219 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1223 return bnet_fsend(dir, OKsession);
1227 * Get address of storage daemon from Director
1230 static int storage_cmd(JCR *jcr)
1232 int stored_port; /* storage daemon port */
1233 int enable_ssl; /* enable ssl to sd */
1234 BSOCK *dir = jcr->dir_bsock;
1235 BSOCK *sd; /* storage daemon bsock */
1237 Dmsg1(100, "StorageCmd: %s", dir->msg);
1238 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1239 pm_strcpy(jcr->errmsg, dir->msg);
1240 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1243 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1244 /* Open command communications with Storage daemon */
1245 /* Try to connect for 1 hour at 10 second intervals */
1246 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1247 jcr->stored_addr, NULL, stored_port, 1);
1249 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1250 jcr->stored_addr, stored_port);
1251 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1252 jcr->stored_addr, stored_port);
1255 Dmsg0(110, "Connection OK to SD.\n");
1257 jcr->store_bsock = sd;
1259 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1260 if (!authenticate_storagedaemon(jcr)) {
1261 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1264 Dmsg0(110, "Authenticated with SD.\n");
1266 /* Send OK to Director */
1267 return bnet_fsend(dir, OKstore);
1272 * Do a backup. For now, we handle only Full and Incremental.
1274 static int backup_cmd(JCR *jcr)
1276 BSOCK *dir = jcr->dir_bsock;
1277 BSOCK *sd = jcr->store_bsock;
1280 char ed1[50], ed2[50];
1282 #if defined(WIN32_VSS)
1283 // capture state here, if client is backed up by multiple directors
1284 // and one enables vss and the other does not then enable_vss can change
1285 // between here and where its evaluated after the job completes.
1286 bool bDoVSS = false;
1288 bDoVSS = g_pVSSClient && enable_vss;
1290 /* Run only one at a time */
1294 set_jcr_job_status(jcr, JS_Blocked);
1295 jcr->JobType = JT_BACKUP;
1296 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1299 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1303 bnet_fsend(dir, OKbackup);
1304 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1307 * Send Append Open Session to Storage daemon
1309 bnet_fsend(sd, append_open);
1310 Dmsg1(110, ">stored: %s", sd->msg);
1312 * Expect to receive back the Ticket number
1314 if (bget_msg(sd) >= 0) {
1315 Dmsg1(110, "<stored: %s", sd->msg);
1316 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1317 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1320 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1322 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1327 * Send Append data command to Storage daemon
1329 bnet_fsend(sd, append_data, jcr->Ticket);
1330 Dmsg1(110, ">stored: %s", sd->msg);
1333 * Expect to get OK data
1335 Dmsg1(110, "<stored: %s", sd->msg);
1336 if (!response(jcr, sd, OK_data, "Append Data")) {
1340 generate_daemon_event(jcr, "JobStart");
1342 #if defined(WIN32_VSS)
1343 /* START VSS ON WIN 32 */
1345 if (g_pVSSClient->InitializeForBackup()) {
1346 /* tell vss which drives to snapshot */
1347 char szWinDriveLetters[27];
1348 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1349 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1350 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1351 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1354 /* tell user if snapshot creation of a specific drive failed */
1356 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1357 if (islower(szWinDriveLetters[i])) {
1358 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1362 /* inform user about writer states */
1363 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1364 if (g_pVSSClient->GetWriterState(i) < 1) {
1365 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1370 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1374 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1380 * Send Files to Storage daemon
1382 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1383 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1384 set_jcr_job_status(jcr, JS_ErrorTerminated);
1385 bnet_suppress_error_messages(sd, 1);
1386 bget_msg(sd); /* Read final response from append_data */
1387 Dmsg0(110, "Error in blast_data.\n");
1388 /* run shortly after end of data transmission */
1389 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1390 jcr->runscript_after=1;
1393 set_jcr_job_status(jcr, JS_Terminated);
1395 /* run shortly after end of data transmission */
1396 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1397 jcr->runscript_after=1;
1399 if (jcr->JobStatus != JS_Terminated) {
1400 bnet_suppress_error_messages(sd, 1);
1401 goto cleanup; /* bail out now */
1404 * Expect to get response to append_data from Storage daemon
1406 if (!response(jcr, sd, OK_append, "Append Data")) {
1407 set_jcr_job_status(jcr, JS_ErrorTerminated);
1412 * Send Append End Data to Storage daemon
1414 bnet_fsend(sd, append_end, jcr->Ticket);
1416 if (!response(jcr, sd, OK_end, "Append End")) {
1417 set_jcr_job_status(jcr, JS_ErrorTerminated);
1422 * Send Append Close to Storage daemon
1424 bnet_fsend(sd, append_close, jcr->Ticket);
1425 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1426 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1428 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1432 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1435 if (SDJobStatus != JS_Terminated) {
1436 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1442 #if defined(WIN32_VSS)
1443 /* STOP VSS ON WIN 32 */
1444 /* tell vss to close the backup session */
1446 if (g_pVSSClient->CloseBackup()) {
1447 /* inform user about writer states */
1448 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1449 int msg_type = M_INFO;
1450 if (g_pVSSClient->GetWriterState(i) < 1) {
1451 msg_type = M_WARNING;
1454 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1461 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1462 edit_uint64(jcr->ReadBytes, ed1),
1463 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1464 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1466 return 0; /* return and stop command loop */
1470 * Do a Verify for Director
1473 static int verify_cmd(JCR *jcr)
1475 BSOCK *dir = jcr->dir_bsock;
1476 BSOCK *sd = jcr->store_bsock;
1477 char level[100], ed1[50], ed2[50];
1479 jcr->JobType = JT_VERIFY;
1480 if (sscanf(dir->msg, verifycmd, level) != 1) {
1481 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1485 if (strcasecmp(level, "init") == 0) {
1486 jcr->JobLevel = L_VERIFY_INIT;
1487 } else if (strcasecmp(level, "catalog") == 0){
1488 jcr->JobLevel = L_VERIFY_CATALOG;
1489 } else if (strcasecmp(level, "volume") == 0){
1490 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1491 } else if (strcasecmp(level, "data") == 0){
1492 jcr->JobLevel = L_VERIFY_DATA;
1493 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1494 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1496 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1500 bnet_fsend(dir, OKverify);
1502 generate_daemon_event(jcr, "JobStart");
1504 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1506 switch (jcr->JobLevel) {
1508 case L_VERIFY_CATALOG:
1511 case L_VERIFY_VOLUME_TO_CATALOG:
1512 if (!open_sd_read_session(jcr)) {
1515 start_dir_heartbeat(jcr);
1516 do_verify_volume(jcr);
1517 stop_dir_heartbeat(jcr);
1519 * Send Close session command to Storage daemon
1521 bnet_fsend(sd, read_close, jcr->Ticket);
1522 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1524 /* ****FIXME**** check response */
1525 bget_msg(sd); /* get OK */
1527 /* Inform Storage daemon that we are done */
1528 bnet_sig(sd, BNET_TERMINATE);
1531 case L_VERIFY_DISK_TO_CATALOG:
1535 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1539 bnet_sig(dir, BNET_EOD);
1541 /* Send termination status back to Dir */
1542 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1543 edit_uint64(jcr->ReadBytes, ed1),
1544 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1546 /* Inform Director that we are done */
1547 bnet_sig(dir, BNET_TERMINATE);
1548 return 0; /* return and terminate command loop */
1552 * Do a Restore for Director
1555 static int restore_cmd(JCR *jcr)
1557 BSOCK *dir = jcr->dir_bsock;
1558 BSOCK *sd = jcr->store_bsock;
1562 char ed1[50], ed2[50];
1565 * Scan WHERE (base directory for restore) from command
1567 Dmsg0(150, "restore command\n");
1568 /* Pickup where string */
1569 where = get_memory(dir->msglen+1);
1572 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1573 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1574 pm_strcpy(jcr->errmsg, dir->msg);
1575 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1580 /* Turn / into nothing */
1581 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1585 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1586 unbash_spaces(where);
1587 jcr->where = bstrdup(where);
1588 free_pool_memory(where);
1589 jcr->replace = replace;
1590 jcr->prefix_links = prefix_links;
1592 bnet_fsend(dir, OKrestore);
1593 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1595 jcr->JobType = JT_RESTORE;
1597 set_jcr_job_status(jcr, JS_Blocked);
1599 if (!open_sd_read_session(jcr)) {
1600 set_jcr_job_status(jcr, JS_ErrorTerminated);
1604 set_jcr_job_status(jcr, JS_Running);
1607 * Do restore of files and data
1609 start_dir_heartbeat(jcr);
1610 generate_daemon_event(jcr, "JobStart");
1612 stop_dir_heartbeat(jcr);
1614 set_jcr_job_status(jcr, JS_Terminated);
1615 if (jcr->JobStatus != JS_Terminated) {
1616 bnet_suppress_error_messages(sd, 1);
1620 * Send Close session command to Storage daemon
1622 bnet_fsend(sd, read_close, jcr->Ticket);
1623 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1625 bget_msg(sd); /* get OK */
1627 /* Inform Storage daemon that we are done */
1628 bnet_sig(sd, BNET_TERMINATE);
1633 set_jcr_job_status(jcr, JS_ErrorTerminated);
1635 /* Send termination status back to Dir */
1636 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1637 edit_uint64(jcr->ReadBytes, ed1),
1638 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1640 /* Inform Director that we are done */
1641 bnet_sig(dir, BNET_TERMINATE);
1643 Dmsg0(130, "Done in job.c\n");
1644 return 0; /* return and terminate command loop */
1647 static int open_sd_read_session(JCR *jcr)
1649 BSOCK *sd = jcr->store_bsock;
1652 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1655 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1656 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1657 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1659 * Open Read Session with Storage daemon
1661 bnet_fsend(sd, read_open, "DummyVolume",
1662 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1663 jcr->StartBlock, jcr->EndBlock);
1664 Dmsg1(110, ">stored: %s", sd->msg);
1669 if (bget_msg(sd) >= 0) {
1670 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1671 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1672 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1675 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1677 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1681 if (!send_bootstrap_file(jcr)) {
1686 * Start read of data with Storage daemon
1688 bnet_fsend(sd, read_data, jcr->Ticket);
1689 Dmsg1(110, ">stored: %s", sd->msg);
1694 if (!response(jcr, sd, OK_data, "Read Data")) {
1701 * Destroy the Job Control Record and associated
1702 * resources (sockets).
1704 static void filed_free_jcr(JCR *jcr)
1706 if (jcr->store_bsock) {
1707 bnet_close(jcr->store_bsock);
1709 free_bootstrap(jcr);
1710 if (jcr->last_fname) {
1711 free_pool_memory(jcr->last_fname);
1713 free_runscripts(jcr->RunScripts);
1714 delete jcr->RunScripts;
1720 * Get response from Storage daemon to a command we
1721 * sent. Check that the response is OK.
1723 * Returns: 0 on failure
1726 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1731 if (bget_msg(sd) > 0) {
1732 Dmsg0(110, sd->msg);
1733 if (strcmp(sd->msg, resp) == 0) {
1737 if (job_canceled(jcr)) {
1738 return 0; /* if canceled avoid useless error messages */
1740 if (is_bnet_error(sd)) {
1741 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1742 cmd, bnet_strerror(sd));
1744 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1745 cmd, resp, sd->msg);
1750 static int send_bootstrap_file(JCR *jcr)
1754 BSOCK *sd = jcr->store_bsock;
1755 const char *bootstrap = "bootstrap\n";
1758 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1759 if (!jcr->RestoreBootstrap) {
1762 bs = fopen(jcr->RestoreBootstrap, "rb");
1765 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1766 jcr->RestoreBootstrap, be.strerror());
1767 set_jcr_job_status(jcr, JS_ErrorTerminated);
1770 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1772 while (fgets(buf, sizeof(buf), bs)) {
1773 sd->msglen = Mmsg(sd->msg, "%s", buf);
1776 bnet_sig(sd, BNET_EOD);
1778 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1779 set_jcr_job_status(jcr, JS_ErrorTerminated);
1785 free_bootstrap(jcr);