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 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
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");
398 static int sm_dump_cmd(JCR *jcr)
400 sm_dump(false, true);
401 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
406 static int exit_cmd(JCR *jcr)
408 jcr->dir_bsock->fsend("2000 exit OK\n");
416 * Hello from Director he must identify himself and provide his
419 static int hello_cmd(JCR *jcr)
421 Dmsg0(120, "Calling Authenticate\n");
422 if (!authenticate_director(jcr)) {
425 Dmsg0(120, "OK Authenticate\n");
426 jcr->authenticated = true;
433 static int cancel_cmd(JCR *jcr)
435 BSOCK *dir = jcr->dir_bsock;
436 char Job[MAX_NAME_LENGTH];
439 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
440 if (!(cjcr=get_jcr_by_full_name(Job))) {
441 dir->fsend(_("2901 Job %s not found.\n"), Job);
443 if (cjcr->store_bsock) {
444 cjcr->store_bsock->set_timed_out();
445 cjcr->store_bsock->set_terminated();
446 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
448 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
449 set_jcr_job_status(cjcr, JS_Canceled);
451 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
454 dir->fsend(_("2902 Error scanning cancel command.\n"));
456 dir->signal(BNET_EOD);
462 * Set debug level as requested by the Director
465 static int setdebug_cmd(JCR *jcr)
467 BSOCK *dir = jcr->dir_bsock;
468 int level, trace_flag;
470 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
471 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
472 pm_strcpy(jcr->errmsg, dir->msg);
473 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
477 set_trace(trace_flag);
478 return dir->fsend(OKsetdebug, level);
482 static int estimate_cmd(JCR *jcr)
484 BSOCK *dir = jcr->dir_bsock;
485 char ed1[50], ed2[50];
487 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
488 pm_strcpy(jcr->errmsg, dir->msg);
489 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
490 dir->fsend(_("2992 Bad estimate command.\n"));
494 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
495 edit_uint64_with_commas(jcr->JobBytes, ed2));
496 dir->signal(BNET_EOD);
501 * Get JobId and Storage Daemon Authorization key from Director
503 static int job_cmd(JCR *jcr)
505 BSOCK *dir = jcr->dir_bsock;
506 POOL_MEM sd_auth_key(PM_MESSAGE);
507 sd_auth_key.check_size(dir->msglen);
509 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
510 &jcr->VolSessionId, &jcr->VolSessionTime,
511 sd_auth_key.c_str()) != 5) {
512 pm_strcpy(jcr->errmsg, dir->msg);
513 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
517 set_storage_auth_key(jcr, sd_auth_key.c_str());
518 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
519 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
520 new_plugins(jcr); /* instantiate plugins for this jcr */
521 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
522 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
525 static int runbefore_cmd(JCR *jcr)
528 BSOCK *dir = jcr->dir_bsock;
529 POOLMEM *cmd = get_memory(dir->msglen+1);
532 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
533 if (sscanf(dir->msg, runbefore, cmd) != 1) {
534 pm_strcpy(jcr->errmsg, dir->msg);
535 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
536 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
542 /* Run the command now */
543 script = new_runscript();
544 script->set_command(cmd);
545 script->when = SCRIPT_Before;
546 ok = script->run(jcr, "ClientRunBeforeJob");
547 free_runscript(script);
551 dir->fsend(OKRunBefore);
554 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
559 static int runbeforenow_cmd(JCR *jcr)
561 BSOCK *dir = jcr->dir_bsock;
563 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
564 if (job_canceled(jcr)) {
565 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
566 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
569 dir->fsend(OKRunBeforeNow);
570 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
575 static int runafter_cmd(JCR *jcr)
577 BSOCK *dir = jcr->dir_bsock;
578 POOLMEM *msg = get_memory(dir->msglen+1);
581 Dmsg1(100, "runafter_cmd: %s", dir->msg);
582 if (sscanf(dir->msg, runafter, msg) != 1) {
583 pm_strcpy(jcr->errmsg, dir->msg);
584 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
585 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
591 cmd = new_runscript();
592 cmd->set_command(msg);
593 cmd->on_success = true;
594 cmd->on_failure = false;
595 cmd->when = SCRIPT_After;
597 jcr->RunScripts->append(cmd);
599 free_pool_memory(msg);
600 return dir->fsend(OKRunAfter);
603 static int runscript_cmd(JCR *jcr)
605 BSOCK *dir = jcr->dir_bsock;
606 POOLMEM *msg = get_memory(dir->msglen+1);
607 int on_success, on_failure, fail_on_error;
609 RUNSCRIPT *cmd = new_runscript() ;
611 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
612 /* Note, we cannot sscanf into bools */
613 if (sscanf(dir->msg, runscript, &on_success,
618 pm_strcpy(jcr->errmsg, dir->msg);
619 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
620 dir->fsend(_("2905 Bad RunScript command.\n"));
625 cmd->on_success = on_success;
626 cmd->on_failure = on_failure;
627 cmd->fail_on_error = fail_on_error;
630 cmd->set_command(msg);
632 jcr->RunScripts->append(cmd);
634 free_pool_memory(msg);
635 return dir->fsend(OKRunScript);
639 static bool init_fileset(JCR *jcr)
642 findFILESET *fileset;
651 fileset = (findFILESET *)malloc(sizeof(findFILESET));
652 memset(fileset, 0, sizeof(findFILESET));
653 ff->fileset = fileset;
654 fileset->state = state_none;
655 fileset->include_list.init(1, true);
656 fileset->exclude_list.init(1, true);
660 static findFOPTS *start_options(FF_PKT *ff)
662 int state = ff->fileset->state;
663 findINCEXE *incexe = ff->fileset->incexe;
665 if (state != state_options) {
666 ff->fileset->state = state_options;
667 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
668 memset(fo, 0, sizeof(findFOPTS));
669 fo->regex.init(1, true);
670 fo->regexdir.init(1, true);
671 fo->regexfile.init(1, true);
672 fo->wild.init(1, true);
673 fo->wilddir.init(1, true);
674 fo->wildfile.init(1, true);
675 fo->wildbase.init(1, true);
676 fo->base.init(1, true);
677 fo->fstype.init(1, true);
678 fo->drivetype.init(1, true);
679 incexe->current_opts = fo;
680 incexe->opts_list.append(fo);
682 return incexe->current_opts;
687 * Add fname to include/exclude fileset list. First check for
688 * | and < and if necessary perform command.
690 void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
705 p++; /* skip over | */
706 fn = get_pool_memory(PM_FNAME);
707 fn = edit_job_codes(jcr, fn, p, "");
708 bpipe = open_bpipe(fn, 0, "r");
711 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
713 free_pool_memory(fn);
716 free_pool_memory(fn);
717 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
718 strip_trailing_junk(buf);
720 fileset->incexe->name_list.append(new_dlistString(buf));
722 fileset->incexe->plugin_list.append(new_dlistString(buf));
725 if ((stat=close_bpipe(bpipe)) != 0) {
727 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
728 p, be.code(stat), be.bstrerror(stat));
733 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
734 p++; /* skip over < */
735 if ((ffd = fopen(p, "rb")) == NULL) {
737 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
741 while (fgets(buf, sizeof(buf), ffd)) {
742 strip_trailing_junk(buf);
743 Dmsg1(100, "%s\n", buf);
745 fileset->incexe->name_list.append(new_dlistString(buf));
747 fileset->incexe->plugin_list.append(new_dlistString(buf));
754 fileset->incexe->name_list.append(new_dlistString(fname));
756 if (me->plugin_directory) {
757 fileset->incexe->plugin_list.append(new_dlistString(fname));
759 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
767 findFILESET *new_exclude(JCR *jcr)
769 FF_PKT *ff = jcr->ff;
770 findFILESET *fileset = ff->fileset;
773 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
774 memset(fileset->incexe, 0, sizeof(findINCEXE));
775 fileset->incexe->opts_list.init(1, true);
776 fileset->incexe->name_list.init();
777 fileset->incexe->plugin_list.init();
778 fileset->exclude_list.append(fileset->incexe);
783 static void add_fileset(JCR *jcr, const char *item)
785 FF_PKT *ff = jcr->ff;
786 findFILESET *fileset = ff->fileset;
787 int state = fileset->state;
788 findFOPTS *current_opts;
790 /* Get code, optional subcode, and position item past the dividing space */
791 Dmsg1(100, "%s\n", item);
796 int subcode = ' '; /* A space is always a valid subcode */
797 if (item[0] != '\0' && item[0] != ' ') {
805 /* Skip all lines we receive after an error */
806 if (state == state_error) {
807 Dmsg0(100, "State=error return\n");
812 * The switch tests the code for validity.
813 * The subcode is always good if it is a space, otherwise we must confirm.
814 * We set state to state_error first assuming the subcode is invalid,
815 * requiring state to be set in cases below that handle subcodes.
817 if (subcode != ' ') {
819 Dmsg0(100, "Set state=error or double code.\n");
824 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
825 memset(fileset->incexe, 0, sizeof(findINCEXE));
826 fileset->incexe->opts_list.init(1, true);
827 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
828 fileset->incexe->plugin_list.init();
829 fileset->include_list.append(fileset->incexe);
832 fileset = new_exclude(jcr);
838 /* File item to include or exclude list */
839 state = state_include;
840 add_file_to_fileset(jcr, item, fileset, true);
843 /* Plugin item to include list */
844 state = state_include;
845 add_file_to_fileset(jcr, item, fileset, false);
848 current_opts = start_options(ff);
852 preg = (regex_t *)malloc(sizeof(regex_t));
853 if (current_opts->flags & FO_IGNORECASE) {
854 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
856 rc = regcomp(preg, item, REG_EXTENDED);
859 regerror(rc, preg, prbuf, sizeof(prbuf));
862 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
866 state = state_options;
867 if (subcode == ' ') {
868 current_opts->regex.append(preg);
869 } else if (subcode == 'D') {
870 current_opts->regexdir.append(preg);
871 } else if (subcode == 'F') {
872 current_opts->regexfile.append(preg);
878 current_opts = start_options(ff);
879 current_opts->base.append(bstrdup(item));
880 state = state_options;
883 current_opts = start_options(ff);
884 state = state_options;
885 if (subcode == ' ') {
886 current_opts->fstype.append(bstrdup(item));
887 } else if (subcode == 'D') {
888 current_opts->drivetype.append(bstrdup(item));
894 current_opts = start_options(ff);
895 state = state_options;
896 if (subcode == ' ') {
897 current_opts->wild.append(bstrdup(item));
898 } else if (subcode == 'D') {
899 current_opts->wilddir.append(bstrdup(item));
900 } else if (subcode == 'F') {
901 current_opts->wildfile.append(bstrdup(item));
902 } else if (subcode == 'B') {
903 current_opts->wildbase.append(bstrdup(item));
909 current_opts = start_options(ff);
910 set_options(current_opts, item);
911 state = state_options;
914 state = state_include;
915 fileset->incexe->ignoredir = bstrdup(item);
918 current_opts = start_options(ff);
919 // current_opts->reader = bstrdup(item);
920 state = state_options;
923 current_opts = start_options(ff);
924 // current_opts->writer = bstrdup(item);
925 state = state_options;
928 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
932 ff->fileset->state = state;
935 static bool term_fileset(JCR *jcr)
937 FF_PKT *ff = jcr->ff;
939 #ifdef xxx_DEBUG_CODE
940 findFILESET *fileset = ff->fileset;
943 for (i=0; i<fileset->include_list.size(); i++) {
944 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
946 for (j=0; j<incexe->opts_list.size(); j++) {
947 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
948 for (k=0; k<fo->regex.size(); k++) {
949 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
951 for (k=0; k<fo->regexdir.size(); k++) {
952 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
954 for (k=0; k<fo->regexfile.size(); k++) {
955 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
957 for (k=0; k<fo->wild.size(); k++) {
958 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
960 for (k=0; k<fo->wilddir.size(); k++) {
961 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
963 for (k=0; k<fo->wildfile.size(); k++) {
964 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
966 for (k=0; k<fo->wildbase.size(); k++) {
967 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
969 for (k=0; k<fo->base.size(); k++) {
970 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
972 for (k=0; k<fo->fstype.size(); k++) {
973 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
975 for (k=0; k<fo->drivetype.size(); k++) {
976 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
979 if (incexe->ignoredir) {
980 Dmsg1(400, "Z %s\n", incexe->ignoredir);
983 foreach_dlist(node, &incexe->name_list) {
984 Dmsg1(400, "F %s\n", node->c_str());
986 foreach_dlist(node, &incexe->plugin_list) {
987 Dmsg1(400, "P %s\n", node->c_str());
990 for (i=0; i<fileset->exclude_list.size(); i++) {
991 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
993 for (j=0; j<incexe->opts_list.size(); j++) {
994 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
995 for (k=0; k<fo->regex.size(); k++) {
996 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
998 for (k=0; k<fo->regexdir.size(); k++) {
999 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1001 for (k=0; k<fo->regexfile.size(); k++) {
1002 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1004 for (k=0; k<fo->wild.size(); k++) {
1005 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1007 for (k=0; k<fo->wilddir.size(); k++) {
1008 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1010 for (k=0; k<fo->wildfile.size(); k++) {
1011 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1013 for (k=0; k<fo->wildbase.size(); k++) {
1014 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1016 for (k=0; k<fo->base.size(); k++) {
1017 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1019 for (k=0; k<fo->fstype.size(); k++) {
1020 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1022 for (k=0; k<fo->drivetype.size(); k++) {
1023 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1027 foreach_dlist(node, incexe->name_list) {
1028 Dmsg1(400, "F %s\n", node->c_str());
1030 foreach_dlist(node, &incexe->plugin_list) {
1031 Dmsg1(400, "P %s\n", node->c_str());
1035 return ff->fileset->state != state_error;
1040 * As an optimization, we should do this during
1041 * "compile" time in filed/job.c, and keep only a bit mask
1042 * and the Verify options.
1044 static void set_options(findFOPTS *fo, const char *opts)
1050 // Commented out as it is not backward compatible - KES
1052 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1055 for (p=opts; *p; p++) {
1057 case 'a': /* alway replace */
1058 case '0': /* no option */
1061 fo->flags |= FO_EXCLUDE;
1064 fo->flags |= FO_MULTIFS;
1066 case 'h': /* no recursion */
1067 fo->flags |= FO_NO_RECURSION;
1069 case 'H': /* no hard link handling */
1070 fo->flags |= FO_NO_HARDLINK;
1073 fo->flags |= FO_IGNORECASE;
1076 fo->flags |= FO_MD5;
1079 fo->flags |= FO_NOREPLACE;
1081 case 'p': /* use portable data format */
1082 fo->flags |= FO_PORTABLE;
1084 case 'R': /* Resource forks and Finder Info */
1085 fo->flags |= FO_HFSPLUS;
1086 case 'r': /* read fifo */
1087 fo->flags |= FO_READFIFO;
1092 fo->flags |= FO_SHA1;
1097 fo->flags |= FO_SHA256;
1101 fo->flags |= FO_SHA512;
1107 * If 2 or 3 is seen here, SHA2 is not configured, so
1108 * eat the option, and drop back to SHA-1.
1110 if (p[1] == '2' || p[1] == '3') {
1113 fo->flags |= FO_SHA1;
1118 fo->flags |= FO_SPARSE;
1121 fo->flags |= FO_MTIMEONLY;
1124 fo->flags |= FO_KEEPATIME;
1127 fo->flags |= FO_ACL;
1129 case 'V': /* verify options */
1130 /* Copy Verify Options */
1131 for (j=0; *p && *p != ':'; p++) {
1132 fo->VerifyOpts[j] = *p;
1133 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1137 fo->VerifyOpts[j] = 0;
1139 case 'C': /* accurate options */
1140 /* Copy Accurate Options */
1141 for (j=0; *p && *p != ':'; p++) {
1142 fo->AccurateOpts[j] = *p;
1143 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1147 fo->AccurateOpts[j] = 0;
1149 case 'J': /* Basejob options */
1150 /* Copy BaseJob Options */
1151 for (j=0; *p && *p != ':'; p++) {
1152 fo->BaseJobOpts[j] = *p;
1153 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1157 fo->BaseJobOpts[j] = 0;
1159 case 'P': /* strip path */
1162 for (j=0; *p && *p != ':'; p++) {
1164 if (j < (int)sizeof(strip) - 1) {
1169 fo->strip_path = atoi(strip);
1170 fo->flags |= FO_STRIPPATH;
1171 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1174 fo->flags |= FO_IF_NEWER;
1177 fo->flags |= FO_ENHANCEDWILD;
1179 case 'Z': /* gzip compression */
1180 fo->flags |= FO_GZIP;
1181 fo->GZIP_level = *++p - '0';
1184 fo->flags |= FO_NOATIME;
1187 fo->flags |= FO_CHKCHANGES;
1190 fo->flags |= FO_HONOR_NODUMP;
1193 fo->flags |= FO_XATTR;
1196 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1204 * Director is passing his Fileset
1206 static int fileset_cmd(JCR *jcr)
1208 BSOCK *dir = jcr->dir_bsock;
1210 #if defined(WIN32_VSS)
1213 sscanf(dir->msg, "fileset vss=%d", &vss);
1217 if (!init_fileset(jcr)) {
1220 while (dir->recv() >= 0) {
1221 strip_trailing_junk(dir->msg);
1222 Dmsg1(500, "Fileset: %s\n", dir->msg);
1223 add_fileset(jcr, dir->msg);
1225 if (!term_fileset(jcr)) {
1228 return dir->fsend(OKinc);
1231 static void free_bootstrap(JCR *jcr)
1233 if (jcr->RestoreBootstrap) {
1234 unlink(jcr->RestoreBootstrap);
1235 free_pool_memory(jcr->RestoreBootstrap);
1236 jcr->RestoreBootstrap = NULL;
1241 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1242 static uint32_t bsr_uniq = 0;
1245 * The Director sends us the bootstrap file, which
1246 * we will in turn pass to the SD.
1248 static int bootstrap_cmd(JCR *jcr)
1250 BSOCK *dir = jcr->dir_bsock;
1251 POOLMEM *fname = get_pool_memory(PM_FNAME);
1254 free_bootstrap(jcr);
1257 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1258 jcr->Job, bsr_uniq);
1260 Dmsg1(400, "bootstrap=%s\n", fname);
1261 jcr->RestoreBootstrap = fname;
1262 bs = fopen(fname, "a+b"); /* create file */
1265 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1266 jcr->RestoreBootstrap, be.bstrerror());
1268 * Suck up what he is sending to us so that he will then
1269 * read our error message.
1271 while (dir->recv() >= 0)
1273 free_bootstrap(jcr);
1274 set_jcr_job_status(jcr, JS_ErrorTerminated);
1278 while (dir->recv() >= 0) {
1279 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1280 fputs(dir->msg, bs);
1284 * Note, do not free the bootstrap yet -- it needs to be
1287 return dir->fsend(OKbootstrap);
1292 * Get backup level from Director
1295 static int level_cmd(JCR *jcr)
1297 BSOCK *dir = jcr->dir_bsock;
1298 POOLMEM *level, *buf = NULL;
1301 level = get_memory(dir->msglen+1);
1302 Dmsg1(100, "level_cmd: %s", dir->msg);
1304 /* keep compatibility with older directors */
1305 if (strstr(dir->msg, "accurate")) {
1306 jcr->accurate = true;
1308 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1311 /* Base backup requested? */
1312 if (strcmp(level, "base") == 0) {
1313 jcr->set_JobLevel(L_BASE);
1314 /* Full backup requested? */
1315 } else if (strcmp(level, "full") == 0) {
1316 jcr->set_JobLevel(L_FULL);
1317 } else if (strstr(level, "differential")) {
1318 jcr->set_JobLevel(L_DIFFERENTIAL);
1321 } else if (strstr(level, "incremental")) {
1322 jcr->set_JobLevel(L_INCREMENTAL);
1326 * We get his UTC since time, then sync the clocks and correct it
1327 * to agree with our clock.
1329 } else if (strcmp(level, "since_utime") == 0) {
1330 buf = get_memory(dir->msglen+1);
1331 utime_t since_time, adj;
1332 btime_t his_time, bt_start, rt=0, bt_adj=0;
1333 if (jcr->getJobLevel() == L_NONE) {
1334 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1336 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1337 buf, &mtime_only) != 2) {
1340 since_time = str_to_uint64(buf); /* this is the since time */
1341 Dmsg1(100, "since_time=%lld\n", since_time);
1342 char ed1[50], ed2[50];
1344 * Sync clocks by polling him for the time. We take
1345 * 10 samples of his time throwing out the first two.
1347 for (int i=0; i<10; i++) {
1348 bt_start = get_current_btime();
1349 dir->signal(BNET_BTIME); /* poll for time */
1350 if (dir->recv() <= 0) { /* get response */
1353 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1356 if (i < 2) { /* toss first two results */
1359 his_time = str_to_uint64(buf);
1360 rt = get_current_btime() - bt_start; /* compute round trip time */
1361 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1362 edit_uint64(bt_start, ed2));
1363 bt_adj += bt_start - his_time - rt/2;
1364 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1367 bt_adj = bt_adj / 8; /* compute average time */
1368 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1369 adj = btime_to_utime(bt_adj);
1370 since_time += adj; /* adjust for clock difference */
1371 /* Don't notify if time within 3 seconds */
1372 if (adj > 3 || adj < -3) {
1374 if (adj > 600 || adj < -600) {
1379 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1381 dir->signal(BNET_EOD);
1383 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1384 jcr->incremental = 1; /* set incremental or decremental backup */
1385 jcr->mtime = since_time; /* set since time */
1386 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1388 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1396 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1397 return dir->fsend(OKlevel);
1400 pm_strcpy(jcr->errmsg, dir->msg);
1401 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1410 * Get session parameters from Director -- this is for a Restore command
1412 static int session_cmd(JCR *jcr)
1414 BSOCK *dir = jcr->dir_bsock;
1416 Dmsg1(100, "SessionCmd: %s", dir->msg);
1417 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1418 &jcr->VolSessionId, &jcr->VolSessionTime,
1419 &jcr->StartFile, &jcr->EndFile,
1420 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1421 pm_strcpy(jcr->errmsg, dir->msg);
1422 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1426 return dir->fsend(OKsession);
1429 static void set_storage_auth_key(JCR *jcr, char *key)
1431 /* if no key don't update anything */
1436 /* We can be contacting multiple storage daemons.
1437 * So, make sure that any old jcr->store_bsock is cleaned up.
1439 if (jcr->store_bsock) {
1440 jcr->store_bsock->destroy();
1441 jcr->store_bsock = NULL;
1444 /* We can be contacting multiple storage daemons.
1445 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1447 if (jcr->sd_auth_key) {
1448 /* If we already have a Authorization key, director can do multi
1451 Dmsg0(5, "set multi_restore=true\n");
1452 jcr->multi_restore = true;
1453 bfree(jcr->sd_auth_key);
1456 jcr->sd_auth_key = bstrdup(key);
1460 * Get address of storage daemon from Director
1463 static int storage_cmd(JCR *jcr)
1465 int stored_port; /* storage daemon port */
1466 int enable_ssl; /* enable ssl to sd */
1467 POOL_MEM sd_auth_key(PM_MESSAGE);
1468 BSOCK *dir = jcr->dir_bsock;
1469 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1472 Dmsg1(100, "StorageCmd: %s", dir->msg);
1473 sd_auth_key.check_size(dir->msglen);
1474 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1475 &enable_ssl, sd_auth_key.c_str()) != 4)
1477 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1478 &stored_port, &enable_ssl) != 3)
1480 pm_strcpy(jcr->errmsg, dir->msg);
1481 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1486 set_storage_auth_key(jcr, sd_auth_key.c_str());
1488 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1490 /* Open command communications with Storage daemon */
1491 /* Try to connect for 1 hour at 10 second intervals */
1493 sd->set_source_address(me->FDsrc_addr);
1494 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1495 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1501 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1502 jcr->stored_addr, stored_port);
1503 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1504 jcr->stored_addr, stored_port);
1507 Dmsg0(110, "Connection OK to SD.\n");
1509 jcr->store_bsock = sd;
1511 sd->fsend("Hello Start Job %s\n", jcr->Job);
1512 if (!authenticate_storagedaemon(jcr)) {
1513 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1516 Dmsg0(110, "Authenticated with SD.\n");
1518 /* Send OK to Director */
1519 return dir->fsend(OKstore);
1522 dir->fsend(BADcmd, "storage");
1531 static int backup_cmd(JCR *jcr)
1533 BSOCK *dir = jcr->dir_bsock;
1534 BSOCK *sd = jcr->store_bsock;
1538 #if defined(WIN32_VSS)
1539 // capture state here, if client is backed up by multiple directors
1540 // and one enables vss and the other does not then enable_vss can change
1541 // between here and where its evaluated after the job completes.
1542 jcr->VSS = g_pVSSClient && enable_vss;
1544 /* Run only one at a time */
1550 * Validate some options given to the backup make sense for the compiled in
1551 * options of this filed.
1553 if (jcr->ff->flags & FO_ACL && !have_acl) {
1554 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1557 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1558 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1562 set_jcr_job_status(jcr, JS_Blocked);
1563 jcr->set_JobType(JT_BACKUP);
1564 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1567 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1568 dir->fsend(BADcmd, "backup");
1572 dir->fsend(OKbackup);
1573 Dmsg1(110, "filed>dird: %s", dir->msg);
1576 * Send Append Open Session to Storage daemon
1578 sd->fsend(append_open);
1579 Dmsg1(110, ">stored: %s", sd->msg);
1581 * Expect to receive back the Ticket number
1583 if (bget_msg(sd) >= 0) {
1584 Dmsg1(110, "<stored: %s", sd->msg);
1585 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1586 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1589 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1591 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1596 * Send Append data command to Storage daemon
1598 sd->fsend(append_data, jcr->Ticket);
1599 Dmsg1(110, ">stored: %s", sd->msg);
1602 * Expect to get OK data
1604 Dmsg1(110, "<stored: %s", sd->msg);
1605 if (!response(jcr, sd, OK_data, "Append Data")) {
1609 generate_daemon_event(jcr, "JobStart");
1610 generate_plugin_event(jcr, bEventStartBackupJob);
1612 #if defined(WIN32_VSS)
1613 /* START VSS ON WIN32 */
1615 if (g_pVSSClient->InitializeForBackup()) {
1616 /* tell vss which drives to snapshot */
1617 char szWinDriveLetters[27];
1618 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1619 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1620 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1622 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1624 /* tell user if snapshot creation of a specific drive failed */
1626 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1627 if (islower(szWinDriveLetters[i])) {
1628 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1632 /* inform user about writer states */
1633 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1634 if (g_pVSSClient->GetWriterState(i) < 1) {
1635 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1640 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1644 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1646 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1651 * Send Files to Storage daemon
1653 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1654 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1655 set_jcr_job_status(jcr, JS_ErrorTerminated);
1656 bnet_suppress_error_messages(sd, 1);
1657 bget_msg(sd); /* Read final response from append_data */
1658 Dmsg0(110, "Error in blast_data.\n");
1660 set_jcr_job_status(jcr, JS_Terminated);
1661 /* Note, the above set status will not override an error */
1662 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1663 bnet_suppress_error_messages(sd, 1);
1664 goto cleanup; /* bail out now */
1667 * Expect to get response to append_data from Storage daemon
1669 if (!response(jcr, sd, OK_append, "Append Data")) {
1670 set_jcr_job_status(jcr, JS_ErrorTerminated);
1675 * Send Append End Data to Storage daemon
1677 sd->fsend(append_end, jcr->Ticket);
1679 if (!response(jcr, sd, OK_end, "Append End")) {
1680 set_jcr_job_status(jcr, JS_ErrorTerminated);
1685 * Send Append Close to Storage daemon
1687 sd->fsend(append_close, jcr->Ticket);
1688 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1689 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1691 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1695 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1698 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1699 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1705 #if defined(WIN32_VSS)
1706 /* STOP VSS ON WIN32 */
1707 /* tell vss to close the backup session */
1709 if (g_pVSSClient->CloseBackup()) {
1710 /* inform user about writer states */
1711 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1712 int msg_type = M_INFO;
1713 if (g_pVSSClient->GetWriterState(i) < 1) {
1714 msg_type = M_WARNING;
1717 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1720 Win32ConvCleanupCache();
1725 generate_plugin_event(jcr, bEventEndBackupJob);
1726 return 0; /* return and stop command loop */
1730 * Do a Verify for Director
1733 static int verify_cmd(JCR *jcr)
1735 BSOCK *dir = jcr->dir_bsock;
1736 BSOCK *sd = jcr->store_bsock;
1739 jcr->set_JobType(JT_VERIFY);
1740 if (sscanf(dir->msg, verifycmd, level) != 1) {
1741 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1745 if (strcasecmp(level, "init") == 0) {
1746 jcr->set_JobLevel(L_VERIFY_INIT);
1747 } else if (strcasecmp(level, "catalog") == 0){
1748 jcr->set_JobLevel(L_VERIFY_CATALOG);
1749 } else if (strcasecmp(level, "volume") == 0){
1750 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1751 } else if (strcasecmp(level, "data") == 0){
1752 jcr->set_JobLevel(L_VERIFY_DATA);
1753 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1754 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1756 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1760 dir->fsend(OKverify);
1762 generate_daemon_event(jcr, "JobStart");
1763 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1764 generate_plugin_event(jcr, bEventStartVerifyJob);
1766 Dmsg1(110, "filed>dird: %s", dir->msg);
1768 switch (jcr->getJobLevel()) {
1770 case L_VERIFY_CATALOG:
1773 case L_VERIFY_VOLUME_TO_CATALOG:
1774 if (!open_sd_read_session(jcr)) {
1777 start_dir_heartbeat(jcr);
1778 do_verify_volume(jcr);
1779 stop_dir_heartbeat(jcr);
1781 * Send Close session command to Storage daemon
1783 sd->fsend(read_close, jcr->Ticket);
1784 Dmsg1(130, "filed>stored: %s", sd->msg);
1786 /* ****FIXME**** check response */
1787 bget_msg(sd); /* get OK */
1789 /* Inform Storage daemon that we are done */
1790 sd->signal(BNET_TERMINATE);
1793 case L_VERIFY_DISK_TO_CATALOG:
1797 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1801 dir->signal(BNET_EOD);
1802 generate_plugin_event(jcr, bEventEndVerifyJob);
1803 return 0; /* return and terminate command loop */
1807 * Do a Restore for Director
1810 static int restore_cmd(JCR *jcr)
1812 BSOCK *dir = jcr->dir_bsock;
1813 BSOCK *sd = jcr->store_bsock;
1815 bool use_regexwhere=false;
1820 * Scan WHERE (base directory for restore) from command
1822 Dmsg0(150, "restore command\n");
1823 /* Pickup where string */
1824 args = get_memory(dir->msglen+1);
1827 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1828 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1829 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1830 pm_strcpy(jcr->errmsg, dir->msg);
1831 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1836 use_regexwhere = true;
1838 /* Turn / into nothing */
1839 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1843 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1844 unbash_spaces(args);
1846 if (use_regexwhere) {
1847 jcr->where_bregexp = get_bregexps(args);
1848 if (!jcr->where_bregexp) {
1849 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1850 free_pool_memory(args);
1854 jcr->where = bstrdup(args);
1857 free_pool_memory(args);
1858 jcr->replace = replace;
1859 jcr->prefix_links = prefix_links;
1861 dir->fsend(OKrestore);
1862 Dmsg1(110, "filed>dird: %s", dir->msg);
1864 jcr->set_JobType(JT_RESTORE);
1866 set_jcr_job_status(jcr, JS_Blocked);
1868 if (!open_sd_read_session(jcr)) {
1869 set_jcr_job_status(jcr, JS_ErrorTerminated);
1873 set_jcr_job_status(jcr, JS_Running);
1876 * Do restore of files and data
1878 start_dir_heartbeat(jcr);
1879 generate_daemon_event(jcr, "JobStart");
1880 generate_plugin_event(jcr, bEventStartRestoreJob);
1882 stop_dir_heartbeat(jcr);
1884 set_jcr_job_status(jcr, JS_Terminated);
1885 if (jcr->JobStatus != JS_Terminated) {
1886 bnet_suppress_error_messages(sd, 1);
1890 * Send Close session command to Storage daemon
1892 sd->fsend(read_close, jcr->Ticket);
1893 Dmsg1(130, "filed>stored: %s", sd->msg);
1895 bget_msg(sd); /* get OK */
1897 /* Inform Storage daemon that we are done */
1898 sd->signal(BNET_TERMINATE);
1901 bfree_and_null(jcr->where);
1903 if (jcr->JobErrors) {
1904 set_jcr_job_status(jcr, JS_ErrorTerminated);
1907 Dmsg0(130, "Done in job.c\n");
1910 if (jcr->multi_restore) {
1911 dir->fsend(OKstoreend);
1912 ret = 1; /* we continue the loop, waiting for next part */
1914 end_restore_cmd(jcr);
1915 ret = 0; /* we stop here */
1921 static int end_restore_cmd(JCR *jcr)
1923 Dmsg0(5, "end_restore_cmd\n");
1924 generate_plugin_event(jcr, bEventEndRestoreJob);
1925 return 0; /* return and terminate command loop */
1928 static int open_sd_read_session(JCR *jcr)
1930 BSOCK *sd = jcr->store_bsock;
1933 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1936 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1937 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1938 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1940 * Open Read Session with Storage daemon
1942 sd->fsend(read_open, "DummyVolume",
1943 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1944 jcr->StartBlock, jcr->EndBlock);
1945 Dmsg1(110, ">stored: %s", sd->msg);
1950 if (bget_msg(sd) >= 0) {
1951 Dmsg1(110, "filed<stored: %s", sd->msg);
1952 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1953 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1956 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1958 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1962 if (!send_bootstrap_file(jcr)) {
1967 * Start read of data with Storage daemon
1969 sd->fsend(read_data, jcr->Ticket);
1970 Dmsg1(110, ">stored: %s", sd->msg);
1975 if (!response(jcr, sd, OK_data, "Read Data")) {
1982 * Destroy the Job Control Record and associated
1983 * resources (sockets).
1985 static void filed_free_jcr(JCR *jcr)
1987 if (jcr->store_bsock) {
1988 jcr->store_bsock->close();
1990 free_bootstrap(jcr);
1991 if (jcr->last_fname) {
1992 free_pool_memory(jcr->last_fname);
1994 free_runscripts(jcr->RunScripts);
1995 delete jcr->RunScripts;
1997 if (jcr->JobId != 0)
1998 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2004 * Get response from Storage daemon to a command we
2005 * sent. Check that the response is OK.
2007 * Returns: 0 on failure
2010 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2015 if (bget_msg(sd) > 0) {
2016 Dmsg0(110, sd->msg);
2017 if (strcmp(sd->msg, resp) == 0) {
2021 if (job_canceled(jcr)) {
2022 return 0; /* if canceled avoid useless error messages */
2024 if (is_bnet_error(sd)) {
2025 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2026 cmd, bnet_strerror(sd));
2028 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2029 cmd, resp, sd->msg);
2034 static int send_bootstrap_file(JCR *jcr)
2038 BSOCK *sd = jcr->store_bsock;
2039 const char *bootstrap = "bootstrap\n";
2042 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2043 if (!jcr->RestoreBootstrap) {
2046 bs = fopen(jcr->RestoreBootstrap, "rb");
2049 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2050 jcr->RestoreBootstrap, be.bstrerror());
2051 set_jcr_job_status(jcr, JS_ErrorTerminated);
2054 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2056 while (fgets(buf, sizeof(buf), bs)) {
2057 sd->msglen = Mmsg(sd->msg, "%s", buf);
2060 sd->signal(BNET_EOD);
2062 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2063 set_jcr_job_status(jcr, JS_ErrorTerminated);
2069 free_bootstrap(jcr);