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