2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula File Daemon Job processing
31 * Kern Sibbald, October MM
40 #if defined(WIN32_VSS)
43 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
44 static int enable_vss;
47 extern CLIENT *me; /* our client resource */
49 /* Imported functions */
50 extern int status_cmd(JCR *jcr);
51 extern int qstatus_cmd(JCR *jcr);
52 extern int accurate_cmd(JCR *jcr);
54 /* Forward referenced functions */
55 static int backup_cmd(JCR *jcr);
56 static int bootstrap_cmd(JCR *jcr);
57 static int cancel_cmd(JCR *jcr);
58 static int setdebug_cmd(JCR *jcr);
59 static int estimate_cmd(JCR *jcr);
60 static int hello_cmd(JCR *jcr);
61 static int job_cmd(JCR *jcr);
62 static int fileset_cmd(JCR *jcr);
63 static int level_cmd(JCR *jcr);
64 static int verify_cmd(JCR *jcr);
65 static int restore_cmd(JCR *jcr);
66 static int storage_cmd(JCR *jcr);
67 static int session_cmd(JCR *jcr);
68 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
69 static void filed_free_jcr(JCR *jcr);
70 static int open_sd_read_session(JCR *jcr);
71 static int send_bootstrap_file(JCR *jcr);
72 static int runscript_cmd(JCR *jcr);
73 static int runbefore_cmd(JCR *jcr);
74 static int runafter_cmd(JCR *jcr);
75 static int runbeforenow_cmd(JCR *jcr);
76 static void set_options(findFOPTS *fo, const char *opts);
79 /* Exported functions */
84 int monitoraccess; /* specify if monitors have access to this function */
88 * The following are the recognized commands from the Director.
90 static struct s_cmds cmds[] = {
91 {"backup", backup_cmd, 0},
92 {"cancel", cancel_cmd, 0},
93 {"setdebug=", setdebug_cmd, 0},
94 {"estimate", estimate_cmd, 0},
95 {"Hello", hello_cmd, 1},
96 {"fileset", fileset_cmd, 0},
97 {"JobId=", job_cmd, 0},
98 {"level = ", level_cmd, 0},
99 {"restore", restore_cmd, 0},
100 {"session", session_cmd, 0},
101 {"status", status_cmd, 1},
102 {".status", qstatus_cmd, 1},
103 {"storage ", storage_cmd, 0},
104 {"verify", verify_cmd, 0},
105 {"bootstrap", bootstrap_cmd, 0},
106 {"RunBeforeNow", runbeforenow_cmd, 0},
107 {"RunBeforeJob", runbefore_cmd, 0},
108 {"RunAfterJob", runafter_cmd, 0},
109 {"Run", runscript_cmd, 0},
110 {"accurate", accurate_cmd, 0},
111 {NULL, NULL} /* list terminator */
114 /* Commands received from director that need scanning */
115 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
116 static char storaddr[] = "storage address=%s port=%d ssl=%d";
117 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
118 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
119 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
120 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
121 static char verifycmd[] = "verify level=%30s";
122 static char estimatecmd[] = "estimate listing=%d";
123 static char runbefore[] = "RunBeforeJob %s";
124 static char runafter[] = "RunAfterJob %s";
125 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
127 /* Responses sent to Director */
128 static char errmsg[] = "2999 Invalid command\n";
129 static char no_auth[] = "2998 No Authorization\n";
130 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
131 static char OKinc[] = "2000 OK include\n";
132 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
133 static char OKlevel[] = "2000 OK level\n";
134 static char OKbackup[] = "2000 OK backup\n";
135 static char OKbootstrap[] = "2000 OK bootstrap\n";
136 static char OKverify[] = "2000 OK verify\n";
137 static char OKrestore[] = "2000 OK restore\n";
138 static char OKsession[] = "2000 OK session\n";
139 static char OKstore[] = "2000 OK storage\n";
140 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
141 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
142 static char BADjob[] = "2901 Bad Job\n";
143 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
144 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
145 static char OKRunBefore[] = "2000 OK RunBefore\n";
146 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
147 static char OKRunAfter[] = "2000 OK RunAfter\n";
148 static char OKRunScript[] = "2000 OK RunScript\n";
151 /* Responses received from Storage Daemon */
152 static char OK_end[] = "3000 OK end\n";
153 static char OK_close[] = "3000 OK close Status = %d\n";
154 static char OK_open[] = "3000 OK open ticket = %d\n";
155 static char OK_data[] = "3000 OK data\n";
156 static char OK_append[] = "3000 OK append data\n";
157 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
160 /* Commands sent to Storage Daemon */
161 static char append_open[] = "append open session\n";
162 static char append_data[] = "append data %d\n";
163 static char append_end[] = "append end session %d\n";
164 static char append_close[] = "append close session %d\n";
165 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
166 static char read_data[] = "read data %d\n";
167 static char read_close[] = "read close session %d\n";
170 * Accept requests from a Director
172 * NOTE! We are running as a separate thread
174 * Send output one line
175 * at a time followed by a zero length transmission.
177 * Return when the connection is terminated or there
180 * Basic task here is:
181 * Authenticate Director (during Hello command).
182 * Accept commands one at a time from the Director
185 * Concerning ClientRunBefore/After, the sequence of events
186 * is rather critical. If they are not done in the right
187 * order one can easily get FD->SD timeouts if the script
190 * The current sequence of events is:
191 * 1. Dir starts job with FD
192 * 2. Dir connects to SD
193 * 3. Dir connects to FD
194 * 4. FD connects to SD
195 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
196 * 6. Dir sends include/exclude
197 * 7. FD sends data to SD
198 * 8. SD/FD disconnects while SD despools data and attributes (optionnal)
199 * 9. FD runs ClientRunAfterJob
202 void *handle_client_request(void *dirp)
207 BSOCK *dir = (BSOCK *)dirp;
209 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
210 jcr->dir_bsock = dir;
211 jcr->ff = init_find_files();
212 jcr->start_time = time(NULL);
213 jcr->RunScripts = New(alist(10, not_owned_by_alist));
214 jcr->last_fname = get_pool_memory(PM_FNAME);
215 jcr->last_fname[0] = 0;
216 jcr->client_name = get_memory(strlen(my_name) + 1);
217 new_plugins(jcr); /* instantiate plugins for this jcr */
218 pm_strcpy(jcr->client_name, my_name);
219 jcr->crypto.pki_sign = me->pki_sign;
220 jcr->crypto.pki_encrypt = me->pki_encrypt;
221 jcr->crypto.pki_keypair = me->pki_keypair;
222 jcr->crypto.pki_signers = me->pki_signers;
223 jcr->crypto.pki_recipients = me->pki_recipients;
225 enable_backup_privileges(NULL, 1 /* ignore_errors */);
227 /**********FIXME******* add command handler error code */
229 for (quit=false; !quit;) {
232 if (bnet_recv(dir) < 0) {
233 break; /* connection terminated */
235 dir->msg[dir->msglen] = 0;
236 Dmsg1(100, "<dird: %s", dir->msg);
238 for (i=0; cmds[i].cmd; i++) {
239 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
240 found = true; /* indicate command found */
241 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
242 bnet_fsend(dir, no_auth);
243 bnet_sig(dir, BNET_EOD);
246 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
247 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
248 bnet_fsend(dir, invalid_cmd);
249 bnet_sig(dir, BNET_EOD);
252 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
253 if (!cmds[i].func(jcr)) { /* do command */
254 quit = true; /* error or fully terminated, get out */
255 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
260 if (!found) { /* command not found */
261 bnet_fsend(dir, errmsg);
267 /* Inform Storage daemon that we are done */
268 if (jcr->store_bsock) {
269 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
272 /* Run the after job */
273 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
275 if (jcr->JobId) { /* send EndJob if running a job */
276 char ed1[50], ed2[50];
277 /* Send termination status back to Dir */
278 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
279 edit_uint64(jcr->ReadBytes, ed1),
280 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, jcr->VSS,
281 jcr->crypto.pki_encrypt);
282 Dmsg1(110, "End FD msg: %s\n", dir->msg);
285 generate_daemon_event(jcr, "JobEnd");
286 generate_plugin_event(jcr, bEventJobEnd);
288 dequeue_messages(jcr); /* send any queued messages */
290 /* Inform Director that we are done */
291 dir->signal(BNET_TERMINATE);
293 free_plugins(jcr); /* release instantiated plugins */
295 /* Clean up fileset */
296 FF_PKT *ff = jcr->ff;
297 findFILESET *fileset = ff->fileset;
300 /* Delete FileSet Include lists */
301 for (i=0; i<fileset->include_list.size(); i++) {
302 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
303 for (j=0; j<incexe->opts_list.size(); j++) {
304 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
305 for (k=0; k<fo->regex.size(); k++) {
306 regfree((regex_t *)fo->regex.get(k));
309 fo->regexdir.destroy();
310 fo->regexfile.destroy();
312 fo->wilddir.destroy();
313 fo->wildfile.destroy();
314 fo->wildbase.destroy();
316 fo->fstype.destroy();
317 fo->drivetype.destroy();
319 incexe->opts_list.destroy();
320 incexe->name_list.destroy();
321 incexe->plugin_list.destroy();
323 fileset->include_list.destroy();
325 /* Delete FileSet Exclude lists */
326 for (i=0; i<fileset->exclude_list.size(); i++) {
327 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
328 for (j=0; j<incexe->opts_list.size(); j++) {
329 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
331 fo->regexdir.destroy();
332 fo->regexfile.destroy();
334 fo->wilddir.destroy();
335 fo->wildfile.destroy();
336 fo->wildbase.destroy();
338 fo->fstype.destroy();
339 fo->drivetype.destroy();
341 incexe->opts_list.destroy();
342 incexe->name_list.destroy();
343 incexe->plugin_list.destroy();
345 fileset->exclude_list.destroy();
349 Dmsg0(100, "Calling term_find_files\n");
350 term_find_files(jcr->ff);
352 Dmsg0(100, "Done with term_find_files\n");
353 free_jcr(jcr); /* destroy JCR record */
354 Dmsg0(100, "Done with free_jcr\n");
360 * Hello from Director he must identify himself and provide his
363 static int hello_cmd(JCR *jcr)
365 Dmsg0(120, "Calling Authenticate\n");
366 if (!authenticate_director(jcr)) {
369 Dmsg0(120, "OK Authenticate\n");
370 jcr->authenticated = true;
377 static int cancel_cmd(JCR *jcr)
379 BSOCK *dir = jcr->dir_bsock;
380 char Job[MAX_NAME_LENGTH];
383 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
384 if (!(cjcr=get_jcr_by_full_name(Job))) {
385 dir->fsend(_("2901 Job %s not found.\n"), Job);
387 if (cjcr->store_bsock) {
388 cjcr->store_bsock->set_timed_out();
389 cjcr->store_bsock->set_terminated();
390 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
392 set_jcr_job_status(cjcr, JS_Canceled);
394 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
397 dir->fsend(_("2902 Error scanning cancel command.\n"));
399 dir->signal(BNET_EOD);
405 * Set debug level as requested by the Director
408 static int setdebug_cmd(JCR *jcr)
410 BSOCK *dir = jcr->dir_bsock;
411 int level, trace_flag;
413 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
414 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
415 pm_strcpy(jcr->errmsg, dir->msg);
416 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
420 set_trace(trace_flag);
421 return dir->fsend(OKsetdebug, level);
425 static int estimate_cmd(JCR *jcr)
427 BSOCK *dir = jcr->dir_bsock;
430 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
431 pm_strcpy(jcr->errmsg, dir->msg);
432 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
433 dir->fsend(_("2992 Bad estimate command.\n"));
437 dir->fsend(OKest, jcr->num_files_examined,
438 edit_uint64_with_commas(jcr->JobBytes, ed2));
439 dir->signal(BNET_EOD);
444 * Get JobId and Storage Daemon Authorization key from Director
446 static int job_cmd(JCR *jcr)
448 BSOCK *dir = jcr->dir_bsock;
449 POOLMEM *sd_auth_key;
451 sd_auth_key = get_memory(dir->msglen);
452 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
453 &jcr->VolSessionId, &jcr->VolSessionTime,
455 pm_strcpy(jcr->errmsg, dir->msg);
456 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
458 free_pool_memory(sd_auth_key);
461 jcr->sd_auth_key = bstrdup(sd_auth_key);
462 free_pool_memory(sd_auth_key);
463 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
464 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
465 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
466 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
469 static int runbefore_cmd(JCR *jcr)
472 BSOCK *dir = jcr->dir_bsock;
473 POOLMEM *cmd = get_memory(dir->msglen+1);
476 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
477 if (sscanf(dir->msg, runbefore, cmd) != 1) {
478 pm_strcpy(jcr->errmsg, dir->msg);
479 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
480 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
486 /* Run the command now */
487 script = new_runscript();
488 script->set_command(cmd);
489 script->when = SCRIPT_Before;
490 ok = script->run(jcr, "ClientRunBeforeJob");
491 free_runscript(script);
495 dir->fsend(OKRunBefore);
498 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
503 static int runbeforenow_cmd(JCR *jcr)
505 BSOCK *dir = jcr->dir_bsock;
507 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
508 if (job_canceled(jcr)) {
509 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
510 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
513 dir->fsend(OKRunBeforeNow);
514 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
519 static int runafter_cmd(JCR *jcr)
521 BSOCK *dir = jcr->dir_bsock;
522 POOLMEM *msg = get_memory(dir->msglen+1);
525 Dmsg1(100, "runafter_cmd: %s", dir->msg);
526 if (sscanf(dir->msg, runafter, msg) != 1) {
527 pm_strcpy(jcr->errmsg, dir->msg);
528 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
529 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
535 cmd = new_runscript();
536 cmd->set_command(msg);
537 cmd->on_success = true;
538 cmd->on_failure = false;
539 cmd->when = SCRIPT_After;
541 jcr->RunScripts->append(cmd);
543 free_pool_memory(msg);
544 return dir->fsend(OKRunAfter);
547 static int runscript_cmd(JCR *jcr)
549 BSOCK *dir = jcr->dir_bsock;
550 POOLMEM *msg = get_memory(dir->msglen+1);
551 int on_success, on_failure, fail_on_error;
553 RUNSCRIPT *cmd = new_runscript() ;
555 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
556 /* Note, we cannot sscanf into bools */
557 if (sscanf(dir->msg, runscript, &on_success,
562 pm_strcpy(jcr->errmsg, dir->msg);
563 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
564 dir->fsend(_("2905 Bad RunScript command.\n"));
569 cmd->on_success = on_success;
570 cmd->on_failure = on_failure;
571 cmd->fail_on_error = fail_on_error;
574 cmd->set_command(msg);
576 jcr->RunScripts->append(cmd);
578 free_pool_memory(msg);
579 return dir->fsend(OKRunScript);
583 static bool init_fileset(JCR *jcr)
586 findFILESET *fileset;
595 fileset = (findFILESET *)malloc(sizeof(findFILESET));
596 memset(fileset, 0, sizeof(findFILESET));
597 ff->fileset = fileset;
598 fileset->state = state_none;
599 fileset->include_list.init(1, true);
600 fileset->exclude_list.init(1, true);
604 static findFOPTS *start_options(FF_PKT *ff)
606 int state = ff->fileset->state;
607 findINCEXE *incexe = ff->fileset->incexe;
609 if (state != state_options) {
610 ff->fileset->state = state_options;
611 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
612 memset(fo, 0, sizeof(findFOPTS));
613 fo->regex.init(1, true);
614 fo->regexdir.init(1, true);
615 fo->regexfile.init(1, true);
616 fo->wild.init(1, true);
617 fo->wilddir.init(1, true);
618 fo->wildfile.init(1, true);
619 fo->wildbase.init(1, true);
620 fo->base.init(1, true);
621 fo->fstype.init(1, true);
622 fo->drivetype.init(1, true);
623 incexe->current_opts = fo;
624 incexe->opts_list.append(fo);
626 return incexe->current_opts;
631 * Add fname to include/exclude fileset list. First check for
632 * | and < and if necessary perform command.
634 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
649 p++; /* skip over | */
650 fn = get_pool_memory(PM_FNAME);
651 fn = edit_job_codes(jcr, fn, p, "");
652 bpipe = open_bpipe(fn, 0, "r");
655 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
657 free_pool_memory(fn);
660 free_pool_memory(fn);
661 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
662 strip_trailing_junk(buf);
664 fileset->incexe->name_list.append(new_dlistString(buf));
666 fileset->incexe->plugin_list.append(new_dlistString(buf));
669 if ((stat=close_bpipe(bpipe)) != 0) {
671 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
672 p, be.code(stat), be.bstrerror(stat));
677 Dmsg0(100, "Doing < include on client.\n");
678 p++; /* skip over < */
679 if ((ffd = fopen(p, "rb")) == NULL) {
681 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
685 while (fgets(buf, sizeof(buf), ffd)) {
686 strip_trailing_junk(buf);
687 Dmsg1(100, "%s\n", buf);
689 fileset->incexe->name_list.append(new_dlistString(buf));
691 fileset->incexe->plugin_list.append(new_dlistString(buf));
698 fileset->incexe->name_list.append(new_dlistString(fname));
700 fileset->incexe->plugin_list.append(new_dlistString(fname));
707 static void add_fileset(JCR *jcr, const char *item)
709 FF_PKT *ff = jcr->ff;
710 findFILESET *fileset = ff->fileset;
711 int state = fileset->state;
712 findFOPTS *current_opts;
714 /* Get code, optional subcode, and position item past the dividing space */
715 Dmsg1(100, "%s\n", item);
720 int subcode = ' '; /* A space is always a valid subcode */
721 if (item[0] != '\0' && item[0] != ' ') {
729 /* Skip all lines we receive after an error */
730 if (state == state_error) {
731 Dmsg0(100, "State=error return\n");
736 * The switch tests the code for validity.
737 * The subcode is always good if it is a space, otherwise we must confirm.
738 * We set state to state_error first assuming the subcode is invalid,
739 * requiring state to be set in cases below that handle subcodes.
741 if (subcode != ' ') {
743 Dmsg0(100, "Set state=error\n");
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(); /* for dlist; was 1,true for alist */
752 fileset->incexe->plugin_list.init();
753 fileset->include_list.append(fileset->incexe);
757 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
758 memset(fileset->incexe, 0, sizeof(findINCEXE));
759 fileset->incexe->opts_list.init(1, true);
760 fileset->incexe->name_list.init();
761 fileset->incexe->plugin_list.init();
762 fileset->exclude_list.append(fileset->incexe);
768 /* File item to include or exclude list */
769 state = state_include;
770 add_file_to_fileset(jcr, item, fileset, true);
773 /* Plugin item to include list */
774 state = state_include;
775 add_file_to_fileset(jcr, item, fileset, false);
778 current_opts = start_options(ff);
782 preg = (regex_t *)malloc(sizeof(regex_t));
783 if (current_opts->flags & FO_IGNORECASE) {
784 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
786 rc = regcomp(preg, item, REG_EXTENDED);
789 regerror(rc, preg, prbuf, sizeof(prbuf));
792 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
796 state = state_options;
797 if (subcode == ' ') {
798 current_opts->regex.append(preg);
799 } else if (subcode == 'D') {
800 current_opts->regexdir.append(preg);
801 } else if (subcode == 'F') {
802 current_opts->regexfile.append(preg);
808 current_opts = start_options(ff);
809 current_opts->base.append(bstrdup(item));
810 state = state_options;
813 current_opts = start_options(ff);
814 state = state_options;
815 if (subcode == ' ') {
816 current_opts->fstype.append(bstrdup(item));
817 } else if (subcode == 'D') {
818 current_opts->drivetype.append(bstrdup(item));
824 current_opts = start_options(ff);
825 state = state_options;
826 if (subcode == ' ') {
827 current_opts->wild.append(bstrdup(item));
828 } else if (subcode == 'D') {
829 current_opts->wilddir.append(bstrdup(item));
830 } else if (subcode == 'F') {
831 current_opts->wildfile.append(bstrdup(item));
832 } else if (subcode == 'B') {
833 current_opts->wildbase.append(bstrdup(item));
839 current_opts = start_options(ff);
840 set_options(current_opts, item);
841 state = state_options;
844 current_opts = start_options(ff);
845 // current_opts->reader = bstrdup(item);
846 state = state_options;
849 current_opts = start_options(ff);
850 // current_opts->writer = bstrdup(item);
851 state = state_options;
854 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
858 ff->fileset->state = state;
861 static bool term_fileset(JCR *jcr)
863 FF_PKT *ff = jcr->ff;
865 #ifdef xxx_DEBUG_CODE
866 findFILESET *fileset = ff->fileset;
869 for (i=0; i<fileset->include_list.size(); i++) {
870 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
872 for (j=0; j<incexe->opts_list.size(); j++) {
873 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
874 for (k=0; k<fo->regex.size(); k++) {
875 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
877 for (k=0; k<fo->regexdir.size(); k++) {
878 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
880 for (k=0; k<fo->regexfile.size(); k++) {
881 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
883 for (k=0; k<fo->wild.size(); k++) {
884 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
886 for (k=0; k<fo->wilddir.size(); k++) {
887 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
889 for (k=0; k<fo->wildfile.size(); k++) {
890 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
892 for (k=0; k<fo->wildbase.size(); k++) {
893 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
895 for (k=0; k<fo->base.size(); k++) {
896 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
898 for (k=0; k<fo->fstype.size(); k++) {
899 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
901 for (k=0; k<fo->drivetype.size(); k++) {
902 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
906 foreach_dlist(node, &incexe->name_list) {
907 Dmsg1(400, "F %s\n", node->c_str());
909 foreach_dlist(node, &incexe->plugin_list) {
910 Dmsg1(400, "P %s\n", node->c_str());
913 for (i=0; i<fileset->exclude_list.size(); i++) {
914 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
916 for (j=0; j<incexe->opts_list.size(); j++) {
917 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
918 for (k=0; k<fo->regex.size(); k++) {
919 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
921 for (k=0; k<fo->regexdir.size(); k++) {
922 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
924 for (k=0; k<fo->regexfile.size(); k++) {
925 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
927 for (k=0; k<fo->wild.size(); k++) {
928 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
930 for (k=0; k<fo->wilddir.size(); k++) {
931 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
933 for (k=0; k<fo->wildfile.size(); k++) {
934 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
936 for (k=0; k<fo->wildbase.size(); k++) {
937 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
939 for (k=0; k<fo->base.size(); k++) {
940 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
942 for (k=0; k<fo->fstype.size(); k++) {
943 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
945 for (k=0; k<fo->drivetype.size(); k++) {
946 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
950 foreach_dlist(node, incexe->name_list) {
951 Dmsg1(400, "F %s\n", node->c_str());
953 foreach_dlist(node, &incexe->plugin_list) {
954 Dmsg1(400, "P %s\n", node->c_str());
958 return ff->fileset->state != state_error;
963 * As an optimization, we should do this during
964 * "compile" time in filed/job.c, and keep only a bit mask
965 * and the Verify options.
967 static void set_options(findFOPTS *fo, const char *opts)
973 // Commented out as it is not backward compatible - KES
975 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
978 for (p=opts; *p; p++) {
980 case 'a': /* alway replace */
981 case '0': /* no option */
984 fo->flags |= FO_EXCLUDE;
987 fo->flags |= FO_MULTIFS;
989 case 'h': /* no recursion */
990 fo->flags |= FO_NO_RECURSION;
992 case 'H': /* no hard link handling */
993 fo->flags |= FO_NO_HARDLINK;
996 fo->flags |= FO_IGNORECASE;
1002 fo->flags |= FO_NOREPLACE;
1004 case 'p': /* use portable data format */
1005 fo->flags |= FO_PORTABLE;
1007 case 'R': /* Resource forks and Finder Info */
1008 fo->flags |= FO_HFSPLUS;
1009 case 'r': /* read fifo */
1010 fo->flags |= FO_READFIFO;
1015 fo->flags |= FO_SHA1;
1020 fo->flags |= FO_SHA256;
1024 fo->flags |= FO_SHA512;
1030 * If 2 or 3 is seen here, SHA2 is not configured, so
1031 * eat the option, and drop back to SHA-1.
1033 if (p[1] == '2' || p[1] == '3') {
1036 fo->flags |= FO_SHA1;
1041 fo->flags |= FO_SPARSE;
1044 fo->flags |= FO_MTIMEONLY;
1047 fo->flags |= FO_KEEPATIME;
1050 fo->flags |= FO_ACL;
1052 case 'V': /* verify options */
1053 /* Copy Verify Options */
1054 for (j=0; *p && *p != ':'; p++) {
1055 fo->VerifyOpts[j] = *p;
1056 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1060 fo->VerifyOpts[j] = 0;
1062 case 'C': /* accurate options */
1063 /* Copy Accurate Options */
1064 for (j=0; *p && *p != ':'; p++) {
1065 fo->AccurateOpts[j] = *p;
1066 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1070 fo->AccurateOpts[j] = 0;
1072 case 'P': /* strip path */
1075 for (j=0; *p && *p != ':'; p++) {
1077 if (j < (int)sizeof(strip) - 1) {
1082 fo->strip_path = atoi(strip);
1083 fo->flags |= FO_STRIPPATH;
1084 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1087 fo->flags |= FO_IF_NEWER;
1090 fo->flags |= FO_ENHANCEDWILD;
1092 case 'Z': /* gzip compression */
1093 fo->flags |= FO_GZIP;
1094 fo->GZIP_level = *++p - '0';
1097 fo->flags |= FO_NOATIME;
1100 fo->flags |= FO_CHKCHANGES;
1103 fo->flags |= FO_HONOR_NODUMP;
1106 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1114 * Director is passing his Fileset
1116 static int fileset_cmd(JCR *jcr)
1118 BSOCK *dir = jcr->dir_bsock;
1120 #if defined(WIN32_VSS)
1123 sscanf(dir->msg, "fileset vss=%d", &vss);
1127 if (!init_fileset(jcr)) {
1130 while (dir->recv() >= 0) {
1131 strip_trailing_junk(dir->msg);
1132 Dmsg1(500, "Fileset: %s\n", dir->msg);
1133 add_fileset(jcr, dir->msg);
1135 if (!term_fileset(jcr)) {
1138 return dir->fsend(OKinc);
1141 static void free_bootstrap(JCR *jcr)
1143 if (jcr->RestoreBootstrap) {
1144 unlink(jcr->RestoreBootstrap);
1145 free_pool_memory(jcr->RestoreBootstrap);
1146 jcr->RestoreBootstrap = NULL;
1151 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1152 static uint32_t bsr_uniq = 0;
1155 * The Director sends us the bootstrap file, which
1156 * we will in turn pass to the SD.
1158 static int bootstrap_cmd(JCR *jcr)
1160 BSOCK *dir = jcr->dir_bsock;
1161 POOLMEM *fname = get_pool_memory(PM_FNAME);
1164 free_bootstrap(jcr);
1167 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1168 jcr->Job, bsr_uniq);
1170 Dmsg1(400, "bootstrap=%s\n", fname);
1171 jcr->RestoreBootstrap = fname;
1172 bs = fopen(fname, "a+b"); /* create file */
1175 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1176 jcr->RestoreBootstrap, be.bstrerror());
1178 * Suck up what he is sending to us so that he will then
1179 * read our error message.
1181 while (dir->recv() >= 0)
1183 free_bootstrap(jcr);
1184 set_jcr_job_status(jcr, JS_ErrorTerminated);
1188 while (dir->recv() >= 0) {
1189 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1190 fputs(dir->msg, bs);
1194 * Note, do not free the bootstrap yet -- it needs to be
1197 return dir->fsend(OKbootstrap);
1202 * Get backup level from Director
1205 static int level_cmd(JCR *jcr)
1207 BSOCK *dir = jcr->dir_bsock;
1208 POOLMEM *level, *buf = NULL;
1211 level = get_memory(dir->msglen+1);
1212 Dmsg1(110, "level_cmd: %s", dir->msg);
1213 if (strstr(dir->msg, "accurate")) {
1214 jcr->accurate = true;
1216 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1219 /* Base backup requested? */
1220 if (strcmp(level, "base") == 0) {
1221 jcr->JobLevel = L_BASE;
1222 /* Full backup requested? */
1223 } else if (strcmp(level, "full") == 0) {
1224 jcr->JobLevel = L_FULL;
1225 } else if (strstr(level, "differential")) {
1226 jcr->JobLevel = L_DIFFERENTIAL;
1229 } else if (strstr(level, "incremental")) {
1230 jcr->JobLevel = L_INCREMENTAL;
1234 * We get his UTC since time, then sync the clocks and correct it
1235 * to agree with our clock.
1237 } else if (strcmp(level, "since_utime") == 0) {
1238 buf = get_memory(dir->msglen+1);
1239 utime_t since_time, adj;
1240 btime_t his_time, bt_start, rt=0, bt_adj=0;
1241 if (jcr->JobLevel == L_NONE) {
1242 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1244 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1245 buf, &mtime_only) != 2) {
1248 since_time = str_to_uint64(buf); /* this is the since time */
1249 Dmsg1(100, "since_time=%d\n", (int)since_time);
1250 char ed1[50], ed2[50];
1252 * Sync clocks by polling him for the time. We take
1253 * 10 samples of his time throwing out the first two.
1255 for (int i=0; i<10; i++) {
1256 bt_start = get_current_btime();
1257 dir->signal(BNET_BTIME); /* poll for time */
1258 if (dir->recv() <= 0) { /* get response */
1261 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1264 if (i < 2) { /* toss first two results */
1267 his_time = str_to_uint64(buf);
1268 rt = get_current_btime() - bt_start; /* compute round trip time */
1269 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1270 edit_uint64(bt_start, ed2));
1271 bt_adj += bt_start - his_time - rt/2;
1272 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1275 bt_adj = bt_adj / 8; /* compute average time */
1276 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1277 adj = btime_to_utime(bt_adj);
1278 since_time += adj; /* adjust for clock difference */
1279 /* Don't notify if time within 3 seconds */
1280 if (adj > 3 || adj < -3) {
1282 if (adj > 600 || adj < -600) {
1287 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1289 dir->signal(BNET_EOD);
1291 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1292 jcr->incremental = 1; /* set incremental or decremental backup */
1293 jcr->mtime = (time_t)since_time; /* set since time */
1294 generate_plugin_event(jcr, bEventSince, (void *)jcr->mtime);
1296 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1304 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1305 return dir->fsend(OKlevel);
1308 pm_strcpy(jcr->errmsg, dir->msg);
1309 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1318 * Get session parameters from Director -- this is for a Restore command
1320 static int session_cmd(JCR *jcr)
1322 BSOCK *dir = jcr->dir_bsock;
1324 Dmsg1(100, "SessionCmd: %s", dir->msg);
1325 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1326 &jcr->VolSessionId, &jcr->VolSessionTime,
1327 &jcr->StartFile, &jcr->EndFile,
1328 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1329 pm_strcpy(jcr->errmsg, dir->msg);
1330 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1334 return bnet_fsend(dir, OKsession);
1338 * Get address of storage daemon from Director
1341 static int storage_cmd(JCR *jcr)
1343 int stored_port; /* storage daemon port */
1344 int enable_ssl; /* enable ssl to sd */
1345 BSOCK *dir = jcr->dir_bsock;
1346 BSOCK *sd; /* storage daemon bsock */
1348 Dmsg1(100, "StorageCmd: %s", dir->msg);
1349 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1350 pm_strcpy(jcr->errmsg, dir->msg);
1351 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1354 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1355 /* Open command communications with Storage daemon */
1356 /* Try to connect for 1 hour at 10 second intervals */
1357 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1358 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1360 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1361 jcr->stored_addr, stored_port);
1362 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1363 jcr->stored_addr, stored_port);
1366 Dmsg0(110, "Connection OK to SD.\n");
1368 jcr->store_bsock = sd;
1370 sd->fsend("Hello Start Job %s\n", jcr->Job);
1371 if (!authenticate_storagedaemon(jcr)) {
1372 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1375 Dmsg0(110, "Authenticated with SD.\n");
1377 /* Send OK to Director */
1378 return dir->fsend(OKstore);
1385 static int backup_cmd(JCR *jcr)
1387 BSOCK *dir = jcr->dir_bsock;
1388 BSOCK *sd = jcr->store_bsock;
1392 #if defined(WIN32_VSS)
1393 // capture state here, if client is backed up by multiple directors
1394 // and one enables vss and the other does not then enable_vss can change
1395 // between here and where its evaluated after the job completes.
1396 jcr->VSS = g_pVSSClient && enable_vss;
1398 /* Run only one at a time */
1403 set_jcr_job_status(jcr, JS_Blocked);
1404 jcr->JobType = JT_BACKUP;
1405 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1408 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1412 dir->fsend(OKbackup);
1413 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1416 * Send Append Open Session to Storage daemon
1418 sd->fsend(append_open);
1419 Dmsg1(110, ">stored: %s", sd->msg);
1421 * Expect to receive back the Ticket number
1423 if (bget_msg(sd) >= 0) {
1424 Dmsg1(110, "<stored: %s", sd->msg);
1425 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1426 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1429 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1431 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1436 * Send Append data command to Storage daemon
1438 sd->fsend(append_data, jcr->Ticket);
1439 Dmsg1(110, ">stored: %s", sd->msg);
1442 * Expect to get OK data
1444 Dmsg1(110, "<stored: %s", sd->msg);
1445 if (!response(jcr, sd, OK_data, "Append Data")) {
1449 generate_daemon_event(jcr, "JobStart");
1450 generate_plugin_event(jcr, bEventStartBackupJob);
1452 #if defined(WIN32_VSS)
1453 /* START VSS ON WIN32 */
1455 if (g_pVSSClient->InitializeForBackup()) {
1456 /* tell vss which drives to snapshot */
1457 char szWinDriveLetters[27];
1458 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1459 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1460 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1461 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1464 /* tell user if snapshot creation of a specific drive failed */
1466 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1467 if (islower(szWinDriveLetters[i])) {
1468 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1472 /* inform user about writer states */
1473 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1474 if (g_pVSSClient->GetWriterState(i) < 1) {
1475 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1480 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1484 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1490 * Send Files to Storage daemon
1492 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1493 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1494 set_jcr_job_status(jcr, JS_ErrorTerminated);
1495 bnet_suppress_error_messages(sd, 1);
1496 bget_msg(sd); /* Read final response from append_data */
1497 Dmsg0(110, "Error in blast_data.\n");
1499 set_jcr_job_status(jcr, JS_Terminated);
1501 if (jcr->JobStatus != JS_Terminated) {
1502 bnet_suppress_error_messages(sd, 1);
1503 goto cleanup; /* bail out now */
1506 * Expect to get response to append_data from Storage daemon
1508 if (!response(jcr, sd, OK_append, "Append Data")) {
1509 set_jcr_job_status(jcr, JS_ErrorTerminated);
1514 * Send Append End Data to Storage daemon
1516 sd->fsend(append_end, jcr->Ticket);
1518 if (!response(jcr, sd, OK_end, "Append End")) {
1519 set_jcr_job_status(jcr, JS_ErrorTerminated);
1524 * Send Append Close to Storage daemon
1526 sd->fsend(append_close, jcr->Ticket);
1527 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1528 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1530 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1534 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1537 if (SDJobStatus != JS_Terminated) {
1538 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1544 #if defined(WIN32_VSS)
1545 /* STOP VSS ON WIN32 */
1546 /* tell vss to close the backup session */
1548 if (g_pVSSClient->CloseBackup()) {
1549 /* inform user about writer states */
1550 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1551 int msg_type = M_INFO;
1552 if (g_pVSSClient->GetWriterState(i) < 1) {
1553 msg_type = M_WARNING;
1556 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1563 generate_plugin_event(jcr, bEventEndBackupJob);
1564 return 0; /* return and stop command loop */
1568 * Do a Verify for Director
1571 static int verify_cmd(JCR *jcr)
1573 BSOCK *dir = jcr->dir_bsock;
1574 BSOCK *sd = jcr->store_bsock;
1577 jcr->JobType = JT_VERIFY;
1578 if (sscanf(dir->msg, verifycmd, level) != 1) {
1579 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1583 if (strcasecmp(level, "init") == 0) {
1584 jcr->JobLevel = L_VERIFY_INIT;
1585 } else if (strcasecmp(level, "catalog") == 0){
1586 jcr->JobLevel = L_VERIFY_CATALOG;
1587 } else if (strcasecmp(level, "volume") == 0){
1588 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1589 } else if (strcasecmp(level, "data") == 0){
1590 jcr->JobLevel = L_VERIFY_DATA;
1591 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1592 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1594 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1598 dir->fsend(OKverify);
1600 generate_daemon_event(jcr, "JobStart");
1601 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1602 generate_plugin_event(jcr, bEventStartVerifyJob);
1604 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1606 switch (jcr->JobLevel) {
1608 case L_VERIFY_CATALOG:
1611 case L_VERIFY_VOLUME_TO_CATALOG:
1612 if (!open_sd_read_session(jcr)) {
1615 start_dir_heartbeat(jcr);
1616 do_verify_volume(jcr);
1617 stop_dir_heartbeat(jcr);
1619 * Send Close session command to Storage daemon
1621 sd->fsend(read_close, jcr->Ticket);
1622 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1624 /* ****FIXME**** check response */
1625 bget_msg(sd); /* get OK */
1627 /* Inform Storage daemon that we are done */
1628 sd->signal(BNET_TERMINATE);
1631 case L_VERIFY_DISK_TO_CATALOG:
1635 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1639 dir->signal(BNET_EOD);
1640 generate_plugin_event(jcr, bEventEndVerifyJob);
1641 return 0; /* return and terminate command loop */
1645 * Do a Restore for Director
1648 static int restore_cmd(JCR *jcr)
1650 BSOCK *dir = jcr->dir_bsock;
1651 BSOCK *sd = jcr->store_bsock;
1653 bool use_regexwhere=false;
1658 * Scan WHERE (base directory for restore) from command
1660 Dmsg0(150, "restore command\n");
1661 /* Pickup where string */
1662 args = get_memory(dir->msglen+1);
1665 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1666 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1667 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1668 pm_strcpy(jcr->errmsg, dir->msg);
1669 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1674 use_regexwhere = true;
1676 /* Turn / into nothing */
1677 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1681 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1682 unbash_spaces(args);
1684 if (use_regexwhere) {
1685 jcr->where_bregexp = get_bregexps(args);
1686 if (!jcr->where_bregexp) {
1687 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1688 free_pool_memory(args);
1692 jcr->where = bstrdup(args);
1695 free_pool_memory(args);
1696 jcr->replace = replace;
1697 jcr->prefix_links = prefix_links;
1699 dir->fsend(OKrestore);
1700 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1702 jcr->JobType = JT_RESTORE;
1704 set_jcr_job_status(jcr, JS_Blocked);
1706 if (!open_sd_read_session(jcr)) {
1707 set_jcr_job_status(jcr, JS_ErrorTerminated);
1711 set_jcr_job_status(jcr, JS_Running);
1714 * Do restore of files and data
1716 start_dir_heartbeat(jcr);
1717 generate_daemon_event(jcr, "JobStart");
1718 generate_plugin_event(jcr, bEventStartRestoreJob);
1720 stop_dir_heartbeat(jcr);
1722 set_jcr_job_status(jcr, JS_Terminated);
1723 if (jcr->JobStatus != JS_Terminated) {
1724 bnet_suppress_error_messages(sd, 1);
1728 * Send Close session command to Storage daemon
1730 sd->fsend(read_close, jcr->Ticket);
1731 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1733 bget_msg(sd); /* get OK */
1735 /* Inform Storage daemon that we are done */
1736 sd->signal(BNET_TERMINATE);
1741 set_jcr_job_status(jcr, JS_ErrorTerminated);
1744 Dmsg0(130, "Done in job.c\n");
1745 generate_plugin_event(jcr, bEventEndRestoreJob);
1746 return 0; /* return and terminate command loop */
1749 static int open_sd_read_session(JCR *jcr)
1751 BSOCK *sd = jcr->store_bsock;
1754 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1757 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1758 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1759 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1761 * Open Read Session with Storage daemon
1763 bnet_fsend(sd, read_open, "DummyVolume",
1764 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1765 jcr->StartBlock, jcr->EndBlock);
1766 Dmsg1(110, ">stored: %s", sd->msg);
1771 if (bget_msg(sd) >= 0) {
1772 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1773 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1774 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1777 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1779 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1783 if (!send_bootstrap_file(jcr)) {
1788 * Start read of data with Storage daemon
1790 bnet_fsend(sd, read_data, jcr->Ticket);
1791 Dmsg1(110, ">stored: %s", sd->msg);
1796 if (!response(jcr, sd, OK_data, "Read Data")) {
1803 * Destroy the Job Control Record and associated
1804 * resources (sockets).
1806 static void filed_free_jcr(JCR *jcr)
1808 if (jcr->store_bsock) {
1809 bnet_close(jcr->store_bsock);
1811 free_bootstrap(jcr);
1812 if (jcr->last_fname) {
1813 free_pool_memory(jcr->last_fname);
1815 free_runscripts(jcr->RunScripts);
1816 delete jcr->RunScripts;
1818 if (jcr->JobId != 0)
1819 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1825 * Get response from Storage daemon to a command we
1826 * sent. Check that the response is OK.
1828 * Returns: 0 on failure
1831 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1836 if (bget_msg(sd) > 0) {
1837 Dmsg0(110, sd->msg);
1838 if (strcmp(sd->msg, resp) == 0) {
1842 if (job_canceled(jcr)) {
1843 return 0; /* if canceled avoid useless error messages */
1845 if (is_bnet_error(sd)) {
1846 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1847 cmd, bnet_strerror(sd));
1849 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1850 cmd, resp, sd->msg);
1855 static int send_bootstrap_file(JCR *jcr)
1859 BSOCK *sd = jcr->store_bsock;
1860 const char *bootstrap = "bootstrap\n";
1863 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1864 if (!jcr->RestoreBootstrap) {
1867 bs = fopen(jcr->RestoreBootstrap, "rb");
1870 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1871 jcr->RestoreBootstrap, be.bstrerror());
1872 set_jcr_job_status(jcr, JS_ErrorTerminated);
1875 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1877 while (fgets(buf, sizeof(buf), bs)) {
1878 sd->msglen = Mmsg(sd->msg, "%s", buf);
1881 bnet_sig(sd, BNET_EOD);
1883 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1884 set_jcr_job_status(jcr, JS_ErrorTerminated);
1890 free_bootstrap(jcr);