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