2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 three of the GNU Affero 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 Affero 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
38 #if defined(WIN32_VSS)
41 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int enable_vss = 0;
46 * As Windows saves ACLs as part of the standard backup stream
47 * we just pretend here that is has implicit acl support.
49 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
50 const bool have_acl = true;
52 const bool have_acl = false;
55 #if defined(HAVE_XATTR)
56 const bool have_xattr = true;
58 const bool have_xattr = false;
61 extern CLIENT *me; /* our client resource */
63 /* Imported functions */
64 extern int status_cmd(JCR *jcr);
65 extern int qstatus_cmd(JCR *jcr);
66 extern int accurate_cmd(JCR *jcr);
68 /* Forward referenced functions */
69 static int backup_cmd(JCR *jcr);
70 static int bootstrap_cmd(JCR *jcr);
71 static int cancel_cmd(JCR *jcr);
72 static int setdebug_cmd(JCR *jcr);
73 static int estimate_cmd(JCR *jcr);
74 static int hello_cmd(JCR *jcr);
75 static int job_cmd(JCR *jcr);
76 static int fileset_cmd(JCR *jcr);
77 static int level_cmd(JCR *jcr);
78 static int verify_cmd(JCR *jcr);
79 static int restore_cmd(JCR *jcr);
80 static int end_restore_cmd(JCR *jcr);
81 static int storage_cmd(JCR *jcr);
82 static int session_cmd(JCR *jcr);
83 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
84 static void filed_free_jcr(JCR *jcr);
85 static int open_sd_read_session(JCR *jcr);
86 static int send_bootstrap_file(JCR *jcr);
87 static int runscript_cmd(JCR *jcr);
88 static int runbefore_cmd(JCR *jcr);
89 static int runafter_cmd(JCR *jcr);
90 static int runbeforenow_cmd(JCR *jcr);
91 static void set_options(findFOPTS *fo, const char *opts);
92 static void set_storage_auth_key(JCR *jcr, char *key);
93 static int sm_dump_cmd(JCR *jcr);
95 static int exit_cmd(JCR *jcr);
98 /* Exported functions */
103 int monitoraccess; /* specify if monitors have access to this function */
107 * The following are the recognized commands from the Director.
109 static struct s_cmds cmds[] = {
110 {"backup", backup_cmd, 0},
111 {"cancel", cancel_cmd, 0},
112 {"setdebug=", setdebug_cmd, 0},
113 {"estimate", estimate_cmd, 0},
114 {"Hello", hello_cmd, 1},
115 {"fileset", fileset_cmd, 0},
116 {"JobId=", job_cmd, 0},
117 {"level = ", level_cmd, 0},
118 {"restore", restore_cmd, 0},
119 {"endrestore", end_restore_cmd, 0},
120 {"session", session_cmd, 0},
121 {"status", status_cmd, 1},
122 {".status", qstatus_cmd, 1},
123 {"storage ", storage_cmd, 0},
124 {"verify", verify_cmd, 0},
125 {"bootstrap", bootstrap_cmd, 0},
126 {"RunBeforeNow", runbeforenow_cmd, 0},
127 {"RunBeforeJob", runbefore_cmd, 0},
128 {"RunAfterJob", runafter_cmd, 0},
129 {"Run", runscript_cmd, 0},
130 {"accurate", accurate_cmd, 0},
131 {"sm_dump", sm_dump_cmd, 0},
133 {"exit", exit_cmd, 0},
135 {NULL, NULL} /* list terminator */
138 /* Commands received from director that need scanning */
139 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
140 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
141 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
142 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
143 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
144 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
145 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
146 static char verifycmd[] = "verify level=%30s";
147 static char estimatecmd[] = "estimate listing=%d";
148 static char runbefore[] = "RunBeforeJob %s";
149 static char runafter[] = "RunAfterJob %s";
150 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
152 /* Responses sent to Director */
153 static char errmsg[] = "2999 Invalid command\n";
154 static char no_auth[] = "2998 No Authorization\n";
155 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
156 static char OKinc[] = "2000 OK include\n";
157 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
158 static char OKlevel[] = "2000 OK level\n";
159 static char OKbackup[] = "2000 OK backup\n";
160 static char OKbootstrap[] = "2000 OK bootstrap\n";
161 static char OKverify[] = "2000 OK verify\n";
162 static char OKrestore[] = "2000 OK restore\n";
163 static char OKsession[] = "2000 OK session\n";
164 static char OKstore[] = "2000 OK storage\n";
165 static char OKstoreend[] = "2000 OK storage end\n";
166 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
167 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
168 static char BADjob[] = "2901 Bad Job\n";
169 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
170 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
171 static char OKRunBefore[] = "2000 OK RunBefore\n";
172 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
173 static char OKRunAfter[] = "2000 OK RunAfter\n";
174 static char OKRunScript[] = "2000 OK RunScript\n";
175 static char BADcmd[] = "2902 Bad %s\n";
178 /* Responses received from Storage Daemon */
179 static char OK_end[] = "3000 OK end\n";
180 static char OK_close[] = "3000 OK close Status = %d\n";
181 static char OK_open[] = "3000 OK open ticket = %d\n";
182 static char OK_data[] = "3000 OK data\n";
183 static char OK_append[] = "3000 OK append data\n";
184 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
187 /* Commands sent to Storage Daemon */
188 static char append_open[] = "append open session\n";
189 static char append_data[] = "append data %d\n";
190 static char append_end[] = "append end session %d\n";
191 static char append_close[] = "append close session %d\n";
192 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
193 static char read_data[] = "read data %d\n";
194 static char read_close[] = "read close session %d\n";
197 * Accept requests from a Director
199 * NOTE! We are running as a separate thread
201 * Send output one line
202 * at a time followed by a zero length transmission.
204 * Return when the connection is terminated or there
207 * Basic task here is:
208 * Authenticate Director (during Hello command).
209 * Accept commands one at a time from the Director
212 * Concerning ClientRunBefore/After, the sequence of events
213 * is rather critical. If they are not done in the right
214 * order one can easily get FD->SD timeouts if the script
217 * The current sequence of events is:
218 * 1. Dir starts job with FD
219 * 2. Dir connects to SD
220 * 3. Dir connects to FD
221 * 4. FD connects to SD
222 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
223 * 6. Dir sends include/exclude
224 * 7. FD sends data to SD
225 * 8. SD/FD disconnects while SD despools data and attributes (optional)
226 * 9. FD runs ClientRunAfterJob
229 void *handle_client_request(void *dirp)
234 BSOCK *dir = (BSOCK *)dirp;
235 const char jobname[12] = "*Director*";
237 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
238 jcr->dir_bsock = dir;
239 jcr->ff = init_find_files();
240 jcr->start_time = time(NULL);
241 jcr->RunScripts = New(alist(10, not_owned_by_alist));
242 jcr->last_fname = get_pool_memory(PM_FNAME);
243 jcr->last_fname[0] = 0;
244 jcr->client_name = get_memory(strlen(my_name) + 1);
245 pm_strcpy(jcr->client_name, my_name);
246 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
247 jcr->crypto.pki_sign = me->pki_sign;
248 jcr->crypto.pki_encrypt = me->pki_encrypt;
249 jcr->crypto.pki_keypair = me->pki_keypair;
250 jcr->crypto.pki_signers = me->pki_signers;
251 jcr->crypto.pki_recipients = me->pki_recipients;
253 enable_backup_privileges(NULL, 1 /* ignore_errors */);
255 /**********FIXME******* add command handler error code */
257 for (quit=false; !quit;) {
259 if (dir->recv() < 0) {
260 break; /* connection terminated */
262 dir->msg[dir->msglen] = 0;
263 Dmsg1(100, "<dird: %s", dir->msg);
265 for (i=0; cmds[i].cmd; i++) {
266 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
267 found = true; /* indicate command found */
268 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
270 dir->signal(BNET_EOD);
273 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
274 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
275 dir->fsend(invalid_cmd);
276 dir->signal(BNET_EOD);
279 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
280 if (!cmds[i].func(jcr)) { /* do command */
281 quit = true; /* error or fully terminated, get out */
282 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
287 if (!found) { /* command not found */
294 /* Inform Storage daemon that we are done */
295 if (jcr->store_bsock) {
296 jcr->store_bsock->signal(BNET_TERMINATE);
299 /* Run the after job */
300 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
302 if (jcr->JobId) { /* send EndJob if running a job */
303 char ed1[50], ed2[50];
304 /* Send termination status back to Dir */
305 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
306 edit_uint64(jcr->ReadBytes, ed1),
307 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
308 jcr->crypto.pki_encrypt);
309 Dmsg1(110, "End FD msg: %s\n", dir->msg);
312 generate_daemon_event(jcr, "JobEnd");
313 generate_plugin_event(jcr, bEventJobEnd);
315 dequeue_messages(jcr); /* send any queued messages */
317 /* Inform Director that we are done */
318 dir->signal(BNET_TERMINATE);
320 free_plugins(jcr); /* release instantiated plugins */
322 /* Clean up fileset */
323 FF_PKT *ff = jcr->ff;
324 findFILESET *fileset = ff->fileset;
327 /* Delete FileSet Include lists */
328 for (i=0; i<fileset->include_list.size(); i++) {
329 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
330 for (j=0; j<incexe->opts_list.size(); j++) {
331 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
332 for (k=0; k<fo->regex.size(); k++) {
333 regfree((regex_t *)fo->regex.get(k));
335 for (k=0; k<fo->regexdir.size(); k++) {
336 regfree((regex_t *)fo->regexdir.get(k));
338 for (k=0; k<fo->regexfile.size(); k++) {
339 regfree((regex_t *)fo->regexfile.get(k));
342 fo->regexdir.destroy();
343 fo->regexfile.destroy();
345 fo->wilddir.destroy();
346 fo->wildfile.destroy();
347 fo->wildbase.destroy();
349 fo->fstype.destroy();
350 fo->drivetype.destroy();
352 incexe->opts_list.destroy();
353 incexe->name_list.destroy();
354 incexe->plugin_list.destroy();
355 if (incexe->ignoredir) {
356 free(incexe->ignoredir);
359 fileset->include_list.destroy();
361 /* Delete FileSet Exclude lists */
362 for (i=0; i<fileset->exclude_list.size(); i++) {
363 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
364 for (j=0; j<incexe->opts_list.size(); j++) {
365 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
367 fo->regexdir.destroy();
368 fo->regexfile.destroy();
370 fo->wilddir.destroy();
371 fo->wildfile.destroy();
372 fo->wildbase.destroy();
374 fo->fstype.destroy();
375 fo->drivetype.destroy();
377 incexe->opts_list.destroy();
378 incexe->name_list.destroy();
379 incexe->plugin_list.destroy();
380 if (incexe->ignoredir) {
381 free(incexe->ignoredir);
384 fileset->exclude_list.destroy();
388 Dmsg0(100, "Calling term_find_files\n");
389 term_find_files(jcr->ff);
391 Dmsg0(100, "Done with term_find_files\n");
392 free_jcr(jcr); /* destroy JCR record */
393 Dmsg0(100, "Done with free_jcr\n");
395 garbage_collect_memory_pool();
399 static int sm_dump_cmd(JCR *jcr)
402 sm_dump(false, true);
403 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
408 static int exit_cmd(JCR *jcr)
410 jcr->dir_bsock->fsend("2000 exit OK\n");
418 * Hello from Director he must identify himself and provide his
421 static int hello_cmd(JCR *jcr)
423 Dmsg0(120, "Calling Authenticate\n");
424 if (!authenticate_director(jcr)) {
427 Dmsg0(120, "OK Authenticate\n");
428 jcr->authenticated = true;
435 static int cancel_cmd(JCR *jcr)
437 BSOCK *dir = jcr->dir_bsock;
438 char Job[MAX_NAME_LENGTH];
441 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
442 if (!(cjcr=get_jcr_by_full_name(Job))) {
443 dir->fsend(_("2901 Job %s not found.\n"), Job);
445 if (cjcr->store_bsock) {
446 cjcr->store_bsock->set_timed_out();
447 cjcr->store_bsock->set_terminated();
448 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
450 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
451 set_jcr_job_status(cjcr, JS_Canceled);
453 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
456 dir->fsend(_("2902 Error scanning cancel command.\n"));
458 dir->signal(BNET_EOD);
464 * Set debug level as requested by the Director
467 static int setdebug_cmd(JCR *jcr)
469 BSOCK *dir = jcr->dir_bsock;
470 int level, trace_flag;
472 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
473 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
474 pm_strcpy(jcr->errmsg, dir->msg);
475 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
479 set_trace(trace_flag);
480 return dir->fsend(OKsetdebug, level);
484 static int estimate_cmd(JCR *jcr)
486 BSOCK *dir = jcr->dir_bsock;
487 char ed1[50], ed2[50];
489 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
490 pm_strcpy(jcr->errmsg, dir->msg);
491 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
492 dir->fsend(_("2992 Bad estimate command.\n"));
496 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
497 edit_uint64_with_commas(jcr->JobBytes, ed2));
498 dir->signal(BNET_EOD);
503 * Get JobId and Storage Daemon Authorization key from Director
505 static int job_cmd(JCR *jcr)
507 BSOCK *dir = jcr->dir_bsock;
508 POOL_MEM sd_auth_key(PM_MESSAGE);
509 sd_auth_key.check_size(dir->msglen);
511 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
512 &jcr->VolSessionId, &jcr->VolSessionTime,
513 sd_auth_key.c_str()) != 5) {
514 pm_strcpy(jcr->errmsg, dir->msg);
515 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
519 set_storage_auth_key(jcr, sd_auth_key.c_str());
520 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
521 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
522 new_plugins(jcr); /* instantiate plugins for this jcr */
523 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
524 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
527 static int runbefore_cmd(JCR *jcr)
530 BSOCK *dir = jcr->dir_bsock;
531 POOLMEM *cmd = get_memory(dir->msglen+1);
534 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
535 if (sscanf(dir->msg, runbefore, cmd) != 1) {
536 pm_strcpy(jcr->errmsg, dir->msg);
537 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
538 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
544 /* Run the command now */
545 script = new_runscript();
546 script->set_command(cmd);
547 script->when = SCRIPT_Before;
548 ok = script->run(jcr, "ClientRunBeforeJob");
549 free_runscript(script);
553 dir->fsend(OKRunBefore);
556 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
561 static int runbeforenow_cmd(JCR *jcr)
563 BSOCK *dir = jcr->dir_bsock;
565 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
566 if (job_canceled(jcr)) {
567 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
568 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
571 dir->fsend(OKRunBeforeNow);
572 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
577 static int runafter_cmd(JCR *jcr)
579 BSOCK *dir = jcr->dir_bsock;
580 POOLMEM *msg = get_memory(dir->msglen+1);
583 Dmsg1(100, "runafter_cmd: %s", dir->msg);
584 if (sscanf(dir->msg, runafter, msg) != 1) {
585 pm_strcpy(jcr->errmsg, dir->msg);
586 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
587 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
593 cmd = new_runscript();
594 cmd->set_command(msg);
595 cmd->on_success = true;
596 cmd->on_failure = false;
597 cmd->when = SCRIPT_After;
599 jcr->RunScripts->append(cmd);
601 free_pool_memory(msg);
602 return dir->fsend(OKRunAfter);
605 static int runscript_cmd(JCR *jcr)
607 BSOCK *dir = jcr->dir_bsock;
608 POOLMEM *msg = get_memory(dir->msglen+1);
609 int on_success, on_failure, fail_on_error;
611 RUNSCRIPT *cmd = new_runscript() ;
613 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
614 /* Note, we cannot sscanf into bools */
615 if (sscanf(dir->msg, runscript, &on_success,
620 pm_strcpy(jcr->errmsg, dir->msg);
621 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
622 dir->fsend(_("2905 Bad RunScript command.\n"));
627 cmd->on_success = on_success;
628 cmd->on_failure = on_failure;
629 cmd->fail_on_error = fail_on_error;
632 cmd->set_command(msg);
634 jcr->RunScripts->append(cmd);
636 free_pool_memory(msg);
637 return dir->fsend(OKRunScript);
641 static bool init_fileset(JCR *jcr)
644 findFILESET *fileset;
653 fileset = (findFILESET *)malloc(sizeof(findFILESET));
654 memset(fileset, 0, sizeof(findFILESET));
655 ff->fileset = fileset;
656 fileset->state = state_none;
657 fileset->include_list.init(1, true);
658 fileset->exclude_list.init(1, true);
662 static findFOPTS *start_options(FF_PKT *ff)
664 int state = ff->fileset->state;
665 findINCEXE *incexe = ff->fileset->incexe;
667 if (state != state_options) {
668 ff->fileset->state = state_options;
669 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
670 memset(fo, 0, sizeof(findFOPTS));
671 fo->regex.init(1, true);
672 fo->regexdir.init(1, true);
673 fo->regexfile.init(1, true);
674 fo->wild.init(1, true);
675 fo->wilddir.init(1, true);
676 fo->wildfile.init(1, true);
677 fo->wildbase.init(1, true);
678 fo->base.init(1, true);
679 fo->fstype.init(1, true);
680 fo->drivetype.init(1, true);
681 incexe->current_opts = fo;
682 incexe->opts_list.append(fo);
684 return incexe->current_opts;
689 * Add fname to include/exclude fileset list. First check for
690 * | and < and if necessary perform command.
692 void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
707 p++; /* skip over | */
708 fn = get_pool_memory(PM_FNAME);
709 fn = edit_job_codes(jcr, fn, p, "");
710 bpipe = open_bpipe(fn, 0, "r");
713 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
715 free_pool_memory(fn);
718 free_pool_memory(fn);
719 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
720 strip_trailing_junk(buf);
722 fileset->incexe->name_list.append(new_dlistString(buf));
724 fileset->incexe->plugin_list.append(new_dlistString(buf));
727 if ((stat=close_bpipe(bpipe)) != 0) {
729 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
730 p, be.code(stat), be.bstrerror(stat));
735 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
736 p++; /* skip over < */
737 if ((ffd = fopen(p, "rb")) == NULL) {
739 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
743 while (fgets(buf, sizeof(buf), ffd)) {
744 strip_trailing_junk(buf);
745 Dmsg1(100, "%s\n", buf);
747 fileset->incexe->name_list.append(new_dlistString(buf));
749 fileset->incexe->plugin_list.append(new_dlistString(buf));
756 fileset->incexe->name_list.append(new_dlistString(fname));
758 if (me->plugin_directory) {
759 fileset->incexe->plugin_list.append(new_dlistString(fname));
761 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
769 findFILESET *new_exclude(JCR *jcr)
771 FF_PKT *ff = jcr->ff;
772 findFILESET *fileset = ff->fileset;
775 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
776 memset(fileset->incexe, 0, sizeof(findINCEXE));
777 fileset->incexe->opts_list.init(1, true);
778 fileset->incexe->name_list.init();
779 fileset->incexe->plugin_list.init();
780 fileset->exclude_list.append(fileset->incexe);
785 static void add_fileset(JCR *jcr, const char *item)
787 FF_PKT *ff = jcr->ff;
788 findFILESET *fileset = ff->fileset;
789 int state = fileset->state;
790 findFOPTS *current_opts;
792 /* Get code, optional subcode, and position item past the dividing space */
793 Dmsg1(100, "%s\n", item);
798 int subcode = ' '; /* A space is always a valid subcode */
799 if (item[0] != '\0' && item[0] != ' ') {
807 /* Skip all lines we receive after an error */
808 if (state == state_error) {
809 Dmsg0(100, "State=error return\n");
814 * The switch tests the code for validity.
815 * The subcode is always good if it is a space, otherwise we must confirm.
816 * We set state to state_error first assuming the subcode is invalid,
817 * requiring state to be set in cases below that handle subcodes.
819 if (subcode != ' ') {
821 Dmsg0(100, "Set state=error or double code.\n");
826 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
827 memset(fileset->incexe, 0, sizeof(findINCEXE));
828 fileset->incexe->opts_list.init(1, true);
829 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
830 fileset->incexe->plugin_list.init();
831 fileset->include_list.append(fileset->incexe);
834 fileset = new_exclude(jcr);
840 /* File item to include or exclude list */
841 state = state_include;
842 add_file_to_fileset(jcr, item, fileset, true);
845 /* Plugin item to include list */
846 state = state_include;
847 add_file_to_fileset(jcr, item, fileset, false);
850 current_opts = start_options(ff);
854 preg = (regex_t *)malloc(sizeof(regex_t));
855 if (current_opts->flags & FO_IGNORECASE) {
856 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
858 rc = regcomp(preg, item, REG_EXTENDED);
861 regerror(rc, preg, prbuf, sizeof(prbuf));
864 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
868 state = state_options;
869 if (subcode == ' ') {
870 current_opts->regex.append(preg);
871 } else if (subcode == 'D') {
872 current_opts->regexdir.append(preg);
873 } else if (subcode == 'F') {
874 current_opts->regexfile.append(preg);
880 current_opts = start_options(ff);
881 current_opts->base.append(bstrdup(item));
882 state = state_options;
885 current_opts = start_options(ff);
886 state = state_options;
887 if (subcode == ' ') {
888 current_opts->fstype.append(bstrdup(item));
889 } else if (subcode == 'D') {
890 current_opts->drivetype.append(bstrdup(item));
896 current_opts = start_options(ff);
897 state = state_options;
898 if (subcode == ' ') {
899 current_opts->wild.append(bstrdup(item));
900 } else if (subcode == 'D') {
901 current_opts->wilddir.append(bstrdup(item));
902 } else if (subcode == 'F') {
903 current_opts->wildfile.append(bstrdup(item));
904 } else if (subcode == 'B') {
905 current_opts->wildbase.append(bstrdup(item));
911 current_opts = start_options(ff);
912 set_options(current_opts, item);
913 state = state_options;
916 state = state_include;
917 fileset->incexe->ignoredir = bstrdup(item);
920 current_opts = start_options(ff);
921 // current_opts->reader = bstrdup(item);
922 state = state_options;
925 current_opts = start_options(ff);
926 // current_opts->writer = bstrdup(item);
927 state = state_options;
930 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
934 ff->fileset->state = state;
937 static bool term_fileset(JCR *jcr)
939 FF_PKT *ff = jcr->ff;
941 #ifdef xxx_DEBUG_CODE
942 findFILESET *fileset = ff->fileset;
945 for (i=0; i<fileset->include_list.size(); i++) {
946 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
948 for (j=0; j<incexe->opts_list.size(); j++) {
949 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
950 for (k=0; k<fo->regex.size(); k++) {
951 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
953 for (k=0; k<fo->regexdir.size(); k++) {
954 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
956 for (k=0; k<fo->regexfile.size(); k++) {
957 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
959 for (k=0; k<fo->wild.size(); k++) {
960 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
962 for (k=0; k<fo->wilddir.size(); k++) {
963 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
965 for (k=0; k<fo->wildfile.size(); k++) {
966 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
968 for (k=0; k<fo->wildbase.size(); k++) {
969 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
971 for (k=0; k<fo->base.size(); k++) {
972 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
974 for (k=0; k<fo->fstype.size(); k++) {
975 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
977 for (k=0; k<fo->drivetype.size(); k++) {
978 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
981 if (incexe->ignoredir) {
982 Dmsg1(400, "Z %s\n", incexe->ignoredir);
985 foreach_dlist(node, &incexe->name_list) {
986 Dmsg1(400, "F %s\n", node->c_str());
988 foreach_dlist(node, &incexe->plugin_list) {
989 Dmsg1(400, "P %s\n", node->c_str());
992 for (i=0; i<fileset->exclude_list.size(); i++) {
993 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
995 for (j=0; j<incexe->opts_list.size(); j++) {
996 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
997 for (k=0; k<fo->regex.size(); k++) {
998 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1000 for (k=0; k<fo->regexdir.size(); k++) {
1001 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1003 for (k=0; k<fo->regexfile.size(); k++) {
1004 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1006 for (k=0; k<fo->wild.size(); k++) {
1007 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1009 for (k=0; k<fo->wilddir.size(); k++) {
1010 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1012 for (k=0; k<fo->wildfile.size(); k++) {
1013 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1015 for (k=0; k<fo->wildbase.size(); k++) {
1016 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1018 for (k=0; k<fo->base.size(); k++) {
1019 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1021 for (k=0; k<fo->fstype.size(); k++) {
1022 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1024 for (k=0; k<fo->drivetype.size(); k++) {
1025 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1029 foreach_dlist(node, incexe->name_list) {
1030 Dmsg1(400, "F %s\n", node->c_str());
1032 foreach_dlist(node, &incexe->plugin_list) {
1033 Dmsg1(400, "P %s\n", node->c_str());
1037 return ff->fileset->state != state_error;
1042 * As an optimization, we should do this during
1043 * "compile" time in filed/job.c, and keep only a bit mask
1044 * and the Verify options.
1046 static void set_options(findFOPTS *fo, const char *opts)
1052 // Commented out as it is not backward compatible - KES
1054 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1057 for (p=opts; *p; p++) {
1059 case 'a': /* alway replace */
1060 case '0': /* no option */
1063 fo->flags |= FO_EXCLUDE;
1066 fo->flags |= FO_MULTIFS;
1068 case 'h': /* no recursion */
1069 fo->flags |= FO_NO_RECURSION;
1071 case 'H': /* no hard link handling */
1072 fo->flags |= FO_NO_HARDLINK;
1075 fo->flags |= FO_IGNORECASE;
1078 fo->flags |= FO_MD5;
1081 fo->flags |= FO_NOREPLACE;
1083 case 'p': /* use portable data format */
1084 fo->flags |= FO_PORTABLE;
1086 case 'R': /* Resource forks and Finder Info */
1087 fo->flags |= FO_HFSPLUS;
1088 case 'r': /* read fifo */
1089 fo->flags |= FO_READFIFO;
1094 fo->flags |= FO_SHA1;
1099 fo->flags |= FO_SHA256;
1103 fo->flags |= FO_SHA512;
1109 * If 2 or 3 is seen here, SHA2 is not configured, so
1110 * eat the option, and drop back to SHA-1.
1112 if (p[1] == '2' || p[1] == '3') {
1115 fo->flags |= FO_SHA1;
1120 fo->flags |= FO_SPARSE;
1123 fo->flags |= FO_MTIMEONLY;
1126 fo->flags |= FO_KEEPATIME;
1129 fo->flags |= FO_ACL;
1131 case 'V': /* verify options */
1132 /* Copy Verify Options */
1133 for (j=0; *p && *p != ':'; p++) {
1134 fo->VerifyOpts[j] = *p;
1135 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1139 fo->VerifyOpts[j] = 0;
1141 case 'C': /* accurate options */
1142 /* Copy Accurate Options */
1143 for (j=0; *p && *p != ':'; p++) {
1144 fo->AccurateOpts[j] = *p;
1145 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1149 fo->AccurateOpts[j] = 0;
1151 case 'J': /* Basejob options */
1152 /* Copy BaseJob Options */
1153 for (j=0; *p && *p != ':'; p++) {
1154 fo->BaseJobOpts[j] = *p;
1155 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1159 fo->BaseJobOpts[j] = 0;
1161 case 'P': /* strip path */
1164 for (j=0; *p && *p != ':'; p++) {
1166 if (j < (int)sizeof(strip) - 1) {
1171 fo->strip_path = atoi(strip);
1172 fo->flags |= FO_STRIPPATH;
1173 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1176 fo->flags |= FO_IF_NEWER;
1179 fo->flags |= FO_ENHANCEDWILD;
1181 case 'Z': /* gzip compression */
1182 fo->flags |= FO_GZIP;
1183 fo->GZIP_level = *++p - '0';
1186 fo->flags |= FO_NOATIME;
1189 fo->flags |= FO_CHKCHANGES;
1192 fo->flags |= FO_HONOR_NODUMP;
1195 fo->flags |= FO_XATTR;
1198 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1206 * Director is passing his Fileset
1208 static int fileset_cmd(JCR *jcr)
1210 BSOCK *dir = jcr->dir_bsock;
1212 #if defined(WIN32_VSS)
1215 sscanf(dir->msg, "fileset vss=%d", &vss);
1219 if (!init_fileset(jcr)) {
1222 while (dir->recv() >= 0) {
1223 strip_trailing_junk(dir->msg);
1224 Dmsg1(500, "Fileset: %s\n", dir->msg);
1225 add_fileset(jcr, dir->msg);
1227 if (!term_fileset(jcr)) {
1230 return dir->fsend(OKinc);
1233 static void free_bootstrap(JCR *jcr)
1235 if (jcr->RestoreBootstrap) {
1236 unlink(jcr->RestoreBootstrap);
1237 free_pool_memory(jcr->RestoreBootstrap);
1238 jcr->RestoreBootstrap = NULL;
1243 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1244 static uint32_t bsr_uniq = 0;
1247 * The Director sends us the bootstrap file, which
1248 * we will in turn pass to the SD.
1250 static int bootstrap_cmd(JCR *jcr)
1252 BSOCK *dir = jcr->dir_bsock;
1253 POOLMEM *fname = get_pool_memory(PM_FNAME);
1256 free_bootstrap(jcr);
1259 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1260 jcr->Job, bsr_uniq);
1262 Dmsg1(400, "bootstrap=%s\n", fname);
1263 jcr->RestoreBootstrap = fname;
1264 bs = fopen(fname, "a+b"); /* create file */
1267 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1268 jcr->RestoreBootstrap, be.bstrerror());
1270 * Suck up what he is sending to us so that he will then
1271 * read our error message.
1273 while (dir->recv() >= 0)
1275 free_bootstrap(jcr);
1276 set_jcr_job_status(jcr, JS_ErrorTerminated);
1280 while (dir->recv() >= 0) {
1281 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1282 fputs(dir->msg, bs);
1286 * Note, do not free the bootstrap yet -- it needs to be
1289 return dir->fsend(OKbootstrap);
1294 * Get backup level from Director
1297 static int level_cmd(JCR *jcr)
1299 BSOCK *dir = jcr->dir_bsock;
1300 POOLMEM *level, *buf = NULL;
1303 level = get_memory(dir->msglen+1);
1304 Dmsg1(100, "level_cmd: %s", dir->msg);
1306 /* keep compatibility with older directors */
1307 if (strstr(dir->msg, "accurate")) {
1308 jcr->accurate = true;
1310 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1313 /* Base backup requested? */
1314 if (strcmp(level, "base") == 0) {
1315 jcr->set_JobLevel(L_BASE);
1316 /* Full backup requested? */
1317 } else if (strcmp(level, "full") == 0) {
1318 jcr->set_JobLevel(L_FULL);
1319 } else if (strstr(level, "differential")) {
1320 jcr->set_JobLevel(L_DIFFERENTIAL);
1323 } else if (strstr(level, "incremental")) {
1324 jcr->set_JobLevel(L_INCREMENTAL);
1328 * We get his UTC since time, then sync the clocks and correct it
1329 * to agree with our clock.
1331 } else if (strcmp(level, "since_utime") == 0) {
1332 buf = get_memory(dir->msglen+1);
1333 utime_t since_time, adj;
1334 btime_t his_time, bt_start, rt=0, bt_adj=0;
1335 if (jcr->getJobLevel() == L_NONE) {
1336 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1338 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1339 buf, &mtime_only) != 2) {
1342 since_time = str_to_uint64(buf); /* this is the since time */
1343 Dmsg1(100, "since_time=%lld\n", since_time);
1344 char ed1[50], ed2[50];
1346 * Sync clocks by polling him for the time. We take
1347 * 10 samples of his time throwing out the first two.
1349 for (int i=0; i<10; i++) {
1350 bt_start = get_current_btime();
1351 dir->signal(BNET_BTIME); /* poll for time */
1352 if (dir->recv() <= 0) { /* get response */
1355 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1358 if (i < 2) { /* toss first two results */
1361 his_time = str_to_uint64(buf);
1362 rt = get_current_btime() - bt_start; /* compute round trip time */
1363 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1364 edit_uint64(bt_start, ed2));
1365 bt_adj += bt_start - his_time - rt/2;
1366 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1369 bt_adj = bt_adj / 8; /* compute average time */
1370 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1371 adj = btime_to_utime(bt_adj);
1372 since_time += adj; /* adjust for clock difference */
1373 /* Don't notify if time within 3 seconds */
1374 if (adj > 3 || adj < -3) {
1376 if (adj > 600 || adj < -600) {
1381 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1383 dir->signal(BNET_EOD);
1385 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1386 jcr->incremental = 1; /* set incremental or decremental backup */
1387 jcr->mtime = since_time; /* set since time */
1388 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1390 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1398 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1399 return dir->fsend(OKlevel);
1402 pm_strcpy(jcr->errmsg, dir->msg);
1403 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1412 * Get session parameters from Director -- this is for a Restore command
1414 static int session_cmd(JCR *jcr)
1416 BSOCK *dir = jcr->dir_bsock;
1418 Dmsg1(100, "SessionCmd: %s", dir->msg);
1419 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1420 &jcr->VolSessionId, &jcr->VolSessionTime,
1421 &jcr->StartFile, &jcr->EndFile,
1422 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1423 pm_strcpy(jcr->errmsg, dir->msg);
1424 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1428 return dir->fsend(OKsession);
1431 static void set_storage_auth_key(JCR *jcr, char *key)
1433 /* if no key don't update anything */
1438 /* We can be contacting multiple storage daemons.
1439 * So, make sure that any old jcr->store_bsock is cleaned up.
1441 if (jcr->store_bsock) {
1442 jcr->store_bsock->destroy();
1443 jcr->store_bsock = NULL;
1446 /* We can be contacting multiple storage daemons.
1447 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1449 if (jcr->sd_auth_key) {
1450 /* If we already have a Authorization key, director can do multi
1453 Dmsg0(5, "set multi_restore=true\n");
1454 jcr->multi_restore = true;
1455 bfree(jcr->sd_auth_key);
1458 jcr->sd_auth_key = bstrdup(key);
1462 * Get address of storage daemon from Director
1465 static int storage_cmd(JCR *jcr)
1467 int stored_port; /* storage daemon port */
1468 int enable_ssl; /* enable ssl to sd */
1469 POOL_MEM sd_auth_key(PM_MESSAGE);
1470 BSOCK *dir = jcr->dir_bsock;
1471 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1474 Dmsg1(100, "StorageCmd: %s", dir->msg);
1475 sd_auth_key.check_size(dir->msglen);
1476 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1477 &enable_ssl, sd_auth_key.c_str()) != 4)
1479 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1480 &stored_port, &enable_ssl) != 3)
1482 pm_strcpy(jcr->errmsg, dir->msg);
1483 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1488 set_storage_auth_key(jcr, sd_auth_key.c_str());
1490 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1492 /* Open command communications with Storage daemon */
1493 /* Try to connect for 1 hour at 10 second intervals */
1495 sd->set_source_address(me->FDsrc_addr);
1496 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1497 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1503 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1504 jcr->stored_addr, stored_port);
1505 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1506 jcr->stored_addr, stored_port);
1509 Dmsg0(110, "Connection OK to SD.\n");
1511 jcr->store_bsock = sd;
1513 sd->fsend("Hello Start Job %s\n", jcr->Job);
1514 if (!authenticate_storagedaemon(jcr)) {
1515 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1518 Dmsg0(110, "Authenticated with SD.\n");
1520 /* Send OK to Director */
1521 return dir->fsend(OKstore);
1524 dir->fsend(BADcmd, "storage");
1533 static int backup_cmd(JCR *jcr)
1535 BSOCK *dir = jcr->dir_bsock;
1536 BSOCK *sd = jcr->store_bsock;
1540 #if defined(WIN32_VSS)
1541 // capture state here, if client is backed up by multiple directors
1542 // and one enables vss and the other does not then enable_vss can change
1543 // between here and where its evaluated after the job completes.
1544 jcr->VSS = g_pVSSClient && enable_vss;
1546 /* Run only one at a time */
1552 * Validate some options given to the backup make sense for the compiled in
1553 * options of this filed.
1555 if (jcr->ff->flags & FO_ACL && !have_acl) {
1556 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1559 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1560 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1564 set_jcr_job_status(jcr, JS_Blocked);
1565 jcr->set_JobType(JT_BACKUP);
1566 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1569 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1570 dir->fsend(BADcmd, "backup");
1574 dir->fsend(OKbackup);
1575 Dmsg1(110, "filed>dird: %s", dir->msg);
1578 * Send Append Open Session to Storage daemon
1580 sd->fsend(append_open);
1581 Dmsg1(110, ">stored: %s", sd->msg);
1583 * Expect to receive back the Ticket number
1585 if (bget_msg(sd) >= 0) {
1586 Dmsg1(110, "<stored: %s", sd->msg);
1587 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1588 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1591 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1593 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1598 * Send Append data command to Storage daemon
1600 sd->fsend(append_data, jcr->Ticket);
1601 Dmsg1(110, ">stored: %s", sd->msg);
1604 * Expect to get OK data
1606 Dmsg1(110, "<stored: %s", sd->msg);
1607 if (!response(jcr, sd, OK_data, "Append Data")) {
1611 generate_daemon_event(jcr, "JobStart");
1612 generate_plugin_event(jcr, bEventStartBackupJob);
1614 #if defined(WIN32_VSS)
1615 /* START VSS ON WIN32 */
1617 if (g_pVSSClient->InitializeForBackup()) {
1618 /* tell vss which drives to snapshot */
1619 char szWinDriveLetters[27];
1620 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1621 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1622 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1624 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1626 /* tell user if snapshot creation of a specific drive failed */
1628 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1629 if (islower(szWinDriveLetters[i])) {
1630 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1634 /* inform user about writer states */
1635 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1636 if (g_pVSSClient->GetWriterState(i) < 1) {
1637 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1642 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1646 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1648 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1653 * Send Files to Storage daemon
1655 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1656 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1657 set_jcr_job_status(jcr, JS_ErrorTerminated);
1658 bnet_suppress_error_messages(sd, 1);
1659 bget_msg(sd); /* Read final response from append_data */
1660 Dmsg0(110, "Error in blast_data.\n");
1662 set_jcr_job_status(jcr, JS_Terminated);
1663 /* Note, the above set status will not override an error */
1664 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1665 bnet_suppress_error_messages(sd, 1);
1666 goto cleanup; /* bail out now */
1669 * Expect to get response to append_data from Storage daemon
1671 if (!response(jcr, sd, OK_append, "Append Data")) {
1672 set_jcr_job_status(jcr, JS_ErrorTerminated);
1677 * Send Append End Data to Storage daemon
1679 sd->fsend(append_end, jcr->Ticket);
1681 if (!response(jcr, sd, OK_end, "Append End")) {
1682 set_jcr_job_status(jcr, JS_ErrorTerminated);
1687 * Send Append Close to Storage daemon
1689 sd->fsend(append_close, jcr->Ticket);
1690 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1691 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1693 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1697 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1700 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1701 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1707 #if defined(WIN32_VSS)
1708 /* STOP VSS ON WIN32 */
1709 /* tell vss to close the backup session */
1711 if (g_pVSSClient->CloseBackup()) {
1712 /* inform user about writer states */
1713 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1714 int msg_type = M_INFO;
1715 if (g_pVSSClient->GetWriterState(i) < 1) {
1716 msg_type = M_WARNING;
1719 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1722 Win32ConvCleanupCache();
1727 generate_plugin_event(jcr, bEventEndBackupJob);
1728 return 0; /* return and stop command loop */
1732 * Do a Verify for Director
1735 static int verify_cmd(JCR *jcr)
1737 BSOCK *dir = jcr->dir_bsock;
1738 BSOCK *sd = jcr->store_bsock;
1741 jcr->set_JobType(JT_VERIFY);
1742 if (sscanf(dir->msg, verifycmd, level) != 1) {
1743 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1747 if (strcasecmp(level, "init") == 0) {
1748 jcr->set_JobLevel(L_VERIFY_INIT);
1749 } else if (strcasecmp(level, "catalog") == 0){
1750 jcr->set_JobLevel(L_VERIFY_CATALOG);
1751 } else if (strcasecmp(level, "volume") == 0){
1752 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1753 } else if (strcasecmp(level, "data") == 0){
1754 jcr->set_JobLevel(L_VERIFY_DATA);
1755 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1756 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1758 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1762 dir->fsend(OKverify);
1764 generate_daemon_event(jcr, "JobStart");
1765 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1766 generate_plugin_event(jcr, bEventStartVerifyJob);
1768 Dmsg1(110, "filed>dird: %s", dir->msg);
1770 switch (jcr->getJobLevel()) {
1772 case L_VERIFY_CATALOG:
1775 case L_VERIFY_VOLUME_TO_CATALOG:
1776 if (!open_sd_read_session(jcr)) {
1779 start_dir_heartbeat(jcr);
1780 do_verify_volume(jcr);
1781 stop_dir_heartbeat(jcr);
1783 * Send Close session command to Storage daemon
1785 sd->fsend(read_close, jcr->Ticket);
1786 Dmsg1(130, "filed>stored: %s", sd->msg);
1788 /* ****FIXME**** check response */
1789 bget_msg(sd); /* get OK */
1791 /* Inform Storage daemon that we are done */
1792 sd->signal(BNET_TERMINATE);
1795 case L_VERIFY_DISK_TO_CATALOG:
1799 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1803 dir->signal(BNET_EOD);
1804 generate_plugin_event(jcr, bEventEndVerifyJob);
1805 return 0; /* return and terminate command loop */
1809 * Do a Restore for Director
1812 static int restore_cmd(JCR *jcr)
1814 BSOCK *dir = jcr->dir_bsock;
1815 BSOCK *sd = jcr->store_bsock;
1817 bool use_regexwhere=false;
1822 * Scan WHERE (base directory for restore) from command
1824 Dmsg0(150, "restore command\n");
1825 /* Pickup where string */
1826 args = get_memory(dir->msglen+1);
1829 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1830 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1831 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1832 pm_strcpy(jcr->errmsg, dir->msg);
1833 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1838 use_regexwhere = true;
1840 /* Turn / into nothing */
1841 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1845 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1846 unbash_spaces(args);
1848 if (use_regexwhere) {
1849 jcr->where_bregexp = get_bregexps(args);
1850 if (!jcr->where_bregexp) {
1851 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1852 free_pool_memory(args);
1856 jcr->where = bstrdup(args);
1859 free_pool_memory(args);
1860 jcr->replace = replace;
1861 jcr->prefix_links = prefix_links;
1863 dir->fsend(OKrestore);
1864 Dmsg1(110, "filed>dird: %s", dir->msg);
1866 jcr->set_JobType(JT_RESTORE);
1868 set_jcr_job_status(jcr, JS_Blocked);
1870 if (!open_sd_read_session(jcr)) {
1871 set_jcr_job_status(jcr, JS_ErrorTerminated);
1875 set_jcr_job_status(jcr, JS_Running);
1878 * Do restore of files and data
1880 start_dir_heartbeat(jcr);
1881 generate_daemon_event(jcr, "JobStart");
1882 generate_plugin_event(jcr, bEventStartRestoreJob);
1884 stop_dir_heartbeat(jcr);
1886 set_jcr_job_status(jcr, JS_Terminated);
1887 if (jcr->JobStatus != JS_Terminated) {
1888 bnet_suppress_error_messages(sd, 1);
1892 * Send Close session command to Storage daemon
1894 sd->fsend(read_close, jcr->Ticket);
1895 Dmsg1(130, "filed>stored: %s", sd->msg);
1897 bget_msg(sd); /* get OK */
1899 /* Inform Storage daemon that we are done */
1900 sd->signal(BNET_TERMINATE);
1903 bfree_and_null(jcr->where);
1905 if (jcr->JobErrors) {
1906 set_jcr_job_status(jcr, JS_ErrorTerminated);
1909 Dmsg0(130, "Done in job.c\n");
1912 if (jcr->multi_restore) {
1913 dir->fsend(OKstoreend);
1914 ret = 1; /* we continue the loop, waiting for next part */
1916 end_restore_cmd(jcr);
1917 ret = 0; /* we stop here */
1923 static int end_restore_cmd(JCR *jcr)
1925 Dmsg0(5, "end_restore_cmd\n");
1926 generate_plugin_event(jcr, bEventEndRestoreJob);
1927 return 0; /* return and terminate command loop */
1930 static int open_sd_read_session(JCR *jcr)
1932 BSOCK *sd = jcr->store_bsock;
1935 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1938 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1939 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1940 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1942 * Open Read Session with Storage daemon
1944 sd->fsend(read_open, "DummyVolume",
1945 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1946 jcr->StartBlock, jcr->EndBlock);
1947 Dmsg1(110, ">stored: %s", sd->msg);
1952 if (bget_msg(sd) >= 0) {
1953 Dmsg1(110, "filed<stored: %s", sd->msg);
1954 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1955 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1958 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1960 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1964 if (!send_bootstrap_file(jcr)) {
1969 * Start read of data with Storage daemon
1971 sd->fsend(read_data, jcr->Ticket);
1972 Dmsg1(110, ">stored: %s", sd->msg);
1977 if (!response(jcr, sd, OK_data, "Read Data")) {
1984 * Destroy the Job Control Record and associated
1985 * resources (sockets).
1987 static void filed_free_jcr(JCR *jcr)
1989 if (jcr->store_bsock) {
1990 jcr->store_bsock->close();
1992 free_bootstrap(jcr);
1993 if (jcr->last_fname) {
1994 free_pool_memory(jcr->last_fname);
1996 free_runscripts(jcr->RunScripts);
1997 delete jcr->RunScripts;
1999 if (jcr->JobId != 0)
2000 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2006 * Get response from Storage daemon to a command we
2007 * sent. Check that the response is OK.
2009 * Returns: 0 on failure
2012 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2017 if (bget_msg(sd) > 0) {
2018 Dmsg0(110, sd->msg);
2019 if (strcmp(sd->msg, resp) == 0) {
2023 if (job_canceled(jcr)) {
2024 return 0; /* if canceled avoid useless error messages */
2026 if (is_bnet_error(sd)) {
2027 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2028 cmd, bnet_strerror(sd));
2030 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2031 cmd, resp, sd->msg);
2036 static int send_bootstrap_file(JCR *jcr)
2040 BSOCK *sd = jcr->store_bsock;
2041 const char *bootstrap = "bootstrap\n";
2044 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2045 if (!jcr->RestoreBootstrap) {
2048 bs = fopen(jcr->RestoreBootstrap, "rb");
2051 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2052 jcr->RestoreBootstrap, be.bstrerror());
2053 set_jcr_job_status(jcr, JS_ErrorTerminated);
2056 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2058 while (fgets(buf, sizeof(buf), bs)) {
2059 sd->msglen = Mmsg(sd->msg, "%s", buf);
2062 sd->signal(BNET_EOD);
2064 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2065 set_jcr_job_status(jcr, JS_ErrorTerminated);
2071 free_bootstrap(jcr);