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