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