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