2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 and included
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 Kern Sibbald.
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
38 #if defined(WIN32_VSS)
41 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int enable_vss = 0;
46 * As Windows saves ACLs as part of the standard backup stream
47 * we just pretend here that is has implicit acl support.
49 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
50 const bool have_acl = true;
52 const bool have_acl = false;
55 #if defined(HAVE_XATTR)
56 const bool have_xattr = true;
58 const bool have_xattr = false;
61 extern CLIENT *me; /* our client resource */
63 /* Imported functions */
64 extern int status_cmd(JCR *jcr);
65 extern int qstatus_cmd(JCR *jcr);
66 extern int accurate_cmd(JCR *jcr);
68 /* Forward referenced functions */
69 static int backup_cmd(JCR *jcr);
70 static int bootstrap_cmd(JCR *jcr);
71 static int cancel_cmd(JCR *jcr);
72 static int setdebug_cmd(JCR *jcr);
73 static int estimate_cmd(JCR *jcr);
74 static int hello_cmd(JCR *jcr);
75 static int job_cmd(JCR *jcr);
76 static int fileset_cmd(JCR *jcr);
77 static int level_cmd(JCR *jcr);
78 static int verify_cmd(JCR *jcr);
79 static int restore_cmd(JCR *jcr);
80 static int end_restore_cmd(JCR *jcr);
81 static int storage_cmd(JCR *jcr);
82 static int session_cmd(JCR *jcr);
83 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
84 static void filed_free_jcr(JCR *jcr);
85 static int open_sd_read_session(JCR *jcr);
86 static int send_bootstrap_file(JCR *jcr);
87 static int runscript_cmd(JCR *jcr);
88 static int runbefore_cmd(JCR *jcr);
89 static int runafter_cmd(JCR *jcr);
90 static int runbeforenow_cmd(JCR *jcr);
91 static int restore_object_cmd(JCR *jcr);
92 static int set_options(findFOPTS *fo, const char *opts);
93 static void set_storage_auth_key(JCR *jcr, char *key);
94 static int sm_dump_cmd(JCR *jcr);
96 /* Exported functions */
101 int monitoraccess; /* specify if monitors have access to this function */
105 * The following are the recognized commands from the Director.
107 static struct s_cmds cmds[] = {
108 {"backup", backup_cmd, 0},
109 {"cancel", cancel_cmd, 0},
110 {"setdebug=", setdebug_cmd, 0},
111 {"estimate", estimate_cmd, 0},
112 {"Hello", hello_cmd, 1},
113 {"fileset", fileset_cmd, 0},
114 {"JobId=", job_cmd, 0},
115 {"level = ", level_cmd, 0},
116 {"restore ", restore_cmd, 0},
117 {"endrestore", end_restore_cmd, 0},
118 {"session", session_cmd, 0},
119 {"status", status_cmd, 1},
120 {".status", qstatus_cmd, 1},
121 {"storage ", storage_cmd, 0},
122 {"verify", verify_cmd, 0},
123 {"bootstrap", bootstrap_cmd, 0},
124 {"RunBeforeNow", runbeforenow_cmd, 0},
125 {"RunBeforeJob", runbefore_cmd, 0},
126 {"RunAfterJob", runafter_cmd, 0},
127 {"Run", runscript_cmd, 0},
128 {"accurate", accurate_cmd, 0},
129 {"restoreobject", restore_object_cmd, 0},
130 {"sm_dump", sm_dump_cmd, 0},
131 {NULL, NULL} /* list terminator */
134 /* Commands received from director that need scanning */
135 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
136 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
137 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
138 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
139 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
140 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
141 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
142 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
143 static char endrestoreobjectcmd[] = "restoreobject end\n";
144 static char verifycmd[] = "verify level=%30s";
145 static char estimatecmd[] = "estimate listing=%d";
146 static char runbefore[] = "RunBeforeJob %s";
147 static char runafter[] = "RunAfterJob %s";
148 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
150 /* Responses sent to Director */
151 static char errmsg[] = "2999 Invalid command\n";
152 static char no_auth[] = "2998 No Authorization\n";
153 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
154 static char OKinc[] = "2000 OK include\n";
155 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
156 static char OKlevel[] = "2000 OK level\n";
157 static char OKbackup[] = "2000 OK backup\n";
158 static char OKbootstrap[] = "2000 OK bootstrap\n";
159 static char OKverify[] = "2000 OK verify\n";
160 static char OKrestore[] = "2000 OK restore\n";
161 static char OKsession[] = "2000 OK session\n";
162 static char OKstore[] = "2000 OK storage\n";
163 static char OKstoreend[] = "2000 OK storage end\n";
164 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
165 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
166 static char BADjob[] = "2901 Bad Job\n";
167 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
168 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
169 static char OKRunBefore[] = "2000 OK RunBefore\n";
170 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
171 static char OKRunAfter[] = "2000 OK RunAfter\n";
172 static char OKRunScript[] = "2000 OK RunScript\n";
173 static char BADcmd[] = "2902 Bad %s\n";
174 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
177 /* Responses received from Storage Daemon */
178 static char OK_end[] = "3000 OK end\n";
179 static char OK_close[] = "3000 OK close Status = %d\n";
180 static char OK_open[] = "3000 OK open ticket = %d\n";
181 static char OK_data[] = "3000 OK data\n";
182 static char OK_append[] = "3000 OK append data\n";
183 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
186 /* Commands sent to Storage Daemon */
187 static char append_open[] = "append open session\n";
188 static char append_data[] = "append data %d\n";
189 static char append_end[] = "append end session %d\n";
190 static char append_close[] = "append close session %d\n";
191 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
192 static char read_data[] = "read data %d\n";
193 static char read_close[] = "read close session %d\n";
196 * Accept requests from a Director
198 * NOTE! We are running as a separate thread
200 * Send output one line
201 * at a time followed by a zero length transmission.
203 * Return when the connection is terminated or there
206 * Basic task here is:
207 * Authenticate Director (during Hello command).
208 * Accept commands one at a time from the Director
211 * Concerning ClientRunBefore/After, the sequence of events
212 * is rather critical. If they are not done in the right
213 * order one can easily get FD->SD timeouts if the script
216 * The current sequence of events is:
217 * 1. Dir starts job with FD
218 * 2. Dir connects to SD
219 * 3. Dir connects to FD
220 * 4. FD connects to SD
221 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
222 * 6. Dir sends include/exclude
223 * 7. FD sends data to SD
224 * 8. SD/FD disconnects while SD despools data and attributes (optional)
225 * 9. FD runs ClientRunAfterJob
228 void *handle_client_request(void *dirp)
233 BSOCK *dir = (BSOCK *)dirp;
234 const char jobname[12] = "*Director*";
237 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
238 jcr->dir_bsock = dir;
239 jcr->ff = init_find_files();
240 // save_cwd.save(jcr);
241 jcr->start_time = time(NULL);
242 jcr->RunScripts = New(alist(10, not_owned_by_alist));
243 jcr->last_fname = get_pool_memory(PM_FNAME);
244 jcr->last_fname[0] = 0;
245 jcr->client_name = get_memory(strlen(my_name) + 1);
246 pm_strcpy(jcr->client_name, my_name);
247 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
248 jcr->crypto.pki_sign = me->pki_sign;
249 jcr->crypto.pki_encrypt = me->pki_encrypt;
250 jcr->crypto.pki_keypair = me->pki_keypair;
251 jcr->crypto.pki_signers = me->pki_signers;
252 jcr->crypto.pki_recipients = me->pki_recipients;
254 enable_backup_privileges(NULL, 1 /* ignore_errors */);
256 /**********FIXME******* add command handler error code */
258 for (quit=false; !quit;) {
260 if (dir->recv() < 0) {
261 break; /* connection terminated */
263 dir->msg[dir->msglen] = 0;
264 Dmsg1(100, "<dird: %s", dir->msg);
266 for (i=0; cmds[i].cmd; i++) {
267 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
268 found = true; /* indicate command found */
269 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
271 dir->signal(BNET_EOD);
274 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
275 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
276 dir->fsend(invalid_cmd);
277 dir->signal(BNET_EOD);
280 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
281 if (!cmds[i].func(jcr)) { /* do command */
282 quit = true; /* error or fully terminated, get out */
283 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
288 if (!found) { /* command not found */
295 /* Inform Storage daemon that we are done */
296 if (jcr->store_bsock) {
297 jcr->store_bsock->signal(BNET_TERMINATE);
300 /* Run the after job */
301 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
303 if (jcr->JobId) { /* send EndJob if running a job */
304 char ed1[50], ed2[50];
305 /* Send termination status back to Dir */
306 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
307 edit_uint64(jcr->ReadBytes, ed1),
308 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
309 jcr->crypto.pki_encrypt);
310 Dmsg1(110, "End FD msg: %s\n", dir->msg);
313 generate_daemon_event(jcr, "JobEnd");
314 generate_plugin_event(jcr, bEventJobEnd);
316 dequeue_messages(jcr); /* send any queued messages */
318 /* Inform Director that we are done */
319 dir->signal(BNET_TERMINATE);
321 free_plugins(jcr); /* release instantiated plugins */
322 free_and_null_pool_memory(jcr->job_metadata);
324 /* Clean up fileset */
325 FF_PKT *ff = jcr->ff;
326 findFILESET *fileset = ff->fileset;
329 /* Delete FileSet Include lists */
330 for (i=0; i<fileset->include_list.size(); i++) {
331 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
332 for (j=0; j<incexe->opts_list.size(); j++) {
333 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
334 for (k=0; k<fo->regex.size(); k++) {
335 regfree((regex_t *)fo->regex.get(k));
337 for (k=0; k<fo->regexdir.size(); k++) {
338 regfree((regex_t *)fo->regexdir.get(k));
340 for (k=0; k<fo->regexfile.size(); k++) {
341 regfree((regex_t *)fo->regexfile.get(k));
344 fo->regexdir.destroy();
345 fo->regexfile.destroy();
347 fo->wilddir.destroy();
348 fo->wildfile.destroy();
349 fo->wildbase.destroy();
351 fo->fstype.destroy();
352 fo->drivetype.destroy();
354 incexe->opts_list.destroy();
355 incexe->name_list.destroy();
356 incexe->plugin_list.destroy();
357 if (incexe->ignoredir) {
358 free(incexe->ignoredir);
361 fileset->include_list.destroy();
363 /* Delete FileSet Exclude lists */
364 for (i=0; i<fileset->exclude_list.size(); i++) {
365 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
366 for (j=0; j<incexe->opts_list.size(); j++) {
367 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
369 fo->regexdir.destroy();
370 fo->regexfile.destroy();
372 fo->wilddir.destroy();
373 fo->wildfile.destroy();
374 fo->wildbase.destroy();
376 fo->fstype.destroy();
377 fo->drivetype.destroy();
379 incexe->opts_list.destroy();
380 incexe->name_list.destroy();
381 incexe->plugin_list.destroy();
382 if (incexe->ignoredir) {
383 free(incexe->ignoredir);
386 fileset->exclude_list.destroy();
390 Dmsg0(100, "Calling term_find_files\n");
391 term_find_files(jcr->ff);
392 // save_cwd.restore(jcr);
393 // save_cwd.release();
395 Dmsg0(100, "Done with term_find_files\n");
396 free_jcr(jcr); /* destroy JCR record */
397 Dmsg0(100, "Done with free_jcr\n");
402 static int sm_dump_cmd(JCR *jcr)
404 BSOCK *dir = jcr->dir_bsock;
405 sm_dump(false, true);
406 dir->fsend("2000 sm_dump OK\n");
411 * Hello from Director he must identify himself and provide his
414 static int hello_cmd(JCR *jcr)
416 Dmsg0(120, "Calling Authenticate\n");
417 if (!authenticate_director(jcr)) {
420 Dmsg0(120, "OK Authenticate\n");
421 jcr->authenticated = true;
428 static int cancel_cmd(JCR *jcr)
430 BSOCK *dir = jcr->dir_bsock;
431 char Job[MAX_NAME_LENGTH];
434 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
435 if (!(cjcr=get_jcr_by_full_name(Job))) {
436 dir->fsend(_("2901 Job %s not found.\n"), Job);
438 if (cjcr->store_bsock) {
439 cjcr->store_bsock->set_timed_out();
440 cjcr->store_bsock->set_terminated();
441 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
443 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
444 set_jcr_job_status(cjcr, JS_Canceled);
446 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
449 dir->fsend(_("2902 Error scanning cancel command.\n"));
451 dir->signal(BNET_EOD);
457 * Set debug level as requested by the Director
460 static int setdebug_cmd(JCR *jcr)
462 BSOCK *dir = jcr->dir_bsock;
463 int level, trace_flag;
465 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
466 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
467 pm_strcpy(jcr->errmsg, dir->msg);
468 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
472 set_trace(trace_flag);
473 return dir->fsend(OKsetdebug, level);
477 static int estimate_cmd(JCR *jcr)
479 BSOCK *dir = jcr->dir_bsock;
480 char ed1[50], ed2[50];
482 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
483 pm_strcpy(jcr->errmsg, dir->msg);
484 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
485 dir->fsend(_("2992 Bad estimate command.\n"));
489 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
490 edit_uint64_with_commas(jcr->JobBytes, ed2));
491 dir->signal(BNET_EOD);
496 * Get JobId and Storage Daemon Authorization key from Director
498 static int job_cmd(JCR *jcr)
500 BSOCK *dir = jcr->dir_bsock;
501 POOL_MEM sd_auth_key(PM_MESSAGE);
502 sd_auth_key.check_size(dir->msglen);
504 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
505 &jcr->VolSessionId, &jcr->VolSessionTime,
506 sd_auth_key.c_str()) != 5) {
507 pm_strcpy(jcr->errmsg, dir->msg);
508 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
512 set_storage_auth_key(jcr, sd_auth_key.c_str());
513 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
514 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
515 new_plugins(jcr); /* instantiate plugins for this jcr */
516 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
517 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
520 static int runbefore_cmd(JCR *jcr)
523 BSOCK *dir = jcr->dir_bsock;
524 POOLMEM *cmd = get_memory(dir->msglen+1);
527 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
528 if (sscanf(dir->msg, runbefore, cmd) != 1) {
529 pm_strcpy(jcr->errmsg, dir->msg);
530 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
531 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
537 /* Run the command now */
538 script = new_runscript();
539 script->set_command(cmd);
540 script->when = SCRIPT_Before;
541 ok = script->run(jcr, "ClientRunBeforeJob");
542 free_runscript(script);
546 dir->fsend(OKRunBefore);
549 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
554 static int runbeforenow_cmd(JCR *jcr)
556 BSOCK *dir = jcr->dir_bsock;
558 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
559 if (job_canceled(jcr)) {
560 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
561 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
564 dir->fsend(OKRunBeforeNow);
565 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
570 static int runafter_cmd(JCR *jcr)
572 BSOCK *dir = jcr->dir_bsock;
573 POOLMEM *msg = get_memory(dir->msglen+1);
576 Dmsg1(100, "runafter_cmd: %s", dir->msg);
577 if (sscanf(dir->msg, runafter, msg) != 1) {
578 pm_strcpy(jcr->errmsg, dir->msg);
579 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
580 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
586 cmd = new_runscript();
587 cmd->set_command(msg);
588 cmd->on_success = true;
589 cmd->on_failure = false;
590 cmd->when = SCRIPT_After;
592 jcr->RunScripts->append(cmd);
594 free_pool_memory(msg);
595 return dir->fsend(OKRunAfter);
598 static int runscript_cmd(JCR *jcr)
600 BSOCK *dir = jcr->dir_bsock;
601 POOLMEM *msg = get_memory(dir->msglen+1);
602 int on_success, on_failure, fail_on_error;
604 RUNSCRIPT *cmd = new_runscript() ;
606 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
607 /* Note, we cannot sscanf into bools */
608 if (sscanf(dir->msg, runscript, &on_success,
613 pm_strcpy(jcr->errmsg, dir->msg);
614 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
615 dir->fsend(_("2905 Bad RunScript command.\n"));
620 cmd->on_success = on_success;
621 cmd->on_failure = on_failure;
622 cmd->fail_on_error = fail_on_error;
625 cmd->set_command(msg);
627 jcr->RunScripts->append(cmd);
629 free_pool_memory(msg);
630 return dir->fsend(OKRunScript);
634 * This reads data sent from the Director from the
635 * RestoreObject table that allows us to get objects
636 * that were backed up (VSS .xml data) and are needed
637 * before starting the restore.
639 static int restore_object_cmd(JCR *jcr)
641 BSOCK *dir = jcr->dir_bsock;
643 restore_object_pkt rop;
645 memset(&rop, 0, sizeof(rop));
646 rop.pkt_size = sizeof(rop);
647 rop.pkt_end = sizeof(rop);
648 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
649 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
650 generate_plugin_event(jcr, bEventRestoreObject, NULL);
651 return dir->fsend(OKRestoreObject);
654 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
655 &rop.object_full_len, &rop.object_index,
656 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
657 Dmsg0(5, "Bad restore object command\n");
658 pm_strcpy(jcr->errmsg, dir->msg);
659 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
663 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
664 rop.JobId, rop.object_len, rop.object_full_len,
665 rop.object_index, rop.object_type, FileIndex);
666 /* Read Object name */
667 if (dir->recv() < 0) {
670 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
671 rop.object_name = bstrdup(dir->msg);
674 if (dir->recv() < 0) {
677 /* Transfer object from message buffer, and get new message buffer */
678 rop.object = dir->msg;
679 dir->msg = get_pool_memory(PM_MESSAGE);
681 /* If object is compressed, uncompress it */
682 if (rop.object_compression == 1) { /* zlib level 9 */
684 int out_len = rop.object_full_len + 100;
685 POOLMEM *obj = get_memory(out_len);
686 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
687 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
688 Dmsg1(100, "Zinflate stat=%d\n", stat);
689 if (out_len != rop.object_full_len) {
690 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
691 rop.object_full_len, out_len, rop.object_name);
693 free_pool_memory(rop.object); /* release compressed object */
694 rop.object = obj; /* new uncompressed object */
695 rop.object_len = out_len;
697 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
698 /* Special Job meta data */
699 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
700 Dmsg0(100, "got job metadata\n");
701 free_and_null_pool_memory(jcr->job_metadata);
702 jcr->job_metadata = rop.object;
706 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
709 if (rop.object_name) {
710 free(rop.object_name);
713 free_pool_memory(rop.object);
716 Dmsg1(100, "Send: %s", OKRestoreObject);
720 dir->fsend(_("2909 Bad RestoreObject command.\n"));
726 static bool init_fileset(JCR *jcr)
729 findFILESET *fileset;
738 fileset = (findFILESET *)malloc(sizeof(findFILESET));
739 memset(fileset, 0, sizeof(findFILESET));
740 ff->fileset = fileset;
741 fileset->state = state_none;
742 fileset->include_list.init(1, true);
743 fileset->exclude_list.init(1, true);
747 static void append_file(JCR *jcr, findINCEXE *incexe,
748 const char *buf, bool is_file)
751 incexe->name_list.append(new_dlistString(buf));
753 } else if (me->plugin_directory) {
754 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
755 incexe->plugin_list.append(new_dlistString(buf));
758 Jmsg(jcr, M_FATAL, 0,
759 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
765 * Add fname to include/exclude fileset list. First check for
766 * | and < and if necessary perform command.
768 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
770 findFILESET *fileset = jcr->ff->fileset;
783 p++; /* skip over | */
784 fn = get_pool_memory(PM_FNAME);
785 fn = edit_job_codes(jcr, fn, p, "");
786 bpipe = open_bpipe(fn, 0, "r");
789 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
791 free_pool_memory(fn);
794 free_pool_memory(fn);
795 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
796 strip_trailing_junk(buf);
797 append_file(jcr, fileset->incexe, buf, is_file);
799 if ((stat=close_bpipe(bpipe)) != 0) {
801 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
802 p, be.code(stat), be.bstrerror(stat));
807 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
808 p++; /* skip over < */
809 if ((ffd = fopen(p, "rb")) == NULL) {
811 Jmsg(jcr, M_FATAL, 0,
812 _("Cannot open FileSet input file: %s. ERR=%s\n"),
816 while (fgets(buf, sizeof(buf), ffd)) {
817 strip_trailing_junk(buf);
818 append_file(jcr, fileset->incexe, buf, is_file);
823 append_file(jcr, fileset->incexe, fname, is_file);
828 void set_incexe(JCR *jcr, findINCEXE *incexe)
830 findFILESET *fileset = jcr->ff->fileset;
831 fileset->incexe = incexe;
836 * Define a new Exclude block in the FileSet
838 findINCEXE *new_exclude(JCR *jcr)
840 findFILESET *fileset = jcr->ff->fileset;
843 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
844 memset(fileset->incexe, 0, sizeof(findINCEXE));
845 fileset->incexe->opts_list.init(1, true);
846 fileset->incexe->name_list.init();
847 fileset->incexe->plugin_list.init();
848 fileset->exclude_list.append(fileset->incexe);
849 return fileset->incexe;
853 * Define a new Include block in the FileSet
855 findINCEXE *new_include(JCR *jcr)
857 findFILESET *fileset = jcr->ff->fileset;
860 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
861 memset(fileset->incexe, 0, sizeof(findINCEXE));
862 fileset->incexe->opts_list.init(1, true);
863 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
864 fileset->incexe->plugin_list.init();
865 fileset->include_list.append(fileset->incexe);
866 return fileset->incexe;
870 * Define a new preInclude block in the FileSet
871 * That is the include is prepended to the other
872 * Includes. This is used for plugin exclusions.
874 findINCEXE *new_preinclude(JCR *jcr)
876 findFILESET *fileset = jcr->ff->fileset;
878 /* New pre-include */
879 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
880 memset(fileset->incexe, 0, sizeof(findINCEXE));
881 fileset->incexe->opts_list.init(1, true);
882 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
883 fileset->incexe->plugin_list.init();
884 fileset->include_list.prepend(fileset->incexe);
885 return fileset->incexe;
888 static findFOPTS *start_options(FF_PKT *ff)
890 int state = ff->fileset->state;
891 findINCEXE *incexe = ff->fileset->incexe;
893 if (state != state_options) {
894 ff->fileset->state = state_options;
895 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
896 memset(fo, 0, sizeof(findFOPTS));
897 fo->regex.init(1, true);
898 fo->regexdir.init(1, true);
899 fo->regexfile.init(1, true);
900 fo->wild.init(1, true);
901 fo->wilddir.init(1, true);
902 fo->wildfile.init(1, true);
903 fo->wildbase.init(1, true);
904 fo->base.init(1, true);
905 fo->fstype.init(1, true);
906 fo->drivetype.init(1, true);
907 incexe->current_opts = fo;
908 incexe->opts_list.append(fo);
910 return incexe->current_opts;
914 * Used by plugins to define a new options block
916 void new_options(JCR *jcr, findINCEXE *incexe)
919 incexe = jcr->ff->fileset->incexe;
921 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
922 memset(fo, 0, sizeof(findFOPTS));
923 fo->regex.init(1, true);
924 fo->regexdir.init(1, true);
925 fo->regexfile.init(1, true);
926 fo->wild.init(1, true);
927 fo->wilddir.init(1, true);
928 fo->wildfile.init(1, true);
929 fo->wildbase.init(1, true);
930 fo->base.init(1, true);
931 fo->fstype.init(1, true);
932 fo->drivetype.init(1, true);
933 incexe->current_opts = fo;
934 incexe->opts_list.prepend(fo);
935 jcr->ff->fileset->state = state_options;
939 * Add a regex to the current fileset
941 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
943 findFOPTS *current_opts = start_options(jcr->ff);
948 preg = (regex_t *)malloc(sizeof(regex_t));
949 if (current_opts->flags & FO_IGNORECASE) {
950 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
952 rc = regcomp(preg, item, REG_EXTENDED);
955 regerror(rc, preg, prbuf, sizeof(prbuf));
958 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
962 current_opts->regex.append(preg);
963 } else if (type == 'D') {
964 current_opts->regexdir.append(preg);
965 } else if (type == 'F') {
966 current_opts->regexfile.append(preg);
970 return state_options;
974 * Add a wild card to the current fileset
976 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
978 findFOPTS *current_opts = start_options(jcr->ff);
981 current_opts->wild.append(bstrdup(item));
982 } else if (type == 'D') {
983 current_opts->wilddir.append(bstrdup(item));
984 } else if (type == 'F') {
985 current_opts->wildfile.append(bstrdup(item));
986 } else if (type == 'B') {
987 current_opts->wildbase.append(bstrdup(item));
991 return state_options;
996 * Add options to the current fileset
998 int add_options_to_fileset(JCR *jcr, const char *item)
1000 findFOPTS *current_opts = start_options(jcr->ff);
1002 set_options(current_opts, item);
1003 return state_options;
1006 static void add_fileset(JCR *jcr, const char *item)
1008 FF_PKT *ff = jcr->ff;
1009 findFILESET *fileset = ff->fileset;
1010 int state = fileset->state;
1011 findFOPTS *current_opts;
1013 /* Get code, optional subcode, and position item past the dividing space */
1014 Dmsg1(100, "%s\n", item);
1019 int subcode = ' '; /* A space is always a valid subcode */
1020 if (item[0] != '\0' && item[0] != ' ') {
1028 /* Skip all lines we receive after an error */
1029 if (state == state_error) {
1030 Dmsg0(100, "State=error return\n");
1035 * The switch tests the code for validity.
1036 * The subcode is always good if it is a space, otherwise we must confirm.
1037 * We set state to state_error first assuming the subcode is invalid,
1038 * requiring state to be set in cases below that handle subcodes.
1040 if (subcode != ' ') {
1041 state = state_error;
1042 Dmsg0(100, "Set state=error or double code.\n");
1046 (void)new_include(jcr);
1049 (void)new_exclude(jcr);
1051 case 'N': /* null */
1054 case 'F': /* file = */
1055 /* File item to include or exclude list */
1056 state = state_include;
1057 add_file_to_fileset(jcr, item, true);
1059 case 'P': /* plugin */
1060 /* Plugin item to include list */
1061 state = state_include;
1062 add_file_to_fileset(jcr, item, false);
1064 case 'R': /* regex */
1065 state = add_regex_to_fileset(jcr, item, subcode);
1068 current_opts = start_options(ff);
1069 current_opts->base.append(bstrdup(item));
1070 state = state_options;
1072 case 'X': /* Filetype or Drive type */
1073 current_opts = start_options(ff);
1074 state = state_options;
1075 if (subcode == ' ') {
1076 current_opts->fstype.append(bstrdup(item));
1077 } else if (subcode == 'D') {
1078 current_opts->drivetype.append(bstrdup(item));
1080 state = state_error;
1083 case 'W': /* wild cards */
1084 state = add_wild_to_fileset(jcr, item, subcode);
1086 case 'O': /* Options */
1087 state = add_options_to_fileset(jcr, item);
1089 case 'Z': /* ignore dir */
1090 state = state_include;
1091 fileset->incexe->ignoredir = bstrdup(item);
1094 current_opts = start_options(ff);
1095 // current_opts->reader = bstrdup(item); /* deprecated */
1096 state = state_options;
1099 current_opts = start_options(ff);
1100 // current_opts->writer = bstrdup(item); /* deprecated */
1101 state = state_options;
1104 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1105 state = state_error;
1108 ff->fileset->state = state;
1111 static bool term_fileset(JCR *jcr)
1113 FF_PKT *ff = jcr->ff;
1115 #ifdef xxx_DEBUG_CODE
1116 findFILESET *fileset = ff->fileset;
1119 for (i=0; i<fileset->include_list.size(); i++) {
1120 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1122 for (j=0; j<incexe->opts_list.size(); j++) {
1123 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1124 for (k=0; k<fo->regex.size(); k++) {
1125 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1127 for (k=0; k<fo->regexdir.size(); k++) {
1128 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1130 for (k=0; k<fo->regexfile.size(); k++) {
1131 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1133 for (k=0; k<fo->wild.size(); k++) {
1134 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1136 for (k=0; k<fo->wilddir.size(); k++) {
1137 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1139 for (k=0; k<fo->wildfile.size(); k++) {
1140 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1142 for (k=0; k<fo->wildbase.size(); k++) {
1143 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1145 for (k=0; k<fo->base.size(); k++) {
1146 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1148 for (k=0; k<fo->fstype.size(); k++) {
1149 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1151 for (k=0; k<fo->drivetype.size(); k++) {
1152 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1155 if (incexe->ignoredir) {
1156 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1159 foreach_dlist(node, &incexe->name_list) {
1160 Dmsg1(400, "F %s\n", node->c_str());
1162 foreach_dlist(node, &incexe->plugin_list) {
1163 Dmsg1(400, "P %s\n", node->c_str());
1166 for (i=0; i<fileset->exclude_list.size(); i++) {
1167 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1169 for (j=0; j<incexe->opts_list.size(); j++) {
1170 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1171 for (k=0; k<fo->regex.size(); k++) {
1172 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1174 for (k=0; k<fo->regexdir.size(); k++) {
1175 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1177 for (k=0; k<fo->regexfile.size(); k++) {
1178 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1180 for (k=0; k<fo->wild.size(); k++) {
1181 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1183 for (k=0; k<fo->wilddir.size(); k++) {
1184 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1186 for (k=0; k<fo->wildfile.size(); k++) {
1187 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1189 for (k=0; k<fo->wildbase.size(); k++) {
1190 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1192 for (k=0; k<fo->base.size(); k++) {
1193 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1195 for (k=0; k<fo->fstype.size(); k++) {
1196 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1198 for (k=0; k<fo->drivetype.size(); k++) {
1199 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1203 foreach_dlist(node, incexe->name_list) {
1204 Dmsg1(400, "F %s\n", node->c_str());
1206 foreach_dlist(node, &incexe->plugin_list) {
1207 Dmsg1(400, "P %s\n", node->c_str());
1211 return ff->fileset->state != state_error;
1216 * As an optimization, we should do this during
1217 * "compile" time in filed/job.c, and keep only a bit mask
1218 * and the Verify options.
1220 static int set_options(findFOPTS *fo, const char *opts)
1226 // Commented out as it is not backward compatible - KES
1228 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1231 for (p=opts; *p; p++) {
1233 case 'a': /* alway replace */
1234 case '0': /* no option */
1237 fo->flags |= FO_EXCLUDE;
1240 fo->flags |= FO_MULTIFS;
1242 case 'h': /* no recursion */
1243 fo->flags |= FO_NO_RECURSION;
1245 case 'H': /* no hard link handling */
1246 fo->flags |= FO_NO_HARDLINK;
1249 fo->flags |= FO_IGNORECASE;
1252 fo->flags |= FO_MD5;
1255 fo->flags |= FO_NOREPLACE;
1257 case 'p': /* use portable data format */
1258 fo->flags |= FO_PORTABLE;
1260 case 'R': /* Resource forks and Finder Info */
1261 fo->flags |= FO_HFSPLUS;
1263 case 'r': /* read fifo */
1264 fo->flags |= FO_READFIFO;
1269 fo->flags |= FO_SHA1;
1274 fo->flags |= FO_SHA256;
1278 fo->flags |= FO_SHA512;
1284 * If 2 or 3 is seen here, SHA2 is not configured, so
1285 * eat the option, and drop back to SHA-1.
1287 if (p[1] == '2' || p[1] == '3') {
1290 fo->flags |= FO_SHA1;
1295 fo->flags |= FO_SPARSE;
1298 fo->flags |= FO_MTIMEONLY;
1301 fo->flags |= FO_KEEPATIME;
1304 fo->flags |= FO_ACL;
1306 case 'V': /* verify options */
1307 /* Copy Verify Options */
1308 for (j=0; *p && *p != ':'; p++) {
1309 fo->VerifyOpts[j] = *p;
1310 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1314 fo->VerifyOpts[j] = 0;
1316 case 'C': /* accurate options */
1317 /* Copy Accurate Options */
1318 for (j=0; *p && *p != ':'; p++) {
1319 fo->AccurateOpts[j] = *p;
1320 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1324 fo->AccurateOpts[j] = 0;
1326 case 'J': /* Basejob options */
1327 /* Copy BaseJob Options */
1328 for (j=0; *p && *p != ':'; p++) {
1329 fo->BaseJobOpts[j] = *p;
1330 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1334 fo->BaseJobOpts[j] = 0;
1336 case 'P': /* strip path */
1339 for (j=0; *p && *p != ':'; p++) {
1341 if (j < (int)sizeof(strip) - 1) {
1346 fo->strip_path = atoi(strip);
1347 fo->flags |= FO_STRIPPATH;
1348 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1351 fo->flags |= FO_IF_NEWER;
1354 fo->flags |= FO_ENHANCEDWILD;
1356 case 'Z': /* gzip compression */
1357 fo->flags |= FO_GZIP;
1358 fo->GZIP_level = *++p - '0';
1361 fo->flags |= FO_NOATIME;
1364 fo->flags |= FO_CHKCHANGES;
1367 fo->flags |= FO_HONOR_NODUMP;
1370 fo->flags |= FO_XATTR;
1373 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1377 return state_options;
1382 * Director is passing his Fileset
1384 static int fileset_cmd(JCR *jcr)
1386 BSOCK *dir = jcr->dir_bsock;
1389 #if defined(WIN32_VSS)
1392 sscanf(dir->msg, "fileset vss=%d", &vss);
1396 if (!init_fileset(jcr)) {
1399 while (dir->recv() >= 0) {
1400 strip_trailing_junk(dir->msg);
1401 Dmsg1(500, "Fileset: %s\n", dir->msg);
1402 add_fileset(jcr, dir->msg);
1404 if (!term_fileset(jcr)) {
1407 rtnstat = dir->fsend(OKinc);
1408 generate_plugin_event(jcr, bEventEndFileSet);
1412 static void free_bootstrap(JCR *jcr)
1414 if (jcr->RestoreBootstrap) {
1415 unlink(jcr->RestoreBootstrap);
1416 free_pool_memory(jcr->RestoreBootstrap);
1417 jcr->RestoreBootstrap = NULL;
1422 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1423 static uint32_t bsr_uniq = 0;
1426 * The Director sends us the bootstrap file, which
1427 * we will in turn pass to the SD.
1428 * Deprecated. The bsr is now sent directly from the
1429 * Director to the SD.
1431 static int bootstrap_cmd(JCR *jcr)
1433 BSOCK *dir = jcr->dir_bsock;
1434 POOLMEM *fname = get_pool_memory(PM_FNAME);
1437 free_bootstrap(jcr);
1440 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1441 jcr->Job, bsr_uniq);
1443 Dmsg1(400, "bootstrap=%s\n", fname);
1444 jcr->RestoreBootstrap = fname;
1445 bs = fopen(fname, "a+b"); /* create file */
1448 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1449 jcr->RestoreBootstrap, be.bstrerror());
1451 * Suck up what he is sending to us so that he will then
1452 * read our error message.
1454 while (dir->recv() >= 0)
1456 free_bootstrap(jcr);
1457 set_jcr_job_status(jcr, JS_ErrorTerminated);
1461 while (dir->recv() >= 0) {
1462 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1463 fputs(dir->msg, bs);
1467 * Note, do not free the bootstrap yet -- it needs to be
1470 return dir->fsend(OKbootstrap);
1475 * Get backup level from Director
1478 static int level_cmd(JCR *jcr)
1480 BSOCK *dir = jcr->dir_bsock;
1481 POOLMEM *level, *buf = NULL;
1484 level = get_memory(dir->msglen+1);
1485 Dmsg1(100, "level_cmd: %s", dir->msg);
1487 /* keep compatibility with older directors */
1488 if (strstr(dir->msg, "accurate")) {
1489 jcr->accurate = true;
1491 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1494 /* Base backup requested? */
1495 if (strcmp(level, "base") == 0) {
1496 jcr->set_JobLevel(L_BASE);
1497 /* Full backup requested? */
1498 } else if (strcmp(level, "full") == 0) {
1499 jcr->set_JobLevel(L_FULL);
1500 } else if (strstr(level, "differential")) {
1501 jcr->set_JobLevel(L_DIFFERENTIAL);
1504 } else if (strstr(level, "incremental")) {
1505 jcr->set_JobLevel(L_INCREMENTAL);
1509 * We get his UTC since time, then sync the clocks and correct it
1510 * to agree with our clock.
1512 } else if (strcmp(level, "since_utime") == 0) {
1513 buf = get_memory(dir->msglen+1);
1514 utime_t since_time, adj;
1515 btime_t his_time, bt_start, rt=0, bt_adj=0;
1516 if (jcr->getJobLevel() == L_NONE) {
1517 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1519 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1520 buf, &mtime_only) != 2) {
1523 since_time = str_to_uint64(buf); /* this is the since time */
1524 Dmsg1(100, "since_time=%lld\n", since_time);
1525 char ed1[50], ed2[50];
1527 * Sync clocks by polling him for the time. We take
1528 * 10 samples of his time throwing out the first two.
1530 for (int i=0; i<10; i++) {
1531 bt_start = get_current_btime();
1532 dir->signal(BNET_BTIME); /* poll for time */
1533 if (dir->recv() <= 0) { /* get response */
1536 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1539 if (i < 2) { /* toss first two results */
1542 his_time = str_to_uint64(buf);
1543 rt = get_current_btime() - bt_start; /* compute round trip time */
1544 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1545 edit_uint64(bt_start, ed2));
1546 bt_adj += bt_start - his_time - rt/2;
1547 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1550 bt_adj = bt_adj / 8; /* compute average time */
1551 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1552 adj = btime_to_utime(bt_adj);
1553 since_time += adj; /* adjust for clock difference */
1554 /* Don't notify if time within 3 seconds */
1555 if (adj > 3 || adj < -3) {
1557 if (adj > 600 || adj < -600) {
1562 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1564 dir->signal(BNET_EOD);
1566 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1567 jcr->incremental = 1; /* set incremental or decremental backup */
1568 jcr->mtime = since_time; /* set since time */
1569 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1571 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1579 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1580 return dir->fsend(OKlevel);
1583 pm_strcpy(jcr->errmsg, dir->msg);
1584 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1593 * Get session parameters from Director -- this is for a Restore command
1594 * This is deprecated. It is now passed via the bsr.
1596 static int session_cmd(JCR *jcr)
1598 BSOCK *dir = jcr->dir_bsock;
1600 Dmsg1(100, "SessionCmd: %s", dir->msg);
1601 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1602 &jcr->VolSessionId, &jcr->VolSessionTime,
1603 &jcr->StartFile, &jcr->EndFile,
1604 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1605 pm_strcpy(jcr->errmsg, dir->msg);
1606 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1610 return dir->fsend(OKsession);
1613 static void set_storage_auth_key(JCR *jcr, char *key)
1615 /* if no key don't update anything */
1621 * We can be contacting multiple storage daemons.
1622 * So, make sure that any old jcr->store_bsock is cleaned up.
1624 if (jcr->store_bsock) {
1625 jcr->store_bsock->destroy();
1626 jcr->store_bsock = NULL;
1630 * We can be contacting multiple storage daemons.
1631 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1633 if (jcr->sd_auth_key) {
1635 * If we already have a Authorization key, director can do multi
1638 Dmsg0(5, "set multi_restore=true\n");
1639 jcr->multi_restore = true;
1640 bfree(jcr->sd_auth_key);
1643 jcr->sd_auth_key = bstrdup(key);
1644 Dmsg0(5, "set sd auth key\n");
1648 * Get address of storage daemon from Director
1651 static int storage_cmd(JCR *jcr)
1653 int stored_port; /* storage daemon port */
1654 int enable_ssl; /* enable ssl to sd */
1655 POOL_MEM sd_auth_key(PM_MESSAGE);
1656 BSOCK *dir = jcr->dir_bsock;
1657 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1660 Dmsg1(100, "StorageCmd: %s", dir->msg);
1661 sd_auth_key.check_size(dir->msglen);
1662 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1663 &enable_ssl, sd_auth_key.c_str()) != 4) {
1664 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1665 &stored_port, &enable_ssl) != 3) {
1666 pm_strcpy(jcr->errmsg, dir->msg);
1667 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1672 set_storage_auth_key(jcr, sd_auth_key.c_str());
1674 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1676 /* Open command communications with Storage daemon */
1677 /* Try to connect for 1 hour at 10 second intervals */
1679 sd->set_source_address(me->FDsrc_addr);
1680 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1681 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1687 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1688 jcr->stored_addr, stored_port);
1689 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1690 jcr->stored_addr, stored_port);
1693 Dmsg0(110, "Connection OK to SD.\n");
1695 jcr->store_bsock = sd;
1697 sd->fsend("Hello Start Job %s\n", jcr->Job);
1698 if (!authenticate_storagedaemon(jcr)) {
1699 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1702 Dmsg0(110, "Authenticated with SD.\n");
1704 /* Send OK to Director */
1705 return dir->fsend(OKstore);
1708 dir->fsend(BADcmd, "storage");
1717 static int backup_cmd(JCR *jcr)
1719 BSOCK *dir = jcr->dir_bsock;
1720 BSOCK *sd = jcr->store_bsock;
1724 #if defined(WIN32_VSS)
1725 // capture state here, if client is backed up by multiple directors
1726 // and one enables vss and the other does not then enable_vss can change
1727 // between here and where its evaluated after the job completes.
1728 jcr->VSS = g_pVSSClient && enable_vss;
1730 /* Run only one at a time */
1736 * Validate some options given to the backup make sense for the compiled in
1737 * options of this filed.
1739 if (jcr->ff->flags & FO_ACL && !have_acl) {
1740 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1743 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1744 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1748 set_jcr_job_status(jcr, JS_Blocked);
1749 jcr->set_JobType(JT_BACKUP);
1750 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1753 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1754 dir->fsend(BADcmd, "backup");
1758 dir->fsend(OKbackup);
1759 Dmsg1(110, "filed>dird: %s", dir->msg);
1762 * Send Append Open Session to Storage daemon
1764 sd->fsend(append_open);
1765 Dmsg1(110, ">stored: %s", sd->msg);
1767 * Expect to receive back the Ticket number
1769 if (bget_msg(sd) >= 0) {
1770 Dmsg1(110, "<stored: %s", sd->msg);
1771 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1772 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1775 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1777 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1782 * Send Append data command to Storage daemon
1784 sd->fsend(append_data, jcr->Ticket);
1785 Dmsg1(110, ">stored: %s", sd->msg);
1788 * Expect to get OK data
1790 Dmsg1(110, "<stored: %s", sd->msg);
1791 if (!response(jcr, sd, OK_data, "Append Data")) {
1795 generate_daemon_event(jcr, "JobStart");
1796 generate_plugin_event(jcr, bEventStartBackupJob);
1798 #if defined(WIN32_VSS)
1799 /* START VSS ON WIN32 */
1801 if (g_pVSSClient->InitializeForBackup(jcr)) {
1802 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1803 /* tell vss which drives to snapshot */
1804 char szWinDriveLetters[27];
1805 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1806 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1807 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1808 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1811 /* tell user if snapshot creation of a specific drive failed */
1813 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1814 if (islower(szWinDriveLetters[i])) {
1815 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1819 /* inform user about writer states */
1820 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1821 if (g_pVSSClient->GetWriterState(i) < 1) {
1822 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1827 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1831 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1833 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1838 * Send Files to Storage daemon
1840 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1841 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1842 set_jcr_job_status(jcr, JS_ErrorTerminated);
1843 bnet_suppress_error_messages(sd, 1);
1844 Dmsg0(110, "Error in blast_data.\n");
1846 set_jcr_job_status(jcr, JS_Terminated);
1847 /* Note, the above set status will not override an error */
1848 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1849 bnet_suppress_error_messages(sd, 1);
1850 goto cleanup; /* bail out now */
1853 * Expect to get response to append_data from Storage daemon
1855 if (!response(jcr, sd, OK_append, "Append Data")) {
1856 set_jcr_job_status(jcr, JS_ErrorTerminated);
1861 * Send Append End Data to Storage daemon
1863 sd->fsend(append_end, jcr->Ticket);
1865 if (!response(jcr, sd, OK_end, "Append End")) {
1866 set_jcr_job_status(jcr, JS_ErrorTerminated);
1871 * Send Append Close to Storage daemon
1873 sd->fsend(append_close, jcr->Ticket);
1874 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1875 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1877 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1881 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1884 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1885 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1891 #if defined(WIN32_VSS)
1893 Win32ConvCleanupCache();
1898 generate_plugin_event(jcr, bEventEndBackupJob);
1899 return 0; /* return and stop command loop */
1903 * Do a Verify for Director
1906 static int verify_cmd(JCR *jcr)
1908 BSOCK *dir = jcr->dir_bsock;
1909 BSOCK *sd = jcr->store_bsock;
1912 jcr->set_JobType(JT_VERIFY);
1913 if (sscanf(dir->msg, verifycmd, level) != 1) {
1914 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1918 if (strcasecmp(level, "init") == 0) {
1919 jcr->set_JobLevel(L_VERIFY_INIT);
1920 } else if (strcasecmp(level, "catalog") == 0){
1921 jcr->set_JobLevel(L_VERIFY_CATALOG);
1922 } else if (strcasecmp(level, "volume") == 0){
1923 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1924 } else if (strcasecmp(level, "data") == 0){
1925 jcr->set_JobLevel(L_VERIFY_DATA);
1926 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1927 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1929 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1933 dir->fsend(OKverify);
1935 generate_daemon_event(jcr, "JobStart");
1936 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1937 generate_plugin_event(jcr, bEventStartVerifyJob);
1939 Dmsg1(110, "filed>dird: %s", dir->msg);
1941 switch (jcr->getJobLevel()) {
1943 case L_VERIFY_CATALOG:
1946 case L_VERIFY_VOLUME_TO_CATALOG:
1947 if (!open_sd_read_session(jcr)) {
1950 start_dir_heartbeat(jcr);
1951 do_verify_volume(jcr);
1952 stop_dir_heartbeat(jcr);
1954 * Send Close session command to Storage daemon
1956 sd->fsend(read_close, jcr->Ticket);
1957 Dmsg1(130, "filed>stored: %s", sd->msg);
1959 /* ****FIXME**** check response */
1960 bget_msg(sd); /* get OK */
1962 /* Inform Storage daemon that we are done */
1963 sd->signal(BNET_TERMINATE);
1966 case L_VERIFY_DISK_TO_CATALOG:
1970 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1974 dir->signal(BNET_EOD);
1975 generate_plugin_event(jcr, bEventEndVerifyJob);
1976 return 0; /* return and terminate command loop */
1980 static bool vss_restore_init_callback(JCR *jcr, int init_type)
1982 switch (init_type) {
1983 case VSS_INIT_RESTORE_AFTER_INIT:
1984 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
1986 case VSS_INIT_RESTORE_AFTER_GATHER:
1987 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
1997 * Do a Restore for Director
2000 static int restore_cmd(JCR *jcr)
2002 BSOCK *dir = jcr->dir_bsock;
2003 BSOCK *sd = jcr->store_bsock;
2005 bool use_regexwhere=false;
2010 * Scan WHERE (base directory for restore) from command
2012 Dmsg0(100, "restore command\n");
2013 #if defined(WIN32_VSS)
2016 * No need to enable VSS for restore if we do not have plugin
2019 enable_vss = jcr->job_metadata != NULL;
2021 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2022 // capture state here, if client is backed up by multiple directors
2023 // and one enables vss and the other does not then enable_vss can change
2024 // between here and where its evaluated after the job completes.
2025 jcr->VSS = g_pVSSClient && enable_vss;
2027 /* Run only one at a time */
2031 /* Pickup where string */
2032 args = get_memory(dir->msglen+1);
2035 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2036 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2037 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2038 pm_strcpy(jcr->errmsg, dir->msg);
2039 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2044 use_regexwhere = true;
2046 /* Turn / into nothing */
2047 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2051 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2052 unbash_spaces(args);
2054 if (use_regexwhere) {
2055 jcr->where_bregexp = get_bregexps(args);
2056 if (!jcr->where_bregexp) {
2057 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2058 free_pool_memory(args);
2062 jcr->where = bstrdup(args);
2065 free_pool_memory(args);
2066 jcr->replace = replace;
2067 jcr->prefix_links = prefix_links;
2069 dir->fsend(OKrestore);
2070 Dmsg1(110, "filed>dird: %s", dir->msg);
2072 jcr->set_JobType(JT_RESTORE);
2074 set_jcr_job_status(jcr, JS_Blocked);
2076 if (!open_sd_read_session(jcr)) {
2077 set_jcr_job_status(jcr, JS_ErrorTerminated);
2081 set_jcr_job_status(jcr, JS_Running);
2084 * Do restore of files and data
2086 start_dir_heartbeat(jcr);
2087 generate_daemon_event(jcr, "JobStart");
2088 generate_plugin_event(jcr, bEventStartRestoreJob);
2090 #if defined(WIN32_VSS)
2091 /* START VSS ON WIN32 */
2093 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2094 (WCHAR *)jcr->job_metadata)) {
2096 /* inform user about writer states */
2098 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2099 if (g_pVSSClient->GetWriterState(i) < 1) {
2100 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2106 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2107 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2111 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2113 free_and_null_pool_memory(jcr->job_metadata);
2114 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2119 stop_dir_heartbeat(jcr);
2121 set_jcr_job_status(jcr, JS_Terminated);
2122 if (jcr->JobStatus != JS_Terminated) {
2123 bnet_suppress_error_messages(sd, 1);
2127 * Send Close session command to Storage daemon
2129 sd->fsend(read_close, jcr->Ticket);
2130 Dmsg1(100, "filed>stored: %s", sd->msg);
2132 bget_msg(sd); /* get OK */
2134 /* Inform Storage daemon that we are done */
2135 sd->signal(BNET_TERMINATE);
2137 #if defined(WIN32_VSS)
2138 /* STOP VSS ON WIN32 */
2139 /* tell vss to close the restore session */
2140 Dmsg0(0, "About to call CloseRestore\n");
2142 Dmsg0(0, "Really about to call CloseRestore\n");
2143 if (g_pVSSClient->CloseRestore()) {
2144 Dmsg0(0, "CloseRestore success\n");
2145 /* inform user about writer states */
2146 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2147 int msg_type = M_INFO;
2148 if (g_pVSSClient->GetWriterState(i) < 1) {
2149 //msg_type = M_WARNING;
2152 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2156 Dmsg1(0, "CloseRestore fail - %08x\n", errno);
2162 bfree_and_null(jcr->where);
2164 if (jcr->JobErrors) {
2165 set_jcr_job_status(jcr, JS_ErrorTerminated);
2168 Dmsg0(100, "Done in job.c\n");
2171 if (jcr->multi_restore) {
2172 Dmsg0(100, OKstoreend);
2173 dir->fsend(OKstoreend);
2174 ret = 1; /* we continue the loop, waiting for next part */
2176 end_restore_cmd(jcr);
2177 ret = 0; /* we stop here */
2183 static int end_restore_cmd(JCR *jcr)
2185 Dmsg0(5, "end_restore_cmd\n");
2186 generate_plugin_event(jcr, bEventEndRestoreJob);
2187 return 0; /* return and terminate command loop */
2190 static int open_sd_read_session(JCR *jcr)
2192 BSOCK *sd = jcr->store_bsock;
2195 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2198 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2199 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2200 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2202 * Open Read Session with Storage daemon
2204 sd->fsend(read_open, "DummyVolume",
2205 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2206 jcr->StartBlock, jcr->EndBlock);
2207 Dmsg1(110, ">stored: %s", sd->msg);
2212 if (bget_msg(sd) >= 0) {
2213 Dmsg1(110, "filed<stored: %s", sd->msg);
2214 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2215 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2218 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2220 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2224 if (!send_bootstrap_file(jcr)) {
2229 * Start read of data with Storage daemon
2231 sd->fsend(read_data, jcr->Ticket);
2232 Dmsg1(110, ">stored: %s", sd->msg);
2237 if (!response(jcr, sd, OK_data, "Read Data")) {
2244 * Destroy the Job Control Record and associated
2245 * resources (sockets).
2247 static void filed_free_jcr(JCR *jcr)
2249 if (jcr->store_bsock) {
2250 jcr->store_bsock->close();
2252 free_bootstrap(jcr);
2253 if (jcr->last_fname) {
2254 free_pool_memory(jcr->last_fname);
2256 free_runscripts(jcr->RunScripts);
2257 delete jcr->RunScripts;
2259 if (jcr->JobId != 0)
2260 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2266 * Get response from Storage daemon to a command we
2267 * sent. Check that the response is OK.
2269 * Returns: 0 on failure
2272 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2277 if (bget_msg(sd) > 0) {
2278 Dmsg0(110, sd->msg);
2279 if (strcmp(sd->msg, resp) == 0) {
2283 if (job_canceled(jcr)) {
2284 return 0; /* if canceled avoid useless error messages */
2286 if (is_bnet_error(sd)) {
2287 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2288 cmd, bnet_strerror(sd));
2290 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2291 cmd, resp, sd->msg);
2296 static int send_bootstrap_file(JCR *jcr)
2300 BSOCK *sd = jcr->store_bsock;
2301 const char *bootstrap = "bootstrap\n";
2304 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2305 if (!jcr->RestoreBootstrap) {
2308 bs = fopen(jcr->RestoreBootstrap, "rb");
2311 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2312 jcr->RestoreBootstrap, be.bstrerror());
2313 set_jcr_job_status(jcr, JS_ErrorTerminated);
2316 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2318 while (fgets(buf, sizeof(buf), bs)) {
2319 sd->msglen = Mmsg(sd->msg, "%s", buf);
2322 sd->signal(BNET_EOD);
2324 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2325 set_jcr_job_status(jcr, JS_ErrorTerminated);
2331 free_bootstrap(jcr);