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