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