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