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);
94 static int exit_cmd(JCR *jcr);
96 /* Exported functions */
101 int monitoraccess; /* specify if monitors have access to this function */
105 * The following are the recognized commands from the Director.
107 static struct s_cmds cmds[] = {
108 {"backup", backup_cmd, 0},
109 {"cancel", cancel_cmd, 0},
110 {"setdebug=", setdebug_cmd, 0},
111 {"estimate", estimate_cmd, 0},
112 {"Hello", hello_cmd, 1},
113 {"fileset", fileset_cmd, 0},
114 {"JobId=", job_cmd, 0},
115 {"level = ", level_cmd, 0},
116 {"restore", restore_cmd, 0},
117 {"endrestore", end_restore_cmd, 0},
118 {"session", session_cmd, 0},
119 {"status", status_cmd, 1},
120 {".status", qstatus_cmd, 1},
121 {"storage ", storage_cmd, 0},
122 {"verify", verify_cmd, 0},
123 {"bootstrap", bootstrap_cmd, 0},
124 {"RunBeforeNow", runbeforenow_cmd, 0},
125 {"RunBeforeJob", runbefore_cmd, 0},
126 {"RunAfterJob", runafter_cmd, 0},
127 {"Run", runscript_cmd, 0},
128 {"accurate", accurate_cmd, 0},
129 {"restoreobject", restore_object_cmd, 0},
130 {"sm_dump", sm_dump_cmd, 0},
132 {"exit", exit_cmd, 0},
134 {NULL, NULL} /* list terminator */
137 /* Commands received from director that need scanning */
138 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
139 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
140 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
141 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
142 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
143 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
144 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
145 static char verifycmd[] = "verify level=%30s";
146 static char estimatecmd[] = "estimate listing=%d";
147 static char runbefore[] = "RunBeforeJob %s";
148 static char runafter[] = "RunAfterJob %s";
149 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
151 /* Responses sent to Director */
152 static char errmsg[] = "2999 Invalid command\n";
153 static char no_auth[] = "2998 No Authorization\n";
154 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
155 static char OKinc[] = "2000 OK include\n";
156 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
157 static char OKlevel[] = "2000 OK level\n";
158 static char OKbackup[] = "2000 OK backup\n";
159 static char OKbootstrap[] = "2000 OK bootstrap\n";
160 static char OKverify[] = "2000 OK verify\n";
161 static char OKrestore[] = "2000 OK restore\n";
162 static char OKsession[] = "2000 OK session\n";
163 static char OKstore[] = "2000 OK storage\n";
164 static char OKstoreend[] = "2000 OK storage end\n";
165 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
166 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
167 static char BADjob[] = "2901 Bad Job\n";
168 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
169 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
170 static char OKRunBefore[] = "2000 OK RunBefore\n";
171 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
172 static char OKRunAfter[] = "2000 OK RunAfter\n";
173 static char OKRunScript[] = "2000 OK RunScript\n";
174 static char BADcmd[] = "2902 Bad %s\n";
177 /* Responses received from Storage Daemon */
178 static char OK_end[] = "3000 OK end\n";
179 static char OK_close[] = "3000 OK close Status = %d\n";
180 static char OK_open[] = "3000 OK open ticket = %d\n";
181 static char OK_data[] = "3000 OK data\n";
182 static char OK_append[] = "3000 OK append data\n";
183 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
186 /* Commands sent to Storage Daemon */
187 static char append_open[] = "append open session\n";
188 static char append_data[] = "append data %d\n";
189 static char append_end[] = "append end session %d\n";
190 static char append_close[] = "append close session %d\n";
191 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
192 static char read_data[] = "read data %d\n";
193 static char read_close[] = "read close session %d\n";
196 * Accept requests from a Director
198 * NOTE! We are running as a separate thread
200 * Send output one line
201 * at a time followed by a zero length transmission.
203 * Return when the connection is terminated or there
206 * Basic task here is:
207 * Authenticate Director (during Hello command).
208 * Accept commands one at a time from the Director
211 * Concerning ClientRunBefore/After, the sequence of events
212 * is rather critical. If they are not done in the right
213 * order one can easily get FD->SD timeouts if the script
216 * The current sequence of events is:
217 * 1. Dir starts job with FD
218 * 2. Dir connects to SD
219 * 3. Dir connects to FD
220 * 4. FD connects to SD
221 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
222 * 6. Dir sends include/exclude
223 * 7. FD sends data to SD
224 * 8. SD/FD disconnects while SD despools data and attributes (optional)
225 * 9. FD runs ClientRunAfterJob
228 void *handle_client_request(void *dirp)
233 BSOCK *dir = (BSOCK *)dirp;
234 const char jobname[12] = "*Director*";
236 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
237 jcr->dir_bsock = dir;
238 jcr->ff = init_find_files();
239 jcr->start_time = time(NULL);
240 jcr->RunScripts = New(alist(10, not_owned_by_alist));
241 jcr->last_fname = get_pool_memory(PM_FNAME);
242 jcr->last_fname[0] = 0;
243 jcr->client_name = get_memory(strlen(my_name) + 1);
244 pm_strcpy(jcr->client_name, my_name);
245 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
246 jcr->crypto.pki_sign = me->pki_sign;
247 jcr->crypto.pki_encrypt = me->pki_encrypt;
248 jcr->crypto.pki_keypair = me->pki_keypair;
249 jcr->crypto.pki_signers = me->pki_signers;
250 jcr->crypto.pki_recipients = me->pki_recipients;
252 enable_backup_privileges(NULL, 1 /* ignore_errors */);
254 /**********FIXME******* add command handler error code */
256 for (quit=false; !quit;) {
258 if (dir->recv() < 0) {
259 break; /* connection terminated */
261 dir->msg[dir->msglen] = 0;
262 Dmsg1(100, "<dird: %s", dir->msg);
264 for (i=0; cmds[i].cmd; i++) {
265 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
266 found = true; /* indicate command found */
267 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
269 dir->signal(BNET_EOD);
272 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
273 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
274 dir->fsend(invalid_cmd);
275 dir->signal(BNET_EOD);
278 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
279 if (!cmds[i].func(jcr)) { /* do command */
280 quit = true; /* error or fully terminated, get out */
281 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
286 if (!found) { /* command not found */
293 /* Inform Storage daemon that we are done */
294 if (jcr->store_bsock) {
295 jcr->store_bsock->signal(BNET_TERMINATE);
298 /* Run the after job */
299 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
301 if (jcr->JobId) { /* send EndJob if running a job */
302 char ed1[50], ed2[50];
303 /* Send termination status back to Dir */
304 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
305 edit_uint64(jcr->ReadBytes, ed1),
306 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
307 jcr->crypto.pki_encrypt);
308 Dmsg1(110, "End FD msg: %s\n", dir->msg);
311 generate_daemon_event(jcr, "JobEnd");
312 generate_plugin_event(jcr, bEventJobEnd);
314 dequeue_messages(jcr); /* send any queued messages */
316 /* Inform Director that we are done */
317 dir->signal(BNET_TERMINATE);
319 free_plugins(jcr); /* release instantiated plugins */
321 /* Clean up fileset */
322 FF_PKT *ff = jcr->ff;
323 findFILESET *fileset = ff->fileset;
326 /* Delete FileSet Include lists */
327 for (i=0; i<fileset->include_list.size(); i++) {
328 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
329 for (j=0; j<incexe->opts_list.size(); j++) {
330 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
331 for (k=0; k<fo->regex.size(); k++) {
332 regfree((regex_t *)fo->regex.get(k));
334 for (k=0; k<fo->regexdir.size(); k++) {
335 regfree((regex_t *)fo->regexdir.get(k));
337 for (k=0; k<fo->regexfile.size(); k++) {
338 regfree((regex_t *)fo->regexfile.get(k));
341 fo->regexdir.destroy();
342 fo->regexfile.destroy();
344 fo->wilddir.destroy();
345 fo->wildfile.destroy();
346 fo->wildbase.destroy();
348 fo->fstype.destroy();
349 fo->drivetype.destroy();
351 incexe->opts_list.destroy();
352 incexe->name_list.destroy();
353 incexe->plugin_list.destroy();
354 if (incexe->ignoredir) {
355 free(incexe->ignoredir);
358 fileset->include_list.destroy();
360 /* Delete FileSet Exclude lists */
361 for (i=0; i<fileset->exclude_list.size(); i++) {
362 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
363 for (j=0; j<incexe->opts_list.size(); j++) {
364 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
366 fo->regexdir.destroy();
367 fo->regexfile.destroy();
369 fo->wilddir.destroy();
370 fo->wildfile.destroy();
371 fo->wildbase.destroy();
373 fo->fstype.destroy();
374 fo->drivetype.destroy();
376 incexe->opts_list.destroy();
377 incexe->name_list.destroy();
378 incexe->plugin_list.destroy();
379 if (incexe->ignoredir) {
380 free(incexe->ignoredir);
383 fileset->exclude_list.destroy();
387 Dmsg0(100, "Calling term_find_files\n");
388 term_find_files(jcr->ff);
390 Dmsg0(100, "Done with term_find_files\n");
391 free_jcr(jcr); /* destroy JCR record */
392 Dmsg0(100, "Done with free_jcr\n");
397 static int sm_dump_cmd(JCR *jcr)
399 sm_dump(false, true);
400 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
405 static int exit_cmd(JCR *jcr)
407 jcr->dir_bsock->fsend("2000 exit OK\n");
415 * Hello from Director he must identify himself and provide his
418 static int hello_cmd(JCR *jcr)
420 Dmsg0(120, "Calling Authenticate\n");
421 if (!authenticate_director(jcr)) {
424 Dmsg0(120, "OK Authenticate\n");
425 jcr->authenticated = true;
432 static int cancel_cmd(JCR *jcr)
434 BSOCK *dir = jcr->dir_bsock;
435 char Job[MAX_NAME_LENGTH];
438 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
439 if (!(cjcr=get_jcr_by_full_name(Job))) {
440 dir->fsend(_("2901 Job %s not found.\n"), Job);
442 if (cjcr->store_bsock) {
443 cjcr->store_bsock->set_timed_out();
444 cjcr->store_bsock->set_terminated();
445 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
447 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
448 set_jcr_job_status(cjcr, JS_Canceled);
450 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
453 dir->fsend(_("2902 Error scanning cancel command.\n"));
455 dir->signal(BNET_EOD);
461 * Set debug level as requested by the Director
464 static int setdebug_cmd(JCR *jcr)
466 BSOCK *dir = jcr->dir_bsock;
467 int level, trace_flag;
469 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
470 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
471 pm_strcpy(jcr->errmsg, dir->msg);
472 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
476 set_trace(trace_flag);
477 return dir->fsend(OKsetdebug, level);
481 static int estimate_cmd(JCR *jcr)
483 BSOCK *dir = jcr->dir_bsock;
484 char ed1[50], ed2[50];
486 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
487 pm_strcpy(jcr->errmsg, dir->msg);
488 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
489 dir->fsend(_("2992 Bad estimate command.\n"));
493 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
494 edit_uint64_with_commas(jcr->JobBytes, ed2));
495 dir->signal(BNET_EOD);
500 * Get JobId and Storage Daemon Authorization key from Director
502 static int job_cmd(JCR *jcr)
504 BSOCK *dir = jcr->dir_bsock;
505 POOL_MEM sd_auth_key(PM_MESSAGE);
506 sd_auth_key.check_size(dir->msglen);
508 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
509 &jcr->VolSessionId, &jcr->VolSessionTime,
510 sd_auth_key.c_str()) != 5) {
511 pm_strcpy(jcr->errmsg, dir->msg);
512 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
516 set_storage_auth_key(jcr, sd_auth_key.c_str());
517 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
518 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
519 new_plugins(jcr); /* instantiate plugins for this jcr */
520 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
521 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
524 static int runbefore_cmd(JCR *jcr)
527 BSOCK *dir = jcr->dir_bsock;
528 POOLMEM *cmd = get_memory(dir->msglen+1);
531 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
532 if (sscanf(dir->msg, runbefore, cmd) != 1) {
533 pm_strcpy(jcr->errmsg, dir->msg);
534 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
535 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
541 /* Run the command now */
542 script = new_runscript();
543 script->set_command(cmd);
544 script->when = SCRIPT_Before;
545 ok = script->run(jcr, "ClientRunBeforeJob");
546 free_runscript(script);
550 dir->fsend(OKRunBefore);
553 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
558 static int runbeforenow_cmd(JCR *jcr)
560 BSOCK *dir = jcr->dir_bsock;
562 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
563 if (job_canceled(jcr)) {
564 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
565 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
568 dir->fsend(OKRunBeforeNow);
569 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
574 static int runafter_cmd(JCR *jcr)
576 BSOCK *dir = jcr->dir_bsock;
577 POOLMEM *msg = get_memory(dir->msglen+1);
580 Dmsg1(100, "runafter_cmd: %s", dir->msg);
581 if (sscanf(dir->msg, runafter, msg) != 1) {
582 pm_strcpy(jcr->errmsg, dir->msg);
583 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
584 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
590 cmd = new_runscript();
591 cmd->set_command(msg);
592 cmd->on_success = true;
593 cmd->on_failure = false;
594 cmd->when = SCRIPT_After;
596 jcr->RunScripts->append(cmd);
598 free_pool_memory(msg);
599 return dir->fsend(OKRunAfter);
602 static int runscript_cmd(JCR *jcr)
604 BSOCK *dir = jcr->dir_bsock;
605 POOLMEM *msg = get_memory(dir->msglen+1);
606 int on_success, on_failure, fail_on_error;
608 RUNSCRIPT *cmd = new_runscript() ;
610 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
611 /* Note, we cannot sscanf into bools */
612 if (sscanf(dir->msg, runscript, &on_success,
617 pm_strcpy(jcr->errmsg, dir->msg);
618 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
619 dir->fsend(_("2905 Bad RunScript command.\n"));
624 cmd->on_success = on_success;
625 cmd->on_failure = on_failure;
626 cmd->fail_on_error = fail_on_error;
629 cmd->set_command(msg);
631 jcr->RunScripts->append(cmd);
633 free_pool_memory(msg);
634 return dir->fsend(OKRunScript);
638 static bool init_fileset(JCR *jcr)
641 findFILESET *fileset;
650 fileset = (findFILESET *)malloc(sizeof(findFILESET));
651 memset(fileset, 0, sizeof(findFILESET));
652 ff->fileset = fileset;
653 fileset->state = state_none;
654 fileset->include_list.init(1, true);
655 fileset->exclude_list.init(1, true);
659 static findFOPTS *start_options(FF_PKT *ff)
661 int state = ff->fileset->state;
662 findINCEXE *incexe = ff->fileset->incexe;
664 if (state != state_options) {
665 ff->fileset->state = state_options;
666 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
667 memset(fo, 0, sizeof(findFOPTS));
668 fo->regex.init(1, true);
669 fo->regexdir.init(1, true);
670 fo->regexfile.init(1, true);
671 fo->wild.init(1, true);
672 fo->wilddir.init(1, true);
673 fo->wildfile.init(1, true);
674 fo->wildbase.init(1, true);
675 fo->base.init(1, true);
676 fo->fstype.init(1, true);
677 fo->drivetype.init(1, true);
678 incexe->current_opts = fo;
679 incexe->opts_list.append(fo);
681 return incexe->current_opts;
686 * Add fname to include/exclude fileset list. First check for
687 * | and < and if necessary perform command.
689 void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
704 p++; /* skip over | */
705 fn = get_pool_memory(PM_FNAME);
706 fn = edit_job_codes(jcr, fn, p, "");
707 bpipe = open_bpipe(fn, 0, "r");
710 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
712 free_pool_memory(fn);
715 free_pool_memory(fn);
716 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
717 strip_trailing_junk(buf);
719 fileset->incexe->name_list.append(new_dlistString(buf));
721 fileset->incexe->plugin_list.append(new_dlistString(buf));
724 if ((stat=close_bpipe(bpipe)) != 0) {
726 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
727 p, be.code(stat), be.bstrerror(stat));
732 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
733 p++; /* skip over < */
734 if ((ffd = fopen(p, "rb")) == NULL) {
736 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
740 while (fgets(buf, sizeof(buf), ffd)) {
741 strip_trailing_junk(buf);
742 Dmsg1(100, "%s\n", buf);
744 fileset->incexe->name_list.append(new_dlistString(buf));
746 fileset->incexe->plugin_list.append(new_dlistString(buf));
753 fileset->incexe->name_list.append(new_dlistString(fname));
755 if (me->plugin_directory) {
756 fileset->incexe->plugin_list.append(new_dlistString(fname));
758 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
766 findFILESET *new_exclude(JCR *jcr)
768 FF_PKT *ff = jcr->ff;
769 findFILESET *fileset = ff->fileset;
772 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
773 memset(fileset->incexe, 0, sizeof(findINCEXE));
774 fileset->incexe->opts_list.init(1, true);
775 fileset->incexe->name_list.init();
776 fileset->incexe->plugin_list.init();
777 fileset->exclude_list.append(fileset->incexe);
782 static void add_fileset(JCR *jcr, const char *item)
784 FF_PKT *ff = jcr->ff;
785 findFILESET *fileset = ff->fileset;
786 int state = fileset->state;
787 findFOPTS *current_opts;
789 /* Get code, optional subcode, and position item past the dividing space */
790 Dmsg1(100, "%s\n", item);
795 int subcode = ' '; /* A space is always a valid subcode */
796 if (item[0] != '\0' && item[0] != ' ') {
804 /* Skip all lines we receive after an error */
805 if (state == state_error) {
806 Dmsg0(100, "State=error return\n");
811 * The switch tests the code for validity.
812 * The subcode is always good if it is a space, otherwise we must confirm.
813 * We set state to state_error first assuming the subcode is invalid,
814 * requiring state to be set in cases below that handle subcodes.
816 if (subcode != ' ') {
818 Dmsg0(100, "Set state=error or double code.\n");
823 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
824 memset(fileset->incexe, 0, sizeof(findINCEXE));
825 fileset->incexe->opts_list.init(1, true);
826 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
827 fileset->incexe->plugin_list.init();
828 fileset->include_list.append(fileset->incexe);
831 fileset = new_exclude(jcr);
837 /* File item to include or exclude list */
838 state = state_include;
839 add_file_to_fileset(jcr, item, fileset, true);
842 /* Plugin item to include list */
843 state = state_include;
844 add_file_to_fileset(jcr, item, fileset, false);
847 current_opts = start_options(ff);
851 preg = (regex_t *)malloc(sizeof(regex_t));
852 if (current_opts->flags & FO_IGNORECASE) {
853 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
855 rc = regcomp(preg, item, REG_EXTENDED);
858 regerror(rc, preg, prbuf, sizeof(prbuf));
861 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
865 state = state_options;
866 if (subcode == ' ') {
867 current_opts->regex.append(preg);
868 } else if (subcode == 'D') {
869 current_opts->regexdir.append(preg);
870 } else if (subcode == 'F') {
871 current_opts->regexfile.append(preg);
877 current_opts = start_options(ff);
878 current_opts->base.append(bstrdup(item));
879 state = state_options;
882 current_opts = start_options(ff);
883 state = state_options;
884 if (subcode == ' ') {
885 current_opts->fstype.append(bstrdup(item));
886 } else if (subcode == 'D') {
887 current_opts->drivetype.append(bstrdup(item));
893 current_opts = start_options(ff);
894 state = state_options;
895 if (subcode == ' ') {
896 current_opts->wild.append(bstrdup(item));
897 } else if (subcode == 'D') {
898 current_opts->wilddir.append(bstrdup(item));
899 } else if (subcode == 'F') {
900 current_opts->wildfile.append(bstrdup(item));
901 } else if (subcode == 'B') {
902 current_opts->wildbase.append(bstrdup(item));
908 current_opts = start_options(ff);
909 set_options(current_opts, item);
910 state = state_options;
913 state = state_include;
914 fileset->incexe->ignoredir = bstrdup(item);
917 current_opts = start_options(ff);
918 // current_opts->reader = bstrdup(item);
919 state = state_options;
922 current_opts = start_options(ff);
923 // current_opts->writer = bstrdup(item);
924 state = state_options;
927 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
931 ff->fileset->state = state;
934 static bool term_fileset(JCR *jcr)
936 FF_PKT *ff = jcr->ff;
938 #ifdef xxx_DEBUG_CODE
939 findFILESET *fileset = ff->fileset;
942 for (i=0; i<fileset->include_list.size(); i++) {
943 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
945 for (j=0; j<incexe->opts_list.size(); j++) {
946 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
947 for (k=0; k<fo->regex.size(); k++) {
948 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
950 for (k=0; k<fo->regexdir.size(); k++) {
951 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
953 for (k=0; k<fo->regexfile.size(); k++) {
954 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
956 for (k=0; k<fo->wild.size(); k++) {
957 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
959 for (k=0; k<fo->wilddir.size(); k++) {
960 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
962 for (k=0; k<fo->wildfile.size(); k++) {
963 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
965 for (k=0; k<fo->wildbase.size(); k++) {
966 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
968 for (k=0; k<fo->base.size(); k++) {
969 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
971 for (k=0; k<fo->fstype.size(); k++) {
972 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
974 for (k=0; k<fo->drivetype.size(); k++) {
975 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
978 if (incexe->ignoredir) {
979 Dmsg1(400, "Z %s\n", incexe->ignoredir);
982 foreach_dlist(node, &incexe->name_list) {
983 Dmsg1(400, "F %s\n", node->c_str());
985 foreach_dlist(node, &incexe->plugin_list) {
986 Dmsg1(400, "P %s\n", node->c_str());
989 for (i=0; i<fileset->exclude_list.size(); i++) {
990 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
992 for (j=0; j<incexe->opts_list.size(); j++) {
993 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
994 for (k=0; k<fo->regex.size(); k++) {
995 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
997 for (k=0; k<fo->regexdir.size(); k++) {
998 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1000 for (k=0; k<fo->regexfile.size(); k++) {
1001 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1003 for (k=0; k<fo->wild.size(); k++) {
1004 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1006 for (k=0; k<fo->wilddir.size(); k++) {
1007 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1009 for (k=0; k<fo->wildfile.size(); k++) {
1010 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1012 for (k=0; k<fo->wildbase.size(); k++) {
1013 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1015 for (k=0; k<fo->base.size(); k++) {
1016 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1018 for (k=0; k<fo->fstype.size(); k++) {
1019 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1021 for (k=0; k<fo->drivetype.size(); k++) {
1022 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1026 foreach_dlist(node, incexe->name_list) {
1027 Dmsg1(400, "F %s\n", node->c_str());
1029 foreach_dlist(node, &incexe->plugin_list) {
1030 Dmsg1(400, "P %s\n", node->c_str());
1034 return ff->fileset->state != state_error;
1039 * As an optimization, we should do this during
1040 * "compile" time in filed/job.c, and keep only a bit mask
1041 * and the Verify options.
1043 static void set_options(findFOPTS *fo, const char *opts)
1049 // Commented out as it is not backward compatible - KES
1051 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1054 for (p=opts; *p; p++) {
1056 case 'a': /* alway replace */
1057 case '0': /* no option */
1060 fo->flags |= FO_EXCLUDE;
1063 fo->flags |= FO_MULTIFS;
1065 case 'h': /* no recursion */
1066 fo->flags |= FO_NO_RECURSION;
1068 case 'H': /* no hard link handling */
1069 fo->flags |= FO_NO_HARDLINK;
1072 fo->flags |= FO_IGNORECASE;
1075 fo->flags |= FO_MD5;
1078 fo->flags |= FO_NOREPLACE;
1080 case 'p': /* use portable data format */
1081 fo->flags |= FO_PORTABLE;
1083 case 'R': /* Resource forks and Finder Info */
1084 fo->flags |= FO_HFSPLUS;
1085 case 'r': /* read fifo */
1086 fo->flags |= FO_READFIFO;
1091 fo->flags |= FO_SHA1;
1096 fo->flags |= FO_SHA256;
1100 fo->flags |= FO_SHA512;
1106 * If 2 or 3 is seen here, SHA2 is not configured, so
1107 * eat the option, and drop back to SHA-1.
1109 if (p[1] == '2' || p[1] == '3') {
1112 fo->flags |= FO_SHA1;
1117 fo->flags |= FO_SPARSE;
1120 fo->flags |= FO_MTIMEONLY;
1123 fo->flags |= FO_KEEPATIME;
1126 fo->flags |= FO_ACL;
1128 case 'V': /* verify options */
1129 /* Copy Verify Options */
1130 for (j=0; *p && *p != ':'; p++) {
1131 fo->VerifyOpts[j] = *p;
1132 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1136 fo->VerifyOpts[j] = 0;
1138 case 'C': /* accurate options */
1139 /* Copy Accurate Options */
1140 for (j=0; *p && *p != ':'; p++) {
1141 fo->AccurateOpts[j] = *p;
1142 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1146 fo->AccurateOpts[j] = 0;
1148 case 'J': /* Basejob options */
1149 /* Copy BaseJob Options */
1150 for (j=0; *p && *p != ':'; p++) {
1151 fo->BaseJobOpts[j] = *p;
1152 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1156 fo->BaseJobOpts[j] = 0;
1158 case 'P': /* strip path */
1161 for (j=0; *p && *p != ':'; p++) {
1163 if (j < (int)sizeof(strip) - 1) {
1168 fo->strip_path = atoi(strip);
1169 fo->flags |= FO_STRIPPATH;
1170 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1173 fo->flags |= FO_IF_NEWER;
1176 fo->flags |= FO_ENHANCEDWILD;
1178 case 'Z': /* gzip compression */
1179 fo->flags |= FO_GZIP;
1180 fo->GZIP_level = *++p - '0';
1183 fo->flags |= FO_NOATIME;
1186 fo->flags |= FO_CHKCHANGES;
1189 fo->flags |= FO_HONOR_NODUMP;
1192 fo->flags |= FO_XATTR;
1195 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1203 * Director is passing his Fileset
1205 static int fileset_cmd(JCR *jcr)
1207 BSOCK *dir = jcr->dir_bsock;
1209 #if defined(WIN32_VSS)
1212 sscanf(dir->msg, "fileset vss=%d", &vss);
1216 if (!init_fileset(jcr)) {
1219 while (dir->recv() >= 0) {
1220 strip_trailing_junk(dir->msg);
1221 Dmsg1(500, "Fileset: %s\n", dir->msg);
1222 add_fileset(jcr, dir->msg);
1224 if (!term_fileset(jcr)) {
1227 return dir->fsend(OKinc);
1230 static void free_bootstrap(JCR *jcr)
1232 if (jcr->RestoreBootstrap) {
1233 unlink(jcr->RestoreBootstrap);
1234 free_pool_memory(jcr->RestoreBootstrap);
1235 jcr->RestoreBootstrap = NULL;
1240 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1241 static uint32_t bsr_uniq = 0;
1244 * The Director sends us the bootstrap file, which
1245 * we will in turn pass to the SD.
1247 static int bootstrap_cmd(JCR *jcr)
1249 BSOCK *dir = jcr->dir_bsock;
1250 POOLMEM *fname = get_pool_memory(PM_FNAME);
1253 free_bootstrap(jcr);
1256 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1257 jcr->Job, bsr_uniq);
1259 Dmsg1(400, "bootstrap=%s\n", fname);
1260 jcr->RestoreBootstrap = fname;
1261 bs = fopen(fname, "a+b"); /* create file */
1264 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1265 jcr->RestoreBootstrap, be.bstrerror());
1267 * Suck up what he is sending to us so that he will then
1268 * read our error message.
1270 while (dir->recv() >= 0)
1272 free_bootstrap(jcr);
1273 set_jcr_job_status(jcr, JS_ErrorTerminated);
1277 while (dir->recv() >= 0) {
1278 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1279 fputs(dir->msg, bs);
1283 * Note, do not free the bootstrap yet -- it needs to be
1286 return dir->fsend(OKbootstrap);
1291 * Get backup level from Director
1294 static int level_cmd(JCR *jcr)
1296 BSOCK *dir = jcr->dir_bsock;
1297 POOLMEM *level, *buf = NULL;
1300 level = get_memory(dir->msglen+1);
1301 Dmsg1(100, "level_cmd: %s", dir->msg);
1303 /* keep compatibility with older directors */
1304 if (strstr(dir->msg, "accurate")) {
1305 jcr->accurate = true;
1307 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1310 /* Base backup requested? */
1311 if (strcmp(level, "base") == 0) {
1312 jcr->set_JobLevel(L_BASE);
1313 /* Full backup requested? */
1314 } else if (strcmp(level, "full") == 0) {
1315 jcr->set_JobLevel(L_FULL);
1316 } else if (strstr(level, "differential")) {
1317 jcr->set_JobLevel(L_DIFFERENTIAL);
1320 } else if (strstr(level, "incremental")) {
1321 jcr->set_JobLevel(L_INCREMENTAL);
1325 * We get his UTC since time, then sync the clocks and correct it
1326 * to agree with our clock.
1328 } else if (strcmp(level, "since_utime") == 0) {
1329 buf = get_memory(dir->msglen+1);
1330 utime_t since_time, adj;
1331 btime_t his_time, bt_start, rt=0, bt_adj=0;
1332 if (jcr->getJobLevel() == L_NONE) {
1333 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1335 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1336 buf, &mtime_only) != 2) {
1339 since_time = str_to_uint64(buf); /* this is the since time */
1340 Dmsg1(100, "since_time=%lld\n", since_time);
1341 char ed1[50], ed2[50];
1343 * Sync clocks by polling him for the time. We take
1344 * 10 samples of his time throwing out the first two.
1346 for (int i=0; i<10; i++) {
1347 bt_start = get_current_btime();
1348 dir->signal(BNET_BTIME); /* poll for time */
1349 if (dir->recv() <= 0) { /* get response */
1352 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1355 if (i < 2) { /* toss first two results */
1358 his_time = str_to_uint64(buf);
1359 rt = get_current_btime() - bt_start; /* compute round trip time */
1360 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1361 edit_uint64(bt_start, ed2));
1362 bt_adj += bt_start - his_time - rt/2;
1363 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1366 bt_adj = bt_adj / 8; /* compute average time */
1367 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1368 adj = btime_to_utime(bt_adj);
1369 since_time += adj; /* adjust for clock difference */
1370 /* Don't notify if time within 3 seconds */
1371 if (adj > 3 || adj < -3) {
1373 if (adj > 600 || adj < -600) {
1378 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1380 dir->signal(BNET_EOD);
1382 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1383 jcr->incremental = 1; /* set incremental or decremental backup */
1384 jcr->mtime = since_time; /* set since time */
1385 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1387 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1395 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1396 return dir->fsend(OKlevel);
1399 pm_strcpy(jcr->errmsg, dir->msg);
1400 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1409 * Get session parameters from Director -- this is for a Restore command
1411 static int session_cmd(JCR *jcr)
1413 BSOCK *dir = jcr->dir_bsock;
1415 Dmsg1(100, "SessionCmd: %s", dir->msg);
1416 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1417 &jcr->VolSessionId, &jcr->VolSessionTime,
1418 &jcr->StartFile, &jcr->EndFile,
1419 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1420 pm_strcpy(jcr->errmsg, dir->msg);
1421 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1425 return dir->fsend(OKsession);
1428 static void set_storage_auth_key(JCR *jcr, char *key)
1430 /* if no key don't update anything */
1435 /* We can be contacting multiple storage daemons.
1436 * So, make sure that any old jcr->store_bsock is cleaned up.
1438 if (jcr->store_bsock) {
1439 jcr->store_bsock->destroy();
1440 jcr->store_bsock = NULL;
1443 /* We can be contacting multiple storage daemons.
1444 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1446 if (jcr->sd_auth_key) {
1447 /* If we already have a Authorization key, director can do multi
1450 Dmsg0(5, "set multi_restore=true\n");
1451 jcr->multi_restore = true;
1452 bfree(jcr->sd_auth_key);
1455 jcr->sd_auth_key = bstrdup(key);
1459 * Get address of storage daemon from Director
1462 static int storage_cmd(JCR *jcr)
1464 int stored_port; /* storage daemon port */
1465 int enable_ssl; /* enable ssl to sd */
1466 POOL_MEM sd_auth_key(PM_MESSAGE);
1467 BSOCK *dir = jcr->dir_bsock;
1468 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1471 Dmsg1(100, "StorageCmd: %s", dir->msg);
1472 sd_auth_key.check_size(dir->msglen);
1473 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1474 &enable_ssl, sd_auth_key.c_str()) != 4)
1476 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1477 &stored_port, &enable_ssl) != 3)
1479 pm_strcpy(jcr->errmsg, dir->msg);
1480 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1485 set_storage_auth_key(jcr, sd_auth_key.c_str());
1487 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1489 /* Open command communications with Storage daemon */
1490 /* Try to connect for 1 hour at 10 second intervals */
1492 sd->set_source_address(me->FDsrc_addr);
1493 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1494 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1500 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1501 jcr->stored_addr, stored_port);
1502 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1503 jcr->stored_addr, stored_port);
1506 Dmsg0(110, "Connection OK to SD.\n");
1508 jcr->store_bsock = sd;
1510 sd->fsend("Hello Start Job %s\n", jcr->Job);
1511 if (!authenticate_storagedaemon(jcr)) {
1512 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1515 Dmsg0(110, "Authenticated with SD.\n");
1517 /* Send OK to Director */
1518 return dir->fsend(OKstore);
1521 dir->fsend(BADcmd, "storage");
1530 static int backup_cmd(JCR *jcr)
1532 BSOCK *dir = jcr->dir_bsock;
1533 BSOCK *sd = jcr->store_bsock;
1537 #if defined(WIN32_VSS)
1538 // capture state here, if client is backed up by multiple directors
1539 // and one enables vss and the other does not then enable_vss can change
1540 // between here and where its evaluated after the job completes.
1541 jcr->VSS = g_pVSSClient && enable_vss;
1543 /* Run only one at a time */
1549 * Validate some options given to the backup make sense for the compiled in
1550 * options of this filed.
1552 if (jcr->ff->flags & FO_ACL && !have_acl) {
1553 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1556 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1557 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1561 set_jcr_job_status(jcr, JS_Blocked);
1562 jcr->set_JobType(JT_BACKUP);
1563 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1566 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1567 dir->fsend(BADcmd, "backup");
1571 dir->fsend(OKbackup);
1572 Dmsg1(110, "filed>dird: %s", dir->msg);
1575 * Send Append Open Session to Storage daemon
1577 sd->fsend(append_open);
1578 Dmsg1(110, ">stored: %s", sd->msg);
1580 * Expect to receive back the Ticket number
1582 if (bget_msg(sd) >= 0) {
1583 Dmsg1(110, "<stored: %s", sd->msg);
1584 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1585 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1588 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1590 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1595 * Send Append data command to Storage daemon
1597 sd->fsend(append_data, jcr->Ticket);
1598 Dmsg1(110, ">stored: %s", sd->msg);
1601 * Expect to get OK data
1603 Dmsg1(110, "<stored: %s", sd->msg);
1604 if (!response(jcr, sd, OK_data, "Append Data")) {
1608 generate_daemon_event(jcr, "JobStart");
1609 generate_plugin_event(jcr, bEventStartBackupJob);
1611 #if defined(WIN32_VSS)
1612 /* START VSS ON WIN32 */
1614 if (g_pVSSClient->InitializeForBackup()) {
1615 /* tell vss which drives to snapshot */
1616 char szWinDriveLetters[27];
1617 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1618 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1619 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1620 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1623 /* tell user if snapshot creation of a specific drive failed */
1625 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1626 if (islower(szWinDriveLetters[i])) {
1627 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1631 /* inform user about writer states */
1632 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1633 if (g_pVSSClient->GetWriterState(i) < 1) {
1634 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1639 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1643 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1645 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1650 * Send Files to Storage daemon
1652 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1653 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1654 set_jcr_job_status(jcr, JS_ErrorTerminated);
1655 bnet_suppress_error_messages(sd, 1);
1656 bget_msg(sd); /* Read final response from append_data */
1657 Dmsg0(110, "Error in blast_data.\n");
1659 set_jcr_job_status(jcr, JS_Terminated);
1660 /* Note, the above set status will not override an error */
1661 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1662 bnet_suppress_error_messages(sd, 1);
1663 goto cleanup; /* bail out now */
1666 * Expect to get response to append_data from Storage daemon
1668 if (!response(jcr, sd, OK_append, "Append Data")) {
1669 set_jcr_job_status(jcr, JS_ErrorTerminated);
1674 * Send Append End Data to Storage daemon
1676 sd->fsend(append_end, jcr->Ticket);
1678 if (!response(jcr, sd, OK_end, "Append End")) {
1679 set_jcr_job_status(jcr, JS_ErrorTerminated);
1684 * Send Append Close to Storage daemon
1686 sd->fsend(append_close, jcr->Ticket);
1687 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1688 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1690 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1694 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1697 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1698 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1704 #if defined(WIN32_VSS)
1705 /* STOP VSS ON WIN32 */
1706 /* tell vss to close the backup session */
1708 if (g_pVSSClient->CloseBackup()) {
1709 /* inform user about writer states */
1710 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1711 int msg_type = M_INFO;
1712 if (g_pVSSClient->GetWriterState(i) < 1) {
1713 msg_type = M_WARNING;
1716 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1719 Win32ConvCleanupCache();
1724 generate_plugin_event(jcr, bEventEndBackupJob);
1725 return 0; /* return and stop command loop */
1729 * Do a Verify for Director
1732 static int verify_cmd(JCR *jcr)
1734 BSOCK *dir = jcr->dir_bsock;
1735 BSOCK *sd = jcr->store_bsock;
1738 jcr->set_JobType(JT_VERIFY);
1739 if (sscanf(dir->msg, verifycmd, level) != 1) {
1740 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1744 if (strcasecmp(level, "init") == 0) {
1745 jcr->set_JobLevel(L_VERIFY_INIT);
1746 } else if (strcasecmp(level, "catalog") == 0){
1747 jcr->set_JobLevel(L_VERIFY_CATALOG);
1748 } else if (strcasecmp(level, "volume") == 0){
1749 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1750 } else if (strcasecmp(level, "data") == 0){
1751 jcr->set_JobLevel(L_VERIFY_DATA);
1752 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1753 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1755 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1759 dir->fsend(OKverify);
1761 generate_daemon_event(jcr, "JobStart");
1762 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1763 generate_plugin_event(jcr, bEventStartVerifyJob);
1765 Dmsg1(110, "filed>dird: %s", dir->msg);
1767 switch (jcr->getJobLevel()) {
1769 case L_VERIFY_CATALOG:
1772 case L_VERIFY_VOLUME_TO_CATALOG:
1773 if (!open_sd_read_session(jcr)) {
1776 start_dir_heartbeat(jcr);
1777 do_verify_volume(jcr);
1778 stop_dir_heartbeat(jcr);
1780 * Send Close session command to Storage daemon
1782 sd->fsend(read_close, jcr->Ticket);
1783 Dmsg1(130, "filed>stored: %s", sd->msg);
1785 /* ****FIXME**** check response */
1786 bget_msg(sd); /* get OK */
1788 /* Inform Storage daemon that we are done */
1789 sd->signal(BNET_TERMINATE);
1792 case L_VERIFY_DISK_TO_CATALOG:
1796 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1800 dir->signal(BNET_EOD);
1801 generate_plugin_event(jcr, bEventEndVerifyJob);
1802 return 0; /* return and terminate command loop */
1806 * Do a Restore for Director
1809 static int restore_cmd(JCR *jcr)
1811 BSOCK *dir = jcr->dir_bsock;
1812 BSOCK *sd = jcr->store_bsock;
1814 bool use_regexwhere=false;
1819 * Scan WHERE (base directory for restore) from command
1821 Dmsg0(150, "restore command\n");
1822 /* Pickup where string */
1823 args = get_memory(dir->msglen+1);
1826 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1827 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1828 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1829 pm_strcpy(jcr->errmsg, dir->msg);
1830 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1835 use_regexwhere = true;
1837 /* Turn / into nothing */
1838 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1842 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1843 unbash_spaces(args);
1845 if (use_regexwhere) {
1846 jcr->where_bregexp = get_bregexps(args);
1847 if (!jcr->where_bregexp) {
1848 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1849 free_pool_memory(args);
1853 jcr->where = bstrdup(args);
1856 free_pool_memory(args);
1857 jcr->replace = replace;
1858 jcr->prefix_links = prefix_links;
1860 dir->fsend(OKrestore);
1861 Dmsg1(110, "filed>dird: %s", dir->msg);
1863 jcr->set_JobType(JT_RESTORE);
1865 set_jcr_job_status(jcr, JS_Blocked);
1867 if (!open_sd_read_session(jcr)) {
1868 set_jcr_job_status(jcr, JS_ErrorTerminated);
1872 set_jcr_job_status(jcr, JS_Running);
1875 * Do restore of files and data
1877 start_dir_heartbeat(jcr);
1878 generate_daemon_event(jcr, "JobStart");
1879 generate_plugin_event(jcr, bEventStartRestoreJob);
1881 stop_dir_heartbeat(jcr);
1883 set_jcr_job_status(jcr, JS_Terminated);
1884 if (jcr->JobStatus != JS_Terminated) {
1885 bnet_suppress_error_messages(sd, 1);
1889 * Send Close session command to Storage daemon
1891 sd->fsend(read_close, jcr->Ticket);
1892 Dmsg1(130, "filed>stored: %s", sd->msg);
1894 bget_msg(sd); /* get OK */
1896 /* Inform Storage daemon that we are done */
1897 sd->signal(BNET_TERMINATE);
1900 bfree_and_null(jcr->where);
1902 if (jcr->JobErrors) {
1903 set_jcr_job_status(jcr, JS_ErrorTerminated);
1906 Dmsg0(130, "Done in job.c\n");
1909 if (jcr->multi_restore) {
1910 dir->fsend(OKstoreend);
1911 ret = 1; /* we continue the loop, waiting for next part */
1913 end_restore_cmd(jcr);
1914 ret = 0; /* we stop here */
1920 static int end_restore_cmd(JCR *jcr)
1922 Dmsg0(5, "end_restore_cmd\n");
1923 generate_plugin_event(jcr, bEventEndRestoreJob);
1924 return 0; /* return and terminate command loop */
1927 static int open_sd_read_session(JCR *jcr)
1929 BSOCK *sd = jcr->store_bsock;
1932 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1935 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1936 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1937 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1939 * Open Read Session with Storage daemon
1941 sd->fsend(read_open, "DummyVolume",
1942 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1943 jcr->StartBlock, jcr->EndBlock);
1944 Dmsg1(110, ">stored: %s", sd->msg);
1949 if (bget_msg(sd) >= 0) {
1950 Dmsg1(110, "filed<stored: %s", sd->msg);
1951 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1952 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1955 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
1957 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1961 if (!send_bootstrap_file(jcr)) {
1966 * Start read of data with Storage daemon
1968 sd->fsend(read_data, jcr->Ticket);
1969 Dmsg1(110, ">stored: %s", sd->msg);
1974 if (!response(jcr, sd, OK_data, "Read Data")) {
1981 * Destroy the Job Control Record and associated
1982 * resources (sockets).
1984 static void filed_free_jcr(JCR *jcr)
1986 if (jcr->store_bsock) {
1987 jcr->store_bsock->close();
1989 free_bootstrap(jcr);
1990 if (jcr->last_fname) {
1991 free_pool_memory(jcr->last_fname);
1993 free_runscripts(jcr->RunScripts);
1994 delete jcr->RunScripts;
1996 if (jcr->JobId != 0)
1997 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2003 * Get response from Storage daemon to a command we
2004 * sent. Check that the response is OK.
2006 * Returns: 0 on failure
2009 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2014 if (bget_msg(sd) > 0) {
2015 Dmsg0(110, sd->msg);
2016 if (strcmp(sd->msg, resp) == 0) {
2020 if (job_canceled(jcr)) {
2021 return 0; /* if canceled avoid useless error messages */
2023 if (is_bnet_error(sd)) {
2024 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2025 cmd, bnet_strerror(sd));
2027 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2028 cmd, resp, sd->msg);
2033 static int send_bootstrap_file(JCR *jcr)
2037 BSOCK *sd = jcr->store_bsock;
2038 const char *bootstrap = "bootstrap\n";
2041 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2042 if (!jcr->RestoreBootstrap) {
2045 bs = fopen(jcr->RestoreBootstrap, "rb");
2048 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2049 jcr->RestoreBootstrap, be.bstrerror());
2050 set_jcr_job_status(jcr, JS_ErrorTerminated);
2053 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2055 while (fgets(buf, sizeof(buf), bs)) {
2056 sd->msglen = Mmsg(sd->msg, "%s", buf);
2059 sd->signal(BNET_EOD);
2061 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2062 set_jcr_job_status(jcr, JS_ErrorTerminated);
2068 free_bootstrap(jcr);