2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 pm_strcpy(jcr->client_name, my_name);
216 jcr->pki_sign = me->pki_sign;
217 jcr->pki_encrypt = me->pki_encrypt;
218 jcr->pki_keypair = me->pki_keypair;
219 jcr->pki_signers = me->pki_signers;
220 jcr->pki_recipients = me->pki_recipients;
222 enable_backup_privileges(NULL, 1 /* ignore_errors */);
224 /**********FIXME******* add command handler error code */
226 for (quit=false; !quit;) {
229 if (bnet_recv(dir) < 0) {
230 break; /* connection terminated */
232 dir->msg[dir->msglen] = 0;
233 Dmsg1(100, "<dird: %s", dir->msg);
235 for (i=0; cmds[i].cmd; i++) {
236 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
237 found = true; /* indicate command found */
238 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
239 bnet_fsend(dir, no_auth);
240 bnet_sig(dir, BNET_EOD);
243 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
244 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
245 bnet_fsend(dir, invalid_cmd);
246 bnet_sig(dir, BNET_EOD);
249 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
250 if (!cmds[i].func(jcr)) { /* do command */
251 quit = true; /* error or fully terminated, get out */
252 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
257 if (!found) { /* command not found */
258 bnet_fsend(dir, errmsg);
264 /* Inform Storage daemon that we are done */
265 if (jcr->store_bsock) {
266 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
269 /* Run the after job */
270 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
272 generate_daemon_event(jcr, "JobEnd");
274 dequeue_messages(jcr); /* send any queued messages */
276 /* Inform Director that we are done */
277 bnet_sig(dir, BNET_TERMINATE);
279 /* Clean up fileset */
280 FF_PKT *ff = jcr->ff;
281 findFILESET *fileset = ff->fileset;
284 /* Delete FileSet Include lists */
285 for (i=0; i<fileset->include_list.size(); i++) {
286 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
287 for (j=0; j<incexe->opts_list.size(); j++) {
288 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
289 for (k=0; k<fo->regex.size(); k++) {
290 regfree((regex_t *)fo->regex.get(k));
292 for (k=0; k<fo->regexdir.size(); k++) {
293 regfree((regex_t *)fo->regexdir.get(k));
295 for (k=0; k<fo->regexfile.size(); k++) {
296 regfree((regex_t *)fo->regexfile.get(k));
299 fo->regexdir.destroy();
300 fo->regexfile.destroy();
302 fo->wilddir.destroy();
303 fo->wildfile.destroy();
304 fo->wildbase.destroy();
306 fo->fstype.destroy();
307 fo->drivetype.destroy();
315 incexe->opts_list.destroy();
316 incexe->name_list.destroy();
318 fileset->include_list.destroy();
320 /* Delete FileSet Exclude lists */
321 for (i=0; i<fileset->exclude_list.size(); i++) {
322 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
323 for (j=0; j<incexe->opts_list.size(); j++) {
324 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
326 fo->regexdir.destroy();
327 fo->regexfile.destroy();
329 fo->wilddir.destroy();
330 fo->wildfile.destroy();
331 fo->wildbase.destroy();
333 fo->fstype.destroy();
334 fo->drivetype.destroy();
336 incexe->opts_list.destroy();
337 incexe->name_list.destroy();
339 fileset->exclude_list.destroy();
343 Dmsg0(100, "Calling term_find_files\n");
344 term_find_files(jcr->ff);
346 Dmsg0(100, "Done with term_find_files\n");
347 free_jcr(jcr); /* destroy JCR record */
348 Dmsg0(100, "Done with free_jcr\n");
354 * Hello from Director he must identify himself and provide his
357 static int hello_cmd(JCR *jcr)
359 Dmsg0(120, "Calling Authenticate\n");
360 if (!authenticate_director(jcr)) {
363 Dmsg0(120, "OK Authenticate\n");
364 jcr->authenticated = true;
371 static int cancel_cmd(JCR *jcr)
373 BSOCK *dir = jcr->dir_bsock;
374 char Job[MAX_NAME_LENGTH];
377 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
378 if (!(cjcr=get_jcr_by_full_name(Job))) {
379 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
381 if (cjcr->store_bsock) {
382 cjcr->store_bsock->set_timed_out();
383 cjcr->store_bsock->set_terminated();
384 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
386 set_jcr_job_status(cjcr, JS_Canceled);
388 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
391 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
393 bnet_sig(dir, BNET_EOD);
399 * Set debug level as requested by the Director
402 static int setdebug_cmd(JCR *jcr)
404 BSOCK *dir = jcr->dir_bsock;
405 int level, trace_flag;
407 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
408 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
409 pm_strcpy(jcr->errmsg, dir->msg);
410 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
414 set_trace(trace_flag);
415 return dir->fsend(OKsetdebug, level);
419 static int estimate_cmd(JCR *jcr)
421 BSOCK *dir = jcr->dir_bsock;
424 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
425 pm_strcpy(jcr->errmsg, dir->msg);
426 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
427 dir->fsend(_("2992 Bad estimate command.\n"));
431 dir->fsend(OKest, jcr->num_files_examined,
432 edit_uint64_with_commas(jcr->JobBytes, ed2));
433 bnet_sig(dir, BNET_EOD);
438 * Get JobId and Storage Daemon Authorization key from Director
440 static int job_cmd(JCR *jcr)
442 BSOCK *dir = jcr->dir_bsock;
443 POOLMEM *sd_auth_key;
445 sd_auth_key = get_memory(dir->msglen);
446 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
447 &jcr->VolSessionId, &jcr->VolSessionTime,
449 pm_strcpy(jcr->errmsg, dir->msg);
450 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
451 bnet_fsend(dir, BADjob);
452 free_pool_memory(sd_auth_key);
455 jcr->sd_auth_key = bstrdup(sd_auth_key);
456 free_pool_memory(sd_auth_key);
457 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
458 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
461 static int runbefore_cmd(JCR *jcr)
464 BSOCK *dir = jcr->dir_bsock;
465 POOLMEM *cmd = get_memory(dir->msglen+1);
468 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
469 if (sscanf(dir->msg, runbefore, cmd) != 1) {
470 pm_strcpy(jcr->errmsg, dir->msg);
471 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
472 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
478 /* Run the command now */
479 script = new_runscript();
480 script->set_command(cmd);
481 script->when = SCRIPT_Before;
482 ok = script->run(jcr, "ClientRunBeforeJob");
483 free_runscript(script);
487 bnet_fsend(dir, OKRunBefore);
490 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
495 static int runbeforenow_cmd(JCR *jcr)
497 BSOCK *dir = jcr->dir_bsock;
499 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
500 if (job_canceled(jcr)) {
501 bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
502 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
505 bnet_fsend(dir, OKRunBeforeNow);
506 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
511 static int runafter_cmd(JCR *jcr)
513 BSOCK *dir = jcr->dir_bsock;
514 POOLMEM *msg = get_memory(dir->msglen+1);
517 Dmsg1(100, "runafter_cmd: %s", dir->msg);
518 if (sscanf(dir->msg, runafter, msg) != 1) {
519 pm_strcpy(jcr->errmsg, dir->msg);
520 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
521 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
527 cmd = new_runscript();
528 cmd->set_command(msg);
529 cmd->on_success = true;
530 cmd->on_failure = false;
531 cmd->when = SCRIPT_After;
533 jcr->RunScripts->append(cmd);
535 free_pool_memory(msg);
536 return bnet_fsend(dir, OKRunAfter);
539 static int runscript_cmd(JCR *jcr)
541 BSOCK *dir = jcr->dir_bsock;
542 POOLMEM *msg = get_memory(dir->msglen+1);
543 int on_success, on_failure, fail_on_error;
545 RUNSCRIPT *cmd = new_runscript() ;
547 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
548 /* Note, we cannot sscanf into bools */
549 if (sscanf(dir->msg, runscript, &on_success,
554 pm_strcpy(jcr->errmsg, dir->msg);
555 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
556 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
561 cmd->on_success = on_success;
562 cmd->on_failure = on_failure;
563 cmd->fail_on_error = fail_on_error;
566 cmd->set_command(msg);
568 jcr->RunScripts->append(cmd);
570 free_pool_memory(msg);
571 return bnet_fsend(dir, OKRunScript);
575 static bool init_fileset(JCR *jcr)
578 findFILESET *fileset;
587 fileset = (findFILESET *)malloc(sizeof(findFILESET));
588 memset(fileset, 0, sizeof(findFILESET));
589 ff->fileset = fileset;
590 fileset->state = state_none;
591 fileset->include_list.init(1, true);
592 fileset->exclude_list.init(1, true);
596 static findFOPTS *start_options(FF_PKT *ff)
598 int state = ff->fileset->state;
599 findINCEXE *incexe = ff->fileset->incexe;
601 if (state != state_options) {
602 ff->fileset->state = state_options;
603 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
604 memset(fo, 0, sizeof(findFOPTS));
605 fo->regex.init(1, true);
606 fo->regexdir.init(1, true);
607 fo->regexfile.init(1, true);
608 fo->wild.init(1, true);
609 fo->wilddir.init(1, true);
610 fo->wildfile.init(1, true);
611 fo->wildbase.init(1, true);
612 fo->base.init(1, true);
613 fo->fstype.init(1, true);
614 fo->drivetype.init(1, true);
615 incexe->current_opts = fo;
616 incexe->opts_list.append(fo);
618 return incexe->current_opts;
623 * Add fname to include/exclude fileset list. First check for
624 * | and < and if necessary perform command.
626 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
640 p++; /* skip over | */
641 fn = get_pool_memory(PM_FNAME);
642 fn = edit_job_codes(jcr, fn, p, "");
643 bpipe = open_bpipe(fn, 0, "r");
646 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
648 free_pool_memory(fn);
651 free_pool_memory(fn);
652 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
653 strip_trailing_junk(buf);
654 fileset->incexe->name_list.append(new_dlistString(buf));
656 if ((stat=close_bpipe(bpipe)) != 0) {
658 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
659 p, be.code(stat), be.bstrerror(stat));
664 Dmsg0(100, "Doing < include on client.\n");
665 p++; /* skip over < */
666 if ((ffd = fopen(p, "rb")) == NULL) {
668 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
672 while (fgets(buf, sizeof(buf), ffd)) {
673 strip_trailing_junk(buf);
674 Dmsg1(100, "%s\n", buf);
675 fileset->incexe->name_list.append(new_dlistString(buf));
680 fileset->incexe->name_list.append(new_dlistString(fname));
686 static void add_fileset(JCR *jcr, const char *item)
688 FF_PKT *ff = jcr->ff;
689 findFILESET *fileset = ff->fileset;
690 int state = fileset->state;
691 findFOPTS *current_opts;
693 /* Get code, optional subcode, and position item past the dividing space */
694 Dmsg1(100, "%s\n", item);
699 int subcode = ' '; /* A space is always a valid subcode */
700 if (item[0] != '\0' && item[0] != ' ') {
708 /* Skip all lines we receive after an error */
709 if (state == state_error) {
710 Dmsg0(100, "State=error return\n");
715 * The switch tests the code for validity.
716 * The subcode is always good if it is a space, otherwise we must confirm.
717 * We set state to state_error first assuming the subcode is invalid,
718 * requiring state to be set in cases below that handle subcodes.
720 if (subcode != ' ') {
722 Dmsg0(100, "Set state=error\n");
727 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
728 memset(fileset->incexe, 0, sizeof(findINCEXE));
729 fileset->incexe->opts_list.init(1, true);
730 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
731 fileset->include_list.append(fileset->incexe);
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();
739 fileset->exclude_list.append(fileset->incexe);
745 /* File item to either include/include list */
746 state = state_include;
747 add_file_to_fileset(jcr, item, fileset);
750 current_opts = start_options(ff);
754 preg = (regex_t *)malloc(sizeof(regex_t));
755 if (current_opts->flags & FO_IGNORECASE) {
756 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
758 rc = regcomp(preg, item, REG_EXTENDED);
761 regerror(rc, preg, prbuf, sizeof(prbuf));
764 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
768 state = state_options;
769 if (subcode == ' ') {
770 current_opts->regex.append(preg);
771 } else if (subcode == 'D') {
772 current_opts->regexdir.append(preg);
773 } else if (subcode == 'F') {
774 current_opts->regexfile.append(preg);
780 current_opts = start_options(ff);
781 current_opts->base.append(bstrdup(item));
782 state = state_options;
785 current_opts = start_options(ff);
786 state = state_options;
787 if (subcode == ' ') {
788 current_opts->fstype.append(bstrdup(item));
789 } else if (subcode == 'D') {
790 current_opts->drivetype.append(bstrdup(item));
796 current_opts = start_options(ff);
797 state = state_options;
798 if (subcode == ' ') {
799 current_opts->wild.append(bstrdup(item));
800 } else if (subcode == 'D') {
801 current_opts->wilddir.append(bstrdup(item));
802 } else if (subcode == 'F') {
803 current_opts->wildfile.append(bstrdup(item));
804 } else if (subcode == 'B') {
805 current_opts->wildbase.append(bstrdup(item));
811 current_opts = start_options(ff);
812 set_options(current_opts, item);
813 state = state_options;
816 current_opts = start_options(ff);
817 current_opts->reader = bstrdup(item);
818 state = state_options;
821 current_opts = start_options(ff);
822 current_opts->writer = bstrdup(item);
823 state = state_options;
826 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
830 ff->fileset->state = state;
833 static bool term_fileset(JCR *jcr)
835 FF_PKT *ff = jcr->ff;
838 findFILESET *fileset = ff->fileset;
841 for (i=0; i<fileset->include_list.size(); i++) {
842 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
844 for (j=0; j<incexe->opts_list.size(); j++) {
845 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
846 for (k=0; k<fo->regex.size(); k++) {
847 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
849 for (k=0; k<fo->regexdir.size(); k++) {
850 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
852 for (k=0; k<fo->regexfile.size(); k++) {
853 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
855 for (k=0; k<fo->wild.size(); k++) {
856 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
858 for (k=0; k<fo->wilddir.size(); k++) {
859 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
861 for (k=0; k<fo->wildfile.size(); k++) {
862 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
864 for (k=0; k<fo->wildbase.size(); k++) {
865 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
867 for (k=0; k<fo->base.size(); k++) {
868 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
870 for (k=0; k<fo->fstype.size(); k++) {
871 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
873 for (k=0; k<fo->drivetype.size(); k++) {
874 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
877 Dmsg1(400, "D %s\n", fo->reader);
880 Dmsg1(400, "T %s\n", fo->writer);
884 foreach_dlist(node, &incexe->name_list) {
885 Dmsg1(400, "F %s\n", node->c_str());
888 for (i=0; i<fileset->exclude_list.size(); i++) {
889 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
891 for (j=0; j<incexe->opts_list.size(); j++) {
892 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
893 for (k=0; k<fo->regex.size(); k++) {
894 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
896 for (k=0; k<fo->regexdir.size(); k++) {
897 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
899 for (k=0; k<fo->regexfile.size(); k++) {
900 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
902 for (k=0; k<fo->wild.size(); k++) {
903 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
905 for (k=0; k<fo->wilddir.size(); k++) {
906 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
908 for (k=0; k<fo->wildfile.size(); k++) {
909 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
911 for (k=0; k<fo->wildbase.size(); k++) {
912 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
914 for (k=0; k<fo->base.size(); k++) {
915 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
917 for (k=0; k<fo->fstype.size(); k++) {
918 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
920 for (k=0; k<fo->drivetype.size(); k++) {
921 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
925 foreach_dlist(node, incexe->name_list) {
926 Dmsg1(400, "F %s\n", node->c_str());
930 return ff->fileset->state != state_error;
935 * As an optimization, we should do this during
936 * "compile" time in filed/job.c, and keep only a bit mask
937 * and the Verify options.
939 static void set_options(findFOPTS *fo, const char *opts)
945 for (p=opts; *p; p++) {
947 case 'a': /* alway replace */
948 case '0': /* no option */
951 fo->flags |= FO_EXCLUDE;
954 fo->flags |= FO_MULTIFS;
956 case 'h': /* no recursion */
957 fo->flags |= FO_NO_RECURSION;
959 case 'H': /* no hard link handling */
960 fo->flags |= FO_NO_HARDLINK;
963 fo->flags |= FO_IGNORECASE;
969 fo->flags |= FO_NOREPLACE;
971 case 'p': /* use portable data format */
972 fo->flags |= FO_PORTABLE;
974 case 'R': /* Resource forks and Finder Info */
975 fo->flags |= FO_HFSPLUS;
976 case 'r': /* read fifo */
977 fo->flags |= FO_READFIFO;
982 fo->flags |= FO_SHA1;
987 fo->flags |= FO_SHA256;
991 fo->flags |= FO_SHA512;
997 * If 2 or 3 is seen here, SHA2 is not configured, so
998 * eat the option, and drop back to SHA-1.
1000 if (p[1] == '2' || p[1] == '3') {
1003 fo->flags |= FO_SHA1;
1008 fo->flags |= FO_SPARSE;
1011 fo->flags |= FO_MTIMEONLY;
1014 fo->flags |= FO_KEEPATIME;
1017 fo->flags |= FO_ACL;
1019 case 'V': /* verify options */
1020 /* Copy Verify Options */
1021 for (j=0; *p && *p != ':'; p++) {
1022 fo->VerifyOpts[j] = *p;
1023 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1027 fo->VerifyOpts[j] = 0;
1029 case 'P': /* strip path */
1032 for (j=0; *p && *p != ':'; p++) {
1034 if (j < (int)sizeof(strip) - 1) {
1039 fo->strip_path = atoi(strip);
1040 fo->flags |= FO_STRIPPATH;
1041 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1044 fo->flags |= FO_IF_NEWER;
1047 fo->flags |= FO_ENHANCEDWILD;
1049 case 'Z': /* gzip compression */
1050 fo->flags |= FO_GZIP;
1051 fo->GZIP_level = *++p - '0';
1054 fo->flags |= FO_NOATIME;
1057 fo->flags |= FO_CHKCHANGES;
1060 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1068 * Director is passing his Fileset
1070 static int fileset_cmd(JCR *jcr)
1072 BSOCK *dir = jcr->dir_bsock;
1074 #if defined(WIN32_VSS)
1077 sscanf(dir->msg, "fileset vss=%d", &vss);
1081 if (!init_fileset(jcr)) {
1084 while (bnet_recv(dir) >= 0) {
1085 strip_trailing_junk(dir->msg);
1086 Dmsg1(500, "Fileset: %s\n", dir->msg);
1087 add_fileset(jcr, dir->msg);
1089 if (!term_fileset(jcr)) {
1092 return bnet_fsend(dir, OKinc);
1095 static void free_bootstrap(JCR *jcr)
1097 if (jcr->RestoreBootstrap) {
1098 unlink(jcr->RestoreBootstrap);
1099 free_pool_memory(jcr->RestoreBootstrap);
1100 jcr->RestoreBootstrap = NULL;
1105 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1106 static uint32_t bsr_uniq = 0;
1109 * The Director sends us the bootstrap file, which
1110 * we will in turn pass to the SD.
1112 static int bootstrap_cmd(JCR *jcr)
1114 BSOCK *dir = jcr->dir_bsock;
1115 POOLMEM *fname = get_pool_memory(PM_FNAME);
1118 free_bootstrap(jcr);
1121 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1122 jcr->Job, bsr_uniq);
1124 Dmsg1(400, "bootstrap=%s\n", fname);
1125 jcr->RestoreBootstrap = fname;
1126 bs = fopen(fname, "a+b"); /* create file */
1129 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1130 jcr->RestoreBootstrap, be.bstrerror());
1132 * Suck up what he is sending to us so that he will then
1133 * read our error message.
1135 while (bnet_recv(dir) >= 0)
1137 free_bootstrap(jcr);
1138 set_jcr_job_status(jcr, JS_ErrorTerminated);
1142 while (bnet_recv(dir) >= 0) {
1143 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1144 fputs(dir->msg, bs);
1148 * Note, do not free the bootstrap yet -- it needs to be
1151 return bnet_fsend(dir, OKbootstrap);
1156 * Get backup level from Director
1159 static int level_cmd(JCR *jcr)
1161 BSOCK *dir = jcr->dir_bsock;
1162 POOLMEM *level, *buf = NULL;
1165 level = get_memory(dir->msglen+1);
1166 Dmsg1(110, "level_cmd: %s", dir->msg);
1167 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1170 /* Base backup requested? */
1171 if (strcmp(level, "base") == 0) {
1172 jcr->JobLevel = L_BASE;
1173 /* Full backup requested? */
1174 } else if (strcmp(level, "full") == 0) {
1175 jcr->JobLevel = L_FULL;
1176 } else if (strcmp(level, "differential") == 0) {
1177 jcr->JobLevel = L_DIFFERENTIAL;
1180 } else if (strcmp(level, "incremental") == 0) {
1181 jcr->JobLevel = L_INCREMENTAL;
1185 * We get his UTC since time, then sync the clocks and correct it
1186 * to agree with our clock.
1188 } else if (strcmp(level, "since_utime") == 0) {
1189 buf = get_memory(dir->msglen+1);
1190 utime_t since_time, adj;
1191 btime_t his_time, bt_start, rt=0, bt_adj=0;
1192 if (jcr->JobLevel == L_NONE) {
1193 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1195 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1196 buf, &mtime_only) != 2) {
1199 since_time = str_to_uint64(buf); /* this is the since time */
1200 Dmsg1(100, "since_time=%d\n", (int)since_time);
1201 char ed1[50], ed2[50];
1203 * Sync clocks by polling him for the time. We take
1204 * 10 samples of his time throwing out the first two.
1206 for (int i=0; i<10; i++) {
1207 bt_start = get_current_btime();
1208 bnet_sig(dir, BNET_BTIME); /* poll for time */
1209 if (bnet_recv(dir) <= 0) { /* get response */
1212 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1215 if (i < 2) { /* toss first two results */
1218 his_time = str_to_uint64(buf);
1219 rt = get_current_btime() - bt_start; /* compute round trip time */
1220 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1221 edit_uint64(bt_start, ed2));
1222 bt_adj += bt_start - his_time - rt/2;
1223 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1226 bt_adj = bt_adj / 8; /* compute average time */
1227 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1228 adj = btime_to_utime(bt_adj);
1229 since_time += adj; /* adjust for clock difference */
1230 /* Don't notify if time within 3 seconds */
1231 if (adj > 3 || adj < -3) {
1233 if (adj > 600 || adj < -600) {
1238 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %d seconds, FD automatically compensating.\n"), adj);
1240 bnet_sig(dir, BNET_EOD);
1242 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1243 jcr->incremental = 1; /* set incremental or decremental backup */
1244 jcr->mtime = (time_t)since_time; /* set since time */
1246 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1254 return bnet_fsend(dir, OKlevel);
1257 pm_strcpy(jcr->errmsg, dir->msg);
1258 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1267 * Get session parameters from Director -- this is for a Restore command
1269 static int session_cmd(JCR *jcr)
1271 BSOCK *dir = jcr->dir_bsock;
1273 Dmsg1(100, "SessionCmd: %s", dir->msg);
1274 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1275 &jcr->VolSessionId, &jcr->VolSessionTime,
1276 &jcr->StartFile, &jcr->EndFile,
1277 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1278 pm_strcpy(jcr->errmsg, dir->msg);
1279 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1283 return bnet_fsend(dir, OKsession);
1287 * Get address of storage daemon from Director
1290 static int storage_cmd(JCR *jcr)
1292 int stored_port; /* storage daemon port */
1293 int enable_ssl; /* enable ssl to sd */
1294 BSOCK *dir = jcr->dir_bsock;
1295 BSOCK *sd; /* storage daemon bsock */
1297 Dmsg1(100, "StorageCmd: %s", dir->msg);
1298 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1299 pm_strcpy(jcr->errmsg, dir->msg);
1300 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1303 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1304 /* Open command communications with Storage daemon */
1305 /* Try to connect for 1 hour at 10 second intervals */
1306 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1307 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
1309 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1310 jcr->stored_addr, stored_port);
1311 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1312 jcr->stored_addr, stored_port);
1315 Dmsg0(110, "Connection OK to SD.\n");
1317 jcr->store_bsock = sd;
1319 sd->fsend("Hello Start Job %s\n", jcr->Job);
1320 if (!authenticate_storagedaemon(jcr)) {
1321 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1324 Dmsg0(110, "Authenticated with SD.\n");
1326 /* Send OK to Director */
1327 return dir->fsend(OKstore);
1334 static int backup_cmd(JCR *jcr)
1336 BSOCK *dir = jcr->dir_bsock;
1337 BSOCK *sd = jcr->store_bsock;
1340 char ed1[50], ed2[50];
1341 bool bDoVSS = false;
1343 #if defined(WIN32_VSS)
1344 // capture state here, if client is backed up by multiple directors
1345 // and one enables vss and the other does not then enable_vss can change
1346 // between here and where its evaluated after the job completes.
1347 bDoVSS = g_pVSSClient && enable_vss;
1349 /* Run only one at a time */
1354 set_jcr_job_status(jcr, JS_Blocked);
1355 jcr->JobType = JT_BACKUP;
1356 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1359 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1363 bnet_fsend(dir, OKbackup);
1364 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1367 * Send Append Open Session to Storage daemon
1369 bnet_fsend(sd, append_open);
1370 Dmsg1(110, ">stored: %s", sd->msg);
1372 * Expect to receive back the Ticket number
1374 if (bget_msg(sd) >= 0) {
1375 Dmsg1(110, "<stored: %s", sd->msg);
1376 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1377 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1380 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1382 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1387 * Send Append data command to Storage daemon
1389 bnet_fsend(sd, append_data, jcr->Ticket);
1390 Dmsg1(110, ">stored: %s", sd->msg);
1393 * Expect to get OK data
1395 Dmsg1(110, "<stored: %s", sd->msg);
1396 if (!response(jcr, sd, OK_data, "Append Data")) {
1400 generate_daemon_event(jcr, "JobStart");
1402 #if defined(WIN32_VSS)
1403 /* START VSS ON WIN 32 */
1405 if (g_pVSSClient->InitializeForBackup()) {
1406 /* tell vss which drives to snapshot */
1407 char szWinDriveLetters[27];
1408 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1409 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1410 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1411 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1414 /* tell user if snapshot creation of a specific drive failed */
1416 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1417 if (islower(szWinDriveLetters[i])) {
1418 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1422 /* inform user about writer states */
1423 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1424 if (g_pVSSClient->GetWriterState(i) < 1) {
1425 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1430 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1434 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1440 * Send Files to Storage daemon
1442 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1443 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1444 set_jcr_job_status(jcr, JS_ErrorTerminated);
1445 bnet_suppress_error_messages(sd, 1);
1446 bget_msg(sd); /* Read final response from append_data */
1447 Dmsg0(110, "Error in blast_data.\n");
1449 set_jcr_job_status(jcr, JS_Terminated);
1451 if (jcr->JobStatus != JS_Terminated) {
1452 bnet_suppress_error_messages(sd, 1);
1453 goto cleanup; /* bail out now */
1456 * Expect to get response to append_data from Storage daemon
1458 if (!response(jcr, sd, OK_append, "Append Data")) {
1459 set_jcr_job_status(jcr, JS_ErrorTerminated);
1464 * Send Append End Data to Storage daemon
1466 bnet_fsend(sd, append_end, jcr->Ticket);
1468 if (!response(jcr, sd, OK_end, "Append End")) {
1469 set_jcr_job_status(jcr, JS_ErrorTerminated);
1474 * Send Append Close to Storage daemon
1476 bnet_fsend(sd, append_close, jcr->Ticket);
1477 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1478 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1480 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1484 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1487 if (SDJobStatus != JS_Terminated) {
1488 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1494 #if defined(WIN32_VSS)
1495 /* STOP VSS ON WIN 32 */
1496 /* tell vss to close the backup session */
1498 if (g_pVSSClient->CloseBackup()) {
1499 /* inform user about writer states */
1500 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1501 int msg_type = M_INFO;
1502 if (g_pVSSClient->GetWriterState(i) < 1) {
1503 msg_type = M_WARNING;
1506 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1513 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1514 edit_uint64(jcr->ReadBytes, ed1),
1515 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, (int)bDoVSS,
1517 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1519 return 0; /* return and stop command loop */
1523 * Do a Verify for Director
1526 static int verify_cmd(JCR *jcr)
1528 BSOCK *dir = jcr->dir_bsock;
1529 BSOCK *sd = jcr->store_bsock;
1530 char level[100], ed1[50], ed2[50];
1532 jcr->JobType = JT_VERIFY;
1533 if (sscanf(dir->msg, verifycmd, level) != 1) {
1534 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1538 if (strcasecmp(level, "init") == 0) {
1539 jcr->JobLevel = L_VERIFY_INIT;
1540 } else if (strcasecmp(level, "catalog") == 0){
1541 jcr->JobLevel = L_VERIFY_CATALOG;
1542 } else if (strcasecmp(level, "volume") == 0){
1543 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1544 } else if (strcasecmp(level, "data") == 0){
1545 jcr->JobLevel = L_VERIFY_DATA;
1546 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1547 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1549 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1553 bnet_fsend(dir, OKverify);
1555 generate_daemon_event(jcr, "JobStart");
1557 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1559 switch (jcr->JobLevel) {
1561 case L_VERIFY_CATALOG:
1564 case L_VERIFY_VOLUME_TO_CATALOG:
1565 if (!open_sd_read_session(jcr)) {
1568 start_dir_heartbeat(jcr);
1569 do_verify_volume(jcr);
1570 stop_dir_heartbeat(jcr);
1572 * Send Close session command to Storage daemon
1574 bnet_fsend(sd, read_close, jcr->Ticket);
1575 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1577 /* ****FIXME**** check response */
1578 bget_msg(sd); /* get OK */
1580 /* Inform Storage daemon that we are done */
1581 bnet_sig(sd, BNET_TERMINATE);
1584 case L_VERIFY_DISK_TO_CATALOG:
1588 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1592 bnet_sig(dir, BNET_EOD);
1594 /* Send termination status back to Dir */
1595 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1596 edit_uint64(jcr->ReadBytes, ed1),
1597 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1599 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1601 /* Inform Director that we are done */
1602 bnet_sig(dir, BNET_TERMINATE);
1603 return 0; /* return and terminate command loop */
1607 * Do a Restore for Director
1610 static int restore_cmd(JCR *jcr)
1612 BSOCK *dir = jcr->dir_bsock;
1613 BSOCK *sd = jcr->store_bsock;
1615 bool use_regexwhere=false;
1618 char ed1[50], ed2[50];
1621 * Scan WHERE (base directory for restore) from command
1623 Dmsg0(150, "restore command\n");
1624 /* Pickup where string */
1625 args = get_memory(dir->msglen+1);
1628 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1629 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1630 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1631 pm_strcpy(jcr->errmsg, dir->msg);
1632 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1637 use_regexwhere = true;
1639 /* Turn / into nothing */
1640 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1644 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1645 unbash_spaces(args);
1647 if (use_regexwhere) {
1648 jcr->where_bregexp = get_bregexps(args);
1649 if (!jcr->where_bregexp) {
1650 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1651 free_pool_memory(args);
1655 jcr->where = bstrdup(args);
1658 free_pool_memory(args);
1659 jcr->replace = replace;
1660 jcr->prefix_links = prefix_links;
1662 bnet_fsend(dir, OKrestore);
1663 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1665 jcr->JobType = JT_RESTORE;
1667 set_jcr_job_status(jcr, JS_Blocked);
1669 if (!open_sd_read_session(jcr)) {
1670 set_jcr_job_status(jcr, JS_ErrorTerminated);
1674 set_jcr_job_status(jcr, JS_Running);
1677 * Do restore of files and data
1679 start_dir_heartbeat(jcr);
1680 generate_daemon_event(jcr, "JobStart");
1682 stop_dir_heartbeat(jcr);
1684 set_jcr_job_status(jcr, JS_Terminated);
1685 if (jcr->JobStatus != JS_Terminated) {
1686 bnet_suppress_error_messages(sd, 1);
1690 * Send Close session command to Storage daemon
1692 bnet_fsend(sd, read_close, jcr->Ticket);
1693 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1695 bget_msg(sd); /* get OK */
1697 /* Inform Storage daemon that we are done */
1698 bnet_sig(sd, BNET_TERMINATE);
1703 set_jcr_job_status(jcr, JS_ErrorTerminated);
1705 /* Send termination status back to Dir */
1706 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1707 edit_uint64(jcr->ReadBytes, ed1),
1708 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1710 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1712 /* Inform Director that we are done */
1713 bnet_sig(dir, BNET_TERMINATE);
1715 Dmsg0(130, "Done in job.c\n");
1716 return 0; /* return and terminate command loop */
1719 static int open_sd_read_session(JCR *jcr)
1721 BSOCK *sd = jcr->store_bsock;
1724 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1727 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1728 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1729 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1731 * Open Read Session with Storage daemon
1733 bnet_fsend(sd, read_open, "DummyVolume",
1734 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1735 jcr->StartBlock, jcr->EndBlock);
1736 Dmsg1(110, ">stored: %s", sd->msg);
1741 if (bget_msg(sd) >= 0) {
1742 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1743 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1744 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1747 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1749 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1753 if (!send_bootstrap_file(jcr)) {
1758 * Start read of data with Storage daemon
1760 bnet_fsend(sd, read_data, jcr->Ticket);
1761 Dmsg1(110, ">stored: %s", sd->msg);
1766 if (!response(jcr, sd, OK_data, "Read Data")) {
1773 * Destroy the Job Control Record and associated
1774 * resources (sockets).
1776 static void filed_free_jcr(JCR *jcr)
1778 if (jcr->store_bsock) {
1779 bnet_close(jcr->store_bsock);
1781 free_bootstrap(jcr);
1782 if (jcr->last_fname) {
1783 free_pool_memory(jcr->last_fname);
1785 free_runscripts(jcr->RunScripts);
1786 delete jcr->RunScripts;
1792 * Get response from Storage daemon to a command we
1793 * sent. Check that the response is OK.
1795 * Returns: 0 on failure
1798 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1803 if (bget_msg(sd) > 0) {
1804 Dmsg0(110, sd->msg);
1805 if (strcmp(sd->msg, resp) == 0) {
1809 if (job_canceled(jcr)) {
1810 return 0; /* if canceled avoid useless error messages */
1812 if (is_bnet_error(sd)) {
1813 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1814 cmd, bnet_strerror(sd));
1816 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1817 cmd, resp, sd->msg);
1822 static int send_bootstrap_file(JCR *jcr)
1826 BSOCK *sd = jcr->store_bsock;
1827 const char *bootstrap = "bootstrap\n";
1830 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1831 if (!jcr->RestoreBootstrap) {
1834 bs = fopen(jcr->RestoreBootstrap, "rb");
1837 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1838 jcr->RestoreBootstrap, be.bstrerror());
1839 set_jcr_job_status(jcr, JS_ErrorTerminated);
1842 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1844 while (fgets(buf, sizeof(buf), bs)) {
1845 sd->msglen = Mmsg(sd->msg, "%s", buf);
1848 bnet_sig(sd, BNET_EOD);
1850 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1851 set_jcr_job_status(jcr, JS_ErrorTerminated);
1857 free_bootstrap(jcr);