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);
94 /* Exported functions */
99 int monitoraccess; /* specify if monitors have access to this function */
103 * The following are the recognized commands from the Director.
105 static struct s_cmds cmds[] = {
106 {"backup", backup_cmd, 0},
107 {"cancel", cancel_cmd, 0},
108 {"setdebug=", setdebug_cmd, 0},
109 {"estimate", estimate_cmd, 0},
110 {"Hello", hello_cmd, 1},
111 {"fileset", fileset_cmd, 0},
112 {"JobId=", job_cmd, 0},
113 {"level = ", level_cmd, 0},
114 {"restore", restore_cmd, 0},
115 {"endrestore", end_restore_cmd, 0},
116 {"session", session_cmd, 0},
117 {"status", status_cmd, 1},
118 {".status", qstatus_cmd, 1},
119 {"storage ", storage_cmd, 0},
120 {"verify", verify_cmd, 0},
121 {"bootstrap", bootstrap_cmd, 0},
122 {"RunBeforeNow", runbeforenow_cmd, 0},
123 {"RunBeforeJob", runbefore_cmd, 0},
124 {"RunAfterJob", runafter_cmd, 0},
125 {"Run", runscript_cmd, 0},
126 {"accurate", accurate_cmd, 0},
127 {NULL, NULL} /* list terminator */
130 /* Commands received from director that need scanning */
131 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
132 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
133 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
134 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
135 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
136 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
137 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
138 static char verifycmd[] = "verify level=%30s";
139 static char estimatecmd[] = "estimate listing=%d";
140 static char runbefore[] = "RunBeforeJob %s";
141 static char runafter[] = "RunAfterJob %s";
142 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
144 /* Responses sent to Director */
145 static char errmsg[] = "2999 Invalid command\n";
146 static char no_auth[] = "2998 No Authorization\n";
147 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
148 static char OKinc[] = "2000 OK include\n";
149 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
150 static char OKlevel[] = "2000 OK level\n";
151 static char OKbackup[] = "2000 OK backup\n";
152 static char OKbootstrap[] = "2000 OK bootstrap\n";
153 static char OKverify[] = "2000 OK verify\n";
154 static char OKrestore[] = "2000 OK restore\n";
155 static char OKsession[] = "2000 OK session\n";
156 static char OKstore[] = "2000 OK storage\n";
157 static char OKstoreend[] = "2000 OK storage end\n";
158 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
159 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
160 static char BADjob[] = "2901 Bad Job\n";
161 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
162 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
163 static char OKRunBefore[] = "2000 OK RunBefore\n";
164 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
165 static char OKRunAfter[] = "2000 OK RunAfter\n";
166 static char OKRunScript[] = "2000 OK RunScript\n";
167 static char BADcmd[] = "2902 Bad %s\n";
170 /* Responses received from Storage Daemon */
171 static char OK_end[] = "3000 OK end\n";
172 static char OK_close[] = "3000 OK close Status = %d\n";
173 static char OK_open[] = "3000 OK open ticket = %d\n";
174 static char OK_data[] = "3000 OK data\n";
175 static char OK_append[] = "3000 OK append data\n";
176 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
179 /* Commands sent to Storage Daemon */
180 static char append_open[] = "append open session\n";
181 static char append_data[] = "append data %d\n";
182 static char append_end[] = "append end session %d\n";
183 static char append_close[] = "append close session %d\n";
184 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
185 static char read_data[] = "read data %d\n";
186 static char read_close[] = "read close session %d\n";
189 * Accept requests from a Director
191 * NOTE! We are running as a separate thread
193 * Send output one line
194 * at a time followed by a zero length transmission.
196 * Return when the connection is terminated or there
199 * Basic task here is:
200 * Authenticate Director (during Hello command).
201 * Accept commands one at a time from the Director
204 * Concerning ClientRunBefore/After, the sequence of events
205 * is rather critical. If they are not done in the right
206 * order one can easily get FD->SD timeouts if the script
209 * The current sequence of events is:
210 * 1. Dir starts job with FD
211 * 2. Dir connects to SD
212 * 3. Dir connects to FD
213 * 4. FD connects to SD
214 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
215 * 6. Dir sends include/exclude
216 * 7. FD sends data to SD
217 * 8. SD/FD disconnects while SD despools data and attributes (optional)
218 * 9. FD runs ClientRunAfterJob
221 void *handle_client_request(void *dirp)
226 BSOCK *dir = (BSOCK *)dirp;
227 const char jobname[12] = "*Director*";
229 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
230 jcr->dir_bsock = dir;
231 jcr->ff = init_find_files();
232 jcr->start_time = time(NULL);
233 jcr->RunScripts = New(alist(10, not_owned_by_alist));
234 jcr->last_fname = get_pool_memory(PM_FNAME);
235 jcr->last_fname[0] = 0;
236 jcr->client_name = get_memory(strlen(my_name) + 1);
237 pm_strcpy(jcr->client_name, my_name);
238 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
239 jcr->crypto.pki_sign = me->pki_sign;
240 jcr->crypto.pki_encrypt = me->pki_encrypt;
241 jcr->crypto.pki_keypair = me->pki_keypair;
242 jcr->crypto.pki_signers = me->pki_signers;
243 jcr->crypto.pki_recipients = me->pki_recipients;
245 enable_backup_privileges(NULL, 1 /* ignore_errors */);
247 /**********FIXME******* add command handler error code */
249 for (quit=false; !quit;) {
251 if (dir->recv() < 0) {
252 break; /* connection terminated */
254 dir->msg[dir->msglen] = 0;
255 Dmsg1(100, "<dird: %s", dir->msg);
257 for (i=0; cmds[i].cmd; i++) {
258 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
259 found = true; /* indicate command found */
260 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
262 dir->signal(BNET_EOD);
265 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
266 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
267 dir->fsend(invalid_cmd);
268 dir->signal(BNET_EOD);
271 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
272 if (!cmds[i].func(jcr)) { /* do command */
273 quit = true; /* error or fully terminated, get out */
274 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
279 if (!found) { /* command not found */
286 /* Inform Storage daemon that we are done */
287 if (jcr->store_bsock) {
288 jcr->store_bsock->signal(BNET_TERMINATE);
291 /* Run the after job */
292 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
294 if (jcr->JobId) { /* send EndJob if running a job */
295 char ed1[50], ed2[50];
296 /* Send termination status back to Dir */
297 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
298 edit_uint64(jcr->ReadBytes, ed1),
299 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
300 jcr->crypto.pki_encrypt);
301 Dmsg1(110, "End FD msg: %s\n", dir->msg);
304 generate_daemon_event(jcr, "JobEnd");
305 generate_plugin_event(jcr, bEventJobEnd);
307 dequeue_messages(jcr); /* send any queued messages */
309 /* Inform Director that we are done */
310 dir->signal(BNET_TERMINATE);
312 free_plugins(jcr); /* release instantiated plugins */
314 /* Clean up fileset */
315 FF_PKT *ff = jcr->ff;
316 findFILESET *fileset = ff->fileset;
319 /* Delete FileSet Include lists */
320 for (i=0; i<fileset->include_list.size(); i++) {
321 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
322 for (j=0; j<incexe->opts_list.size(); j++) {
323 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
324 for (k=0; k<fo->regex.size(); k++) {
325 regfree((regex_t *)fo->regex.get(k));
327 for (k=0; k<fo->regexdir.size(); k++) {
328 regfree((regex_t *)fo->regexdir.get(k));
330 for (k=0; k<fo->regexfile.size(); k++) {
331 regfree((regex_t *)fo->regexfile.get(k));
334 fo->regexdir.destroy();
335 fo->regexfile.destroy();
337 fo->wilddir.destroy();
338 fo->wildfile.destroy();
339 fo->wildbase.destroy();
341 fo->fstype.destroy();
342 fo->drivetype.destroy();
344 incexe->opts_list.destroy();
345 incexe->name_list.destroy();
346 incexe->plugin_list.destroy();
347 if (incexe->ignoredir) {
348 free(incexe->ignoredir);
351 fileset->include_list.destroy();
353 /* Delete FileSet Exclude lists */
354 for (i=0; i<fileset->exclude_list.size(); i++) {
355 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
356 for (j=0; j<incexe->opts_list.size(); j++) {
357 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
359 fo->regexdir.destroy();
360 fo->regexfile.destroy();
362 fo->wilddir.destroy();
363 fo->wildfile.destroy();
364 fo->wildbase.destroy();
366 fo->fstype.destroy();
367 fo->drivetype.destroy();
369 incexe->opts_list.destroy();
370 incexe->name_list.destroy();
371 incexe->plugin_list.destroy();
372 if (incexe->ignoredir) {
373 free(incexe->ignoredir);
376 fileset->exclude_list.destroy();
380 Dmsg0(100, "Calling term_find_files\n");
381 term_find_files(jcr->ff);
383 Dmsg0(100, "Done with term_find_files\n");
384 free_jcr(jcr); /* destroy JCR record */
385 Dmsg0(100, "Done with free_jcr\n");
391 * Hello from Director he must identify himself and provide his
394 static int hello_cmd(JCR *jcr)
396 Dmsg0(120, "Calling Authenticate\n");
397 if (!authenticate_director(jcr)) {
400 Dmsg0(120, "OK Authenticate\n");
401 jcr->authenticated = true;
408 static int cancel_cmd(JCR *jcr)
410 BSOCK *dir = jcr->dir_bsock;
411 char Job[MAX_NAME_LENGTH];
414 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
415 if (!(cjcr=get_jcr_by_full_name(Job))) {
416 dir->fsend(_("2901 Job %s not found.\n"), Job);
418 if (cjcr->store_bsock) {
419 cjcr->store_bsock->set_timed_out();
420 cjcr->store_bsock->set_terminated();
421 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
423 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
424 set_jcr_job_status(cjcr, JS_Canceled);
426 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
429 dir->fsend(_("2902 Error scanning cancel command.\n"));
431 dir->signal(BNET_EOD);
437 * Set debug level as requested by the Director
440 static int setdebug_cmd(JCR *jcr)
442 BSOCK *dir = jcr->dir_bsock;
443 int level, trace_flag;
445 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
446 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
447 pm_strcpy(jcr->errmsg, dir->msg);
448 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
452 set_trace(trace_flag);
453 return dir->fsend(OKsetdebug, level);
457 static int estimate_cmd(JCR *jcr)
459 BSOCK *dir = jcr->dir_bsock;
460 char ed1[50], ed2[50];
462 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
463 pm_strcpy(jcr->errmsg, dir->msg);
464 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
465 dir->fsend(_("2992 Bad estimate command.\n"));
469 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
470 edit_uint64_with_commas(jcr->JobBytes, ed2));
471 dir->signal(BNET_EOD);
476 * Get JobId and Storage Daemon Authorization key from Director
478 static int job_cmd(JCR *jcr)
480 BSOCK *dir = jcr->dir_bsock;
481 POOL_MEM sd_auth_key(PM_MESSAGE);
482 sd_auth_key.check_size(dir->msglen);
484 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
485 &jcr->VolSessionId, &jcr->VolSessionTime,
486 sd_auth_key.c_str()) != 5) {
487 pm_strcpy(jcr->errmsg, dir->msg);
488 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
492 set_storage_auth_key(jcr, sd_auth_key.c_str());
493 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
494 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
495 new_plugins(jcr); /* instantiate plugins for this jcr */
496 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
497 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
500 static int runbefore_cmd(JCR *jcr)
503 BSOCK *dir = jcr->dir_bsock;
504 POOLMEM *cmd = get_memory(dir->msglen+1);
507 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
508 if (sscanf(dir->msg, runbefore, cmd) != 1) {
509 pm_strcpy(jcr->errmsg, dir->msg);
510 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
511 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
517 /* Run the command now */
518 script = new_runscript();
519 script->set_command(cmd);
520 script->when = SCRIPT_Before;
521 ok = script->run(jcr, "ClientRunBeforeJob");
522 free_runscript(script);
526 dir->fsend(OKRunBefore);
529 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
534 static int runbeforenow_cmd(JCR *jcr)
536 BSOCK *dir = jcr->dir_bsock;
538 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
539 if (job_canceled(jcr)) {
540 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
541 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
544 dir->fsend(OKRunBeforeNow);
545 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
550 static int runafter_cmd(JCR *jcr)
552 BSOCK *dir = jcr->dir_bsock;
553 POOLMEM *msg = get_memory(dir->msglen+1);
556 Dmsg1(100, "runafter_cmd: %s", dir->msg);
557 if (sscanf(dir->msg, runafter, msg) != 1) {
558 pm_strcpy(jcr->errmsg, dir->msg);
559 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
560 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
566 cmd = new_runscript();
567 cmd->set_command(msg);
568 cmd->on_success = true;
569 cmd->on_failure = false;
570 cmd->when = SCRIPT_After;
572 jcr->RunScripts->append(cmd);
574 free_pool_memory(msg);
575 return dir->fsend(OKRunAfter);
578 static int runscript_cmd(JCR *jcr)
580 BSOCK *dir = jcr->dir_bsock;
581 POOLMEM *msg = get_memory(dir->msglen+1);
582 int on_success, on_failure, fail_on_error;
584 RUNSCRIPT *cmd = new_runscript() ;
586 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
587 /* Note, we cannot sscanf into bools */
588 if (sscanf(dir->msg, runscript, &on_success,
593 pm_strcpy(jcr->errmsg, dir->msg);
594 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
595 dir->fsend(_("2905 Bad RunScript command.\n"));
600 cmd->on_success = on_success;
601 cmd->on_failure = on_failure;
602 cmd->fail_on_error = fail_on_error;
605 cmd->set_command(msg);
607 jcr->RunScripts->append(cmd);
609 free_pool_memory(msg);
610 return dir->fsend(OKRunScript);
614 static bool init_fileset(JCR *jcr)
617 findFILESET *fileset;
626 fileset = (findFILESET *)malloc(sizeof(findFILESET));
627 memset(fileset, 0, sizeof(findFILESET));
628 ff->fileset = fileset;
629 fileset->state = state_none;
630 fileset->include_list.init(1, true);
631 fileset->exclude_list.init(1, true);
635 static findFOPTS *start_options(FF_PKT *ff)
637 int state = ff->fileset->state;
638 findINCEXE *incexe = ff->fileset->incexe;
640 if (state != state_options) {
641 ff->fileset->state = state_options;
642 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
643 memset(fo, 0, sizeof(findFOPTS));
644 fo->regex.init(1, true);
645 fo->regexdir.init(1, true);
646 fo->regexfile.init(1, true);
647 fo->wild.init(1, true);
648 fo->wilddir.init(1, true);
649 fo->wildfile.init(1, true);
650 fo->wildbase.init(1, true);
651 fo->base.init(1, true);
652 fo->fstype.init(1, true);
653 fo->drivetype.init(1, true);
654 incexe->current_opts = fo;
655 incexe->opts_list.append(fo);
657 return incexe->current_opts;
662 * Add fname to include/exclude fileset list. First check for
663 * | and < and if necessary perform command.
665 void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
680 p++; /* skip over | */
681 fn = get_pool_memory(PM_FNAME);
682 fn = edit_job_codes(jcr, fn, p, "");
683 bpipe = open_bpipe(fn, 0, "r");
686 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
688 free_pool_memory(fn);
691 free_pool_memory(fn);
692 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
693 strip_trailing_junk(buf);
695 fileset->incexe->name_list.append(new_dlistString(buf));
697 fileset->incexe->plugin_list.append(new_dlistString(buf));
700 if ((stat=close_bpipe(bpipe)) != 0) {
702 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
703 p, be.code(stat), be.bstrerror(stat));
708 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
709 p++; /* skip over < */
710 if ((ffd = fopen(p, "rb")) == NULL) {
712 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
716 while (fgets(buf, sizeof(buf), ffd)) {
717 strip_trailing_junk(buf);
718 Dmsg1(100, "%s\n", buf);
720 fileset->incexe->name_list.append(new_dlistString(buf));
722 fileset->incexe->plugin_list.append(new_dlistString(buf));
729 fileset->incexe->name_list.append(new_dlistString(fname));
731 if (me->plugin_directory) {
732 fileset->incexe->plugin_list.append(new_dlistString(fname));
734 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
742 findFILESET *new_exclude(JCR *jcr)
744 FF_PKT *ff = jcr->ff;
745 findFILESET *fileset = ff->fileset;
748 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
749 memset(fileset->incexe, 0, sizeof(findINCEXE));
750 fileset->incexe->opts_list.init(1, true);
751 fileset->incexe->name_list.init();
752 fileset->incexe->plugin_list.init();
753 fileset->exclude_list.append(fileset->incexe);
758 static void add_fileset(JCR *jcr, const char *item)
760 FF_PKT *ff = jcr->ff;
761 findFILESET *fileset = ff->fileset;
762 int state = fileset->state;
763 findFOPTS *current_opts;
765 /* Get code, optional subcode, and position item past the dividing space */
766 Dmsg1(100, "%s\n", item);
771 int subcode = ' '; /* A space is always a valid subcode */
772 if (item[0] != '\0' && item[0] != ' ') {
780 /* Skip all lines we receive after an error */
781 if (state == state_error) {
782 Dmsg0(100, "State=error return\n");
787 * The switch tests the code for validity.
788 * The subcode is always good if it is a space, otherwise we must confirm.
789 * We set state to state_error first assuming the subcode is invalid,
790 * requiring state to be set in cases below that handle subcodes.
792 if (subcode != ' ') {
794 Dmsg0(100, "Set state=error or double code.\n");
799 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
800 memset(fileset->incexe, 0, sizeof(findINCEXE));
801 fileset->incexe->opts_list.init(1, true);
802 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
803 fileset->incexe->plugin_list.init();
804 fileset->include_list.append(fileset->incexe);
807 fileset = new_exclude(jcr);
813 /* File item to include or exclude list */
814 state = state_include;
815 add_file_to_fileset(jcr, item, fileset, true);
818 /* Plugin item to include list */
819 state = state_include;
820 add_file_to_fileset(jcr, item, fileset, false);
823 current_opts = start_options(ff);
827 preg = (regex_t *)malloc(sizeof(regex_t));
828 if (current_opts->flags & FO_IGNORECASE) {
829 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
831 rc = regcomp(preg, item, REG_EXTENDED);
834 regerror(rc, preg, prbuf, sizeof(prbuf));
837 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
841 state = state_options;
842 if (subcode == ' ') {
843 current_opts->regex.append(preg);
844 } else if (subcode == 'D') {
845 current_opts->regexdir.append(preg);
846 } else if (subcode == 'F') {
847 current_opts->regexfile.append(preg);
853 current_opts = start_options(ff);
854 current_opts->base.append(bstrdup(item));
855 state = state_options;
858 current_opts = start_options(ff);
859 state = state_options;
860 if (subcode == ' ') {
861 current_opts->fstype.append(bstrdup(item));
862 } else if (subcode == 'D') {
863 current_opts->drivetype.append(bstrdup(item));
869 current_opts = start_options(ff);
870 state = state_options;
871 if (subcode == ' ') {
872 current_opts->wild.append(bstrdup(item));
873 } else if (subcode == 'D') {
874 current_opts->wilddir.append(bstrdup(item));
875 } else if (subcode == 'F') {
876 current_opts->wildfile.append(bstrdup(item));
877 } else if (subcode == 'B') {
878 current_opts->wildbase.append(bstrdup(item));
884 current_opts = start_options(ff);
885 set_options(current_opts, item);
886 state = state_options;
889 state = state_include;
890 fileset->incexe->ignoredir = bstrdup(item);
893 current_opts = start_options(ff);
894 // current_opts->reader = bstrdup(item);
895 state = state_options;
898 current_opts = start_options(ff);
899 // current_opts->writer = bstrdup(item);
900 state = state_options;
903 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
907 ff->fileset->state = state;
910 static bool term_fileset(JCR *jcr)
912 FF_PKT *ff = jcr->ff;
914 #ifdef xxx_DEBUG_CODE
915 findFILESET *fileset = ff->fileset;
918 for (i=0; i<fileset->include_list.size(); i++) {
919 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
921 for (j=0; j<incexe->opts_list.size(); j++) {
922 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
923 for (k=0; k<fo->regex.size(); k++) {
924 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
926 for (k=0; k<fo->regexdir.size(); k++) {
927 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
929 for (k=0; k<fo->regexfile.size(); k++) {
930 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
932 for (k=0; k<fo->wild.size(); k++) {
933 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
935 for (k=0; k<fo->wilddir.size(); k++) {
936 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
938 for (k=0; k<fo->wildfile.size(); k++) {
939 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
941 for (k=0; k<fo->wildbase.size(); k++) {
942 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
944 for (k=0; k<fo->base.size(); k++) {
945 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
947 for (k=0; k<fo->fstype.size(); k++) {
948 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
950 for (k=0; k<fo->drivetype.size(); k++) {
951 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
954 if (incexe->ignoredir) {
955 Dmsg1(400, "Z %s\n", incexe->ignoredir);
958 foreach_dlist(node, &incexe->name_list) {
959 Dmsg1(400, "F %s\n", node->c_str());
961 foreach_dlist(node, &incexe->plugin_list) {
962 Dmsg1(400, "P %s\n", node->c_str());
965 for (i=0; i<fileset->exclude_list.size(); i++) {
966 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
968 for (j=0; j<incexe->opts_list.size(); j++) {
969 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
970 for (k=0; k<fo->regex.size(); k++) {
971 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
973 for (k=0; k<fo->regexdir.size(); k++) {
974 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
976 for (k=0; k<fo->regexfile.size(); k++) {
977 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
979 for (k=0; k<fo->wild.size(); k++) {
980 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
982 for (k=0; k<fo->wilddir.size(); k++) {
983 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
985 for (k=0; k<fo->wildfile.size(); k++) {
986 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
988 for (k=0; k<fo->wildbase.size(); k++) {
989 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
991 for (k=0; k<fo->base.size(); k++) {
992 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
994 for (k=0; k<fo->fstype.size(); k++) {
995 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
997 for (k=0; k<fo->drivetype.size(); k++) {
998 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1002 foreach_dlist(node, incexe->name_list) {
1003 Dmsg1(400, "F %s\n", node->c_str());
1005 foreach_dlist(node, &incexe->plugin_list) {
1006 Dmsg1(400, "P %s\n", node->c_str());
1010 return ff->fileset->state != state_error;
1015 * As an optimization, we should do this during
1016 * "compile" time in filed/job.c, and keep only a bit mask
1017 * and the Verify options.
1019 static void set_options(findFOPTS *fo, const char *opts)
1025 // Commented out as it is not backward compatible - KES
1027 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1030 for (p=opts; *p; p++) {
1032 case 'a': /* alway replace */
1033 case '0': /* no option */
1036 fo->flags |= FO_EXCLUDE;
1039 fo->flags |= FO_MULTIFS;
1041 case 'h': /* no recursion */
1042 fo->flags |= FO_NO_RECURSION;
1044 case 'H': /* no hard link handling */
1045 fo->flags |= FO_NO_HARDLINK;
1048 fo->flags |= FO_IGNORECASE;
1051 fo->flags |= FO_MD5;
1054 fo->flags |= FO_NOREPLACE;
1056 case 'p': /* use portable data format */
1057 fo->flags |= FO_PORTABLE;
1059 case 'R': /* Resource forks and Finder Info */
1060 fo->flags |= FO_HFSPLUS;
1061 case 'r': /* read fifo */
1062 fo->flags |= FO_READFIFO;
1067 fo->flags |= FO_SHA1;
1072 fo->flags |= FO_SHA256;
1076 fo->flags |= FO_SHA512;
1082 * If 2 or 3 is seen here, SHA2 is not configured, so
1083 * eat the option, and drop back to SHA-1.
1085 if (p[1] == '2' || p[1] == '3') {
1088 fo->flags |= FO_SHA1;
1093 fo->flags |= FO_SPARSE;
1096 fo->flags |= FO_MTIMEONLY;
1099 fo->flags |= FO_KEEPATIME;
1102 fo->flags |= FO_ACL;
1104 case 'V': /* verify options */
1105 /* Copy Verify Options */
1106 for (j=0; *p && *p != ':'; p++) {
1107 fo->VerifyOpts[j] = *p;
1108 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1112 fo->VerifyOpts[j] = 0;
1114 case 'C': /* accurate options */
1115 /* Copy Accurate Options */
1116 for (j=0; *p && *p != ':'; p++) {
1117 fo->AccurateOpts[j] = *p;
1118 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1122 fo->AccurateOpts[j] = 0;
1124 case 'J': /* Basejob options */
1125 /* Copy BaseJob Options */
1126 for (j=0; *p && *p != ':'; p++) {
1127 fo->BaseJobOpts[j] = *p;
1128 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1132 fo->BaseJobOpts[j] = 0;
1134 case 'P': /* strip path */
1137 for (j=0; *p && *p != ':'; p++) {
1139 if (j < (int)sizeof(strip) - 1) {
1144 fo->strip_path = atoi(strip);
1145 fo->flags |= FO_STRIPPATH;
1146 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1149 fo->flags |= FO_IF_NEWER;
1152 fo->flags |= FO_ENHANCEDWILD;
1154 case 'Z': /* gzip compression */
1155 fo->flags |= FO_GZIP;
1156 fo->GZIP_level = *++p - '0';
1159 fo->flags |= FO_NOATIME;
1162 fo->flags |= FO_CHKCHANGES;
1165 fo->flags |= FO_HONOR_NODUMP;
1168 fo->flags |= FO_XATTR;
1171 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1179 * Director is passing his Fileset
1181 static int fileset_cmd(JCR *jcr)
1183 BSOCK *dir = jcr->dir_bsock;
1185 #if defined(WIN32_VSS)
1188 sscanf(dir->msg, "fileset vss=%d", &vss);
1192 if (!init_fileset(jcr)) {
1195 while (dir->recv() >= 0) {
1196 strip_trailing_junk(dir->msg);
1197 Dmsg1(500, "Fileset: %s\n", dir->msg);
1198 add_fileset(jcr, dir->msg);
1200 if (!term_fileset(jcr)) {
1203 return dir->fsend(OKinc);
1206 static void free_bootstrap(JCR *jcr)
1208 if (jcr->RestoreBootstrap) {
1209 unlink(jcr->RestoreBootstrap);
1210 free_pool_memory(jcr->RestoreBootstrap);
1211 jcr->RestoreBootstrap = NULL;
1216 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1217 static uint32_t bsr_uniq = 0;
1220 * The Director sends us the bootstrap file, which
1221 * we will in turn pass to the SD.
1223 static int bootstrap_cmd(JCR *jcr)
1225 BSOCK *dir = jcr->dir_bsock;
1226 POOLMEM *fname = get_pool_memory(PM_FNAME);
1229 free_bootstrap(jcr);
1232 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1233 jcr->Job, bsr_uniq);
1235 Dmsg1(400, "bootstrap=%s\n", fname);
1236 jcr->RestoreBootstrap = fname;
1237 bs = fopen(fname, "a+b"); /* create file */
1240 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1241 jcr->RestoreBootstrap, be.bstrerror());
1243 * Suck up what he is sending to us so that he will then
1244 * read our error message.
1246 while (dir->recv() >= 0)
1248 free_bootstrap(jcr);
1249 set_jcr_job_status(jcr, JS_ErrorTerminated);
1253 while (dir->recv() >= 0) {
1254 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1255 fputs(dir->msg, bs);
1259 * Note, do not free the bootstrap yet -- it needs to be
1262 return dir->fsend(OKbootstrap);
1267 * Get backup level from Director
1270 static int level_cmd(JCR *jcr)
1272 BSOCK *dir = jcr->dir_bsock;
1273 POOLMEM *level, *buf = NULL;
1276 level = get_memory(dir->msglen+1);
1277 Dmsg1(100, "level_cmd: %s", dir->msg);
1279 /* keep compatibility with older directors */
1280 if (strstr(dir->msg, "accurate")) {
1281 jcr->accurate = true;
1283 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1286 /* Base backup requested? */
1287 if (strcmp(level, "base") == 0) {
1288 jcr->set_JobLevel(L_BASE);
1289 /* Full backup requested? */
1290 } else if (strcmp(level, "full") == 0) {
1291 jcr->set_JobLevel(L_FULL);
1292 } else if (strstr(level, "differential")) {
1293 jcr->set_JobLevel(L_DIFFERENTIAL);
1296 } else if (strstr(level, "incremental")) {
1297 jcr->set_JobLevel(L_INCREMENTAL);
1301 * We get his UTC since time, then sync the clocks and correct it
1302 * to agree with our clock.
1304 } else if (strcmp(level, "since_utime") == 0) {
1305 buf = get_memory(dir->msglen+1);
1306 utime_t since_time, adj;
1307 btime_t his_time, bt_start, rt=0, bt_adj=0;
1308 if (jcr->getJobLevel() == L_NONE) {
1309 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1311 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1312 buf, &mtime_only) != 2) {
1315 since_time = str_to_uint64(buf); /* this is the since time */
1316 Dmsg1(100, "since_time=%lld\n", since_time);
1317 char ed1[50], ed2[50];
1319 * Sync clocks by polling him for the time. We take
1320 * 10 samples of his time throwing out the first two.
1322 for (int i=0; i<10; i++) {
1323 bt_start = get_current_btime();
1324 dir->signal(BNET_BTIME); /* poll for time */
1325 if (dir->recv() <= 0) { /* get response */
1328 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1331 if (i < 2) { /* toss first two results */
1334 his_time = str_to_uint64(buf);
1335 rt = get_current_btime() - bt_start; /* compute round trip time */
1336 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1337 edit_uint64(bt_start, ed2));
1338 bt_adj += bt_start - his_time - rt/2;
1339 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1342 bt_adj = bt_adj / 8; /* compute average time */
1343 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1344 adj = btime_to_utime(bt_adj);
1345 since_time += adj; /* adjust for clock difference */
1346 /* Don't notify if time within 3 seconds */
1347 if (adj > 3 || adj < -3) {
1349 if (adj > 600 || adj < -600) {
1354 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1356 dir->signal(BNET_EOD);
1358 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1359 jcr->incremental = 1; /* set incremental or decremental backup */
1360 jcr->mtime = since_time; /* set since time */
1361 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1363 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1371 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1372 return dir->fsend(OKlevel);
1375 pm_strcpy(jcr->errmsg, dir->msg);
1376 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1385 * Get session parameters from Director -- this is for a Restore command
1387 static int session_cmd(JCR *jcr)
1389 BSOCK *dir = jcr->dir_bsock;
1391 Dmsg1(100, "SessionCmd: %s", dir->msg);
1392 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1393 &jcr->VolSessionId, &jcr->VolSessionTime,
1394 &jcr->StartFile, &jcr->EndFile,
1395 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1396 pm_strcpy(jcr->errmsg, dir->msg);
1397 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1401 return dir->fsend(OKsession);
1404 static void set_storage_auth_key(JCR *jcr, char *key)
1406 /* if no key don't update anything */
1411 /* We can be contacting multiple storage daemons.
1412 * So, make sure that any old jcr->store_bsock is cleaned up.
1414 if (jcr->store_bsock) {
1415 jcr->store_bsock->destroy();
1416 jcr->store_bsock = NULL;
1419 /* We can be contacting multiple storage daemons.
1420 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1422 if (jcr->sd_auth_key) {
1423 /* If we already have a Authorization key, director can do multi
1426 Dmsg0(5, "set multi_restore=true\n");
1427 jcr->multi_restore = true;
1428 bfree(jcr->sd_auth_key);
1431 jcr->sd_auth_key = bstrdup(key);
1435 * Get address of storage daemon from Director
1438 static int storage_cmd(JCR *jcr)
1440 int stored_port; /* storage daemon port */
1441 int enable_ssl; /* enable ssl to sd */
1442 POOL_MEM sd_auth_key(PM_MESSAGE);
1443 BSOCK *dir = jcr->dir_bsock;
1444 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1447 Dmsg1(100, "StorageCmd: %s", dir->msg);
1448 sd_auth_key.check_size(dir->msglen);
1449 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1450 &enable_ssl, sd_auth_key.c_str()) != 4)
1452 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1453 &stored_port, &enable_ssl) != 3)
1455 pm_strcpy(jcr->errmsg, dir->msg);
1456 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1461 set_storage_auth_key(jcr, sd_auth_key.c_str());
1463 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1465 /* Open command communications with Storage daemon */
1466 /* Try to connect for 1 hour at 10 second intervals */
1468 sd->set_source_address(me->FDsrc_addr);
1469 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1470 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1476 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1477 jcr->stored_addr, stored_port);
1478 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1479 jcr->stored_addr, stored_port);
1482 Dmsg0(110, "Connection OK to SD.\n");
1484 jcr->store_bsock = sd;
1486 sd->fsend("Hello Start Job %s\n", jcr->Job);
1487 if (!authenticate_storagedaemon(jcr)) {
1488 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1491 Dmsg0(110, "Authenticated with SD.\n");
1493 /* Send OK to Director */
1494 return dir->fsend(OKstore);
1497 dir->fsend(BADcmd, "storage");
1506 static int backup_cmd(JCR *jcr)
1508 BSOCK *dir = jcr->dir_bsock;
1509 BSOCK *sd = jcr->store_bsock;
1513 #if defined(WIN32_VSS)
1514 // capture state here, if client is backed up by multiple directors
1515 // and one enables vss and the other does not then enable_vss can change
1516 // between here and where its evaluated after the job completes.
1517 jcr->VSS = g_pVSSClient && enable_vss;
1519 /* Run only one at a time */
1525 * Validate some options given to the backup make sense for the compiled in
1526 * options of this filed.
1528 if (jcr->ff->flags & FO_ACL && !have_acl) {
1529 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1532 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1533 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1537 set_jcr_job_status(jcr, JS_Blocked);
1538 jcr->set_JobType(JT_BACKUP);
1539 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1542 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1543 dir->fsend(BADcmd, "backup");
1547 dir->fsend(OKbackup);
1548 Dmsg1(110, "filed>dird: %s", dir->msg);
1551 * Send Append Open Session to Storage daemon
1553 sd->fsend(append_open);
1554 Dmsg1(110, ">stored: %s", sd->msg);
1556 * Expect to receive back the Ticket number
1558 if (bget_msg(sd) >= 0) {
1559 Dmsg1(110, "<stored: %s", sd->msg);
1560 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1561 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1564 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1566 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1571 * Send Append data command to Storage daemon
1573 sd->fsend(append_data, jcr->Ticket);
1574 Dmsg1(110, ">stored: %s", sd->msg);
1577 * Expect to get OK data
1579 Dmsg1(110, "<stored: %s", sd->msg);
1580 if (!response(jcr, sd, OK_data, "Append Data")) {
1584 generate_daemon_event(jcr, "JobStart");
1585 generate_plugin_event(jcr, bEventStartBackupJob);
1587 #if defined(WIN32_VSS)
1588 /* START VSS ON WIN32 */
1590 if (g_pVSSClient->InitializeForBackup()) {
1591 /* tell vss which drives to snapshot */
1592 char szWinDriveLetters[27];
1593 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1594 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1595 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1596 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1599 /* tell user if snapshot creation of a specific drive failed */
1601 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1602 if (islower(szWinDriveLetters[i])) {
1603 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1607 /* inform user about writer states */
1608 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1609 if (g_pVSSClient->GetWriterState(i) < 1) {
1610 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1615 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1619 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1621 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1626 * Send Files to Storage daemon
1628 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1629 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1630 set_jcr_job_status(jcr, JS_ErrorTerminated);
1631 bnet_suppress_error_messages(sd, 1);
1632 bget_msg(sd); /* Read final response from append_data */
1633 Dmsg0(110, "Error in blast_data.\n");
1635 set_jcr_job_status(jcr, JS_Terminated);
1636 /* Note, the above set status will not override an error */
1637 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1638 bnet_suppress_error_messages(sd, 1);
1639 goto cleanup; /* bail out now */
1642 * Expect to get response to append_data from Storage daemon
1644 if (!response(jcr, sd, OK_append, "Append Data")) {
1645 set_jcr_job_status(jcr, JS_ErrorTerminated);
1650 * Send Append End Data to Storage daemon
1652 sd->fsend(append_end, jcr->Ticket);
1654 if (!response(jcr, sd, OK_end, "Append End")) {
1655 set_jcr_job_status(jcr, JS_ErrorTerminated);
1660 * Send Append Close to Storage daemon
1662 sd->fsend(append_close, jcr->Ticket);
1663 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1664 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1666 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1670 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1673 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1674 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1680 #if defined(WIN32_VSS)
1681 /* STOP VSS ON WIN32 */
1682 /* tell vss to close the backup session */
1684 if (g_pVSSClient->CloseBackup()) {
1685 /* inform user about writer states */
1686 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1687 int msg_type = M_INFO;
1688 if (g_pVSSClient->GetWriterState(i) < 1) {
1689 msg_type = M_WARNING;
1692 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1695 Win32ConvCleanupCache();
1700 generate_plugin_event(jcr, bEventEndBackupJob);
1701 return 0; /* return and stop command loop */
1705 * Do a Verify for Director
1708 static int verify_cmd(JCR *jcr)
1710 BSOCK *dir = jcr->dir_bsock;
1711 BSOCK *sd = jcr->store_bsock;
1714 jcr->set_JobType(JT_VERIFY);
1715 if (sscanf(dir->msg, verifycmd, level) != 1) {
1716 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1720 if (strcasecmp(level, "init") == 0) {
1721 jcr->set_JobLevel(L_VERIFY_INIT);
1722 } else if (strcasecmp(level, "catalog") == 0){
1723 jcr->set_JobLevel(L_VERIFY_CATALOG);
1724 } else if (strcasecmp(level, "volume") == 0){
1725 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1726 } else if (strcasecmp(level, "data") == 0){
1727 jcr->set_JobLevel(L_VERIFY_DATA);
1728 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1729 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1731 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1735 dir->fsend(OKverify);
1737 generate_daemon_event(jcr, "JobStart");
1738 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1739 generate_plugin_event(jcr, bEventStartVerifyJob);
1741 Dmsg1(110, "filed>dird: %s", dir->msg);
1743 switch (jcr->getJobLevel()) {
1745 case L_VERIFY_CATALOG:
1748 case L_VERIFY_VOLUME_TO_CATALOG:
1749 if (!open_sd_read_session(jcr)) {
1752 start_dir_heartbeat(jcr);
1753 do_verify_volume(jcr);
1754 stop_dir_heartbeat(jcr);
1756 * Send Close session command to Storage daemon
1758 sd->fsend(read_close, jcr->Ticket);
1759 Dmsg1(130, "filed>stored: %s", sd->msg);
1761 /* ****FIXME**** check response */
1762 bget_msg(sd); /* get OK */
1764 /* Inform Storage daemon that we are done */
1765 sd->signal(BNET_TERMINATE);
1768 case L_VERIFY_DISK_TO_CATALOG:
1772 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1776 dir->signal(BNET_EOD);
1777 generate_plugin_event(jcr, bEventEndVerifyJob);
1778 return 0; /* return and terminate command loop */
1782 * Do a Restore for Director
1785 static int restore_cmd(JCR *jcr)
1787 BSOCK *dir = jcr->dir_bsock;
1788 BSOCK *sd = jcr->store_bsock;
1790 bool use_regexwhere=false;
1795 * Scan WHERE (base directory for restore) from command
1797 Dmsg0(150, "restore command\n");
1798 /* Pickup where string */
1799 args = get_memory(dir->msglen+1);
1802 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1803 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1804 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1805 pm_strcpy(jcr->errmsg, dir->msg);
1806 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1811 use_regexwhere = true;
1813 /* Turn / into nothing */
1814 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1818 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1819 unbash_spaces(args);
1821 if (use_regexwhere) {
1822 jcr->where_bregexp = get_bregexps(args);
1823 if (!jcr->where_bregexp) {
1824 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1825 free_pool_memory(args);
1829 jcr->where = bstrdup(args);
1832 free_pool_memory(args);
1833 jcr->replace = replace;
1834 jcr->prefix_links = prefix_links;
1836 dir->fsend(OKrestore);
1837 Dmsg1(110, "filed>dird: %s", dir->msg);
1839 jcr->set_JobType(JT_RESTORE);
1841 set_jcr_job_status(jcr, JS_Blocked);
1843 if (!open_sd_read_session(jcr)) {
1844 set_jcr_job_status(jcr, JS_ErrorTerminated);
1848 set_jcr_job_status(jcr, JS_Running);
1851 * Do restore of files and data
1853 start_dir_heartbeat(jcr);
1854 generate_daemon_event(jcr, "JobStart");
1855 generate_plugin_event(jcr, bEventStartRestoreJob);
1857 stop_dir_heartbeat(jcr);
1859 set_jcr_job_status(jcr, JS_Terminated);
1860 if (jcr->JobStatus != JS_Terminated) {
1861 bnet_suppress_error_messages(sd, 1);
1865 * Send Close session command to Storage daemon
1867 sd->fsend(read_close, jcr->Ticket);
1868 Dmsg1(130, "filed>stored: %s", sd->msg);
1870 bget_msg(sd); /* get OK */
1872 /* Inform Storage daemon that we are done */
1873 sd->signal(BNET_TERMINATE);
1876 bfree_and_null(jcr->where);
1878 if (jcr->JobErrors) {
1879 set_jcr_job_status(jcr, JS_ErrorTerminated);
1882 Dmsg0(130, "Done in job.c\n");
1885 if (jcr->multi_restore) {
1886 dir->fsend(OKstoreend);
1887 ret = 1; /* we continue the loop, waiting for next part */
1889 end_restore_cmd(jcr);
1890 ret = 0; /* we stop here */
1896 static int end_restore_cmd(JCR *jcr)
1898 Dmsg0(5, "end_restore_cmd\n");
1899 generate_plugin_event(jcr, bEventEndRestoreJob);
1900 return 0; /* return and terminate command loop */
1903 static int open_sd_read_session(JCR *jcr)
1905 BSOCK *sd = jcr->store_bsock;
1908 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1911 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1912 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1913 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1915 * Open Read Session with Storage daemon
1917 sd->fsend(read_open, "DummyVolume",
1918 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1919 jcr->StartBlock, jcr->EndBlock);
1920 Dmsg1(110, ">stored: %s", sd->msg);
1925 if (bget_msg(sd) >= 0) {
1926 Dmsg1(110, "filed<stored: %s", sd->msg);
1927 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1928 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1931 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1933 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1937 if (!send_bootstrap_file(jcr)) {
1942 * Start read of data with Storage daemon
1944 sd->fsend(read_data, jcr->Ticket);
1945 Dmsg1(110, ">stored: %s", sd->msg);
1950 if (!response(jcr, sd, OK_data, "Read Data")) {
1957 * Destroy the Job Control Record and associated
1958 * resources (sockets).
1960 static void filed_free_jcr(JCR *jcr)
1962 if (jcr->store_bsock) {
1963 jcr->store_bsock->close();
1965 free_bootstrap(jcr);
1966 if (jcr->last_fname) {
1967 free_pool_memory(jcr->last_fname);
1969 free_runscripts(jcr->RunScripts);
1970 delete jcr->RunScripts;
1972 if (jcr->JobId != 0)
1973 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1979 * Get response from Storage daemon to a command we
1980 * sent. Check that the response is OK.
1982 * Returns: 0 on failure
1985 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1990 if (bget_msg(sd) > 0) {
1991 Dmsg0(110, sd->msg);
1992 if (strcmp(sd->msg, resp) == 0) {
1996 if (job_canceled(jcr)) {
1997 return 0; /* if canceled avoid useless error messages */
1999 if (is_bnet_error(sd)) {
2000 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2001 cmd, bnet_strerror(sd));
2003 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2004 cmd, resp, sd->msg);
2009 static int send_bootstrap_file(JCR *jcr)
2013 BSOCK *sd = jcr->store_bsock;
2014 const char *bootstrap = "bootstrap\n";
2017 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2018 if (!jcr->RestoreBootstrap) {
2021 bs = fopen(jcr->RestoreBootstrap, "rb");
2024 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2025 jcr->RestoreBootstrap, be.bstrerror());
2026 set_jcr_job_status(jcr, JS_ErrorTerminated);
2029 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2031 while (fgets(buf, sizeof(buf), bs)) {
2032 sd->msglen = Mmsg(sd->msg, "%s", buf);
2035 sd->signal(BNET_EOD);
2037 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2038 set_jcr_job_status(jcr, JS_ErrorTerminated);
2044 free_bootstrap(jcr);