]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/job.c
Done with item 9 = Implement new {Client}Run{Before|After}Job feature.
[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 char my_name[];
32 extern CLIENT *me;                    /* our client resource */
33
34 int enable_vss = 0;                   /* set to use vss */
35
36 /* Imported functions */
37 extern int status_cmd(JCR *jcr);
38 extern int qstatus_cmd(JCR *jcr);
39
40 /* Forward referenced functions */
41 static int backup_cmd(JCR *jcr);
42 static int bootstrap_cmd(JCR *jcr);
43 static int cancel_cmd(JCR *jcr);
44 static int setdebug_cmd(JCR *jcr);
45 static int estimate_cmd(JCR *jcr);
46 static int hello_cmd(JCR *jcr);
47 static int job_cmd(JCR *jcr);
48 static int fileset_cmd(JCR *jcr);
49 static int level_cmd(JCR *jcr);
50 static int verify_cmd(JCR *jcr);
51 static int restore_cmd(JCR *jcr);
52 static int storage_cmd(JCR *jcr);
53 static int session_cmd(JCR *jcr);
54 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
55 static void filed_free_jcr(JCR *jcr);
56 static int open_sd_read_session(JCR *jcr);
57 static int send_bootstrap_file(JCR *jcr);
58 static int runscript_cmd(JCR *jcr);
59 static int runbefore_cmd(JCR *jcr);
60 static int runafter_cmd(JCR *jcr);
61 static int runbeforenow_cmd(JCR *jcr);
62 static void set_options(findFOPTS *fo, const char *opts);
63
64
65 /* Exported functions */
66
67 struct s_cmds {
68    const char *cmd;
69    int (*func)(JCR *);
70    int monitoraccess; /* specify if monitors have access to this function */
71 };
72
73 /*
74  * The following are the recognized commands from the Director.
75  */
76 static struct s_cmds cmds[] = {
77    {"backup",       backup_cmd,    0},
78    {"cancel",       cancel_cmd,    0},
79    {"setdebug=",    setdebug_cmd,  0},
80    {"estimate",     estimate_cmd,  0},
81    {"Hello",        hello_cmd,     1},
82    {"fileset",      fileset_cmd,   0},
83    {"JobId=",       job_cmd,       0},
84    {"level = ",     level_cmd,     0},
85    {"restore",      restore_cmd,   0},
86    {"session",      session_cmd,   0},
87    {"status",       status_cmd,    1},
88    {".status",      qstatus_cmd,   1},
89    {"storage ",     storage_cmd,   0},
90    {"verify",       verify_cmd,    0},
91    {"bootstrap",    bootstrap_cmd, 0},
92    {"RunBeforeNow", runbeforenow_cmd, 0},
93    {"RunBeforeJob", runbefore_cmd, 0},
94    {"RunAfterJob",  runafter_cmd,  0},
95    {"Run",          runscript_cmd, 0},
96    {NULL,       NULL}                  /* list terminator */
97 };
98
99 /* Commands received from director that need scanning */
100 static char jobcmd[]      = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
101 static char storaddr[]    = "storage address=%s port=%d ssl=%d\n";
102 static char sessioncmd[]  = "session %127s %ld %ld %ld %ld %ld %ld\n";
103 static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
104 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
105 static char verifycmd[]   = "verify level=%30s\n";
106 static char estimatecmd[] = "estimate listing=%d\n";
107 static char runbefore[]   = "RunBeforeJob %s\n";
108 static char runafter[]    = "RunAfterJob %s\n";
109 static char runscript[]   = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
110 /* Responses sent to Director */
111 static char errmsg[]      = "2999 Invalid command\n";
112 static char no_auth[]     = "2998 No Authorization\n";
113 static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n";
114 static char OKinc[]       = "2000 OK include\n";
115 static char OKest[]       = "2000 OK estimate files=%u bytes=%s\n";
116 static char OKlevel[]     = "2000 OK level\n";
117 static char OKbackup[]    = "2000 OK backup\n";
118 static char OKbootstrap[] = "2000 OK bootstrap\n";
119 static char OKverify[]    = "2000 OK verify\n";
120 static char OKrestore[]   = "2000 OK restore\n";
121 static char OKsession[]   = "2000 OK session\n";
122 static char OKstore[]     = "2000 OK storage\n";
123 static char OKjob[]       = "2000 OK Job %s,%s,%s";
124 static char OKsetdebug[]  = "2000 OK setdebug=%d\n";
125 static char BADjob[]      = "2901 Bad Job\n";
126 static char EndJob[]      = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n";
127 static char OKRunBefore[] = "2000 OK RunBefore\n";
128 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
129 static char OKRunAfter[]  = "2000 OK RunAfter\n";
130 static char OKRunScript[] = "2000 OK RunScript\n";
131
132
133 /* Responses received from Storage Daemon */
134 static char OK_end[]       = "3000 OK end\n";
135 static char OK_close[]     = "3000 OK close Status = %d\n";
136 static char OK_open[]      = "3000 OK open ticket = %d\n";
137 static char OK_data[]      = "3000 OK data\n";
138 static char OK_append[]    = "3000 OK append data\n";
139 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
140
141
142 /* Commands sent to Storage Daemon */
143 static char append_open[]  = "append open session\n";
144 static char append_data[]  = "append data %d\n";
145 static char append_end[]   = "append end session %d\n";
146 static char append_close[] = "append close session %d\n";
147 static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
148 static char read_data[]    = "read data %d\n";
149 static char read_close[]   = "read close session %d\n";
150
151 /*
152  * Accept requests from a Director
153  *
154  * NOTE! We are running as a separate thread
155  *
156  * Send output one line
157  * at a time followed by a zero length transmission.
158  *
159  * Return when the connection is terminated or there
160  * is an error.
161  *
162  * Basic task here is:
163  *   Authenticate Director (during Hello command).
164  *   Accept commands one at a time from the Director
165  *     and execute them.
166  *
167  */
168 void *handle_client_request(void *dirp)
169 {
170    int i;
171    bool found, quit;
172    JCR *jcr;
173    BSOCK *dir = (BSOCK *)dirp;
174
175    jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
176    jcr->dir_bsock = dir;
177    jcr->ff = init_find_files();
178    jcr->start_time = time(NULL);
179    jcr->RunScripts = New(alist(10, not_owned_by_alist));
180    jcr->last_fname = get_pool_memory(PM_FNAME);
181    jcr->last_fname[0] = 0;
182    jcr->client_name = get_memory(strlen(my_name) + 1);
183    pm_strcpy(jcr->client_name, my_name);
184    jcr->pki_sign = me->pki_sign;
185    jcr->pki_encrypt = me->pki_encrypt;
186    jcr->pki_keypair = me->pki_keypair;
187    jcr->pki_signers = me->pki_signers;
188    jcr->pki_recipients = me->pki_recipients;
189    dir->jcr = jcr;
190    enable_backup_privileges(NULL, 1 /* ignore_errors */);
191
192    /**********FIXME******* add command handler error code */
193
194    for (quit=false; !quit;) {
195
196       /* Read command */
197       if (bnet_recv(dir) < 0) {
198          break;               /* connection terminated */
199       }
200       dir->msg[dir->msglen] = 0;
201       Dmsg1(100, "<dird: %s", dir->msg);
202       found = false;
203       for (i=0; cmds[i].cmd; i++) {
204          if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
205             found = true;         /* indicate command found */
206             if (!jcr->authenticated && cmds[i].func != hello_cmd) {
207                bnet_fsend(dir, no_auth);
208                bnet_sig(dir, BNET_EOD);
209                break;
210             }
211             if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
212                Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd);
213                bnet_fsend(dir, illegal_cmd);
214                bnet_sig(dir, BNET_EOD);
215                break;
216             }
217             Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
218             if (!cmds[i].func(jcr)) {         /* do command */
219                quit = true;         /* error or fully terminated, get out */
220                Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
221             }
222             break;
223          }
224       }
225       if (!found) {              /* command not found */
226          bnet_fsend(dir, errmsg);
227          quit = true;
228          break;
229       }
230    }
231
232    /* Inform Storage daemon that we are done */
233    if (jcr->store_bsock) {
234       bnet_sig(jcr->store_bsock, BNET_TERMINATE);
235    }
236
237    /* run after job */
238    run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
239
240    generate_daemon_event(jcr, "JobEnd");
241
242    dequeue_messages(jcr);             /* send any queued messages */
243
244    /* Inform Director that we are done */
245    bnet_sig(dir, BNET_TERMINATE);
246
247    /* Clean up fileset */
248    FF_PKT *ff = jcr->ff;
249    findFILESET *fileset = ff->fileset;
250    if (fileset) {
251       int i, j, k;
252       /* Delete FileSet Include lists */
253       for (i=0; i<fileset->include_list.size(); i++) {
254          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
255          for (j=0; j<incexe->opts_list.size(); j++) {
256             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
257             for (k=0; k<fo->regex.size(); k++) {
258                regfree((regex_t *)fo->regex.get(k));
259             }
260             fo->regex.destroy();
261             fo->regexdir.destroy();
262             fo->regexfile.destroy();
263             fo->wild.destroy();
264             fo->wilddir.destroy();
265             fo->wildfile.destroy();
266             fo->base.destroy();
267             fo->fstype.destroy();
268             if (fo->reader) {
269                free(fo->reader);
270             }
271             if (fo->writer) {
272                free(fo->writer);
273             }
274          }
275          incexe->opts_list.destroy();
276          incexe->name_list.destroy();
277       }
278       fileset->include_list.destroy();
279
280       /* Delete FileSet Exclude lists */
281       for (i=0; i<fileset->exclude_list.size(); i++) {
282          findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
283          for (j=0; j<incexe->opts_list.size(); j++) {
284             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
285             fo->regex.destroy();
286             fo->regexdir.destroy();
287             fo->regexfile.destroy();
288             fo->wild.destroy();
289             fo->wilddir.destroy();
290             fo->wildfile.destroy();
291             fo->base.destroy();
292             fo->fstype.destroy();
293          }
294          incexe->opts_list.destroy();
295          incexe->name_list.destroy();
296       }
297       fileset->exclude_list.destroy();
298       free(fileset);
299    }
300    ff->fileset = NULL;
301    Dmsg0(100, "Calling term_find_files\n");
302    term_find_files(jcr->ff);
303    jcr->ff = NULL;
304    Dmsg0(100, "Done with term_find_files\n");
305    free_jcr(jcr);                     /* destroy JCR record */
306    Dmsg0(100, "Done with free_jcr\n");
307    return NULL;
308 }
309
310 /*
311  * Hello from Director he must identify himself and provide his
312  *  password.
313  */
314 static int hello_cmd(JCR *jcr)
315 {
316    Dmsg0(120, "Calling Authenticate\n");
317    if (!authenticate_director(jcr)) {
318       return 0;
319    }
320    Dmsg0(120, "OK Authenticate\n");
321    jcr->authenticated = true;
322    return 1;
323 }
324
325 /*
326  * Cancel a Job
327  */
328 static int cancel_cmd(JCR *jcr)
329 {
330    BSOCK *dir = jcr->dir_bsock;
331    char Job[MAX_NAME_LENGTH];
332    JCR *cjcr;
333
334    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
335       if (!(cjcr=get_jcr_by_full_name(Job))) {
336          bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
337       } else {
338          if (cjcr->store_bsock) {
339             cjcr->store_bsock->timed_out = 1;
340             cjcr->store_bsock->terminated = 1;
341 #if !defined(HAVE_CYGWIN)
342             pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
343 #endif
344          }
345          set_jcr_job_status(cjcr, JS_Canceled);
346          free_jcr(cjcr);
347          bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
348       }
349    } else {
350       bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
351    }
352    bnet_sig(dir, BNET_EOD);
353    return 1;
354 }
355
356
357 /*
358  * Set debug level as requested by the Director
359  *
360  */
361 static int setdebug_cmd(JCR *jcr)
362 {
363    BSOCK *dir = jcr->dir_bsock;
364    int level, trace_flag;
365
366    Dmsg1(110, "setdebug_cmd: %s", dir->msg);
367    if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
368       pm_strcpy(jcr->errmsg, dir->msg);
369       bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
370       return 0;
371    }
372    debug_level = level;
373    set_trace(trace_flag);
374    return bnet_fsend(dir, OKsetdebug, level);
375 }
376
377
378 static int estimate_cmd(JCR *jcr)
379 {
380    BSOCK *dir = jcr->dir_bsock;
381    char ed2[50];
382
383    if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
384       pm_strcpy(jcr->errmsg, dir->msg);
385       Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
386       bnet_fsend(dir, _("2992 Bad estimate command.\n"));
387       return 0;
388    }
389    make_estimate(jcr);
390    bnet_fsend(dir, OKest, jcr->num_files_examined,
391       edit_uint64_with_commas(jcr->JobBytes, ed2));
392    bnet_sig(dir, BNET_EOD);
393    return 1;
394 }
395
396 /*
397  * Get JobId and Storage Daemon Authorization key from Director
398  */
399 static int job_cmd(JCR *jcr)
400 {
401    BSOCK *dir = jcr->dir_bsock;
402    POOLMEM *sd_auth_key;
403    
404    sd_auth_key = get_memory(dir->msglen);
405    if (sscanf(dir->msg, jobcmd,  &jcr->JobId, jcr->Job,
406               &jcr->VolSessionId, &jcr->VolSessionTime,
407               sd_auth_key) != 5) {
408       pm_strcpy(jcr->errmsg, dir->msg);
409       Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
410       bnet_fsend(dir, BADjob);
411       free_pool_memory(sd_auth_key);
412       return 0;
413    }
414    jcr->sd_auth_key = bstrdup(sd_auth_key);
415    free_pool_memory(sd_auth_key);
416    Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
417    return bnet_fsend(dir, OKjob, HOST_OS, DISTNAME, DISTVER);
418 }
419
420 static int runbefore_cmd(JCR *jcr)
421 {
422    bool ok;
423    BSOCK *dir = jcr->dir_bsock;
424    POOLMEM *cmd = get_memory(dir->msglen+1);
425    RUNSCRIPT *script;
426
427    Dmsg1(100, "runbefore_cmd: %s", dir->msg);
428    if (sscanf(dir->msg, runbefore, cmd) != 1) {
429       pm_strcpy(jcr->errmsg, dir->msg);
430       Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
431       bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
432       free_memory(cmd);
433       return 0;
434    }
435    unbash_spaces(cmd);
436
437    /* Run the command now */
438    script = new_runscript();
439    script->set_command(cmd);
440    script->when = SCRIPT_Before;
441    ok = script->run(jcr, "ClientRunBeforeJob");
442    free_runscript(script);
443
444    free_memory(cmd);
445    if (ok) {
446       bnet_fsend(dir, OKRunBefore);
447       return 1;
448    } else {
449       bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
450       return 0;
451    }
452 }
453
454 static int runbeforenow_cmd(JCR *jcr)
455 {
456    BSOCK *dir = jcr->dir_bsock;
457
458    run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
459    return  bnet_fsend(dir, OKRunBeforeNow);
460 }
461
462 static int runafter_cmd(JCR *jcr)
463 {
464    BSOCK *dir = jcr->dir_bsock;
465    POOLMEM *msg = get_memory(dir->msglen+1);
466    RUNSCRIPT *cmd;
467
468    Dmsg1(100, "runafter_cmd: %s", dir->msg);
469    if (sscanf(dir->msg, runafter, msg) != 1) {
470       pm_strcpy(jcr->errmsg, dir->msg);
471       Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
472       bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
473       free_memory(msg);
474       return 0;
475    }
476    unbash_spaces(msg);
477
478    cmd = new_runscript();
479    cmd->set_command(msg);
480    cmd->on_success = true;
481    cmd->on_failure = false;
482    cmd->when = SCRIPT_After;
483
484    jcr->RunScripts->append(cmd);
485
486    free_pool_memory(msg);
487    return bnet_fsend(dir, OKRunAfter);
488 }
489
490 static int runscript_cmd(JCR *jcr)
491 {
492    BSOCK *dir = jcr->dir_bsock;
493    POOLMEM *msg = get_memory(dir->msglen+1);
494
495    RUNSCRIPT *cmd = new_runscript() ;
496
497    Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
498    if (sscanf(dir->msg, runscript, &cmd->on_success, 
499                                   &cmd->on_failure,
500                                   &cmd->abort_on_error,
501                                   &cmd->when,
502                                   msg) != 5) {
503       pm_strcpy(jcr->errmsg, dir->msg);
504       Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
505       bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
506       free_runscript(cmd);
507       free_memory(msg);
508       return 0;
509    }
510    unbash_spaces(msg);
511
512    cmd->set_command(msg);
513    cmd->debug();
514    jcr->RunScripts->append(cmd);
515
516    free_pool_memory(msg);
517    return bnet_fsend(dir, OKRunScript);
518 }
519
520
521 static bool init_fileset(JCR *jcr)
522 {
523    FF_PKT *ff;
524    findFILESET *fileset;
525
526    if (!jcr->ff) {
527       return false;
528    }
529    ff = jcr->ff;
530    if (ff->fileset) {
531       return false;
532    }
533    fileset = (findFILESET *)malloc(sizeof(findFILESET));
534    memset(fileset, 0, sizeof(findFILESET));
535    ff->fileset = fileset;
536    fileset->state = state_none;
537    fileset->include_list.init(1, true);
538    fileset->exclude_list.init(1, true);
539    return true;
540 }
541
542 static findFOPTS *start_options(FF_PKT *ff)
543 {
544    int state = ff->fileset->state;
545    findINCEXE *incexe = ff->fileset->incexe;
546
547    if (state != state_options) {
548       ff->fileset->state = state_options;
549       findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
550       memset(fo, 0, sizeof(findFOPTS));
551       fo->regex.init(1, true);
552       fo->regexdir.init(1, true);
553       fo->regexfile.init(1, true);
554       fo->wild.init(1, true);
555       fo->wilddir.init(1, true);
556       fo->wildfile.init(1, true);
557       fo->base.init(1, true);
558       fo->fstype.init(1, true);
559       incexe->current_opts = fo;
560       incexe->opts_list.append(fo);
561    }
562    return incexe->current_opts;
563
564 }
565
566 /*
567  * Add fname to include/exclude fileset list. First check for
568  * | and < and if necessary perform command.
569  */
570 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
571 {
572    char *p;
573    BPIPE *bpipe;
574    POOLMEM *fn;
575    FILE *ffd;
576    char buf[1000];
577    int ch;
578    int stat;
579
580    p = (char *)fname;
581    ch = (uint8_t)*p;
582    switch (ch) {
583    case '|':
584       p++;                            /* skip over | */
585       fn = get_pool_memory(PM_FNAME);
586       fn = edit_job_codes(jcr, fn, p, "");
587       bpipe = open_bpipe(fn, 0, "r");
588       free_pool_memory(fn);
589       if (!bpipe) {
590          Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
591             p, strerror(errno));
592          return;
593       }
594       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
595          strip_trailing_junk(buf);
596          fileset->incexe->name_list.append(bstrdup(buf));
597       }
598       if ((stat=close_bpipe(bpipe)) != 0) {
599          Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
600             p, stat, strerror(errno));
601          return;
602       }
603       break;
604    case '<':
605       Dmsg0(100, "Doing < include on client.\n");
606       p++;                      /* skip over < */
607       if ((ffd = fopen(p, "r")) == NULL) {
608          berrno be;
609          Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
610             p, be.strerror());
611          return;
612       }
613       while (fgets(buf, sizeof(buf), ffd)) {
614          strip_trailing_junk(buf);
615          Dmsg1(100, "%s\n", buf);
616          fileset->incexe->name_list.append(bstrdup(buf));
617       }
618       fclose(ffd);
619       break;
620    default:
621       fileset->incexe->name_list.append(bstrdup(fname));
622       break;
623    }
624 }
625
626
627 static void add_fileset(JCR *jcr, const char *item)
628 {
629    FF_PKT *ff = jcr->ff;
630    findFILESET *fileset = ff->fileset;
631    int state = fileset->state;
632    findFOPTS *current_opts;
633
634    /* Get code, optional subcode, and position item past the dividing space */
635    Dmsg1(100, "%s\n", item);
636    int code = item[0];
637    if (code != '\0') {
638       ++item;
639    }
640    int subcode = ' ';               /* A space is always a valid subcode */
641    if (item[0] != '\0' && item[0] != ' ') {
642       subcode = item[0];
643       ++item;
644    }
645    if (*item == ' ') {
646       ++item;
647    }
648
649    /* Skip all lines we receive after an error */
650    if (state == state_error) {
651       return;
652    }
653
654    /*
655     * The switch tests the code for validity.
656     * The subcode is always good if it is a space, otherwise we must confirm.
657     * We set state to state_error first assuming the subcode is invalid,
658     * requiring state to be set in cases below that handle subcodes.
659     */
660    if (subcode != ' ') {
661       state = state_error;
662    }
663    switch (code) {
664    case 'I':
665       /* New include */
666       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
667       memset(fileset->incexe, 0, sizeof(findINCEXE));
668       fileset->incexe->opts_list.init(1, true);
669       fileset->incexe->name_list.init(1, true);
670       fileset->include_list.append(fileset->incexe);
671       break;
672    case 'E':
673       /* New exclude */
674       fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
675       memset(fileset->incexe, 0, sizeof(findINCEXE));
676       fileset->incexe->opts_list.init(1, true);
677       fileset->incexe->name_list.init(1, true);
678       fileset->exclude_list.append(fileset->incexe);
679       break;
680    case 'N':
681       state = state_none;
682       break;
683    case 'F':
684       /* File item to either include/include list */
685       state = state_include;
686       add_file_to_fileset(jcr, item, fileset);
687       break;
688    case 'R':
689       current_opts = start_options(ff);
690       regex_t *preg;
691       int rc;
692       char prbuf[500];
693       preg = (regex_t *)malloc(sizeof(regex_t));
694       if (current_opts->flags & FO_IGNORECASE) {
695          rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
696       } else {
697          rc = regcomp(preg, item, REG_EXTENDED);
698       }
699       if (rc != 0) {
700          regerror(rc, preg, prbuf, sizeof(prbuf));
701          regfree(preg);
702          free(preg);
703          Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
704          state = state_error;
705          break;
706       }
707       state = state_options;
708       if (subcode == ' ') {
709          current_opts->regex.append(preg);
710       } else if (subcode == 'D') {
711          current_opts->regexdir.append(preg);
712       } else if (subcode == 'F') {
713          current_opts->regexfile.append(preg);
714       } else {
715          state = state_error;
716       }
717       break;
718    case 'B':
719       current_opts = start_options(ff);
720       current_opts->base.append(bstrdup(item));
721       state = state_options;
722       break;
723    case 'X':
724       current_opts = start_options(ff);
725       current_opts->fstype.append(bstrdup(item));
726       state = state_options;
727       break;
728    case 'W':
729       current_opts = start_options(ff);
730       state = state_options;
731       if (subcode == ' ') {
732          current_opts->wild.append(bstrdup(item));
733       } else if (subcode == 'D') {
734          current_opts->wilddir.append(bstrdup(item));
735       } else if (subcode == 'F') {
736          current_opts->wildfile.append(bstrdup(item));
737       } else {
738          state = state_error;
739       }
740       break;
741    case 'O':
742       current_opts = start_options(ff);
743       set_options(current_opts, item);
744       state = state_options;
745       break;
746    case 'D':
747       current_opts = start_options(ff);
748       current_opts->reader = bstrdup(item);
749       state = state_options;
750       break;
751    case 'T':
752       current_opts = start_options(ff);
753       current_opts->writer = bstrdup(item);
754       state = state_options;
755       break;
756    default:
757       Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
758       state = state_error;
759       break;
760    }
761    ff->fileset->state = state;
762 }
763
764 static bool term_fileset(JCR *jcr)
765 {
766    FF_PKT *ff = jcr->ff;
767
768 #ifdef xxx
769    findFILESET *fileset = ff->fileset;
770    int i, j, k;
771
772    for (i=0; i<fileset->include_list.size(); i++) {
773       findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
774       Dmsg0(400, "I\n");
775       for (j=0; j<incexe->opts_list.size(); j++) {
776          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
777          for (k=0; k<fo->regex.size(); k++) {
778             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
779          }
780          for (k=0; k<fo->regexdir.size(); k++) {
781             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
782          }
783          for (k=0; k<fo->regexfile.size(); k++) {
784             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
785          }
786          for (k=0; k<fo->wild.size(); k++) {
787             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
788          }
789          for (k=0; k<fo->wilddir.size(); k++) {
790             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
791          }
792          for (k=0; k<fo->wildfile.size(); k++) {
793             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
794          }
795          for (k=0; k<fo->base.size(); k++) {
796             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
797          }
798          for (k=0; k<fo->fstype.size(); k++) {
799             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
800          }
801          if (fo->reader) {
802             Dmsg1(400, "D %s\n", fo->reader);
803          }
804          if (fo->writer) {
805             Dmsg1(400, "T %s\n", fo->writer);
806          }
807       }
808       for (j=0; j<incexe->name_list.size(); j++) {
809          Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
810       }
811    }
812    for (i=0; i<fileset->exclude_list.size(); i++) {
813       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
814       Dmsg0(400, "E\n");
815       for (j=0; j<incexe->opts_list.size(); j++) {
816          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
817          for (k=0; k<fo->regex.size(); k++) {
818             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
819          }
820          for (k=0; k<fo->regexdir.size(); k++) {
821             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
822          }
823          for (k=0; k<fo->regexfile.size(); k++) {
824             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
825          }
826          for (k=0; k<fo->wild.size(); k++) {
827             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
828          }
829          for (k=0; k<fo->wilddir.size(); k++) {
830             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
831          }
832          for (k=0; k<fo->wildfile.size(); k++) {
833             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
834          }
835          for (k=0; k<fo->base.size(); k++) {
836             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
837          }
838          for (k=0; k<fo->fstype.size(); k++) {
839             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
840          }
841       }
842       for (j=0; j<incexe->name_list.size(); j++) {
843          Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
844       }
845    }
846 #endif
847    return ff->fileset->state != state_error;
848 }
849
850
851 /*
852  * As an optimization, we should do this during
853  *  "compile" time in filed/job.c, and keep only a bit mask
854  *  and the Verify options.
855  */
856 static void set_options(findFOPTS *fo, const char *opts)
857 {
858    int j;
859    const char *p;
860
861    for (p=opts; *p; p++) {
862       switch (*p) {
863       case 'a':                 /* alway replace */
864       case '0':                 /* no option */
865          break;
866       case 'e':
867          fo->flags |= FO_EXCLUDE;
868          break;
869       case 'f':
870          fo->flags |= FO_MULTIFS;
871          break;
872       case 'h':                 /* no recursion */
873          fo->flags |= FO_NO_RECURSION;
874          break;
875       case 'H':                 /* no hard link handling */
876          fo->flags |= FO_NO_HARDLINK;
877          break;
878       case 'i':
879          fo->flags |= FO_IGNORECASE;
880          break;
881       case 'M':                 /* MD5 */
882          fo->flags |= FO_MD5;
883          break;
884       case 'n':
885          fo->flags |= FO_NOREPLACE;
886          break;
887       case 'p':                 /* use portable data format */
888          fo->flags |= FO_PORTABLE;
889          break;
890       case 'R':                 /* Resource forks and Finder Info */
891          fo->flags |= FO_HFSPLUS;
892       case 'r':                 /* read fifo */
893          fo->flags |= FO_READFIFO;
894          break;
895       case 'S':
896          switch(*(p + 1)) {
897          case ' ':
898             /* Old director did not specify SHA variant */
899             fo->flags |= FO_SHA1;
900             break;
901          case '1':
902             fo->flags |= FO_SHA1;
903             p++;
904             break;
905 #ifdef HAVE_SHA2
906          case '2':
907             fo->flags |= FO_SHA256;
908             p++;
909             break;
910          case '3':
911             fo->flags |= FO_SHA512;
912             p++;
913             break;
914 #endif
915          default:
916             /* Automatically downgrade to SHA-1 if an unsupported
917              * SHA variant is specified */
918             fo->flags |= FO_SHA1;
919             p++;
920             break;
921          }
922          break;
923       case 's':
924          fo->flags |= FO_SPARSE;
925          break;
926       case 'm':
927          fo->flags |= FO_MTIMEONLY;
928          break;
929       case 'k':
930          fo->flags |= FO_KEEPATIME;
931          break;
932       case 'A':
933          fo->flags |= FO_ACL;
934          break;
935       case 'V':                  /* verify options */
936          /* Copy Verify Options */
937          for (j=0; *p && *p != ':'; p++) {
938             fo->VerifyOpts[j] = *p;
939             if (j < (int)sizeof(fo->VerifyOpts) - 1) {
940                j++;
941             }
942          }
943          fo->VerifyOpts[j] = 0;
944          break;
945       case 'w':
946          fo->flags |= FO_IF_NEWER;
947          break;
948       case 'Z':                 /* gzip compression */
949          fo->flags |= FO_GZIP;
950          fo->GZIP_level = *++p - '0';
951          Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
952          break;
953       case 'K':
954          fo->flags |= FO_NOATIME;
955          break;
956       default:
957          Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
958          break;
959       }
960    }
961 }
962
963
964 /*
965  * Director is passing his Fileset
966  */
967 static int fileset_cmd(JCR *jcr)
968 {
969    BSOCK *dir = jcr->dir_bsock;
970    int vss = 0;
971
972    sscanf(dir->msg, "fileset vss=%d", &vss);
973    enable_vss = vss;
974
975    if (!init_fileset(jcr)) {
976       return 0;
977    }
978    while (bnet_recv(dir) >= 0) {
979       strip_trailing_junk(dir->msg);
980       Dmsg1(500, "Fileset: %s\n", dir->msg);
981       add_fileset(jcr, dir->msg);
982    }
983    if (!term_fileset(jcr)) {
984       return 0;
985    }
986    return bnet_fsend(dir, OKinc);
987 }
988
989 static void free_bootstrap(JCR *jcr)
990 {
991    if (jcr->RestoreBootstrap) {
992       unlink(jcr->RestoreBootstrap);
993       free_pool_memory(jcr->RestoreBootstrap);
994       jcr->RestoreBootstrap = NULL;
995    }
996 }
997
998
999 /* 
1000  * The Director sends us the bootstrap file, which
1001  *   we will in turn pass to the SD.
1002  */
1003 static int bootstrap_cmd(JCR *jcr)
1004 {
1005    BSOCK *dir = jcr->dir_bsock;
1006    POOLMEM *fname = get_pool_memory(PM_FNAME);
1007    FILE *bs;
1008
1009    free_bootstrap(jcr);
1010    Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
1011       jcr->Job);
1012    Dmsg1(400, "bootstrap=%s\n", fname);
1013    jcr->RestoreBootstrap = fname;
1014    bs = fopen(fname, "a+");           /* 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                size_t 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    } else {
1330       set_jcr_job_status(jcr, JS_Terminated);
1331
1332       /* run shortly after end of data transmission */ 
1333       run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
1334
1335       if (jcr->JobStatus != JS_Terminated) {
1336          bnet_suppress_error_messages(sd, 1);
1337          goto cleanup;                /* bail out now */
1338       }
1339       /*
1340        * Expect to get response to append_data from Storage daemon
1341        */
1342       if (!response(jcr, sd, OK_append, "Append Data")) {
1343          set_jcr_job_status(jcr, JS_ErrorTerminated);
1344          goto cleanup;
1345       }
1346
1347       /*
1348        * Send Append End Data to Storage daemon
1349        */
1350       bnet_fsend(sd, append_end, jcr->Ticket);
1351       /* Get end OK */
1352       if (!response(jcr, sd, OK_end, "Append End")) {
1353          set_jcr_job_status(jcr, JS_ErrorTerminated);
1354          goto cleanup;
1355       }
1356
1357       /*
1358        * Send Append Close to Storage daemon
1359        */
1360       bnet_fsend(sd, append_close, jcr->Ticket);
1361       while (bget_msg(sd) >= 0) {    /* stop on signal or error */
1362          if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1363             ok = 1;
1364             Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1365          }
1366       }
1367       if (!ok) {
1368          Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1369          goto cleanup;
1370       }
1371       if (SDJobStatus != JS_Terminated) {
1372          Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1373             SDJobStatus);
1374       }
1375    }
1376
1377 cleanup:
1378 #ifdef WIN32_VSS
1379    /* STOP VSS ON WIN 32 */
1380    /* tell vss to close the backup session */
1381    if (bDoVSS) {
1382       if (g_pVSSClient->CloseBackup()) {             
1383          /* inform user about writer states */
1384          for (size_t i=0; i<g_pVSSClient->GetWriterCount(); i++) {
1385             int msg_type = M_INFO;
1386             if (g_pVSSClient->GetWriterState(i) < 1) {
1387                msg_type = M_WARNING;
1388                jcr->Errors++;
1389             }
1390             Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1391          }
1392       }
1393       V(vss_mutex);
1394    }
1395 #endif
1396
1397    bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1398       edit_uint64(jcr->ReadBytes, ed1),
1399       edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1400    Dmsg1(110, "End FD msg: %s\n", dir->msg);
1401    
1402    return 0;                          /* return and stop command loop */
1403 }
1404
1405 /*
1406  * Do a Verify for Director
1407  *
1408  */
1409 static int verify_cmd(JCR *jcr)
1410 {
1411    BSOCK *dir = jcr->dir_bsock;
1412    BSOCK *sd  = jcr->store_bsock;
1413    char level[100], ed1[50], ed2[50];
1414
1415    jcr->JobType = JT_VERIFY;
1416    if (sscanf(dir->msg, verifycmd, level) != 1) {
1417       bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1418       return 0;
1419    }
1420
1421    if (strcasecmp(level, "init") == 0) {
1422       jcr->JobLevel = L_VERIFY_INIT;
1423    } else if (strcasecmp(level, "catalog") == 0){
1424       jcr->JobLevel = L_VERIFY_CATALOG;
1425    } else if (strcasecmp(level, "volume") == 0){
1426       jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1427    } else if (strcasecmp(level, "data") == 0){
1428       jcr->JobLevel = L_VERIFY_DATA;
1429    } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1430       jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1431    } else {
1432       bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1433       return 0;
1434    }
1435
1436    bnet_fsend(dir, OKverify);
1437
1438    generate_daemon_event(jcr, "JobStart");
1439
1440    Dmsg1(110, "bfiled>dird: %s", dir->msg);
1441
1442    switch (jcr->JobLevel) {
1443    case L_VERIFY_INIT:
1444    case L_VERIFY_CATALOG:
1445       do_verify(jcr);
1446       break;
1447    case L_VERIFY_VOLUME_TO_CATALOG:
1448       if (!open_sd_read_session(jcr)) {
1449          return 0;
1450       }
1451       start_dir_heartbeat(jcr);
1452       do_verify_volume(jcr);
1453       stop_dir_heartbeat(jcr);
1454       /*
1455        * Send Close session command to Storage daemon
1456        */
1457       bnet_fsend(sd, read_close, jcr->Ticket);
1458       Dmsg1(130, "bfiled>stored: %s", sd->msg);
1459
1460       /* ****FIXME**** check response */
1461       bget_msg(sd);                      /* get OK */
1462
1463       /* Inform Storage daemon that we are done */
1464       bnet_sig(sd, BNET_TERMINATE);
1465
1466       break;
1467    case L_VERIFY_DISK_TO_CATALOG:
1468       do_verify(jcr);
1469       break;
1470    default:
1471       bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1472       return 0;
1473    }
1474
1475    bnet_sig(dir, BNET_EOD);
1476
1477    /* Send termination status back to Dir */
1478    bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1479       edit_uint64(jcr->ReadBytes, ed1),
1480       edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1481
1482    /* Inform Director that we are done */
1483    bnet_sig(dir, BNET_TERMINATE);
1484    return 0;                          /* return and terminate command loop */
1485 }
1486
1487 /*
1488  * Do a Restore for Director
1489  *
1490  */
1491 static int restore_cmd(JCR *jcr)
1492 {
1493    BSOCK *dir = jcr->dir_bsock;
1494    BSOCK *sd = jcr->store_bsock;
1495    POOLMEM *where;
1496    int prefix_links;
1497    char replace;
1498    char ed1[50], ed2[50];
1499
1500    /*
1501     * Scan WHERE (base directory for restore) from command
1502     */
1503    Dmsg0(150, "restore command\n");
1504    /* Pickup where string */
1505    where = get_memory(dir->msglen+1);
1506    *where = 0;
1507
1508    if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1509       if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1510          pm_strcpy(jcr->errmsg, dir->msg);
1511          Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1512          return 0;
1513       }
1514       *where = 0;
1515    }
1516    /* Turn / into nothing */
1517    if (where[0] == '/' && where[1] == 0) {
1518       where[0] = 0;
1519    }
1520
1521    Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1522    unbash_spaces(where);
1523    jcr->where = bstrdup(where);
1524    free_pool_memory(where);
1525    jcr->replace = replace;
1526    jcr->prefix_links = prefix_links;
1527
1528    bnet_fsend(dir, OKrestore);
1529    Dmsg1(110, "bfiled>dird: %s", dir->msg);
1530
1531    jcr->JobType = JT_RESTORE;
1532
1533    set_jcr_job_status(jcr, JS_Blocked);
1534
1535    if (!open_sd_read_session(jcr)) {
1536       set_jcr_job_status(jcr, JS_ErrorTerminated);
1537       goto bail_out;
1538    }
1539
1540    set_jcr_job_status(jcr, JS_Running);
1541
1542    /*
1543     * Do restore of files and data
1544     */
1545    start_dir_heartbeat(jcr);
1546    generate_daemon_event(jcr, "JobStart");
1547    do_restore(jcr);
1548    stop_dir_heartbeat(jcr);
1549
1550    set_jcr_job_status(jcr, JS_Terminated);
1551    if (jcr->JobStatus != JS_Terminated) {
1552       bnet_suppress_error_messages(sd, 1);
1553    }
1554
1555    /*
1556     * Send Close session command to Storage daemon
1557     */
1558    bnet_fsend(sd, read_close, jcr->Ticket);
1559    Dmsg1(130, "bfiled>stored: %s", sd->msg);
1560
1561    bget_msg(sd);                      /* get OK */
1562
1563    /* Inform Storage daemon that we are done */
1564    bnet_sig(sd, BNET_TERMINATE);
1565
1566 bail_out:
1567
1568    if (jcr->Errors) {
1569       set_jcr_job_status(jcr, JS_ErrorTerminated);
1570    }
1571    /* Send termination status back to Dir */
1572    bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1573       edit_uint64(jcr->ReadBytes, ed1),
1574       edit_uint64(jcr->JobBytes, ed2), jcr->Errors);
1575
1576    /* Inform Director that we are done */
1577    bnet_sig(dir, BNET_TERMINATE);
1578
1579    Dmsg0(130, "Done in job.c\n");
1580    return 0;                          /* return and terminate command loop */
1581 }
1582
1583 static int open_sd_read_session(JCR *jcr)
1584 {
1585    BSOCK *sd = jcr->store_bsock;
1586
1587    if (!sd) {
1588       Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1589       return 0;
1590    }
1591    Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1592       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1593    Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1594    /*
1595     * Open Read Session with Storage daemon
1596     */
1597    bnet_fsend(sd, read_open, "DummyVolume",
1598       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1599       jcr->StartBlock, jcr->EndBlock);
1600    Dmsg1(110, ">stored: %s", sd->msg);
1601
1602    /*
1603     * Get ticket number
1604     */
1605    if (bget_msg(sd) >= 0) {
1606       Dmsg1(110, "bfiled<stored: %s", sd->msg);
1607       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1608          Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1609          return 0;
1610       }
1611       Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1612    } else {
1613       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1614       return 0;
1615    }
1616
1617    if (!send_bootstrap_file(jcr)) {
1618       return 0;
1619    }
1620
1621    /*
1622     * Start read of data with Storage daemon
1623     */
1624    bnet_fsend(sd, read_data, jcr->Ticket);
1625    Dmsg1(110, ">stored: %s", sd->msg);
1626
1627    /*
1628     * Get OK data
1629     */
1630    if (!response(jcr, sd, OK_data, "Read Data")) {
1631       return 0;
1632    }
1633    return 1;
1634 }
1635
1636 /*
1637  * Destroy the Job Control Record and associated
1638  * resources (sockets).
1639  */
1640 static void filed_free_jcr(JCR *jcr)
1641 {
1642    if (jcr->store_bsock) {
1643       bnet_close(jcr->store_bsock);
1644    }
1645    free_bootstrap(jcr);
1646    if (jcr->last_fname) {
1647       free_pool_memory(jcr->last_fname);
1648    }
1649    free_runscripts(jcr->RunScripts);
1650    delete jcr->RunScripts;
1651
1652    return;
1653 }
1654
1655 /*
1656  * Get response from Storage daemon to a command we
1657  * sent. Check that the response is OK.
1658  *
1659  *  Returns: 0 on failure
1660  *           1 on success
1661  */
1662 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1663 {
1664    if (sd->errors) {
1665       return 0;
1666    }
1667    if (bget_msg(sd) > 0) {
1668       Dmsg0(110, sd->msg);
1669       if (strcmp(sd->msg, resp) == 0) {
1670          return 1;
1671       }
1672    }
1673    if (job_canceled(jcr)) {
1674       return 0;                       /* if canceled avoid useless error messages */
1675    }
1676    if (is_bnet_error(sd)) {
1677       Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1678          cmd, bnet_strerror(sd));
1679    } else {
1680       Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1681          cmd, resp, sd->msg);
1682    }
1683    return 0;
1684 }
1685
1686 static int send_bootstrap_file(JCR *jcr)
1687 {
1688    FILE *bs;
1689    char buf[2000];
1690    BSOCK *sd = jcr->store_bsock;
1691    const char *bootstrap = "bootstrap\n";
1692    int stat = 0;
1693
1694    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1695    if (!jcr->RestoreBootstrap) {
1696       return 1;
1697    }
1698    bs = fopen(jcr->RestoreBootstrap, "r");
1699    if (!bs) {
1700       berrno be;
1701       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1702          jcr->RestoreBootstrap, be.strerror());
1703       set_jcr_job_status(jcr, JS_ErrorTerminated);
1704       goto bail_out;
1705    }
1706    sd->msglen = pm_strcpy(sd->msg, bootstrap);
1707    bnet_send(sd);
1708    while (fgets(buf, sizeof(buf), bs)) {
1709       sd->msglen = Mmsg(sd->msg, "%s", buf);
1710       bnet_send(sd);
1711    }
1712    bnet_sig(sd, BNET_EOD);
1713    fclose(bs);
1714    if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1715       set_jcr_job_status(jcr, JS_ErrorTerminated);
1716       goto bail_out;
1717    }
1718    stat = 1;
1719
1720 bail_out:
1721    free_bootstrap(jcr);
1722    return stat;
1723 }