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