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);
53 /* Forward referenced functions */
54 static int backup_cmd(JCR *jcr);
55 static int bootstrap_cmd(JCR *jcr);
56 static int cancel_cmd(JCR *jcr);
57 static int setdebug_cmd(JCR *jcr);
58 static int estimate_cmd(JCR *jcr);
59 static int hello_cmd(JCR *jcr);
60 static int job_cmd(JCR *jcr);
61 static int fileset_cmd(JCR *jcr);
62 static int level_cmd(JCR *jcr);
63 static int verify_cmd(JCR *jcr);
64 static int restore_cmd(JCR *jcr);
65 static int storage_cmd(JCR *jcr);
66 static int session_cmd(JCR *jcr);
67 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
68 static void filed_free_jcr(JCR *jcr);
69 static int open_sd_read_session(JCR *jcr);
70 static int send_bootstrap_file(JCR *jcr);
71 static int runscript_cmd(JCR *jcr);
72 static int runbefore_cmd(JCR *jcr);
73 static int runafter_cmd(JCR *jcr);
74 static int runbeforenow_cmd(JCR *jcr);
75 static void set_options(findFOPTS *fo, const char *opts);
78 /* Exported functions */
83 int monitoraccess; /* specify if monitors have access to this function */
87 * The following are the recognized commands from the Director.
89 static struct s_cmds cmds[] = {
90 {"backup", backup_cmd, 0},
91 {"cancel", cancel_cmd, 0},
92 {"setdebug=", setdebug_cmd, 0},
93 {"estimate", estimate_cmd, 0},
94 {"Hello", hello_cmd, 1},
95 {"fileset", fileset_cmd, 0},
96 {"JobId=", job_cmd, 0},
97 {"level = ", level_cmd, 0},
98 {"restore", restore_cmd, 0},
99 {"session", session_cmd, 0},
100 {"status", status_cmd, 1},
101 {".status", qstatus_cmd, 1},
102 {"storage ", storage_cmd, 0},
103 {"verify", verify_cmd, 0},
104 {"bootstrap", bootstrap_cmd, 0},
105 {"RunBeforeNow", runbeforenow_cmd, 0},
106 {"RunBeforeJob", runbefore_cmd, 0},
107 {"RunAfterJob", runafter_cmd, 0},
108 {"Run", runscript_cmd, 0},
109 {NULL, NULL} /* list terminator */
112 /* Commands received from director that need scanning */
113 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
114 static char storaddr[] = "storage address=%s port=%d ssl=%d";
115 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
116 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
117 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
118 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
119 static char verifycmd[] = "verify level=%30s";
120 static char estimatecmd[] = "estimate listing=%d";
121 static char runbefore[] = "RunBeforeJob %s";
122 static char runafter[] = "RunAfterJob %s";
123 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
125 /* Responses sent to Director */
126 static char errmsg[] = "2999 Invalid command\n";
127 static char no_auth[] = "2998 No Authorization\n";
128 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
129 static char OKinc[] = "2000 OK include\n";
130 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
131 static char OKlevel[] = "2000 OK level\n";
132 static char OKbackup[] = "2000 OK backup\n";
133 static char OKbootstrap[] = "2000 OK bootstrap\n";
134 static char OKverify[] = "2000 OK verify\n";
135 static char OKrestore[] = "2000 OK restore\n";
136 static char OKsession[] = "2000 OK session\n";
137 static char OKstore[] = "2000 OK storage\n";
138 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
139 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
140 static char BADjob[] = "2901 Bad Job\n";
141 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
142 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
143 static char OKRunBefore[] = "2000 OK RunBefore\n";
144 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
145 static char OKRunAfter[] = "2000 OK RunAfter\n";
146 static char OKRunScript[] = "2000 OK RunScript\n";
149 /* Responses received from Storage Daemon */
150 static char OK_end[] = "3000 OK end\n";
151 static char OK_close[] = "3000 OK close Status = %d\n";
152 static char OK_open[] = "3000 OK open ticket = %d\n";
153 static char OK_data[] = "3000 OK data\n";
154 static char OK_append[] = "3000 OK append data\n";
155 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
158 /* Commands sent to Storage Daemon */
159 static char append_open[] = "append open session\n";
160 static char append_data[] = "append data %d\n";
161 static char append_end[] = "append end session %d\n";
162 static char append_close[] = "append close session %d\n";
163 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
164 static char read_data[] = "read data %d\n";
165 static char read_close[] = "read close session %d\n";
168 * Accept requests from a Director
170 * NOTE! We are running as a separate thread
172 * Send output one line
173 * at a time followed by a zero length transmission.
175 * Return when the connection is terminated or there
178 * Basic task here is:
179 * Authenticate Director (during Hello command).
180 * Accept commands one at a time from the Director
183 * Concerning ClientRunBefore/After, the sequence of events
184 * is rather critical. If they are not done in the right
185 * order one can easily get FD->SD timeouts if the script
188 * The current sequence of events is:
189 * 1. Dir starts job with FD
190 * 2. Dir connects to SD
191 * 3. Dir connects to FD
192 * 4. FD connects to SD
193 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
194 * 6. Dir sends include/exclude
195 * 7. FD sends data to SD
196 * 8. SD/FD disconnects while SD despools data and attributes (optionnal)
197 * 9. FD runs ClientRunAfterJob
200 void *handle_client_request(void *dirp)
205 BSOCK *dir = (BSOCK *)dirp;
207 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
208 jcr->dir_bsock = dir;
209 jcr->ff = init_find_files();
210 jcr->start_time = time(NULL);
211 jcr->RunScripts = New(alist(10, not_owned_by_alist));
212 jcr->last_fname = get_pool_memory(PM_FNAME);
213 jcr->last_fname[0] = 0;
214 jcr->client_name = get_memory(strlen(my_name) + 1);
215 new_plugins(jcr); /* instantiate plugins for this jcr */
216 pm_strcpy(jcr->client_name, my_name);
217 jcr->pki_sign = me->pki_sign;
218 jcr->pki_encrypt = me->pki_encrypt;
219 jcr->pki_keypair = me->pki_keypair;
220 jcr->pki_signers = me->pki_signers;
221 jcr->pki_recipients = me->pki_recipients;
223 enable_backup_privileges(NULL, 1 /* ignore_errors */);
225 /**********FIXME******* add command handler error code */
227 for (quit=false; !quit;) {
230 if (bnet_recv(dir) < 0) {
231 break; /* connection terminated */
233 dir->msg[dir->msglen] = 0;
234 Dmsg1(100, "<dird: %s", dir->msg);
236 for (i=0; cmds[i].cmd; i++) {
237 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
238 found = true; /* indicate command found */
239 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
240 bnet_fsend(dir, no_auth);
241 bnet_sig(dir, BNET_EOD);
244 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
245 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
246 bnet_fsend(dir, invalid_cmd);
247 bnet_sig(dir, BNET_EOD);
250 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
251 if (!cmds[i].func(jcr)) { /* do command */
252 quit = true; /* error or fully terminated, get out */
253 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
258 if (!found) { /* command not found */
259 bnet_fsend(dir, errmsg);
265 /* Inform Storage daemon that we are done */
266 if (jcr->store_bsock) {
267 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
270 /* Run the after job */
271 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
273 if (jcr->JobId) { /* send EndJob if running a job */
274 char ed1[50], ed2[50];
275 /* Send termination status back to Dir */
276 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
277 edit_uint64(jcr->ReadBytes, ed1),
278 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, jcr->VSS,
280 Dmsg1(110, "End FD msg: %s\n", dir->msg);
283 generate_daemon_event(jcr, "JobEnd");
284 generate_plugin_event(jcr, bEventJobEnd);
286 dequeue_messages(jcr); /* send any queued messages */
288 /* Inform Director that we are done */
289 dir->signal(BNET_TERMINATE);
291 free_plugins(jcr); /* release instantiated plugins */
293 /* Clean up fileset */
294 FF_PKT *ff = jcr->ff;
295 findFILESET *fileset = ff->fileset;
298 /* Delete FileSet Include lists */
299 for (i=0; i<fileset->include_list.size(); i++) {
300 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
301 for (j=0; j<incexe->opts_list.size(); j++) {
302 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
303 for (k=0; k<fo->regex.size(); k++) {
304 regfree((regex_t *)fo->regex.get(k));
307 fo->regexdir.destroy();
308 fo->regexfile.destroy();
310 fo->wilddir.destroy();
311 fo->wildfile.destroy();
312 fo->wildbase.destroy();
314 fo->fstype.destroy();
315 fo->drivetype.destroy();
323 incexe->opts_list.destroy();
324 incexe->name_list.destroy();
326 fileset->include_list.destroy();
328 /* Delete FileSet Exclude lists */
329 for (i=0; i<fileset->exclude_list.size(); i++) {
330 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
331 for (j=0; j<incexe->opts_list.size(); j++) {
332 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
334 fo->regexdir.destroy();
335 fo->regexfile.destroy();
337 fo->wilddir.destroy();
338 fo->wildfile.destroy();
339 fo->wildbase.destroy();
341 fo->fstype.destroy();
342 fo->drivetype.destroy();
344 incexe->opts_list.destroy();
345 incexe->name_list.destroy();
347 fileset->exclude_list.destroy();
351 Dmsg0(100, "Calling term_find_files\n");
352 term_find_files(jcr->ff);
354 Dmsg0(100, "Done with term_find_files\n");
355 free_jcr(jcr); /* destroy JCR record */
356 Dmsg0(100, "Done with free_jcr\n");
362 * Hello from Director he must identify himself and provide his
365 static int hello_cmd(JCR *jcr)
367 Dmsg0(120, "Calling Authenticate\n");
368 if (!authenticate_director(jcr)) {
371 Dmsg0(120, "OK Authenticate\n");
372 jcr->authenticated = true;
379 static int cancel_cmd(JCR *jcr)
381 BSOCK *dir = jcr->dir_bsock;
382 char Job[MAX_NAME_LENGTH];
385 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
386 if (!(cjcr=get_jcr_by_full_name(Job))) {
387 dir->fsend(_("2901 Job %s not found.\n"), Job);
389 if (cjcr->store_bsock) {
390 cjcr->store_bsock->set_timed_out();
391 cjcr->store_bsock->set_terminated();
392 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
394 set_jcr_job_status(cjcr, JS_Canceled);
396 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
399 dir->fsend(_("2902 Error scanning cancel command.\n"));
401 dir->signal(BNET_EOD);
407 * Set debug level as requested by the Director
410 static int setdebug_cmd(JCR *jcr)
412 BSOCK *dir = jcr->dir_bsock;
413 int level, trace_flag;
415 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
416 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
417 pm_strcpy(jcr->errmsg, dir->msg);
418 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
422 set_trace(trace_flag);
423 return dir->fsend(OKsetdebug, level);
427 static int estimate_cmd(JCR *jcr)
429 BSOCK *dir = jcr->dir_bsock;
432 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
433 pm_strcpy(jcr->errmsg, dir->msg);
434 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
435 dir->fsend(_("2992 Bad estimate command.\n"));
439 dir->fsend(OKest, jcr->num_files_examined,
440 edit_uint64_with_commas(jcr->JobBytes, ed2));
441 dir->signal(BNET_EOD);
446 * Get JobId and Storage Daemon Authorization key from Director
448 static int job_cmd(JCR *jcr)
450 BSOCK *dir = jcr->dir_bsock;
451 POOLMEM *sd_auth_key;
453 sd_auth_key = get_memory(dir->msglen);
454 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
455 &jcr->VolSessionId, &jcr->VolSessionTime,
457 pm_strcpy(jcr->errmsg, dir->msg);
458 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
460 free_pool_memory(sd_auth_key);
463 jcr->sd_auth_key = bstrdup(sd_auth_key);
464 free_pool_memory(sd_auth_key);
465 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
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)
648 p++; /* skip over | */
649 fn = get_pool_memory(PM_FNAME);
650 fn = edit_job_codes(jcr, fn, p, "");
651 bpipe = open_bpipe(fn, 0, "r");
654 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
656 free_pool_memory(fn);
659 free_pool_memory(fn);
660 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
661 strip_trailing_junk(buf);
662 fileset->incexe->name_list.append(new_dlistString(buf));
664 if ((stat=close_bpipe(bpipe)) != 0) {
666 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
667 p, be.code(stat), be.bstrerror(stat));
672 Dmsg0(100, "Doing < include on client.\n");
673 p++; /* skip over < */
674 if ((ffd = fopen(p, "rb")) == NULL) {
676 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
680 while (fgets(buf, sizeof(buf), ffd)) {
681 strip_trailing_junk(buf);
682 Dmsg1(100, "%s\n", buf);
683 fileset->incexe->name_list.append(new_dlistString(buf));
688 fileset->incexe->name_list.append(new_dlistString(fname));
694 static void add_fileset(JCR *jcr, const char *item)
696 FF_PKT *ff = jcr->ff;
697 findFILESET *fileset = ff->fileset;
698 int state = fileset->state;
699 findFOPTS *current_opts;
701 /* Get code, optional subcode, and position item past the dividing space */
702 Dmsg1(100, "%s\n", item);
707 int subcode = ' '; /* A space is always a valid subcode */
708 if (item[0] != '\0' && item[0] != ' ') {
716 /* Skip all lines we receive after an error */
717 if (state == state_error) {
718 Dmsg0(100, "State=error return\n");
723 * The switch tests the code for validity.
724 * The subcode is always good if it is a space, otherwise we must confirm.
725 * We set state to state_error first assuming the subcode is invalid,
726 * requiring state to be set in cases below that handle subcodes.
728 if (subcode != ' ') {
730 Dmsg0(100, "Set state=error\n");
735 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
736 memset(fileset->incexe, 0, sizeof(findINCEXE));
737 fileset->incexe->opts_list.init(1, true);
738 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
739 fileset->include_list.append(fileset->incexe);
743 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
744 memset(fileset->incexe, 0, sizeof(findINCEXE));
745 fileset->incexe->opts_list.init(1, true);
746 fileset->incexe->name_list.init();
747 fileset->exclude_list.append(fileset->incexe);
753 /* File item to either include/include list */
754 state = state_include;
755 add_file_to_fileset(jcr, item, fileset);
758 current_opts = start_options(ff);
762 preg = (regex_t *)malloc(sizeof(regex_t));
763 if (current_opts->flags & FO_IGNORECASE) {
764 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
766 rc = regcomp(preg, item, REG_EXTENDED);
769 regerror(rc, preg, prbuf, sizeof(prbuf));
772 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
776 state = state_options;
777 if (subcode == ' ') {
778 current_opts->regex.append(preg);
779 } else if (subcode == 'D') {
780 current_opts->regexdir.append(preg);
781 } else if (subcode == 'F') {
782 current_opts->regexfile.append(preg);
788 current_opts = start_options(ff);
789 current_opts->base.append(bstrdup(item));
790 state = state_options;
793 current_opts = start_options(ff);
794 state = state_options;
795 if (subcode == ' ') {
796 current_opts->fstype.append(bstrdup(item));
797 } else if (subcode == 'D') {
798 current_opts->drivetype.append(bstrdup(item));
804 current_opts = start_options(ff);
805 state = state_options;
806 if (subcode == ' ') {
807 current_opts->wild.append(bstrdup(item));
808 } else if (subcode == 'D') {
809 current_opts->wilddir.append(bstrdup(item));
810 } else if (subcode == 'F') {
811 current_opts->wildfile.append(bstrdup(item));
812 } else if (subcode == 'B') {
813 current_opts->wildbase.append(bstrdup(item));
819 current_opts = start_options(ff);
820 set_options(current_opts, item);
821 state = state_options;
824 current_opts = start_options(ff);
825 current_opts->reader = bstrdup(item);
826 state = state_options;
829 current_opts = start_options(ff);
830 current_opts->writer = bstrdup(item);
831 state = state_options;
834 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
838 ff->fileset->state = state;
841 static bool term_fileset(JCR *jcr)
843 FF_PKT *ff = jcr->ff;
845 #ifdef xxx_DEBUG_CODE
846 findFILESET *fileset = ff->fileset;
849 for (i=0; i<fileset->include_list.size(); i++) {
850 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
852 for (j=0; j<incexe->opts_list.size(); j++) {
853 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
854 for (k=0; k<fo->regex.size(); k++) {
855 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
857 for (k=0; k<fo->regexdir.size(); k++) {
858 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
860 for (k=0; k<fo->regexfile.size(); k++) {
861 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
863 for (k=0; k<fo->wild.size(); k++) {
864 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
866 for (k=0; k<fo->wilddir.size(); k++) {
867 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
869 for (k=0; k<fo->wildfile.size(); k++) {
870 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
872 for (k=0; k<fo->wildbase.size(); k++) {
873 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
875 for (k=0; k<fo->base.size(); k++) {
876 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
878 for (k=0; k<fo->fstype.size(); k++) {
879 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
881 for (k=0; k<fo->drivetype.size(); k++) {
882 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
885 Dmsg1(400, "D %s\n", fo->reader);
888 Dmsg1(400, "T %s\n", fo->writer);
892 foreach_dlist(node, &incexe->name_list) {
893 Dmsg1(400, "F %s\n", node->c_str());
896 for (i=0; i<fileset->exclude_list.size(); i++) {
897 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
899 for (j=0; j<incexe->opts_list.size(); j++) {
900 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
901 for (k=0; k<fo->regex.size(); k++) {
902 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
904 for (k=0; k<fo->regexdir.size(); k++) {
905 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
907 for (k=0; k<fo->regexfile.size(); k++) {
908 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
910 for (k=0; k<fo->wild.size(); k++) {
911 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
913 for (k=0; k<fo->wilddir.size(); k++) {
914 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
916 for (k=0; k<fo->wildfile.size(); k++) {
917 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
919 for (k=0; k<fo->wildbase.size(); k++) {
920 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
922 for (k=0; k<fo->base.size(); k++) {
923 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
925 for (k=0; k<fo->fstype.size(); k++) {
926 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
928 for (k=0; k<fo->drivetype.size(); k++) {
929 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
933 foreach_dlist(node, incexe->name_list) {
934 Dmsg1(400, "F %s\n", node->c_str());
938 return ff->fileset->state != state_error;
943 * As an optimization, we should do this during
944 * "compile" time in filed/job.c, and keep only a bit mask
945 * and the Verify options.
947 static void set_options(findFOPTS *fo, const char *opts)
953 // Commented out as it is not backward compatible - KES
955 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
958 for (p=opts; *p; p++) {
960 case 'a': /* alway replace */
961 case '0': /* no option */
964 fo->flags |= FO_EXCLUDE;
967 fo->flags |= FO_MULTIFS;
969 case 'h': /* no recursion */
970 fo->flags |= FO_NO_RECURSION;
972 case 'H': /* no hard link handling */
973 fo->flags |= FO_NO_HARDLINK;
976 fo->flags |= FO_IGNORECASE;
982 fo->flags |= FO_NOREPLACE;
984 case 'p': /* use portable data format */
985 fo->flags |= FO_PORTABLE;
987 case 'R': /* Resource forks and Finder Info */
988 fo->flags |= FO_HFSPLUS;
989 case 'r': /* read fifo */
990 fo->flags |= FO_READFIFO;
995 fo->flags |= FO_SHA1;
1000 fo->flags |= FO_SHA256;
1004 fo->flags |= FO_SHA512;
1010 * If 2 or 3 is seen here, SHA2 is not configured, so
1011 * eat the option, and drop back to SHA-1.
1013 if (p[1] == '2' || p[1] == '3') {
1016 fo->flags |= FO_SHA1;
1021 fo->flags |= FO_SPARSE;
1024 fo->flags |= FO_MTIMEONLY;
1027 fo->flags |= FO_KEEPATIME;
1030 fo->flags |= FO_ACL;
1032 case 'V': /* verify options */
1033 /* Copy Verify Options */
1034 for (j=0; *p && *p != ':'; p++) {
1035 fo->VerifyOpts[j] = *p;
1036 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1040 fo->VerifyOpts[j] = 0;
1042 case 'P': /* strip path */
1045 for (j=0; *p && *p != ':'; p++) {
1047 if (j < (int)sizeof(strip) - 1) {
1052 fo->strip_path = atoi(strip);
1053 fo->flags |= FO_STRIPPATH;
1054 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1057 fo->flags |= FO_IF_NEWER;
1060 fo->flags |= FO_ENHANCEDWILD;
1062 case 'Z': /* gzip compression */
1063 fo->flags |= FO_GZIP;
1064 fo->GZIP_level = *++p - '0';
1067 fo->flags |= FO_NOATIME;
1070 fo->flags |= FO_CHKCHANGES;
1073 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1081 * Director is passing his Fileset
1083 static int fileset_cmd(JCR *jcr)
1085 BSOCK *dir = jcr->dir_bsock;
1087 #if defined(WIN32_VSS)
1090 sscanf(dir->msg, "fileset vss=%d", &vss);
1094 if (!init_fileset(jcr)) {
1097 while (dir->recv() >= 0) {
1098 strip_trailing_junk(dir->msg);
1099 Dmsg1(500, "Fileset: %s\n", dir->msg);
1100 add_fileset(jcr, dir->msg);
1102 if (!term_fileset(jcr)) {
1105 return bnet_fsend(dir, OKinc);
1108 static void free_bootstrap(JCR *jcr)
1110 if (jcr->RestoreBootstrap) {
1111 unlink(jcr->RestoreBootstrap);
1112 free_pool_memory(jcr->RestoreBootstrap);
1113 jcr->RestoreBootstrap = NULL;
1118 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1119 static uint32_t bsr_uniq = 0;
1122 * The Director sends us the bootstrap file, which
1123 * we will in turn pass to the SD.
1125 static int bootstrap_cmd(JCR *jcr)
1127 BSOCK *dir = jcr->dir_bsock;
1128 POOLMEM *fname = get_pool_memory(PM_FNAME);
1131 free_bootstrap(jcr);
1134 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1135 jcr->Job, bsr_uniq);
1137 Dmsg1(400, "bootstrap=%s\n", fname);
1138 jcr->RestoreBootstrap = fname;
1139 bs = fopen(fname, "a+b"); /* create file */
1142 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1143 jcr->RestoreBootstrap, be.bstrerror());
1145 * Suck up what he is sending to us so that he will then
1146 * read our error message.
1148 while (dir->recv() >= 0)
1150 free_bootstrap(jcr);
1151 set_jcr_job_status(jcr, JS_ErrorTerminated);
1155 while (dir->recv() >= 0) {
1156 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1157 fputs(dir->msg, bs);
1161 * Note, do not free the bootstrap yet -- it needs to be
1164 return dir->fsend(OKbootstrap);
1169 * Get backup level from Director
1172 static int level_cmd(JCR *jcr)
1174 BSOCK *dir = jcr->dir_bsock;
1175 POOLMEM *level, *buf = NULL;
1178 level = get_memory(dir->msglen+1);
1179 Dmsg1(110, "level_cmd: %s", dir->msg);
1180 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1183 /* Base backup requested? */
1184 if (strcmp(level, "base") == 0) {
1185 jcr->JobLevel = L_BASE;
1186 /* Full backup requested? */
1187 } else if (strcmp(level, "full") == 0) {
1188 jcr->JobLevel = L_FULL;
1189 } else if (strcmp(level, "differential") == 0) {
1190 jcr->JobLevel = L_DIFFERENTIAL;
1193 } else if (strcmp(level, "incremental") == 0) {
1194 jcr->JobLevel = L_INCREMENTAL;
1198 * We get his UTC since time, then sync the clocks and correct it
1199 * to agree with our clock.
1201 } else if (strcmp(level, "since_utime") == 0) {
1202 buf = get_memory(dir->msglen+1);
1203 utime_t since_time, adj;
1204 btime_t his_time, bt_start, rt=0, bt_adj=0;
1205 if (jcr->JobLevel == L_NONE) {
1206 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1208 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1209 buf, &mtime_only) != 2) {
1212 since_time = str_to_uint64(buf); /* this is the since time */
1213 Dmsg1(100, "since_time=%d\n", (int)since_time);
1214 char ed1[50], ed2[50];
1216 * Sync clocks by polling him for the time. We take
1217 * 10 samples of his time throwing out the first two.
1219 for (int i=0; i<10; i++) {
1220 bt_start = get_current_btime();
1221 dir->signal(BNET_BTIME); /* poll for time */
1222 if (dir->recv() <= 0) { /* get response */
1225 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1228 if (i < 2) { /* toss first two results */
1231 his_time = str_to_uint64(buf);
1232 rt = get_current_btime() - bt_start; /* compute round trip time */
1233 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1234 edit_uint64(bt_start, ed2));
1235 bt_adj += bt_start - his_time - rt/2;
1236 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1239 bt_adj = bt_adj / 8; /* compute average time */
1240 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1241 adj = btime_to_utime(bt_adj);
1242 since_time += adj; /* adjust for clock difference */
1243 /* Don't notify if time within 3 seconds */
1244 if (adj > 3 || adj < -3) {
1246 if (adj > 600 || adj < -600) {
1251 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1253 dir->signal(BNET_EOD);
1255 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1256 jcr->incremental = 1; /* set incremental or decremental backup */
1257 jcr->mtime = (time_t)since_time; /* set since time */
1259 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1267 return dir->fsend(OKlevel);
1270 pm_strcpy(jcr->errmsg, dir->msg);
1271 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1280 * Get session parameters from Director -- this is for a Restore command
1282 static int session_cmd(JCR *jcr)
1284 BSOCK *dir = jcr->dir_bsock;
1286 Dmsg1(100, "SessionCmd: %s", dir->msg);
1287 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1288 &jcr->VolSessionId, &jcr->VolSessionTime,
1289 &jcr->StartFile, &jcr->EndFile,
1290 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1291 pm_strcpy(jcr->errmsg, dir->msg);
1292 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1296 return bnet_fsend(dir, OKsession);
1300 * Get address of storage daemon from Director
1303 static int storage_cmd(JCR *jcr)
1305 int stored_port; /* storage daemon port */
1306 int enable_ssl; /* enable ssl to sd */
1307 BSOCK *dir = jcr->dir_bsock;
1308 BSOCK *sd; /* storage daemon bsock */
1310 Dmsg1(100, "StorageCmd: %s", dir->msg);
1311 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1312 pm_strcpy(jcr->errmsg, dir->msg);
1313 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1316 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1317 /* Open command communications with Storage daemon */
1318 /* Try to connect for 1 hour at 10 second intervals */
1319 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1320 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1322 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1323 jcr->stored_addr, stored_port);
1324 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1325 jcr->stored_addr, stored_port);
1328 Dmsg0(110, "Connection OK to SD.\n");
1330 jcr->store_bsock = sd;
1332 sd->fsend("Hello Start Job %s\n", jcr->Job);
1333 if (!authenticate_storagedaemon(jcr)) {
1334 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1337 Dmsg0(110, "Authenticated with SD.\n");
1339 /* Send OK to Director */
1340 return dir->fsend(OKstore);
1347 static int backup_cmd(JCR *jcr)
1349 BSOCK *dir = jcr->dir_bsock;
1350 BSOCK *sd = jcr->store_bsock;
1354 #if defined(WIN32_VSS)
1355 // capture state here, if client is backed up by multiple directors
1356 // and one enables vss and the other does not then enable_vss can change
1357 // between here and where its evaluated after the job completes.
1358 jcr->VSS = g_pVSSClient && enable_vss;
1360 /* Run only one at a time */
1365 set_jcr_job_status(jcr, JS_Blocked);
1366 jcr->JobType = JT_BACKUP;
1367 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1370 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1374 dir->fsend(OKbackup);
1375 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1378 * Send Append Open Session to Storage daemon
1380 sd->fsend(append_open);
1381 Dmsg1(110, ">stored: %s", sd->msg);
1383 * Expect to receive back the Ticket number
1385 if (bget_msg(sd) >= 0) {
1386 Dmsg1(110, "<stored: %s", sd->msg);
1387 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1388 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1391 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1393 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1398 * Send Append data command to Storage daemon
1400 sd->fsend(append_data, jcr->Ticket);
1401 Dmsg1(110, ">stored: %s", sd->msg);
1404 * Expect to get OK data
1406 Dmsg1(110, "<stored: %s", sd->msg);
1407 if (!response(jcr, sd, OK_data, "Append Data")) {
1411 generate_daemon_event(jcr, "JobStart");
1412 generate_plugin_event(jcr, bEventJobStart);
1414 #if defined(WIN32_VSS)
1415 /* START VSS ON WIN 32 */
1417 if (g_pVSSClient->InitializeForBackup()) {
1418 /* tell vss which drives to snapshot */
1419 char szWinDriveLetters[27];
1420 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1421 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1422 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1423 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1426 /* tell user if snapshot creation of a specific drive failed */
1428 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1429 if (islower(szWinDriveLetters[i])) {
1430 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1434 /* inform user about writer states */
1435 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1436 if (g_pVSSClient->GetWriterState(i) < 1) {
1437 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1442 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1446 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1452 * Send Files to Storage daemon
1454 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1455 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1456 set_jcr_job_status(jcr, JS_ErrorTerminated);
1457 bnet_suppress_error_messages(sd, 1);
1458 bget_msg(sd); /* Read final response from append_data */
1459 Dmsg0(110, "Error in blast_data.\n");
1461 set_jcr_job_status(jcr, JS_Terminated);
1463 if (jcr->JobStatus != JS_Terminated) {
1464 bnet_suppress_error_messages(sd, 1);
1465 goto cleanup; /* bail out now */
1468 * Expect to get response to append_data from Storage daemon
1470 if (!response(jcr, sd, OK_append, "Append Data")) {
1471 set_jcr_job_status(jcr, JS_ErrorTerminated);
1476 * Send Append End Data to Storage daemon
1478 sd->fsend(append_end, jcr->Ticket);
1480 if (!response(jcr, sd, OK_end, "Append End")) {
1481 set_jcr_job_status(jcr, JS_ErrorTerminated);
1486 * Send Append Close to Storage daemon
1488 sd->fsend(append_close, jcr->Ticket);
1489 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1490 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1492 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1496 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1499 if (SDJobStatus != JS_Terminated) {
1500 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1506 #if defined(WIN32_VSS)
1507 /* STOP VSS ON WIN 32 */
1508 /* tell vss to close the backup session */
1510 if (g_pVSSClient->CloseBackup()) {
1511 /* inform user about writer states */
1512 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1513 int msg_type = M_INFO;
1514 if (g_pVSSClient->GetWriterState(i) < 1) {
1515 msg_type = M_WARNING;
1518 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1525 return 0; /* return and stop command loop */
1529 * Do a Verify for Director
1532 static int verify_cmd(JCR *jcr)
1534 BSOCK *dir = jcr->dir_bsock;
1535 BSOCK *sd = jcr->store_bsock;
1538 jcr->JobType = JT_VERIFY;
1539 if (sscanf(dir->msg, verifycmd, level) != 1) {
1540 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1544 if (strcasecmp(level, "init") == 0) {
1545 jcr->JobLevel = L_VERIFY_INIT;
1546 } else if (strcasecmp(level, "catalog") == 0){
1547 jcr->JobLevel = L_VERIFY_CATALOG;
1548 } else if (strcasecmp(level, "volume") == 0){
1549 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1550 } else if (strcasecmp(level, "data") == 0){
1551 jcr->JobLevel = L_VERIFY_DATA;
1552 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1553 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1555 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1559 dir->fsend(OKverify);
1561 generate_daemon_event(jcr, "JobStart");
1562 generate_plugin_event(jcr, bEventJobStart);
1564 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1566 switch (jcr->JobLevel) {
1568 case L_VERIFY_CATALOG:
1571 case L_VERIFY_VOLUME_TO_CATALOG:
1572 if (!open_sd_read_session(jcr)) {
1575 start_dir_heartbeat(jcr);
1576 do_verify_volume(jcr);
1577 stop_dir_heartbeat(jcr);
1579 * Send Close session command to Storage daemon
1581 sd->fsend(read_close, jcr->Ticket);
1582 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1584 /* ****FIXME**** check response */
1585 bget_msg(sd); /* get OK */
1587 /* Inform Storage daemon that we are done */
1588 sd->signal(BNET_TERMINATE);
1591 case L_VERIFY_DISK_TO_CATALOG:
1595 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1599 dir->signal(BNET_EOD);
1601 return 0; /* return and terminate command loop */
1605 * Do a Restore for Director
1608 static int restore_cmd(JCR *jcr)
1610 BSOCK *dir = jcr->dir_bsock;
1611 BSOCK *sd = jcr->store_bsock;
1613 bool use_regexwhere=false;
1618 * Scan WHERE (base directory for restore) from command
1620 Dmsg0(150, "restore command\n");
1621 /* Pickup where string */
1622 args = get_memory(dir->msglen+1);
1625 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1626 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1627 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1628 pm_strcpy(jcr->errmsg, dir->msg);
1629 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1634 use_regexwhere = true;
1636 /* Turn / into nothing */
1637 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1641 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1642 unbash_spaces(args);
1644 if (use_regexwhere) {
1645 jcr->where_bregexp = get_bregexps(args);
1646 if (!jcr->where_bregexp) {
1647 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1648 free_pool_memory(args);
1652 jcr->where = bstrdup(args);
1655 free_pool_memory(args);
1656 jcr->replace = replace;
1657 jcr->prefix_links = prefix_links;
1659 dir->fsend(OKrestore);
1660 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1662 jcr->JobType = JT_RESTORE;
1664 set_jcr_job_status(jcr, JS_Blocked);
1666 if (!open_sd_read_session(jcr)) {
1667 set_jcr_job_status(jcr, JS_ErrorTerminated);
1671 set_jcr_job_status(jcr, JS_Running);
1674 * Do restore of files and data
1676 start_dir_heartbeat(jcr);
1677 generate_daemon_event(jcr, "JobStart");
1678 generate_plugin_event(jcr, bEventJobStart);
1680 stop_dir_heartbeat(jcr);
1682 set_jcr_job_status(jcr, JS_Terminated);
1683 if (jcr->JobStatus != JS_Terminated) {
1684 bnet_suppress_error_messages(sd, 1);
1688 * Send Close session command to Storage daemon
1690 sd->fsend(read_close, jcr->Ticket);
1691 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1693 bget_msg(sd); /* get OK */
1695 /* Inform Storage daemon that we are done */
1696 sd->signal(BNET_TERMINATE);
1701 set_jcr_job_status(jcr, JS_ErrorTerminated);
1704 Dmsg0(130, "Done in job.c\n");
1705 return 0; /* return and terminate command loop */
1708 static int open_sd_read_session(JCR *jcr)
1710 BSOCK *sd = jcr->store_bsock;
1713 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1716 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1717 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1718 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1720 * Open Read Session with Storage daemon
1722 bnet_fsend(sd, read_open, "DummyVolume",
1723 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1724 jcr->StartBlock, jcr->EndBlock);
1725 Dmsg1(110, ">stored: %s", sd->msg);
1730 if (bget_msg(sd) >= 0) {
1731 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1732 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1733 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1736 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1738 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1742 if (!send_bootstrap_file(jcr)) {
1747 * Start read of data with Storage daemon
1749 bnet_fsend(sd, read_data, jcr->Ticket);
1750 Dmsg1(110, ">stored: %s", sd->msg);
1755 if (!response(jcr, sd, OK_data, "Read Data")) {
1762 * Destroy the Job Control Record and associated
1763 * resources (sockets).
1765 static void filed_free_jcr(JCR *jcr)
1767 if (jcr->store_bsock) {
1768 bnet_close(jcr->store_bsock);
1770 free_bootstrap(jcr);
1771 if (jcr->last_fname) {
1772 free_pool_memory(jcr->last_fname);
1774 free_runscripts(jcr->RunScripts);
1775 delete jcr->RunScripts;
1781 * Get response from Storage daemon to a command we
1782 * sent. Check that the response is OK.
1784 * Returns: 0 on failure
1787 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1792 if (bget_msg(sd) > 0) {
1793 Dmsg0(110, sd->msg);
1794 if (strcmp(sd->msg, resp) == 0) {
1798 if (job_canceled(jcr)) {
1799 return 0; /* if canceled avoid useless error messages */
1801 if (is_bnet_error(sd)) {
1802 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1803 cmd, bnet_strerror(sd));
1805 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1806 cmd, resp, sd->msg);
1811 static int send_bootstrap_file(JCR *jcr)
1815 BSOCK *sd = jcr->store_bsock;
1816 const char *bootstrap = "bootstrap\n";
1819 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1820 if (!jcr->RestoreBootstrap) {
1823 bs = fopen(jcr->RestoreBootstrap, "rb");
1826 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1827 jcr->RestoreBootstrap, be.bstrerror());
1828 set_jcr_job_status(jcr, JS_ErrorTerminated);
1831 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1833 while (fgets(buf, sizeof(buf), bs)) {
1834 sd->msglen = Mmsg(sd->msg, "%s", buf);
1837 bnet_sig(sd, BNET_EOD);
1839 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1840 set_jcr_job_status(jcr, JS_ErrorTerminated);
1846 free_bootstrap(jcr);