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