2 * Bacula File Daemon Job processing
4 * Kern Sibbald, October MM
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
27 #if defined(WIN32_VSS)
30 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 static int enable_vss;
34 extern CLIENT *me; /* our client resource */
36 /* Imported functions */
37 extern int status_cmd(JCR *jcr);
38 extern int qstatus_cmd(JCR *jcr);
40 /* Forward referenced functions */
41 static int backup_cmd(JCR *jcr);
42 static int bootstrap_cmd(JCR *jcr);
43 static int cancel_cmd(JCR *jcr);
44 static int setdebug_cmd(JCR *jcr);
45 static int estimate_cmd(JCR *jcr);
46 static int hello_cmd(JCR *jcr);
47 static int job_cmd(JCR *jcr);
48 static int fileset_cmd(JCR *jcr);
49 static int level_cmd(JCR *jcr);
50 static int verify_cmd(JCR *jcr);
51 static int restore_cmd(JCR *jcr);
52 static int storage_cmd(JCR *jcr);
53 static int session_cmd(JCR *jcr);
54 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
55 static void filed_free_jcr(JCR *jcr);
56 static int open_sd_read_session(JCR *jcr);
57 static int send_bootstrap_file(JCR *jcr);
58 static int runscript_cmd(JCR *jcr);
59 static int runbefore_cmd(JCR *jcr);
60 static int runafter_cmd(JCR *jcr);
61 static int runbeforenow_cmd(JCR *jcr);
62 static void set_options(findFOPTS *fo, const char *opts);
65 /* Exported functions */
70 int monitoraccess; /* specify if monitors have access to this function */
74 * The following are the recognized commands from the Director.
76 static struct s_cmds cmds[] = {
77 {"backup", backup_cmd, 0},
78 {"cancel", cancel_cmd, 0},
79 {"setdebug=", setdebug_cmd, 0},
80 {"estimate", estimate_cmd, 0},
81 {"Hello", hello_cmd, 1},
82 {"fileset", fileset_cmd, 0},
83 {"JobId=", job_cmd, 0},
84 {"level = ", level_cmd, 0},
85 {"restore", restore_cmd, 0},
86 {"session", session_cmd, 0},
87 {"status", status_cmd, 1},
88 {".status", qstatus_cmd, 1},
89 {"storage ", storage_cmd, 0},
90 {"verify", verify_cmd, 0},
91 {"bootstrap", bootstrap_cmd, 0},
92 {"RunBeforeNow", runbeforenow_cmd, 0},
93 {"RunBeforeJob", runbefore_cmd, 0},
94 {"RunAfterJob", runafter_cmd, 0},
95 {"Run", runscript_cmd, 0},
96 {NULL, NULL} /* list terminator */
99 /* Commands received from director that need scanning */
100 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
101 static char storaddr[] = "storage address=%s port=%d ssl=%d";
102 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
103 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
104 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
105 static char verifycmd[] = "verify level=%30s";
106 static char estimatecmd[] = "estimate listing=%d";
107 static char runbefore[] = "RunBeforeJob %s";
108 static char runafter[] = "RunAfterJob %s";
109 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s";
111 /* Responses sent to Director */
112 static char errmsg[] = "2999 Invalid command\n";
113 static char no_auth[] = "2998 No Authorization\n";
114 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
115 static char OKinc[] = "2000 OK include\n";
116 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
117 static char OKlevel[] = "2000 OK level\n";
118 static char OKbackup[] = "2000 OK backup\n";
119 static char OKbootstrap[] = "2000 OK bootstrap\n";
120 static char OKverify[] = "2000 OK verify\n";
121 static char OKrestore[] = "2000 OK restore\n";
122 static char OKsession[] = "2000 OK session\n";
123 static char OKstore[] = "2000 OK storage\n";
124 static char OKjob[] = "2000 OK Job %s,%s,%s";
125 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
126 static char BADjob[] = "2901 Bad Job\n";
127 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
128 static char OKRunBefore[] = "2000 OK RunBefore\n";
129 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
130 static char OKRunAfter[] = "2000 OK RunAfter\n";
131 static char OKRunScript[] = "2000 OK RunScript\n";
134 /* Responses received from Storage Daemon */
135 static char OK_end[] = "3000 OK end\n";
136 static char OK_close[] = "3000 OK close Status = %d\n";
137 static char OK_open[] = "3000 OK open ticket = %d\n";
138 static char OK_data[] = "3000 OK data\n";
139 static char OK_append[] = "3000 OK append data\n";
140 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
143 /* Commands sent to Storage Daemon */
144 static char append_open[] = "append open session\n";
145 static char append_data[] = "append data %d\n";
146 static char append_end[] = "append end session %d\n";
147 static char append_close[] = "append close session %d\n";
148 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
149 static char read_data[] = "read data %d\n";
150 static char read_close[] = "read close session %d\n";
153 * Accept requests from a Director
155 * NOTE! We are running as a separate thread
157 * Send output one line
158 * at a time followed by a zero length transmission.
160 * Return when the connection is terminated or there
163 * Basic task here is:
164 * Authenticate Director (during Hello command).
165 * Accept commands one at a time from the Director
169 void *handle_client_request(void *dirp)
174 BSOCK *dir = (BSOCK *)dirp;
176 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
177 jcr->dir_bsock = dir;
178 jcr->ff = init_find_files();
179 jcr->start_time = time(NULL);
180 jcr->RunScripts = New(alist(10, not_owned_by_alist));
181 jcr->last_fname = get_pool_memory(PM_FNAME);
182 jcr->last_fname[0] = 0;
183 jcr->client_name = get_memory(strlen(my_name) + 1);
184 pm_strcpy(jcr->client_name, my_name);
185 jcr->pki_sign = me->pki_sign;
186 jcr->pki_encrypt = me->pki_encrypt;
187 jcr->pki_keypair = me->pki_keypair;
188 jcr->pki_signers = me->pki_signers;
189 jcr->pki_recipients = me->pki_recipients;
191 enable_backup_privileges(NULL, 1 /* ignore_errors */);
193 /**********FIXME******* add command handler error code */
195 for (quit=false; !quit;) {
198 if (bnet_recv(dir) < 0) {
199 break; /* connection terminated */
201 dir->msg[dir->msglen] = 0;
202 Dmsg1(100, "<dird: %s", dir->msg);
204 for (i=0; cmds[i].cmd; i++) {
205 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
206 found = true; /* indicate command found */
207 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
208 bnet_fsend(dir, no_auth);
209 bnet_sig(dir, BNET_EOD);
212 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
213 Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
214 bnet_fsend(dir, illegal_cmd);
215 bnet_sig(dir, BNET_EOD);
218 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
219 if (!cmds[i].func(jcr)) { /* do command */
220 quit = true; /* error or fully terminated, get out */
221 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
226 if (!found) { /* command not found */
227 bnet_fsend(dir, errmsg);
233 /* Inform Storage daemon that we are done */
234 if (jcr->store_bsock) {
235 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
238 generate_daemon_event(jcr, "JobEnd");
240 dequeue_messages(jcr); /* send any queued messages */
242 /* Inform Director that we are done */
243 bnet_sig(dir, BNET_TERMINATE);
245 /* Clean up fileset */
246 FF_PKT *ff = jcr->ff;
247 findFILESET *fileset = ff->fileset;
250 /* Delete FileSet Include lists */
251 for (i=0; i<fileset->include_list.size(); i++) {
252 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
253 for (j=0; j<incexe->opts_list.size(); j++) {
254 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
255 for (k=0; k<fo->regex.size(); k++) {
256 regfree((regex_t *)fo->regex.get(k));
259 fo->regexdir.destroy();
260 fo->regexfile.destroy();
262 fo->wilddir.destroy();
263 fo->wildfile.destroy();
264 fo->wildbase.destroy();
266 fo->fstype.destroy();
267 fo->drivetype.destroy();
275 incexe->opts_list.destroy();
276 incexe->name_list.destroy();
278 fileset->include_list.destroy();
280 /* Delete FileSet Exclude lists */
281 for (i=0; i<fileset->exclude_list.size(); i++) {
282 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
283 for (j=0; j<incexe->opts_list.size(); j++) {
284 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
286 fo->regexdir.destroy();
287 fo->regexfile.destroy();
289 fo->wilddir.destroy();
290 fo->wildfile.destroy();
291 fo->wildbase.destroy();
293 fo->fstype.destroy();
294 fo->drivetype.destroy();
296 incexe->opts_list.destroy();
297 incexe->name_list.destroy();
299 fileset->exclude_list.destroy();
303 Dmsg0(100, "Calling term_find_files\n");
304 term_find_files(jcr->ff);
306 Dmsg0(100, "Done with term_find_files\n");
307 free_jcr(jcr); /* destroy JCR record */
308 Dmsg0(100, "Done with free_jcr\n");
313 * Hello from Director he must identify himself and provide his
316 static int hello_cmd(JCR *jcr)
318 Dmsg0(120, "Calling Authenticate\n");
319 if (!authenticate_director(jcr)) {
322 Dmsg0(120, "OK Authenticate\n");
323 jcr->authenticated = true;
330 static int cancel_cmd(JCR *jcr)
332 BSOCK *dir = jcr->dir_bsock;
333 char Job[MAX_NAME_LENGTH];
336 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
337 if (!(cjcr=get_jcr_by_full_name(Job))) {
338 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
340 if (cjcr->store_bsock) {
341 cjcr->store_bsock->timed_out = 1;
342 cjcr->store_bsock->terminated = 1;
343 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
345 set_jcr_job_status(cjcr, JS_Canceled);
347 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
350 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
352 bnet_sig(dir, BNET_EOD);
358 * Set debug level as requested by the Director
361 static int setdebug_cmd(JCR *jcr)
363 BSOCK *dir = jcr->dir_bsock;
364 int level, trace_flag;
366 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
367 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
368 pm_strcpy(jcr->errmsg, dir->msg);
369 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
373 set_trace(trace_flag);
374 return bnet_fsend(dir, OKsetdebug, level);
378 static int estimate_cmd(JCR *jcr)
380 BSOCK *dir = jcr->dir_bsock;
383 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
384 pm_strcpy(jcr->errmsg, dir->msg);
385 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
386 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
390 bnet_fsend(dir, OKest, jcr->num_files_examined,
391 edit_uint64_with_commas(jcr->JobBytes, ed2));
392 bnet_sig(dir, BNET_EOD);
397 * Get JobId and Storage Daemon Authorization key from Director
399 static int job_cmd(JCR *jcr)
401 BSOCK *dir = jcr->dir_bsock;
402 POOLMEM *sd_auth_key;
404 sd_auth_key = get_memory(dir->msglen);
405 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
406 &jcr->VolSessionId, &jcr->VolSessionTime,
408 pm_strcpy(jcr->errmsg, dir->msg);
409 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
410 bnet_fsend(dir, BADjob);
411 free_pool_memory(sd_auth_key);
414 jcr->sd_auth_key = bstrdup(sd_auth_key);
415 free_pool_memory(sd_auth_key);
416 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
417 return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
420 static int runbefore_cmd(JCR *jcr)
423 BSOCK *dir = jcr->dir_bsock;
424 POOLMEM *cmd = get_memory(dir->msglen+1);
427 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
428 if (sscanf(dir->msg, runbefore, cmd) != 1) {
429 pm_strcpy(jcr->errmsg, dir->msg);
430 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
431 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
437 /* Run the command now */
438 script = new_runscript();
439 script->set_command(cmd);
440 script->when = SCRIPT_Before;
441 ok = script->run(jcr, "ClientRunBeforeJob");
442 free_runscript(script);
446 bnet_fsend(dir, OKRunBefore);
449 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
454 static int runbeforenow_cmd(JCR *jcr)
456 BSOCK *dir = jcr->dir_bsock;
458 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
459 return bnet_fsend(dir, OKRunBeforeNow);
462 static int runafter_cmd(JCR *jcr)
464 BSOCK *dir = jcr->dir_bsock;
465 POOLMEM *msg = get_memory(dir->msglen+1);
468 Dmsg1(100, "runafter_cmd: %s", dir->msg);
469 if (sscanf(dir->msg, runafter, msg) != 1) {
470 pm_strcpy(jcr->errmsg, dir->msg);
471 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
472 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
478 cmd = new_runscript();
479 cmd->set_command(msg);
480 cmd->on_success = true;
481 cmd->on_failure = false;
482 cmd->when = SCRIPT_After;
484 jcr->RunScripts->append(cmd);
486 free_pool_memory(msg);
487 return bnet_fsend(dir, OKRunAfter);
490 static int runscript_cmd(JCR *jcr)
492 BSOCK *dir = jcr->dir_bsock;
493 POOLMEM *msg = get_memory(dir->msglen+1);
495 RUNSCRIPT *cmd = new_runscript() ;
497 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
498 if (sscanf(dir->msg, runscript, &cmd->on_success,
500 &cmd->abort_on_error,
503 pm_strcpy(jcr->errmsg, dir->msg);
504 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
505 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
512 cmd->set_command(msg);
514 jcr->RunScripts->append(cmd);
516 free_pool_memory(msg);
517 return bnet_fsend(dir, OKRunScript);
521 static bool init_fileset(JCR *jcr)
524 findFILESET *fileset;
533 fileset = (findFILESET *)malloc(sizeof(findFILESET));
534 memset(fileset, 0, sizeof(findFILESET));
535 ff->fileset = fileset;
536 fileset->state = state_none;
537 fileset->include_list.init(1, true);
538 fileset->exclude_list.init(1, true);
542 static findFOPTS *start_options(FF_PKT *ff)
544 int state = ff->fileset->state;
545 findINCEXE *incexe = ff->fileset->incexe;
547 if (state != state_options) {
548 ff->fileset->state = state_options;
549 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
550 memset(fo, 0, sizeof(findFOPTS));
551 fo->regex.init(1, true);
552 fo->regexdir.init(1, true);
553 fo->regexfile.init(1, true);
554 fo->wild.init(1, true);
555 fo->wilddir.init(1, true);
556 fo->wildfile.init(1, true);
557 fo->wildbase.init(1, true);
558 fo->base.init(1, true);
559 fo->fstype.init(1, true);
560 fo->drivetype.init(1, true);
561 incexe->current_opts = fo;
562 incexe->opts_list.append(fo);
564 return incexe->current_opts;
569 * Add fname to include/exclude fileset list. First check for
570 * | and < and if necessary perform command.
572 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
586 p++; /* skip over | */
587 fn = get_pool_memory(PM_FNAME);
588 fn = edit_job_codes(jcr, fn, p, "");
589 bpipe = open_bpipe(fn, 0, "r");
590 free_pool_memory(fn);
592 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
596 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
597 strip_trailing_junk(buf);
598 fileset->incexe->name_list.append(bstrdup(buf));
600 if ((stat=close_bpipe(bpipe)) != 0) {
601 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
602 p, stat, strerror(errno));
607 Dmsg0(100, "Doing < include on client.\n");
608 p++; /* skip over < */
609 if ((ffd = fopen(p, "rb")) == NULL) {
611 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
615 while (fgets(buf, sizeof(buf), ffd)) {
616 strip_trailing_junk(buf);
617 Dmsg1(100, "%s\n", buf);
618 fileset->incexe->name_list.append(bstrdup(buf));
623 fileset->incexe->name_list.append(bstrdup(fname));
629 static void add_fileset(JCR *jcr, const char *item)
631 FF_PKT *ff = jcr->ff;
632 findFILESET *fileset = ff->fileset;
633 int state = fileset->state;
634 findFOPTS *current_opts;
636 /* Get code, optional subcode, and position item past the dividing space */
637 Dmsg1(100, "%s\n", item);
642 int subcode = ' '; /* A space is always a valid subcode */
643 if (item[0] != '\0' && item[0] != ' ') {
651 /* Skip all lines we receive after an error */
652 if (state == state_error) {
657 * The switch tests the code for validity.
658 * The subcode is always good if it is a space, otherwise we must confirm.
659 * We set state to state_error first assuming the subcode is invalid,
660 * requiring state to be set in cases below that handle subcodes.
662 if (subcode != ' ') {
668 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
669 memset(fileset->incexe, 0, sizeof(findINCEXE));
670 fileset->incexe->opts_list.init(1, true);
671 fileset->incexe->name_list.init(1, true);
672 fileset->include_list.append(fileset->incexe);
676 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
677 memset(fileset->incexe, 0, sizeof(findINCEXE));
678 fileset->incexe->opts_list.init(1, true);
679 fileset->incexe->name_list.init(1, true);
680 fileset->exclude_list.append(fileset->incexe);
686 /* File item to either include/include list */
687 state = state_include;
688 add_file_to_fileset(jcr, item, fileset);
691 current_opts = start_options(ff);
695 preg = (regex_t *)malloc(sizeof(regex_t));
696 if (current_opts->flags & FO_IGNORECASE) {
697 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
699 rc = regcomp(preg, item, REG_EXTENDED);
702 regerror(rc, preg, prbuf, sizeof(prbuf));
705 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
709 state = state_options;
710 if (subcode == ' ') {
711 current_opts->regex.append(preg);
712 } else if (subcode == 'D') {
713 current_opts->regexdir.append(preg);
714 } else if (subcode == 'F') {
715 current_opts->regexfile.append(preg);
721 current_opts = start_options(ff);
722 current_opts->base.append(bstrdup(item));
723 state = state_options;
726 current_opts = start_options(ff);
727 state = state_options;
728 if (subcode == ' ') {
729 current_opts->fstype.append(bstrdup(item));
730 } else if (subcode == 'D') {
731 current_opts->drivetype.append(bstrdup(item));
737 current_opts = start_options(ff);
738 state = state_options;
739 if (subcode == ' ') {
740 current_opts->wild.append(bstrdup(item));
741 } else if (subcode == 'D') {
742 current_opts->wilddir.append(bstrdup(item));
743 } else if (subcode == 'F') {
744 current_opts->wildfile.append(bstrdup(item));
745 } else if (subcode == 'B') {
746 current_opts->wildbase.append(bstrdup(item));
752 current_opts = start_options(ff);
753 set_options(current_opts, item);
754 state = state_options;
757 current_opts = start_options(ff);
758 current_opts->reader = bstrdup(item);
759 state = state_options;
762 current_opts = start_options(ff);
763 current_opts->writer = bstrdup(item);
764 state = state_options;
767 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
771 ff->fileset->state = state;
774 static bool term_fileset(JCR *jcr)
776 FF_PKT *ff = jcr->ff;
779 findFILESET *fileset = ff->fileset;
782 for (i=0; i<fileset->include_list.size(); i++) {
783 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
785 for (j=0; j<incexe->opts_list.size(); j++) {
786 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
787 for (k=0; k<fo->regex.size(); k++) {
788 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
790 for (k=0; k<fo->regexdir.size(); k++) {
791 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
793 for (k=0; k<fo->regexfile.size(); k++) {
794 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
796 for (k=0; k<fo->wild.size(); k++) {
797 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
799 for (k=0; k<fo->wilddir.size(); k++) {
800 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
802 for (k=0; k<fo->wildfile.size(); k++) {
803 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
805 for (k=0; k<fo->wildbase.size(); k++) {
806 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
808 for (k=0; k<fo->base.size(); k++) {
809 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
811 for (k=0; k<fo->fstype.size(); k++) {
812 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
814 for (k=0; k<fo->drivetype.size(); k++) {
815 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
818 Dmsg1(400, "D %s\n", fo->reader);
821 Dmsg1(400, "T %s\n", fo->writer);
824 for (j=0; j<incexe->name_list.size(); j++) {
825 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
828 for (i=0; i<fileset->exclude_list.size(); i++) {
829 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
831 for (j=0; j<incexe->opts_list.size(); j++) {
832 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
833 for (k=0; k<fo->regex.size(); k++) {
834 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
836 for (k=0; k<fo->regexdir.size(); k++) {
837 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
839 for (k=0; k<fo->regexfile.size(); k++) {
840 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
842 for (k=0; k<fo->wild.size(); k++) {
843 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
845 for (k=0; k<fo->wilddir.size(); k++) {
846 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
848 for (k=0; k<fo->wildfile.size(); k++) {
849 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
851 for (k=0; k<fo->wildbase.size(); k++) {
852 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
854 for (k=0; k<fo->base.size(); k++) {
855 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
857 for (k=0; k<fo->fstype.size(); k++) {
858 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
860 for (k=0; k<fo->drivetype.size(); k++) {
861 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
864 for (j=0; j<incexe->name_list.size(); j++) {
865 Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
869 return ff->fileset->state != state_error;
874 * As an optimization, we should do this during
875 * "compile" time in filed/job.c, and keep only a bit mask
876 * and the Verify options.
878 static void set_options(findFOPTS *fo, const char *opts)
883 for (p=opts; *p; p++) {
885 case 'a': /* alway replace */
886 case '0': /* no option */
889 fo->flags |= FO_EXCLUDE;
892 fo->flags |= FO_MULTIFS;
894 case 'h': /* no recursion */
895 fo->flags |= FO_NO_RECURSION;
897 case 'H': /* no hard link handling */
898 fo->flags |= FO_NO_HARDLINK;
901 fo->flags |= FO_IGNORECASE;
907 fo->flags |= FO_NOREPLACE;
909 case 'p': /* use portable data format */
910 fo->flags |= FO_PORTABLE;
912 case 'R': /* Resource forks and Finder Info */
913 fo->flags |= FO_HFSPLUS;
914 case 'r': /* read fifo */
915 fo->flags |= FO_READFIFO;
920 /* Old director did not specify SHA variant */
921 fo->flags |= FO_SHA1;
924 fo->flags |= FO_SHA1;
929 fo->flags |= FO_SHA256;
933 fo->flags |= FO_SHA512;
938 /* Automatically downgrade to SHA-1 if an unsupported
939 * SHA variant is specified */
940 fo->flags |= FO_SHA1;
946 fo->flags |= FO_SPARSE;
949 fo->flags |= FO_MTIMEONLY;
952 fo->flags |= FO_KEEPATIME;
957 case 'V': /* verify options */
958 /* Copy Verify Options */
959 for (j=0; *p && *p != ':'; p++) {
960 fo->VerifyOpts[j] = *p;
961 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
965 fo->VerifyOpts[j] = 0;
968 fo->flags |= FO_IF_NEWER;
971 fo->flags |= FO_ENHANCEDWILD;
973 case 'Z': /* gzip compression */
974 fo->flags |= FO_GZIP;
975 fo->GZIP_level = *++p - '0';
976 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
979 fo->flags |= FO_NOATIME;
982 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
990 * Director is passing his Fileset
992 static int fileset_cmd(JCR *jcr)
994 BSOCK *dir = jcr->dir_bsock;
996 #if defined(WIN32_VSS)
999 sscanf(dir->msg, "fileset vss=%d", &vss);
1003 if (!init_fileset(jcr)) {
1006 while (bnet_recv(dir) >= 0) {
1007 strip_trailing_junk(dir->msg);
1008 Dmsg1(500, "Fileset: %s\n", dir->msg);
1009 add_fileset(jcr, dir->msg);
1011 if (!term_fileset(jcr)) {
1014 return bnet_fsend(dir, OKinc);
1017 static void free_bootstrap(JCR *jcr)
1019 if (jcr->RestoreBootstrap) {
1020 unlink(jcr->RestoreBootstrap);
1021 free_pool_memory(jcr->RestoreBootstrap);
1022 jcr->RestoreBootstrap = NULL;
1027 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1028 static uint32_t bsr_uniq = 0;
1031 * The Director sends us the bootstrap file, which
1032 * we will in turn pass to the SD.
1034 static int bootstrap_cmd(JCR *jcr)
1036 BSOCK *dir = jcr->dir_bsock;
1037 POOLMEM *fname = get_pool_memory(PM_FNAME);
1040 free_bootstrap(jcr);
1043 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1044 jcr->Job, bsr_uniq);
1046 Dmsg1(400, "bootstrap=%s\n", fname);
1047 jcr->RestoreBootstrap = fname;
1048 bs = fopen(fname, "a+b"); /* create file */
1051 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1052 jcr->RestoreBootstrap, be.strerror());
1054 * Suck up what he is sending to us so that he will then
1055 * read our error message.
1057 while (bnet_recv(dir) >= 0)
1059 free_bootstrap(jcr);
1060 set_jcr_job_status(jcr, JS_ErrorTerminated);
1064 while (bnet_recv(dir) >= 0) {
1065 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1066 fputs(dir->msg, bs);
1070 * Note, do not free the bootstrap yet -- it needs to be
1073 return bnet_fsend(dir, OKbootstrap);
1078 * Get backup level from Director
1081 static int level_cmd(JCR *jcr)
1083 BSOCK *dir = jcr->dir_bsock;
1084 POOLMEM *level, *buf = NULL;
1087 level = get_memory(dir->msglen+1);
1088 Dmsg1(110, "level_cmd: %s", dir->msg);
1089 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1092 /* Base backup requested? */
1093 if (strcmp(level, "base") == 0) {
1094 jcr->JobLevel = L_BASE;
1095 /* Full backup requested? */
1096 } else if (strcmp(level, "full") == 0) {
1097 jcr->JobLevel = L_FULL;
1098 } else if (strcmp(level, "differential") == 0) {
1099 jcr->JobLevel = L_DIFFERENTIAL;
1102 } else if (strcmp(level, "incremental") == 0) {
1103 jcr->JobLevel = L_INCREMENTAL;
1107 * We get his UTC since time, then sync the clocks and correct it
1108 * to agree with our clock.
1110 } else if (strcmp(level, "since_utime") == 0) {
1111 buf = get_memory(dir->msglen+1);
1112 utime_t since_time, adj;
1113 btime_t his_time, bt_start, rt=0, bt_adj=0;
1114 if (jcr->JobLevel == L_NONE) {
1115 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1117 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1118 buf, &mtime_only) != 2) {
1121 since_time = str_to_uint64(buf); /* this is the since time */
1122 Dmsg1(100, "since_time=%d\n", (int)since_time);
1123 char ed1[50], ed2[50];
1125 * Sync clocks by polling him for the time. We take
1126 * 10 samples of his time throwing out the first two.
1128 for (int i=0; i<10; i++) {
1129 bt_start = get_current_btime();
1130 bnet_sig(dir, BNET_BTIME); /* poll for time */
1131 if (bnet_recv(dir) <= 0) { /* get response */
1134 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1137 if (i < 2) { /* toss first two results */
1140 his_time = str_to_uint64(buf);
1141 rt = get_current_btime() - bt_start; /* compute round trip time */
1142 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1143 edit_uint64(bt_start, ed2));
1144 bt_adj += bt_start - his_time - rt/2;
1145 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1148 bt_adj = bt_adj / 8; /* compute average time */
1149 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1150 adj = btime_to_utime(bt_adj);
1151 since_time += adj; /* adjust for clock difference */
1153 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1155 bnet_sig(dir, BNET_EOD);
1157 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1158 jcr->incremental = 1; /* set incremental or decremental backup */
1159 jcr->mtime = (time_t)since_time; /* set since time */
1161 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1169 return bnet_fsend(dir, OKlevel);
1172 pm_strcpy(jcr->errmsg, dir->msg);
1173 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1182 * Get session parameters from Director -- this is for a Restore command
1184 static int session_cmd(JCR *jcr)
1186 BSOCK *dir = jcr->dir_bsock;
1188 Dmsg1(100, "SessionCmd: %s", dir->msg);
1189 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1190 &jcr->VolSessionId, &jcr->VolSessionTime,
1191 &jcr->StartFile, &jcr->EndFile,
1192 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1193 pm_strcpy(jcr->errmsg, dir->msg);
1194 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1198 return bnet_fsend(dir, OKsession);
1202 * Get address of storage daemon from Director
1205 static int storage_cmd(JCR *jcr)
1207 int stored_port; /* storage daemon port */
1208 int enable_ssl; /* enable ssl to sd */
1209 BSOCK *dir = jcr->dir_bsock;
1210 BSOCK *sd; /* storage daemon bsock */
1212 Dmsg1(100, "StorageCmd: %s", dir->msg);
1213 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1214 pm_strcpy(jcr->errmsg, dir->msg);
1215 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1218 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1219 /* Open command communications with Storage daemon */
1220 /* Try to connect for 1 hour at 10 second intervals */
1221 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1222 jcr->stored_addr, NULL, stored_port, 1);
1224 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1225 jcr->stored_addr, stored_port);
1226 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1227 jcr->stored_addr, stored_port);
1230 Dmsg0(110, "Connection OK to SD.\n");
1232 jcr->store_bsock = sd;
1234 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1235 if (!authenticate_storagedaemon(jcr)) {
1236 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1239 Dmsg0(110, "Authenticated with SD.\n");
1241 /* Send OK to Director */
1242 return bnet_fsend(dir, OKstore);
1247 * Do a backup. For now, we handle only Full and Incremental.
1249 static int backup_cmd(JCR *jcr)
1251 BSOCK *dir = jcr->dir_bsock;
1252 BSOCK *sd = jcr->store_bsock;
1255 char ed1[50], ed2[50];
1257 #if defined(WIN32_VSS)
1258 // capture state here, if client is backed up by multiple directors
1259 // and one enables vss and the other does not then enable_vss can change
1260 // between here and where its evaluated after the job completes.
1261 bool bDoVSS = false;
1263 bDoVSS = g_pVSSClient && enable_vss;
1265 /* Run only one at a time */
1269 set_jcr_job_status(jcr, JS_Blocked);
1270 jcr->JobType = JT_BACKUP;
1271 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1274 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1278 bnet_fsend(dir, OKbackup);
1279 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1282 * Send Append Open Session to Storage daemon
1284 bnet_fsend(sd, append_open);
1285 Dmsg1(110, ">stored: %s", sd->msg);
1287 * Expect to receive back the Ticket number
1289 if (bget_msg(sd) >= 0) {
1290 Dmsg1(110, "<stored: %s", sd->msg);
1291 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1292 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1295 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1297 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1302 * Send Append data command to Storage daemon
1304 bnet_fsend(sd, append_data, jcr->Ticket);
1305 Dmsg1(110, ">stored: %s", sd->msg);
1308 * Expect to get OK data
1310 Dmsg1(110, "<stored: %s", sd->msg);
1311 if (!response(jcr, sd, OK_data, "Append Data")) {
1315 generate_daemon_event(jcr, "JobStart");
1317 #if defined(WIN32_VSS)
1318 /* START VSS ON WIN 32 */
1320 if (g_pVSSClient->InitializeForBackup()) {
1321 /* tell vss which drives to snapshot */
1322 char szWinDriveLetters[27];
1323 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1324 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1325 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1326 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1329 /* tell user if snapshot creation of a specific drive failed */
1331 for (i=0; i < strlen(szWinDriveLetters); i++) {
1332 if (islower(szWinDriveLetters[i])) {
1333 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1337 /* inform user about writer states */
1338 for (i=0; i<g_pVSSClient->GetWriterCount(); i++)
1339 if (g_pVSSClient->GetWriterState(i) < 1) {
1340 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1345 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1349 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1355 * Send Files to Storage daemon
1357 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1358 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1359 set_jcr_job_status(jcr, JS_ErrorTerminated);
1360 bnet_suppress_error_messages(sd, 1);
1361 bget_msg(sd); /* Read final response from append_data */
1362 Dmsg0(110, "Error in blast_data.\n");
1363 /* run shortly after end of data transmission */
1364 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1367 set_jcr_job_status(jcr, JS_Terminated);
1369 /* run shortly after end of data transmission */
1370 run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1372 if (jcr->JobStatus != JS_Terminated) {
1373 bnet_suppress_error_messages(sd, 1);
1374 goto cleanup; /* bail out now */
1377 * Expect to get response to append_data from Storage daemon
1379 if (!response(jcr, sd, OK_append, "Append Data")) {
1380 set_jcr_job_status(jcr, JS_ErrorTerminated);
1385 * Send Append End Data to Storage daemon
1387 bnet_fsend(sd, append_end, jcr->Ticket);
1389 if (!response(jcr, sd, OK_end, "Append End")) {
1390 set_jcr_job_status(jcr, JS_ErrorTerminated);
1395 * Send Append Close to Storage daemon
1397 bnet_fsend(sd, append_close, jcr->Ticket);
1398 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1399 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1401 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1405 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1408 if (SDJobStatus != JS_Terminated) {
1409 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1415 #if defined(WIN32_VSS)
1416 /* STOP VSS ON WIN 32 */
1417 /* tell vss to close the backup session */
1419 if (g_pVSSClient->CloseBackup()) {
1420 /* inform user about writer states */
1421 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1422 int msg_type = M_INFO;
1423 if (g_pVSSClient->GetWriterState(i) < 1) {
1424 msg_type = M_WARNING;
1427 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1434 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1435 edit_uint64(jcr->ReadBytes, ed1),
1436 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1437 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1439 return 0; /* return and stop command loop */
1443 * Do a Verify for Director
1446 static int verify_cmd(JCR *jcr)
1448 BSOCK *dir = jcr->dir_bsock;
1449 BSOCK *sd = jcr->store_bsock;
1450 char level[100], ed1[50], ed2[50];
1452 jcr->JobType = JT_VERIFY;
1453 if (sscanf(dir->msg, verifycmd, level) != 1) {
1454 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1458 if (strcasecmp(level, "init") == 0) {
1459 jcr->JobLevel = L_VERIFY_INIT;
1460 } else if (strcasecmp(level, "catalog") == 0){
1461 jcr->JobLevel = L_VERIFY_CATALOG;
1462 } else if (strcasecmp(level, "volume") == 0){
1463 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1464 } else if (strcasecmp(level, "data") == 0){
1465 jcr->JobLevel = L_VERIFY_DATA;
1466 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1467 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1469 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1473 bnet_fsend(dir, OKverify);
1475 generate_daemon_event(jcr, "JobStart");
1477 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1479 switch (jcr->JobLevel) {
1481 case L_VERIFY_CATALOG:
1484 case L_VERIFY_VOLUME_TO_CATALOG:
1485 if (!open_sd_read_session(jcr)) {
1488 start_dir_heartbeat(jcr);
1489 do_verify_volume(jcr);
1490 stop_dir_heartbeat(jcr);
1492 * Send Close session command to Storage daemon
1494 bnet_fsend(sd, read_close, jcr->Ticket);
1495 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1497 /* ****FIXME**** check response */
1498 bget_msg(sd); /* get OK */
1500 /* Inform Storage daemon that we are done */
1501 bnet_sig(sd, BNET_TERMINATE);
1504 case L_VERIFY_DISK_TO_CATALOG:
1508 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1512 bnet_sig(dir, BNET_EOD);
1514 /* Send termination status back to Dir */
1515 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1516 edit_uint64(jcr->ReadBytes, ed1),
1517 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1519 /* Inform Director that we are done */
1520 bnet_sig(dir, BNET_TERMINATE);
1521 return 0; /* return and terminate command loop */
1525 * Do a Restore for Director
1528 static int restore_cmd(JCR *jcr)
1530 BSOCK *dir = jcr->dir_bsock;
1531 BSOCK *sd = jcr->store_bsock;
1535 char ed1[50], ed2[50];
1538 * Scan WHERE (base directory for restore) from command
1540 Dmsg0(150, "restore command\n");
1541 /* Pickup where string */
1542 where = get_memory(dir->msglen+1);
1545 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1546 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1547 pm_strcpy(jcr->errmsg, dir->msg);
1548 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1553 /* Turn / into nothing */
1554 if (where[0] == '/' && where[1] == 0) {
1558 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1559 unbash_spaces(where);
1560 jcr->where = bstrdup(where);
1561 free_pool_memory(where);
1562 jcr->replace = replace;
1563 jcr->prefix_links = prefix_links;
1565 bnet_fsend(dir, OKrestore);
1566 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1568 jcr->JobType = JT_RESTORE;
1570 set_jcr_job_status(jcr, JS_Blocked);
1572 if (!open_sd_read_session(jcr)) {
1573 set_jcr_job_status(jcr, JS_ErrorTerminated);
1577 set_jcr_job_status(jcr, JS_Running);
1580 * Do restore of files and data
1582 start_dir_heartbeat(jcr);
1583 generate_daemon_event(jcr, "JobStart");
1585 stop_dir_heartbeat(jcr);
1587 set_jcr_job_status(jcr, JS_Terminated);
1588 if (jcr->JobStatus != JS_Terminated) {
1589 bnet_suppress_error_messages(sd, 1);
1593 * Send Close session command to Storage daemon
1595 bnet_fsend(sd, read_close, jcr->Ticket);
1596 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1598 bget_msg(sd); /* get OK */
1600 /* Inform Storage daemon that we are done */
1601 bnet_sig(sd, BNET_TERMINATE);
1606 set_jcr_job_status(jcr, JS_ErrorTerminated);
1608 /* Send termination status back to Dir */
1609 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1610 edit_uint64(jcr->ReadBytes, ed1),
1611 edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1613 /* Inform Director that we are done */
1614 bnet_sig(dir, BNET_TERMINATE);
1616 Dmsg0(130, "Done in job.c\n");
1617 return 0; /* return and terminate command loop */
1620 static int open_sd_read_session(JCR *jcr)
1622 BSOCK *sd = jcr->store_bsock;
1625 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1628 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1629 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1630 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1632 * Open Read Session with Storage daemon
1634 bnet_fsend(sd, read_open, "DummyVolume",
1635 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1636 jcr->StartBlock, jcr->EndBlock);
1637 Dmsg1(110, ">stored: %s", sd->msg);
1642 if (bget_msg(sd) >= 0) {
1643 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1644 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1645 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1648 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1650 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1654 if (!send_bootstrap_file(jcr)) {
1659 * Start read of data with Storage daemon
1661 bnet_fsend(sd, read_data, jcr->Ticket);
1662 Dmsg1(110, ">stored: %s", sd->msg);
1667 if (!response(jcr, sd, OK_data, "Read Data")) {
1674 * Destroy the Job Control Record and associated
1675 * resources (sockets).
1677 static void filed_free_jcr(JCR *jcr)
1679 if (jcr->store_bsock) {
1680 bnet_close(jcr->store_bsock);
1682 free_bootstrap(jcr);
1683 if (jcr->last_fname) {
1684 free_pool_memory(jcr->last_fname);
1686 free_runscripts(jcr->RunScripts);
1687 delete jcr->RunScripts;
1693 * Get response from Storage daemon to a command we
1694 * sent. Check that the response is OK.
1696 * Returns: 0 on failure
1699 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1704 if (bget_msg(sd) > 0) {
1705 Dmsg0(110, sd->msg);
1706 if (strcmp(sd->msg, resp) == 0) {
1710 if (job_canceled(jcr)) {
1711 return 0; /* if canceled avoid useless error messages */
1713 if (is_bnet_error(sd)) {
1714 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1715 cmd, bnet_strerror(sd));
1717 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1718 cmd, resp, sd->msg);
1723 static int send_bootstrap_file(JCR *jcr)
1727 BSOCK *sd = jcr->store_bsock;
1728 const char *bootstrap = "bootstrap\n";
1731 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1732 if (!jcr->RestoreBootstrap) {
1735 bs = fopen(jcr->RestoreBootstrap, "rb");
1738 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1739 jcr->RestoreBootstrap, be.strerror());
1740 set_jcr_job_status(jcr, JS_ErrorTerminated);
1743 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1745 while (fgets(buf, sizeof(buf), bs)) {
1746 sd->msglen = Mmsg(sd->msg, "%s", buf);
1749 bnet_sig(sd, BNET_EOD);
1751 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1752 set_jcr_job_status(jcr, JS_ErrorTerminated);
1758 free_bootstrap(jcr);