]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/job.c
Fix bug #1246 Sometimes access denied with VSS enabled. UCS
[bacula/bacula] / bacula / src / filed / job.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *  Bacula File Daemon Job processing
30  *
31  *    Kern Sibbald, October MM
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "filed.h"
39
40 #if defined(WIN32_VSS)
41 #include "vss.h"
42
43 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
44 static int enable_vss = 0;
45 #endif
46
47 extern CLIENT *me;                    /* our client resource */
48
49 /* Imported functions */
50 extern int status_cmd(JCR *jcr);
51 extern int qstatus_cmd(JCR *jcr);
52 extern int accurate_cmd(JCR *jcr);
53
54 /* Forward referenced functions */
55 static int backup_cmd(JCR *jcr);
56 static int bootstrap_cmd(JCR *jcr);
57 static int cancel_cmd(JCR *jcr);
58 static int setdebug_cmd(JCR *jcr);
59 static int estimate_cmd(JCR *jcr);
60 static int hello_cmd(JCR *jcr);
61 static int job_cmd(JCR *jcr);
62 static int fileset_cmd(JCR *jcr);
63 static int level_cmd(JCR *jcr);
64 static int verify_cmd(JCR *jcr);
65 static int restore_cmd(JCR *jcr);
66 static int storage_cmd(JCR *jcr);
67 static int session_cmd(JCR *jcr);
68 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
69 static void filed_free_jcr(JCR *jcr);
70 static int open_sd_read_session(JCR *jcr);
71 static int send_bootstrap_file(JCR *jcr);
72 static int runscript_cmd(JCR *jcr);
73 static int runbefore_cmd(JCR *jcr);
74 static int runafter_cmd(JCR *jcr);
75 static int runbeforenow_cmd(JCR *jcr);
76 static void set_options(findFOPTS *fo, const char *opts);
77
78
79 /* Exported functions */
80
81 struct s_cmds {
82    const char *cmd;
83    int (*func)(JCR *);
84    int monitoraccess; /* specify if monitors have access to this function */
85 };
86
87 /*
88  * The following are the recognized commands from the Director.
89  */
90 static struct s_cmds cmds[] = {
91    {"backup",       backup_cmd,    0},
92    {"cancel",       cancel_cmd,    0},
93    {"setdebug=",    setdebug_cmd,  0},
94    {"estimate",     estimate_cmd,  0},
95    {"Hello",        hello_cmd,     1},
96    {"fileset",      fileset_cmd,   0},
97    {"JobId=",       job_cmd,       0},
98    {"level = ",     level_cmd,     0},
99    {"restore",      restore_cmd,   0},
100    {"session",      session_cmd,   0},
101    {"status",       status_cmd,    1},
102    {".status",      qstatus_cmd,   1},
103    {"storage ",     storage_cmd,   0},
104    {"verify",       verify_cmd,    0},
105    {"bootstrap",    bootstrap_cmd, 0},
106    {"RunBeforeNow", runbeforenow_cmd, 0},
107    {"RunBeforeJob", runbefore_cmd, 0},
108    {"RunAfterJob",  runafter_cmd,  0},
109    {"Run",          runscript_cmd, 0},
110    {"accurate",     accurate_cmd,  0},
111    {NULL,       NULL}                  /* list terminator */
112 };
113
114 /* Commands received from director that need scanning */
115 static char jobcmd[]      = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
116 static char storaddr[]    = "storage address=%s port=%d ssl=%d";
117 static char sessioncmd[]  = "session %127s %ld %ld %ld %ld %ld %ld\n";
118 static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
119 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
120 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
121 static char verifycmd[]   = "verify level=%30s";
122 static char estimatecmd[] = "estimate listing=%d";
123 static char runbefore[]   = "RunBeforeJob %s";
124 static char runafter[]    = "RunAfterJob %s";
125 static char runscript[]   = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
126
127 /* Responses sent to Director */
128 static char errmsg[]      = "2999 Invalid command\n";
129 static char no_auth[]     = "2998 No Authorization\n";
130 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
131 static char OKinc[]       = "2000 OK include\n";
132 static char OKest[]       = "2000 OK estimate files=%u bytes=%s\n";
133 static char OKlevel[]     = "2000 OK level\n";
134 static char OKbackup[]    = "2000 OK backup\n";
135 static char OKbootstrap[] = "2000 OK bootstrap\n";
136 static char OKverify[]    = "2000 OK verify\n";
137 static char OKrestore[]   = "2000 OK restore\n";
138 static char OKsession[]   = "2000 OK session\n";
139 static char OKstore[]     = "2000 OK storage\n";
140 static char OKjob[]       = "2000 OK Job %s (%s) %s,%s,%s";
141 static char OKsetdebug[]  = "2000 OK setdebug=%d\n";
142 static char BADjob[]      = "2901 Bad Job\n";
143 static char EndJob[]      = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
144                             " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
145 static char OKRunBefore[] = "2000 OK RunBefore\n";
146 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
147 static char OKRunAfter[]  = "2000 OK RunAfter\n";
148 static char OKRunScript[] = "2000 OK RunScript\n";
149 static char BADcmd[]      = "2902 Bad %s\n";
150
151
152 /* Responses received from Storage Daemon */
153 static char OK_end[]       = "3000 OK end\n";
154 static char OK_close[]     = "3000 OK close Status = %d\n";
155 static char OK_open[]      = "3000 OK open ticket = %d\n";
156 static char OK_data[]      = "3000 OK data\n";
157 static char OK_append[]    = "3000 OK append data\n";
158 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
159
160
161 /* Commands sent to Storage Daemon */
162 static char append_open[]  = "append open session\n";
163 static char append_data[]  = "append data %d\n";
164 static char append_end[]   = "append end session %d\n";
165 static char append_close[] = "append close session %d\n";
166 static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
167 static char read_data[]    = "read data %d\n";
168 static char read_close[]   = "read close session %d\n";
169
170 /*
171  * Accept requests from a Director
172  *
173  * NOTE! We are running as a separate thread
174  *
175  * Send output one line
176  * at a time followed by a zero length transmission.
177  *
178  * Return when the connection is terminated or there
179  * is an error.
180  *
181  * Basic task here is:
182  *   Authenticate Director (during Hello command).
183  *   Accept commands one at a time from the Director
184  *     and execute them.
185  *
186  * Concerning ClientRunBefore/After, the sequence of events
187  * is rather critical. If they are not done in the right
188  * order one can easily get FD->SD timeouts if the script
189  * runs a long time.
190  *
191  * The current sequence of events is:
192  *  1. Dir starts job with FD
193  *  2. Dir connects to SD
194  *  3. Dir connects to FD
195  *  4. FD connects to SD
196  *  5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
197  *  6. Dir sends include/exclude
198  *  7. FD sends data to SD
199  *  8. SD/FD disconnects while SD despools data and attributes (optionnal)
200  *  9. FD runs ClientRunAfterJob
201  */
202
203 void *handle_client_request(void *dirp)
204 {
205    int i;
206    bool found, quit;
207    JCR *jcr;
208    BSOCK *dir = (BSOCK *)dirp;
209    const char jobname[12] = "*Director*";
210
211    jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
212    jcr->dir_bsock = dir;
213    jcr->ff = init_find_files();
214    jcr->start_time = time(NULL);
215    jcr->RunScripts = New(alist(10, not_owned_by_alist));
216    jcr->last_fname = get_pool_memory(PM_FNAME);
217    jcr->last_fname[0] = 0;
218    jcr->client_name = get_memory(strlen(my_name) + 1);
219    pm_strcpy(jcr->client_name, my_name);
220    bstrncpy(jcr->Job, jobname, sizeof(jobname));  /* dummy */
221    jcr->crypto.pki_sign = me->pki_sign;
222    jcr->crypto.pki_encrypt = me->pki_encrypt;
223    jcr->crypto.pki_keypair = me->pki_keypair;
224    jcr->crypto.pki_signers = me->pki_signers;
225    jcr->crypto.pki_recipients = me->pki_recipients;
226    dir->set_jcr(jcr);
227    enable_backup_privileges(NULL, 1 /* ignore_errors */);
228
229    /**********FIXME******* add command handler error code */
230
231    for (quit=false; !quit;) {
232       /* Read command */
233       if (dir->recv() < 0) {
234          break;               /* connection terminated */
235       }
236       dir->msg[dir->msglen] = 0;
237       Dmsg1(100, "<dird: %s", dir->msg);
238       found = false;
239       for (i=0; cmds[i].cmd; i++) {
240          if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
241             found = true;         /* indicate command found */
242             if (!jcr->authenticated && cmds[i].func != hello_cmd) {
243                dir->fsend(no_auth);
244                dir->signal(BNET_EOD);
245                break;
246             }
247             if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
248                Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
249                dir->fsend(invalid_cmd);
250                dir->signal(BNET_EOD);
251                break;
252             }
253             Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
254             if (!cmds[i].func(jcr)) {         /* do command */
255                quit = true;         /* error or fully terminated, get out */
256                Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
257             }
258             break;
259          }
260       }
261       if (!found) {              /* command not found */
262          dir->fsend(errmsg);
263          quit = true;
264          break;
265       }
266    }
267
268    /* Inform Storage daemon that we are done */
269    if (jcr->store_bsock) {
270       jcr->store_bsock->signal(BNET_TERMINATE);
271    }
272
273    /* Run the after job */
274    run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
275
276    if (jcr->JobId) {            /* send EndJob if running a job */
277       char ed1[50], ed2[50];
278       /* Send termination status back to Dir */
279       dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
280                  edit_uint64(jcr->ReadBytes, ed1),
281                  edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
282                  jcr->crypto.pki_encrypt);
283       Dmsg1(110, "End FD msg: %s\n", dir->msg);
284    }
285
286    generate_daemon_event(jcr, "JobEnd");
287    generate_plugin_event(jcr, bEventJobEnd);
288
289    dequeue_messages(jcr);             /* send any queued messages */
290
291    /* Inform Director that we are done */
292    dir->signal(BNET_TERMINATE);
293
294    free_plugins(jcr);                 /* release instantiated plugins */
295
296    /* Clean up fileset */
297    FF_PKT *ff = jcr->ff;
298    findFILESET *fileset = ff->fileset;
299    if (fileset) {
300       int i, j, k;
301       /* Delete FileSet Include lists */
302       for (i=0; i<fileset->include_list.size(); i++) {
303          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
304          for (j=0; j<incexe->opts_list.size(); j++) {
305             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
306             for (k=0; k<fo->regex.size(); k++) {
307                regfree((regex_t *)fo->regex.get(k));
308             }
309             for (k=0; k<fo->regexdir.size(); k++) {
310                regfree((regex_t *)fo->regexdir.get(k));
311             }
312             for (k=0; k<fo->regexfile.size(); k++) {
313                regfree((regex_t *)fo->regexfile.get(k));
314             }
315             fo->regex.destroy();
316             fo->regexdir.destroy();
317             fo->regexfile.destroy();
318             fo->wild.destroy();
319             fo->wilddir.destroy();
320             fo->wildfile.destroy();
321             fo->wildbase.destroy();
322             fo->base.destroy();
323             fo->fstype.destroy();
324             fo->drivetype.destroy();
325             if (fo->ignoredir != NULL) {
326                free(fo->ignoredir);
327             }
328          }
329          incexe->opts_list.destroy();
330          incexe->name_list.destroy();
331          incexe->plugin_list.destroy();
332       }
333       fileset->include_list.destroy();
334
335       /* Delete FileSet Exclude lists */
336       for (i=0; i<fileset->exclude_list.size(); i++) {
337          findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
338          for (j=0; j<incexe->opts_list.size(); j++) {
339             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
340             fo->regex.destroy();
341             fo->regexdir.destroy();
342             fo->regexfile.destroy();
343             fo->wild.destroy();
344             fo->wilddir.destroy();
345             fo->wildfile.destroy();
346             fo->wildbase.destroy();
347             fo->base.destroy();
348             fo->fstype.destroy();
349             fo->drivetype.destroy();
350          }
351          incexe->opts_list.destroy();
352          incexe->name_list.destroy();
353          incexe->plugin_list.destroy();
354       }
355       fileset->exclude_list.destroy();
356       free(fileset);
357    }
358    ff->fileset = NULL;
359    Dmsg0(100, "Calling term_find_files\n");
360    term_find_files(jcr->ff);
361    jcr->ff = NULL;
362    Dmsg0(100, "Done with term_find_files\n");
363    free_jcr(jcr);                     /* destroy JCR record */
364    Dmsg0(100, "Done with free_jcr\n");
365    Dsm_check(1);
366    return NULL;
367 }
368
369 /*
370  * Hello from Director he must identify himself and provide his
371  *  password.
372  */
373 static int hello_cmd(JCR *jcr)
374 {
375    Dmsg0(120, "Calling Authenticate\n");
376    if (!authenticate_director(jcr)) {
377       return 0;
378    }
379    Dmsg0(120, "OK Authenticate\n");
380    jcr->authenticated = true;
381    return 1;
382 }
383
384 /*
385  * Cancel a Job
386  */
387 static int cancel_cmd(JCR *jcr)
388 {
389    BSOCK *dir = jcr->dir_bsock;
390    char Job[MAX_NAME_LENGTH];
391    JCR *cjcr;
392
393    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
394       if (!(cjcr=get_jcr_by_full_name(Job))) {
395          dir->fsend(_("2901 Job %s not found.\n"), Job);
396       } else {
397          if (cjcr->store_bsock) {
398             cjcr->store_bsock->set_timed_out();
399             cjcr->store_bsock->set_terminated();
400             pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
401          }
402          generate_plugin_event(cjcr, bEventCancelCommand, NULL);
403          set_jcr_job_status(cjcr, JS_Canceled);
404          free_jcr(cjcr);
405          dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
406       }
407    } else {
408       dir->fsend(_("2902 Error scanning cancel command.\n"));
409    }
410    dir->signal(BNET_EOD);
411    return 1;
412 }
413
414
415 /*
416  * Set debug level as requested by the Director
417  *
418  */
419 static int setdebug_cmd(JCR *jcr)
420 {
421    BSOCK *dir = jcr->dir_bsock;
422    int level, trace_flag;
423
424    Dmsg1(110, "setdebug_cmd: %s", dir->msg);
425    if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
426       pm_strcpy(jcr->errmsg, dir->msg);
427       dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
428       return 0;
429    }
430    debug_level = level;
431    set_trace(trace_flag);
432    return dir->fsend(OKsetdebug, level);
433 }
434
435
436 static int estimate_cmd(JCR *jcr)
437 {
438    BSOCK *dir = jcr->dir_bsock;
439    char ed2[50];
440
441    if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
442       pm_strcpy(jcr->errmsg, dir->msg);
443       Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
444       dir->fsend(_("2992 Bad estimate command.\n"));
445       return 0;
446    }
447    make_estimate(jcr);
448    dir->fsend(OKest, jcr->num_files_examined,
449       edit_uint64_with_commas(jcr->JobBytes, ed2));
450    dir->signal(BNET_EOD);
451    return 1;
452 }
453
454 /*
455  * Get JobId and Storage Daemon Authorization key from Director
456  */
457 static int job_cmd(JCR *jcr)
458 {
459    BSOCK *dir = jcr->dir_bsock;
460    POOLMEM *sd_auth_key;
461
462    sd_auth_key = get_memory(dir->msglen);
463    if (sscanf(dir->msg, jobcmd,  &jcr->JobId, jcr->Job,
464               &jcr->VolSessionId, &jcr->VolSessionTime,
465               sd_auth_key) != 5) {
466       pm_strcpy(jcr->errmsg, dir->msg);
467       Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
468       dir->fsend(BADjob);
469       free_pool_memory(sd_auth_key);
470       return 0;
471    }
472    jcr->sd_auth_key = bstrdup(sd_auth_key);
473    free_pool_memory(sd_auth_key);
474    Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
475    Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
476    new_plugins(jcr);                  /* instantiate plugins for this jcr */
477    generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
478    return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
479 }
480
481 static int runbefore_cmd(JCR *jcr)
482 {
483    bool ok;
484    BSOCK *dir = jcr->dir_bsock;
485    POOLMEM *cmd = get_memory(dir->msglen+1);
486    RUNSCRIPT *script;
487
488    Dmsg1(100, "runbefore_cmd: %s", dir->msg);
489    if (sscanf(dir->msg, runbefore, cmd) != 1) {
490       pm_strcpy(jcr->errmsg, dir->msg);
491       Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
492       dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
493       free_memory(cmd);
494       return 0;
495    }
496    unbash_spaces(cmd);
497
498    /* Run the command now */
499    script = new_runscript();
500    script->set_command(cmd);
501    script->when = SCRIPT_Before;
502    ok = script->run(jcr, "ClientRunBeforeJob");
503    free_runscript(script);
504
505    free_memory(cmd);
506    if (ok) {
507       dir->fsend(OKRunBefore);
508       return 1;
509    } else {
510       dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
511       return 0;
512    }
513 }
514
515 static int runbeforenow_cmd(JCR *jcr)
516 {
517    BSOCK *dir = jcr->dir_bsock;
518
519    run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
520    if (job_canceled(jcr)) {
521       dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
522       Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
523       return 0;
524    } else {
525       dir->fsend(OKRunBeforeNow);
526       Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
527       return 1;
528    }
529 }
530
531 static int runafter_cmd(JCR *jcr)
532 {
533    BSOCK *dir = jcr->dir_bsock;
534    POOLMEM *msg = get_memory(dir->msglen+1);
535    RUNSCRIPT *cmd;
536
537    Dmsg1(100, "runafter_cmd: %s", dir->msg);
538    if (sscanf(dir->msg, runafter, msg) != 1) {
539       pm_strcpy(jcr->errmsg, dir->msg);
540       Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
541       dir->fsend(_("2905 Bad RunAfterJob command.\n"));
542       free_memory(msg);
543       return 0;
544    }
545    unbash_spaces(msg);
546
547    cmd = new_runscript();
548    cmd->set_command(msg);
549    cmd->on_success = true;
550    cmd->on_failure = false;
551    cmd->when = SCRIPT_After;
552
553    jcr->RunScripts->append(cmd);
554
555    free_pool_memory(msg);
556    return dir->fsend(OKRunAfter);
557 }
558
559 static int runscript_cmd(JCR *jcr)
560 {
561    BSOCK *dir = jcr->dir_bsock;
562    POOLMEM *msg = get_memory(dir->msglen+1);
563    int on_success, on_failure, fail_on_error;
564
565    RUNSCRIPT *cmd = new_runscript() ;
566
567    Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
568    /* Note, we cannot sscanf into bools */
569    if (sscanf(dir->msg, runscript, &on_success, 
570                                   &on_failure,
571                                   &fail_on_error,
572                                   &cmd->when,
573                                   msg) != 5) {
574       pm_strcpy(jcr->errmsg, dir->msg);
575       Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
576       dir->fsend(_("2905 Bad RunScript command.\n"));
577       free_runscript(cmd);
578       free_memory(msg);
579       return 0;
580    }
581    cmd->on_success = on_success;
582    cmd->on_failure = on_failure;
583    cmd->fail_on_error = fail_on_error;
584    unbash_spaces(msg);
585
586    cmd->set_command(msg);
587    cmd->debug();
588    jcr->RunScripts->append(cmd);
589
590    free_pool_memory(msg);
591    return dir->fsend(OKRunScript);
592 }
593
594
595 static bool init_fileset(JCR *jcr)
596 {
597    FF_PKT *ff;
598    findFILESET *fileset;
599
600    if (!jcr->ff) {
601       return false;
602    }
603    ff = jcr->ff;
604    if (ff->fileset) {
605       return false;
606    }
607    fileset = (findFILESET *)malloc(sizeof(findFILESET));
608    memset(fileset, 0, sizeof(findFILESET));
609    ff->fileset = fileset;
610    fileset->state = state_none;
611    fileset->include_list.init(1, true);
612    fileset->exclude_list.init(1, true);
613    return true;
614 }
615
616 static findFOPTS *start_options(FF_PKT *ff)
617 {
618    int state = ff->fileset->state;
619    findINCEXE *incexe = ff->fileset->incexe;
620
621    if (state != state_options) {
622       ff->fileset->state = state_options;
623       findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
624       memset(fo, 0, sizeof(findFOPTS));
625       fo->regex.init(1, true);
626       fo->regexdir.init(1, true);
627       fo->regexfile.init(1, true);
628       fo->wild.init(1, true);
629       fo->wilddir.init(1, true);
630       fo->wildfile.init(1, true);
631       fo->wildbase.init(1, true);
632       fo->base.init(1, true);
633       fo->fstype.init(1, true);
634       fo->drivetype.init(1, true);
635       incexe->current_opts = fo;
636       incexe->opts_list.append(fo);
637    }
638    return incexe->current_opts;
639
640 }
641
642 /*
643  * Add fname to include/exclude fileset list. First check for
644  * | and < and if necessary perform command.
645  */
646 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
647                                 bool is_file)
648 {
649    char *p;
650    BPIPE *bpipe;
651    POOLMEM *fn;
652    FILE *ffd;
653    char buf[1000];
654    int ch;
655    int stat;
656
657    p = (char *)fname;
658    ch = (uint8_t)*p;
659    switch (ch) {
660    case '|':
661       p++;                            /* skip over | */
662       fn = get_pool_memory(PM_FNAME);
663       fn = edit_job_codes(jcr, fn, p, "");
664       bpipe = open_bpipe(fn, 0, "r");
665       if (!bpipe) {
666          berrno be;
667          Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
668             p, be.bstrerror());
669          free_pool_memory(fn);
670          return;
671       }
672       free_pool_memory(fn);
673       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
674          strip_trailing_junk(buf);
675          if (is_file) {
676             fileset->incexe->name_list.append(new_dlistString(buf));
677          } else {
678             fileset->incexe->plugin_list.append(new_dlistString(buf));
679          }
680       }
681       if ((stat=close_bpipe(bpipe)) != 0) {
682          berrno be;
683          Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
684             p, be.code(stat), be.bstrerror(stat));
685          return;
686       }
687       break;
688    case '<':
689       Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
690       p++;                      /* skip over < */
691       if ((ffd = fopen(p, "rb")) == NULL) {
692          berrno be;
693          Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
694             p, be.bstrerror());
695          return;
696       }
697       while (fgets(buf, sizeof(buf), ffd)) {
698          strip_trailing_junk(buf);
699          Dmsg1(100, "%s\n", buf);
700          if (is_file) {
701             fileset->incexe->name_list.append(new_dlistString(buf));
702          } else {
703             fileset->incexe->plugin_list.append(new_dlistString(buf));
704          }
705       }
706       fclose(ffd);
707       break;
708    default:
709       if (is_file) {
710          fileset->incexe->name_list.append(new_dlistString(fname));
711       } else {
712          if (me->plugin_directory) {
713             fileset->incexe->plugin_list.append(new_dlistString(fname));
714          } else {
715             Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
716                fname);
717          }
718       }
719       break;
720    }
721 }
722
723
724 static void add_fileset(JCR *jcr, const char *item)
725 {
726    FF_PKT *ff = jcr->ff;
727    findFILESET *fileset = ff->fileset;
728    int state = fileset->state;
729    findFOPTS *current_opts;
730
731    /* Get code, optional subcode, and position item past the dividing space */
732    Dmsg1(100, "%s\n", item);
733    int code = item[0];
734    if (code != '\0') {
735       ++item;
736    }
737    int subcode = ' ';               /* A space is always a valid subcode */
738    if (item[0] != '\0' && item[0] != ' ') {
739       subcode = item[0];
740       ++item;
741    }
742    if (*item == ' ') {
743       ++item;
744    }
745
746    /* Skip all lines we receive after an error */
747    if (state == state_error) {
748       Dmsg0(100, "State=error return\n");
749       return;
750    }
751
752    /*
753     * The switch tests the code for validity.
754     * The subcode is always good if it is a space, otherwise we must confirm.
755     * We set state to state_error first assuming the subcode is invalid,
756     * requiring state to be set in cases below that handle subcodes.
757     */
758    if (subcode != ' ') {
759       state = state_error;
760       Dmsg0(100, "Set state=error or double code.\n");
761    }
762    switch (code) {
763    case 'I':
764       /* New include */
765       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
766       memset(fileset->incexe, 0, sizeof(findINCEXE));
767       fileset->incexe->opts_list.init(1, true);
768       fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
769       fileset->incexe->plugin_list.init();
770       fileset->include_list.append(fileset->incexe);
771       break;
772    case 'E':
773       /* New exclude */
774       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
775       memset(fileset->incexe, 0, sizeof(findINCEXE));
776       fileset->incexe->opts_list.init(1, true);
777       fileset->incexe->name_list.init();
778       fileset->incexe->plugin_list.init();
779       fileset->exclude_list.append(fileset->incexe);
780       break;
781    case 'N':
782       state = state_none;
783       break;
784    case 'F':
785       /* File item to include or exclude list */
786       state = state_include;
787       add_file_to_fileset(jcr, item, fileset, true);
788       break;
789    case 'P':
790       /* Plugin item to include list */
791       state = state_include;
792       add_file_to_fileset(jcr, item, fileset, false);
793       break;
794    case 'R':
795       current_opts = start_options(ff);
796       regex_t *preg;
797       int rc;
798       char prbuf[500];
799       preg = (regex_t *)malloc(sizeof(regex_t));
800       if (current_opts->flags & FO_IGNORECASE) {
801          rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
802       } else {
803          rc = regcomp(preg, item, REG_EXTENDED);
804       }
805       if (rc != 0) {
806          regerror(rc, preg, prbuf, sizeof(prbuf));
807          regfree(preg);
808          free(preg);
809          Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
810          state = state_error;
811          break;
812       }
813       state = state_options;
814       if (subcode == ' ') {
815          current_opts->regex.append(preg);
816       } else if (subcode == 'D') {
817          current_opts->regexdir.append(preg);
818       } else if (subcode == 'F') {
819          current_opts->regexfile.append(preg);
820       } else {
821          state = state_error;
822       }
823       break;
824    case 'B':
825       current_opts = start_options(ff);
826       current_opts->base.append(bstrdup(item));
827       state = state_options;
828       break;
829    case 'X':
830       current_opts = start_options(ff);
831       state = state_options;
832       if (subcode == ' ') {
833          current_opts->fstype.append(bstrdup(item));
834       } else if (subcode == 'D') {
835          current_opts->drivetype.append(bstrdup(item));
836       } else {
837          state = state_error;
838       }
839       break;
840    case 'W':
841       current_opts = start_options(ff);
842       state = state_options;
843       if (subcode == ' ') {
844          current_opts->wild.append(bstrdup(item));
845       } else if (subcode == 'D') {
846          current_opts->wilddir.append(bstrdup(item));
847       } else if (subcode == 'F') {
848          current_opts->wildfile.append(bstrdup(item));
849       } else if (subcode == 'B') {
850          current_opts->wildbase.append(bstrdup(item));
851       } else {
852          state = state_error;
853       }
854       break;
855    case 'O':
856       current_opts = start_options(ff);
857       set_options(current_opts, item);
858       state = state_options;
859       break;
860    case 'Z':
861       current_opts = start_options(ff);
862       current_opts->ignoredir = bstrdup(item);
863       state = state_options;
864       break;
865    case 'D':
866       current_opts = start_options(ff);
867 //    current_opts->reader = bstrdup(item);
868       state = state_options;
869       break;
870    case 'T':
871       current_opts = start_options(ff);
872 //    current_opts->writer = bstrdup(item);
873       state = state_options;
874       break;
875    default:
876       Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
877       state = state_error;
878       break;
879    }
880    ff->fileset->state = state;
881 }
882
883 static bool term_fileset(JCR *jcr)
884 {
885    FF_PKT *ff = jcr->ff;
886
887 #ifdef xxx_DEBUG_CODE
888    findFILESET *fileset = ff->fileset;
889    int i, j, k;
890
891    for (i=0; i<fileset->include_list.size(); i++) {
892       findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
893       Dmsg0(400, "I\n");
894       for (j=0; j<incexe->opts_list.size(); j++) {
895          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
896          for (k=0; k<fo->regex.size(); k++) {
897             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
898          }
899          for (k=0; k<fo->regexdir.size(); k++) {
900             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
901          }
902          for (k=0; k<fo->regexfile.size(); k++) {
903             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
904          }
905          for (k=0; k<fo->wild.size(); k++) {
906             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
907          }
908          for (k=0; k<fo->wilddir.size(); k++) {
909             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
910          }
911          for (k=0; k<fo->wildfile.size(); k++) {
912             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
913          }
914          for (k=0; k<fo->wildbase.size(); k++) {
915             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
916          }
917          for (k=0; k<fo->base.size(); k++) {
918             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
919          }
920          for (k=0; k<fo->fstype.size(); k++) {
921             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
922          }
923          for (k=0; k<fo->drivetype.size(); k++) {
924             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
925          }
926          if (fo->ignoredir) {
927             Dmsg1(400, "Z %s\n", fo->ignoredir);
928          }
929       }
930       dlistString *node;
931       foreach_dlist(node, &incexe->name_list) {
932          Dmsg1(400, "F %s\n", node->c_str());
933       }
934       foreach_dlist(node, &incexe->plugin_list) {
935          Dmsg1(400, "P %s\n", node->c_str());
936       }
937    }
938    for (i=0; i<fileset->exclude_list.size(); i++) {
939       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
940       Dmsg0(400, "E\n");
941       for (j=0; j<incexe->opts_list.size(); j++) {
942          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
943          for (k=0; k<fo->regex.size(); k++) {
944             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
945          }
946          for (k=0; k<fo->regexdir.size(); k++) {
947             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
948          }
949          for (k=0; k<fo->regexfile.size(); k++) {
950             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
951          }
952          for (k=0; k<fo->wild.size(); k++) {
953             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
954          }
955          for (k=0; k<fo->wilddir.size(); k++) {
956             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
957          }
958          for (k=0; k<fo->wildfile.size(); k++) {
959             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
960          }
961          for (k=0; k<fo->wildbase.size(); k++) {
962             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
963          }
964          for (k=0; k<fo->base.size(); k++) {
965             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
966          }
967          for (k=0; k<fo->fstype.size(); k++) {
968             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
969          }
970          for (k=0; k<fo->drivetype.size(); k++) {
971             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
972          }
973       }
974       dlistString *node;
975       foreach_dlist(node, incexe->name_list) {
976          Dmsg1(400, "F %s\n", node->c_str());
977       }
978       foreach_dlist(node, &incexe->plugin_list) {
979          Dmsg1(400, "P %s\n", node->c_str());
980       }
981    }
982 #endif
983    return ff->fileset->state != state_error;
984 }
985
986
987 /*
988  * As an optimization, we should do this during
989  *  "compile" time in filed/job.c, and keep only a bit mask
990  *  and the Verify options.
991  */
992 static void set_options(findFOPTS *fo, const char *opts)
993 {
994    int j;
995    const char *p;
996    char strip[100];
997
998 // Commented out as it is not backward compatible - KES
999 #ifdef HAVE_WIN32
1000 //   fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1001 #endif
1002
1003    for (p=opts; *p; p++) {
1004       switch (*p) {
1005       case 'a':                 /* alway replace */
1006       case '0':                 /* no option */
1007          break;
1008       case 'e':
1009          fo->flags |= FO_EXCLUDE;
1010          break;
1011       case 'f':
1012          fo->flags |= FO_MULTIFS;
1013          break;
1014       case 'h':                 /* no recursion */
1015          fo->flags |= FO_NO_RECURSION;
1016          break;
1017       case 'H':                 /* no hard link handling */
1018          fo->flags |= FO_NO_HARDLINK;
1019          break;
1020       case 'i':
1021          fo->flags |= FO_IGNORECASE;
1022          break;
1023       case 'M':                 /* MD5 */
1024          fo->flags |= FO_MD5;
1025          break;
1026       case 'n':
1027          fo->flags |= FO_NOREPLACE;
1028          break;
1029       case 'p':                 /* use portable data format */
1030          fo->flags |= FO_PORTABLE;
1031          break;
1032       case 'R':                 /* Resource forks and Finder Info */
1033          fo->flags |= FO_HFSPLUS;
1034       case 'r':                 /* read fifo */
1035          fo->flags |= FO_READFIFO;
1036          break;
1037       case 'S':
1038          switch(*(p + 1)) {
1039          case '1':
1040             fo->flags |= FO_SHA1;
1041             p++;
1042             break;
1043 #ifdef HAVE_SHA2
1044          case '2':
1045             fo->flags |= FO_SHA256;
1046             p++;
1047             break;
1048          case '3':
1049             fo->flags |= FO_SHA512;
1050             p++;
1051             break;
1052 #endif
1053          default:
1054             /*
1055              * If 2 or 3 is seen here, SHA2 is not configured, so
1056              *  eat the option, and drop back to SHA-1.
1057              */
1058             if (p[1] == '2' || p[1] == '3') {
1059                p++;
1060             }
1061             fo->flags |= FO_SHA1;
1062             break;
1063          }
1064          break;
1065       case 's':
1066          fo->flags |= FO_SPARSE;
1067          break;
1068       case 'm':
1069          fo->flags |= FO_MTIMEONLY;
1070          break;
1071       case 'k':
1072          fo->flags |= FO_KEEPATIME;
1073          break;
1074       case 'A':
1075          fo->flags |= FO_ACL;
1076          break;
1077       case 'V':                  /* verify options */
1078          /* Copy Verify Options */
1079          for (j=0; *p && *p != ':'; p++) {
1080             fo->VerifyOpts[j] = *p;
1081             if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1082                j++;
1083             }
1084          }
1085          fo->VerifyOpts[j] = 0;
1086          break;
1087       case 'C':                  /* accurate options */
1088          /* Copy Accurate Options */
1089          for (j=0; *p && *p != ':'; p++) {
1090             fo->AccurateOpts[j] = *p;
1091             if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1092                j++;
1093             }
1094          }
1095          fo->AccurateOpts[j] = 0;
1096          break;
1097       case 'P':                  /* strip path */
1098          /* Get integer */
1099          p++;                    /* skip P */
1100          for (j=0; *p && *p != ':'; p++) {
1101             strip[j] = *p;
1102             if (j < (int)sizeof(strip) - 1) {
1103                j++;
1104             }
1105          }
1106          strip[j] = 0;
1107          fo->strip_path = atoi(strip);
1108          fo->flags |= FO_STRIPPATH;
1109          Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1110          break;
1111       case 'w':
1112          fo->flags |= FO_IF_NEWER;
1113          break;
1114       case 'W':
1115          fo->flags |= FO_ENHANCEDWILD;
1116          break;
1117       case 'Z':                 /* gzip compression */
1118          fo->flags |= FO_GZIP;
1119          fo->GZIP_level = *++p - '0';
1120          break;
1121       case 'K':
1122          fo->flags |= FO_NOATIME;
1123          break;
1124       case 'c':
1125          fo->flags |= FO_CHKCHANGES;
1126          break;
1127       case 'N':
1128          fo->flags |= FO_HONOR_NODUMP;
1129          break;
1130       case 'X':
1131          fo->flags |= FO_XATTR;
1132          break;
1133       default:
1134          Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1135          break;
1136       }
1137    }
1138 }
1139
1140
1141 /*
1142  * Director is passing his Fileset
1143  */
1144 static int fileset_cmd(JCR *jcr)
1145 {
1146    BSOCK *dir = jcr->dir_bsock;
1147
1148 #if defined(WIN32_VSS)
1149    int vss = 0;
1150
1151    sscanf(dir->msg, "fileset vss=%d", &vss);
1152    enable_vss = vss;
1153 #endif
1154
1155    if (!init_fileset(jcr)) {
1156       return 0;
1157    }
1158    while (dir->recv() >= 0) {
1159       strip_trailing_junk(dir->msg);
1160       Dmsg1(500, "Fileset: %s\n", dir->msg);
1161       add_fileset(jcr, dir->msg);
1162    }
1163    if (!term_fileset(jcr)) {
1164       return 0;
1165    }
1166    return dir->fsend(OKinc);
1167 }
1168
1169 static void free_bootstrap(JCR *jcr)
1170 {
1171    if (jcr->RestoreBootstrap) {
1172       unlink(jcr->RestoreBootstrap);
1173       free_pool_memory(jcr->RestoreBootstrap);
1174       jcr->RestoreBootstrap = NULL;
1175    }
1176 }
1177
1178
1179 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1180 static uint32_t bsr_uniq = 0;
1181
1182 /* 
1183  * The Director sends us the bootstrap file, which
1184  *   we will in turn pass to the SD.
1185  */
1186 static int bootstrap_cmd(JCR *jcr)
1187 {
1188    BSOCK *dir = jcr->dir_bsock;
1189    POOLMEM *fname = get_pool_memory(PM_FNAME);
1190    FILE *bs;
1191
1192    free_bootstrap(jcr);
1193    P(bsr_mutex);
1194    bsr_uniq++;
1195    Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1196       jcr->Job, bsr_uniq);
1197    V(bsr_mutex);
1198    Dmsg1(400, "bootstrap=%s\n", fname);
1199    jcr->RestoreBootstrap = fname;
1200    bs = fopen(fname, "a+b");           /* create file */
1201    if (!bs) {
1202       berrno be;
1203       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1204          jcr->RestoreBootstrap, be.bstrerror());
1205       /*
1206        * Suck up what he is sending to us so that he will then
1207        *   read our error message.
1208        */
1209       while (dir->recv() >= 0)
1210         {  }
1211       free_bootstrap(jcr);
1212       set_jcr_job_status(jcr, JS_ErrorTerminated);
1213       return 0;
1214    }
1215
1216    while (dir->recv() >= 0) {
1217        Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1218        fputs(dir->msg, bs);
1219    }
1220    fclose(bs);
1221    /*
1222     * Note, do not free the bootstrap yet -- it needs to be 
1223     *  sent to the SD 
1224     */
1225    return dir->fsend(OKbootstrap);
1226 }
1227
1228
1229 /*
1230  * Get backup level from Director
1231  *
1232  */
1233 static int level_cmd(JCR *jcr)
1234 {
1235    BSOCK *dir = jcr->dir_bsock;
1236    POOLMEM *level, *buf = NULL;
1237    int mtime_only;
1238
1239    level = get_memory(dir->msglen+1);
1240    Dmsg1(100, "level_cmd: %s", dir->msg);
1241    if (strstr(dir->msg, "accurate")) {
1242       jcr->accurate = true;
1243    }
1244    if (sscanf(dir->msg, "level = %s ", level) != 1) {
1245       goto bail_out;
1246    }
1247    /* Base backup requested? */
1248    if (strcmp(level, "base") == 0) {
1249       jcr->set_JobLevel(L_BASE);
1250    /* Full backup requested? */
1251    } else if (strcmp(level, "full") == 0) {
1252       jcr->set_JobLevel(L_FULL);
1253    } else if (strstr(level, "differential")) {
1254       jcr->set_JobLevel(L_DIFFERENTIAL);
1255       free_memory(level);
1256       return 1;
1257    } else if (strstr(level, "incremental")) {
1258       jcr->set_JobLevel(L_INCREMENTAL);
1259       free_memory(level);
1260       return 1;
1261    /*
1262     * We get his UTC since time, then sync the clocks and correct it
1263     *   to agree with our clock.
1264     */
1265    } else if (strcmp(level, "since_utime") == 0) {
1266       buf = get_memory(dir->msglen+1);
1267       utime_t since_time, adj;
1268       btime_t his_time, bt_start, rt=0, bt_adj=0;
1269       if (jcr->get_JobLevel() == L_NONE) {
1270          jcr->set_JobLevel(L_SINCE);     /* if no other job level set, do it now */
1271       }
1272       if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1273                  buf, &mtime_only) != 2) {
1274          goto bail_out;
1275       }
1276       since_time = str_to_uint64(buf);  /* this is the since time */
1277       Dmsg1(100, "since_time=%lld\n", since_time);
1278       char ed1[50], ed2[50];
1279       /*
1280        * Sync clocks by polling him for the time. We take
1281        *   10 samples of his time throwing out the first two.
1282        */
1283       for (int i=0; i<10; i++) {
1284          bt_start = get_current_btime();
1285          dir->signal(BNET_BTIME);     /* poll for time */
1286          if (dir->recv() <= 0) {      /* get response */
1287             goto bail_out;
1288          }
1289          if (sscanf(dir->msg, "btime %s", buf) != 1) {
1290             goto bail_out;
1291          }
1292          if (i < 2) {                 /* toss first two results */
1293             continue;
1294          }
1295          his_time = str_to_uint64(buf);
1296          rt = get_current_btime() - bt_start; /* compute round trip time */
1297          Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1298                edit_uint64(bt_start, ed2));
1299          bt_adj +=  bt_start - his_time - rt/2;
1300          Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1301       }
1302
1303       bt_adj = bt_adj / 8;            /* compute average time */
1304       Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1305       adj = btime_to_utime(bt_adj);
1306       since_time += adj;              /* adjust for clock difference */
1307       /* Don't notify if time within 3 seconds */
1308       if (adj > 3 || adj < -3) {
1309          int type;
1310          if (adj > 600 || adj < -600) {
1311             type = M_WARNING;
1312          } else {
1313             type = M_INFO;
1314          }
1315          Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1316       }
1317       dir->signal(BNET_EOD);
1318
1319       Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1320       jcr->incremental = 1;           /* set incremental or decremental backup */
1321       jcr->mtime = since_time;        /* set since time */
1322       generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1323    } else {
1324       Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1325       free_memory(level);
1326       return 0;
1327    }
1328    free_memory(level);
1329    if (buf) {
1330       free_memory(buf);
1331    }
1332    generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1333    return dir->fsend(OKlevel);
1334
1335 bail_out:
1336    pm_strcpy(jcr->errmsg, dir->msg);
1337    Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1338    free_memory(level);
1339    if (buf) {
1340       free_memory(buf);
1341    }
1342    return 0;
1343 }
1344
1345 /*
1346  * Get session parameters from Director -- this is for a Restore command
1347  */
1348 static int session_cmd(JCR *jcr)
1349 {
1350    BSOCK *dir = jcr->dir_bsock;
1351
1352    Dmsg1(100, "SessionCmd: %s", dir->msg);
1353    if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1354               &jcr->VolSessionId, &jcr->VolSessionTime,
1355               &jcr->StartFile, &jcr->EndFile,
1356               &jcr->StartBlock, &jcr->EndBlock) != 7) {
1357       pm_strcpy(jcr->errmsg, dir->msg);
1358       Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1359       return 0;
1360    }
1361
1362    return dir->fsend(OKsession);
1363 }
1364
1365 /*
1366  * Get address of storage daemon from Director
1367  *
1368  */
1369 static int storage_cmd(JCR *jcr)
1370 {
1371    int stored_port;                /* storage daemon port */
1372    int enable_ssl;                 /* enable ssl to sd */
1373    BSOCK *dir = jcr->dir_bsock;
1374    BSOCK *sd;                         /* storage daemon bsock */
1375
1376    Dmsg1(100, "StorageCmd: %s", dir->msg);
1377    if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1378       pm_strcpy(jcr->errmsg, dir->msg);
1379       Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1380       goto bail_out;
1381    }
1382    Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1383    /* Open command communications with Storage daemon */
1384    /* Try to connect for 1 hour at 10 second intervals */
1385    sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1386                       _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1387    if (sd == NULL) {
1388       Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1389           jcr->stored_addr, stored_port);
1390       Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1391           jcr->stored_addr, stored_port);
1392       goto bail_out;
1393    }
1394    Dmsg0(110, "Connection OK to SD.\n");
1395
1396    jcr->store_bsock = sd;
1397
1398    sd->fsend("Hello Start Job %s\n", jcr->Job);
1399    if (!authenticate_storagedaemon(jcr)) {
1400       Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1401       goto bail_out;
1402    }
1403    Dmsg0(110, "Authenticated with SD.\n");
1404
1405    /* Send OK to Director */
1406    return dir->fsend(OKstore);
1407
1408 bail_out:
1409       dir->fsend(BADcmd, "storage");
1410       return 0;
1411
1412 }
1413
1414
1415 /*
1416  * Do a backup.
1417  */
1418 static int backup_cmd(JCR *jcr)
1419 {
1420    BSOCK *dir = jcr->dir_bsock;
1421    BSOCK *sd = jcr->store_bsock;
1422    int ok = 0;
1423    int SDJobStatus;
1424
1425 #if defined(WIN32_VSS)
1426    // capture state here, if client is backed up by multiple directors
1427    // and one enables vss and the other does not then enable_vss can change
1428    // between here and where its evaluated after the job completes.
1429    jcr->VSS = g_pVSSClient && enable_vss;
1430    if (jcr->VSS) {
1431       /* Run only one at a time */
1432       P(vss_mutex);
1433    }
1434 #endif
1435
1436    set_jcr_job_status(jcr, JS_Blocked);
1437    jcr->set_JobType(JT_BACKUP);
1438    Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1439
1440    if (sd == NULL) {
1441       Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1442       dir->fsend(BADcmd, "backup");
1443       goto cleanup;
1444    }
1445
1446    dir->fsend(OKbackup);
1447    Dmsg1(110, "filed>dird: %s", dir->msg);
1448
1449    /*
1450     * Send Append Open Session to Storage daemon
1451     */
1452    sd->fsend(append_open);
1453    Dmsg1(110, ">stored: %s", sd->msg);
1454    /*
1455     * Expect to receive back the Ticket number
1456     */
1457    if (bget_msg(sd) >= 0) {
1458       Dmsg1(110, "<stored: %s", sd->msg);
1459       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1460          Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1461          goto cleanup;
1462       }
1463       Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1464    } else {
1465       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1466       goto cleanup;
1467    }
1468
1469    /*
1470     * Send Append data command to Storage daemon
1471     */
1472    sd->fsend(append_data, jcr->Ticket);
1473    Dmsg1(110, ">stored: %s", sd->msg);
1474
1475    /*
1476     * Expect to get OK data
1477     */
1478    Dmsg1(110, "<stored: %s", sd->msg);
1479    if (!response(jcr, sd, OK_data, "Append Data")) {
1480       goto cleanup;
1481    }
1482    
1483    generate_daemon_event(jcr, "JobStart");
1484    generate_plugin_event(jcr, bEventStartBackupJob);
1485
1486 #if defined(WIN32_VSS)
1487    /* START VSS ON WIN32 */
1488    if (jcr->VSS) {      
1489       if (g_pVSSClient->InitializeForBackup()) {   
1490         /* tell vss which drives to snapshot */   
1491         char szWinDriveLetters[27];   
1492         if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1493             Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1494             if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {               
1495                Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1496                jcr->JobErrors++;
1497             } else {
1498                /* tell user if snapshot creation of a specific drive failed */
1499                int i;
1500                for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1501                   if (islower(szWinDriveLetters[i])) {
1502                      Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1503                      jcr->JobErrors++;
1504                   }
1505                }
1506                /* inform user about writer states */
1507                for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)                
1508                   if (g_pVSSClient->GetWriterState(i) < 1) {
1509                      Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));                    
1510                      jcr->JobErrors++;
1511                   }                            
1512             }
1513         } else {
1514             Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1515         }
1516       } else {
1517          berrno be;
1518          Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1519       } 
1520       run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1521    }
1522 #endif
1523
1524    /*
1525     * Send Files to Storage daemon
1526     */
1527    Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1528    if (!blast_data_to_storage_daemon(jcr, NULL)) {
1529       set_jcr_job_status(jcr, JS_ErrorTerminated);
1530       bnet_suppress_error_messages(sd, 1);
1531       bget_msg(sd);                   /* Read final response from append_data */
1532       Dmsg0(110, "Error in blast_data.\n");
1533    } else {
1534       set_jcr_job_status(jcr, JS_Terminated);
1535       /* Note, the above set status will not override an error */
1536       if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1537          bnet_suppress_error_messages(sd, 1);
1538          goto cleanup;                /* bail out now */
1539       }
1540       /*
1541        * Expect to get response to append_data from Storage daemon
1542        */
1543       if (!response(jcr, sd, OK_append, "Append Data")) {
1544          set_jcr_job_status(jcr, JS_ErrorTerminated);
1545          goto cleanup;
1546       }
1547
1548       /*
1549        * Send Append End Data to Storage daemon
1550        */
1551       sd->fsend(append_end, jcr->Ticket);
1552       /* Get end OK */
1553       if (!response(jcr, sd, OK_end, "Append End")) {
1554          set_jcr_job_status(jcr, JS_ErrorTerminated);
1555          goto cleanup;
1556       }
1557
1558       /*
1559        * Send Append Close to Storage daemon
1560        */
1561       sd->fsend(append_close, jcr->Ticket);
1562       while (bget_msg(sd) >= 0) {    /* stop on signal or error */
1563          if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1564             ok = 1;
1565             Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1566          }
1567       }
1568       if (!ok) {
1569          Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1570          goto cleanup;
1571       }
1572       if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1573          Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1574             SDJobStatus);
1575       }
1576    }
1577
1578 cleanup:
1579 #if defined(WIN32_VSS)
1580    /* STOP VSS ON WIN32 */
1581    /* tell vss to close the backup session */
1582    if (jcr->VSS) {
1583       if (g_pVSSClient->CloseBackup()) {             
1584          /* inform user about writer states */
1585          for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1586             int msg_type = M_INFO;
1587             if (g_pVSSClient->GetWriterState(i) < 1) {
1588                msg_type = M_WARNING;
1589                jcr->JobErrors++;
1590             }
1591             Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1592          }
1593       }
1594       Win32ConvCleanupCache();
1595       V(vss_mutex);
1596    }
1597 #endif
1598
1599    generate_plugin_event(jcr, bEventEndBackupJob);
1600    return 0;                          /* return and stop command loop */
1601 }
1602
1603 /*
1604  * Do a Verify for Director
1605  *
1606  */
1607 static int verify_cmd(JCR *jcr)
1608 {
1609    BSOCK *dir = jcr->dir_bsock;
1610    BSOCK *sd  = jcr->store_bsock;
1611    char level[100];
1612
1613    jcr->set_JobType(JT_VERIFY);
1614    if (sscanf(dir->msg, verifycmd, level) != 1) {
1615       dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1616       return 0;
1617    }
1618
1619    if (strcasecmp(level, "init") == 0) {
1620       jcr->set_JobLevel(L_VERIFY_INIT);
1621    } else if (strcasecmp(level, "catalog") == 0){
1622       jcr->set_JobLevel(L_VERIFY_CATALOG);
1623    } else if (strcasecmp(level, "volume") == 0){
1624       jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1625    } else if (strcasecmp(level, "data") == 0){
1626       jcr->set_JobLevel(L_VERIFY_DATA);
1627    } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1628       jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1629    } else {
1630       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1631       return 0;
1632    }
1633
1634    dir->fsend(OKverify);
1635
1636    generate_daemon_event(jcr, "JobStart");
1637    generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1638    generate_plugin_event(jcr, bEventStartVerifyJob);
1639
1640    Dmsg1(110, "filed>dird: %s", dir->msg);
1641
1642    switch (jcr->get_JobLevel()) {
1643    case L_VERIFY_INIT:
1644    case L_VERIFY_CATALOG:
1645       do_verify(jcr);
1646       break;
1647    case L_VERIFY_VOLUME_TO_CATALOG:
1648       if (!open_sd_read_session(jcr)) {
1649          return 0;
1650       }
1651       start_dir_heartbeat(jcr);
1652       do_verify_volume(jcr);
1653       stop_dir_heartbeat(jcr);
1654       /*
1655        * Send Close session command to Storage daemon
1656        */
1657       sd->fsend(read_close, jcr->Ticket);
1658       Dmsg1(130, "filed>stored: %s", sd->msg);
1659
1660       /* ****FIXME**** check response */
1661       bget_msg(sd);                      /* get OK */
1662
1663       /* Inform Storage daemon that we are done */
1664       sd->signal(BNET_TERMINATE);
1665
1666       break;
1667    case L_VERIFY_DISK_TO_CATALOG:
1668       do_verify(jcr);
1669       break;
1670    default:
1671       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1672       return 0;
1673    }
1674
1675    dir->signal(BNET_EOD);
1676    generate_plugin_event(jcr, bEventEndVerifyJob);
1677    return 0;                          /* return and terminate command loop */
1678 }
1679
1680 /*
1681  * Do a Restore for Director
1682  *
1683  */
1684 static int restore_cmd(JCR *jcr)
1685 {
1686    BSOCK *dir = jcr->dir_bsock;
1687    BSOCK *sd = jcr->store_bsock;
1688    POOLMEM *args;
1689    bool use_regexwhere=false;
1690    int prefix_links;
1691    char replace;
1692
1693    /*
1694     * Scan WHERE (base directory for restore) from command
1695     */
1696    Dmsg0(150, "restore command\n");
1697    /* Pickup where string */
1698    args = get_memory(dir->msglen+1);
1699    *args = 0;
1700
1701    if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1702       if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1703          if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1704             pm_strcpy(jcr->errmsg, dir->msg);
1705             Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1706             return 0;
1707          }
1708          *args = 0;
1709       }
1710       use_regexwhere = true;
1711    }
1712    /* Turn / into nothing */
1713    if (IsPathSeparator(args[0]) && args[1] == '\0') {
1714       args[0] = '\0';
1715    }
1716
1717    Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1718    unbash_spaces(args);
1719
1720    if (use_regexwhere) {
1721       jcr->where_bregexp = get_bregexps(args);
1722       if (!jcr->where_bregexp) {
1723          Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1724          free_pool_memory(args);
1725          return 0;
1726       }
1727    } else {
1728       jcr->where = bstrdup(args);
1729    }
1730
1731    free_pool_memory(args);
1732    jcr->replace = replace;
1733    jcr->prefix_links = prefix_links;
1734
1735    dir->fsend(OKrestore);
1736    Dmsg1(110, "filed>dird: %s", dir->msg);
1737
1738    jcr->set_JobType(JT_RESTORE);
1739
1740    set_jcr_job_status(jcr, JS_Blocked);
1741
1742    if (!open_sd_read_session(jcr)) {
1743       set_jcr_job_status(jcr, JS_ErrorTerminated);
1744       goto bail_out;
1745    }
1746
1747    set_jcr_job_status(jcr, JS_Running);
1748
1749    /*
1750     * Do restore of files and data
1751     */
1752    start_dir_heartbeat(jcr);
1753    generate_daemon_event(jcr, "JobStart");
1754    generate_plugin_event(jcr, bEventStartRestoreJob);
1755    do_restore(jcr);
1756    stop_dir_heartbeat(jcr);
1757
1758    set_jcr_job_status(jcr, JS_Terminated);
1759    if (jcr->JobStatus != JS_Terminated) {
1760       bnet_suppress_error_messages(sd, 1);
1761    }
1762
1763    /*
1764     * Send Close session command to Storage daemon
1765     */
1766    sd->fsend(read_close, jcr->Ticket);
1767    Dmsg1(130, "filed>stored: %s", sd->msg);
1768
1769    bget_msg(sd);                      /* get OK */
1770
1771    /* Inform Storage daemon that we are done */
1772    sd->signal(BNET_TERMINATE);
1773
1774 bail_out:
1775
1776    if (jcr->JobErrors) {
1777       set_jcr_job_status(jcr, JS_ErrorTerminated);
1778    }
1779
1780    Dmsg0(130, "Done in job.c\n");
1781    generate_plugin_event(jcr, bEventEndRestoreJob);
1782    return 0;                          /* return and terminate command loop */
1783 }
1784
1785 static int open_sd_read_session(JCR *jcr)
1786 {
1787    BSOCK *sd = jcr->store_bsock;
1788
1789    if (!sd) {
1790       Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1791       return 0;
1792    }
1793    Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1794       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1795    Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1796    /*
1797     * Open Read Session with Storage daemon
1798     */
1799    sd->fsend(read_open, "DummyVolume",
1800       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1801       jcr->StartBlock, jcr->EndBlock);
1802    Dmsg1(110, ">stored: %s", sd->msg);
1803
1804    /*
1805     * Get ticket number
1806     */
1807    if (bget_msg(sd) >= 0) {
1808       Dmsg1(110, "filed<stored: %s", sd->msg);
1809       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1810          Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1811          return 0;
1812       }
1813       Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1814    } else {
1815       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1816       return 0;
1817    }
1818
1819    if (!send_bootstrap_file(jcr)) {
1820       return 0;
1821    }
1822
1823    /*
1824     * Start read of data with Storage daemon
1825     */
1826    sd->fsend(read_data, jcr->Ticket);
1827    Dmsg1(110, ">stored: %s", sd->msg);
1828
1829    /*
1830     * Get OK data
1831     */
1832    if (!response(jcr, sd, OK_data, "Read Data")) {
1833       return 0;
1834    }
1835    return 1;
1836 }
1837
1838 /*
1839  * Destroy the Job Control Record and associated
1840  * resources (sockets).
1841  */
1842 static void filed_free_jcr(JCR *jcr)
1843 {
1844    if (jcr->store_bsock) {
1845       jcr->store_bsock->close();
1846    }
1847    free_bootstrap(jcr);
1848    if (jcr->last_fname) {
1849       free_pool_memory(jcr->last_fname);
1850    }
1851    free_runscripts(jcr->RunScripts);
1852    delete jcr->RunScripts;
1853
1854    if (jcr->JobId != 0)
1855       write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1856
1857    return;
1858 }
1859
1860 /*
1861  * Get response from Storage daemon to a command we
1862  * sent. Check that the response is OK.
1863  *
1864  *  Returns: 0 on failure
1865  *           1 on success
1866  */
1867 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1868 {
1869    if (sd->errors) {
1870       return 0;
1871    }
1872    if (bget_msg(sd) > 0) {
1873       Dmsg0(110, sd->msg);
1874       if (strcmp(sd->msg, resp) == 0) {
1875          return 1;
1876       }
1877    }
1878    if (job_canceled(jcr)) {
1879       return 0;                       /* if canceled avoid useless error messages */
1880    }
1881    if (is_bnet_error(sd)) {
1882       Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1883          cmd, bnet_strerror(sd));
1884    } else {
1885       Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1886          cmd, resp, sd->msg);
1887    }
1888    return 0;
1889 }
1890
1891 static int send_bootstrap_file(JCR *jcr)
1892 {
1893    FILE *bs;
1894    char buf[2000];
1895    BSOCK *sd = jcr->store_bsock;
1896    const char *bootstrap = "bootstrap\n";
1897    int stat = 0;
1898
1899    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1900    if (!jcr->RestoreBootstrap) {
1901       return 1;
1902    }
1903    bs = fopen(jcr->RestoreBootstrap, "rb");
1904    if (!bs) {
1905       berrno be;
1906       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1907          jcr->RestoreBootstrap, be.bstrerror());
1908       set_jcr_job_status(jcr, JS_ErrorTerminated);
1909       goto bail_out;
1910    }
1911    sd->msglen = pm_strcpy(sd->msg, bootstrap);
1912    sd->send();
1913    while (fgets(buf, sizeof(buf), bs)) {
1914       sd->msglen = Mmsg(sd->msg, "%s", buf);
1915       sd->send();
1916    }
1917    sd->signal(BNET_EOD);
1918    fclose(bs);
1919    if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1920       set_jcr_job_status(jcr, JS_ErrorTerminated);
1921       goto bail_out;
1922    }
1923    stat = 1;
1924
1925 bail_out:
1926    free_bootstrap(jcr);
1927    return stat;
1928 }