2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
28 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 extern CLIENT *me; /* our client resource */
33 int enable_vss = 0; /* set to use vss */
35 /* Imported functions */
36 extern int status_cmd(JCR *jcr);
37 extern int qstatus_cmd(JCR *jcr);
39 /* Forward referenced functions */
40 static int backup_cmd(JCR *jcr);
41 static int bootstrap_cmd(JCR *jcr);
42 static int cancel_cmd(JCR *jcr);
43 static int setdebug_cmd(JCR *jcr);
44 static int estimate_cmd(JCR *jcr);
45 static int hello_cmd(JCR *jcr);
46 static int job_cmd(JCR *jcr);
47 static int fileset_cmd(JCR *jcr);
48 static int level_cmd(JCR *jcr);
49 static int verify_cmd(JCR *jcr);
50 static int restore_cmd(JCR *jcr);
51 static int storage_cmd(JCR *jcr);
52 static int session_cmd(JCR *jcr);
53 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
54 static void filed_free_jcr(JCR *jcr);
55 static int open_sd_read_session(JCR *jcr);
56 static int send_bootstrap_file(JCR *jcr);
57 static int runscript_cmd(JCR *jcr);
58 static int runbefore_cmd(JCR *jcr);
59 static int runafter_cmd(JCR *jcr);
60 static int runbeforenow_cmd(JCR *jcr);
61 static void set_options(findFOPTS *fo, const char *opts);
64 /* Exported functions */
69 int monitoraccess; /* specify if monitors have access to this function */
73 * The following are the recognized commands from the Director.
75 static struct s_cmds cmds[] = {
76 {"backup", backup_cmd, 0},
77 {"cancel", cancel_cmd, 0},
78 {"setdebug=", setdebug_cmd, 0},
79 {"estimate", estimate_cmd, 0},
80 {"Hello", hello_cmd, 1},
81 {"fileset", fileset_cmd, 0},
82 {"JobId=", job_cmd, 0},
83 {"level = ", level_cmd, 0},
84 {"restore", restore_cmd, 0},
85 {"session", session_cmd, 0},
86 {"status", status_cmd, 1},
87 {".status", qstatus_cmd, 1},
88 {"storage ", storage_cmd, 0},
89 {"verify", verify_cmd, 0},
90 {"bootstrap", bootstrap_cmd, 0},
91 {"RunBeforeNow", runbeforenow_cmd, 0},
92 {"RunBeforeJob", runbefore_cmd, 0},
93 {"RunAfterJob", runafter_cmd, 0},
94 {"Run", runscript_cmd, 0},
95 {NULL, NULL} /* list terminator */
98 /* Commands received from director that need scanning */
99 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
100 static char storaddr[] = "storage address=%s port=%d ssl=%d";
101 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
102 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
103 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
104 static char verifycmd[] = "verify level=%30s";
105 static char estimatecmd[] = "estimate listing=%d";
106 static char runbefore[] = "RunBeforeJob %s";
107 static char runafter[] = "RunAfterJob %s";
108 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s";
110 /* Responses sent to Director */
111 static char errmsg[] = "2999 Invalid command\n";
112 static char no_auth[] = "2998 No Authorization\n";
113 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
114 static char OKinc[] = "2000 OK include\n";
115 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
116 static char OKlevel[] = "2000 OK level\n";
117 static char OKbackup[] = "2000 OK backup\n";
118 static char OKbootstrap[] = "2000 OK bootstrap\n";
119 static char OKverify[] = "2000 OK verify\n";
120 static char OKrestore[] = "2000 OK restore\n";
121 static char OKsession[] = "2000 OK session\n";
122 static char OKstore[] = "2000 OK storage\n";
123 static char OKjob[] = "2000 OK Job %s,%s,%s";
124 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
125 static char BADjob[] = "2901 Bad Job\n";
126 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
127 static char OKRunBefore[] = "2000 OK RunBefore\n";
128 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
129 static char OKRunAfter[] = "2000 OK RunAfter\n";
130 static char OKRunScript[] = "2000 OK RunScript\n";
133 /* Responses received from Storage Daemon */
134 static char OK_end[] = "3000 OK end\n";
135 static char OK_close[] = "3000 OK close Status = %d\n";
136 static char OK_open[] = "3000 OK open ticket = %d\n";
137 static char OK_data[] = "3000 OK data\n";
138 static char OK_append[] = "3000 OK append data\n";
139 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
142 /* Commands sent to Storage Daemon */
143 static char append_open[] = "append open session\n";
144 static char append_data[] = "append data %d\n";
145 static char append_end[] = "append end session %d\n";
146 static char append_close[] = "append close session %d\n";
147 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
148 static char read_data[] = "read data %d\n";
149 static char read_close[] = "read close session %d\n";
152 * Accept requests from a Director
154 * NOTE! We are running as a separate thread
156 * Send output one line
157 * at a time followed by a zero length transmission.
159 * Return when the connection is terminated or there
162 * Basic task here is:
163 * Authenticate Director (during Hello command).
164 * Accept commands one at a time from the Director
168 void *handle_client_request(void *dirp)
173 BSOCK *dir = (BSOCK *)dirp;
175 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
176 jcr->dir_bsock = dir;
177 jcr->ff = init_find_files();
178 jcr->start_time = time(NULL);
179 jcr->RunScripts = New(alist(10, not_owned_by_alist));
180 jcr->last_fname = get_pool_memory(PM_FNAME);
181 jcr->last_fname[0] = 0;
182 jcr->client_name = get_memory(strlen(my_name) + 1);
183 pm_strcpy(jcr->client_name, my_name);
184 jcr->pki_sign = me->pki_sign;
185 jcr->pki_encrypt = me->pki_encrypt;
186 jcr->pki_keypair = me->pki_keypair;
187 jcr->pki_signers = me->pki_signers;
188 jcr->pki_recipients = me->pki_recipients;
190 enable_backup_privileges(NULL, 1 /* ignore_errors */);
192 /**********FIXME******* add command handler error code */
194 for (quit=false; !quit;) {
197 if (bnet_recv(dir) < 0) {
198 break; /* connection terminated */
200 dir->msg[dir->msglen] = 0;
201 Dmsg1(100, "<dird: %s", dir->msg);
203 for (i=0; cmds[i].cmd; i++) {
204 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
205 found = true; /* indicate command found */
206 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
207 bnet_fsend(dir, no_auth);
208 bnet_sig(dir, BNET_EOD);
211 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
212 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
213 bnet_fsend(dir, illegal_cmd);
214 bnet_sig(dir, BNET_EOD);
217 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
218 if (!cmds[i].func(jcr)) { /* do command */
219 quit = true; /* error or fully terminated, get out */
220 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
225 if (!found) { /* command not found */
226 bnet_fsend(dir, errmsg);
232 /* Inform Storage daemon that we are done */
233 if (jcr->store_bsock) {
234 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
237 generate_daemon_event(jcr, "JobEnd");
239 dequeue_messages(jcr); /* send any queued messages */
241 /* Inform Director that we are done */
242 bnet_sig(dir, BNET_TERMINATE);
244 /* Clean up fileset */
245 FF_PKT *ff = jcr->ff;
246 findFILESET *fileset = ff->fileset;
249 /* Delete FileSet Include lists */
250 for (i=0; i<fileset->include_list.size(); i++) {
251 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
252 for (j=0; j<incexe->opts_list.size(); j++) {
253 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
254 for (k=0; k<fo->regex.size(); k++) {
255 regfree((regex_t *)fo->regex.get(k));
258 fo->regexdir.destroy();
259 fo->regexfile.destroy();
261 fo->wilddir.destroy();
262 fo->wildfile.destroy();
263 fo->wildbase.destroy();
265 fo->fstype.destroy();
266 fo->drivetype.destroy();
274 incexe->opts_list.destroy();
275 incexe->name_list.destroy();
277 fileset->include_list.destroy();
279 /* Delete FileSet Exclude lists */
280 for (i=0; i<fileset->exclude_list.size(); i++) {
281 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
282 for (j=0; j<incexe->opts_list.size(); j++) {
283 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
285 fo->regexdir.destroy();
286 fo->regexfile.destroy();
288 fo->wilddir.destroy();
289 fo->wildfile.destroy();
290 fo->wildbase.destroy();
292 fo->fstype.destroy();
293 fo->drivetype.destroy();
295 incexe->opts_list.destroy();
296 incexe->name_list.destroy();
298 fileset->exclude_list.destroy();
302 Dmsg0(100, "Calling term_find_files\n");
303 term_find_files(jcr->ff);
305 Dmsg0(100, "Done with term_find_files\n");
306 free_jcr(jcr); /* destroy JCR record */
307 Dmsg0(100, "Done with free_jcr\n");
312 * Hello from Director he must identify himself and provide his
315 static int hello_cmd(JCR *jcr)
317 Dmsg0(120, "Calling Authenticate\n");
318 if (!authenticate_director(jcr)) {
321 Dmsg0(120, "OK Authenticate\n");
322 jcr->authenticated = true;
329 static int cancel_cmd(JCR *jcr)
331 BSOCK *dir = jcr->dir_bsock;
332 char Job[MAX_NAME_LENGTH];
335 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
336 if (!(cjcr=get_jcr_by_full_name(Job))) {
337 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
339 if (cjcr->store_bsock) {
340 cjcr->store_bsock->timed_out = 1;
341 cjcr->store_bsock->terminated = 1;
342 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
344 set_jcr_job_status(cjcr, JS_Canceled);
346 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
349 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
351 bnet_sig(dir, BNET_EOD);
357 * Set debug level as requested by the Director
360 static int setdebug_cmd(JCR *jcr)
362 BSOCK *dir = jcr->dir_bsock;
363 int level, trace_flag;
365 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
366 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
367 pm_strcpy(jcr->errmsg, dir->msg);
368 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
372 set_trace(trace_flag);
373 return bnet_fsend(dir, OKsetdebug, level);
377 static int estimate_cmd(JCR *jcr)
379 BSOCK *dir = jcr->dir_bsock;
382 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
383 pm_strcpy(jcr->errmsg, dir->msg);
384 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
385 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
389 bnet_fsend(dir, OKest, jcr->num_files_examined,
390 edit_uint64_with_commas(jcr->JobBytes, ed2));
391 bnet_sig(dir, BNET_EOD);
396 * Get JobId and Storage Daemon Authorization key from Director
398 static int job_cmd(JCR *jcr)
400 BSOCK *dir = jcr->dir_bsock;
401 POOLMEM *sd_auth_key;
403 sd_auth_key = get_memory(dir->msglen);
404 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
405 &jcr->VolSessionId, &jcr->VolSessionTime,
407 pm_strcpy(jcr->errmsg, dir->msg);
408 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
409 bnet_fsend(dir, BADjob);
410 free_pool_memory(sd_auth_key);
413 jcr->sd_auth_key = bstrdup(sd_auth_key);
414 free_pool_memory(sd_auth_key);
415 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
416 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
419 static int runbefore_cmd(JCR *jcr)
422 BSOCK *dir = jcr->dir_bsock;
423 POOLMEM *cmd = get_memory(dir->msglen+1);
426 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
427 if (sscanf(dir->msg, runbefore, cmd) != 1) {
428 pm_strcpy(jcr->errmsg, dir->msg);
429 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
430 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
436 /* Run the command now */
437 script = new_runscript();
438 script->set_command(cmd);
439 script->when = SCRIPT_Before;
440 ok = script->run(jcr, "ClientRunBeforeJob");
441 free_runscript(script);
445 bnet_fsend(dir, OKRunBefore);
448 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
453 static int runbeforenow_cmd(JCR *jcr)
455 BSOCK *dir = jcr->dir_bsock;
457 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
458 return bnet_fsend(dir, OKRunBeforeNow);
461 static int runafter_cmd(JCR *jcr)
463 BSOCK *dir = jcr->dir_bsock;
464 POOLMEM *msg = get_memory(dir->msglen+1);
467 Dmsg1(100, "runafter_cmd: %s", dir->msg);
468 if (sscanf(dir->msg, runafter, msg) != 1) {
469 pm_strcpy(jcr->errmsg, dir->msg);
470 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
471 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
477 cmd = new_runscript();
478 cmd->set_command(msg);
479 cmd->on_success = true;
480 cmd->on_failure = false;
481 cmd->when = SCRIPT_After;
483 jcr->RunScripts->append(cmd);
485 free_pool_memory(msg);
486 return bnet_fsend(dir, OKRunAfter);
489 static int runscript_cmd(JCR *jcr)
491 BSOCK *dir = jcr->dir_bsock;
492 POOLMEM *msg = get_memory(dir->msglen+1);
494 RUNSCRIPT *cmd = new_runscript() ;
496 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
497 if (sscanf(dir->msg, runscript, &cmd->on_success,
499 &cmd->abort_on_error,
502 pm_strcpy(jcr->errmsg, dir->msg);
503 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
504 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
511 cmd->set_command(msg);
513 jcr->RunScripts->append(cmd);
515 free_pool_memory(msg);
516 return bnet_fsend(dir, OKRunScript);
520 static bool init_fileset(JCR *jcr)
523 findFILESET *fileset;
532 fileset = (findFILESET *)malloc(sizeof(findFILESET));
533 memset(fileset, 0, sizeof(findFILESET));
534 ff->fileset = fileset;
535 fileset->state = state_none;
536 fileset->include_list.init(1, true);
537 fileset->exclude_list.init(1, true);
541 static findFOPTS *start_options(FF_PKT *ff)
543 int state = ff->fileset->state;
544 findINCEXE *incexe = ff->fileset->incexe;
546 if (state != state_options) {
547 ff->fileset->state = state_options;
548 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
549 memset(fo, 0, sizeof(findFOPTS));
550 fo->regex.init(1, true);
551 fo->regexdir.init(1, true);
552 fo->regexfile.init(1, true);
553 fo->wild.init(1, true);
554 fo->wilddir.init(1, true);
555 fo->wildfile.init(1, true);
556 fo->wildbase.init(1, true);
557 fo->base.init(1, true);
558 fo->fstype.init(1, true);
559 fo->drivetype.init(1, true);
560 incexe->current_opts = fo;
561 incexe->opts_list.append(fo);
563 return incexe->current_opts;
568 * Add fname to include/exclude fileset list. First check for
569 * | and < and if necessary perform command.
571 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
585 p++; /* skip over | */
586 fn = get_pool_memory(PM_FNAME);
587 fn = edit_job_codes(jcr, fn, p, "");
588 bpipe = open_bpipe(fn, 0, "r");
589 free_pool_memory(fn);
591 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
595 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
596 strip_trailing_junk(buf);
597 fileset->incexe->name_list.append(bstrdup(buf));
599 if ((stat=close_bpipe(bpipe)) != 0) {
600 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
601 p, stat, strerror(errno));
606 Dmsg0(100, "Doing < include on client.\n");
607 p++; /* skip over < */
608 if ((ffd = fopen(p, "rb")) == NULL) {
610 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
614 while (fgets(buf, sizeof(buf), ffd)) {
615 strip_trailing_junk(buf);
616 Dmsg1(100, "%s\n", buf);
617 fileset->incexe->name_list.append(bstrdup(buf));
622 fileset->incexe->name_list.append(bstrdup(fname));
628 static void add_fileset(JCR *jcr, const char *item)
630 FF_PKT *ff = jcr->ff;
631 findFILESET *fileset = ff->fileset;
632 int state = fileset->state;
633 findFOPTS *current_opts;
635 /* Get code, optional subcode, and position item past the dividing space */
636 Dmsg1(100, "%s\n", item);
641 int subcode = ' '; /* A space is always a valid subcode */
642 if (item[0] != '\0' && item[0] != ' ') {
650 /* Skip all lines we receive after an error */
651 if (state == state_error) {
656 * The switch tests the code for validity.
657 * The subcode is always good if it is a space, otherwise we must confirm.
658 * We set state to state_error first assuming the subcode is invalid,
659 * requiring state to be set in cases below that handle subcodes.
661 if (subcode != ' ') {
667 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
668 memset(fileset->incexe, 0, sizeof(findINCEXE));
669 fileset->incexe->opts_list.init(1, true);
670 fileset->incexe->name_list.init(1, true);
671 fileset->include_list.append(fileset->incexe);
675 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
676 memset(fileset->incexe, 0, sizeof(findINCEXE));
677 fileset->incexe->opts_list.init(1, true);
678 fileset->incexe->name_list.init(1, true);
679 fileset->exclude_list.append(fileset->incexe);
685 /* File item to either include/include list */
686 state = state_include;
687 add_file_to_fileset(jcr, item, fileset);
690 current_opts = start_options(ff);
694 preg = (regex_t *)malloc(sizeof(regex_t));
695 if (current_opts->flags & FO_IGNORECASE) {
696 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
698 rc = regcomp(preg, item, REG_EXTENDED);
701 regerror(rc, preg, prbuf, sizeof(prbuf));
704 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
708 state = state_options;
709 if (subcode == ' ') {
710 current_opts->regex.append(preg);
711 } else if (subcode == 'D') {
712 current_opts->regexdir.append(preg);
713 } else if (subcode == 'F') {
714 current_opts->regexfile.append(preg);
720 current_opts = start_options(ff);
721 current_opts->base.append(bstrdup(item));
722 state = state_options;
725 current_opts = start_options(ff);
726 state = state_options;
727 if (subcode == ' ') {
728 current_opts->fstype.append(bstrdup(item));
729 } else if (subcode == 'D') {
730 current_opts->drivetype.append(bstrdup(item));
736 current_opts = start_options(ff);
737 state = state_options;
738 if (subcode == ' ') {
739 current_opts->wild.append(bstrdup(item));
740 } else if (subcode == 'D') {
741 current_opts->wilddir.append(bstrdup(item));
742 } else if (subcode == 'F') {
743 current_opts->wildfile.append(bstrdup(item));
744 } else if (subcode == 'B') {
745 current_opts->wildbase.append(bstrdup(item));
751 current_opts = start_options(ff);
752 set_options(current_opts, item);
753 state = state_options;
756 current_opts = start_options(ff);
757 current_opts->reader = bstrdup(item);
758 state = state_options;
761 current_opts = start_options(ff);
762 current_opts->writer = bstrdup(item);
763 state = state_options;
766 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
770 ff->fileset->state = state;
773 static bool term_fileset(JCR *jcr)
775 FF_PKT *ff = jcr->ff;
778 findFILESET *fileset = ff->fileset;
781 for (i=0; i<fileset->include_list.size(); i++) {
782 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
784 for (j=0; j<incexe->opts_list.size(); j++) {
785 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
786 for (k=0; k<fo->regex.size(); k++) {
787 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
789 for (k=0; k<fo->regexdir.size(); k++) {
790 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
792 for (k=0; k<fo->regexfile.size(); k++) {
793 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
795 for (k=0; k<fo->wild.size(); k++) {
796 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
798 for (k=0; k<fo->wilddir.size(); k++) {
799 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
801 for (k=0; k<fo->wildfile.size(); k++) {
802 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
804 for (k=0; k<fo->wildbase.size(); k++) {
805 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
807 for (k=0; k<fo->base.size(); k++) {
808 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
810 for (k=0; k<fo->fstype.size(); k++) {
811 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
813 for (k=0; k<fo->drivetype.size(); k++) {
814 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
817 Dmsg1(400, "D %s\n", fo->reader);
820 Dmsg1(400, "T %s\n", fo->writer);
823 for (j=0; j<incexe->name_list.size(); j++) {
824 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
827 for (i=0; i<fileset->exclude_list.size(); i++) {
828 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
830 for (j=0; j<incexe->opts_list.size(); j++) {
831 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
832 for (k=0; k<fo->regex.size(); k++) {
833 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
835 for (k=0; k<fo->regexdir.size(); k++) {
836 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
838 for (k=0; k<fo->regexfile.size(); k++) {
839 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
841 for (k=0; k<fo->wild.size(); k++) {
842 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
844 for (k=0; k<fo->wilddir.size(); k++) {
845 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
847 for (k=0; k<fo->wildfile.size(); k++) {
848 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
850 for (k=0; k<fo->wildbase.size(); k++) {
851 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
853 for (k=0; k<fo->base.size(); k++) {
854 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
856 for (k=0; k<fo->fstype.size(); k++) {
857 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
859 for (k=0; k<fo->drivetype.size(); k++) {
860 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
863 for (j=0; j<incexe->name_list.size(); j++) {
864 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
868 return ff->fileset->state != state_error;
873 * As an optimization, we should do this during
874 * "compile" time in filed/job.c, and keep only a bit mask
875 * and the Verify options.
877 static void set_options(findFOPTS *fo, const char *opts)
882 for (p=opts; *p; p++) {
884 case 'a': /* alway replace */
885 case '0': /* no option */
888 fo->flags |= FO_EXCLUDE;
891 fo->flags |= FO_MULTIFS;
893 case 'h': /* no recursion */
894 fo->flags |= FO_NO_RECURSION;
896 case 'H': /* no hard link handling */
897 fo->flags |= FO_NO_HARDLINK;
900 fo->flags |= FO_IGNORECASE;
906 fo->flags |= FO_NOREPLACE;
908 case 'p': /* use portable data format */
909 fo->flags |= FO_PORTABLE;
911 case 'R': /* Resource forks and Finder Info */
912 fo->flags |= FO_HFSPLUS;
913 case 'r': /* read fifo */
914 fo->flags |= FO_READFIFO;
919 /* Old director did not specify SHA variant */
920 fo->flags |= FO_SHA1;
923 fo->flags |= FO_SHA1;
928 fo->flags |= FO_SHA256;
932 fo->flags |= FO_SHA512;
937 /* Automatically downgrade to SHA-1 if an unsupported
938 * SHA variant is specified */
939 fo->flags |= FO_SHA1;
945 fo->flags |= FO_SPARSE;
948 fo->flags |= FO_MTIMEONLY;
951 fo->flags |= FO_KEEPATIME;
956 case 'V': /* verify options */
957 /* Copy Verify Options */
958 for (j=0; *p && *p != ':'; p++) {
959 fo->VerifyOpts[j] = *p;
960 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
964 fo->VerifyOpts[j] = 0;
967 fo->flags |= FO_IF_NEWER;
970 fo->flags |= FO_ENHANCEDWILD;
972 case 'Z': /* gzip compression */
973 fo->flags |= FO_GZIP;
974 fo->GZIP_level = *++p - '0';
975 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
978 fo->flags |= FO_NOATIME;
981 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
989 * Director is passing his Fileset
991 static int fileset_cmd(JCR *jcr)
993 BSOCK *dir = jcr->dir_bsock;
996 sscanf(dir->msg, "fileset vss=%d", &vss);
999 if (!init_fileset(jcr)) {
1002 while (bnet_recv(dir) >= 0) {
1003 strip_trailing_junk(dir->msg);
1004 Dmsg1(500, "Fileset: %s\n", dir->msg);
1005 add_fileset(jcr, dir->msg);
1007 if (!term_fileset(jcr)) {
1010 return bnet_fsend(dir, OKinc);
1013 static void free_bootstrap(JCR *jcr)
1015 if (jcr->RestoreBootstrap) {
1016 unlink(jcr->RestoreBootstrap);
1017 free_pool_memory(jcr->RestoreBootstrap);
1018 jcr->RestoreBootstrap = NULL;
1023 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1024 static uint32_t bsr_uniq = 0;
1027 * The Director sends us the bootstrap file, which
1028 * we will in turn pass to the SD.
1030 static int bootstrap_cmd(JCR *jcr)
1032 BSOCK *dir = jcr->dir_bsock;
1033 POOLMEM *fname = get_pool_memory(PM_FNAME);
1036 free_bootstrap(jcr);
1039 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1040 jcr->Job, bsr_uniq);
1042 Dmsg1(400, "bootstrap=%s\n", fname);
1043 jcr->RestoreBootstrap = fname;
1044 bs = fopen(fname, "a+b"); /* create file */
1047 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1048 jcr->RestoreBootstrap, be.strerror());
1050 * Suck up what he is sending to us so that he will then
1051 * read our error message.
1053 while (bnet_recv(dir) >= 0)
1055 free_bootstrap(jcr);
1056 set_jcr_job_status(jcr, JS_ErrorTerminated);
1060 while (bnet_recv(dir) >= 0) {
1061 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1062 fputs(dir->msg, bs);
1066 * Note, do not free the bootstrap yet -- it needs to be
1069 return bnet_fsend(dir, OKbootstrap);
1074 * Get backup level from Director
1077 static int level_cmd(JCR *jcr)
1079 BSOCK *dir = jcr->dir_bsock;
1080 POOLMEM *level, *buf = NULL;
1083 level = get_memory(dir->msglen+1);
1084 Dmsg1(110, "level_cmd: %s", dir->msg);
1085 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1088 /* Base backup requested? */
1089 if (strcmp(level, "base") == 0) {
1090 jcr->JobLevel = L_BASE;
1091 /* Full backup requested? */
1092 } else if (strcmp(level, "full") == 0) {
1093 jcr->JobLevel = L_FULL;
1094 } else if (strcmp(level, "differential") == 0) {
1095 jcr->JobLevel = L_DIFFERENTIAL;
1098 } else if (strcmp(level, "incremental") == 0) {
1099 jcr->JobLevel = L_INCREMENTAL;
1103 * We get his UTC since time, then sync the clocks and correct it
1104 * to agree with our clock.
1106 } else if (strcmp(level, "since_utime") == 0) {
1107 buf = get_memory(dir->msglen+1);
1108 utime_t since_time, adj;
1109 btime_t his_time, bt_start, rt=0, bt_adj=0;
1110 if (jcr->JobLevel == L_NONE) {
1111 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1113 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1114 buf, &mtime_only) != 2) {
1117 since_time = str_to_uint64(buf); /* this is the since time */
1118 Dmsg1(100, "since_time=%d\n", (int)since_time);
1119 char ed1[50], ed2[50];
1121 * Sync clocks by polling him for the time. We take
1122 * 10 samples of his time throwing out the first two.
1124 for (int i=0; i<10; i++) {
1125 bt_start = get_current_btime();
1126 bnet_sig(dir, BNET_BTIME); /* poll for time */
1127 if (bnet_recv(dir) <= 0) { /* get response */
1130 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1133 if (i < 2) { /* toss first two results */
1136 his_time = str_to_uint64(buf);
1137 rt = get_current_btime() - bt_start; /* compute round trip time */
1138 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1139 edit_uint64(bt_start, ed2));
1140 bt_adj += bt_start - his_time - rt/2;
1141 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1144 bt_adj = bt_adj / 8; /* compute average time */
1145 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1146 adj = btime_to_utime(bt_adj);
1147 since_time += adj; /* adjust for clock difference */
1149 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1151 bnet_sig(dir, BNET_EOD);
1153 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1154 jcr->incremental = 1; /* set incremental or decremental backup */
1155 jcr->mtime = (time_t)since_time; /* set since time */
1157 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1165 return bnet_fsend(dir, OKlevel);
1168 pm_strcpy(jcr->errmsg, dir->msg);
1169 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1178 * Get session parameters from Director -- this is for a Restore command
1180 static int session_cmd(JCR *jcr)
1182 BSOCK *dir = jcr->dir_bsock;
1184 Dmsg1(100, "SessionCmd: %s", dir->msg);
1185 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1186 &jcr->VolSessionId, &jcr->VolSessionTime,
1187 &jcr->StartFile, &jcr->EndFile,
1188 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1189 pm_strcpy(jcr->errmsg, dir->msg);
1190 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1194 return bnet_fsend(dir, OKsession);
1198 * Get address of storage daemon from Director
1201 static int storage_cmd(JCR *jcr)
1203 int stored_port; /* storage daemon port */
1204 int enable_ssl; /* enable ssl to sd */
1205 BSOCK *dir = jcr->dir_bsock;
1206 BSOCK *sd; /* storage daemon bsock */
1208 Dmsg1(100, "StorageCmd: %s", dir->msg);
1209 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1210 pm_strcpy(jcr->errmsg, dir->msg);
1211 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1214 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1215 /* Open command communications with Storage daemon */
1216 /* Try to connect for 1 hour at 10 second intervals */
1217 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1218 jcr->stored_addr, NULL, stored_port, 1);
1220 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1221 jcr->stored_addr, stored_port);
1222 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1223 jcr->stored_addr, stored_port);
1226 Dmsg0(110, "Connection OK to SD.\n");
1228 jcr->store_bsock = sd;
1230 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1231 if (!authenticate_storagedaemon(jcr)) {
1232 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1235 Dmsg0(110, "Authenticated with SD.\n");
1237 /* Send OK to Director */
1238 return bnet_fsend(dir, OKstore);
1243 * Do a backup. For now, we handle only Full and Incremental.
1245 static int backup_cmd(JCR *jcr)
1247 BSOCK *dir = jcr->dir_bsock;
1248 BSOCK *sd = jcr->store_bsock;
1251 char ed1[50], ed2[50];
1254 // capture state here, if client is backed up by multiple directors
1255 // and one enables vss and the other does not then enable_vss can change
1256 // between here and where its evaluated after the job completes.
1257 bool bDoVSS = false;
1259 bDoVSS = g_pVSSClient && enable_vss;
1261 /* Run only one at a time */
1265 set_jcr_job_status(jcr, JS_Blocked);
1266 jcr->JobType = JT_BACKUP;
1267 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1270 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1274 bnet_fsend(dir, OKbackup);
1275 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1278 * Send Append Open Session to Storage daemon
1280 bnet_fsend(sd, append_open);
1281 Dmsg1(110, ">stored: %s", sd->msg);
1283 * Expect to receive back the Ticket number
1285 if (bget_msg(sd) >= 0) {
1286 Dmsg1(110, "<stored: %s", sd->msg);
1287 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1288 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1291 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1293 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1298 * Send Append data command to Storage daemon
1300 bnet_fsend(sd, append_data, jcr->Ticket);
1301 Dmsg1(110, ">stored: %s", sd->msg);
1304 * Expect to get OK data
1306 Dmsg1(110, "<stored: %s", sd->msg);
1307 if (!response(jcr, sd, OK_data, "Append Data")) {
1311 generate_daemon_event(jcr, "JobStart");
1314 /* START VSS ON WIN 32 */
1316 if (g_pVSSClient->InitializeForBackup()) {
1317 /* tell vss which drives to snapshot */
1318 char szWinDriveLetters[27];
1319 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1320 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1321 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1322 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1325 /* tell user if snapshot creation of a specific drive failed */
1327 for (i=0; i < strlen(szWinDriveLetters); i++) {
1328 if (islower(szWinDriveLetters[i])) {
1329 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1333 /* inform user about writer states */
1334 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1335 if (g_pVSSClient->GetWriterState(i) < 1) {
1336 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1341 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1345 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1351 * Send Files to Storage daemon
1353 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1354 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1355 set_jcr_job_status(jcr, JS_ErrorTerminated);
1356 bnet_suppress_error_messages(sd, 1);
1357 bget_msg(sd); /* Read final response from append_data */
1358 Dmsg0(110, "Error in blast_data.\n");
1359 /* run shortly after end of data transmission */
1360 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1363 set_jcr_job_status(jcr, JS_Terminated);
1365 /* run shortly after end of data transmission */
1366 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1368 if (jcr->JobStatus != JS_Terminated) {
1369 bnet_suppress_error_messages(sd, 1);
1370 goto cleanup; /* bail out now */
1373 * Expect to get response to append_data from Storage daemon
1375 if (!response(jcr, sd, OK_append, "Append Data")) {
1376 set_jcr_job_status(jcr, JS_ErrorTerminated);
1381 * Send Append End Data to Storage daemon
1383 bnet_fsend(sd, append_end, jcr->Ticket);
1385 if (!response(jcr, sd, OK_end, "Append End")) {
1386 set_jcr_job_status(jcr, JS_ErrorTerminated);
1391 * Send Append Close to Storage daemon
1393 bnet_fsend(sd, append_close, jcr->Ticket);
1394 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1395 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1397 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1401 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1404 if (SDJobStatus != JS_Terminated) {
1405 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1412 /* STOP VSS ON WIN 32 */
1413 /* tell vss to close the backup session */
1415 if (g_pVSSClient->CloseBackup()) {
1416 /* inform user about writer states */
1417 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1418 int msg_type = M_INFO;
1419 if (g_pVSSClient->GetWriterState(i) < 1) {
1420 msg_type = M_WARNING;
1423 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1430 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1431 edit_uint64(jcr->ReadBytes, ed1),
1432 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1433 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1435 return 0; /* return and stop command loop */
1439 * Do a Verify for Director
1442 static int verify_cmd(JCR *jcr)
1444 BSOCK *dir = jcr->dir_bsock;
1445 BSOCK *sd = jcr->store_bsock;
1446 char level[100], ed1[50], ed2[50];
1448 jcr->JobType = JT_VERIFY;
1449 if (sscanf(dir->msg, verifycmd, level) != 1) {
1450 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1454 if (strcasecmp(level, "init") == 0) {
1455 jcr->JobLevel = L_VERIFY_INIT;
1456 } else if (strcasecmp(level, "catalog") == 0){
1457 jcr->JobLevel = L_VERIFY_CATALOG;
1458 } else if (strcasecmp(level, "volume") == 0){
1459 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1460 } else if (strcasecmp(level, "data") == 0){
1461 jcr->JobLevel = L_VERIFY_DATA;
1462 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1463 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1465 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1469 bnet_fsend(dir, OKverify);
1471 generate_daemon_event(jcr, "JobStart");
1473 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1475 switch (jcr->JobLevel) {
1477 case L_VERIFY_CATALOG:
1480 case L_VERIFY_VOLUME_TO_CATALOG:
1481 if (!open_sd_read_session(jcr)) {
1484 start_dir_heartbeat(jcr);
1485 do_verify_volume(jcr);
1486 stop_dir_heartbeat(jcr);
1488 * Send Close session command to Storage daemon
1490 bnet_fsend(sd, read_close, jcr->Ticket);
1491 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1493 /* ****FIXME**** check response */
1494 bget_msg(sd); /* get OK */
1496 /* Inform Storage daemon that we are done */
1497 bnet_sig(sd, BNET_TERMINATE);
1500 case L_VERIFY_DISK_TO_CATALOG:
1504 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1508 bnet_sig(dir, BNET_EOD);
1510 /* Send termination status back to Dir */
1511 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1512 edit_uint64(jcr->ReadBytes, ed1),
1513 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1515 /* Inform Director that we are done */
1516 bnet_sig(dir, BNET_TERMINATE);
1517 return 0; /* return and terminate command loop */
1521 * Do a Restore for Director
1524 static int restore_cmd(JCR *jcr)
1526 BSOCK *dir = jcr->dir_bsock;
1527 BSOCK *sd = jcr->store_bsock;
1531 char ed1[50], ed2[50];
1534 * Scan WHERE (base directory for restore) from command
1536 Dmsg0(150, "restore command\n");
1537 /* Pickup where string */
1538 where = get_memory(dir->msglen+1);
1541 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1542 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1543 pm_strcpy(jcr->errmsg, dir->msg);
1544 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1549 /* Turn / into nothing */
1550 if (where[0] == '/' && where[1] == 0) {
1554 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1555 unbash_spaces(where);
1556 jcr->where = bstrdup(where);
1557 free_pool_memory(where);
1558 jcr->replace = replace;
1559 jcr->prefix_links = prefix_links;
1561 bnet_fsend(dir, OKrestore);
1562 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1564 jcr->JobType = JT_RESTORE;
1566 set_jcr_job_status(jcr, JS_Blocked);
1568 if (!open_sd_read_session(jcr)) {
1569 set_jcr_job_status(jcr, JS_ErrorTerminated);
1573 set_jcr_job_status(jcr, JS_Running);
1576 * Do restore of files and data
1578 start_dir_heartbeat(jcr);
1579 generate_daemon_event(jcr, "JobStart");
1581 stop_dir_heartbeat(jcr);
1583 set_jcr_job_status(jcr, JS_Terminated);
1584 if (jcr->JobStatus != JS_Terminated) {
1585 bnet_suppress_error_messages(sd, 1);
1589 * Send Close session command to Storage daemon
1591 bnet_fsend(sd, read_close, jcr->Ticket);
1592 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1594 bget_msg(sd); /* get OK */
1596 /* Inform Storage daemon that we are done */
1597 bnet_sig(sd, BNET_TERMINATE);
1602 set_jcr_job_status(jcr, JS_ErrorTerminated);
1604 /* Send termination status back to Dir */
1605 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1606 edit_uint64(jcr->ReadBytes, ed1),
1607 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1609 /* Inform Director that we are done */
1610 bnet_sig(dir, BNET_TERMINATE);
1612 Dmsg0(130, "Done in job.c\n");
1613 return 0; /* return and terminate command loop */
1616 static int open_sd_read_session(JCR *jcr)
1618 BSOCK *sd = jcr->store_bsock;
1621 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1624 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1625 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1626 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1628 * Open Read Session with Storage daemon
1630 bnet_fsend(sd, read_open, "DummyVolume",
1631 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1632 jcr->StartBlock, jcr->EndBlock);
1633 Dmsg1(110, ">stored: %s", sd->msg);
1638 if (bget_msg(sd) >= 0) {
1639 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1640 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1641 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1644 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1646 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1650 if (!send_bootstrap_file(jcr)) {
1655 * Start read of data with Storage daemon
1657 bnet_fsend(sd, read_data, jcr->Ticket);
1658 Dmsg1(110, ">stored: %s", sd->msg);
1663 if (!response(jcr, sd, OK_data, "Read Data")) {
1670 * Destroy the Job Control Record and associated
1671 * resources (sockets).
1673 static void filed_free_jcr(JCR *jcr)
1675 if (jcr->store_bsock) {
1676 bnet_close(jcr->store_bsock);
1678 free_bootstrap(jcr);
1679 if (jcr->last_fname) {
1680 free_pool_memory(jcr->last_fname);
1682 free_runscripts(jcr->RunScripts);
1683 delete jcr->RunScripts;
1689 * Get response from Storage daemon to a command we
1690 * sent. Check that the response is OK.
1692 * Returns: 0 on failure
1695 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1700 if (bget_msg(sd) > 0) {
1701 Dmsg0(110, sd->msg);
1702 if (strcmp(sd->msg, resp) == 0) {
1706 if (job_canceled(jcr)) {
1707 return 0; /* if canceled avoid useless error messages */
1709 if (is_bnet_error(sd)) {
1710 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1711 cmd, bnet_strerror(sd));
1713 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1714 cmd, resp, sd->msg);
1719 static int send_bootstrap_file(JCR *jcr)
1723 BSOCK *sd = jcr->store_bsock;
1724 const char *bootstrap = "bootstrap\n";
1727 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1728 if (!jcr->RestoreBootstrap) {
1731 bs = fopen(jcr->RestoreBootstrap, "rb");
1734 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1735 jcr->RestoreBootstrap, be.strerror());
1736 set_jcr_job_status(jcr, JS_ErrorTerminated);
1739 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1741 while (fgets(buf, sizeof(buf), bs)) {
1742 sd->msglen = Mmsg(sd->msg, "%s", buf);
1745 bnet_sig(sd, BNET_EOD);
1747 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1748 set_jcr_job_status(jcr, JS_ErrorTerminated);
1754 free_bootstrap(jcr);