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