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 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1111 * Director is passing his Fileset
1113 static int fileset_cmd(JCR *jcr)
1115 BSOCK *dir = jcr->dir_bsock;
1117 #if defined(WIN32_VSS)
1120 sscanf(dir->msg, "fileset vss=%d", &vss);
1124 if (!init_fileset(jcr)) {
1127 while (dir->recv() >= 0) {
1128 strip_trailing_junk(dir->msg);
1129 Dmsg1(500, "Fileset: %s\n", dir->msg);
1130 add_fileset(jcr, dir->msg);
1132 if (!term_fileset(jcr)) {
1135 return dir->fsend(OKinc);
1138 static void free_bootstrap(JCR *jcr)
1140 if (jcr->RestoreBootstrap) {
1141 unlink(jcr->RestoreBootstrap);
1142 free_pool_memory(jcr->RestoreBootstrap);
1143 jcr->RestoreBootstrap = NULL;
1148 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1149 static uint32_t bsr_uniq = 0;
1152 * The Director sends us the bootstrap file, which
1153 * we will in turn pass to the SD.
1155 static int bootstrap_cmd(JCR *jcr)
1157 BSOCK *dir = jcr->dir_bsock;
1158 POOLMEM *fname = get_pool_memory(PM_FNAME);
1161 free_bootstrap(jcr);
1164 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1165 jcr->Job, bsr_uniq);
1167 Dmsg1(400, "bootstrap=%s\n", fname);
1168 jcr->RestoreBootstrap = fname;
1169 bs = fopen(fname, "a+b"); /* create file */
1172 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1173 jcr->RestoreBootstrap, be.bstrerror());
1175 * Suck up what he is sending to us so that he will then
1176 * read our error message.
1178 while (dir->recv() >= 0)
1180 free_bootstrap(jcr);
1181 set_jcr_job_status(jcr, JS_ErrorTerminated);
1185 while (dir->recv() >= 0) {
1186 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1187 fputs(dir->msg, bs);
1191 * Note, do not free the bootstrap yet -- it needs to be
1194 return dir->fsend(OKbootstrap);
1199 * Get backup level from Director
1202 static int level_cmd(JCR *jcr)
1204 BSOCK *dir = jcr->dir_bsock;
1205 POOLMEM *level, *buf = NULL;
1208 level = get_memory(dir->msglen+1);
1209 Dmsg1(110, "level_cmd: %s", dir->msg);
1210 if (strstr(dir->msg, "accurate")) {
1211 jcr->accurate = true;
1213 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1216 /* Base backup requested? */
1217 if (strcmp(level, "base") == 0) {
1218 jcr->JobLevel = L_BASE;
1219 /* Full backup requested? */
1220 } else if (strcmp(level, "full") == 0) {
1221 jcr->JobLevel = L_FULL;
1222 } else if (strstr(level, "differential")) {
1223 jcr->JobLevel = L_DIFFERENTIAL;
1226 } else if (strstr(level, "incremental")) {
1227 jcr->JobLevel = L_INCREMENTAL;
1231 * We get his UTC since time, then sync the clocks and correct it
1232 * to agree with our clock.
1234 } else if (strcmp(level, "since_utime") == 0) {
1235 buf = get_memory(dir->msglen+1);
1236 utime_t since_time, adj;
1237 btime_t his_time, bt_start, rt=0, bt_adj=0;
1238 if (jcr->JobLevel == L_NONE) {
1239 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1241 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1242 buf, &mtime_only) != 2) {
1245 since_time = str_to_uint64(buf); /* this is the since time */
1246 Dmsg1(100, "since_time=%d\n", (int)since_time);
1247 char ed1[50], ed2[50];
1249 * Sync clocks by polling him for the time. We take
1250 * 10 samples of his time throwing out the first two.
1252 for (int i=0; i<10; i++) {
1253 bt_start = get_current_btime();
1254 dir->signal(BNET_BTIME); /* poll for time */
1255 if (dir->recv() <= 0) { /* get response */
1258 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1261 if (i < 2) { /* toss first two results */
1264 his_time = str_to_uint64(buf);
1265 rt = get_current_btime() - bt_start; /* compute round trip time */
1266 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1267 edit_uint64(bt_start, ed2));
1268 bt_adj += bt_start - his_time - rt/2;
1269 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1272 bt_adj = bt_adj / 8; /* compute average time */
1273 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1274 adj = btime_to_utime(bt_adj);
1275 since_time += adj; /* adjust for clock difference */
1276 /* Don't notify if time within 3 seconds */
1277 if (adj > 3 || adj < -3) {
1279 if (adj > 600 || adj < -600) {
1284 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1286 dir->signal(BNET_EOD);
1288 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1289 jcr->incremental = 1; /* set incremental or decremental backup */
1290 jcr->mtime = (time_t)since_time; /* set since time */
1291 generate_plugin_event(jcr, bEventSince, (void *)jcr->mtime);
1293 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1301 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1302 return dir->fsend(OKlevel);
1305 pm_strcpy(jcr->errmsg, dir->msg);
1306 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1315 * Get session parameters from Director -- this is for a Restore command
1317 static int session_cmd(JCR *jcr)
1319 BSOCK *dir = jcr->dir_bsock;
1321 Dmsg1(100, "SessionCmd: %s", dir->msg);
1322 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1323 &jcr->VolSessionId, &jcr->VolSessionTime,
1324 &jcr->StartFile, &jcr->EndFile,
1325 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1326 pm_strcpy(jcr->errmsg, dir->msg);
1327 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1331 return bnet_fsend(dir, OKsession);
1335 * Get address of storage daemon from Director
1338 static int storage_cmd(JCR *jcr)
1340 int stored_port; /* storage daemon port */
1341 int enable_ssl; /* enable ssl to sd */
1342 BSOCK *dir = jcr->dir_bsock;
1343 BSOCK *sd; /* storage daemon bsock */
1345 Dmsg1(100, "StorageCmd: %s", dir->msg);
1346 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1347 pm_strcpy(jcr->errmsg, dir->msg);
1348 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1351 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1352 /* Open command communications with Storage daemon */
1353 /* Try to connect for 1 hour at 10 second intervals */
1354 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1355 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1357 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1358 jcr->stored_addr, stored_port);
1359 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1360 jcr->stored_addr, stored_port);
1363 Dmsg0(110, "Connection OK to SD.\n");
1365 jcr->store_bsock = sd;
1367 sd->fsend("Hello Start Job %s\n", jcr->Job);
1368 if (!authenticate_storagedaemon(jcr)) {
1369 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1372 Dmsg0(110, "Authenticated with SD.\n");
1374 /* Send OK to Director */
1375 return dir->fsend(OKstore);
1382 static int backup_cmd(JCR *jcr)
1384 BSOCK *dir = jcr->dir_bsock;
1385 BSOCK *sd = jcr->store_bsock;
1389 #if defined(WIN32_VSS)
1390 // capture state here, if client is backed up by multiple directors
1391 // and one enables vss and the other does not then enable_vss can change
1392 // between here and where its evaluated after the job completes.
1393 jcr->VSS = g_pVSSClient && enable_vss;
1395 /* Run only one at a time */
1400 set_jcr_job_status(jcr, JS_Blocked);
1401 jcr->JobType = JT_BACKUP;
1402 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1405 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1409 dir->fsend(OKbackup);
1410 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1413 * Send Append Open Session to Storage daemon
1415 sd->fsend(append_open);
1416 Dmsg1(110, ">stored: %s", sd->msg);
1418 * Expect to receive back the Ticket number
1420 if (bget_msg(sd) >= 0) {
1421 Dmsg1(110, "<stored: %s", sd->msg);
1422 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1423 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1426 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1428 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1433 * Send Append data command to Storage daemon
1435 sd->fsend(append_data, jcr->Ticket);
1436 Dmsg1(110, ">stored: %s", sd->msg);
1439 * Expect to get OK data
1441 Dmsg1(110, "<stored: %s", sd->msg);
1442 if (!response(jcr, sd, OK_data, "Append Data")) {
1446 generate_daemon_event(jcr, "JobStart");
1447 generate_plugin_event(jcr, bEventStartBackupJob);
1449 #if defined(WIN32_VSS)
1450 /* START VSS ON WIN32 */
1452 if (g_pVSSClient->InitializeForBackup()) {
1453 /* tell vss which drives to snapshot */
1454 char szWinDriveLetters[27];
1455 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1456 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1457 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1458 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1461 /* tell user if snapshot creation of a specific drive failed */
1463 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1464 if (islower(szWinDriveLetters[i])) {
1465 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1469 /* inform user about writer states */
1470 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1471 if (g_pVSSClient->GetWriterState(i) < 1) {
1472 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1477 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1481 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1487 * Send Files to Storage daemon
1489 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1490 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1491 set_jcr_job_status(jcr, JS_ErrorTerminated);
1492 bnet_suppress_error_messages(sd, 1);
1493 bget_msg(sd); /* Read final response from append_data */
1494 Dmsg0(110, "Error in blast_data.\n");
1496 set_jcr_job_status(jcr, JS_Terminated);
1498 if (jcr->JobStatus != JS_Terminated) {
1499 bnet_suppress_error_messages(sd, 1);
1500 goto cleanup; /* bail out now */
1503 * Expect to get response to append_data from Storage daemon
1505 if (!response(jcr, sd, OK_append, "Append Data")) {
1506 set_jcr_job_status(jcr, JS_ErrorTerminated);
1511 * Send Append End Data to Storage daemon
1513 sd->fsend(append_end, jcr->Ticket);
1515 if (!response(jcr, sd, OK_end, "Append End")) {
1516 set_jcr_job_status(jcr, JS_ErrorTerminated);
1521 * Send Append Close to Storage daemon
1523 sd->fsend(append_close, jcr->Ticket);
1524 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1525 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1527 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1531 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1534 if (SDJobStatus != JS_Terminated) {
1535 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1541 #if defined(WIN32_VSS)
1542 /* STOP VSS ON WIN32 */
1543 /* tell vss to close the backup session */
1545 if (g_pVSSClient->CloseBackup()) {
1546 /* inform user about writer states */
1547 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1548 int msg_type = M_INFO;
1549 if (g_pVSSClient->GetWriterState(i) < 1) {
1550 msg_type = M_WARNING;
1553 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1560 generate_plugin_event(jcr, bEventEndBackupJob);
1561 return 0; /* return and stop command loop */
1565 * Do a Verify for Director
1568 static int verify_cmd(JCR *jcr)
1570 BSOCK *dir = jcr->dir_bsock;
1571 BSOCK *sd = jcr->store_bsock;
1574 jcr->JobType = JT_VERIFY;
1575 if (sscanf(dir->msg, verifycmd, level) != 1) {
1576 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1580 if (strcasecmp(level, "init") == 0) {
1581 jcr->JobLevel = L_VERIFY_INIT;
1582 } else if (strcasecmp(level, "catalog") == 0){
1583 jcr->JobLevel = L_VERIFY_CATALOG;
1584 } else if (strcasecmp(level, "volume") == 0){
1585 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1586 } else if (strcasecmp(level, "data") == 0){
1587 jcr->JobLevel = L_VERIFY_DATA;
1588 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1589 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1591 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1595 dir->fsend(OKverify);
1597 generate_daemon_event(jcr, "JobStart");
1598 generate_plugin_event(jcr, bEventLevel, (void *)jcr->JobLevel);
1599 generate_plugin_event(jcr, bEventStartVerifyJob);
1601 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1603 switch (jcr->JobLevel) {
1605 case L_VERIFY_CATALOG:
1608 case L_VERIFY_VOLUME_TO_CATALOG:
1609 if (!open_sd_read_session(jcr)) {
1612 start_dir_heartbeat(jcr);
1613 do_verify_volume(jcr);
1614 stop_dir_heartbeat(jcr);
1616 * Send Close session command to Storage daemon
1618 sd->fsend(read_close, jcr->Ticket);
1619 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1621 /* ****FIXME**** check response */
1622 bget_msg(sd); /* get OK */
1624 /* Inform Storage daemon that we are done */
1625 sd->signal(BNET_TERMINATE);
1628 case L_VERIFY_DISK_TO_CATALOG:
1632 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1636 dir->signal(BNET_EOD);
1637 generate_plugin_event(jcr, bEventEndVerifyJob);
1638 return 0; /* return and terminate command loop */
1642 * Do a Restore for Director
1645 static int restore_cmd(JCR *jcr)
1647 BSOCK *dir = jcr->dir_bsock;
1648 BSOCK *sd = jcr->store_bsock;
1650 bool use_regexwhere=false;
1655 * Scan WHERE (base directory for restore) from command
1657 Dmsg0(150, "restore command\n");
1658 /* Pickup where string */
1659 args = get_memory(dir->msglen+1);
1662 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1663 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1664 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1665 pm_strcpy(jcr->errmsg, dir->msg);
1666 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1671 use_regexwhere = true;
1673 /* Turn / into nothing */
1674 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1678 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1679 unbash_spaces(args);
1681 if (use_regexwhere) {
1682 jcr->where_bregexp = get_bregexps(args);
1683 if (!jcr->where_bregexp) {
1684 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1685 free_pool_memory(args);
1689 jcr->where = bstrdup(args);
1692 free_pool_memory(args);
1693 jcr->replace = replace;
1694 jcr->prefix_links = prefix_links;
1696 dir->fsend(OKrestore);
1697 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1699 jcr->JobType = JT_RESTORE;
1701 set_jcr_job_status(jcr, JS_Blocked);
1703 if (!open_sd_read_session(jcr)) {
1704 set_jcr_job_status(jcr, JS_ErrorTerminated);
1708 set_jcr_job_status(jcr, JS_Running);
1711 * Do restore of files and data
1713 start_dir_heartbeat(jcr);
1714 generate_daemon_event(jcr, "JobStart");
1715 generate_plugin_event(jcr, bEventStartRestoreJob);
1717 stop_dir_heartbeat(jcr);
1719 set_jcr_job_status(jcr, JS_Terminated);
1720 if (jcr->JobStatus != JS_Terminated) {
1721 bnet_suppress_error_messages(sd, 1);
1725 * Send Close session command to Storage daemon
1727 sd->fsend(read_close, jcr->Ticket);
1728 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1730 bget_msg(sd); /* get OK */
1732 /* Inform Storage daemon that we are done */
1733 sd->signal(BNET_TERMINATE);
1738 set_jcr_job_status(jcr, JS_ErrorTerminated);
1741 Dmsg0(130, "Done in job.c\n");
1742 generate_plugin_event(jcr, bEventEndRestoreJob);
1743 return 0; /* return and terminate command loop */
1746 static int open_sd_read_session(JCR *jcr)
1748 BSOCK *sd = jcr->store_bsock;
1751 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1754 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1755 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1756 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1758 * Open Read Session with Storage daemon
1760 bnet_fsend(sd, read_open, "DummyVolume",
1761 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1762 jcr->StartBlock, jcr->EndBlock);
1763 Dmsg1(110, ">stored: %s", sd->msg);
1768 if (bget_msg(sd) >= 0) {
1769 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1770 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1771 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1774 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1776 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1780 if (!send_bootstrap_file(jcr)) {
1785 * Start read of data with Storage daemon
1787 bnet_fsend(sd, read_data, jcr->Ticket);
1788 Dmsg1(110, ">stored: %s", sd->msg);
1793 if (!response(jcr, sd, OK_data, "Read Data")) {
1800 * Destroy the Job Control Record and associated
1801 * resources (sockets).
1803 static void filed_free_jcr(JCR *jcr)
1805 if (jcr->store_bsock) {
1806 bnet_close(jcr->store_bsock);
1808 free_bootstrap(jcr);
1809 if (jcr->last_fname) {
1810 free_pool_memory(jcr->last_fname);
1812 free_runscripts(jcr->RunScripts);
1813 delete jcr->RunScripts;
1815 if (jcr->JobId != 0)
1816 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
1822 * Get response from Storage daemon to a command we
1823 * sent. Check that the response is OK.
1825 * Returns: 0 on failure
1828 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1833 if (bget_msg(sd) > 0) {
1834 Dmsg0(110, sd->msg);
1835 if (strcmp(sd->msg, resp) == 0) {
1839 if (job_canceled(jcr)) {
1840 return 0; /* if canceled avoid useless error messages */
1842 if (is_bnet_error(sd)) {
1843 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1844 cmd, bnet_strerror(sd));
1846 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1847 cmd, resp, sd->msg);
1852 static int send_bootstrap_file(JCR *jcr)
1856 BSOCK *sd = jcr->store_bsock;
1857 const char *bootstrap = "bootstrap\n";
1860 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1861 if (!jcr->RestoreBootstrap) {
1864 bs = fopen(jcr->RestoreBootstrap, "rb");
1867 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1868 jcr->RestoreBootstrap, be.bstrerror());
1869 set_jcr_job_status(jcr, JS_ErrorTerminated);
1872 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1874 while (fgets(buf, sizeof(buf), bs)) {
1875 sd->msglen = Mmsg(sd->msg, "%s", buf);
1878 bnet_sig(sd, BNET_EOD);
1880 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1881 set_jcr_job_status(jcr, JS_ErrorTerminated);
1887 free_bootstrap(jcr);