2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 Kern Sibbald.
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 = 0;
48 * As Windows saves ACLs as part of the standard backup stream
49 * we just pretend here that is has implicit acl support.
51 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
52 const bool have_acl = true;
54 const bool have_acl = false;
57 #if defined(HAVE_XATTR)
58 const bool have_xattr = true;
60 const bool have_xattr = false;
63 extern CLIENT *me; /* our client resource */
65 /* Imported functions */
66 extern int status_cmd(JCR *jcr);
67 extern int qstatus_cmd(JCR *jcr);
68 extern int accurate_cmd(JCR *jcr);
70 /* Forward referenced functions */
71 static int backup_cmd(JCR *jcr);
72 static int bootstrap_cmd(JCR *jcr);
73 static int cancel_cmd(JCR *jcr);
74 static int setdebug_cmd(JCR *jcr);
75 static int estimate_cmd(JCR *jcr);
76 static int hello_cmd(JCR *jcr);
77 static int job_cmd(JCR *jcr);
78 static int fileset_cmd(JCR *jcr);
79 static int level_cmd(JCR *jcr);
80 static int verify_cmd(JCR *jcr);
81 static int restore_cmd(JCR *jcr);
82 static int storage_cmd(JCR *jcr);
83 static int session_cmd(JCR *jcr);
84 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
85 static void filed_free_jcr(JCR *jcr);
86 static int open_sd_read_session(JCR *jcr);
87 static int send_bootstrap_file(JCR *jcr);
88 static int runscript_cmd(JCR *jcr);
89 static int runbefore_cmd(JCR *jcr);
90 static int runafter_cmd(JCR *jcr);
91 static int runbeforenow_cmd(JCR *jcr);
92 static void set_options(findFOPTS *fo, const char *opts);
95 /* Exported functions */
100 int monitoraccess; /* specify if monitors have access to this function */
104 * The following are the recognized commands from the Director.
106 static struct s_cmds cmds[] = {
107 {"backup", backup_cmd, 0},
108 {"cancel", cancel_cmd, 0},
109 {"setdebug=", setdebug_cmd, 0},
110 {"estimate", estimate_cmd, 0},
111 {"Hello", hello_cmd, 1},
112 {"fileset", fileset_cmd, 0},
113 {"JobId=", job_cmd, 0},
114 {"level = ", level_cmd, 0},
115 {"restore", restore_cmd, 0},
116 {"session", session_cmd, 0},
117 {"status", status_cmd, 1},
118 {".status", qstatus_cmd, 1},
119 {"storage ", storage_cmd, 0},
120 {"verify", verify_cmd, 0},
121 {"bootstrap", bootstrap_cmd, 0},
122 {"RunBeforeNow", runbeforenow_cmd, 0},
123 {"RunBeforeJob", runbefore_cmd, 0},
124 {"RunAfterJob", runafter_cmd, 0},
125 {"Run", runscript_cmd, 0},
126 {"accurate", accurate_cmd, 0},
127 {NULL, NULL} /* list terminator */
130 /* Commands received from director that need scanning */
131 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
132 static char storaddr[] = "storage address=%s port=%d ssl=%d";
133 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
134 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
135 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
136 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
137 static char verifycmd[] = "verify level=%30s";
138 static char estimatecmd[] = "estimate listing=%d";
139 static char runbefore[] = "RunBeforeJob %s";
140 static char runafter[] = "RunAfterJob %s";
141 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
143 /* Responses sent to Director */
144 static char errmsg[] = "2999 Invalid command\n";
145 static char no_auth[] = "2998 No Authorization\n";
146 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
147 static char OKinc[] = "2000 OK include\n";
148 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
149 static char OKlevel[] = "2000 OK level\n";
150 static char OKbackup[] = "2000 OK backup\n";
151 static char OKbootstrap[] = "2000 OK bootstrap\n";
152 static char OKverify[] = "2000 OK verify\n";
153 static char OKrestore[] = "2000 OK restore\n";
154 static char OKsession[] = "2000 OK session\n";
155 static char OKstore[] = "2000 OK storage\n";
156 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
157 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
158 static char BADjob[] = "2901 Bad Job\n";
159 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
160 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
161 static char OKRunBefore[] = "2000 OK RunBefore\n";
162 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
163 static char OKRunAfter[] = "2000 OK RunAfter\n";
164 static char OKRunScript[] = "2000 OK RunScript\n";
165 static char BADcmd[] = "2902 Bad %s\n";
168 /* Responses received from Storage Daemon */
169 static char OK_end[] = "3000 OK end\n";
170 static char OK_close[] = "3000 OK close Status = %d\n";
171 static char OK_open[] = "3000 OK open ticket = %d\n";
172 static char OK_data[] = "3000 OK data\n";
173 static char OK_append[] = "3000 OK append data\n";
174 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
177 /* Commands sent to Storage Daemon */
178 static char append_open[] = "append open session\n";
179 static char append_data[] = "append data %d\n";
180 static char append_end[] = "append end session %d\n";
181 static char append_close[] = "append close session %d\n";
182 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
183 static char read_data[] = "read data %d\n";
184 static char read_close[] = "read close session %d\n";
187 * Accept requests from a Director
189 * NOTE! We are running as a separate thread
191 * Send output one line
192 * at a time followed by a zero length transmission.
194 * Return when the connection is terminated or there
197 * Basic task here is:
198 * Authenticate Director (during Hello command).
199 * Accept commands one at a time from the Director
202 * Concerning ClientRunBefore/After, the sequence of events
203 * is rather critical. If they are not done in the right
204 * order one can easily get FD->SD timeouts if the script
207 * The current sequence of events is:
208 * 1. Dir starts job with FD
209 * 2. Dir connects to SD
210 * 3. Dir connects to FD
211 * 4. FD connects to SD
212 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
213 * 6. Dir sends include/exclude
214 * 7. FD sends data to SD
215 * 8. SD/FD disconnects while SD despools data and attributes (optional)
216 * 9. FD runs ClientRunAfterJob
219 void *handle_client_request(void *dirp)
224 BSOCK *dir = (BSOCK *)dirp;
225 const char jobname[12] = "*Director*";
227 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
228 jcr->dir_bsock = dir;
229 jcr->ff = init_find_files();
230 jcr->start_time = time(NULL);
231 jcr->RunScripts = New(alist(10, not_owned_by_alist));
232 jcr->last_fname = get_pool_memory(PM_FNAME);
233 jcr->last_fname[0] = 0;
234 jcr->client_name = get_memory(strlen(my_name) + 1);
235 pm_strcpy(jcr->client_name, my_name);
236 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
237 jcr->crypto.pki_sign = me->pki_sign;
238 jcr->crypto.pki_encrypt = me->pki_encrypt;
239 jcr->crypto.pki_keypair = me->pki_keypair;
240 jcr->crypto.pki_signers = me->pki_signers;
241 jcr->crypto.pki_recipients = me->pki_recipients;
243 enable_backup_privileges(NULL, 1 /* ignore_errors */);
245 /**********FIXME******* add command handler error code */
247 for (quit=false; !quit;) {
249 if (dir->recv() < 0) {
250 break; /* connection terminated */
252 dir->msg[dir->msglen] = 0;
253 Dmsg1(100, "<dird: %s", dir->msg);
255 for (i=0; cmds[i].cmd; i++) {
256 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
257 found = true; /* indicate command found */
258 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
260 dir->signal(BNET_EOD);
263 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
264 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
265 dir->fsend(invalid_cmd);
266 dir->signal(BNET_EOD);
269 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
270 if (!cmds[i].func(jcr)) { /* do command */
271 quit = true; /* error or fully terminated, get out */
272 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
277 if (!found) { /* command not found */
284 /* Inform Storage daemon that we are done */
285 if (jcr->store_bsock) {
286 jcr->store_bsock->signal(BNET_TERMINATE);
289 /* Run the after job */
290 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
292 if (jcr->JobId) { /* send EndJob if running a job */
293 char ed1[50], ed2[50];
294 /* Send termination status back to Dir */
295 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
296 edit_uint64(jcr->ReadBytes, ed1),
297 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
298 jcr->crypto.pki_encrypt);
299 Dmsg1(110, "End FD msg: %s\n", dir->msg);
302 generate_daemon_event(jcr, "JobEnd");
303 generate_plugin_event(jcr, bEventJobEnd);
305 dequeue_messages(jcr); /* send any queued messages */
307 /* Inform Director that we are done */
308 dir->signal(BNET_TERMINATE);
310 free_plugins(jcr); /* release instantiated plugins */
312 /* Clean up fileset */
313 FF_PKT *ff = jcr->ff;
314 findFILESET *fileset = ff->fileset;
317 /* Delete FileSet Include lists */
318 for (i=0; i<fileset->include_list.size(); i++) {
319 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
320 for (j=0; j<incexe->opts_list.size(); j++) {
321 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
322 for (k=0; k<fo->regex.size(); k++) {
323 regfree((regex_t *)fo->regex.get(k));
325 for (k=0; k<fo->regexdir.size(); k++) {
326 regfree((regex_t *)fo->regexdir.get(k));
328 for (k=0; k<fo->regexfile.size(); k++) {
329 regfree((regex_t *)fo->regexfile.get(k));
332 fo->regexdir.destroy();
333 fo->regexfile.destroy();
335 fo->wilddir.destroy();
336 fo->wildfile.destroy();
337 fo->wildbase.destroy();
339 fo->fstype.destroy();
340 fo->drivetype.destroy();
341 if (fo->ignoredir != NULL) {
345 incexe->opts_list.destroy();
346 incexe->name_list.destroy();
347 incexe->plugin_list.destroy();
349 fileset->include_list.destroy();
351 /* Delete FileSet Exclude lists */
352 for (i=0; i<fileset->exclude_list.size(); i++) {
353 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
354 for (j=0; j<incexe->opts_list.size(); j++) {
355 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
357 fo->regexdir.destroy();
358 fo->regexfile.destroy();
360 fo->wilddir.destroy();
361 fo->wildfile.destroy();
362 fo->wildbase.destroy();
364 fo->fstype.destroy();
365 fo->drivetype.destroy();
367 incexe->opts_list.destroy();
368 incexe->name_list.destroy();
369 incexe->plugin_list.destroy();
371 fileset->exclude_list.destroy();
375 Dmsg0(100, "Calling term_find_files\n");
376 term_find_files(jcr->ff);
378 Dmsg0(100, "Done with term_find_files\n");
379 free_jcr(jcr); /* destroy JCR record */
380 Dmsg0(100, "Done with free_jcr\n");
386 * Hello from Director he must identify himself and provide his
389 static int hello_cmd(JCR *jcr)
391 Dmsg0(120, "Calling Authenticate\n");
392 if (!authenticate_director(jcr)) {
395 Dmsg0(120, "OK Authenticate\n");
396 jcr->authenticated = true;
403 static int cancel_cmd(JCR *jcr)
405 BSOCK *dir = jcr->dir_bsock;
406 char Job[MAX_NAME_LENGTH];
409 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
410 if (!(cjcr=get_jcr_by_full_name(Job))) {
411 dir->fsend(_("2901 Job %s not found.\n"), Job);
413 if (cjcr->store_bsock) {
414 cjcr->store_bsock->set_timed_out();
415 cjcr->store_bsock->set_terminated();
416 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
418 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
419 set_jcr_job_status(cjcr, JS_Canceled);
421 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
424 dir->fsend(_("2902 Error scanning cancel command.\n"));
426 dir->signal(BNET_EOD);
432 * Set debug level as requested by the Director
435 static int setdebug_cmd(JCR *jcr)
437 BSOCK *dir = jcr->dir_bsock;
438 int level, trace_flag;
440 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
441 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
442 pm_strcpy(jcr->errmsg, dir->msg);
443 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
447 set_trace(trace_flag);
448 return dir->fsend(OKsetdebug, level);
452 static int estimate_cmd(JCR *jcr)
454 BSOCK *dir = jcr->dir_bsock;
457 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
458 pm_strcpy(jcr->errmsg, dir->msg);
459 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
460 dir->fsend(_("2992 Bad estimate command.\n"));
464 dir->fsend(OKest, jcr->num_files_examined,
465 edit_uint64_with_commas(jcr->JobBytes, ed2));
466 dir->signal(BNET_EOD);
471 * Get JobId and Storage Daemon Authorization key from Director
473 static int job_cmd(JCR *jcr)
475 BSOCK *dir = jcr->dir_bsock;
476 POOLMEM *sd_auth_key;
478 sd_auth_key = get_memory(dir->msglen);
479 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
480 &jcr->VolSessionId, &jcr->VolSessionTime,
482 pm_strcpy(jcr->errmsg, dir->msg);
483 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
485 free_pool_memory(sd_auth_key);
488 jcr->sd_auth_key = bstrdup(sd_auth_key);
489 free_pool_memory(sd_auth_key);
490 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
491 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
492 new_plugins(jcr); /* instantiate plugins for this jcr */
493 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
494 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
497 static int runbefore_cmd(JCR *jcr)
500 BSOCK *dir = jcr->dir_bsock;
501 POOLMEM *cmd = get_memory(dir->msglen+1);
504 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
505 if (sscanf(dir->msg, runbefore, cmd) != 1) {
506 pm_strcpy(jcr->errmsg, dir->msg);
507 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
508 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
514 /* Run the command now */
515 script = new_runscript();
516 script->set_command(cmd);
517 script->when = SCRIPT_Before;
518 ok = script->run(jcr, "ClientRunBeforeJob");
519 free_runscript(script);
523 dir->fsend(OKRunBefore);
526 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
531 static int runbeforenow_cmd(JCR *jcr)
533 BSOCK *dir = jcr->dir_bsock;
535 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
536 if (job_canceled(jcr)) {
537 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
538 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
541 dir->fsend(OKRunBeforeNow);
542 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
547 static int runafter_cmd(JCR *jcr)
549 BSOCK *dir = jcr->dir_bsock;
550 POOLMEM *msg = get_memory(dir->msglen+1);
553 Dmsg1(100, "runafter_cmd: %s", dir->msg);
554 if (sscanf(dir->msg, runafter, msg) != 1) {
555 pm_strcpy(jcr->errmsg, dir->msg);
556 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
557 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
563 cmd = new_runscript();
564 cmd->set_command(msg);
565 cmd->on_success = true;
566 cmd->on_failure = false;
567 cmd->when = SCRIPT_After;
569 jcr->RunScripts->append(cmd);
571 free_pool_memory(msg);
572 return dir->fsend(OKRunAfter);
575 static int runscript_cmd(JCR *jcr)
577 BSOCK *dir = jcr->dir_bsock;
578 POOLMEM *msg = get_memory(dir->msglen+1);
579 int on_success, on_failure, fail_on_error;
581 RUNSCRIPT *cmd = new_runscript() ;
583 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
584 /* Note, we cannot sscanf into bools */
585 if (sscanf(dir->msg, runscript, &on_success,
590 pm_strcpy(jcr->errmsg, dir->msg);
591 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
592 dir->fsend(_("2905 Bad RunScript command.\n"));
597 cmd->on_success = on_success;
598 cmd->on_failure = on_failure;
599 cmd->fail_on_error = fail_on_error;
602 cmd->set_command(msg);
604 jcr->RunScripts->append(cmd);
606 free_pool_memory(msg);
607 return dir->fsend(OKRunScript);
611 static bool init_fileset(JCR *jcr)
614 findFILESET *fileset;
623 fileset = (findFILESET *)malloc(sizeof(findFILESET));
624 memset(fileset, 0, sizeof(findFILESET));
625 ff->fileset = fileset;
626 fileset->state = state_none;
627 fileset->include_list.init(1, true);
628 fileset->exclude_list.init(1, true);
632 static findFOPTS *start_options(FF_PKT *ff)
634 int state = ff->fileset->state;
635 findINCEXE *incexe = ff->fileset->incexe;
637 if (state != state_options) {
638 ff->fileset->state = state_options;
639 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
640 memset(fo, 0, sizeof(findFOPTS));
641 fo->regex.init(1, true);
642 fo->regexdir.init(1, true);
643 fo->regexfile.init(1, true);
644 fo->wild.init(1, true);
645 fo->wilddir.init(1, true);
646 fo->wildfile.init(1, true);
647 fo->wildbase.init(1, true);
648 fo->base.init(1, true);
649 fo->fstype.init(1, true);
650 fo->drivetype.init(1, true);
651 incexe->current_opts = fo;
652 incexe->opts_list.append(fo);
654 return incexe->current_opts;
659 * Add fname to include/exclude fileset list. First check for
660 * | and < and if necessary perform command.
662 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
677 p++; /* skip over | */
678 fn = get_pool_memory(PM_FNAME);
679 fn = edit_job_codes(jcr, fn, p, "");
680 bpipe = open_bpipe(fn, 0, "r");
683 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
685 free_pool_memory(fn);
688 free_pool_memory(fn);
689 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
690 strip_trailing_junk(buf);
692 fileset->incexe->name_list.append(new_dlistString(buf));
694 fileset->incexe->plugin_list.append(new_dlistString(buf));
697 if ((stat=close_bpipe(bpipe)) != 0) {
699 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
700 p, be.code(stat), be.bstrerror(stat));
705 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
706 p++; /* skip over < */
707 if ((ffd = fopen(p, "rb")) == NULL) {
709 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
713 while (fgets(buf, sizeof(buf), ffd)) {
714 strip_trailing_junk(buf);
715 Dmsg1(100, "%s\n", buf);
717 fileset->incexe->name_list.append(new_dlistString(buf));
719 fileset->incexe->plugin_list.append(new_dlistString(buf));
726 fileset->incexe->name_list.append(new_dlistString(fname));
728 if (me->plugin_directory) {
729 fileset->incexe->plugin_list.append(new_dlistString(fname));
731 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
740 static void add_fileset(JCR *jcr, const char *item)
742 FF_PKT *ff = jcr->ff;
743 findFILESET *fileset = ff->fileset;
744 int state = fileset->state;
745 findFOPTS *current_opts;
747 /* Get code, optional subcode, and position item past the dividing space */
748 Dmsg1(100, "%s\n", item);
753 int subcode = ' '; /* A space is always a valid subcode */
754 if (item[0] != '\0' && item[0] != ' ') {
762 /* Skip all lines we receive after an error */
763 if (state == state_error) {
764 Dmsg0(100, "State=error return\n");
769 * The switch tests the code for validity.
770 * The subcode is always good if it is a space, otherwise we must confirm.
771 * We set state to state_error first assuming the subcode is invalid,
772 * requiring state to be set in cases below that handle subcodes.
774 if (subcode != ' ') {
776 Dmsg0(100, "Set state=error or double code.\n");
781 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
782 memset(fileset->incexe, 0, sizeof(findINCEXE));
783 fileset->incexe->opts_list.init(1, true);
784 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
785 fileset->incexe->plugin_list.init();
786 fileset->include_list.append(fileset->incexe);
790 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
791 memset(fileset->incexe, 0, sizeof(findINCEXE));
792 fileset->incexe->opts_list.init(1, true);
793 fileset->incexe->name_list.init();
794 fileset->incexe->plugin_list.init();
795 fileset->exclude_list.append(fileset->incexe);
801 /* File item to include or exclude list */
802 state = state_include;
803 add_file_to_fileset(jcr, item, fileset, true);
806 /* Plugin item to include list */
807 state = state_include;
808 add_file_to_fileset(jcr, item, fileset, false);
811 current_opts = start_options(ff);
815 preg = (regex_t *)malloc(sizeof(regex_t));
816 if (current_opts->flags & FO_IGNORECASE) {
817 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
819 rc = regcomp(preg, item, REG_EXTENDED);
822 regerror(rc, preg, prbuf, sizeof(prbuf));
825 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
829 state = state_options;
830 if (subcode == ' ') {
831 current_opts->regex.append(preg);
832 } else if (subcode == 'D') {
833 current_opts->regexdir.append(preg);
834 } else if (subcode == 'F') {
835 current_opts->regexfile.append(preg);
841 current_opts = start_options(ff);
842 current_opts->base.append(bstrdup(item));
843 state = state_options;
846 current_opts = start_options(ff);
847 state = state_options;
848 if (subcode == ' ') {
849 current_opts->fstype.append(bstrdup(item));
850 } else if (subcode == 'D') {
851 current_opts->drivetype.append(bstrdup(item));
857 current_opts = start_options(ff);
858 state = state_options;
859 if (subcode == ' ') {
860 current_opts->wild.append(bstrdup(item));
861 } else if (subcode == 'D') {
862 current_opts->wilddir.append(bstrdup(item));
863 } else if (subcode == 'F') {
864 current_opts->wildfile.append(bstrdup(item));
865 } else if (subcode == 'B') {
866 current_opts->wildbase.append(bstrdup(item));
872 current_opts = start_options(ff);
873 set_options(current_opts, item);
874 state = state_options;
877 current_opts = start_options(ff);
878 current_opts->ignoredir = bstrdup(item);
879 state = state_options;
882 current_opts = start_options(ff);
883 // current_opts->reader = bstrdup(item);
884 state = state_options;
887 current_opts = start_options(ff);
888 // current_opts->writer = bstrdup(item);
889 state = state_options;
892 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
896 ff->fileset->state = state;
899 static bool term_fileset(JCR *jcr)
901 FF_PKT *ff = jcr->ff;
903 #ifdef xxx_DEBUG_CODE
904 findFILESET *fileset = ff->fileset;
907 for (i=0; i<fileset->include_list.size(); i++) {
908 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
910 for (j=0; j<incexe->opts_list.size(); j++) {
911 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
912 for (k=0; k<fo->regex.size(); k++) {
913 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
915 for (k=0; k<fo->regexdir.size(); k++) {
916 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
918 for (k=0; k<fo->regexfile.size(); k++) {
919 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
921 for (k=0; k<fo->wild.size(); k++) {
922 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
924 for (k=0; k<fo->wilddir.size(); k++) {
925 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
927 for (k=0; k<fo->wildfile.size(); k++) {
928 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
930 for (k=0; k<fo->wildbase.size(); k++) {
931 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
933 for (k=0; k<fo->base.size(); k++) {
934 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
936 for (k=0; k<fo->fstype.size(); k++) {
937 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
939 for (k=0; k<fo->drivetype.size(); k++) {
940 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
943 Dmsg1(400, "Z %s\n", fo->ignoredir);
947 foreach_dlist(node, &incexe->name_list) {
948 Dmsg1(400, "F %s\n", node->c_str());
950 foreach_dlist(node, &incexe->plugin_list) {
951 Dmsg1(400, "P %s\n", node->c_str());
954 for (i=0; i<fileset->exclude_list.size(); i++) {
955 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
957 for (j=0; j<incexe->opts_list.size(); j++) {
958 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
959 for (k=0; k<fo->regex.size(); k++) {
960 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
962 for (k=0; k<fo->regexdir.size(); k++) {
963 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
965 for (k=0; k<fo->regexfile.size(); k++) {
966 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
968 for (k=0; k<fo->wild.size(); k++) {
969 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
971 for (k=0; k<fo->wilddir.size(); k++) {
972 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
974 for (k=0; k<fo->wildfile.size(); k++) {
975 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
977 for (k=0; k<fo->wildbase.size(); k++) {
978 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
980 for (k=0; k<fo->base.size(); k++) {
981 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
983 for (k=0; k<fo->fstype.size(); k++) {
984 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
986 for (k=0; k<fo->drivetype.size(); k++) {
987 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
991 foreach_dlist(node, incexe->name_list) {
992 Dmsg1(400, "F %s\n", node->c_str());
994 foreach_dlist(node, &incexe->plugin_list) {
995 Dmsg1(400, "P %s\n", node->c_str());
999 return ff->fileset->state != state_error;
1004 * As an optimization, we should do this during
1005 * "compile" time in filed/job.c, and keep only a bit mask
1006 * and the Verify options.
1008 static void set_options(findFOPTS *fo, const char *opts)
1014 // Commented out as it is not backward compatible - KES
1016 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1019 for (p=opts; *p; p++) {
1021 case 'a': /* alway replace */
1022 case '0': /* no option */
1025 fo->flags |= FO_EXCLUDE;
1028 fo->flags |= FO_MULTIFS;
1030 case 'h': /* no recursion */
1031 fo->flags |= FO_NO_RECURSION;
1033 case 'H': /* no hard link handling */
1034 fo->flags |= FO_NO_HARDLINK;
1037 fo->flags |= FO_IGNORECASE;
1040 fo->flags |= FO_MD5;
1043 fo->flags |= FO_NOREPLACE;
1045 case 'p': /* use portable data format */
1046 fo->flags |= FO_PORTABLE;
1048 case 'R': /* Resource forks and Finder Info */
1049 fo->flags |= FO_HFSPLUS;
1050 case 'r': /* read fifo */
1051 fo->flags |= FO_READFIFO;
1056 fo->flags |= FO_SHA1;
1061 fo->flags |= FO_SHA256;
1065 fo->flags |= FO_SHA512;
1071 * If 2 or 3 is seen here, SHA2 is not configured, so
1072 * eat the option, and drop back to SHA-1.
1074 if (p[1] == '2' || p[1] == '3') {
1077 fo->flags |= FO_SHA1;
1082 fo->flags |= FO_SPARSE;
1085 fo->flags |= FO_MTIMEONLY;
1088 fo->flags |= FO_KEEPATIME;
1091 fo->flags |= FO_ACL;
1093 case 'V': /* verify options */
1094 /* Copy Verify Options */
1095 for (j=0; *p && *p != ':'; p++) {
1096 fo->VerifyOpts[j] = *p;
1097 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1101 fo->VerifyOpts[j] = 0;
1103 case 'C': /* accurate options */
1104 /* Copy Accurate Options */
1105 for (j=0; *p && *p != ':'; p++) {
1106 fo->AccurateOpts[j] = *p;
1107 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1111 fo->AccurateOpts[j] = 0;
1113 case 'P': /* strip path */
1116 for (j=0; *p && *p != ':'; p++) {
1118 if (j < (int)sizeof(strip) - 1) {
1123 fo->strip_path = atoi(strip);
1124 fo->flags |= FO_STRIPPATH;
1125 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1128 fo->flags |= FO_IF_NEWER;
1131 fo->flags |= FO_ENHANCEDWILD;
1133 case 'Z': /* gzip compression */
1134 fo->flags |= FO_GZIP;
1135 fo->GZIP_level = *++p - '0';
1138 fo->flags |= FO_NOATIME;
1141 fo->flags |= FO_CHKCHANGES;
1144 fo->flags |= FO_HONOR_NODUMP;
1147 fo->flags |= FO_XATTR;
1150 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1158 * Director is passing his Fileset
1160 static int fileset_cmd(JCR *jcr)
1162 BSOCK *dir = jcr->dir_bsock;
1164 #if defined(WIN32_VSS)
1167 sscanf(dir->msg, "fileset vss=%d", &vss);
1171 if (!init_fileset(jcr)) {
1174 while (dir->recv() >= 0) {
1175 strip_trailing_junk(dir->msg);
1176 Dmsg1(500, "Fileset: %s\n", dir->msg);
1177 add_fileset(jcr, dir->msg);
1179 if (!term_fileset(jcr)) {
1182 return dir->fsend(OKinc);
1185 static void free_bootstrap(JCR *jcr)
1187 if (jcr->RestoreBootstrap) {
1188 unlink(jcr->RestoreBootstrap);
1189 free_pool_memory(jcr->RestoreBootstrap);
1190 jcr->RestoreBootstrap = NULL;
1195 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1196 static uint32_t bsr_uniq = 0;
1199 * The Director sends us the bootstrap file, which
1200 * we will in turn pass to the SD.
1202 static int bootstrap_cmd(JCR *jcr)
1204 BSOCK *dir = jcr->dir_bsock;
1205 POOLMEM *fname = get_pool_memory(PM_FNAME);
1208 free_bootstrap(jcr);
1211 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1212 jcr->Job, bsr_uniq);
1214 Dmsg1(400, "bootstrap=%s\n", fname);
1215 jcr->RestoreBootstrap = fname;
1216 bs = fopen(fname, "a+b"); /* create file */
1219 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1220 jcr->RestoreBootstrap, be.bstrerror());
1222 * Suck up what he is sending to us so that he will then
1223 * read our error message.
1225 while (dir->recv() >= 0)
1227 free_bootstrap(jcr);
1228 set_jcr_job_status(jcr, JS_ErrorTerminated);
1232 while (dir->recv() >= 0) {
1233 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1234 fputs(dir->msg, bs);
1238 * Note, do not free the bootstrap yet -- it needs to be
1241 return dir->fsend(OKbootstrap);
1246 * Get backup level from Director
1249 static int level_cmd(JCR *jcr)
1251 BSOCK *dir = jcr->dir_bsock;
1252 POOLMEM *level, *buf = NULL;
1255 level = get_memory(dir->msglen+1);
1256 Dmsg1(100, "level_cmd: %s", dir->msg);
1257 if (strstr(dir->msg, "accurate")) {
1258 jcr->accurate = true;
1260 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1263 /* Base backup requested? */
1264 if (strcmp(level, "base") == 0) {
1265 jcr->set_JobLevel(L_BASE);
1266 /* Full backup requested? */
1267 } else if (strcmp(level, "full") == 0) {
1268 jcr->set_JobLevel(L_FULL);
1269 } else if (strstr(level, "differential")) {
1270 jcr->set_JobLevel(L_DIFFERENTIAL);
1273 } else if (strstr(level, "incremental")) {
1274 jcr->set_JobLevel(L_INCREMENTAL);
1278 * We get his UTC since time, then sync the clocks and correct it
1279 * to agree with our clock.
1281 } else if (strcmp(level, "since_utime") == 0) {
1282 buf = get_memory(dir->msglen+1);
1283 utime_t since_time, adj;
1284 btime_t his_time, bt_start, rt=0, bt_adj=0;
1285 if (jcr->get_JobLevel() == L_NONE) {
1286 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1288 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1289 buf, &mtime_only) != 2) {
1292 since_time = str_to_uint64(buf); /* this is the since time */
1293 Dmsg1(100, "since_time=%lld\n", since_time);
1294 char ed1[50], ed2[50];
1296 * Sync clocks by polling him for the time. We take
1297 * 10 samples of his time throwing out the first two.
1299 for (int i=0; i<10; i++) {
1300 bt_start = get_current_btime();
1301 dir->signal(BNET_BTIME); /* poll for time */
1302 if (dir->recv() <= 0) { /* get response */
1305 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1308 if (i < 2) { /* toss first two results */
1311 his_time = str_to_uint64(buf);
1312 rt = get_current_btime() - bt_start; /* compute round trip time */
1313 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1314 edit_uint64(bt_start, ed2));
1315 bt_adj += bt_start - his_time - rt/2;
1316 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1319 bt_adj = bt_adj / 8; /* compute average time */
1320 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1321 adj = btime_to_utime(bt_adj);
1322 since_time += adj; /* adjust for clock difference */
1323 /* Don't notify if time within 3 seconds */
1324 if (adj > 3 || adj < -3) {
1326 if (adj > 600 || adj < -600) {
1331 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1333 dir->signal(BNET_EOD);
1335 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1336 jcr->incremental = 1; /* set incremental or decremental backup */
1337 jcr->mtime = since_time; /* set since time */
1338 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1340 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1348 generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1349 return dir->fsend(OKlevel);
1352 pm_strcpy(jcr->errmsg, dir->msg);
1353 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1362 * Get session parameters from Director -- this is for a Restore command
1364 static int session_cmd(JCR *jcr)
1366 BSOCK *dir = jcr->dir_bsock;
1368 Dmsg1(100, "SessionCmd: %s", dir->msg);
1369 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1370 &jcr->VolSessionId, &jcr->VolSessionTime,
1371 &jcr->StartFile, &jcr->EndFile,
1372 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1373 pm_strcpy(jcr->errmsg, dir->msg);
1374 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1378 return dir->fsend(OKsession);
1382 * Get address of storage daemon from Director
1385 static int storage_cmd(JCR *jcr)
1387 int stored_port; /* storage daemon port */
1388 int enable_ssl; /* enable ssl to sd */
1389 BSOCK *dir = jcr->dir_bsock;
1390 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1392 Dmsg1(100, "StorageCmd: %s", dir->msg);
1393 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1394 pm_strcpy(jcr->errmsg, dir->msg);
1395 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1398 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1399 /* Open command communications with Storage daemon */
1400 /* Try to connect for 1 hour at 10 second intervals */
1402 sd->set_source_address(me->FDsrc_addr);
1403 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1404 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1410 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1411 jcr->stored_addr, stored_port);
1412 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1413 jcr->stored_addr, stored_port);
1416 Dmsg0(110, "Connection OK to SD.\n");
1418 jcr->store_bsock = sd;
1420 sd->fsend("Hello Start Job %s\n", jcr->Job);
1421 if (!authenticate_storagedaemon(jcr)) {
1422 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1425 Dmsg0(110, "Authenticated with SD.\n");
1427 /* Send OK to Director */
1428 return dir->fsend(OKstore);
1431 dir->fsend(BADcmd, "storage");
1440 static int backup_cmd(JCR *jcr)
1442 BSOCK *dir = jcr->dir_bsock;
1443 BSOCK *sd = jcr->store_bsock;
1447 #if defined(WIN32_VSS)
1448 // capture state here, if client is backed up by multiple directors
1449 // and one enables vss and the other does not then enable_vss can change
1450 // between here and where its evaluated after the job completes.
1451 jcr->VSS = g_pVSSClient && enable_vss;
1453 /* Run only one at a time */
1459 * Validate some options given to the backup make sense for the compiled in
1460 * options of this filed.
1462 if (jcr->ff->flags & FO_ACL && !have_acl) {
1463 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1466 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1467 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1471 set_jcr_job_status(jcr, JS_Blocked);
1472 jcr->set_JobType(JT_BACKUP);
1473 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1476 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1477 dir->fsend(BADcmd, "backup");
1481 dir->fsend(OKbackup);
1482 Dmsg1(110, "filed>dird: %s", dir->msg);
1485 * Send Append Open Session to Storage daemon
1487 sd->fsend(append_open);
1488 Dmsg1(110, ">stored: %s", sd->msg);
1490 * Expect to receive back the Ticket number
1492 if (bget_msg(sd) >= 0) {
1493 Dmsg1(110, "<stored: %s", sd->msg);
1494 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1495 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1498 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1500 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1505 * Send Append data command to Storage daemon
1507 sd->fsend(append_data, jcr->Ticket);
1508 Dmsg1(110, ">stored: %s", sd->msg);
1511 * Expect to get OK data
1513 Dmsg1(110, "<stored: %s", sd->msg);
1514 if (!response(jcr, sd, OK_data, "Append Data")) {
1518 generate_daemon_event(jcr, "JobStart");
1519 generate_plugin_event(jcr, bEventStartBackupJob);
1521 #if defined(WIN32_VSS)
1522 /* START VSS ON WIN32 */
1524 if (g_pVSSClient->InitializeForBackup()) {
1525 /* tell vss which drives to snapshot */
1526 char szWinDriveLetters[27];
1527 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1528 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1529 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1530 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1533 /* tell user if snapshot creation of a specific drive failed */
1535 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1536 if (islower(szWinDriveLetters[i])) {
1537 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1541 /* inform user about writer states */
1542 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1543 if (g_pVSSClient->GetWriterState(i) < 1) {
1544 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1549 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1553 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1555 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1560 * Send Files to Storage daemon
1562 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1563 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1564 set_jcr_job_status(jcr, JS_ErrorTerminated);
1565 bnet_suppress_error_messages(sd, 1);
1566 bget_msg(sd); /* Read final response from append_data */
1567 Dmsg0(110, "Error in blast_data.\n");
1569 set_jcr_job_status(jcr, JS_Terminated);
1570 /* Note, the above set status will not override an error */
1571 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1572 bnet_suppress_error_messages(sd, 1);
1573 goto cleanup; /* bail out now */
1576 * Expect to get response to append_data from Storage daemon
1578 if (!response(jcr, sd, OK_append, "Append Data")) {
1579 set_jcr_job_status(jcr, JS_ErrorTerminated);
1584 * Send Append End Data to Storage daemon
1586 sd->fsend(append_end, jcr->Ticket);
1588 if (!response(jcr, sd, OK_end, "Append End")) {
1589 set_jcr_job_status(jcr, JS_ErrorTerminated);
1594 * Send Append Close to Storage daemon
1596 sd->fsend(append_close, jcr->Ticket);
1597 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1598 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1600 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1604 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1607 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1608 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1614 #if defined(WIN32_VSS)
1615 /* STOP VSS ON WIN32 */
1616 /* tell vss to close the backup session */
1618 if (g_pVSSClient->CloseBackup()) {
1619 /* inform user about writer states */
1620 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1621 int msg_type = M_INFO;
1622 if (g_pVSSClient->GetWriterState(i) < 1) {
1623 msg_type = M_WARNING;
1626 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1629 Win32ConvCleanupCache();
1634 generate_plugin_event(jcr, bEventEndBackupJob);
1635 return 0; /* return and stop command loop */
1639 * Do a Verify for Director
1642 static int verify_cmd(JCR *jcr)
1644 BSOCK *dir = jcr->dir_bsock;
1645 BSOCK *sd = jcr->store_bsock;
1648 jcr->set_JobType(JT_VERIFY);
1649 if (sscanf(dir->msg, verifycmd, level) != 1) {
1650 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1654 if (strcasecmp(level, "init") == 0) {
1655 jcr->set_JobLevel(L_VERIFY_INIT);
1656 } else if (strcasecmp(level, "catalog") == 0){
1657 jcr->set_JobLevel(L_VERIFY_CATALOG);
1658 } else if (strcasecmp(level, "volume") == 0){
1659 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1660 } else if (strcasecmp(level, "data") == 0){
1661 jcr->set_JobLevel(L_VERIFY_DATA);
1662 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1663 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1665 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1669 dir->fsend(OKverify);
1671 generate_daemon_event(jcr, "JobStart");
1672 generate_plugin_event(jcr, bEventLevel, (void *)jcr->get_JobLevel());
1673 generate_plugin_event(jcr, bEventStartVerifyJob);
1675 Dmsg1(110, "filed>dird: %s", dir->msg);
1677 switch (jcr->get_JobLevel()) {
1679 case L_VERIFY_CATALOG:
1682 case L_VERIFY_VOLUME_TO_CATALOG:
1683 if (!open_sd_read_session(jcr)) {
1686 start_dir_heartbeat(jcr);
1687 do_verify_volume(jcr);
1688 stop_dir_heartbeat(jcr);
1690 * Send Close session command to Storage daemon
1692 sd->fsend(read_close, jcr->Ticket);
1693 Dmsg1(130, "filed>stored: %s", sd->msg);
1695 /* ****FIXME**** check response */
1696 bget_msg(sd); /* get OK */
1698 /* Inform Storage daemon that we are done */
1699 sd->signal(BNET_TERMINATE);
1702 case L_VERIFY_DISK_TO_CATALOG:
1706 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1710 dir->signal(BNET_EOD);
1711 generate_plugin_event(jcr, bEventEndVerifyJob);
1712 return 0; /* return and terminate command loop */
1716 * Do a Restore for Director
1719 static int restore_cmd(JCR *jcr)
1721 BSOCK *dir = jcr->dir_bsock;
1722 BSOCK *sd = jcr->store_bsock;
1724 bool use_regexwhere=false;
1729 * Scan WHERE (base directory for restore) from command
1731 Dmsg0(150, "restore command\n");
1732 /* Pickup where string */
1733 args = get_memory(dir->msglen+1);
1736 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1737 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1738 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1739 pm_strcpy(jcr->errmsg, dir->msg);
1740 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1745 use_regexwhere = true;
1747 /* Turn / into nothing */
1748 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1752 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1753 unbash_spaces(args);
1755 if (use_regexwhere) {
1756 jcr->where_bregexp = get_bregexps(args);
1757 if (!jcr->where_bregexp) {
1758 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1759 free_pool_memory(args);
1763 jcr->where = bstrdup(args);
1766 free_pool_memory(args);
1767 jcr->replace = replace;
1768 jcr->prefix_links = prefix_links;
1770 dir->fsend(OKrestore);
1771 Dmsg1(110, "filed>dird: %s", dir->msg);
1773 jcr->set_JobType(JT_RESTORE);
1775 set_jcr_job_status(jcr, JS_Blocked);
1777 if (!open_sd_read_session(jcr)) {
1778 set_jcr_job_status(jcr, JS_ErrorTerminated);
1782 set_jcr_job_status(jcr, JS_Running);
1785 * Do restore of files and data
1787 start_dir_heartbeat(jcr);
1788 generate_daemon_event(jcr, "JobStart");
1789 generate_plugin_event(jcr, bEventStartRestoreJob);
1791 stop_dir_heartbeat(jcr);
1793 set_jcr_job_status(jcr, JS_Terminated);
1794 if (jcr->JobStatus != JS_Terminated) {
1795 bnet_suppress_error_messages(sd, 1);
1799 * Send Close session command to Storage daemon
1801 sd->fsend(read_close, jcr->Ticket);
1802 Dmsg1(130, "filed>stored: %s", sd->msg);
1804 bget_msg(sd); /* get OK */
1806 /* Inform Storage daemon that we are done */
1807 sd->signal(BNET_TERMINATE);
1811 if (jcr->JobErrors) {
1812 set_jcr_job_status(jcr, JS_ErrorTerminated);
1815 Dmsg0(130, "Done in job.c\n");
1816 generate_plugin_event(jcr, bEventEndRestoreJob);
1817 return 0; /* return and terminate command loop */
1820 static int open_sd_read_session(JCR *jcr)
1822 BSOCK *sd = jcr->store_bsock;
1825 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1828 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1829 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1830 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1832 * Open Read Session with Storage daemon
1834 sd->fsend(read_open, "DummyVolume",
1835 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1836 jcr->StartBlock, jcr->EndBlock);
1837 Dmsg1(110, ">stored: %s", sd->msg);
1842 if (bget_msg(sd) >= 0) {
1843 Dmsg1(110, "filed<stored: %s", sd->msg);
1844 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1845 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1848 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1850 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1854 if (!send_bootstrap_file(jcr)) {
1859 * Start read of data with Storage daemon
1861 sd->fsend(read_data, jcr->Ticket);
1862 Dmsg1(110, ">stored: %s", sd->msg);
1867 if (!response(jcr, sd, OK_data, "Read Data")) {
1874 * Destroy the Job Control Record and associated
1875 * resources (sockets).
1877 static void filed_free_jcr(JCR *jcr)
1879 if (jcr->store_bsock) {
1880 jcr->store_bsock->close();
1882 free_bootstrap(jcr);
1883 if (jcr->last_fname) {
1884 free_pool_memory(jcr->last_fname);
1886 free_runscripts(jcr->RunScripts);
1887 delete jcr->RunScripts;
1889 if (jcr->JobId != 0)
1890 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1896 * Get response from Storage daemon to a command we
1897 * sent. Check that the response is OK.
1899 * Returns: 0 on failure
1902 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1907 if (bget_msg(sd) > 0) {
1908 Dmsg0(110, sd->msg);
1909 if (strcmp(sd->msg, resp) == 0) {
1913 if (job_canceled(jcr)) {
1914 return 0; /* if canceled avoid useless error messages */
1916 if (is_bnet_error(sd)) {
1917 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1918 cmd, bnet_strerror(sd));
1920 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1921 cmd, resp, sd->msg);
1926 static int send_bootstrap_file(JCR *jcr)
1930 BSOCK *sd = jcr->store_bsock;
1931 const char *bootstrap = "bootstrap\n";
1934 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1935 if (!jcr->RestoreBootstrap) {
1938 bs = fopen(jcr->RestoreBootstrap, "rb");
1941 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1942 jcr->RestoreBootstrap, be.bstrerror());
1943 set_jcr_job_status(jcr, JS_ErrorTerminated);
1946 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1948 while (fgets(buf, sizeof(buf), bs)) {
1949 sd->msglen = Mmsg(sd->msg, "%s", buf);
1952 sd->signal(BNET_EOD);
1954 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1955 set_jcr_job_status(jcr, JS_ErrorTerminated);
1961 free_bootstrap(jcr);