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