2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2006 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 plus additions
11 that are listed in the file LICENSE.
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 verifycmd[] = "verify level=%30s";
119 static char estimatecmd[] = "estimate listing=%d";
120 static char runbefore[] = "RunBeforeJob %s";
121 static char runafter[] = "RunAfterJob %s";
122 static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s";
124 /* Responses sent to Director */
125 static char errmsg[] = "2999 Invalid command\n";
126 static char no_auth[] = "2998 No Authorization\n";
127 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
128 static char OKinc[] = "2000 OK include\n";
129 static char OKest[] = "2000 OK estimate files=%u bytes=%s\n";
130 static char OKlevel[] = "2000 OK level\n";
131 static char OKbackup[] = "2000 OK backup\n";
132 static char OKbootstrap[] = "2000 OK bootstrap\n";
133 static char OKverify[] = "2000 OK verify\n";
134 static char OKrestore[] = "2000 OK restore\n";
135 static char OKsession[] = "2000 OK session\n";
136 static char OKstore[] = "2000 OK storage\n";
137 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
138 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
139 static char BADjob[] = "2901 Bad Job\n";
140 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
141 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
142 static char OKRunBefore[] = "2000 OK RunBefore\n";
143 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
144 static char OKRunAfter[] = "2000 OK RunAfter\n";
145 static char OKRunScript[] = "2000 OK RunScript\n";
148 /* Responses received from Storage Daemon */
149 static char OK_end[] = "3000 OK end\n";
150 static char OK_close[] = "3000 OK close Status = %d\n";
151 static char OK_open[] = "3000 OK open ticket = %d\n";
152 static char OK_data[] = "3000 OK data\n";
153 static char OK_append[] = "3000 OK append data\n";
154 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
157 /* Commands sent to Storage Daemon */
158 static char append_open[] = "append open session\n";
159 static char append_data[] = "append data %d\n";
160 static char append_end[] = "append end session %d\n";
161 static char append_close[] = "append close session %d\n";
162 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
163 static char read_data[] = "read data %d\n";
164 static char read_close[] = "read close session %d\n";
167 * Accept requests from a Director
169 * NOTE! We are running as a separate thread
171 * Send output one line
172 * at a time followed by a zero length transmission.
174 * Return when the connection is terminated or there
177 * Basic task here is:
178 * Authenticate Director (during Hello command).
179 * Accept commands one at a time from the Director
182 * Concerning ClientRunBefore/After, the sequence of events
183 * is rather critical. If they are not done in the right
184 * order one can easily get FD->SD timeouts if the script
187 * The current sequence of events is:
188 * 1. Dir starts job with FD
189 * 2. Dir connects to SD
190 * 3. Dir connects to FD
191 * 4. FD connects to SD
192 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
193 * 6. Dir sends include/exclude
194 * 7. FD sends data to SD
195 * 8. SD/FD disconnects while SD despools data and attributes (optionnal)
196 * 9. FD runs ClientRunAfterJob
199 void *handle_client_request(void *dirp)
204 BSOCK *dir = (BSOCK *)dirp;
206 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
207 jcr->dir_bsock = dir;
208 jcr->ff = init_find_files();
209 jcr->start_time = time(NULL);
210 jcr->RunScripts = New(alist(10, not_owned_by_alist));
211 jcr->last_fname = get_pool_memory(PM_FNAME);
212 jcr->last_fname[0] = 0;
213 jcr->client_name = get_memory(strlen(my_name) + 1);
214 pm_strcpy(jcr->client_name, my_name);
215 jcr->pki_sign = me->pki_sign;
216 jcr->pki_encrypt = me->pki_encrypt;
217 jcr->pki_keypair = me->pki_keypair;
218 jcr->pki_signers = me->pki_signers;
219 jcr->pki_recipients = me->pki_recipients;
221 enable_backup_privileges(NULL, 1 /* ignore_errors */);
223 /**********FIXME******* add command handler error code */
225 for (quit=false; !quit;) {
228 if (bnet_recv(dir) < 0) {
229 break; /* connection terminated */
231 dir->msg[dir->msglen] = 0;
232 Dmsg1(100, "<dird: %s", dir->msg);
234 for (i=0; cmds[i].cmd; i++) {
235 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
236 found = true; /* indicate command found */
237 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
238 bnet_fsend(dir, no_auth);
239 bnet_sig(dir, BNET_EOD);
242 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
243 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
244 bnet_fsend(dir, invalid_cmd);
245 bnet_sig(dir, BNET_EOD);
248 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
249 if (!cmds[i].func(jcr)) { /* do command */
250 quit = true; /* error or fully terminated, get out */
251 Dmsg1(20, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
256 if (!found) { /* command not found */
257 bnet_fsend(dir, errmsg);
263 /* Inform Storage daemon that we are done */
264 if (jcr->store_bsock) {
265 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
268 /* Run the after job */
269 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
271 generate_daemon_event(jcr, "JobEnd");
273 dequeue_messages(jcr); /* send any queued messages */
275 /* Inform Director that we are done */
276 bnet_sig(dir, BNET_TERMINATE);
278 /* Clean up fileset */
279 FF_PKT *ff = jcr->ff;
280 findFILESET *fileset = ff->fileset;
283 /* Delete FileSet Include lists */
284 for (i=0; i<fileset->include_list.size(); i++) {
285 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
286 for (j=0; j<incexe->opts_list.size(); j++) {
287 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
288 for (k=0; k<fo->regex.size(); k++) {
289 regfree((regex_t *)fo->regex.get(k));
292 fo->regexdir.destroy();
293 fo->regexfile.destroy();
295 fo->wilddir.destroy();
296 fo->wildfile.destroy();
297 fo->wildbase.destroy();
299 fo->fstype.destroy();
300 fo->drivetype.destroy();
308 incexe->opts_list.destroy();
309 incexe->name_list.destroy();
311 fileset->include_list.destroy();
313 /* Delete FileSet Exclude lists */
314 for (i=0; i<fileset->exclude_list.size(); i++) {
315 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
316 for (j=0; j<incexe->opts_list.size(); j++) {
317 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
319 fo->regexdir.destroy();
320 fo->regexfile.destroy();
322 fo->wilddir.destroy();
323 fo->wildfile.destroy();
324 fo->wildbase.destroy();
326 fo->fstype.destroy();
327 fo->drivetype.destroy();
329 incexe->opts_list.destroy();
330 incexe->name_list.destroy();
332 fileset->exclude_list.destroy();
336 Dmsg0(100, "Calling term_find_files\n");
337 term_find_files(jcr->ff);
339 Dmsg0(100, "Done with term_find_files\n");
340 free_jcr(jcr); /* destroy JCR record */
341 Dmsg0(100, "Done with free_jcr\n");
346 * Hello from Director he must identify himself and provide his
349 static int hello_cmd(JCR *jcr)
351 Dmsg0(120, "Calling Authenticate\n");
352 if (!authenticate_director(jcr)) {
355 Dmsg0(120, "OK Authenticate\n");
356 jcr->authenticated = true;
363 static int cancel_cmd(JCR *jcr)
365 BSOCK *dir = jcr->dir_bsock;
366 char Job[MAX_NAME_LENGTH];
369 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
370 if (!(cjcr=get_jcr_by_full_name(Job))) {
371 bnet_fsend(dir, _("2901 Job %s not found.\n"), Job);
373 if (cjcr->store_bsock) {
374 cjcr->store_bsock->timed_out = 1;
375 cjcr->store_bsock->terminated = 1;
376 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
378 set_jcr_job_status(cjcr, JS_Canceled);
380 bnet_fsend(dir, _("2001 Job %s marked to be canceled.\n"), Job);
383 bnet_fsend(dir, _("2902 Error scanning cancel command.\n"));
385 bnet_sig(dir, BNET_EOD);
391 * Set debug level as requested by the Director
394 static int setdebug_cmd(JCR *jcr)
396 BSOCK *dir = jcr->dir_bsock;
397 int level, trace_flag;
399 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
400 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
401 pm_strcpy(jcr->errmsg, dir->msg);
402 bnet_fsend(dir, _("2991 Bad setdebug command: %s\n"), jcr->errmsg);
406 set_trace(trace_flag);
407 return bnet_fsend(dir, OKsetdebug, level);
411 static int estimate_cmd(JCR *jcr)
413 BSOCK *dir = jcr->dir_bsock;
416 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
417 pm_strcpy(jcr->errmsg, dir->msg);
418 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
419 bnet_fsend(dir, _("2992 Bad estimate command.\n"));
423 bnet_fsend(dir, OKest, jcr->num_files_examined,
424 edit_uint64_with_commas(jcr->JobBytes, ed2));
425 bnet_sig(dir, BNET_EOD);
430 * Get JobId and Storage Daemon Authorization key from Director
432 static int job_cmd(JCR *jcr)
434 BSOCK *dir = jcr->dir_bsock;
435 POOLMEM *sd_auth_key;
437 sd_auth_key = get_memory(dir->msglen);
438 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
439 &jcr->VolSessionId, &jcr->VolSessionTime,
441 pm_strcpy(jcr->errmsg, dir->msg);
442 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
443 bnet_fsend(dir, BADjob);
444 free_pool_memory(sd_auth_key);
447 jcr->sd_auth_key = bstrdup(sd_auth_key);
448 free_pool_memory(sd_auth_key);
449 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
450 return bnet_fsend(dir, OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
453 static int runbefore_cmd(JCR *jcr)
456 BSOCK *dir = jcr->dir_bsock;
457 POOLMEM *cmd = get_memory(dir->msglen+1);
460 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
461 if (sscanf(dir->msg, runbefore, cmd) != 1) {
462 pm_strcpy(jcr->errmsg, dir->msg);
463 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
464 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
470 /* Run the command now */
471 script = new_runscript();
472 script->set_command(cmd);
473 script->when = SCRIPT_Before;
474 ok = script->run(jcr, "ClientRunBeforeJob");
475 free_runscript(script);
479 bnet_fsend(dir, OKRunBefore);
482 bnet_fsend(dir, _("2905 Bad RunBeforeJob command.\n"));
487 static int runbeforenow_cmd(JCR *jcr)
489 BSOCK *dir = jcr->dir_bsock;
491 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
492 if (job_canceled(jcr)) {
493 return bnet_fsend(dir, _("2905 Bad RunBeforeNow command.\n"));
495 return bnet_fsend(dir, OKRunBeforeNow);
499 static int runafter_cmd(JCR *jcr)
501 BSOCK *dir = jcr->dir_bsock;
502 POOLMEM *msg = get_memory(dir->msglen+1);
505 Dmsg1(100, "runafter_cmd: %s", dir->msg);
506 if (sscanf(dir->msg, runafter, msg) != 1) {
507 pm_strcpy(jcr->errmsg, dir->msg);
508 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
509 bnet_fsend(dir, _("2905 Bad RunAfterJob command.\n"));
515 cmd = new_runscript();
516 cmd->set_command(msg);
517 cmd->on_success = true;
518 cmd->on_failure = false;
519 cmd->when = SCRIPT_After;
521 jcr->RunScripts->append(cmd);
523 free_pool_memory(msg);
524 return bnet_fsend(dir, OKRunAfter);
527 static int runscript_cmd(JCR *jcr)
529 BSOCK *dir = jcr->dir_bsock;
530 POOLMEM *msg = get_memory(dir->msglen+1);
532 RUNSCRIPT *cmd = new_runscript() ;
534 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
535 if (sscanf(dir->msg, runscript, &cmd->on_success,
537 &cmd->abort_on_error,
540 pm_strcpy(jcr->errmsg, dir->msg);
541 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
542 bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
549 cmd->set_command(msg);
551 jcr->RunScripts->append(cmd);
553 free_pool_memory(msg);
554 return bnet_fsend(dir, OKRunScript);
558 static bool init_fileset(JCR *jcr)
561 findFILESET *fileset;
570 fileset = (findFILESET *)malloc(sizeof(findFILESET));
571 memset(fileset, 0, sizeof(findFILESET));
572 ff->fileset = fileset;
573 fileset->state = state_none;
574 fileset->include_list.init(1, true);
575 fileset->exclude_list.init(1, true);
579 static findFOPTS *start_options(FF_PKT *ff)
581 int state = ff->fileset->state;
582 findINCEXE *incexe = ff->fileset->incexe;
584 if (state != state_options) {
585 ff->fileset->state = state_options;
586 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
587 memset(fo, 0, sizeof(findFOPTS));
588 fo->regex.init(1, true);
589 fo->regexdir.init(1, true);
590 fo->regexfile.init(1, true);
591 fo->wild.init(1, true);
592 fo->wilddir.init(1, true);
593 fo->wildfile.init(1, true);
594 fo->wildbase.init(1, true);
595 fo->base.init(1, true);
596 fo->fstype.init(1, true);
597 fo->drivetype.init(1, true);
598 incexe->current_opts = fo;
599 incexe->opts_list.append(fo);
601 return incexe->current_opts;
606 * Add fname to include/exclude fileset list. First check for
607 * | and < and if necessary perform command.
609 static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset)
623 p++; /* skip over | */
624 fn = get_pool_memory(PM_FNAME);
625 fn = edit_job_codes(jcr, fn, p, "");
626 bpipe = open_bpipe(fn, 0, "r");
629 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
631 free_pool_memory(fn);
634 free_pool_memory(fn);
635 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
636 strip_trailing_junk(buf);
637 fileset->incexe->name_list.append(new_dlistString(buf));
639 if ((stat=close_bpipe(bpipe)) != 0) {
641 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
642 p, be.code(stat), be.strerror(stat));
647 Dmsg0(100, "Doing < include on client.\n");
648 p++; /* skip over < */
649 if ((ffd = fopen(p, "rb")) == NULL) {
651 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
655 while (fgets(buf, sizeof(buf), ffd)) {
656 strip_trailing_junk(buf);
657 Dmsg1(100, "%s\n", buf);
658 fileset->incexe->name_list.append(new_dlistString(buf));
663 fileset->incexe->name_list.append(new_dlistString(fname));
669 static void add_fileset(JCR *jcr, const char *item)
671 FF_PKT *ff = jcr->ff;
672 findFILESET *fileset = ff->fileset;
673 int state = fileset->state;
674 findFOPTS *current_opts;
676 /* Get code, optional subcode, and position item past the dividing space */
677 Dmsg1(100, "%s\n", item);
682 int subcode = ' '; /* A space is always a valid subcode */
683 if (item[0] != '\0' && item[0] != ' ') {
691 /* Skip all lines we receive after an error */
692 if (state == state_error) {
693 Dmsg0(100, "State=error return\n");
698 * The switch tests the code for validity.
699 * The subcode is always good if it is a space, otherwise we must confirm.
700 * We set state to state_error first assuming the subcode is invalid,
701 * requiring state to be set in cases below that handle subcodes.
703 if (subcode != ' ') {
705 Dmsg0(100, "Set state=error\n");
710 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
711 memset(fileset->incexe, 0, sizeof(findINCEXE));
712 fileset->incexe->opts_list.init(1, true);
713 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
714 fileset->include_list.append(fileset->incexe);
718 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
719 memset(fileset->incexe, 0, sizeof(findINCEXE));
720 fileset->incexe->opts_list.init(1, true);
721 fileset->incexe->name_list.init();
722 fileset->exclude_list.append(fileset->incexe);
728 /* File item to either include/include list */
729 state = state_include;
730 add_file_to_fileset(jcr, item, fileset);
733 current_opts = start_options(ff);
737 preg = (regex_t *)malloc(sizeof(regex_t));
738 if (current_opts->flags & FO_IGNORECASE) {
739 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
741 rc = regcomp(preg, item, REG_EXTENDED);
744 regerror(rc, preg, prbuf, sizeof(prbuf));
747 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
751 state = state_options;
752 if (subcode == ' ') {
753 current_opts->regex.append(preg);
754 } else if (subcode == 'D') {
755 current_opts->regexdir.append(preg);
756 } else if (subcode == 'F') {
757 current_opts->regexfile.append(preg);
763 current_opts = start_options(ff);
764 current_opts->base.append(bstrdup(item));
765 state = state_options;
768 current_opts = start_options(ff);
769 state = state_options;
770 if (subcode == ' ') {
771 current_opts->fstype.append(bstrdup(item));
772 } else if (subcode == 'D') {
773 current_opts->drivetype.append(bstrdup(item));
779 current_opts = start_options(ff);
780 state = state_options;
781 if (subcode == ' ') {
782 current_opts->wild.append(bstrdup(item));
783 } else if (subcode == 'D') {
784 current_opts->wilddir.append(bstrdup(item));
785 } else if (subcode == 'F') {
786 current_opts->wildfile.append(bstrdup(item));
787 } else if (subcode == 'B') {
788 current_opts->wildbase.append(bstrdup(item));
794 current_opts = start_options(ff);
795 set_options(current_opts, item);
796 state = state_options;
799 current_opts = start_options(ff);
800 current_opts->reader = bstrdup(item);
801 state = state_options;
804 current_opts = start_options(ff);
805 current_opts->writer = bstrdup(item);
806 state = state_options;
809 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
813 ff->fileset->state = state;
816 static bool term_fileset(JCR *jcr)
818 FF_PKT *ff = jcr->ff;
821 findFILESET *fileset = ff->fileset;
824 for (i=0; i<fileset->include_list.size(); i++) {
825 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
827 for (j=0; j<incexe->opts_list.size(); j++) {
828 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
829 for (k=0; k<fo->regex.size(); k++) {
830 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
832 for (k=0; k<fo->regexdir.size(); k++) {
833 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
835 for (k=0; k<fo->regexfile.size(); k++) {
836 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
838 for (k=0; k<fo->wild.size(); k++) {
839 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
841 for (k=0; k<fo->wilddir.size(); k++) {
842 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
844 for (k=0; k<fo->wildfile.size(); k++) {
845 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
847 for (k=0; k<fo->wildbase.size(); k++) {
848 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
850 for (k=0; k<fo->base.size(); k++) {
851 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
853 for (k=0; k<fo->fstype.size(); k++) {
854 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
856 for (k=0; k<fo->drivetype.size(); k++) {
857 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
860 Dmsg1(400, "D %s\n", fo->reader);
863 Dmsg1(400, "T %s\n", fo->writer);
867 foreach_dlist(node, &incexe->name_list) {
868 Dmsg1(400, "F %s\n", node->c_str());
871 for (i=0; i<fileset->exclude_list.size(); i++) {
872 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
874 for (j=0; j<incexe->opts_list.size(); j++) {
875 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
876 for (k=0; k<fo->regex.size(); k++) {
877 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
879 for (k=0; k<fo->regexdir.size(); k++) {
880 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
882 for (k=0; k<fo->regexfile.size(); k++) {
883 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
885 for (k=0; k<fo->wild.size(); k++) {
886 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
888 for (k=0; k<fo->wilddir.size(); k++) {
889 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
891 for (k=0; k<fo->wildfile.size(); k++) {
892 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
894 for (k=0; k<fo->wildbase.size(); k++) {
895 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
897 for (k=0; k<fo->base.size(); k++) {
898 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
900 for (k=0; k<fo->fstype.size(); k++) {
901 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
903 for (k=0; k<fo->drivetype.size(); k++) {
904 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
908 foreach_dlist(node, incexe->name_list) {
909 Dmsg1(400, "F %s\n", node->c_str());
913 return ff->fileset->state != state_error;
918 * As an optimization, we should do this during
919 * "compile" time in filed/job.c, and keep only a bit mask
920 * and the Verify options.
922 static void set_options(findFOPTS *fo, const char *opts)
927 for (p=opts; *p; p++) {
929 case 'a': /* alway replace */
930 case '0': /* no option */
933 fo->flags |= FO_EXCLUDE;
936 fo->flags |= FO_MULTIFS;
938 case 'h': /* no recursion */
939 fo->flags |= FO_NO_RECURSION;
941 case 'H': /* no hard link handling */
942 fo->flags |= FO_NO_HARDLINK;
945 fo->flags |= FO_IGNORECASE;
951 fo->flags |= FO_NOREPLACE;
953 case 'p': /* use portable data format */
954 fo->flags |= FO_PORTABLE;
956 case 'R': /* Resource forks and Finder Info */
957 fo->flags |= FO_HFSPLUS;
958 case 'r': /* read fifo */
959 fo->flags |= FO_READFIFO;
964 fo->flags |= FO_SHA1;
969 fo->flags |= FO_SHA256;
973 fo->flags |= FO_SHA512;
979 * If 2 or 3 is seen here, SHA2 is not configured, so
980 * eat the option, and drop back to SHA-1.
982 if (p[1] == '2' || p[1] == '3') {
985 fo->flags |= FO_SHA1;
990 fo->flags |= FO_SPARSE;
993 fo->flags |= FO_MTIMEONLY;
996 fo->flags |= FO_KEEPATIME;
1001 case 'V': /* verify options */
1002 /* Copy Verify Options */
1003 for (j=0; *p && *p != ':'; p++) {
1004 fo->VerifyOpts[j] = *p;
1005 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1009 fo->VerifyOpts[j] = 0;
1012 fo->flags |= FO_IF_NEWER;
1015 fo->flags |= FO_ENHANCEDWILD;
1017 case 'Z': /* gzip compression */
1018 fo->flags |= FO_GZIP;
1019 fo->GZIP_level = *++p - '0';
1022 fo->flags |= FO_NOATIME;
1025 fo->flags |= FO_CHKCHANGES;
1028 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1036 * Director is passing his Fileset
1038 static int fileset_cmd(JCR *jcr)
1040 BSOCK *dir = jcr->dir_bsock;
1042 #if defined(WIN32_VSS)
1045 sscanf(dir->msg, "fileset vss=%d", &vss);
1049 if (!init_fileset(jcr)) {
1052 while (bnet_recv(dir) >= 0) {
1053 strip_trailing_junk(dir->msg);
1054 Dmsg1(500, "Fileset: %s\n", dir->msg);
1055 add_fileset(jcr, dir->msg);
1057 if (!term_fileset(jcr)) {
1060 return bnet_fsend(dir, OKinc);
1063 static void free_bootstrap(JCR *jcr)
1065 if (jcr->RestoreBootstrap) {
1066 unlink(jcr->RestoreBootstrap);
1067 free_pool_memory(jcr->RestoreBootstrap);
1068 jcr->RestoreBootstrap = NULL;
1073 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1074 static uint32_t bsr_uniq = 0;
1077 * The Director sends us the bootstrap file, which
1078 * we will in turn pass to the SD.
1080 static int bootstrap_cmd(JCR *jcr)
1082 BSOCK *dir = jcr->dir_bsock;
1083 POOLMEM *fname = get_pool_memory(PM_FNAME);
1086 free_bootstrap(jcr);
1089 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1090 jcr->Job, bsr_uniq);
1092 Dmsg1(400, "bootstrap=%s\n", fname);
1093 jcr->RestoreBootstrap = fname;
1094 bs = fopen(fname, "a+b"); /* create file */
1097 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1098 jcr->RestoreBootstrap, be.strerror());
1100 * Suck up what he is sending to us so that he will then
1101 * read our error message.
1103 while (bnet_recv(dir) >= 0)
1105 free_bootstrap(jcr);
1106 set_jcr_job_status(jcr, JS_ErrorTerminated);
1110 while (bnet_recv(dir) >= 0) {
1111 Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
1112 fputs(dir->msg, bs);
1116 * Note, do not free the bootstrap yet -- it needs to be
1119 return bnet_fsend(dir, OKbootstrap);
1124 * Get backup level from Director
1127 static int level_cmd(JCR *jcr)
1129 BSOCK *dir = jcr->dir_bsock;
1130 POOLMEM *level, *buf = NULL;
1133 level = get_memory(dir->msglen+1);
1134 Dmsg1(110, "level_cmd: %s", dir->msg);
1135 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1138 /* Base backup requested? */
1139 if (strcmp(level, "base") == 0) {
1140 jcr->JobLevel = L_BASE;
1141 /* Full backup requested? */
1142 } else if (strcmp(level, "full") == 0) {
1143 jcr->JobLevel = L_FULL;
1144 } else if (strcmp(level, "differential") == 0) {
1145 jcr->JobLevel = L_DIFFERENTIAL;
1148 } else if (strcmp(level, "incremental") == 0) {
1149 jcr->JobLevel = L_INCREMENTAL;
1153 * We get his UTC since time, then sync the clocks and correct it
1154 * to agree with our clock.
1156 } else if (strcmp(level, "since_utime") == 0) {
1157 buf = get_memory(dir->msglen+1);
1158 utime_t since_time, adj;
1159 btime_t his_time, bt_start, rt=0, bt_adj=0;
1160 if (jcr->JobLevel == L_NONE) {
1161 jcr->JobLevel = L_SINCE; /* if no other job level set, do it now */
1163 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1164 buf, &mtime_only) != 2) {
1167 since_time = str_to_uint64(buf); /* this is the since time */
1168 Dmsg1(100, "since_time=%d\n", (int)since_time);
1169 char ed1[50], ed2[50];
1171 * Sync clocks by polling him for the time. We take
1172 * 10 samples of his time throwing out the first two.
1174 for (int i=0; i<10; i++) {
1175 bt_start = get_current_btime();
1176 bnet_sig(dir, BNET_BTIME); /* poll for time */
1177 if (bnet_recv(dir) <= 0) { /* get response */
1180 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1183 if (i < 2) { /* toss first two results */
1186 his_time = str_to_uint64(buf);
1187 rt = get_current_btime() - bt_start; /* compute round trip time */
1188 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1189 edit_uint64(bt_start, ed2));
1190 bt_adj += bt_start - his_time - rt/2;
1191 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1194 bt_adj = bt_adj / 8; /* compute average time */
1195 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1196 adj = btime_to_utime(bt_adj);
1197 since_time += adj; /* adjust for clock difference */
1199 Jmsg(jcr, M_INFO, 0, _("DIR and FD clocks differ by %d seconds, FD automatically adjusting.\n"), adj);
1201 bnet_sig(dir, BNET_EOD);
1203 Dmsg2(100, "adj = %d since_time=%d\n", (int)adj, (int)since_time);
1204 jcr->incremental = 1; /* set incremental or decremental backup */
1205 jcr->mtime = (time_t)since_time; /* set since time */
1207 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1215 return bnet_fsend(dir, OKlevel);
1218 pm_strcpy(jcr->errmsg, dir->msg);
1219 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1228 * Get session parameters from Director -- this is for a Restore command
1230 static int session_cmd(JCR *jcr)
1232 BSOCK *dir = jcr->dir_bsock;
1234 Dmsg1(100, "SessionCmd: %s", dir->msg);
1235 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1236 &jcr->VolSessionId, &jcr->VolSessionTime,
1237 &jcr->StartFile, &jcr->EndFile,
1238 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1239 pm_strcpy(jcr->errmsg, dir->msg);
1240 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1244 return bnet_fsend(dir, OKsession);
1248 * Get address of storage daemon from Director
1251 static int storage_cmd(JCR *jcr)
1253 int stored_port; /* storage daemon port */
1254 int enable_ssl; /* enable ssl to sd */
1255 BSOCK *dir = jcr->dir_bsock;
1256 BSOCK *sd; /* storage daemon bsock */
1258 Dmsg1(100, "StorageCmd: %s", dir->msg);
1259 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
1260 pm_strcpy(jcr->errmsg, dir->msg);
1261 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1264 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
1265 /* Open command communications with Storage daemon */
1266 /* Try to connect for 1 hour at 10 second intervals */
1267 sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, _("Storage daemon"),
1268 jcr->stored_addr, NULL, stored_port, 1);
1270 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1271 jcr->stored_addr, stored_port);
1272 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1273 jcr->stored_addr, stored_port);
1276 Dmsg0(110, "Connection OK to SD.\n");
1278 jcr->store_bsock = sd;
1280 bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
1281 if (!authenticate_storagedaemon(jcr)) {
1282 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1285 Dmsg0(110, "Authenticated with SD.\n");
1287 /* Send OK to Director */
1288 return bnet_fsend(dir, OKstore);
1295 static int backup_cmd(JCR *jcr)
1297 BSOCK *dir = jcr->dir_bsock;
1298 BSOCK *sd = jcr->store_bsock;
1301 char ed1[50], ed2[50];
1302 bool bDoVSS = false;
1304 #if defined(WIN32_VSS)
1305 // capture state here, if client is backed up by multiple directors
1306 // and one enables vss and the other does not then enable_vss can change
1307 // between here and where its evaluated after the job completes.
1308 bDoVSS = g_pVSSClient && enable_vss;
1310 /* Run only one at a time */
1315 set_jcr_job_status(jcr, JS_Blocked);
1316 jcr->JobType = JT_BACKUP;
1317 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1320 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1324 bnet_fsend(dir, OKbackup);
1325 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1328 * Send Append Open Session to Storage daemon
1330 bnet_fsend(sd, append_open);
1331 Dmsg1(110, ">stored: %s", sd->msg);
1333 * Expect to receive back the Ticket number
1335 if (bget_msg(sd) >= 0) {
1336 Dmsg1(110, "<stored: %s", sd->msg);
1337 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1338 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1341 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1343 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1348 * Send Append data command to Storage daemon
1350 bnet_fsend(sd, append_data, jcr->Ticket);
1351 Dmsg1(110, ">stored: %s", sd->msg);
1354 * Expect to get OK data
1356 Dmsg1(110, "<stored: %s", sd->msg);
1357 if (!response(jcr, sd, OK_data, "Append Data")) {
1361 generate_daemon_event(jcr, "JobStart");
1363 #if defined(WIN32_VSS)
1364 /* START VSS ON WIN 32 */
1366 if (g_pVSSClient->InitializeForBackup()) {
1367 /* tell vss which drives to snapshot */
1368 char szWinDriveLetters[27];
1369 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1370 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1371 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1372 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1375 /* tell user if snapshot creation of a specific drive failed */
1377 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1378 if (islower(szWinDriveLetters[i])) {
1379 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1383 /* inform user about writer states */
1384 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1385 if (g_pVSSClient->GetWriterState(i) < 1) {
1386 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1391 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1395 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.strerror());
1401 * Send Files to Storage daemon
1403 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1404 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1405 set_jcr_job_status(jcr, JS_ErrorTerminated);
1406 bnet_suppress_error_messages(sd, 1);
1407 bget_msg(sd); /* Read final response from append_data */
1408 Dmsg0(110, "Error in blast_data.\n");
1410 set_jcr_job_status(jcr, JS_Terminated);
1412 if (jcr->JobStatus != JS_Terminated) {
1413 bnet_suppress_error_messages(sd, 1);
1414 goto cleanup; /* bail out now */
1417 * Expect to get response to append_data from Storage daemon
1419 if (!response(jcr, sd, OK_append, "Append Data")) {
1420 set_jcr_job_status(jcr, JS_ErrorTerminated);
1425 * Send Append End Data to Storage daemon
1427 bnet_fsend(sd, append_end, jcr->Ticket);
1429 if (!response(jcr, sd, OK_end, "Append End")) {
1430 set_jcr_job_status(jcr, JS_ErrorTerminated);
1435 * Send Append Close to Storage daemon
1437 bnet_fsend(sd, append_close, jcr->Ticket);
1438 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1439 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1441 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1445 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1448 if (SDJobStatus != JS_Terminated) {
1449 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1455 #if defined(WIN32_VSS)
1456 /* STOP VSS ON WIN 32 */
1457 /* tell vss to close the backup session */
1459 if (g_pVSSClient->CloseBackup()) {
1460 /* inform user about writer states */
1461 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
1462 int msg_type = M_INFO;
1463 if (g_pVSSClient->GetWriterState(i) < 1) {
1464 msg_type = M_WARNING;
1467 Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
1474 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1475 edit_uint64(jcr->ReadBytes, ed1),
1476 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, (int)bDoVSS,
1478 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1480 return 0; /* return and stop command loop */
1484 * Do a Verify for Director
1487 static int verify_cmd(JCR *jcr)
1489 BSOCK *dir = jcr->dir_bsock;
1490 BSOCK *sd = jcr->store_bsock;
1491 char level[100], ed1[50], ed2[50];
1493 jcr->JobType = JT_VERIFY;
1494 if (sscanf(dir->msg, verifycmd, level) != 1) {
1495 bnet_fsend(dir, _("2994 Bad verify command: %s\n"), dir->msg);
1499 if (strcasecmp(level, "init") == 0) {
1500 jcr->JobLevel = L_VERIFY_INIT;
1501 } else if (strcasecmp(level, "catalog") == 0){
1502 jcr->JobLevel = L_VERIFY_CATALOG;
1503 } else if (strcasecmp(level, "volume") == 0){
1504 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
1505 } else if (strcasecmp(level, "data") == 0){
1506 jcr->JobLevel = L_VERIFY_DATA;
1507 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1508 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
1510 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1514 bnet_fsend(dir, OKverify);
1516 generate_daemon_event(jcr, "JobStart");
1518 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1520 switch (jcr->JobLevel) {
1522 case L_VERIFY_CATALOG:
1525 case L_VERIFY_VOLUME_TO_CATALOG:
1526 if (!open_sd_read_session(jcr)) {
1529 start_dir_heartbeat(jcr);
1530 do_verify_volume(jcr);
1531 stop_dir_heartbeat(jcr);
1533 * Send Close session command to Storage daemon
1535 bnet_fsend(sd, read_close, jcr->Ticket);
1536 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1538 /* ****FIXME**** check response */
1539 bget_msg(sd); /* get OK */
1541 /* Inform Storage daemon that we are done */
1542 bnet_sig(sd, BNET_TERMINATE);
1545 case L_VERIFY_DISK_TO_CATALOG:
1549 bnet_fsend(dir, _("2994 Bad verify level: %s\n"), dir->msg);
1553 bnet_sig(dir, BNET_EOD);
1555 /* Send termination status back to Dir */
1556 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1557 edit_uint64(jcr->ReadBytes, ed1),
1558 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1560 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1562 /* Inform Director that we are done */
1563 bnet_sig(dir, BNET_TERMINATE);
1564 return 0; /* return and terminate command loop */
1568 * Do a Restore for Director
1571 static int restore_cmd(JCR *jcr)
1573 BSOCK *dir = jcr->dir_bsock;
1574 BSOCK *sd = jcr->store_bsock;
1578 char ed1[50], ed2[50];
1581 * Scan WHERE (base directory for restore) from command
1583 Dmsg0(150, "restore command\n");
1584 /* Pickup where string */
1585 where = get_memory(dir->msglen+1);
1588 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
1589 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1590 pm_strcpy(jcr->errmsg, dir->msg);
1591 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1596 /* Turn / into nothing */
1597 if (IsPathSeparator(where[0]) && where[1] == '\0') {
1601 Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
1602 unbash_spaces(where);
1603 jcr->where = bstrdup(where);
1604 free_pool_memory(where);
1605 jcr->replace = replace;
1606 jcr->prefix_links = prefix_links;
1608 bnet_fsend(dir, OKrestore);
1609 Dmsg1(110, "bfiled>dird: %s", dir->msg);
1611 jcr->JobType = JT_RESTORE;
1613 set_jcr_job_status(jcr, JS_Blocked);
1615 if (!open_sd_read_session(jcr)) {
1616 set_jcr_job_status(jcr, JS_ErrorTerminated);
1620 set_jcr_job_status(jcr, JS_Running);
1623 * Do restore of files and data
1625 start_dir_heartbeat(jcr);
1626 generate_daemon_event(jcr, "JobStart");
1628 stop_dir_heartbeat(jcr);
1630 set_jcr_job_status(jcr, JS_Terminated);
1631 if (jcr->JobStatus != JS_Terminated) {
1632 bnet_suppress_error_messages(sd, 1);
1636 * Send Close session command to Storage daemon
1638 bnet_fsend(sd, read_close, jcr->Ticket);
1639 Dmsg1(130, "bfiled>stored: %s", sd->msg);
1641 bget_msg(sd); /* get OK */
1643 /* Inform Storage daemon that we are done */
1644 bnet_sig(sd, BNET_TERMINATE);
1649 set_jcr_job_status(jcr, JS_ErrorTerminated);
1651 /* Send termination status back to Dir */
1652 bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
1653 edit_uint64(jcr->ReadBytes, ed1),
1654 edit_uint64(jcr->JobBytes, ed2), jcr->Errors, 0,
1656 Dmsg1(110, "End FD msg: %s\n", dir->msg);
1658 /* Inform Director that we are done */
1659 bnet_sig(dir, BNET_TERMINATE);
1661 Dmsg0(130, "Done in job.c\n");
1662 return 0; /* return and terminate command loop */
1665 static int open_sd_read_session(JCR *jcr)
1667 BSOCK *sd = jcr->store_bsock;
1670 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
1673 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
1674 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
1675 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
1677 * Open Read Session with Storage daemon
1679 bnet_fsend(sd, read_open, "DummyVolume",
1680 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
1681 jcr->StartBlock, jcr->EndBlock);
1682 Dmsg1(110, ">stored: %s", sd->msg);
1687 if (bget_msg(sd) >= 0) {
1688 Dmsg1(110, "bfiled<stored: %s", sd->msg);
1689 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1690 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
1693 Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
1695 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
1699 if (!send_bootstrap_file(jcr)) {
1704 * Start read of data with Storage daemon
1706 bnet_fsend(sd, read_data, jcr->Ticket);
1707 Dmsg1(110, ">stored: %s", sd->msg);
1712 if (!response(jcr, sd, OK_data, "Read Data")) {
1719 * Destroy the Job Control Record and associated
1720 * resources (sockets).
1722 static void filed_free_jcr(JCR *jcr)
1724 if (jcr->store_bsock) {
1725 bnet_close(jcr->store_bsock);
1727 free_bootstrap(jcr);
1728 if (jcr->last_fname) {
1729 free_pool_memory(jcr->last_fname);
1731 free_runscripts(jcr->RunScripts);
1732 delete jcr->RunScripts;
1738 * Get response from Storage daemon to a command we
1739 * sent. Check that the response is OK.
1741 * Returns: 0 on failure
1744 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
1749 if (bget_msg(sd) > 0) {
1750 Dmsg0(110, sd->msg);
1751 if (strcmp(sd->msg, resp) == 0) {
1755 if (job_canceled(jcr)) {
1756 return 0; /* if canceled avoid useless error messages */
1758 if (is_bnet_error(sd)) {
1759 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
1760 cmd, bnet_strerror(sd));
1762 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
1763 cmd, resp, sd->msg);
1768 static int send_bootstrap_file(JCR *jcr)
1772 BSOCK *sd = jcr->store_bsock;
1773 const char *bootstrap = "bootstrap\n";
1776 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
1777 if (!jcr->RestoreBootstrap) {
1780 bs = fopen(jcr->RestoreBootstrap, "rb");
1783 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
1784 jcr->RestoreBootstrap, be.strerror());
1785 set_jcr_job_status(jcr, JS_ErrorTerminated);
1788 sd->msglen = pm_strcpy(sd->msg, bootstrap);
1790 while (fgets(buf, sizeof(buf), bs)) {
1791 sd->msglen = Mmsg(sd->msg, "%s", buf);
1794 bnet_sig(sd, BNET_EOD);
1796 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
1797 set_jcr_job_status(jcr, JS_ErrorTerminated);
1803 free_bootstrap(jcr);