2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula File Daemon Job processing
31 * Kern Sibbald, October MM
40 #if defined(WIN32_VSS)
43 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
44 static int enable_vss;
47 extern CLIENT *me; /* our client resource */
49 /* Imported functions */
50 extern int status_cmd(JCR *jcr);
51 extern int qstatus_cmd(JCR *jcr);
52 extern int accurate_cmd(JCR *jcr);
54 /* Forward referenced functions */
55 static int backup_cmd(JCR *jcr);
56 static int bootstrap_cmd(JCR *jcr);
57 static int cancel_cmd(JCR *jcr);
58 static int setdebug_cmd(JCR *jcr);
59 static int estimate_cmd(JCR *jcr);
60 static int hello_cmd(JCR *jcr);
61 static int job_cmd(JCR *jcr);
62 static int fileset_cmd(JCR *jcr);
63 static int level_cmd(JCR *jcr);
64 static int verify_cmd(JCR *jcr);
65 static int restore_cmd(JCR *jcr);
66 static int storage_cmd(JCR *jcr);
67 static int session_cmd(JCR *jcr);
68 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
69 static void filed_free_jcr(JCR *jcr);
70 static int open_sd_read_session(JCR *jcr);
71 static int send_bootstrap_file(JCR *jcr);
72 static int runscript_cmd(JCR *jcr);
73 static int runbefore_cmd(JCR *jcr);
74 static int runafter_cmd(JCR *jcr);
75 static int runbeforenow_cmd(JCR *jcr);
76 static void set_options(findFOPTS *fo, const char *opts);
79 /* Exported functions */
84 int monitoraccess; /* specify if monitors have access to this function */
88 * The following are the recognized commands from the Director.
90 static struct s_cmds cmds[] = {
91 {"backup", backup_cmd, 0},
92 {"cancel", cancel_cmd, 0},
93 {"setdebug=", setdebug_cmd, 0},
94 {"estimate", estimate_cmd, 0},
95 {"Hello", hello_cmd, 1},
96 {"fileset", fileset_cmd, 0},
97 {"JobId=", job_cmd, 0},
98 {"level = ", level_cmd, 0},
99 {"restore", restore_cmd, 0},
100 {"session", session_cmd, 0},
101 {"status", status_cmd, 1},
102 {".status", qstatus_cmd, 1},
103 {"storage ", storage_cmd, 0},
104 {"verify", verify_cmd, 0},
105 {"bootstrap", bootstrap_cmd, 0},
106 {"RunBeforeNow", runbeforenow_cmd, 0},
107 {"RunBeforeJob", runbefore_cmd, 0},
108 {"RunAfterJob", runafter_cmd, 0},
109 {"Run", runscript_cmd, 0},
110 {"accurate", accurate_cmd, 0},
111 {NULL, NULL} /* list terminator */
114 /* Commands received from director that need scanning */
115 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
116 static char storaddr[] = "storage address=%s port=%d ssl=%d";
117 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
118 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
119 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
120 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
121 static char verifycmd[] = "verify level=%30s";
122 static char estimatecmd[] = "estimate listing=%d";
123 static char runbefore[] = "RunBeforeJob %s";
124 static char runafter[] = "RunAfterJob %s";
125 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
127 /* Responses sent to Director */
128 static char errmsg[] = "2999 Invalid command\n";
129 static char no_auth[] = "2998 No Authorization\n";
130 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
131 static char OKinc[] = "2000 OK include\n";
132 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
133 static char OKlevel[] = "2000 OK level\n";
134 static char OKbackup[] = "2000 OK backup\n";
135 static char OKbootstrap[] = "2000 OK bootstrap\n";
136 static char OKverify[] = "2000 OK verify\n";
137 static char OKrestore[] = "2000 OK restore\n";
138 static char OKsession[] = "2000 OK session\n";
139 static char OKstore[] = "2000 OK storage\n";
140 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
141 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
142 static char BADjob[] = "2901 Bad Job\n";
143 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
144 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
145 static char OKRunBefore[] = "2000 OK RunBefore\n";
146 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
147 static char OKRunAfter[] = "2000 OK RunAfter\n";
148 static char OKRunScript[] = "2000 OK RunScript\n";
151 /* Responses received from Storage Daemon */
152 static char OK_end[] = "3000 OK end\n";
153 static char OK_close[] = "3000 OK close Status = %d\n";
154 static char OK_open[] = "3000 OK open ticket = %d\n";
155 static char OK_data[] = "3000 OK data\n";
156 static char OK_append[] = "3000 OK append data\n";
157 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
160 /* Commands sent to Storage Daemon */
161 static char append_open[] = "append open session\n";
162 static char append_data[] = "append data %d\n";
163 static char append_end[] = "append end session %d\n";
164 static char append_close[] = "append close session %d\n";
165 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
166 static char read_data[] = "read data %d\n";
167 static char read_close[] = "read close session %d\n";
170 * Accept requests from a Director
172 * NOTE! We are running as a separate thread
174 * Send output one line
175 * at a time followed by a zero length transmission.
177 * Return when the connection is terminated or there
180 * Basic task here is:
181 * Authenticate Director (during Hello command).
182 * Accept commands one at a time from the Director
185 * Concerning ClientRunBefore/After, the sequence of events
186 * is rather critical. If they are not done in the right
187 * order one can easily get FD->SD timeouts if the script
190 * The current sequence of events is:
191 * 1. Dir starts job with FD
192 * 2. Dir connects to SD
193 * 3. Dir connects to FD
194 * 4. FD connects to SD
195 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
196 * 6. Dir sends include/exclude
197 * 7. FD sends data to SD
198 * 8. SD/FD disconnects while SD despools data and attributes (optionnal)
199 * 9. FD runs ClientRunAfterJob
202 void *handle_client_request(void *dirp)
207 BSOCK *dir = (BSOCK *)dirp;
209 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
210 jcr->dir_bsock = dir;
211 jcr->ff = init_find_files();
212 jcr->start_time = time(NULL);
213 jcr->RunScripts = New(alist(10, not_owned_by_alist));
214 jcr->last_fname = get_pool_memory(PM_FNAME);
215 jcr->last_fname[0] = 0;
216 jcr->client_name = get_memory(strlen(my_name) + 1);
217 new_plugins(jcr); /* instantiate plugins for this jcr */
218 pm_strcpy(jcr->client_name, my_name);
219 jcr->crypto.pki_sign = me->pki_sign;
220 jcr->crypto.pki_encrypt = me->pki_encrypt;
221 jcr->crypto.pki_keypair = me->pki_keypair;
222 jcr->crypto.pki_signers = me->pki_signers;
223 jcr->crypto.pki_recipients = me->pki_recipients;
225 enable_backup_privileges(NULL, 1 /* ignore_errors */);
227 /**********FIXME******* add command handler error code */
229 for (quit=false; !quit;) {
232 if (bnet_recv(dir) < 0) {
233 break; /* connection terminated */
235 dir->msg[dir->msglen] = 0;
236 Dmsg1(100, "<dird: %s", dir->msg);
238 for (i=0; cmds[i].cmd; i++) {
239 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
240 found = true; /* indicate command found */
241 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
242 bnet_fsend(dir, no_auth);
243 bnet_sig(dir, BNET_EOD);
246 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
247 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
248 bnet_fsend(dir, invalid_cmd);
249 bnet_sig(dir, BNET_EOD);
252 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
253 if (!cmds[i].func(jcr)) { /* do command */
254 quit = true; /* error or fully terminated, get out */
255 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
260 if (!found) { /* command not found */
261 bnet_fsend(dir, errmsg);
267 /* Inform Storage daemon that we are done */
268 if (jcr->store_bsock) {
269 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
272 /* Run the after job */
273 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
275 if (jcr->JobId) { /* send EndJob if running a job */
276 char ed1[50], ed2[50];
277 /* Send termination status back to Dir */
278 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
279 edit_uint64(jcr->ReadBytes, ed1),
280 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, jcr->VSS,
281 jcr->crypto.pki_encrypt);
282 Dmsg1(110, "End FD msg: %s\n", dir->msg);
285 generate_daemon_event(jcr, "JobEnd");
286 generate_plugin_event(jcr, bEventJobEnd);
288 dequeue_messages(jcr); /* send any queued messages */
290 /* Inform Director that we are done */
291 dir->signal(BNET_TERMINATE);
293 free_plugins(jcr); /* release instantiated plugins */
295 /* Clean up fileset */
296 FF_PKT *ff = jcr->ff;
297 findFILESET *fileset = ff->fileset;
300 /* Delete FileSet Include lists */
301 for (i=0; i<fileset->include_list.size(); i++) {
302 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
303 for (j=0; j<incexe->opts_list.size(); j++) {
304 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
305 for (k=0; k<fo->regex.size(); k++) {
306 regfree((regex_t *)fo->regex.get(k));
308 for (k=0; k<fo->regexdir.size(); k++) {
309 regfree((regex_t *)fo->regexdir.get(k));
311 for (k=0; k<fo->regexfile.size(); k++) {
312 regfree((regex_t *)fo->regexfile.get(k));
315 fo->regexdir.destroy();
316 fo->regexfile.destroy();
318 fo->wilddir.destroy();
319 fo->wildfile.destroy();
320 fo->wildbase.destroy();
322 fo->fstype.destroy();
323 fo->drivetype.destroy();
325 incexe->opts_list.destroy();
326 incexe->name_list.destroy();
327 incexe->plugin_list.destroy();
329 fileset->include_list.destroy();
331 /* Delete FileSet Exclude lists */
332 for (i=0; i<fileset->exclude_list.size(); i++) {
333 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
334 for (j=0; j<incexe->opts_list.size(); j++) {
335 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
337 fo->regexdir.destroy();
338 fo->regexfile.destroy();
340 fo->wilddir.destroy();
341 fo->wildfile.destroy();
342 fo->wildbase.destroy();
344 fo->fstype.destroy();
345 fo->drivetype.destroy();
347 incexe->opts_list.destroy();
348 incexe->name_list.destroy();
349 incexe->plugin_list.destroy();
351 fileset->exclude_list.destroy();
355 Dmsg0(100, "Calling term_find_files\n");
356 term_find_files(jcr->ff);
358 Dmsg0(100, "Done with term_find_files\n");
359 free_jcr(jcr); /* destroy JCR record */
360 Dmsg0(100, "Done with free_jcr\n");
366 * Hello from Director he must identify himself and provide his
369 static int hello_cmd(JCR *jcr)
371 Dmsg0(120, "Calling Authenticate\n");
372 if (!authenticate_director(jcr)) {
375 Dmsg0(120, "OK Authenticate\n");
376 jcr->authenticated = true;
383 static int cancel_cmd(JCR *jcr)
385 BSOCK *dir = jcr->dir_bsock;
386 char Job[MAX_NAME_LENGTH];
389 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
390 if (!(cjcr=get_jcr_by_full_name(Job))) {
391 dir->fsend(_("2901 Job %s not found.\n"), Job);
393 if (cjcr->store_bsock) {
394 cjcr->store_bsock->set_timed_out();
395 cjcr->store_bsock->set_terminated();
396 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
398 set_jcr_job_status(cjcr, JS_Canceled);
400 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
403 dir->fsend(_("2902 Error scanning cancel command.\n"));
405 dir->signal(BNET_EOD);
411 * Set debug level as requested by the Director
414 static int setdebug_cmd(JCR *jcr)
416 BSOCK *dir = jcr->dir_bsock;
417 int level, trace_flag;
419 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
420 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
421 pm_strcpy(jcr->errmsg, dir->msg);
422 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
426 set_trace(trace_flag);
427 return dir->fsend(OKsetdebug, level);
431 static int estimate_cmd(JCR *jcr)
433 BSOCK *dir = jcr->dir_bsock;
436 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
437 pm_strcpy(jcr->errmsg, dir->msg);
438 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
439 dir->fsend(_("2992 Bad estimate command.\n"));
443 dir->fsend(OKest, jcr->num_files_examined,
444 edit_uint64_with_commas(jcr->JobBytes, ed2));
445 dir->signal(BNET_EOD);
450 * Get JobId and Storage Daemon Authorization key from Director
452 static int job_cmd(JCR *jcr)
454 BSOCK *dir = jcr->dir_bsock;
455 POOLMEM *sd_auth_key;
457 sd_auth_key = get_memory(dir->msglen);
458 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
459 &jcr->VolSessionId, &jcr->VolSessionTime,
461 pm_strcpy(jcr->errmsg, dir->msg);
462 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
464 free_pool_memory(sd_auth_key);
467 jcr->sd_auth_key = bstrdup(sd_auth_key);
468 free_pool_memory(sd_auth_key);
469 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
470 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
471 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
472 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
475 static int runbefore_cmd(JCR *jcr)
478 BSOCK *dir = jcr->dir_bsock;
479 POOLMEM *cmd = get_memory(dir->msglen+1);
482 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
483 if (sscanf(dir->msg, runbefore, cmd) != 1) {
484 pm_strcpy(jcr->errmsg, dir->msg);
485 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
486 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
492 /* Run the command now */
493 script = new_runscript();
494 script->set_command(cmd);
495 script->when = SCRIPT_Before;
496 ok = script->run(jcr, "ClientRunBeforeJob");
497 free_runscript(script);
501 dir->fsend(OKRunBefore);
504 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
509 static int runbeforenow_cmd(JCR *jcr)
511 BSOCK *dir = jcr->dir_bsock;
513 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
514 if (job_canceled(jcr)) {
515 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
516 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
519 dir->fsend(OKRunBeforeNow);
520 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
525 static int runafter_cmd(JCR *jcr)
527 BSOCK *dir = jcr->dir_bsock;
528 POOLMEM *msg = get_memory(dir->msglen+1);
531 Dmsg1(100, "runafter_cmd: %s", dir->msg);
532 if (sscanf(dir->msg, runafter, msg) != 1) {
533 pm_strcpy(jcr->errmsg, dir->msg);
534 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
535 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
541 cmd = new_runscript();
542 cmd->set_command(msg);
543 cmd->on_success = true;
544 cmd->on_failure = false;
545 cmd->when = SCRIPT_After;
547 jcr->RunScripts->append(cmd);
549 free_pool_memory(msg);
550 return dir->fsend(OKRunAfter);
553 static int runscript_cmd(JCR *jcr)
555 BSOCK *dir = jcr->dir_bsock;
556 POOLMEM *msg = get_memory(dir->msglen+1);
557 int on_success, on_failure, fail_on_error;
559 RUNSCRIPT *cmd = new_runscript() ;
561 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
562 /* Note, we cannot sscanf into bools */
563 if (sscanf(dir->msg, runscript, &on_success,
568 pm_strcpy(jcr->errmsg, dir->msg);
569 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
570 dir->fsend(_("2905 Bad RunScript command.\n"));
575 cmd->on_success = on_success;
576 cmd->on_failure = on_failure;
577 cmd->fail_on_error = fail_on_error;
580 cmd->set_command(msg);
582 jcr->RunScripts->append(cmd);
584 free_pool_memory(msg);
585 return dir->fsend(OKRunScript);
589 static bool init_fileset(JCR *jcr)
592 findFILESET *fileset;
601 fileset = (findFILESET *)malloc(sizeof(findFILESET));
602 memset(fileset, 0, sizeof(findFILESET));
603 ff->fileset = fileset;
604 fileset->state = state_none;
605 fileset->include_list.init(1, true);
606 fileset->exclude_list.init(1, true);
610 static findFOPTS *start_options(FF_PKT *ff)
612 int state = ff->fileset->state;
613 findINCEXE *incexe = ff->fileset->incexe;
615 if (state != state_options) {
616 ff->fileset->state = state_options;
617 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
618 memset(fo, 0, sizeof(findFOPTS));
619 fo->regex.init(1, true);
620 fo->regexdir.init(1, true);
621 fo->regexfile.init(1, true);
622 fo->wild.init(1, true);
623 fo->wilddir.init(1, true);
624 fo->wildfile.init(1, true);
625 fo->wildbase.init(1, true);
626 fo->base.init(1, true);
627 fo->fstype.init(1, true);
628 fo->drivetype.init(1, true);
629 incexe->current_opts = fo;
630 incexe->opts_list.append(fo);
632 return incexe->current_opts;
637 * Add fname to include/exclude fileset list. First check for
638 * | and < and if necessary perform command.
640 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
655 p++; /* skip over | */
656 fn = get_pool_memory(PM_FNAME);
657 fn = edit_job_codes(jcr, fn, p, "");
658 bpipe = open_bpipe(fn, 0, "r");
661 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
663 free_pool_memory(fn);
666 free_pool_memory(fn);
667 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
668 strip_trailing_junk(buf);
670 fileset->incexe->name_list.append(new_dlistString(buf));
672 fileset->incexe->plugin_list.append(new_dlistString(buf));
675 if ((stat=close_bpipe(bpipe)) != 0) {
677 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
678 p, be.code(stat), be.bstrerror(stat));
683 Dmsg0(100, "Doing < include on client.\n");
684 p++; /* skip over < */
685 if ((ffd = fopen(p, "rb")) == NULL) {
687 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
691 while (fgets(buf, sizeof(buf), ffd)) {
692 strip_trailing_junk(buf);
693 Dmsg1(100, "%s\n", buf);
695 fileset->incexe->name_list.append(new_dlistString(buf));
697 fileset->incexe->plugin_list.append(new_dlistString(buf));
704 fileset->incexe->name_list.append(new_dlistString(fname));
706 fileset->incexe->plugin_list.append(new_dlistString(fname));
713 static void add_fileset(JCR *jcr, const char *item)
715 FF_PKT *ff = jcr->ff;
716 findFILESET *fileset = ff->fileset;
717 int state = fileset->state;
718 findFOPTS *current_opts;
720 /* Get code, optional subcode, and position item past the dividing space */
721 Dmsg1(100, "%s\n", item);
726 int subcode = ' '; /* A space is always a valid subcode */
727 if (item[0] != '\0' && item[0] != ' ') {
735 /* Skip all lines we receive after an error */
736 if (state == state_error) {
737 Dmsg0(100, "State=error return\n");
742 * The switch tests the code for validity.
743 * The subcode is always good if it is a space, otherwise we must confirm.
744 * We set state to state_error first assuming the subcode is invalid,
745 * requiring state to be set in cases below that handle subcodes.
747 if (subcode != ' ') {
749 Dmsg0(100, "Set state=error\n");
754 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
755 memset(fileset->incexe, 0, sizeof(findINCEXE));
756 fileset->incexe->opts_list.init(1, true);
757 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
758 fileset->incexe->plugin_list.init();
759 fileset->include_list.append(fileset->incexe);
763 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
764 memset(fileset->incexe, 0, sizeof(findINCEXE));
765 fileset->incexe->opts_list.init(1, true);
766 fileset->incexe->name_list.init();
767 fileset->incexe->plugin_list.init();
768 fileset->exclude_list.append(fileset->incexe);
774 /* File item to include or exclude list */
775 state = state_include;
776 add_file_to_fileset(jcr, item, fileset, true);
779 /* Plugin item to include list */
780 state = state_include;
781 add_file_to_fileset(jcr, item, fileset, false);
784 current_opts = start_options(ff);
788 preg = (regex_t *)malloc(sizeof(regex_t));
789 if (current_opts->flags & FO_IGNORECASE) {
790 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
792 rc = regcomp(preg, item, REG_EXTENDED);
795 regerror(rc, preg, prbuf, sizeof(prbuf));
798 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
802 state = state_options;
803 if (subcode == ' ') {
804 current_opts->regex.append(preg);
805 } else if (subcode == 'D') {
806 current_opts->regexdir.append(preg);
807 } else if (subcode == 'F') {
808 current_opts->regexfile.append(preg);
814 current_opts = start_options(ff);
815 current_opts->base.append(bstrdup(item));
816 state = state_options;
819 current_opts = start_options(ff);
820 state = state_options;
821 if (subcode == ' ') {
822 current_opts->fstype.append(bstrdup(item));
823 } else if (subcode == 'D') {
824 current_opts->drivetype.append(bstrdup(item));
830 current_opts = start_options(ff);
831 state = state_options;
832 if (subcode == ' ') {
833 current_opts->wild.append(bstrdup(item));
834 } else if (subcode == 'D') {
835 current_opts->wilddir.append(bstrdup(item));
836 } else if (subcode == 'F') {
837 current_opts->wildfile.append(bstrdup(item));
838 } else if (subcode == 'B') {
839 current_opts->wildbase.append(bstrdup(item));
845 current_opts = start_options(ff);
846 set_options(current_opts, item);
847 state = state_options;
850 current_opts = start_options(ff);
851 // current_opts->reader = bstrdup(item);
852 state = state_options;
855 current_opts = start_options(ff);
856 // current_opts->writer = bstrdup(item);
857 state = state_options;
860 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
864 ff->fileset->state = state;
867 static bool term_fileset(JCR *jcr)
869 FF_PKT *ff = jcr->ff;
871 #ifdef xxx_DEBUG_CODE
872 findFILESET *fileset = ff->fileset;
875 for (i=0; i<fileset->include_list.size(); i++) {
876 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
878 for (j=0; j<incexe->opts_list.size(); j++) {
879 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
880 for (k=0; k<fo->regex.size(); k++) {
881 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
883 for (k=0; k<fo->regexdir.size(); k++) {
884 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
886 for (k=0; k<fo->regexfile.size(); k++) {
887 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
889 for (k=0; k<fo->wild.size(); k++) {
890 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
892 for (k=0; k<fo->wilddir.size(); k++) {
893 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
895 for (k=0; k<fo->wildfile.size(); k++) {
896 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
898 for (k=0; k<fo->wildbase.size(); k++) {
899 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
901 for (k=0; k<fo->base.size(); k++) {
902 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
904 for (k=0; k<fo->fstype.size(); k++) {
905 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
907 for (k=0; k<fo->drivetype.size(); k++) {
908 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
912 foreach_dlist(node, &incexe->name_list) {
913 Dmsg1(400, "F %s\n", node->c_str());
915 foreach_dlist(node, &incexe->plugin_list) {
916 Dmsg1(400, "P %s\n", node->c_str());
919 for (i=0; i<fileset->exclude_list.size(); i++) {
920 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
922 for (j=0; j<incexe->opts_list.size(); j++) {
923 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
924 for (k=0; k<fo->regex.size(); k++) {
925 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
927 for (k=0; k<fo->regexdir.size(); k++) {
928 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
930 for (k=0; k<fo->regexfile.size(); k++) {
931 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
933 for (k=0; k<fo->wild.size(); k++) {
934 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
936 for (k=0; k<fo->wilddir.size(); k++) {
937 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
939 for (k=0; k<fo->wildfile.size(); k++) {
940 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
942 for (k=0; k<fo->wildbase.size(); k++) {
943 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
945 for (k=0; k<fo->base.size(); k++) {
946 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
948 for (k=0; k<fo->fstype.size(); k++) {
949 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
951 for (k=0; k<fo->drivetype.size(); k++) {
952 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
956 foreach_dlist(node, incexe->name_list) {
957 Dmsg1(400, "F %s\n", node->c_str());
959 foreach_dlist(node, &incexe->plugin_list) {
960 Dmsg1(400, "P %s\n", node->c_str());
964 return ff->fileset->state != state_error;
969 * As an optimization, we should do this during
970 * "compile" time in filed/job.c, and keep only a bit mask
971 * and the Verify options.
973 static void set_options(findFOPTS *fo, const char *opts)
979 // Commented out as it is not backward compatible - KES
981 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
984 for (p=opts; *p; p++) {
986 case 'a': /* alway replace */
987 case '0': /* no option */
990 fo->flags |= FO_EXCLUDE;
993 fo->flags |= FO_MULTIFS;
995 case 'h': /* no recursion */
996 fo->flags |= FO_NO_RECURSION;
998 case 'H': /* no hard link handling */
999 fo->flags |= FO_NO_HARDLINK;
1002 fo->flags |= FO_IGNORECASE;
1005 fo->flags |= FO_MD5;
1008 fo->flags |= FO_NOREPLACE;
1010 case 'p': /* use portable data format */
1011 fo->flags |= FO_PORTABLE;
1013 case 'R': /* Resource forks and Finder Info */
1014 fo->flags |= FO_HFSPLUS;
1015 case 'r': /* read fifo */
1016 fo->flags |= FO_READFIFO;
1021 fo->flags |= FO_SHA1;
1026 fo->flags |= FO_SHA256;
1030 fo->flags |= FO_SHA512;
1036 * If 2 or 3 is seen here, SHA2 is not configured, so
1037 * eat the option, and drop back to SHA-1.
1039 if (p[1] == '2' || p[1] == '3') {
1042 fo->flags |= FO_SHA1;
1047 fo->flags |= FO_SPARSE;
1050 fo->flags |= FO_MTIMEONLY;
1053 fo->flags |= FO_KEEPATIME;
1056 fo->flags |= FO_ACL;
1058 case 'V': /* verify options */
1059 /* Copy Verify Options */
1060 for (j=0; *p && *p != ':'; p++) {
1061 fo->VerifyOpts[j] = *p;
1062 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1066 fo->VerifyOpts[j] = 0;
1068 case 'C': /* accurate options */
1069 /* Copy Accurate Options */
1070 for (j=0; *p && *p != ':'; p++) {
1071 fo->AccurateOpts[j] = *p;
1072 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1076 fo->AccurateOpts[j] = 0;
1078 case 'P': /* strip path */
1081 for (j=0; *p && *p != ':'; p++) {
1083 if (j < (int)sizeof(strip) - 1) {
1088 fo->strip_path = atoi(strip);
1089 fo->flags |= FO_STRIPPATH;
1090 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1093 fo->flags |= FO_IF_NEWER;
1096 fo->flags |= FO_ENHANCEDWILD;
1098 case 'Z': /* gzip compression */
1099 fo->flags |= FO_GZIP;
1100 fo->GZIP_level = *++p - '0';
1103 fo->flags |= FO_NOATIME;
1106 fo->flags |= FO_CHKCHANGES;
1109 fo->flags |= FO_HONOR_NODUMP;
1112 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1120 * Director is passing his Fileset
1122 static int fileset_cmd(JCR *jcr)
1124 BSOCK *dir = jcr->dir_bsock;
1126 #if defined(WIN32_VSS)
1129 sscanf(dir->msg, "fileset vss=%d", &vss);
1133 if (!init_fileset(jcr)) {
1136 while (dir->recv() >= 0) {
1137 strip_trailing_junk(dir->msg);
1138 Dmsg1(500, "Fileset: %s\n", dir->msg);
1139 add_fileset(jcr, dir->msg);
1141 if (!term_fileset(jcr)) {
1144 return dir->fsend(OKinc);
1147 static void free_bootstrap(JCR *jcr)
1149 if (jcr->RestoreBootstrap) {
1150 unlink(jcr->RestoreBootstrap);
1151 free_pool_memory(jcr->RestoreBootstrap);
1152 jcr->RestoreBootstrap = NULL;
1157 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1158 static uint32_t bsr_uniq = 0;
1161 * The Director sends us the bootstrap file, which
1162 * we will in turn pass to the SD.
1164 static int bootstrap_cmd(JCR *jcr)
1166 BSOCK *dir = jcr->dir_bsock;
1167 POOLMEM *fname = get_pool_memory(PM_FNAME);
1170 free_bootstrap(jcr);
1173 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1174 jcr->Job, bsr_uniq);
1176 Dmsg1(400, "bootstrap=%s\n", fname);
1177 jcr->RestoreBootstrap = fname;
1178 bs = fopen(fname, "a+b"); /* create file */
1181 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1182 jcr->RestoreBootstrap, be.bstrerror());
1184 * Suck up what he is sending to us so that he will then
1185 * read our error message.
1187 while (dir->recv() >= 0)
1189 free_bootstrap(jcr);
1190 set_jcr_job_status(jcr, JS_ErrorTerminated);
1194 while (dir->recv() >= 0) {
1195 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1196 fputs(dir->msg, bs);
1200 * Note, do not free the bootstrap yet -- it needs to be
1203 return dir->fsend(OKbootstrap);
1208 * Get backup level from Director
1211 static int level_cmd(JCR *jcr)
1213 BSOCK *dir = jcr->dir_bsock;
1214 POOLMEM *level, *buf = NULL;
1217 level = get_memory(dir->msglen+1);
1218 Dmsg1(110, "level_cmd: %s", dir->msg);
1219 if (strstr(dir->msg, "accurate")) {
1220 jcr->accurate = true;
1222 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1225 /* Base backup requested? */
1226 if (strcmp(level, "base") == 0) {
1227 jcr->JobLevel = L_BASE;
1228 /* Full backup requested? */
1229 } else if (strcmp(level, "full") == 0) {
1230 jcr->JobLevel = L_FULL;
1231 } else if (strstr(level, "differential")) {
1232 jcr->JobLevel = L_DIFFERENTIAL;
1235 } else if (strstr(level, "incremental")) {
1236 jcr->JobLevel = L_INCREMENTAL;
1240 * We get his UTC since time, then sync the clocks and correct it
1241 * to agree with our clock.
1243 } else if (strcmp(level, "since_utime") == 0) {
1244 buf = get_memory(dir->msglen+1);
1245 utime_t since_time, adj;
1246 btime_t his_time, bt_start, rt=0, bt_adj=0;
1247 if (jcr->JobLevel == L_NONE) {
1248 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1250 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1251 buf, &mtime_only) != 2) {
1254 since_time = str_to_uint64(buf); /* this is the since time */
1255 Dmsg1(100, "since_time=%d\n", (int)since_time);
1256 char ed1[50], ed2[50];
1258 * Sync clocks by polling him for the time. We take
1259 * 10 samples of his time throwing out the first two.
1261 for (int i=0; i<10; i++) {
1262 bt_start = get_current_btime();
1263 dir->signal(BNET_BTIME); /* poll for time */
1264 if (dir->recv() <= 0) { /* get response */
1267 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1270 if (i < 2) { /* toss first two results */
1273 his_time = str_to_uint64(buf);
1274 rt = get_current_btime() - bt_start; /* compute round trip time */
1275 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1276 edit_uint64(bt_start, ed2));
1277 bt_adj += bt_start - his_time - rt/2;
1278 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1281 bt_adj = bt_adj / 8; /* compute average time */
1282 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1283 adj = btime_to_utime(bt_adj);
1284 since_time += adj; /* adjust for clock difference */
1285 /* Don't notify if time within 3 seconds */
1286 if (adj > 3 || adj < -3) {
1288 if (adj > 600 || adj < -600) {
1293 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1295 dir->signal(BNET_EOD);
1297 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1298 jcr->incremental = 1; /* set incremental or decremental backup */
1299 jcr->mtime = (time_t)since_time; /* set since time */
1300 generate_plugin_event(jcr, bEventSince, (void *)jcr->mtime);
1302 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1310 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1311 return dir->fsend(OKlevel);
1314 pm_strcpy(jcr->errmsg, dir->msg);
1315 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1324 * Get session parameters from Director -- this is for a Restore command
1326 static int session_cmd(JCR *jcr)
1328 BSOCK *dir = jcr->dir_bsock;
1330 Dmsg1(100, "SessionCmd: %s", dir->msg);
1331 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1332 &jcr->VolSessionId, &jcr->VolSessionTime,
1333 &jcr->StartFile, &jcr->EndFile,
1334 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1335 pm_strcpy(jcr->errmsg, dir->msg);
1336 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1340 return bnet_fsend(dir, OKsession);
1344 * Get address of storage daemon from Director
1347 static int storage_cmd(JCR *jcr)
1349 int stored_port; /* storage daemon port */
1350 int enable_ssl; /* enable ssl to sd */
1351 BSOCK *dir = jcr->dir_bsock;
1352 BSOCK *sd; /* storage daemon bsock */
1354 Dmsg1(100, "StorageCmd: %s", dir->msg);
1355 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1356 pm_strcpy(jcr->errmsg, dir->msg);
1357 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1360 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1361 /* Open command communications with Storage daemon */
1362 /* Try to connect for 1 hour at 10 second intervals */
1363 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1364 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1366 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1367 jcr->stored_addr, stored_port);
1368 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1369 jcr->stored_addr, stored_port);
1372 Dmsg0(110, "Connection OK to SD.\n");
1374 jcr->store_bsock = sd;
1376 sd->fsend("Hello Start Job %s\n", jcr->Job);
1377 if (!authenticate_storagedaemon(jcr)) {
1378 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1381 Dmsg0(110, "Authenticated with SD.\n");
1383 /* Send OK to Director */
1384 return dir->fsend(OKstore);
1391 static int backup_cmd(JCR *jcr)
1393 BSOCK *dir = jcr->dir_bsock;
1394 BSOCK *sd = jcr->store_bsock;
1398 #if defined(WIN32_VSS)
1399 // capture state here, if client is backed up by multiple directors
1400 // and one enables vss and the other does not then enable_vss can change
1401 // between here and where its evaluated after the job completes.
1402 jcr->VSS = g_pVSSClient && enable_vss;
1404 /* Run only one at a time */
1409 set_jcr_job_status(jcr, JS_Blocked);
1410 jcr->JobType = JT_BACKUP;
1411 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1414 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1418 dir->fsend(OKbackup);
1419 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1422 * Send Append Open Session to Storage daemon
1424 sd->fsend(append_open);
1425 Dmsg1(110, ">stored: %s", sd->msg);
1427 * Expect to receive back the Ticket number
1429 if (bget_msg(sd) >= 0) {
1430 Dmsg1(110, "<stored: %s", sd->msg);
1431 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1432 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1435 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1437 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1442 * Send Append data command to Storage daemon
1444 sd->fsend(append_data, jcr->Ticket);
1445 Dmsg1(110, ">stored: %s", sd->msg);
1448 * Expect to get OK data
1450 Dmsg1(110, "<stored: %s", sd->msg);
1451 if (!response(jcr, sd, OK_data, "Append Data")) {
1455 generate_daemon_event(jcr, "JobStart");
1456 generate_plugin_event(jcr, bEventStartBackupJob);
1458 #if defined(WIN32_VSS)
1459 /* START VSS ON WIN32 */
1461 if (g_pVSSClient->InitializeForBackup()) {
1462 /* tell vss which drives to snapshot */
1463 char szWinDriveLetters[27];
1464 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1465 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1466 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1467 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1470 /* tell user if snapshot creation of a specific drive failed */
1472 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1473 if (islower(szWinDriveLetters[i])) {
1474 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1478 /* inform user about writer states */
1479 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1480 if (g_pVSSClient->GetWriterState(i) < 1) {
1481 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1486 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1490 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1492 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1497 * Send Files to Storage daemon
1499 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1500 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1501 set_jcr_job_status(jcr, JS_ErrorTerminated);
1502 bnet_suppress_error_messages(sd, 1);
1503 bget_msg(sd); /* Read final response from append_data */
1504 Dmsg0(110, "Error in blast_data.\n");
1506 set_jcr_job_status(jcr, JS_Terminated);
1508 if (jcr->JobStatus != JS_Terminated) {
1509 bnet_suppress_error_messages(sd, 1);
1510 goto cleanup; /* bail out now */
1513 * Expect to get response to append_data from Storage daemon
1515 if (!response(jcr, sd, OK_append, "Append Data")) {
1516 set_jcr_job_status(jcr, JS_ErrorTerminated);
1521 * Send Append End Data to Storage daemon
1523 sd->fsend(append_end, jcr->Ticket);
1525 if (!response(jcr, sd, OK_end, "Append End")) {
1526 set_jcr_job_status(jcr, JS_ErrorTerminated);
1531 * Send Append Close to Storage daemon
1533 sd->fsend(append_close, jcr->Ticket);
1534 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1535 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1537 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1541 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1544 if (SDJobStatus != JS_Terminated) {
1545 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1551 #if defined(WIN32_VSS)
1552 /* STOP VSS ON WIN32 */
1553 /* tell vss to close the backup session */
1555 if (g_pVSSClient->CloseBackup()) {
1556 /* inform user about writer states */
1557 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1558 int msg_type = M_INFO;
1559 if (g_pVSSClient->GetWriterState(i) < 1) {
1560 msg_type = M_WARNING;
1563 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1570 generate_plugin_event(jcr, bEventEndBackupJob);
1571 return 0; /* return and stop command loop */
1575 * Do a Verify for Director
1578 static int verify_cmd(JCR *jcr)
1580 BSOCK *dir = jcr->dir_bsock;
1581 BSOCK *sd = jcr->store_bsock;
1584 jcr->JobType = JT_VERIFY;
1585 if (sscanf(dir->msg, verifycmd, level) != 1) {
1586 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1590 if (strcasecmp(level, "init") == 0) {
1591 jcr->JobLevel = L_VERIFY_INIT;
1592 } else if (strcasecmp(level, "catalog") == 0){
1593 jcr->JobLevel = L_VERIFY_CATALOG;
1594 } else if (strcasecmp(level, "volume") == 0){
1595 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1596 } else if (strcasecmp(level, "data") == 0){
1597 jcr->JobLevel = L_VERIFY_DATA;
1598 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1599 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1601 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1605 dir->fsend(OKverify);
1607 generate_daemon_event(jcr, "JobStart");
1608 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1609 generate_plugin_event(jcr, bEventStartVerifyJob);
1611 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1613 switch (jcr->JobLevel) {
1615 case L_VERIFY_CATALOG:
1618 case L_VERIFY_VOLUME_TO_CATALOG:
1619 if (!open_sd_read_session(jcr)) {
1622 start_dir_heartbeat(jcr);
1623 do_verify_volume(jcr);
1624 stop_dir_heartbeat(jcr);
1626 * Send Close session command to Storage daemon
1628 sd->fsend(read_close, jcr->Ticket);
1629 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1631 /* ****FIXME**** check response */
1632 bget_msg(sd); /* get OK */
1634 /* Inform Storage daemon that we are done */
1635 sd->signal(BNET_TERMINATE);
1638 case L_VERIFY_DISK_TO_CATALOG:
1642 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1646 dir->signal(BNET_EOD);
1647 generate_plugin_event(jcr, bEventEndVerifyJob);
1648 return 0; /* return and terminate command loop */
1652 * Do a Restore for Director
1655 static int restore_cmd(JCR *jcr)
1657 BSOCK *dir = jcr->dir_bsock;
1658 BSOCK *sd = jcr->store_bsock;
1660 bool use_regexwhere=false;
1665 * Scan WHERE (base directory for restore) from command
1667 Dmsg0(150, "restore command\n");
1668 /* Pickup where string */
1669 args = get_memory(dir->msglen+1);
1672 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1673 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1674 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1675 pm_strcpy(jcr->errmsg, dir->msg);
1676 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1681 use_regexwhere = true;
1683 /* Turn / into nothing */
1684 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1688 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1689 unbash_spaces(args);
1691 if (use_regexwhere) {
1692 jcr->where_bregexp = get_bregexps(args);
1693 if (!jcr->where_bregexp) {
1694 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1695 free_pool_memory(args);
1699 jcr->where = bstrdup(args);
1702 free_pool_memory(args);
1703 jcr->replace = replace;
1704 jcr->prefix_links = prefix_links;
1706 dir->fsend(OKrestore);
1707 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1709 jcr->JobType = JT_RESTORE;
1711 set_jcr_job_status(jcr, JS_Blocked);
1713 if (!open_sd_read_session(jcr)) {
1714 set_jcr_job_status(jcr, JS_ErrorTerminated);
1718 set_jcr_job_status(jcr, JS_Running);
1721 * Do restore of files and data
1723 start_dir_heartbeat(jcr);
1724 generate_daemon_event(jcr, "JobStart");
1725 generate_plugin_event(jcr, bEventStartRestoreJob);
1727 stop_dir_heartbeat(jcr);
1729 set_jcr_job_status(jcr, JS_Terminated);
1730 if (jcr->JobStatus != JS_Terminated) {
1731 bnet_suppress_error_messages(sd, 1);
1735 * Send Close session command to Storage daemon
1737 sd->fsend(read_close, jcr->Ticket);
1738 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1740 bget_msg(sd); /* get OK */
1742 /* Inform Storage daemon that we are done */
1743 sd->signal(BNET_TERMINATE);
1748 set_jcr_job_status(jcr, JS_ErrorTerminated);
1751 Dmsg0(130, "Done in job.c\n");
1752 generate_plugin_event(jcr, bEventEndRestoreJob);
1753 return 0; /* return and terminate command loop */
1756 static int open_sd_read_session(JCR *jcr)
1758 BSOCK *sd = jcr->store_bsock;
1761 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1764 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1765 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1766 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1768 * Open Read Session with Storage daemon
1770 bnet_fsend(sd, read_open, "DummyVolume",
1771 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1772 jcr->StartBlock, jcr->EndBlock);
1773 Dmsg1(110, ">stored: %s", sd->msg);
1778 if (bget_msg(sd) >= 0) {
1779 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1780 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1781 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1784 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1786 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1790 if (!send_bootstrap_file(jcr)) {
1795 * Start read of data with Storage daemon
1797 bnet_fsend(sd, read_data, jcr->Ticket);
1798 Dmsg1(110, ">stored: %s", sd->msg);
1803 if (!response(jcr, sd, OK_data, "Read Data")) {
1810 * Destroy the Job Control Record and associated
1811 * resources (sockets).
1813 static void filed_free_jcr(JCR *jcr)
1815 if (jcr->store_bsock) {
1816 bnet_close(jcr->store_bsock);
1818 free_bootstrap(jcr);
1819 if (jcr->last_fname) {
1820 free_pool_memory(jcr->last_fname);
1822 free_runscripts(jcr->RunScripts);
1823 delete jcr->RunScripts;
1825 if (jcr->JobId != 0)
1826 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1832 * Get response from Storage daemon to a command we
1833 * sent. Check that the response is OK.
1835 * Returns: 0 on failure
1838 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1843 if (bget_msg(sd) > 0) {
1844 Dmsg0(110, sd->msg);
1845 if (strcmp(sd->msg, resp) == 0) {
1849 if (job_canceled(jcr)) {
1850 return 0; /* if canceled avoid useless error messages */
1852 if (is_bnet_error(sd)) {
1853 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1854 cmd, bnet_strerror(sd));
1856 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1857 cmd, resp, sd->msg);
1862 static int send_bootstrap_file(JCR *jcr)
1866 BSOCK *sd = jcr->store_bsock;
1867 const char *bootstrap = "bootstrap\n";
1870 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1871 if (!jcr->RestoreBootstrap) {
1874 bs = fopen(jcr->RestoreBootstrap, "rb");
1877 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1878 jcr->RestoreBootstrap, be.bstrerror());
1879 set_jcr_job_status(jcr, JS_ErrorTerminated);
1882 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1884 while (fgets(buf, sizeof(buf), bs)) {
1885 sd->msglen = Mmsg(sd->msg, "%s", buf);
1888 bnet_sig(sd, BNET_EOD);
1890 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1891 set_jcr_job_status(jcr, JS_ErrorTerminated);
1897 free_bootstrap(jcr);