2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula File Daemon Job processing
31 * Kern Sibbald, October MM
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
182 * Concerning ClientRunBefore/After, the sequence of events
183 * is rather critical. If they are not done in the right
184 * order one can easily get FD->SD timeouts if the script
187 * The current sequence of events is:
188 * 1. Dir starts job with FD
189 * 2. Dir connects to SD
190 * 3. Dir connects to FD
191 * 4. FD connects to SD
192 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
193 * 6. Dir sends include/exclude
194 * 7. FD sends data to SD
195 * 8. SD/FD disconnects while SD despools data and attributes (optionnal)
196 * 9. FD runs ClientRunAfterJob
199 void *handle_client_request(void *dirp)
204 BSOCK *dir = (BSOCK *)dirp;
206 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
207 jcr->dir_bsock = dir;
208 jcr->ff = init_find_files();
209 jcr->start_time = time(NULL);
210 jcr->RunScripts = New(alist(10, not_owned_by_alist));
211 jcr->last_fname = get_pool_memory(PM_FNAME);
212 jcr->last_fname[0] = 0;
213 jcr->client_name = get_memory(strlen(my_name) + 1);
214 pm_strcpy(jcr->client_name, my_name);
215 jcr->pki_sign = me->pki_sign;
216 jcr->pki_encrypt = me->pki_encrypt;
217 jcr->pki_keypair = me->pki_keypair;
218 jcr->pki_signers = me->pki_signers;
219 jcr->pki_recipients = me->pki_recipients;
221 enable_backup_privileges(NULL, 1 /* ignore_errors */);
223 /**********FIXME******* add command handler error code */
225 for (quit=false; !quit;) {
228 if (bnet_recv(dir) < 0) {
229 break; /* connection terminated */
231 dir->msg[dir->msglen] = 0;
232 Dmsg1(100, "<dird: %s", dir->msg);
234 for (i=0; cmds[i].cmd; i++) {
235 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
236 found = true; /* indicate command found */
237 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
238 bnet_fsend(dir, no_auth);
239 bnet_sig(dir, BNET_EOD);
242 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
243 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
244 bnet_fsend(dir, invalid_cmd);
245 bnet_sig(dir, BNET_EOD);
248 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
249 if (!cmds[i].func(jcr)) { /* do command */
250 quit = true; /* error or fully terminated, get out */
251 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
256 if (!found) { /* command not found */
257 bnet_fsend(dir, errmsg);
263 /* Inform Storage daemon that we are done */
264 if (jcr->store_bsock) {
265 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
268 /* Run the after job */
269 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
271 generate_daemon_event(jcr, "JobEnd");
273 dequeue_messages(jcr); /* send any queued messages */
275 /* Inform Director that we are done */
276 bnet_sig(dir, BNET_TERMINATE);
278 /* Clean up fileset */
279 FF_PKT *ff = jcr->ff;
280 findFILESET *fileset = ff->fileset;
283 /* Delete FileSet Include lists */
284 for (i=0; i<fileset->include_list.size(); i++) {
285 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
286 for (j=0; j<incexe->opts_list.size(); j++) {
287 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
288 for (k=0; k<fo->regex.size(); k++) {
289 regfree((regex_t *)fo->regex.get(k));
292 fo->regexdir.destroy();
293 fo->regexfile.destroy();
295 fo->wilddir.destroy();
296 fo->wildfile.destroy();
297 fo->wildbase.destroy();
299 fo->fstype.destroy();
300 fo->drivetype.destroy();
308 incexe->opts_list.destroy();
309 incexe->name_list.destroy();
311 fileset->include_list.destroy();
313 /* Delete FileSet Exclude lists */
314 for (i=0; i<fileset->exclude_list.size(); i++) {
315 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
316 for (j=0; j<incexe->opts_list.size(); j++) {
317 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
319 fo->regexdir.destroy();
320 fo->regexfile.destroy();
322 fo->wilddir.destroy();
323 fo->wildfile.destroy();
324 fo->wildbase.destroy();
326 fo->fstype.destroy();
327 fo->drivetype.destroy();
329 incexe->opts_list.destroy();
330 incexe->name_list.destroy();
332 fileset->exclude_list.destroy();
336 Dmsg0(100, "Calling term_find_files\n");
337 term_find_files(jcr->ff);
339 Dmsg0(100, "Done with term_find_files\n");
340 free_jcr(jcr); /* destroy JCR record */
341 Dmsg0(100, "Done with free_jcr\n");
346 * Hello from Director he must identify himself and provide his
349 static int hello_cmd(JCR *jcr)
351 Dmsg0(120, "Calling Authenticate\n");
352 if (!authenticate_director(jcr)) {
355 Dmsg0(120, "OK Authenticate\n");
356 jcr->authenticated = true;
363 static int cancel_cmd(JCR *jcr)
365 BSOCK *dir = jcr->dir_bsock;
366 char Job[MAX_NAME_LENGTH];
369 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
370 if (!(cjcr=get_jcr_by_full_name(Job))) {
371 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
373 if (cjcr->store_bsock) {
374 cjcr->store_bsock->timed_out = 1;
375 cjcr->store_bsock->terminated = 1;
376 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
378 set_jcr_job_status(cjcr, JS_Canceled);
380 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
383 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
385 bnet_sig(dir, BNET_EOD);
391 * Set debug level as requested by the Director
394 static int setdebug_cmd(JCR *jcr)
396 BSOCK *dir = jcr->dir_bsock;
397 int level, trace_flag;
399 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
400 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
401 pm_strcpy(jcr->errmsg, dir->msg);
402 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
406 set_trace(trace_flag);
407 return bnet_fsend(dir, OKsetdebug, level);
411 static int estimate_cmd(JCR *jcr)
413 BSOCK *dir = jcr->dir_bsock;
416 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
417 pm_strcpy(jcr->errmsg, dir->msg);
418 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
419 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
423 bnet_fsend(dir, OKest, jcr->num_files_examined,
424 edit_uint64_with_commas(jcr->JobBytes, ed2));
425 bnet_sig(dir, BNET_EOD);
430 * Get JobId and Storage Daemon Authorization key from Director
432 static int job_cmd(JCR *jcr)
434 BSOCK *dir = jcr->dir_bsock;
435 POOLMEM *sd_auth_key;
437 sd_auth_key = get_memory(dir->msglen);
438 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
439 &jcr->VolSessionId, &jcr->VolSessionTime,
441 pm_strcpy(jcr->errmsg, dir->msg);
442 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
443 bnet_fsend(dir, BADjob);
444 free_pool_memory(sd_auth_key);
447 jcr->sd_auth_key = bstrdup(sd_auth_key);
448 free_pool_memory(sd_auth_key);
449 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
450 return bnet_fsend(dir, OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
453 static int runbefore_cmd(JCR *jcr)
456 BSOCK *dir = jcr->dir_bsock;
457 POOLMEM *cmd = get_memory(dir->msglen+1);
460 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
461 if (sscanf(dir->msg, runbefore, cmd) != 1) {
462 pm_strcpy(jcr->errmsg, dir->msg);
463 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
464 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
470 /* Run the command now */
471 script = new_runscript();
472 script->set_command(cmd);
473 script->when = SCRIPT_Before;
474 ok = script->run(jcr, "ClientRunBeforeJob");
475 free_runscript(script);
479 bnet_fsend(dir, OKRunBefore);
482 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
487 static int runbeforenow_cmd(JCR *jcr)
489 BSOCK *dir = jcr->dir_bsock;
491 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
492 if (job_canceled(jcr)) {
493 return bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
495 return bnet_fsend(dir, OKRunBeforeNow);
499 static int runafter_cmd(JCR *jcr)
501 BSOCK *dir = jcr->dir_bsock;
502 POOLMEM *msg = get_memory(dir->msglen+1);
505 Dmsg1(100, "runafter_cmd: %s", dir->msg);
506 if (sscanf(dir->msg, runafter, msg) != 1) {
507 pm_strcpy(jcr->errmsg, dir->msg);
508 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
509 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
515 cmd = new_runscript();
516 cmd->set_command(msg);
517 cmd->on_success = true;
518 cmd->on_failure = false;
519 cmd->when = SCRIPT_After;
521 jcr->RunScripts->append(cmd);
523 free_pool_memory(msg);
524 return bnet_fsend(dir, OKRunAfter);
527 static int runscript_cmd(JCR *jcr)
529 BSOCK *dir = jcr->dir_bsock;
530 POOLMEM *msg = get_memory(dir->msglen+1);
532 RUNSCRIPT *cmd = new_runscript() ;
534 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
535 if (sscanf(dir->msg, runscript, &cmd->on_success,
537 &cmd->abort_on_error,
540 pm_strcpy(jcr->errmsg, dir->msg);
541 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
542 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
549 cmd->set_command(msg);
551 jcr->RunScripts->append(cmd);
553 free_pool_memory(msg);
554 return bnet_fsend(dir, OKRunScript);
558 static bool init_fileset(JCR *jcr)
561 findFILESET *fileset;
570 fileset = (findFILESET *)malloc(sizeof(findFILESET));
571 memset(fileset, 0, sizeof(findFILESET));
572 ff->fileset = fileset;
573 fileset->state = state_none;
574 fileset->include_list.init(1, true);
575 fileset->exclude_list.init(1, true);
579 static findFOPTS *start_options(FF_PKT *ff)
581 int state = ff->fileset->state;
582 findINCEXE *incexe = ff->fileset->incexe;
584 if (state != state_options) {
585 ff->fileset->state = state_options;
586 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
587 memset(fo, 0, sizeof(findFOPTS));
588 fo->regex.init(1, true);
589 fo->regexdir.init(1, true);
590 fo->regexfile.init(1, true);
591 fo->wild.init(1, true);
592 fo->wilddir.init(1, true);
593 fo->wildfile.init(1, true);
594 fo->wildbase.init(1, true);
595 fo->base.init(1, true);
596 fo->fstype.init(1, true);
597 fo->drivetype.init(1, true);
598 incexe->current_opts = fo;
599 incexe->opts_list.append(fo);
601 return incexe->current_opts;
606 * Add fname to include/exclude fileset list. First check for
607 * | and < and if necessary perform command.
609 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
623 p++; /* skip over | */
624 fn = get_pool_memory(PM_FNAME);
625 fn = edit_job_codes(jcr, fn, p, "");
626 bpipe = open_bpipe(fn, 0, "r");
629 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
631 free_pool_memory(fn);
634 free_pool_memory(fn);
635 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
636 strip_trailing_junk(buf);
637 fileset->incexe->name_list.append(new_dlistString(buf));
639 if ((stat=close_bpipe(bpipe)) != 0) {
641 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
642 p, be.code(stat), be.strerror(stat));
647 Dmsg0(100, "Doing < include on client.\n");
648 p++; /* skip over < */
649 if ((ffd = fopen(p, "rb")) == NULL) {
651 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
655 while (fgets(buf, sizeof(buf), ffd)) {
656 strip_trailing_junk(buf);
657 Dmsg1(100, "%s\n", buf);
658 fileset->incexe->name_list.append(new_dlistString(buf));
663 fileset->incexe->name_list.append(new_dlistString(fname));
669 static void add_fileset(JCR *jcr, const char *item)
671 FF_PKT *ff = jcr->ff;
672 findFILESET *fileset = ff->fileset;
673 int state = fileset->state;
674 findFOPTS *current_opts;
676 /* Get code, optional subcode, and position item past the dividing space */
677 Dmsg1(100, "%s\n", item);
682 int subcode = ' '; /* A space is always a valid subcode */
683 if (item[0] != '\0' && item[0] != ' ') {
691 /* Skip all lines we receive after an error */
692 if (state == state_error) {
693 Dmsg0(100, "State=error return\n");
698 * The switch tests the code for validity.
699 * The subcode is always good if it is a space, otherwise we must confirm.
700 * We set state to state_error first assuming the subcode is invalid,
701 * requiring state to be set in cases below that handle subcodes.
703 if (subcode != ' ') {
705 Dmsg0(100, "Set state=error\n");
710 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
711 memset(fileset->incexe, 0, sizeof(findINCEXE));
712 fileset->incexe->opts_list.init(1, true);
713 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
714 fileset->include_list.append(fileset->incexe);
718 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
719 memset(fileset->incexe, 0, sizeof(findINCEXE));
720 fileset->incexe->opts_list.init(1, true);
721 fileset->incexe->name_list.init();
722 fileset->exclude_list.append(fileset->incexe);
728 /* File item to either include/include list */
729 state = state_include;
730 add_file_to_fileset(jcr, item, fileset);
733 current_opts = start_options(ff);
737 preg = (regex_t *)malloc(sizeof(regex_t));
738 if (current_opts->flags & FO_IGNORECASE) {
739 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
741 rc = regcomp(preg, item, REG_EXTENDED);
744 regerror(rc, preg, prbuf, sizeof(prbuf));
747 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
751 state = state_options;
752 if (subcode == ' ') {
753 current_opts->regex.append(preg);
754 } else if (subcode == 'D') {
755 current_opts->regexdir.append(preg);
756 } else if (subcode == 'F') {
757 current_opts->regexfile.append(preg);
763 current_opts = start_options(ff);
764 current_opts->base.append(bstrdup(item));
765 state = state_options;
768 current_opts = start_options(ff);
769 state = state_options;
770 if (subcode == ' ') {
771 current_opts->fstype.append(bstrdup(item));
772 } else if (subcode == 'D') {
773 current_opts->drivetype.append(bstrdup(item));
779 current_opts = start_options(ff);
780 state = state_options;
781 if (subcode == ' ') {
782 current_opts->wild.append(bstrdup(item));
783 } else if (subcode == 'D') {
784 current_opts->wilddir.append(bstrdup(item));
785 } else if (subcode == 'F') {
786 current_opts->wildfile.append(bstrdup(item));
787 } else if (subcode == 'B') {
788 current_opts->wildbase.append(bstrdup(item));
794 current_opts = start_options(ff);
795 set_options(current_opts, item);
796 state = state_options;
799 current_opts = start_options(ff);
800 current_opts->reader = bstrdup(item);
801 state = state_options;
804 current_opts = start_options(ff);
805 current_opts->writer = bstrdup(item);
806 state = state_options;
809 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
813 ff->fileset->state = state;
816 static bool term_fileset(JCR *jcr)
818 FF_PKT *ff = jcr->ff;
821 findFILESET *fileset = ff->fileset;
824 for (i=0; i<fileset->include_list.size(); i++) {
825 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
827 for (j=0; j<incexe->opts_list.size(); j++) {
828 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
829 for (k=0; k<fo->regex.size(); k++) {
830 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
832 for (k=0; k<fo->regexdir.size(); k++) {
833 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
835 for (k=0; k<fo->regexfile.size(); k++) {
836 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
838 for (k=0; k<fo->wild.size(); k++) {
839 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
841 for (k=0; k<fo->wilddir.size(); k++) {
842 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
844 for (k=0; k<fo->wildfile.size(); k++) {
845 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
847 for (k=0; k<fo->wildbase.size(); k++) {
848 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
850 for (k=0; k<fo->base.size(); k++) {
851 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
853 for (k=0; k<fo->fstype.size(); k++) {
854 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
856 for (k=0; k<fo->drivetype.size(); k++) {
857 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
860 Dmsg1(400, "D %s\n", fo->reader);
863 Dmsg1(400, "T %s\n", fo->writer);
867 foreach_dlist(node, &incexe->name_list) {
868 Dmsg1(400, "F %s\n", node->c_str());
871 for (i=0; i<fileset->exclude_list.size(); i++) {
872 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
874 for (j=0; j<incexe->opts_list.size(); j++) {
875 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
876 for (k=0; k<fo->regex.size(); k++) {
877 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
879 for (k=0; k<fo->regexdir.size(); k++) {
880 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
882 for (k=0; k<fo->regexfile.size(); k++) {
883 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
885 for (k=0; k<fo->wild.size(); k++) {
886 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
888 for (k=0; k<fo->wilddir.size(); k++) {
889 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
891 for (k=0; k<fo->wildfile.size(); k++) {
892 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
894 for (k=0; k<fo->wildbase.size(); k++) {
895 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
897 for (k=0; k<fo->base.size(); k++) {
898 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
900 for (k=0; k<fo->fstype.size(); k++) {
901 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
903 for (k=0; k<fo->drivetype.size(); k++) {
904 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
908 foreach_dlist(node, incexe->name_list) {
909 Dmsg1(400, "F %s\n", node->c_str());
913 return ff->fileset->state != state_error;
918 * As an optimization, we should do this during
919 * "compile" time in filed/job.c, and keep only a bit mask
920 * and the Verify options.
922 static void set_options(findFOPTS *fo, const char *opts)
927 for (p=opts; *p; p++) {
929 case 'a': /* alway replace */
930 case '0': /* no option */
933 fo->flags |= FO_EXCLUDE;
936 fo->flags |= FO_MULTIFS;
938 case 'h': /* no recursion */
939 fo->flags |= FO_NO_RECURSION;
941 case 'H': /* no hard link handling */
942 fo->flags |= FO_NO_HARDLINK;
945 fo->flags |= FO_IGNORECASE;
951 fo->flags |= FO_NOREPLACE;
953 case 'p': /* use portable data format */
954 fo->flags |= FO_PORTABLE;
956 case 'R': /* Resource forks and Finder Info */
957 fo->flags |= FO_HFSPLUS;
958 case 'r': /* read fifo */
959 fo->flags |= FO_READFIFO;
964 fo->flags |= FO_SHA1;
969 fo->flags |= FO_SHA256;
973 fo->flags |= FO_SHA512;
979 * If 2 or 3 is seen here, SHA2 is not configured, so
980 * eat the option, and drop back to SHA-1.
982 if (p[1] == '2' || p[1] == '3') {
985 fo->flags |= FO_SHA1;
990 fo->flags |= FO_SPARSE;
993 fo->flags |= FO_MTIMEONLY;
996 fo->flags |= FO_KEEPATIME;
1001 case 'V': /* verify options */
1002 /* Copy Verify Options */
1003 for (j=0; *p && *p != ':'; p++) {
1004 fo->VerifyOpts[j] = *p;
1005 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1009 fo->VerifyOpts[j] = 0;
1012 fo->flags |= FO_IF_NEWER;
1015 fo->flags |= FO_ENHANCEDWILD;
1017 case 'Z': /* gzip compression */
1018 fo->flags |= FO_GZIP;
1019 fo->GZIP_level = *++p - '0';
1022 fo->flags |= FO_NOATIME;
1025 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1033 * Director is passing his Fileset
1035 static int fileset_cmd(JCR *jcr)
1037 BSOCK *dir = jcr->dir_bsock;
1039 #if defined(WIN32_VSS)
1042 sscanf(dir->msg, "fileset vss=%d", &vss);
1046 if (!init_fileset(jcr)) {
1049 while (bnet_recv(dir) >= 0) {
1050 strip_trailing_junk(dir->msg);
1051 Dmsg1(500, "Fileset: %s\n", dir->msg);
1052 add_fileset(jcr, dir->msg);
1054 if (!term_fileset(jcr)) {
1057 return bnet_fsend(dir, OKinc);
1060 static void free_bootstrap(JCR *jcr)
1062 if (jcr->RestoreBootstrap) {
1063 unlink(jcr->RestoreBootstrap);
1064 free_pool_memory(jcr->RestoreBootstrap);
1065 jcr->RestoreBootstrap = NULL;
1070 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1071 static uint32_t bsr_uniq = 0;
1074 * The Director sends us the bootstrap file, which
1075 * we will in turn pass to the SD.
1077 static int bootstrap_cmd(JCR *jcr)
1079 BSOCK *dir = jcr->dir_bsock;
1080 POOLMEM *fname = get_pool_memory(PM_FNAME);
1083 free_bootstrap(jcr);
1086 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1087 jcr->Job, bsr_uniq);
1089 Dmsg1(400, "bootstrap=%s\n", fname);
1090 jcr->RestoreBootstrap = fname;
1091 bs = fopen(fname, "a+b"); /* create file */
1094 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1095 jcr->RestoreBootstrap, be.strerror());
1097 * Suck up what he is sending to us so that he will then
1098 * read our error message.
1100 while (bnet_recv(dir) >= 0)
1102 free_bootstrap(jcr);
1103 set_jcr_job_status(jcr, JS_ErrorTerminated);
1107 while (bnet_recv(dir) >= 0) {
1108 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1109 fputs(dir->msg, bs);
1113 * Note, do not free the bootstrap yet -- it needs to be
1116 return bnet_fsend(dir, OKbootstrap);
1121 * Get backup level from Director
1124 static int level_cmd(JCR *jcr)
1126 BSOCK *dir = jcr->dir_bsock;
1127 POOLMEM *level, *buf = NULL;
1130 level = get_memory(dir->msglen+1);
1131 Dmsg1(110, "level_cmd: %s", dir->msg);
1132 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1135 /* Base backup requested? */
1136 if (strcmp(level, "base") == 0) {
1137 jcr->JobLevel = L_BASE;
1138 /* Full backup requested? */
1139 } else if (strcmp(level, "full") == 0) {
1140 jcr->JobLevel = L_FULL;
1141 } else if (strcmp(level, "differential") == 0) {
1142 jcr->JobLevel = L_DIFFERENTIAL;
1145 } else if (strcmp(level, "incremental") == 0) {
1146 jcr->JobLevel = L_INCREMENTAL;
1150 * We get his UTC since time, then sync the clocks and correct it
1151 * to agree with our clock.
1153 } else if (strcmp(level, "since_utime") == 0) {
1154 buf = get_memory(dir->msglen+1);
1155 utime_t since_time, adj;
1156 btime_t his_time, bt_start, rt=0, bt_adj=0;
1157 if (jcr->JobLevel == L_NONE) {
1158 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1160 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1161 buf, &mtime_only) != 2) {
1164 since_time = str_to_uint64(buf); /* this is the since time */
1165 Dmsg1(100, "since_time=%d\n", (int)since_time);
1166 char ed1[50], ed2[50];
1168 * Sync clocks by polling him for the time. We take
1169 * 10 samples of his time throwing out the first two.
1171 for (int i=0; i<10; i++) {
1172 bt_start = get_current_btime();
1173 bnet_sig(dir, BNET_BTIME); /* poll for time */
1174 if (bnet_recv(dir) <= 0) { /* get response */
1177 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1180 if (i < 2) { /* toss first two results */
1183 his_time = str_to_uint64(buf);
1184 rt = get_current_btime() - bt_start; /* compute round trip time */
1185 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1186 edit_uint64(bt_start, ed2));
1187 bt_adj += bt_start - his_time - rt/2;
1188 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1191 bt_adj = bt_adj / 8; /* compute average time */
1192 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1193 adj = btime_to_utime(bt_adj);
1194 since_time += adj; /* adjust for clock difference */
1196 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1198 bnet_sig(dir, BNET_EOD);
1200 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1201 jcr->incremental = 1; /* set incremental or decremental backup */
1202 jcr->mtime = (time_t)since_time; /* set since time */
1204 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1212 return bnet_fsend(dir, OKlevel);
1215 pm_strcpy(jcr->errmsg, dir->msg);
1216 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1225 * Get session parameters from Director -- this is for a Restore command
1227 static int session_cmd(JCR *jcr)
1229 BSOCK *dir = jcr->dir_bsock;
1231 Dmsg1(100, "SessionCmd: %s", dir->msg);
1232 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1233 &jcr->VolSessionId, &jcr->VolSessionTime,
1234 &jcr->StartFile, &jcr->EndFile,
1235 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1236 pm_strcpy(jcr->errmsg, dir->msg);
1237 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1241 return bnet_fsend(dir, OKsession);
1245 * Get address of storage daemon from Director
1248 static int storage_cmd(JCR *jcr)
1250 int stored_port; /* storage daemon port */
1251 int enable_ssl; /* enable ssl to sd */
1252 BSOCK *dir = jcr->dir_bsock;
1253 BSOCK *sd; /* storage daemon bsock */
1255 Dmsg1(100, "StorageCmd: %s", dir->msg);
1256 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1257 pm_strcpy(jcr->errmsg, dir->msg);
1258 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1261 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1262 /* Open command communications with Storage daemon */
1263 /* Try to connect for 1 hour at 10 second intervals */
1264 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1265 jcr->stored_addr, NULL, stored_port, 1);
1267 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1268 jcr->stored_addr, stored_port);
1269 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1270 jcr->stored_addr, stored_port);
1273 Dmsg0(110, "Connection OK to SD.\n");
1275 jcr->store_bsock = sd;
1277 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1278 if (!authenticate_storagedaemon(jcr)) {
1279 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1282 Dmsg0(110, "Authenticated with SD.\n");
1284 /* Send OK to Director */
1285 return bnet_fsend(dir, OKstore);
1292 static int backup_cmd(JCR *jcr)
1294 BSOCK *dir = jcr->dir_bsock;
1295 BSOCK *sd = jcr->store_bsock;
1298 char ed1[50], ed2[50];
1299 bool bDoVSS = false;
1301 #if defined(WIN32_VSS)
1302 // capture state here, if client is backed up by multiple directors
1303 // and one enables vss and the other does not then enable_vss can change
1304 // between here and where its evaluated after the job completes.
1305 bDoVSS = g_pVSSClient && enable_vss;
1307 /* Run only one at a time */
1312 set_jcr_job_status(jcr, JS_Blocked);
1313 jcr->JobType = JT_BACKUP;
1314 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1317 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1321 bnet_fsend(dir, OKbackup);
1322 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1325 * Send Append Open Session to Storage daemon
1327 bnet_fsend(sd, append_open);
1328 Dmsg1(110, ">stored: %s", sd->msg);
1330 * Expect to receive back the Ticket number
1332 if (bget_msg(sd) >= 0) {
1333 Dmsg1(110, "<stored: %s", sd->msg);
1334 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1335 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1338 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1340 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1345 * Send Append data command to Storage daemon
1347 bnet_fsend(sd, append_data, jcr->Ticket);
1348 Dmsg1(110, ">stored: %s", sd->msg);
1351 * Expect to get OK data
1353 Dmsg1(110, "<stored: %s", sd->msg);
1354 if (!response(jcr, sd, OK_data, "Append Data")) {
1358 generate_daemon_event(jcr, "JobStart");
1360 #if defined(WIN32_VSS)
1361 /* START VSS ON WIN 32 */
1363 if (g_pVSSClient->InitializeForBackup()) {
1364 /* tell vss which drives to snapshot */
1365 char szWinDriveLetters[27];
1366 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1367 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1368 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1369 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1372 /* tell user if snapshot creation of a specific drive failed */
1374 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1375 if (islower(szWinDriveLetters[i])) {
1376 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1380 /* inform user about writer states */
1381 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1382 if (g_pVSSClient->GetWriterState(i) < 1) {
1383 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1388 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1392 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1398 * Send Files to Storage daemon
1400 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1401 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1402 set_jcr_job_status(jcr, JS_ErrorTerminated);
1403 bnet_suppress_error_messages(sd, 1);
1404 bget_msg(sd); /* Read final response from append_data */
1405 Dmsg0(110, "Error in blast_data.\n");
1407 set_jcr_job_status(jcr, JS_Terminated);
1409 if (jcr->JobStatus != JS_Terminated) {
1410 bnet_suppress_error_messages(sd, 1);
1411 goto cleanup; /* bail out now */
1414 * Expect to get response to append_data from Storage daemon
1416 if (!response(jcr, sd, OK_append, "Append Data")) {
1417 set_jcr_job_status(jcr, JS_ErrorTerminated);
1422 * Send Append End Data to Storage daemon
1424 bnet_fsend(sd, append_end, jcr->Ticket);
1426 if (!response(jcr, sd, OK_end, "Append End")) {
1427 set_jcr_job_status(jcr, JS_ErrorTerminated);
1432 * Send Append Close to Storage daemon
1434 bnet_fsend(sd, append_close, jcr->Ticket);
1435 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1436 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1438 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1442 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1445 if (SDJobStatus != JS_Terminated) {
1446 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1452 #if defined(WIN32_VSS)
1453 /* STOP VSS ON WIN 32 */
1454 /* tell vss to close the backup session */
1456 if (g_pVSSClient->CloseBackup()) {
1457 /* inform user about writer states */
1458 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1459 int msg_type = M_INFO;
1460 if (g_pVSSClient->GetWriterState(i) < 1) {
1461 msg_type = M_WARNING;
1464 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1471 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1472 edit_uint64(jcr->ReadBytes, ed1),
1473 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, (int)bDoVSS,
1475 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1477 return 0; /* return and stop command loop */
1481 * Do a Verify for Director
1484 static int verify_cmd(JCR *jcr)
1486 BSOCK *dir = jcr->dir_bsock;
1487 BSOCK *sd = jcr->store_bsock;
1488 char level[100], ed1[50], ed2[50];
1490 jcr->JobType = JT_VERIFY;
1491 if (sscanf(dir->msg, verifycmd, level) != 1) {
1492 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1496 if (strcasecmp(level, "init") == 0) {
1497 jcr->JobLevel = L_VERIFY_INIT;
1498 } else if (strcasecmp(level, "catalog") == 0){
1499 jcr->JobLevel = L_VERIFY_CATALOG;
1500 } else if (strcasecmp(level, "volume") == 0){
1501 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1502 } else if (strcasecmp(level, "data") == 0){
1503 jcr->JobLevel = L_VERIFY_DATA;
1504 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1505 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1507 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1511 bnet_fsend(dir, OKverify);
1513 generate_daemon_event(jcr, "JobStart");
1515 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1517 switch (jcr->JobLevel) {
1519 case L_VERIFY_CATALOG:
1522 case L_VERIFY_VOLUME_TO_CATALOG:
1523 if (!open_sd_read_session(jcr)) {
1526 start_dir_heartbeat(jcr);
1527 do_verify_volume(jcr);
1528 stop_dir_heartbeat(jcr);
1530 * Send Close session command to Storage daemon
1532 bnet_fsend(sd, read_close, jcr->Ticket);
1533 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1535 /* ****FIXME**** check response */
1536 bget_msg(sd); /* get OK */
1538 /* Inform Storage daemon that we are done */
1539 bnet_sig(sd, BNET_TERMINATE);
1542 case L_VERIFY_DISK_TO_CATALOG:
1546 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1550 bnet_sig(dir, BNET_EOD);
1552 /* Send termination status back to Dir */
1553 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1554 edit_uint64(jcr->ReadBytes, ed1),
1555 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1557 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1559 /* Inform Director that we are done */
1560 bnet_sig(dir, BNET_TERMINATE);
1561 return 0; /* return and terminate command loop */
1565 * Do a Restore for Director
1568 static int restore_cmd(JCR *jcr)
1570 BSOCK *dir = jcr->dir_bsock;
1571 BSOCK *sd = jcr->store_bsock;
1575 char ed1[50], ed2[50];
1578 * Scan WHERE (base directory for restore) from command
1580 Dmsg0(150, "restore command\n");
1581 /* Pickup where string */
1582 where = get_memory(dir->msglen+1);
1585 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1586 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1587 pm_strcpy(jcr->errmsg, dir->msg);
1588 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1593 /* Turn / into nothing */
1594 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1598 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1599 unbash_spaces(where);
1600 jcr->where = bstrdup(where);
1601 free_pool_memory(where);
1602 jcr->replace = replace;
1603 jcr->prefix_links = prefix_links;
1605 bnet_fsend(dir, OKrestore);
1606 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1608 jcr->JobType = JT_RESTORE;
1610 set_jcr_job_status(jcr, JS_Blocked);
1612 if (!open_sd_read_session(jcr)) {
1613 set_jcr_job_status(jcr, JS_ErrorTerminated);
1617 set_jcr_job_status(jcr, JS_Running);
1620 * Do restore of files and data
1622 start_dir_heartbeat(jcr);
1623 generate_daemon_event(jcr, "JobStart");
1625 stop_dir_heartbeat(jcr);
1627 set_jcr_job_status(jcr, JS_Terminated);
1628 if (jcr->JobStatus != JS_Terminated) {
1629 bnet_suppress_error_messages(sd, 1);
1633 * Send Close session command to Storage daemon
1635 bnet_fsend(sd, read_close, jcr->Ticket);
1636 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1638 bget_msg(sd); /* get OK */
1640 /* Inform Storage daemon that we are done */
1641 bnet_sig(sd, BNET_TERMINATE);
1646 set_jcr_job_status(jcr, JS_ErrorTerminated);
1648 /* Send termination status back to Dir */
1649 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1650 edit_uint64(jcr->ReadBytes, ed1),
1651 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1653 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1655 /* Inform Director that we are done */
1656 bnet_sig(dir, BNET_TERMINATE);
1658 Dmsg0(130, "Done in job.c\n");
1659 return 0; /* return and terminate command loop */
1662 static int open_sd_read_session(JCR *jcr)
1664 BSOCK *sd = jcr->store_bsock;
1667 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1670 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1671 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1672 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1674 * Open Read Session with Storage daemon
1676 bnet_fsend(sd, read_open, "DummyVolume",
1677 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1678 jcr->StartBlock, jcr->EndBlock);
1679 Dmsg1(110, ">stored: %s", sd->msg);
1684 if (bget_msg(sd) >= 0) {
1685 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1686 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1687 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1690 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1692 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1696 if (!send_bootstrap_file(jcr)) {
1701 * Start read of data with Storage daemon
1703 bnet_fsend(sd, read_data, jcr->Ticket);
1704 Dmsg1(110, ">stored: %s", sd->msg);
1709 if (!response(jcr, sd, OK_data, "Read Data")) {
1716 * Destroy the Job Control Record and associated
1717 * resources (sockets).
1719 static void filed_free_jcr(JCR *jcr)
1721 if (jcr->store_bsock) {
1722 bnet_close(jcr->store_bsock);
1724 free_bootstrap(jcr);
1725 if (jcr->last_fname) {
1726 free_pool_memory(jcr->last_fname);
1728 free_runscripts(jcr->RunScripts);
1729 delete jcr->RunScripts;
1735 * Get response from Storage daemon to a command we
1736 * sent. Check that the response is OK.
1738 * Returns: 0 on failure
1741 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1746 if (bget_msg(sd) > 0) {
1747 Dmsg0(110, sd->msg);
1748 if (strcmp(sd->msg, resp) == 0) {
1752 if (job_canceled(jcr)) {
1753 return 0; /* if canceled avoid useless error messages */
1755 if (is_bnet_error(sd)) {
1756 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1757 cmd, bnet_strerror(sd));
1759 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1760 cmd, resp, sd->msg);
1765 static int send_bootstrap_file(JCR *jcr)
1769 BSOCK *sd = jcr->store_bsock;
1770 const char *bootstrap = "bootstrap\n";
1773 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1774 if (!jcr->RestoreBootstrap) {
1777 bs = fopen(jcr->RestoreBootstrap, "rb");
1780 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1781 jcr->RestoreBootstrap, be.strerror());
1782 set_jcr_job_status(jcr, JS_ErrorTerminated);
1785 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1787 while (fgets(buf, sizeof(buf), bs)) {
1788 sd->msglen = Mmsg(sd->msg, "%s", buf);
1791 bnet_sig(sd, BNET_EOD);
1793 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1794 set_jcr_job_status(jcr, JS_ErrorTerminated);
1800 free_bootstrap(jcr);