]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/job.c
9256b4241f15198bcd3928f56d1850da94aff03d
[bacula/bacula] / bacula / src / filed / job.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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->Errors, 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          fileset->incexe->plugin_list.append(new_dlistString(fname));
711       }
712       break;
713    }
714 }
715
716
717 static void add_fileset(JCR *jcr, const char *item)
718 {
719    FF_PKT *ff = jcr->ff;
720    findFILESET *fileset = ff->fileset;
721    int state = fileset->state;
722    findFOPTS *current_opts;
723
724    /* Get code, optional subcode, and position item past the dividing space */
725    Dmsg1(100, "%s\n", item);
726    int code = item[0];
727    if (code != '\0') {
728       ++item;
729    }
730    int subcode = ' ';               /* A space is always a valid subcode */
731    if (item[0] != '\0' && item[0] != ' ') {
732       subcode = item[0];
733       ++item;
734    }
735    if (*item == ' ') {
736       ++item;
737    }
738
739    /* Skip all lines we receive after an error */
740    if (state == state_error) {
741       Dmsg0(100, "State=error return\n");
742       return;
743    }
744
745    /*
746     * The switch tests the code for validity.
747     * The subcode is always good if it is a space, otherwise we must confirm.
748     * We set state to state_error first assuming the subcode is invalid,
749     * requiring state to be set in cases below that handle subcodes.
750     */
751    if (subcode != ' ') {
752       state = state_error;
753       Dmsg0(100, "Set state=error or double code.\n");
754    }
755    switch (code) {
756    case 'I':
757       /* New include */
758       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
759       memset(fileset->incexe, 0, sizeof(findINCEXE));
760       fileset->incexe->opts_list.init(1, true);
761       fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
762       fileset->incexe->plugin_list.init();
763       fileset->include_list.append(fileset->incexe);
764       break;
765    case 'E':
766       /* New exclude */
767       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
768       memset(fileset->incexe, 0, sizeof(findINCEXE));
769       fileset->incexe->opts_list.init(1, true);
770       fileset->incexe->name_list.init();
771       fileset->incexe->plugin_list.init();
772       fileset->exclude_list.append(fileset->incexe);
773       break;
774    case 'N':
775       state = state_none;
776       break;
777    case 'F':
778       /* File item to include or exclude list */
779       state = state_include;
780       add_file_to_fileset(jcr, item, fileset, true);
781       break;
782    case 'P':
783       /* Plugin item to include list */
784       state = state_include;
785       add_file_to_fileset(jcr, item, fileset, false);
786       break;
787    case 'R':
788       current_opts = start_options(ff);
789       regex_t *preg;
790       int rc;
791       char prbuf[500];
792       preg = (regex_t *)malloc(sizeof(regex_t));
793       if (current_opts->flags & FO_IGNORECASE) {
794          rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
795       } else {
796          rc = regcomp(preg, item, REG_EXTENDED);
797       }
798       if (rc != 0) {
799          regerror(rc, preg, prbuf, sizeof(prbuf));
800          regfree(preg);
801          free(preg);
802          Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
803          state = state_error;
804          break;
805       }
806       state = state_options;
807       if (subcode == ' ') {
808          current_opts->regex.append(preg);
809       } else if (subcode == 'D') {
810          current_opts->regexdir.append(preg);
811       } else if (subcode == 'F') {
812          current_opts->regexfile.append(preg);
813       } else {
814          state = state_error;
815       }
816       break;
817    case 'B':
818       current_opts = start_options(ff);
819       current_opts->base.append(bstrdup(item));
820       state = state_options;
821       break;
822    case 'X':
823       current_opts = start_options(ff);
824       state = state_options;
825       if (subcode == ' ') {
826          current_opts->fstype.append(bstrdup(item));
827       } else if (subcode == 'D') {
828          current_opts->drivetype.append(bstrdup(item));
829       } else {
830          state = state_error;
831       }
832       break;
833    case 'W':
834       current_opts = start_options(ff);
835       state = state_options;
836       if (subcode == ' ') {
837          current_opts->wild.append(bstrdup(item));
838       } else if (subcode == 'D') {
839          current_opts->wilddir.append(bstrdup(item));
840       } else if (subcode == 'F') {
841          current_opts->wildfile.append(bstrdup(item));
842       } else if (subcode == 'B') {
843          current_opts->wildbase.append(bstrdup(item));
844       } else {
845          state = state_error;
846       }
847       break;
848    case 'O':
849       current_opts = start_options(ff);
850       set_options(current_opts, item);
851       state = state_options;
852       break;
853    case 'Z':
854       current_opts = start_options(ff);
855       current_opts->ignoredir = bstrdup(item);
856       state = state_options;
857       break;
858    case 'D':
859       current_opts = start_options(ff);
860 //    current_opts->reader = bstrdup(item);
861       state = state_options;
862       break;
863    case 'T':
864       current_opts = start_options(ff);
865 //    current_opts->writer = bstrdup(item);
866       state = state_options;
867       break;
868    default:
869       Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
870       state = state_error;
871       break;
872    }
873    ff->fileset->state = state;
874 }
875
876 static bool term_fileset(JCR *jcr)
877 {
878    FF_PKT *ff = jcr->ff;
879
880 #ifdef xxx_DEBUG_CODE
881    findFILESET *fileset = ff->fileset;
882    int i, j, k;
883
884    for (i=0; i<fileset->include_list.size(); i++) {
885       findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
886       Dmsg0(400, "I\n");
887       for (j=0; j<incexe->opts_list.size(); j++) {
888          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
889          for (k=0; k<fo->regex.size(); k++) {
890             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
891          }
892          for (k=0; k<fo->regexdir.size(); k++) {
893             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
894          }
895          for (k=0; k<fo->regexfile.size(); k++) {
896             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
897          }
898          for (k=0; k<fo->wild.size(); k++) {
899             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
900          }
901          for (k=0; k<fo->wilddir.size(); k++) {
902             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
903          }
904          for (k=0; k<fo->wildfile.size(); k++) {
905             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
906          }
907          for (k=0; k<fo->wildbase.size(); k++) {
908             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
909          }
910          for (k=0; k<fo->base.size(); k++) {
911             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
912          }
913          for (k=0; k<fo->fstype.size(); k++) {
914             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
915          }
916          for (k=0; k<fo->drivetype.size(); k++) {
917             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
918          }
919          if (fo->ignoredir) {
920             Dmsg1(400, "Z %s\n", fo->ignoredir);
921          }
922       }
923       dlistString *node;
924       foreach_dlist(node, &incexe->name_list) {
925          Dmsg1(400, "F %s\n", node->c_str());
926       }
927       foreach_dlist(node, &incexe->plugin_list) {
928          Dmsg1(400, "P %s\n", node->c_str());
929       }
930    }
931    for (i=0; i<fileset->exclude_list.size(); i++) {
932       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
933       Dmsg0(400, "E\n");
934       for (j=0; j<incexe->opts_list.size(); j++) {
935          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
936          for (k=0; k<fo->regex.size(); k++) {
937             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
938          }
939          for (k=0; k<fo->regexdir.size(); k++) {
940             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
941          }
942          for (k=0; k<fo->regexfile.size(); k++) {
943             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
944          }
945          for (k=0; k<fo->wild.size(); k++) {
946             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
947          }
948          for (k=0; k<fo->wilddir.size(); k++) {
949             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
950          }
951          for (k=0; k<fo->wildfile.size(); k++) {
952             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
953          }
954          for (k=0; k<fo->wildbase.size(); k++) {
955             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
956          }
957          for (k=0; k<fo->base.size(); k++) {
958             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
959          }
960          for (k=0; k<fo->fstype.size(); k++) {
961             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
962          }
963          for (k=0; k<fo->drivetype.size(); k++) {
964             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
965          }
966       }
967       dlistString *node;
968       foreach_dlist(node, incexe->name_list) {
969          Dmsg1(400, "F %s\n", node->c_str());
970       }
971       foreach_dlist(node, &incexe->plugin_list) {
972          Dmsg1(400, "P %s\n", node->c_str());
973       }
974    }
975 #endif
976    return ff->fileset->state != state_error;
977 }
978
979
980 /*
981  * As an optimization, we should do this during
982  *  "compile" time in filed/job.c, and keep only a bit mask
983  *  and the Verify options.
984  */
985 static void set_options(findFOPTS *fo, const char *opts)
986 {
987    int j;
988    const char *p;
989    char strip[100];
990
991 // Commented out as it is not backward compatible - KES
992 #ifdef HAVE_WIN32
993 //   fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
994 #endif
995
996    for (p=opts; *p; p++) {
997       switch (*p) {
998       case 'a':                 /* alway replace */
999       case '0':                 /* no option */
1000          break;
1001       case 'e':
1002          fo->flags |= FO_EXCLUDE;
1003          break;
1004       case 'f':
1005          fo->flags |= FO_MULTIFS;
1006          break;
1007       case 'h':                 /* no recursion */
1008          fo->flags |= FO_NO_RECURSION;
1009          break;
1010       case 'H':                 /* no hard link handling */
1011          fo->flags |= FO_NO_HARDLINK;
1012          break;
1013       case 'i':
1014          fo->flags |= FO_IGNORECASE;
1015          break;
1016       case 'M':                 /* MD5 */
1017          fo->flags |= FO_MD5;
1018          break;
1019       case 'n':
1020          fo->flags |= FO_NOREPLACE;
1021          break;
1022       case 'p':                 /* use portable data format */
1023          fo->flags |= FO_PORTABLE;
1024          break;
1025       case 'R':                 /* Resource forks and Finder Info */
1026          fo->flags |= FO_HFSPLUS;
1027       case 'r':                 /* read fifo */
1028          fo->flags |= FO_READFIFO;
1029          break;
1030       case 'S':
1031          switch(*(p + 1)) {
1032          case '1':
1033             fo->flags |= FO_SHA1;
1034             p++;
1035             break;
1036 #ifdef HAVE_SHA2
1037          case '2':
1038             fo->flags |= FO_SHA256;
1039             p++;
1040             break;
1041          case '3':
1042             fo->flags |= FO_SHA512;
1043             p++;
1044             break;
1045 #endif
1046          default:
1047             /*
1048              * If 2 or 3 is seen here, SHA2 is not configured, so
1049              *  eat the option, and drop back to SHA-1.
1050              */
1051             if (p[1] == '2' || p[1] == '3') {
1052                p++;
1053             }
1054             fo->flags |= FO_SHA1;
1055             break;
1056          }
1057          break;
1058       case 's':
1059          fo->flags |= FO_SPARSE;
1060          break;
1061       case 'm':
1062          fo->flags |= FO_MTIMEONLY;
1063          break;
1064       case 'k':
1065          fo->flags |= FO_KEEPATIME;
1066          break;
1067       case 'A':
1068          fo->flags |= FO_ACL;
1069          break;
1070       case 'V':                  /* verify options */
1071          /* Copy Verify Options */
1072          for (j=0; *p && *p != ':'; p++) {
1073             fo->VerifyOpts[j] = *p;
1074             if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1075                j++;
1076             }
1077          }
1078          fo->VerifyOpts[j] = 0;
1079          break;
1080       case 'C':                  /* accurate options */
1081          /* Copy Accurate Options */
1082          for (j=0; *p && *p != ':'; p++) {
1083             fo->AccurateOpts[j] = *p;
1084             if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1085                j++;
1086             }
1087          }
1088          fo->AccurateOpts[j] = 0;
1089          break;
1090       case 'P':                  /* strip path */
1091          /* Get integer */
1092          p++;                    /* skip P */
1093          for (j=0; *p && *p != ':'; p++) {
1094             strip[j] = *p;
1095             if (j < (int)sizeof(strip) - 1) {
1096                j++;
1097             }
1098          }
1099          strip[j] = 0;
1100          fo->strip_path = atoi(strip);
1101          fo->flags |= FO_STRIPPATH;
1102          Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1103          break;
1104       case 'w':
1105          fo->flags |= FO_IF_NEWER;
1106          break;
1107       case 'W':
1108          fo->flags |= FO_ENHANCEDWILD;
1109          break;
1110       case 'Z':                 /* gzip compression */
1111          fo->flags |= FO_GZIP;
1112          fo->GZIP_level = *++p - '0';
1113          break;
1114       case 'K':
1115          fo->flags |= FO_NOATIME;
1116          break;
1117       case 'c':
1118          fo->flags |= FO_CHKCHANGES;
1119          break;
1120       case 'N':
1121          fo->flags |= FO_HONOR_NODUMP;
1122          break;
1123       default:
1124          Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1125          break;
1126       }
1127    }
1128 }
1129
1130
1131 /*
1132  * Director is passing his Fileset
1133  */
1134 static int fileset_cmd(JCR *jcr)
1135 {
1136    BSOCK *dir = jcr->dir_bsock;
1137
1138 #if defined(WIN32_VSS)
1139    int vss = 0;
1140
1141    sscanf(dir->msg, "fileset vss=%d", &vss);
1142    enable_vss = vss;
1143 #endif
1144
1145    if (!init_fileset(jcr)) {
1146       return 0;
1147    }
1148    while (dir->recv() >= 0) {
1149       strip_trailing_junk(dir->msg);
1150       Dmsg1(500, "Fileset: %s\n", dir->msg);
1151       add_fileset(jcr, dir->msg);
1152    }
1153    if (!term_fileset(jcr)) {
1154       return 0;
1155    }
1156    return dir->fsend(OKinc);
1157 }
1158
1159 static void free_bootstrap(JCR *jcr)
1160 {
1161    if (jcr->RestoreBootstrap) {
1162       unlink(jcr->RestoreBootstrap);
1163       free_pool_memory(jcr->RestoreBootstrap);
1164       jcr->RestoreBootstrap = NULL;
1165    }
1166 }
1167
1168
1169 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1170 static uint32_t bsr_uniq = 0;
1171
1172 /* 
1173  * The Director sends us the bootstrap file, which
1174  *   we will in turn pass to the SD.
1175  */
1176 static int bootstrap_cmd(JCR *jcr)
1177 {
1178    BSOCK *dir = jcr->dir_bsock;
1179    POOLMEM *fname = get_pool_memory(PM_FNAME);
1180    FILE *bs;
1181
1182    free_bootstrap(jcr);
1183    P(bsr_mutex);
1184    bsr_uniq++;
1185    Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1186       jcr->Job, bsr_uniq);
1187    V(bsr_mutex);
1188    Dmsg1(400, "bootstrap=%s\n", fname);
1189    jcr->RestoreBootstrap = fname;
1190    bs = fopen(fname, "a+b");           /* create file */
1191    if (!bs) {
1192       berrno be;
1193       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1194          jcr->RestoreBootstrap, be.bstrerror());
1195       /*
1196        * Suck up what he is sending to us so that he will then
1197        *   read our error message.
1198        */
1199       while (dir->recv() >= 0)
1200         {  }
1201       free_bootstrap(jcr);
1202       set_jcr_job_status(jcr, JS_ErrorTerminated);
1203       return 0;
1204    }
1205
1206    while (dir->recv() >= 0) {
1207        Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1208        fputs(dir->msg, bs);
1209    }
1210    fclose(bs);
1211    /*
1212     * Note, do not free the bootstrap yet -- it needs to be 
1213     *  sent to the SD 
1214     */
1215    return dir->fsend(OKbootstrap);
1216 }
1217
1218
1219 /*
1220  * Get backup level from Director
1221  *
1222  */
1223 static int level_cmd(JCR *jcr)
1224 {
1225    BSOCK *dir = jcr->dir_bsock;
1226    POOLMEM *level, *buf = NULL;
1227    int mtime_only;
1228
1229    level = get_memory(dir->msglen+1);
1230    Dmsg1(100, "level_cmd: %s", dir->msg);
1231    if (strstr(dir->msg, "accurate")) {
1232       jcr->accurate = true;
1233    }
1234    if (sscanf(dir->msg, "level = %s ", level) != 1) {
1235       goto bail_out;
1236    }
1237    /* Base backup requested? */
1238    if (strcmp(level, "base") == 0) {
1239       jcr->set_JobLevel(L_BASE);
1240    /* Full backup requested? */
1241    } else if (strcmp(level, "full") == 0) {
1242       jcr->set_JobLevel(L_FULL);
1243    } else if (strstr(level, "differential")) {
1244       jcr->set_JobLevel(L_DIFFERENTIAL);
1245       free_memory(level);
1246       return 1;
1247    } else if (strstr(level, "incremental")) {
1248       jcr->set_JobLevel(L_INCREMENTAL);
1249       free_memory(level);
1250       return 1;
1251    /*
1252     * We get his UTC since time, then sync the clocks and correct it
1253     *   to agree with our clock.
1254     */
1255    } else if (strcmp(level, "since_utime") == 0) {
1256       buf = get_memory(dir->msglen+1);
1257       utime_t since_time, adj;
1258       btime_t his_time, bt_start, rt=0, bt_adj=0;
1259       if (jcr->get_JobLevel() == L_NONE) {
1260          jcr->set_JobLevel(L_SINCE);     /* if no other job level set, do it now */
1261       }
1262       if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1263                  buf, &mtime_only) != 2) {
1264          goto bail_out;
1265       }
1266       since_time = str_to_uint64(buf);  /* this is the since time */
1267       Dmsg1(100, "since_time=%d\n", (int)since_time);
1268       char ed1[50], ed2[50];
1269       /*
1270        * Sync clocks by polling him for the time. We take
1271        *   10 samples of his time throwing out the first two.
1272        */
1273       for (int i=0; i<10; i++) {
1274          bt_start = get_current_btime();
1275          dir->signal(BNET_BTIME);     /* poll for time */
1276          if (dir->recv() <= 0) {      /* get response */
1277             goto bail_out;
1278          }
1279          if (sscanf(dir->msg, "btime %s", buf) != 1) {
1280             goto bail_out;
1281          }
1282          if (i < 2) {                 /* toss first two results */
1283             continue;
1284          }
1285          his_time = str_to_uint64(buf);
1286          rt = get_current_btime() - bt_start; /* compute round trip time */
1287          Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1288                edit_uint64(bt_start, ed2));
1289          bt_adj +=  bt_start - his_time - rt/2;
1290          Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1291       }
1292
1293       bt_adj = bt_adj / 8;            /* compute average time */
1294       Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1295       adj = btime_to_utime(bt_adj);
1296       since_time += adj;              /* adjust for clock difference */
1297       /* Don't notify if time within 3 seconds */
1298       if (adj > 3 || adj < -3) {
1299          int type;
1300          if (adj > 600 || adj < -600) {
1301             type = M_WARNING;
1302          } else {
1303             type = M_INFO;
1304          }
1305          Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1306       }
1307       dir->signal(BNET_EOD);
1308
1309       Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1310       jcr->incremental = 1;           /* set incremental or decremental backup */
1311       jcr->mtime = (time_t)since_time; /* set since time */
1312       generate_plugin_event(jcr, bEventSince, (void *)jcr->mtime);
1313    } else {
1314       Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1315       free_memory(level);
1316       return 0;
1317    }
1318    free_memory(level);
1319    if (buf) {
1320       free_memory(buf);
1321    }
1322    generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1323    return dir->fsend(OKlevel);
1324
1325 bail_out:
1326    pm_strcpy(jcr->errmsg, dir->msg);
1327    Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1328    free_memory(level);
1329    if (buf) {
1330       free_memory(buf);
1331    }
1332    return 0;
1333 }
1334
1335 /*
1336  * Get session parameters from Director -- this is for a Restore command
1337  */
1338 static int session_cmd(JCR *jcr)
1339 {
1340    BSOCK *dir = jcr->dir_bsock;
1341
1342    Dmsg1(100, "SessionCmd: %s", dir->msg);
1343    if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1344               &jcr->VolSessionId, &jcr->VolSessionTime,
1345               &jcr->StartFile, &jcr->EndFile,
1346               &jcr->StartBlock, &jcr->EndBlock) != 7) {
1347       pm_strcpy(jcr->errmsg, dir->msg);
1348       Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1349       return 0;
1350    }
1351
1352    return dir->fsend(OKsession);
1353 }
1354
1355 /*
1356  * Get address of storage daemon from Director
1357  *
1358  */
1359 static int storage_cmd(JCR *jcr)
1360 {
1361    int stored_port;                /* storage daemon port */
1362    int enable_ssl;                 /* enable ssl to sd */
1363    BSOCK *dir = jcr->dir_bsock;
1364    BSOCK *sd;                         /* storage daemon bsock */
1365
1366    Dmsg1(100, "StorageCmd: %s", dir->msg);
1367    if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1368       pm_strcpy(jcr->errmsg, dir->msg);
1369       Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1370       goto bail_out;
1371    }
1372    Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1373    /* Open command communications with Storage daemon */
1374    /* Try to connect for 1 hour at 10 second intervals */
1375    sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1376                       _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1377    if (sd == NULL) {
1378       Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1379           jcr->stored_addr, stored_port);
1380       Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1381           jcr->stored_addr, stored_port);
1382       goto bail_out;
1383    }
1384    Dmsg0(110, "Connection OK to SD.\n");
1385
1386    jcr->store_bsock = sd;
1387
1388    sd->fsend("Hello Start Job %s\n", jcr->Job);
1389    if (!authenticate_storagedaemon(jcr)) {
1390       Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1391       goto bail_out;
1392    }
1393    Dmsg0(110, "Authenticated with SD.\n");
1394
1395    /* Send OK to Director */
1396    return dir->fsend(OKstore);
1397
1398 bail_out:
1399       dir->fsend(BADcmd, "storage");
1400       return 0;
1401
1402 }
1403
1404
1405 /*
1406  * Do a backup.
1407  */
1408 static int backup_cmd(JCR *jcr)
1409 {
1410    BSOCK *dir = jcr->dir_bsock;
1411    BSOCK *sd = jcr->store_bsock;
1412    int ok = 0;
1413    int SDJobStatus;
1414
1415 #if defined(WIN32_VSS)
1416    // capture state here, if client is backed up by multiple directors
1417    // and one enables vss and the other does not then enable_vss can change
1418    // between here and where its evaluated after the job completes.
1419    jcr->VSS = g_pVSSClient && enable_vss;
1420    if (jcr->VSS) {
1421       /* Run only one at a time */
1422       P(vss_mutex);
1423    }
1424 #endif
1425
1426    set_jcr_job_status(jcr, JS_Blocked);
1427    jcr->set_JobType(JT_BACKUP);
1428    Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1429
1430    if (sd == NULL) {
1431       Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1432       dir->fsend(BADcmd, "backup");
1433       goto cleanup;
1434    }
1435
1436    dir->fsend(OKbackup);
1437    Dmsg1(110, "bfiled>dird: %s", dir->msg);
1438
1439    /*
1440     * Send Append Open Session to Storage daemon
1441     */
1442    sd->fsend(append_open);
1443    Dmsg1(110, ">stored: %s", sd->msg);
1444    /*
1445     * Expect to receive back the Ticket number
1446     */
1447    if (bget_msg(sd) >= 0) {
1448       Dmsg1(110, "<stored: %s", sd->msg);
1449       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1450          Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1451          goto cleanup;
1452       }
1453       Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1454    } else {
1455       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1456       goto cleanup;
1457    }
1458
1459    /*
1460     * Send Append data command to Storage daemon
1461     */
1462    sd->fsend(append_data, jcr->Ticket);
1463    Dmsg1(110, ">stored: %s", sd->msg);
1464
1465    /*
1466     * Expect to get OK data
1467     */
1468    Dmsg1(110, "<stored: %s", sd->msg);
1469    if (!response(jcr, sd, OK_data, "Append Data")) {
1470       goto cleanup;
1471    }
1472    
1473    generate_daemon_event(jcr, "JobStart");
1474    generate_plugin_event(jcr, bEventStartBackupJob);
1475
1476 #if defined(WIN32_VSS)
1477    /* START VSS ON WIN32 */
1478    if (jcr->VSS) {      
1479       if (g_pVSSClient->InitializeForBackup()) {   
1480         /* tell vss which drives to snapshot */   
1481         char szWinDriveLetters[27];   
1482         if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1483             Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1484             if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {               
1485                Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1486                jcr->Errors++;
1487             } else {
1488                /* tell user if snapshot creation of a specific drive failed */
1489                int i;
1490                for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1491                   if (islower(szWinDriveLetters[i])) {
1492                      Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1493                      jcr->Errors++;
1494                   }
1495                }
1496                /* inform user about writer states */
1497                for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)                
1498                   if (g_pVSSClient->GetWriterState(i) < 1) {
1499                      Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));                    
1500                      jcr->Errors++;
1501                   }                            
1502             }
1503         } else {
1504             Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1505         }
1506       } else {
1507          berrno be;
1508          Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1509       } 
1510       run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1511    }
1512 #endif
1513
1514    /*
1515     * Send Files to Storage daemon
1516     */
1517    Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1518    if (!blast_data_to_storage_daemon(jcr, NULL)) {
1519       set_jcr_job_status(jcr, JS_ErrorTerminated);
1520       bnet_suppress_error_messages(sd, 1);
1521       bget_msg(sd);                   /* Read final response from append_data */
1522       Dmsg0(110, "Error in blast_data.\n");
1523    } else {
1524       set_jcr_job_status(jcr, JS_Terminated);
1525
1526       if (jcr->JobStatus != JS_Terminated) {
1527          bnet_suppress_error_messages(sd, 1);
1528          goto cleanup;                /* bail out now */
1529       }
1530       /*
1531        * Expect to get response to append_data from Storage daemon
1532        */
1533       if (!response(jcr, sd, OK_append, "Append Data")) {
1534          set_jcr_job_status(jcr, JS_ErrorTerminated);
1535          goto cleanup;
1536       }
1537
1538       /*
1539        * Send Append End Data to Storage daemon
1540        */
1541       sd->fsend(append_end, jcr->Ticket);
1542       /* Get end OK */
1543       if (!response(jcr, sd, OK_end, "Append End")) {
1544          set_jcr_job_status(jcr, JS_ErrorTerminated);
1545          goto cleanup;
1546       }
1547
1548       /*
1549        * Send Append Close to Storage daemon
1550        */
1551       sd->fsend(append_close, jcr->Ticket);
1552       while (bget_msg(sd) >= 0) {    /* stop on signal or error */
1553          if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1554             ok = 1;
1555             Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1556          }
1557       }
1558       if (!ok) {
1559          Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1560          goto cleanup;
1561       }
1562       if (SDJobStatus != JS_Terminated) {
1563          Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1564             SDJobStatus);
1565       }
1566    }
1567
1568 cleanup:
1569 #if defined(WIN32_VSS)
1570    /* STOP VSS ON WIN32 */
1571    /* tell vss to close the backup session */
1572    if (jcr->VSS) {
1573       if (g_pVSSClient->CloseBackup()) {             
1574          /* inform user about writer states */
1575          for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1576             int msg_type = M_INFO;
1577             if (g_pVSSClient->GetWriterState(i) < 1) {
1578                msg_type = M_WARNING;
1579                jcr->Errors++;
1580             }
1581             Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1582          }
1583       }
1584       V(vss_mutex);
1585    }
1586 #endif
1587
1588    generate_plugin_event(jcr, bEventEndBackupJob);
1589    return 0;                          /* return and stop command loop */
1590 }
1591
1592 /*
1593  * Do a Verify for Director
1594  *
1595  */
1596 static int verify_cmd(JCR *jcr)
1597 {
1598    BSOCK *dir = jcr->dir_bsock;
1599    BSOCK *sd  = jcr->store_bsock;
1600    char level[100];
1601
1602    jcr->set_JobType(JT_VERIFY);
1603    if (sscanf(dir->msg, verifycmd, level) != 1) {
1604       dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1605       return 0;
1606    }
1607
1608    if (strcasecmp(level, "init") == 0) {
1609       jcr->set_JobLevel(L_VERIFY_INIT);
1610    } else if (strcasecmp(level, "catalog") == 0){
1611       jcr->set_JobLevel(L_VERIFY_CATALOG);
1612    } else if (strcasecmp(level, "volume") == 0){
1613       jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1614    } else if (strcasecmp(level, "data") == 0){
1615       jcr->set_JobLevel(L_VERIFY_DATA);
1616    } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1617       jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1618    } else {
1619       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1620       return 0;
1621    }
1622
1623    dir->fsend(OKverify);
1624
1625    generate_daemon_event(jcr, "JobStart");
1626    generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1627    generate_plugin_event(jcr, bEventStartVerifyJob);
1628
1629    Dmsg1(110, "bfiled>dird: %s", dir->msg);
1630
1631    switch (jcr->get_JobLevel()) {
1632    case L_VERIFY_INIT:
1633    case L_VERIFY_CATALOG:
1634       do_verify(jcr);
1635       break;
1636    case L_VERIFY_VOLUME_TO_CATALOG:
1637       if (!open_sd_read_session(jcr)) {
1638          return 0;
1639       }
1640       start_dir_heartbeat(jcr);
1641       do_verify_volume(jcr);
1642       stop_dir_heartbeat(jcr);
1643       /*
1644        * Send Close session command to Storage daemon
1645        */
1646       sd->fsend(read_close, jcr->Ticket);
1647       Dmsg1(130, "bfiled>stored: %s", sd->msg);
1648
1649       /* ****FIXME**** check response */
1650       bget_msg(sd);                      /* get OK */
1651
1652       /* Inform Storage daemon that we are done */
1653       sd->signal(BNET_TERMINATE);
1654
1655       break;
1656    case L_VERIFY_DISK_TO_CATALOG:
1657       do_verify(jcr);
1658       break;
1659    default:
1660       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1661       return 0;
1662    }
1663
1664    dir->signal(BNET_EOD);
1665    generate_plugin_event(jcr, bEventEndVerifyJob);
1666    return 0;                          /* return and terminate command loop */
1667 }
1668
1669 /*
1670  * Do a Restore for Director
1671  *
1672  */
1673 static int restore_cmd(JCR *jcr)
1674 {
1675    BSOCK *dir = jcr->dir_bsock;
1676    BSOCK *sd = jcr->store_bsock;
1677    POOLMEM *args;
1678    bool use_regexwhere=false;
1679    int prefix_links;
1680    char replace;
1681
1682    /*
1683     * Scan WHERE (base directory for restore) from command
1684     */
1685    Dmsg0(150, "restore command\n");
1686    /* Pickup where string */
1687    args = get_memory(dir->msglen+1);
1688    *args = 0;
1689
1690    if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1691       if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1692          if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1693             pm_strcpy(jcr->errmsg, dir->msg);
1694             Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1695             return 0;
1696          }
1697          *args = 0;
1698       }
1699       use_regexwhere = true;
1700    }
1701    /* Turn / into nothing */
1702    if (IsPathSeparator(args[0]) && args[1] == '\0') {
1703       args[0] = '\0';
1704    }
1705
1706    Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1707    unbash_spaces(args);
1708
1709    if (use_regexwhere) {
1710       jcr->where_bregexp = get_bregexps(args);
1711       if (!jcr->where_bregexp) {
1712          Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1713          free_pool_memory(args);
1714          return 0;
1715       }
1716    } else {
1717       jcr->where = bstrdup(args);
1718    }
1719
1720    free_pool_memory(args);
1721    jcr->replace = replace;
1722    jcr->prefix_links = prefix_links;
1723
1724    dir->fsend(OKrestore);
1725    Dmsg1(110, "bfiled>dird: %s", dir->msg);
1726
1727    jcr->set_JobType(JT_RESTORE);
1728
1729    set_jcr_job_status(jcr, JS_Blocked);
1730
1731    if (!open_sd_read_session(jcr)) {
1732       set_jcr_job_status(jcr, JS_ErrorTerminated);
1733       goto bail_out;
1734    }
1735
1736    set_jcr_job_status(jcr, JS_Running);
1737
1738    /*
1739     * Do restore of files and data
1740     */
1741    start_dir_heartbeat(jcr);
1742    generate_daemon_event(jcr, "JobStart");
1743    generate_plugin_event(jcr, bEventStartRestoreJob);
1744    do_restore(jcr);
1745    stop_dir_heartbeat(jcr);
1746
1747    set_jcr_job_status(jcr, JS_Terminated);
1748    if (jcr->JobStatus != JS_Terminated) {
1749       bnet_suppress_error_messages(sd, 1);
1750    }
1751
1752    /*
1753     * Send Close session command to Storage daemon
1754     */
1755    sd->fsend(read_close, jcr->Ticket);
1756    Dmsg1(130, "bfiled>stored: %s", sd->msg);
1757
1758    bget_msg(sd);                      /* get OK */
1759
1760    /* Inform Storage daemon that we are done */
1761    sd->signal(BNET_TERMINATE);
1762
1763 bail_out:
1764
1765    if (jcr->Errors) {
1766       set_jcr_job_status(jcr, JS_ErrorTerminated);
1767    }
1768
1769    Dmsg0(130, "Done in job.c\n");
1770    generate_plugin_event(jcr, bEventEndRestoreJob);
1771    return 0;                          /* return and terminate command loop */
1772 }
1773
1774 static int open_sd_read_session(JCR *jcr)
1775 {
1776    BSOCK *sd = jcr->store_bsock;
1777
1778    if (!sd) {
1779       Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1780       return 0;
1781    }
1782    Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1783       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1784    Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1785    /*
1786     * Open Read Session with Storage daemon
1787     */
1788    sd->fsend(read_open, "DummyVolume",
1789       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1790       jcr->StartBlock, jcr->EndBlock);
1791    Dmsg1(110, ">stored: %s", sd->msg);
1792
1793    /*
1794     * Get ticket number
1795     */
1796    if (bget_msg(sd) >= 0) {
1797       Dmsg1(110, "bfiled<stored: %s", sd->msg);
1798       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1799          Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1800          return 0;
1801       }
1802       Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1803    } else {
1804       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1805       return 0;
1806    }
1807
1808    if (!send_bootstrap_file(jcr)) {
1809       return 0;
1810    }
1811
1812    /*
1813     * Start read of data with Storage daemon
1814     */
1815    sd->fsend(read_data, jcr->Ticket);
1816    Dmsg1(110, ">stored: %s", sd->msg);
1817
1818    /*
1819     * Get OK data
1820     */
1821    if (!response(jcr, sd, OK_data, "Read Data")) {
1822       return 0;
1823    }
1824    return 1;
1825 }
1826
1827 /*
1828  * Destroy the Job Control Record and associated
1829  * resources (sockets).
1830  */
1831 static void filed_free_jcr(JCR *jcr)
1832 {
1833    if (jcr->store_bsock) {
1834       jcr->store_bsock->close();
1835    }
1836    free_bootstrap(jcr);
1837    if (jcr->last_fname) {
1838       free_pool_memory(jcr->last_fname);
1839    }
1840    free_runscripts(jcr->RunScripts);
1841    delete jcr->RunScripts;
1842
1843    if (jcr->JobId != 0)
1844       write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1845
1846    return;
1847 }
1848
1849 /*
1850  * Get response from Storage daemon to a command we
1851  * sent. Check that the response is OK.
1852  *
1853  *  Returns: 0 on failure
1854  *           1 on success
1855  */
1856 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1857 {
1858    if (sd->errors) {
1859       return 0;
1860    }
1861    if (bget_msg(sd) > 0) {
1862       Dmsg0(110, sd->msg);
1863       if (strcmp(sd->msg, resp) == 0) {
1864          return 1;
1865       }
1866    }
1867    if (job_canceled(jcr)) {
1868       return 0;                       /* if canceled avoid useless error messages */
1869    }
1870    if (is_bnet_error(sd)) {
1871       Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1872          cmd, bnet_strerror(sd));
1873    } else {
1874       Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1875          cmd, resp, sd->msg);
1876    }
1877    return 0;
1878 }
1879
1880 static int send_bootstrap_file(JCR *jcr)
1881 {
1882    FILE *bs;
1883    char buf[2000];
1884    BSOCK *sd = jcr->store_bsock;
1885    const char *bootstrap = "bootstrap\n";
1886    int stat = 0;
1887
1888    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1889    if (!jcr->RestoreBootstrap) {
1890       return 1;
1891    }
1892    bs = fopen(jcr->RestoreBootstrap, "rb");
1893    if (!bs) {
1894       berrno be;
1895       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1896          jcr->RestoreBootstrap, be.bstrerror());
1897       set_jcr_job_status(jcr, JS_ErrorTerminated);
1898       goto bail_out;
1899    }
1900    sd->msglen = pm_strcpy(sd->msg, bootstrap);
1901    sd->send();
1902    while (fgets(buf, sizeof(buf), bs)) {
1903       sd->msglen = Mmsg(sd->msg, "%s", buf);
1904       sd->send();
1905    }
1906    sd->signal(BNET_EOD);
1907    fclose(bs);
1908    if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1909       set_jcr_job_status(jcr, JS_ErrorTerminated);
1910       goto bail_out;
1911    }
1912    stat = 1;
1913
1914 bail_out:
1915    free_bootstrap(jcr);
1916    return stat;
1917 }