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