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