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) {
679 Dmsg0(100, "State=error return\n");
684 * The switch tests the code for validity.
685 * The subcode is always good if it is a space, otherwise we must confirm.
686 * We set state to state_error first assuming the subcode is invalid,
687 * requiring state to be set in cases below that handle subcodes.
689 if (subcode != ' ') {
691 Dmsg0(100, "Set state=error\n");
696 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
697 memset(fileset->incexe, 0, sizeof(findINCEXE));
698 fileset->incexe->opts_list.init(1, true);
699 fileset->incexe->name_list.init(1, true);
700 fileset->include_list.append(fileset->incexe);
704 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
705 memset(fileset->incexe, 0, sizeof(findINCEXE));
706 fileset->incexe->opts_list.init(1, true);
707 fileset->incexe->name_list.init(1, true);
708 fileset->exclude_list.append(fileset->incexe);
714 /* File item to either include/include list */
715 state = state_include;
716 add_file_to_fileset(jcr, item, fileset);
719 current_opts = start_options(ff);
723 preg = (regex_t *)malloc(sizeof(regex_t));
724 if (current_opts->flags & FO_IGNORECASE) {
725 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
727 rc = regcomp(preg, item, REG_EXTENDED);
730 regerror(rc, preg, prbuf, sizeof(prbuf));
733 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
737 state = state_options;
738 if (subcode == ' ') {
739 current_opts->regex.append(preg);
740 } else if (subcode == 'D') {
741 current_opts->regexdir.append(preg);
742 } else if (subcode == 'F') {
743 current_opts->regexfile.append(preg);
749 current_opts = start_options(ff);
750 current_opts->base.append(bstrdup(item));
751 state = state_options;
754 current_opts = start_options(ff);
755 state = state_options;
756 if (subcode == ' ') {
757 current_opts->fstype.append(bstrdup(item));
758 } else if (subcode == 'D') {
759 current_opts->drivetype.append(bstrdup(item));
765 current_opts = start_options(ff);
766 state = state_options;
767 if (subcode == ' ') {
768 current_opts->wild.append(bstrdup(item));
769 } else if (subcode == 'D') {
770 current_opts->wilddir.append(bstrdup(item));
771 } else if (subcode == 'F') {
772 current_opts->wildfile.append(bstrdup(item));
773 } else if (subcode == 'B') {
774 current_opts->wildbase.append(bstrdup(item));
780 current_opts = start_options(ff);
781 set_options(current_opts, item);
782 state = state_options;
785 current_opts = start_options(ff);
786 current_opts->reader = bstrdup(item);
787 state = state_options;
790 current_opts = start_options(ff);
791 current_opts->writer = bstrdup(item);
792 state = state_options;
795 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
799 ff->fileset->state = state;
802 static bool term_fileset(JCR *jcr)
804 FF_PKT *ff = jcr->ff;
807 findFILESET *fileset = ff->fileset;
810 for (i=0; i<fileset->include_list.size(); i++) {
811 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
813 for (j=0; j<incexe->opts_list.size(); j++) {
814 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
815 for (k=0; k<fo->regex.size(); k++) {
816 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
818 for (k=0; k<fo->regexdir.size(); k++) {
819 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
821 for (k=0; k<fo->regexfile.size(); k++) {
822 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
824 for (k=0; k<fo->wild.size(); k++) {
825 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
827 for (k=0; k<fo->wilddir.size(); k++) {
828 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
830 for (k=0; k<fo->wildfile.size(); k++) {
831 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
833 for (k=0; k<fo->wildbase.size(); k++) {
834 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
836 for (k=0; k<fo->base.size(); k++) {
837 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
839 for (k=0; k<fo->fstype.size(); k++) {
840 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
842 for (k=0; k<fo->drivetype.size(); k++) {
843 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
846 Dmsg1(400, "D %s\n", fo->reader);
849 Dmsg1(400, "T %s\n", fo->writer);
852 for (j=0; j<incexe->name_list.size(); j++) {
853 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
856 for (i=0; i<fileset->exclude_list.size(); i++) {
857 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
859 for (j=0; j<incexe->opts_list.size(); j++) {
860 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
861 for (k=0; k<fo->regex.size(); k++) {
862 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
864 for (k=0; k<fo->regexdir.size(); k++) {
865 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
867 for (k=0; k<fo->regexfile.size(); k++) {
868 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
870 for (k=0; k<fo->wild.size(); k++) {
871 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
873 for (k=0; k<fo->wilddir.size(); k++) {
874 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
876 for (k=0; k<fo->wildfile.size(); k++) {
877 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
879 for (k=0; k<fo->wildbase.size(); k++) {
880 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
882 for (k=0; k<fo->base.size(); k++) {
883 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
885 for (k=0; k<fo->fstype.size(); k++) {
886 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
888 for (k=0; k<fo->drivetype.size(); k++) {
889 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
892 for (j=0; j<incexe->name_list.size(); j++) {
893 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
897 return ff->fileset->state != state_error;
902 * As an optimization, we should do this during
903 * "compile" time in filed/job.c, and keep only a bit mask
904 * and the Verify options.
906 static void set_options(findFOPTS *fo, const char *opts)
911 for (p=opts; *p; p++) {
913 case 'a': /* alway replace */
914 case '0': /* no option */
917 fo->flags |= FO_EXCLUDE;
920 fo->flags |= FO_MULTIFS;
922 case 'h': /* no recursion */
923 fo->flags |= FO_NO_RECURSION;
925 case 'H': /* no hard link handling */
926 fo->flags |= FO_NO_HARDLINK;
929 fo->flags |= FO_IGNORECASE;
935 fo->flags |= FO_NOREPLACE;
937 case 'p': /* use portable data format */
938 fo->flags |= FO_PORTABLE;
940 case 'R': /* Resource forks and Finder Info */
941 fo->flags |= FO_HFSPLUS;
942 case 'r': /* read fifo */
943 fo->flags |= FO_READFIFO;
948 fo->flags |= FO_SHA1;
953 fo->flags |= FO_SHA256;
957 fo->flags |= FO_SHA512;
963 * If 2 or 3 is seen here, SHA2 is not configured, so
964 * eat the option, and drop back to SHA-1.
966 if (p[1] == '2' || p[1] == '3') {
969 fo->flags |= FO_SHA1;
974 fo->flags |= FO_SPARSE;
977 fo->flags |= FO_MTIMEONLY;
980 fo->flags |= FO_KEEPATIME;
985 case 'V': /* verify options */
986 /* Copy Verify Options */
987 for (j=0; *p && *p != ':'; p++) {
988 fo->VerifyOpts[j] = *p;
989 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
993 fo->VerifyOpts[j] = 0;
996 fo->flags |= FO_IF_NEWER;
999 fo->flags |= FO_ENHANCEDWILD;
1001 case 'Z': /* gzip compression */
1002 fo->flags |= FO_GZIP;
1003 fo->GZIP_level = *++p - '0';
1006 fo->flags |= FO_NOATIME;
1009 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1017 * Director is passing his Fileset
1019 static int fileset_cmd(JCR *jcr)
1021 BSOCK *dir = jcr->dir_bsock;
1023 #if defined(WIN32_VSS)
1026 sscanf(dir->msg, "fileset vss=%d", &vss);
1030 if (!init_fileset(jcr)) {
1033 while (bnet_recv(dir) >= 0) {
1034 strip_trailing_junk(dir->msg);
1035 Dmsg1(500, "Fileset: %s\n", dir->msg);
1036 add_fileset(jcr, dir->msg);
1038 if (!term_fileset(jcr)) {
1041 return bnet_fsend(dir, OKinc);
1044 static void free_bootstrap(JCR *jcr)
1046 if (jcr->RestoreBootstrap) {
1047 unlink(jcr->RestoreBootstrap);
1048 free_pool_memory(jcr->RestoreBootstrap);
1049 jcr->RestoreBootstrap = NULL;
1054 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1055 static uint32_t bsr_uniq = 0;
1058 * The Director sends us the bootstrap file, which
1059 * we will in turn pass to the SD.
1061 static int bootstrap_cmd(JCR *jcr)
1063 BSOCK *dir = jcr->dir_bsock;
1064 POOLMEM *fname = get_pool_memory(PM_FNAME);
1067 free_bootstrap(jcr);
1070 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1071 jcr->Job, bsr_uniq);
1073 Dmsg1(400, "bootstrap=%s\n", fname);
1074 jcr->RestoreBootstrap = fname;
1075 bs = fopen(fname, "a+b"); /* create file */
1078 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1079 jcr->RestoreBootstrap, be.strerror());
1081 * Suck up what he is sending to us so that he will then
1082 * read our error message.
1084 while (bnet_recv(dir) >= 0)
1086 free_bootstrap(jcr);
1087 set_jcr_job_status(jcr, JS_ErrorTerminated);
1091 while (bnet_recv(dir) >= 0) {
1092 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1093 fputs(dir->msg, bs);
1097 * Note, do not free the bootstrap yet -- it needs to be
1100 return bnet_fsend(dir, OKbootstrap);
1105 * Get backup level from Director
1108 static int level_cmd(JCR *jcr)
1110 BSOCK *dir = jcr->dir_bsock;
1111 POOLMEM *level, *buf = NULL;
1114 level = get_memory(dir->msglen+1);
1115 Dmsg1(110, "level_cmd: %s", dir->msg);
1116 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1119 /* Base backup requested? */
1120 if (strcmp(level, "base") == 0) {
1121 jcr->JobLevel = L_BASE;
1122 /* Full backup requested? */
1123 } else if (strcmp(level, "full") == 0) {
1124 jcr->JobLevel = L_FULL;
1125 } else if (strcmp(level, "differential") == 0) {
1126 jcr->JobLevel = L_DIFFERENTIAL;
1129 } else if (strcmp(level, "incremental") == 0) {
1130 jcr->JobLevel = L_INCREMENTAL;
1134 * We get his UTC since time, then sync the clocks and correct it
1135 * to agree with our clock.
1137 } else if (strcmp(level, "since_utime") == 0) {
1138 buf = get_memory(dir->msglen+1);
1139 utime_t since_time, adj;
1140 btime_t his_time, bt_start, rt=0, bt_adj=0;
1141 if (jcr->JobLevel == L_NONE) {
1142 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1144 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1145 buf, &mtime_only) != 2) {
1148 since_time = str_to_uint64(buf); /* this is the since time */
1149 Dmsg1(100, "since_time=%d\n", (int)since_time);
1150 char ed1[50], ed2[50];
1152 * Sync clocks by polling him for the time. We take
1153 * 10 samples of his time throwing out the first two.
1155 for (int i=0; i<10; i++) {
1156 bt_start = get_current_btime();
1157 bnet_sig(dir, BNET_BTIME); /* poll for time */
1158 if (bnet_recv(dir) <= 0) { /* get response */
1161 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1164 if (i < 2) { /* toss first two results */
1167 his_time = str_to_uint64(buf);
1168 rt = get_current_btime() - bt_start; /* compute round trip time */
1169 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1170 edit_uint64(bt_start, ed2));
1171 bt_adj += bt_start - his_time - rt/2;
1172 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1175 bt_adj = bt_adj / 8; /* compute average time */
1176 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1177 adj = btime_to_utime(bt_adj);
1178 since_time += adj; /* adjust for clock difference */
1180 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1182 bnet_sig(dir, BNET_EOD);
1184 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1185 jcr->incremental = 1; /* set incremental or decremental backup */
1186 jcr->mtime = (time_t)since_time; /* set since time */
1188 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1196 return bnet_fsend(dir, OKlevel);
1199 pm_strcpy(jcr->errmsg, dir->msg);
1200 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1209 * Get session parameters from Director -- this is for a Restore command
1211 static int session_cmd(JCR *jcr)
1213 BSOCK *dir = jcr->dir_bsock;
1215 Dmsg1(100, "SessionCmd: %s", dir->msg);
1216 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1217 &jcr->VolSessionId, &jcr->VolSessionTime,
1218 &jcr->StartFile, &jcr->EndFile,
1219 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1220 pm_strcpy(jcr->errmsg, dir->msg);
1221 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1225 return bnet_fsend(dir, OKsession);
1229 * Get address of storage daemon from Director
1232 static int storage_cmd(JCR *jcr)
1234 int stored_port; /* storage daemon port */
1235 int enable_ssl; /* enable ssl to sd */
1236 BSOCK *dir = jcr->dir_bsock;
1237 BSOCK *sd; /* storage daemon bsock */
1239 Dmsg1(100, "StorageCmd: %s", dir->msg);
1240 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1241 pm_strcpy(jcr->errmsg, dir->msg);
1242 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1245 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1246 /* Open command communications with Storage daemon */
1247 /* Try to connect for 1 hour at 10 second intervals */
1248 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1249 jcr->stored_addr, NULL, stored_port, 1);
1251 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1252 jcr->stored_addr, stored_port);
1253 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1254 jcr->stored_addr, stored_port);
1257 Dmsg0(110, "Connection OK to SD.\n");
1259 jcr->store_bsock = sd;
1261 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1262 if (!authenticate_storagedaemon(jcr)) {
1263 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1266 Dmsg0(110, "Authenticated with SD.\n");
1268 /* Send OK to Director */
1269 return bnet_fsend(dir, OKstore);
1276 static int backup_cmd(JCR *jcr)
1278 BSOCK *dir = jcr->dir_bsock;
1279 BSOCK *sd = jcr->store_bsock;
1282 char ed1[50], ed2[50];
1283 bool bDoVSS = false;
1285 #if defined(WIN32_VSS)
1286 // capture state here, if client is backed up by multiple directors
1287 // and one enables vss and the other does not then enable_vss can change
1288 // between here and where its evaluated after the job completes.
1289 bDoVSS = g_pVSSClient && enable_vss;
1291 /* Run only one at a time */
1296 set_jcr_job_status(jcr, JS_Blocked);
1297 jcr->JobType = JT_BACKUP;
1298 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1301 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1305 bnet_fsend(dir, OKbackup);
1306 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1309 * Send Append Open Session to Storage daemon
1311 bnet_fsend(sd, append_open);
1312 Dmsg1(110, ">stored: %s", sd->msg);
1314 * Expect to receive back the Ticket number
1316 if (bget_msg(sd) >= 0) {
1317 Dmsg1(110, "<stored: %s", sd->msg);
1318 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1319 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1322 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1324 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1329 * Send Append data command to Storage daemon
1331 bnet_fsend(sd, append_data, jcr->Ticket);
1332 Dmsg1(110, ">stored: %s", sd->msg);
1335 * Expect to get OK data
1337 Dmsg1(110, "<stored: %s", sd->msg);
1338 if (!response(jcr, sd, OK_data, "Append Data")) {
1342 generate_daemon_event(jcr, "JobStart");
1344 #if defined(WIN32_VSS)
1345 /* START VSS ON WIN 32 */
1347 if (g_pVSSClient->InitializeForBackup()) {
1348 /* tell vss which drives to snapshot */
1349 char szWinDriveLetters[27];
1350 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1351 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1352 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1353 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1356 /* tell user if snapshot creation of a specific drive failed */
1358 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1359 if (islower(szWinDriveLetters[i])) {
1360 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1364 /* inform user about writer states */
1365 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1366 if (g_pVSSClient->GetWriterState(i) < 1) {
1367 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1372 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1376 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1382 * Send Files to Storage daemon
1384 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1385 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1386 set_jcr_job_status(jcr, JS_ErrorTerminated);
1387 bnet_suppress_error_messages(sd, 1);
1388 bget_msg(sd); /* Read final response from append_data */
1389 Dmsg0(110, "Error in blast_data.\n");
1390 /* run shortly after end of data transmission */
1391 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1392 jcr->runscript_after=1;
1395 set_jcr_job_status(jcr, JS_Terminated);
1397 /* run shortly after end of data transmission */
1398 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
1399 jcr->runscript_after=1;
1401 if (jcr->JobStatus != JS_Terminated) {
1402 bnet_suppress_error_messages(sd, 1);
1403 goto cleanup; /* bail out now */
1406 * Expect to get response to append_data from Storage daemon
1408 if (!response(jcr, sd, OK_append, "Append Data")) {
1409 set_jcr_job_status(jcr, JS_ErrorTerminated);
1414 * Send Append End Data to Storage daemon
1416 bnet_fsend(sd, append_end, jcr->Ticket);
1418 if (!response(jcr, sd, OK_end, "Append End")) {
1419 set_jcr_job_status(jcr, JS_ErrorTerminated);
1424 * Send Append Close to Storage daemon
1426 bnet_fsend(sd, append_close, jcr->Ticket);
1427 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1428 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1430 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1434 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1437 if (SDJobStatus != JS_Terminated) {
1438 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1444 #if defined(WIN32_VSS)
1445 /* STOP VSS ON WIN 32 */
1446 /* tell vss to close the backup session */
1448 if (g_pVSSClient->CloseBackup()) {
1449 /* inform user about writer states */
1450 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1451 int msg_type = M_INFO;
1452 if (g_pVSSClient->GetWriterState(i) < 1) {
1453 msg_type = M_WARNING;
1456 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1463 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1464 edit_uint64(jcr->ReadBytes, ed1),
1465 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, (int)bDoVSS,
1467 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1469 return 0; /* return and stop command loop */
1473 * Do a Verify for Director
1476 static int verify_cmd(JCR *jcr)
1478 BSOCK *dir = jcr->dir_bsock;
1479 BSOCK *sd = jcr->store_bsock;
1480 char level[100], ed1[50], ed2[50];
1482 jcr->JobType = JT_VERIFY;
1483 if (sscanf(dir->msg, verifycmd, level) != 1) {
1484 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1488 if (strcasecmp(level, "init") == 0) {
1489 jcr->JobLevel = L_VERIFY_INIT;
1490 } else if (strcasecmp(level, "catalog") == 0){
1491 jcr->JobLevel = L_VERIFY_CATALOG;
1492 } else if (strcasecmp(level, "volume") == 0){
1493 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1494 } else if (strcasecmp(level, "data") == 0){
1495 jcr->JobLevel = L_VERIFY_DATA;
1496 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1497 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1499 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1503 bnet_fsend(dir, OKverify);
1505 generate_daemon_event(jcr, "JobStart");
1507 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1509 switch (jcr->JobLevel) {
1511 case L_VERIFY_CATALOG:
1514 case L_VERIFY_VOLUME_TO_CATALOG:
1515 if (!open_sd_read_session(jcr)) {
1518 start_dir_heartbeat(jcr);
1519 do_verify_volume(jcr);
1520 stop_dir_heartbeat(jcr);
1522 * Send Close session command to Storage daemon
1524 bnet_fsend(sd, read_close, jcr->Ticket);
1525 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1527 /* ****FIXME**** check response */
1528 bget_msg(sd); /* get OK */
1530 /* Inform Storage daemon that we are done */
1531 bnet_sig(sd, BNET_TERMINATE);
1534 case L_VERIFY_DISK_TO_CATALOG:
1538 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1542 bnet_sig(dir, BNET_EOD);
1544 /* Send termination status back to Dir */
1545 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1546 edit_uint64(jcr->ReadBytes, ed1),
1547 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1549 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1551 /* Inform Director that we are done */
1552 bnet_sig(dir, BNET_TERMINATE);
1553 return 0; /* return and terminate command loop */
1557 * Do a Restore for Director
1560 static int restore_cmd(JCR *jcr)
1562 BSOCK *dir = jcr->dir_bsock;
1563 BSOCK *sd = jcr->store_bsock;
1567 char ed1[50], ed2[50];
1570 * Scan WHERE (base directory for restore) from command
1572 Dmsg0(150, "restore command\n");
1573 /* Pickup where string */
1574 where = get_memory(dir->msglen+1);
1577 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1578 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1579 pm_strcpy(jcr->errmsg, dir->msg);
1580 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1585 /* Turn / into nothing */
1586 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1590 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1591 unbash_spaces(where);
1592 jcr->where = bstrdup(where);
1593 free_pool_memory(where);
1594 jcr->replace = replace;
1595 jcr->prefix_links = prefix_links;
1597 bnet_fsend(dir, OKrestore);
1598 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1600 jcr->JobType = JT_RESTORE;
1602 set_jcr_job_status(jcr, JS_Blocked);
1604 if (!open_sd_read_session(jcr)) {
1605 set_jcr_job_status(jcr, JS_ErrorTerminated);
1609 set_jcr_job_status(jcr, JS_Running);
1612 * Do restore of files and data
1614 start_dir_heartbeat(jcr);
1615 generate_daemon_event(jcr, "JobStart");
1617 stop_dir_heartbeat(jcr);
1619 set_jcr_job_status(jcr, JS_Terminated);
1620 if (jcr->JobStatus != JS_Terminated) {
1621 bnet_suppress_error_messages(sd, 1);
1625 * Send Close session command to Storage daemon
1627 bnet_fsend(sd, read_close, jcr->Ticket);
1628 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1630 bget_msg(sd); /* get OK */
1632 /* Inform Storage daemon that we are done */
1633 bnet_sig(sd, BNET_TERMINATE);
1638 set_jcr_job_status(jcr, JS_ErrorTerminated);
1640 /* Send termination status back to Dir */
1641 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1642 edit_uint64(jcr->ReadBytes, ed1),
1643 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1645 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1647 /* Inform Director that we are done */
1648 bnet_sig(dir, BNET_TERMINATE);
1650 Dmsg0(130, "Done in job.c\n");
1651 return 0; /* return and terminate command loop */
1654 static int open_sd_read_session(JCR *jcr)
1656 BSOCK *sd = jcr->store_bsock;
1659 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1662 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1663 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1664 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1666 * Open Read Session with Storage daemon
1668 bnet_fsend(sd, read_open, "DummyVolume",
1669 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1670 jcr->StartBlock, jcr->EndBlock);
1671 Dmsg1(110, ">stored: %s", sd->msg);
1676 if (bget_msg(sd) >= 0) {
1677 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1678 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1679 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1682 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1684 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1688 if (!send_bootstrap_file(jcr)) {
1693 * Start read of data with Storage daemon
1695 bnet_fsend(sd, read_data, jcr->Ticket);
1696 Dmsg1(110, ">stored: %s", sd->msg);
1701 if (!response(jcr, sd, OK_data, "Read Data")) {
1708 * Destroy the Job Control Record and associated
1709 * resources (sockets).
1711 static void filed_free_jcr(JCR *jcr)
1713 if (jcr->store_bsock) {
1714 bnet_close(jcr->store_bsock);
1716 free_bootstrap(jcr);
1717 if (jcr->last_fname) {
1718 free_pool_memory(jcr->last_fname);
1720 free_runscripts(jcr->RunScripts);
1721 delete jcr->RunScripts;
1727 * Get response from Storage daemon to a command we
1728 * sent. Check that the response is OK.
1730 * Returns: 0 on failure
1733 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1738 if (bget_msg(sd) > 0) {
1739 Dmsg0(110, sd->msg);
1740 if (strcmp(sd->msg, resp) == 0) {
1744 if (job_canceled(jcr)) {
1745 return 0; /* if canceled avoid useless error messages */
1747 if (is_bnet_error(sd)) {
1748 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1749 cmd, bnet_strerror(sd));
1751 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1752 cmd, resp, sd->msg);
1757 static int send_bootstrap_file(JCR *jcr)
1761 BSOCK *sd = jcr->store_bsock;
1762 const char *bootstrap = "bootstrap\n";
1765 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1766 if (!jcr->RestoreBootstrap) {
1769 bs = fopen(jcr->RestoreBootstrap, "rb");
1772 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1773 jcr->RestoreBootstrap, be.strerror());
1774 set_jcr_job_status(jcr, JS_ErrorTerminated);
1777 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1779 while (fgets(buf, sizeof(buf), bs)) {
1780 sd->msglen = Mmsg(sd->msg, "%s", buf);
1783 bnet_sig(sd, BNET_EOD);
1785 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1786 set_jcr_job_status(jcr, JS_ErrorTerminated);
1792 free_bootstrap(jcr);