2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
39 #if defined(WIN32_VSS)
42 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
43 static int enable_vss = 0;
47 * As Windows saves ACLs as part of the standard backup stream
48 * we just pretend here that is has implicit acl support.
50 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
51 const bool have_acl = true;
53 const bool have_acl = false;
56 #if defined(HAVE_XATTR)
57 const bool have_xattr = true;
59 const bool have_xattr = false;
62 extern CLIENT *me; /* our client resource */
64 /* Imported functions */
65 extern int status_cmd(JCR *jcr);
66 extern int qstatus_cmd(JCR *jcr);
67 extern int accurate_cmd(JCR *jcr);
69 /* Forward referenced functions */
70 static int backup_cmd(JCR *jcr);
71 static int bootstrap_cmd(JCR *jcr);
72 static int cancel_cmd(JCR *jcr);
73 static int setdebug_cmd(JCR *jcr);
74 static int estimate_cmd(JCR *jcr);
75 static int hello_cmd(JCR *jcr);
76 static int job_cmd(JCR *jcr);
77 static int fileset_cmd(JCR *jcr);
78 static int level_cmd(JCR *jcr);
79 static int verify_cmd(JCR *jcr);
80 static int restore_cmd(JCR *jcr);
81 static int end_restore_cmd(JCR *jcr);
82 static int storage_cmd(JCR *jcr);
83 static int session_cmd(JCR *jcr);
84 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
85 static void filed_free_jcr(JCR *jcr);
86 static int open_sd_read_session(JCR *jcr);
87 static int send_bootstrap_file(JCR *jcr);
88 static int runscript_cmd(JCR *jcr);
89 static int runbefore_cmd(JCR *jcr);
90 static int runafter_cmd(JCR *jcr);
91 static int runbeforenow_cmd(JCR *jcr);
92 static int restore_object_cmd(JCR *jcr);
93 static int set_options(findFOPTS *fo, const char *opts);
94 static void set_storage_auth_key(JCR *jcr, char *key);
95 static int sm_dump_cmd(JCR *jcr);
97 static int exit_cmd(JCR *jcr);
100 /* Exported functions */
105 int monitoraccess; /* specify if monitors have access to this function */
109 * The following are the recognized commands from the Director.
111 static struct s_cmds cmds[] = {
112 {"backup", backup_cmd, 0},
113 {"cancel", cancel_cmd, 0},
114 {"setdebug=", setdebug_cmd, 0},
115 {"estimate", estimate_cmd, 0},
116 {"Hello", hello_cmd, 1},
117 {"fileset", fileset_cmd, 0},
118 {"JobId=", job_cmd, 0},
119 {"level = ", level_cmd, 0},
120 {"restore ", restore_cmd, 0},
121 {"endrestore", end_restore_cmd, 0},
122 {"session", session_cmd, 0},
123 {"status", status_cmd, 1},
124 {".status", qstatus_cmd, 1},
125 {"storage ", storage_cmd, 0},
126 {"verify", verify_cmd, 0},
127 {"bootstrap", bootstrap_cmd, 0},
128 {"RunBeforeNow", runbeforenow_cmd, 0},
129 {"RunBeforeJob", runbefore_cmd, 0},
130 {"RunAfterJob", runafter_cmd, 0},
131 {"Run", runscript_cmd, 0},
132 {"accurate", accurate_cmd, 0},
133 {"restoreobject", restore_object_cmd, 0},
134 {"sm_dump", sm_dump_cmd, 0},
136 {"exit", exit_cmd, 0},
138 {NULL, NULL} /* list terminator */
141 /* Commands received from director that need scanning */
142 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
143 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
144 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
145 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
146 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
147 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
148 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
149 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
150 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
151 static char endrestoreobjectcmd[] = "restoreobject end\n";
152 static char verifycmd[] = "verify level=%30s";
153 static char estimatecmd[] = "estimate listing=%d";
154 static char runbefore[] = "RunBeforeJob %s";
155 static char runafter[] = "RunAfterJob %s";
156 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
158 /* Responses sent to Director */
159 static char errmsg[] = "2999 Invalid command\n";
160 static char no_auth[] = "2998 No Authorization\n";
161 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
162 static char OKinc[] = "2000 OK include\n";
163 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
164 static char OKlevel[] = "2000 OK level\n";
165 static char OKbackup[] = "2000 OK backup\n";
166 static char OKbootstrap[] = "2000 OK bootstrap\n";
167 static char OKverify[] = "2000 OK verify\n";
168 static char OKrestore[] = "2000 OK restore\n";
169 static char OKsession[] = "2000 OK session\n";
170 static char OKstore[] = "2000 OK storage\n";
171 static char OKstoreend[] = "2000 OK storage end\n";
172 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
173 static char OKsetdebug[] = "2000 OK setdebug=%d trace=%d hangup=%d\n";
174 static char BADjob[] = "2901 Bad Job\n";
175 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
176 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
177 static char OKRunBefore[] = "2000 OK RunBefore\n";
178 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
179 static char OKRunAfter[] = "2000 OK RunAfter\n";
180 static char OKRunScript[] = "2000 OK RunScript\n";
181 static char BADcmd[] = "2902 Bad %s\n";
182 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
185 /* Responses received from Storage Daemon */
186 static char OK_end[] = "3000 OK end\n";
187 static char OK_close[] = "3000 OK close Status = %d\n";
188 static char OK_open[] = "3000 OK open ticket = %d\n";
189 static char OK_data[] = "3000 OK data\n";
190 static char OK_append[] = "3000 OK append data\n";
191 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
194 /* Commands sent to Storage Daemon */
195 static char append_open[] = "append open session\n";
196 static char append_data[] = "append data %d\n";
197 static char append_end[] = "append end session %d\n";
198 static char append_close[] = "append close session %d\n";
199 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
200 static char read_data[] = "read data %d\n";
201 static char read_close[] = "read close session %d\n";
204 * Accept requests from a Director
206 * NOTE! We are running as a separate thread
208 * Send output one line
209 * at a time followed by a zero length transmission.
211 * Return when the connection is terminated or there
214 * Basic task here is:
215 * Authenticate Director (during Hello command).
216 * Accept commands one at a time from the Director
219 * Concerning ClientRunBefore/After, the sequence of events
220 * is rather critical. If they are not done in the right
221 * order one can easily get FD->SD timeouts if the script
224 * The current sequence of events is:
225 * 1. Dir starts job with FD
226 * 2. Dir connects to SD
227 * 3. Dir connects to FD
228 * 4. FD connects to SD
229 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
230 * 6. Dir sends include/exclude
231 * 7. FD sends data to SD
232 * 8. SD/FD disconnects while SD despools data and attributes (optional)
233 * 9. FD runs ClientRunAfterJob
236 void *handle_client_request(void *dirp)
241 BSOCK *dir = (BSOCK *)dirp;
242 const char jobname[12] = "*Director*";
245 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
246 jcr->dir_bsock = dir;
247 jcr->ff = init_find_files();
248 // save_cwd.save(jcr);
249 jcr->start_time = time(NULL);
250 jcr->RunScripts = New(alist(10, not_owned_by_alist));
251 jcr->last_fname = get_pool_memory(PM_FNAME);
252 jcr->last_fname[0] = 0;
253 jcr->client_name = get_memory(strlen(my_name) + 1);
254 pm_strcpy(jcr->client_name, my_name);
255 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
256 jcr->crypto.pki_sign = me->pki_sign;
257 jcr->crypto.pki_encrypt = me->pki_encrypt;
258 jcr->crypto.pki_keypair = me->pki_keypair;
259 jcr->crypto.pki_signers = me->pki_signers;
260 jcr->crypto.pki_recipients = me->pki_recipients;
262 enable_backup_privileges(NULL, 1 /* ignore_errors */);
264 /**********FIXME******* add command handler error code */
266 for (quit=false; !quit;) {
268 if (dir->recv() < 0) {
269 break; /* connection terminated */
271 dir->msg[dir->msglen] = 0;
272 Dmsg1(100, "<dird: %s", dir->msg);
274 for (i=0; cmds[i].cmd; i++) {
275 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
276 found = true; /* indicate command found */
277 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
279 dir->signal(BNET_EOD);
282 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
283 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
284 dir->fsend(invalid_cmd);
285 dir->signal(BNET_EOD);
288 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
289 if (!cmds[i].func(jcr)) { /* do command */
290 quit = true; /* error or fully terminated, get out */
291 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
296 if (!found) { /* command not found */
303 /* Inform Storage daemon that we are done */
304 if (jcr->store_bsock) {
305 jcr->store_bsock->signal(BNET_TERMINATE);
308 /* Run the after job */
309 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
311 if (jcr->JobId) { /* send EndJob if running a job */
312 char ed1[50], ed2[50];
313 /* Send termination status back to Dir */
314 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
315 edit_uint64(jcr->ReadBytes, ed1),
316 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
317 jcr->crypto.pki_encrypt);
318 Dmsg1(110, "End FD msg: %s\n", dir->msg);
321 generate_daemon_event(jcr, "JobEnd");
322 generate_plugin_event(jcr, bEventJobEnd);
324 dequeue_messages(jcr); /* send any queued messages */
326 /* Inform Director that we are done */
327 dir->signal(BNET_TERMINATE);
329 free_plugins(jcr); /* release instantiated plugins */
330 free_and_null_pool_memory(jcr->job_metadata);
332 /* Clean up fileset */
333 FF_PKT *ff = jcr->ff;
334 findFILESET *fileset = ff->fileset;
337 /* Delete FileSet Include lists */
338 for (i=0; i<fileset->include_list.size(); i++) {
339 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
340 for (j=0; j<incexe->opts_list.size(); j++) {
341 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
345 for (k=0; k<fo->regex.size(); k++) {
346 regfree((regex_t *)fo->regex.get(k));
348 for (k=0; k<fo->regexdir.size(); k++) {
349 regfree((regex_t *)fo->regexdir.get(k));
351 for (k=0; k<fo->regexfile.size(); k++) {
352 regfree((regex_t *)fo->regexfile.get(k));
355 fo->regexdir.destroy();
356 fo->regexfile.destroy();
358 fo->wilddir.destroy();
359 fo->wildfile.destroy();
360 fo->wildbase.destroy();
362 fo->fstype.destroy();
363 fo->drivetype.destroy();
365 incexe->opts_list.destroy();
366 incexe->name_list.destroy();
367 incexe->plugin_list.destroy();
368 if (incexe->ignoredir) {
369 free(incexe->ignoredir);
372 fileset->include_list.destroy();
374 /* Delete FileSet Exclude lists */
375 for (i=0; i<fileset->exclude_list.size(); i++) {
376 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
377 for (j=0; j<incexe->opts_list.size(); j++) {
378 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
380 fo->regexdir.destroy();
381 fo->regexfile.destroy();
383 fo->wilddir.destroy();
384 fo->wildfile.destroy();
385 fo->wildbase.destroy();
387 fo->fstype.destroy();
388 fo->drivetype.destroy();
390 incexe->opts_list.destroy();
391 incexe->name_list.destroy();
392 incexe->plugin_list.destroy();
393 if (incexe->ignoredir) {
394 free(incexe->ignoredir);
397 fileset->exclude_list.destroy();
401 Dmsg0(100, "Calling term_find_files\n");
402 term_find_files(jcr->ff);
403 // save_cwd.restore(jcr);
404 // save_cwd.release();
406 Dmsg0(100, "Done with term_find_files\n");
407 free_jcr(jcr); /* destroy JCR record */
408 Dmsg0(100, "Done with free_jcr\n");
410 garbage_collect_memory_pool();
414 static int sm_dump_cmd(JCR *jcr)
417 sm_dump(false, true);
418 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
423 static int exit_cmd(JCR *jcr)
425 jcr->dir_bsock->fsend("2000 exit OK\n");
433 * Hello from Director he must identify himself and provide his
436 static int hello_cmd(JCR *jcr)
438 Dmsg0(120, "Calling Authenticate\n");
439 if (!authenticate_director(jcr)) {
442 Dmsg0(120, "OK Authenticate\n");
443 jcr->authenticated = true;
450 static int cancel_cmd(JCR *jcr)
452 BSOCK *dir = jcr->dir_bsock;
453 char Job[MAX_NAME_LENGTH];
456 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
457 if (!(cjcr=get_jcr_by_full_name(Job))) {
458 dir->fsend(_("2901 Job %s not found.\n"), Job);
460 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
461 cjcr->setJobStatus(JS_Canceled);
462 if (cjcr->store_bsock) {
463 cjcr->store_bsock->set_timed_out();
464 cjcr->store_bsock->set_terminated();
465 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
468 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
471 dir->fsend(_("2902 Error scanning cancel command.\n"));
473 dir->signal(BNET_EOD);
478 * Set debug level as requested by the Director
481 static int setdebug_cmd(JCR *jcr)
483 BSOCK *dir = jcr->dir_bsock;
484 int32_t level, trace, hangup;
487 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
488 scan = sscanf(dir->msg, "setdebug=%d trace=%d hangup=%d",
489 &level, &trace, &hangup);
491 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
492 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace) != 2) {
493 pm_strcpy(jcr->errmsg, dir->msg);
494 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
505 Dmsg3(50, "level=%d trace=%d hangup=%d\n", level, get_trace(), get_hangup());
506 return dir->fsend(OKsetdebug, level, get_trace(), get_hangup());
510 static int estimate_cmd(JCR *jcr)
512 BSOCK *dir = jcr->dir_bsock;
513 char ed1[50], ed2[50];
515 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
516 pm_strcpy(jcr->errmsg, dir->msg);
517 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
518 dir->fsend(_("2992 Bad estimate command.\n"));
522 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
523 edit_uint64_with_commas(jcr->JobBytes, ed2));
524 dir->signal(BNET_EOD);
529 * Get JobId and Storage Daemon Authorization key from Director
531 static int job_cmd(JCR *jcr)
533 BSOCK *dir = jcr->dir_bsock;
534 POOL_MEM sd_auth_key(PM_MESSAGE);
535 sd_auth_key.check_size(dir->msglen);
537 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
538 &jcr->VolSessionId, &jcr->VolSessionTime,
539 sd_auth_key.c_str()) != 5) {
540 pm_strcpy(jcr->errmsg, dir->msg);
541 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
545 set_storage_auth_key(jcr, sd_auth_key.c_str());
546 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
547 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
548 new_plugins(jcr); /* instantiate plugins for this jcr */
549 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
551 return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
553 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
557 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param)
562 return jcr->director->hdr.name;
570 static int runbefore_cmd(JCR *jcr)
573 BSOCK *dir = jcr->dir_bsock;
574 POOLMEM *cmd = get_memory(dir->msglen+1);
577 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
578 if (sscanf(dir->msg, runbefore, cmd) != 1) {
579 pm_strcpy(jcr->errmsg, dir->msg);
580 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
581 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
587 /* Run the command now */
588 script = new_runscript();
589 script->set_job_code_callback(job_code_callback_filed);
590 script->set_command(cmd);
591 script->when = SCRIPT_Before;
592 ok = script->run(jcr, "ClientRunBeforeJob");
593 free_runscript(script);
597 dir->fsend(OKRunBefore);
600 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
605 static int runbeforenow_cmd(JCR *jcr)
607 BSOCK *dir = jcr->dir_bsock;
609 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
610 if (job_canceled(jcr)) {
611 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
612 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
615 dir->fsend(OKRunBeforeNow);
616 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
621 static int runafter_cmd(JCR *jcr)
623 BSOCK *dir = jcr->dir_bsock;
624 POOLMEM *msg = get_memory(dir->msglen+1);
627 Dmsg1(100, "runafter_cmd: %s", dir->msg);
628 if (sscanf(dir->msg, runafter, msg) != 1) {
629 pm_strcpy(jcr->errmsg, dir->msg);
630 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
631 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
637 cmd = new_runscript();
638 cmd->set_job_code_callback(job_code_callback_filed);
639 cmd->set_command(msg);
640 cmd->on_success = true;
641 cmd->on_failure = false;
642 cmd->when = SCRIPT_After;
644 jcr->RunScripts->append(cmd);
646 free_pool_memory(msg);
647 return dir->fsend(OKRunAfter);
650 static int runscript_cmd(JCR *jcr)
652 BSOCK *dir = jcr->dir_bsock;
653 POOLMEM *msg = get_memory(dir->msglen+1);
654 int on_success, on_failure, fail_on_error;
656 RUNSCRIPT *cmd = new_runscript() ;
657 cmd->set_job_code_callback(job_code_callback_filed);
659 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
660 /* Note, we cannot sscanf into bools */
661 if (sscanf(dir->msg, runscript, &on_success,
666 pm_strcpy(jcr->errmsg, dir->msg);
667 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
668 dir->fsend(_("2905 Bad RunScript command.\n"));
673 cmd->on_success = on_success;
674 cmd->on_failure = on_failure;
675 cmd->fail_on_error = fail_on_error;
678 cmd->set_command(msg);
680 jcr->RunScripts->append(cmd);
682 free_pool_memory(msg);
683 return dir->fsend(OKRunScript);
687 * This reads data sent from the Director from the
688 * RestoreObject table that allows us to get objects
689 * that were backed up (VSS .xml data) and are needed
690 * before starting the restore.
692 static int restore_object_cmd(JCR *jcr)
694 BSOCK *dir = jcr->dir_bsock;
696 restore_object_pkt rop;
698 memset(&rop, 0, sizeof(rop));
699 rop.pkt_size = sizeof(rop);
700 rop.pkt_end = sizeof(rop);
702 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
703 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
704 generate_plugin_event(jcr, bEventRestoreObject, NULL);
705 return dir->fsend(OKRestoreObject);
708 rop.plugin_name = (char *) malloc (dir->msglen);
709 *rop.plugin_name = 0;
711 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
712 &rop.object_full_len, &rop.object_index,
713 &rop.object_type, &rop.object_compression, &FileIndex,
714 rop.plugin_name) != 8) {
716 /* Old version, no plugin_name */
717 if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
718 &rop.object_full_len, &rop.object_index,
719 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
720 Dmsg0(5, "Bad restore object command\n");
721 pm_strcpy(jcr->errmsg, dir->msg);
722 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
727 unbash_spaces(rop.plugin_name);
729 Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
730 "FI=%d plugin_name=%s\n",
731 rop.JobId, rop.object_len, rop.object_full_len,
732 rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
733 /* Read Object name */
734 if (dir->recv() < 0) {
737 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
738 rop.object_name = bstrdup(dir->msg);
741 if (dir->recv() < 0) {
744 /* Transfer object from message buffer, and get new message buffer */
745 rop.object = dir->msg;
746 dir->msg = get_pool_memory(PM_MESSAGE);
748 /* If object is compressed, uncompress it */
749 if (rop.object_compression == 1) { /* zlib level 9 */
751 int out_len = rop.object_full_len + 100;
752 POOLMEM *obj = get_memory(out_len);
753 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
754 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
755 Dmsg1(100, "Zinflate stat=%d\n", stat);
756 if (out_len != rop.object_full_len) {
757 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
758 rop.object_full_len, out_len, rop.object_name);
760 free_pool_memory(rop.object); /* release compressed object */
761 rop.object = obj; /* new uncompressed object */
762 rop.object_len = out_len;
764 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
765 /* we still need to do this to detect a vss restore */
766 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
767 Dmsg0(100, "got job metadata\n");
768 //free_and_null_pool_memory(jcr->job_metadata);
769 jcr->job_metadata = rop.object; /* this is like a boolean in the restore case */
770 // rop.object = NULL; /* but not this */
773 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
775 if (rop.object_name) {
776 free(rop.object_name);
779 free_pool_memory(rop.object);
781 if (rop.plugin_name) {
782 free(rop.plugin_name);
785 Dmsg1(100, "Send: %s", OKRestoreObject);
789 dir->fsend(_("2909 Bad RestoreObject command.\n"));
795 static bool init_fileset(JCR *jcr)
798 findFILESET *fileset;
807 fileset = (findFILESET *)malloc(sizeof(findFILESET));
808 memset(fileset, 0, sizeof(findFILESET));
809 ff->fileset = fileset;
810 fileset->state = state_none;
811 fileset->include_list.init(1, true);
812 fileset->exclude_list.init(1, true);
816 static void append_file(JCR *jcr, findINCEXE *incexe,
817 const char *buf, bool is_file)
820 incexe->name_list.append(new_dlistString(buf));
822 } else if (me->plugin_directory) {
823 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
824 incexe->plugin_list.append(new_dlistString(buf));
827 Jmsg(jcr, M_FATAL, 0,
828 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
834 * Add fname to include/exclude fileset list. First check for
835 * | and < and if necessary perform command.
837 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
839 findFILESET *fileset = jcr->ff->fileset;
852 p++; /* skip over | */
853 fn = get_pool_memory(PM_FNAME);
854 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
855 bpipe = open_bpipe(fn, 0, "r");
858 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
860 free_pool_memory(fn);
863 free_pool_memory(fn);
864 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
865 strip_trailing_junk(buf);
866 append_file(jcr, fileset->incexe, buf, is_file);
868 if ((stat=close_bpipe(bpipe)) != 0) {
870 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
871 p, be.code(stat), be.bstrerror(stat));
876 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
877 p++; /* skip over < */
878 if ((ffd = fopen(p, "rb")) == NULL) {
880 Jmsg(jcr, M_FATAL, 0,
881 _("Cannot open FileSet input file: %s. ERR=%s\n"),
885 while (fgets(buf, sizeof(buf), ffd)) {
886 strip_trailing_junk(buf);
887 append_file(jcr, fileset->incexe, buf, is_file);
892 append_file(jcr, fileset->incexe, fname, is_file);
897 void set_incexe(JCR *jcr, findINCEXE *incexe)
899 findFILESET *fileset = jcr->ff->fileset;
900 fileset->incexe = incexe;
905 * Define a new Exclude block in the FileSet
907 findINCEXE *new_exclude(JCR *jcr)
909 findFILESET *fileset = jcr->ff->fileset;
912 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
913 memset(fileset->incexe, 0, sizeof(findINCEXE));
914 fileset->incexe->opts_list.init(1, true);
915 fileset->incexe->name_list.init();
916 fileset->incexe->plugin_list.init();
917 fileset->exclude_list.append(fileset->incexe);
918 return fileset->incexe;
922 * Define a new Include block in the FileSet
924 findINCEXE *new_include(JCR *jcr)
926 findFILESET *fileset = jcr->ff->fileset;
929 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
930 memset(fileset->incexe, 0, sizeof(findINCEXE));
931 fileset->incexe->opts_list.init(1, true);
932 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
933 fileset->incexe->plugin_list.init();
934 fileset->include_list.append(fileset->incexe);
935 return fileset->incexe;
939 * Define a new preInclude block in the FileSet
940 * That is the include is prepended to the other
941 * Includes. This is used for plugin exclusions.
943 findINCEXE *new_preinclude(JCR *jcr)
945 findFILESET *fileset = jcr->ff->fileset;
947 /* New pre-include */
948 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
949 memset(fileset->incexe, 0, sizeof(findINCEXE));
950 fileset->incexe->opts_list.init(1, true);
951 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
952 fileset->incexe->plugin_list.init();
953 fileset->include_list.prepend(fileset->incexe);
954 return fileset->incexe;
957 static findFOPTS *start_options(FF_PKT *ff)
959 int state = ff->fileset->state;
960 findINCEXE *incexe = ff->fileset->incexe;
962 if (state != state_options) {
963 ff->fileset->state = state_options;
964 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
965 memset(fo, 0, sizeof(findFOPTS));
966 fo->regex.init(1, true);
967 fo->regexdir.init(1, true);
968 fo->regexfile.init(1, true);
969 fo->wild.init(1, true);
970 fo->wilddir.init(1, true);
971 fo->wildfile.init(1, true);
972 fo->wildbase.init(1, true);
973 fo->base.init(1, true);
974 fo->fstype.init(1, true);
975 fo->drivetype.init(1, true);
976 incexe->current_opts = fo;
977 incexe->opts_list.append(fo);
979 return incexe->current_opts;
983 * Used by plugins to define a new options block
985 void new_options(JCR *jcr, findINCEXE *incexe)
988 incexe = jcr->ff->fileset->incexe;
990 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
991 memset(fo, 0, sizeof(findFOPTS));
992 fo->regex.init(1, true);
993 fo->regexdir.init(1, true);
994 fo->regexfile.init(1, true);
995 fo->wild.init(1, true);
996 fo->wilddir.init(1, true);
997 fo->wildfile.init(1, true);
998 fo->wildbase.init(1, true);
999 fo->base.init(1, true);
1000 fo->fstype.init(1, true);
1001 fo->drivetype.init(1, true);
1002 incexe->current_opts = fo;
1003 incexe->opts_list.prepend(fo);
1004 jcr->ff->fileset->state = state_options;
1008 * Add a regex to the current fileset
1010 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1012 findFOPTS *current_opts = start_options(jcr->ff);
1017 preg = (regex_t *)malloc(sizeof(regex_t));
1018 if (current_opts->flags & FO_IGNORECASE) {
1019 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1021 rc = regcomp(preg, item, REG_EXTENDED);
1024 regerror(rc, preg, prbuf, sizeof(prbuf));
1027 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1031 current_opts->regex.append(preg);
1032 } else if (type == 'D') {
1033 current_opts->regexdir.append(preg);
1034 } else if (type == 'F') {
1035 current_opts->regexfile.append(preg);
1039 return state_options;
1043 * Add a wild card to the current fileset
1045 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1047 findFOPTS *current_opts = start_options(jcr->ff);
1050 current_opts->wild.append(bstrdup(item));
1051 } else if (type == 'D') {
1052 current_opts->wilddir.append(bstrdup(item));
1053 } else if (type == 'F') {
1054 current_opts->wildfile.append(bstrdup(item));
1055 } else if (type == 'B') {
1056 current_opts->wildbase.append(bstrdup(item));
1060 return state_options;
1065 * Add options to the current fileset
1067 int add_options_to_fileset(JCR *jcr, const char *item)
1069 findFOPTS *current_opts = start_options(jcr->ff);
1071 set_options(current_opts, item);
1072 return state_options;
1075 static void add_fileset(JCR *jcr, const char *item)
1077 FF_PKT *ff = jcr->ff;
1078 findFILESET *fileset = ff->fileset;
1079 int state = fileset->state;
1080 findFOPTS *current_opts;
1082 /* Get code, optional subcode, and position item past the dividing space */
1083 Dmsg1(100, "%s\n", item);
1088 int subcode = ' '; /* A space is always a valid subcode */
1089 if (item[0] != '\0' && item[0] != ' ') {
1097 /* Skip all lines we receive after an error */
1098 if (state == state_error) {
1099 Dmsg0(100, "State=error return\n");
1104 * The switch tests the code for validity.
1105 * The subcode is always good if it is a space, otherwise we must confirm.
1106 * We set state to state_error first assuming the subcode is invalid,
1107 * requiring state to be set in cases below that handle subcodes.
1109 if (subcode != ' ') {
1110 state = state_error;
1111 Dmsg0(100, "Set state=error or double code.\n");
1115 (void)new_include(jcr);
1118 (void)new_exclude(jcr);
1120 case 'N': /* null */
1123 case 'F': /* file = */
1124 /* File item to include or exclude list */
1125 state = state_include;
1126 add_file_to_fileset(jcr, item, true);
1128 case 'P': /* plugin */
1129 /* Plugin item to include list */
1130 state = state_include;
1131 add_file_to_fileset(jcr, item, false);
1133 case 'R': /* regex */
1134 state = add_regex_to_fileset(jcr, item, subcode);
1137 current_opts = start_options(ff);
1138 current_opts->base.append(bstrdup(item));
1139 state = state_options;
1141 case 'X': /* Filetype or Drive type */
1142 current_opts = start_options(ff);
1143 state = state_options;
1144 if (subcode == ' ') {
1145 current_opts->fstype.append(bstrdup(item));
1146 } else if (subcode == 'D') {
1147 current_opts->drivetype.append(bstrdup(item));
1149 state = state_error;
1152 case 'W': /* wild cards */
1153 state = add_wild_to_fileset(jcr, item, subcode);
1155 case 'O': /* Options */
1156 state = add_options_to_fileset(jcr, item);
1158 case 'Z': /* ignore dir */
1159 state = state_include;
1160 fileset->incexe->ignoredir = bstrdup(item);
1163 current_opts = start_options(ff);
1164 // current_opts->reader = bstrdup(item); /* deprecated */
1165 state = state_options;
1168 current_opts = start_options(ff);
1169 // current_opts->writer = bstrdup(item); /* deprecated */
1170 state = state_options;
1172 case 'G': /* Plugin command for this Option block */
1173 current_opts = start_options(ff);
1174 current_opts->plugin = bstrdup(item);
1175 state = state_options;
1178 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1179 state = state_error;
1182 ff->fileset->state = state;
1185 static bool term_fileset(JCR *jcr)
1187 FF_PKT *ff = jcr->ff;
1189 #ifdef xxx_DEBUG_CODE
1190 findFILESET *fileset = ff->fileset;
1193 for (i=0; i<fileset->include_list.size(); i++) {
1194 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1196 for (j=0; j<incexe->opts_list.size(); j++) {
1197 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1198 for (k=0; k<fo->regex.size(); k++) {
1199 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1201 for (k=0; k<fo->regexdir.size(); k++) {
1202 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1204 for (k=0; k<fo->regexfile.size(); k++) {
1205 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1207 for (k=0; k<fo->wild.size(); k++) {
1208 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1210 for (k=0; k<fo->wilddir.size(); k++) {
1211 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1213 for (k=0; k<fo->wildfile.size(); k++) {
1214 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1216 for (k=0; k<fo->wildbase.size(); k++) {
1217 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1219 for (k=0; k<fo->base.size(); k++) {
1220 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1222 for (k=0; k<fo->fstype.size(); k++) {
1223 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1225 for (k=0; k<fo->drivetype.size(); k++) {
1226 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1229 if (incexe->ignoredir) {
1230 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1233 foreach_dlist(node, &incexe->name_list) {
1234 Dmsg1(400, "F %s\n", node->c_str());
1236 foreach_dlist(node, &incexe->plugin_list) {
1237 Dmsg1(400, "P %s\n", node->c_str());
1240 for (i=0; i<fileset->exclude_list.size(); i++) {
1241 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1243 for (j=0; j<incexe->opts_list.size(); j++) {
1244 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1245 for (k=0; k<fo->regex.size(); k++) {
1246 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1248 for (k=0; k<fo->regexdir.size(); k++) {
1249 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1251 for (k=0; k<fo->regexfile.size(); k++) {
1252 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1254 for (k=0; k<fo->wild.size(); k++) {
1255 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1257 for (k=0; k<fo->wilddir.size(); k++) {
1258 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1260 for (k=0; k<fo->wildfile.size(); k++) {
1261 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1263 for (k=0; k<fo->wildbase.size(); k++) {
1264 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1266 for (k=0; k<fo->base.size(); k++) {
1267 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1269 for (k=0; k<fo->fstype.size(); k++) {
1270 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1272 for (k=0; k<fo->drivetype.size(); k++) {
1273 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1277 foreach_dlist(node, &incexe->name_list) {
1278 Dmsg1(400, "F %s\n", node->c_str());
1280 foreach_dlist(node, &incexe->plugin_list) {
1281 Dmsg1(400, "P %s\n", node->c_str());
1285 return ff->fileset->state != state_error;
1290 * As an optimization, we should do this during
1291 * "compile" time in filed/job.c, and keep only a bit mask
1292 * and the Verify options.
1294 static int set_options(findFOPTS *fo, const char *opts)
1300 // Commented out as it is not backward compatible - KES
1302 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1305 for (p=opts; *p; p++) {
1307 case 'a': /* alway replace */
1308 case '0': /* no option */
1311 fo->flags |= FO_EXCLUDE;
1314 fo->flags |= FO_MULTIFS;
1316 case 'h': /* no recursion */
1317 fo->flags |= FO_NO_RECURSION;
1319 case 'H': /* no hard link handling */
1320 fo->flags |= FO_NO_HARDLINK;
1323 fo->flags |= FO_IGNORECASE;
1326 fo->flags |= FO_MD5;
1329 fo->flags |= FO_NOREPLACE;
1331 case 'p': /* use portable data format */
1332 fo->flags |= FO_PORTABLE;
1334 case 'R': /* Resource forks and Finder Info */
1335 fo->flags |= FO_HFSPLUS;
1337 case 'r': /* read fifo */
1338 fo->flags |= FO_READFIFO;
1343 fo->flags |= FO_SHA1;
1348 fo->flags |= FO_SHA256;
1352 fo->flags |= FO_SHA512;
1358 * If 2 or 3 is seen here, SHA2 is not configured, so
1359 * eat the option, and drop back to SHA-1.
1361 if (p[1] == '2' || p[1] == '3') {
1364 fo->flags |= FO_SHA1;
1369 fo->flags |= FO_SPARSE;
1372 fo->flags |= FO_MTIMEONLY;
1375 fo->flags |= FO_KEEPATIME;
1378 fo->flags |= FO_ACL;
1380 case 'V': /* verify options */
1381 /* Copy Verify Options */
1382 for (j=0; *p && *p != ':'; p++) {
1383 fo->VerifyOpts[j] = *p;
1384 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1388 fo->VerifyOpts[j] = 0;
1390 case 'C': /* accurate options */
1391 /* Copy Accurate Options */
1392 for (j=0; *p && *p != ':'; p++) {
1393 fo->AccurateOpts[j] = *p;
1394 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1398 fo->AccurateOpts[j] = 0;
1400 case 'J': /* Basejob options */
1401 /* Copy BaseJob Options */
1402 for (j=0; *p && *p != ':'; p++) {
1403 fo->BaseJobOpts[j] = *p;
1404 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1408 fo->BaseJobOpts[j] = 0;
1410 case 'P': /* strip path */
1413 for (j=0; *p && *p != ':'; p++) {
1415 if (j < (int)sizeof(strip) - 1) {
1420 fo->strip_path = atoi(strip);
1421 fo->flags |= FO_STRIPPATH;
1422 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1425 fo->flags |= FO_IF_NEWER;
1428 fo->flags |= FO_ENHANCEDWILD;
1430 case 'Z': /* compression */
1432 if (*p >= '0' && *p <= '9') {
1433 fo->flags |= FO_COMPRESS;
1434 fo->Compress_algo = COMPRESS_GZIP;
1435 fo->Compress_level = *p - '0';
1437 else if (*p == 'o') {
1438 fo->flags |= FO_COMPRESS;
1439 fo->Compress_algo = COMPRESS_LZO1X;
1440 fo->Compress_level = 1; /* not used with LZO */
1444 fo->flags |= FO_NOATIME;
1447 fo->flags |= FO_CHKCHANGES;
1450 fo->flags |= FO_HONOR_NODUMP;
1453 fo->flags |= FO_XATTR;
1456 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1460 return state_options;
1465 * Director is passing his Fileset
1467 static int fileset_cmd(JCR *jcr)
1469 BSOCK *dir = jcr->dir_bsock;
1472 #if defined(WIN32_VSS)
1475 sscanf(dir->msg, "fileset vss=%d", &vss);
1479 if (!init_fileset(jcr)) {
1482 while (dir->recv() >= 0) {
1483 strip_trailing_junk(dir->msg);
1484 Dmsg1(500, "Fileset: %s\n", dir->msg);
1485 add_fileset(jcr, dir->msg);
1487 if (!term_fileset(jcr)) {
1490 rtnstat = dir->fsend(OKinc);
1491 generate_plugin_event(jcr, bEventEndFileSet);
1495 static void free_bootstrap(JCR *jcr)
1497 if (jcr->RestoreBootstrap) {
1498 unlink(jcr->RestoreBootstrap);
1499 free_pool_memory(jcr->RestoreBootstrap);
1500 jcr->RestoreBootstrap = NULL;
1505 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1506 static uint32_t bsr_uniq = 0;
1509 * The Director sends us the bootstrap file, which
1510 * we will in turn pass to the SD.
1511 * Deprecated. The bsr is now sent directly from the
1512 * Director to the SD.
1514 static int bootstrap_cmd(JCR *jcr)
1516 BSOCK *dir = jcr->dir_bsock;
1517 POOLMEM *fname = get_pool_memory(PM_FNAME);
1520 free_bootstrap(jcr);
1523 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1524 jcr->Job, bsr_uniq);
1526 Dmsg1(400, "bootstrap=%s\n", fname);
1527 jcr->RestoreBootstrap = fname;
1528 bs = fopen(fname, "a+b"); /* create file */
1531 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1532 jcr->RestoreBootstrap, be.bstrerror());
1534 * Suck up what he is sending to us so that he will then
1535 * read our error message.
1537 while (dir->recv() >= 0)
1539 free_bootstrap(jcr);
1540 jcr->setJobStatus(JS_ErrorTerminated);
1544 while (dir->recv() >= 0) {
1545 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1546 fputs(dir->msg, bs);
1550 * Note, do not free the bootstrap yet -- it needs to be
1553 return dir->fsend(OKbootstrap);
1558 * Get backup level from Director
1561 static int level_cmd(JCR *jcr)
1563 BSOCK *dir = jcr->dir_bsock;
1564 POOLMEM *level, *buf = NULL;
1567 level = get_memory(dir->msglen+1);
1568 Dmsg1(10, "level_cmd: %s", dir->msg);
1570 /* keep compatibility with older directors */
1571 if (strstr(dir->msg, "accurate")) {
1572 jcr->accurate = true;
1574 if (strstr(dir->msg, "rerunning")) {
1575 jcr->rerunning = true;
1577 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1580 /* Base backup requested? */
1581 if (strcmp(level, "base") == 0) {
1582 jcr->setJobLevel(L_BASE);
1583 /* Full backup requested? */
1584 } else if (strcmp(level, "full") == 0) {
1585 jcr->setJobLevel(L_FULL);
1586 } else if (strstr(level, "differential")) {
1587 jcr->setJobLevel(L_DIFFERENTIAL);
1590 } else if (strstr(level, "incremental")) {
1591 jcr->setJobLevel(L_INCREMENTAL);
1595 * We get his UTC since time, then sync the clocks and correct it
1596 * to agree with our clock.
1598 } else if (strcmp(level, "since_utime") == 0) {
1599 buf = get_memory(dir->msglen+1);
1600 utime_t since_time, adj;
1601 btime_t his_time, bt_start, rt=0, bt_adj=0;
1602 if (jcr->getJobLevel() == L_NONE) {
1603 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1605 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1606 buf, &mtime_only, jcr->PrevJob) != 3) {
1607 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1608 buf, &mtime_only) != 2) {
1612 since_time = str_to_uint64(buf); /* this is the since time */
1613 Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1614 char ed1[50], ed2[50];
1616 * Sync clocks by polling him for the time. We take
1617 * 10 samples of his time throwing out the first two.
1619 for (int i=0; i<10; i++) {
1620 bt_start = get_current_btime();
1621 dir->signal(BNET_BTIME); /* poll for time */
1622 if (dir->recv() <= 0) { /* get response */
1625 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1628 if (i < 2) { /* toss first two results */
1631 his_time = str_to_uint64(buf);
1632 rt = get_current_btime() - bt_start; /* compute round trip time */
1633 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1634 edit_uint64(bt_start, ed2));
1635 bt_adj += bt_start - his_time - rt/2;
1636 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1639 bt_adj = bt_adj / 8; /* compute average time */
1640 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1641 adj = btime_to_utime(bt_adj);
1642 since_time += adj; /* adjust for clock difference */
1643 /* Don't notify if time within 3 seconds */
1644 if (adj > 3 || adj < -3) {
1646 if (adj > 600 || adj < -600) {
1651 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1653 dir->signal(BNET_EOD);
1655 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1656 jcr->incremental = 1; /* set incremental or decremental backup */
1657 jcr->mtime = since_time; /* set since time */
1658 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1660 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1668 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1669 return dir->fsend(OKlevel);
1672 pm_strcpy(jcr->errmsg, dir->msg);
1673 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1682 * Get session parameters from Director -- this is for a Restore command
1683 * This is deprecated. It is now passed via the bsr.
1685 static int session_cmd(JCR *jcr)
1687 BSOCK *dir = jcr->dir_bsock;
1689 Dmsg1(100, "SessionCmd: %s", dir->msg);
1690 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1691 &jcr->VolSessionId, &jcr->VolSessionTime,
1692 &jcr->StartFile, &jcr->EndFile,
1693 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1694 pm_strcpy(jcr->errmsg, dir->msg);
1695 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1699 return dir->fsend(OKsession);
1702 static void set_storage_auth_key(JCR *jcr, char *key)
1704 /* if no key don't update anything */
1710 * We can be contacting multiple storage daemons.
1711 * So, make sure that any old jcr->store_bsock is cleaned up.
1713 if (jcr->store_bsock) {
1714 jcr->store_bsock->destroy();
1715 jcr->store_bsock = NULL;
1719 * We can be contacting multiple storage daemons.
1720 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1722 if (jcr->sd_auth_key) {
1724 * If we already have a Authorization key, director can do multi
1727 Dmsg0(5, "set multi_restore=true\n");
1728 jcr->multi_restore = true;
1729 bfree(jcr->sd_auth_key);
1732 jcr->sd_auth_key = bstrdup(key);
1733 Dmsg0(5, "set sd auth key\n");
1737 * Get address of storage daemon from Director
1740 static int storage_cmd(JCR *jcr)
1742 int stored_port; /* storage daemon port */
1743 int enable_ssl; /* enable ssl to sd */
1744 POOL_MEM sd_auth_key(PM_MESSAGE);
1745 BSOCK *dir = jcr->dir_bsock;
1746 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1749 Dmsg1(100, "StorageCmd: %s", dir->msg);
1750 sd_auth_key.check_size(dir->msglen);
1751 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1752 &enable_ssl, sd_auth_key.c_str()) != 4) {
1753 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1754 &stored_port, &enable_ssl) != 3) {
1755 pm_strcpy(jcr->errmsg, dir->msg);
1756 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1761 set_storage_auth_key(jcr, sd_auth_key.c_str());
1763 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1765 /* Open command communications with Storage daemon */
1766 /* Try to connect for 1 hour at 10 second intervals */
1768 sd->set_source_address(me->FDsrc_addr);
1770 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1771 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1777 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1778 jcr->stored_addr, stored_port);
1779 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1780 jcr->stored_addr, stored_port);
1783 Dmsg0(110, "Connection OK to SD.\n");
1785 jcr->store_bsock = sd;
1787 sd->fsend("Hello Start Job %s\n", jcr->Job);
1788 if (!authenticate_storagedaemon(jcr)) {
1789 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1792 Dmsg0(110, "Authenticated with SD.\n");
1794 /* Send OK to Director */
1795 return dir->fsend(OKstore);
1798 dir->fsend(BADcmd, "storage");
1807 static int backup_cmd(JCR *jcr)
1809 BSOCK *dir = jcr->dir_bsock;
1810 BSOCK *sd = jcr->store_bsock;
1815 #if defined(WIN32_VSS)
1816 // capture state here, if client is backed up by multiple directors
1817 // and one enables vss and the other does not then enable_vss can change
1818 // between here and where its evaluated after the job completes.
1819 jcr->VSS = g_pVSSClient && enable_vss;
1821 /* Run only one at a time */
1826 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1827 jcr->JobFiles = FileIndex;
1828 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1832 * Validate some options given to the backup make sense for the compiled in
1833 * options of this filed.
1835 if (jcr->ff->flags & FO_ACL && !have_acl) {
1836 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1839 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1840 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1844 jcr->setJobStatus(JS_Blocked);
1845 jcr->setJobType(JT_BACKUP);
1846 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1849 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1850 dir->fsend(BADcmd, "backup");
1854 dir->fsend(OKbackup);
1855 Dmsg1(110, "filed>dird: %s", dir->msg);
1858 * Send Append Open Session to Storage daemon
1860 sd->fsend(append_open);
1861 Dmsg1(110, ">stored: %s", sd->msg);
1863 * Expect to receive back the Ticket number
1865 if (bget_msg(sd) >= 0) {
1866 Dmsg1(110, "<stored: %s", sd->msg);
1867 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1868 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1871 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1873 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1878 * Send Append data command to Storage daemon
1880 sd->fsend(append_data, jcr->Ticket);
1881 Dmsg1(110, ">stored: %s", sd->msg);
1884 * Expect to get OK data
1886 Dmsg1(110, "<stored: %s", sd->msg);
1887 if (!response(jcr, sd, OK_data, "Append Data")) {
1891 generate_daemon_event(jcr, "JobStart");
1892 generate_plugin_event(jcr, bEventStartBackupJob);
1894 #if defined(WIN32_VSS)
1895 /* START VSS ON WIN32 */
1897 if (g_pVSSClient->InitializeForBackup(jcr)) {
1898 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1899 /* tell vss which drives to snapshot */
1900 char szWinDriveLetters[27];
1901 *szWinDriveLetters=0;
1902 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1903 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1904 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1905 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1906 Jmsg(jcr, M_FATAL, 0, _("CreateSGenerate VSS snapshots failed.\n"));
1908 /* tell user if snapshot creation of a specific drive failed */
1910 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1911 if (islower(szWinDriveLetters[i])) {
1912 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1915 /* inform user about writer states */
1916 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1917 if (g_pVSSClient->GetWriterState(i) < 1) {
1918 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1923 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1926 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly.\n"));
1928 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1933 * Send Files to Storage daemon
1935 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1936 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1937 jcr->setJobStatus(JS_ErrorTerminated);
1938 bnet_suppress_error_messages(sd, 1);
1939 Dmsg0(110, "Error in blast_data.\n");
1941 jcr->setJobStatus(JS_Terminated);
1942 /* Note, the above set status will not override an error */
1943 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1944 bnet_suppress_error_messages(sd, 1);
1945 goto cleanup; /* bail out now */
1948 * Expect to get response to append_data from Storage daemon
1950 if (!response(jcr, sd, OK_append, "Append Data")) {
1951 jcr->setJobStatus(JS_ErrorTerminated);
1956 * Send Append End Data to Storage daemon
1958 sd->fsend(append_end, jcr->Ticket);
1960 if (!response(jcr, sd, OK_end, "Append End")) {
1961 jcr->setJobStatus(JS_ErrorTerminated);
1966 * Send Append Close to Storage daemon
1968 sd->fsend(append_close, jcr->Ticket);
1969 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1970 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1972 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1976 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1979 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1980 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1986 #if defined(WIN32_VSS)
1988 Win32ConvCleanupCache();
1989 g_pVSSClient->DestroyWriterInfo();
1994 generate_plugin_event(jcr, bEventEndBackupJob);
1995 return 0; /* return and stop command loop */
1999 * Do a Verify for Director
2002 static int verify_cmd(JCR *jcr)
2004 BSOCK *dir = jcr->dir_bsock;
2005 BSOCK *sd = jcr->store_bsock;
2008 jcr->setJobType(JT_VERIFY);
2009 if (sscanf(dir->msg, verifycmd, level) != 1) {
2010 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2014 if (strcasecmp(level, "init") == 0) {
2015 jcr->setJobLevel(L_VERIFY_INIT);
2016 } else if (strcasecmp(level, "catalog") == 0){
2017 jcr->setJobLevel(L_VERIFY_CATALOG);
2018 } else if (strcasecmp(level, "volume") == 0){
2019 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2020 } else if (strcasecmp(level, "data") == 0){
2021 jcr->setJobLevel(L_VERIFY_DATA);
2022 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2023 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2025 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2029 dir->fsend(OKverify);
2031 generate_daemon_event(jcr, "JobStart");
2032 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2033 generate_plugin_event(jcr, bEventStartVerifyJob);
2035 Dmsg1(110, "filed>dird: %s", dir->msg);
2037 switch (jcr->getJobLevel()) {
2039 case L_VERIFY_CATALOG:
2042 case L_VERIFY_VOLUME_TO_CATALOG:
2043 if (!open_sd_read_session(jcr)) {
2046 start_dir_heartbeat(jcr);
2047 do_verify_volume(jcr);
2048 stop_dir_heartbeat(jcr);
2050 * Send Close session command to Storage daemon
2052 sd->fsend(read_close, jcr->Ticket);
2053 Dmsg1(130, "filed>stored: %s", sd->msg);
2055 /* ****FIXME**** check response */
2056 bget_msg(sd); /* get OK */
2058 /* Inform Storage daemon that we are done */
2059 sd->signal(BNET_TERMINATE);
2062 case L_VERIFY_DISK_TO_CATALOG:
2066 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2070 dir->signal(BNET_EOD);
2071 generate_plugin_event(jcr, bEventEndVerifyJob);
2072 return 0; /* return and terminate command loop */
2077 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2079 switch (init_type) {
2080 case VSS_INIT_RESTORE_AFTER_INIT:
2081 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2083 case VSS_INIT_RESTORE_AFTER_GATHER:
2084 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2095 * Do a Restore for Director
2098 static int restore_cmd(JCR *jcr)
2100 BSOCK *dir = jcr->dir_bsock;
2101 BSOCK *sd = jcr->store_bsock;
2103 bool use_regexwhere=false;
2108 * Scan WHERE (base directory for restore) from command
2110 Dmsg0(100, "restore command\n");
2111 #if defined(WIN32_VSS)
2114 * No need to enable VSS for restore if we do not have plugin
2117 enable_vss = jcr->job_metadata != NULL;
2118 jcr->job_metadata = NULL;
2120 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2121 // capture state here, if client is backed up by multiple directors
2122 // and one enables vss and the other does not then enable_vss can change
2123 // between here and where its evaluated after the job completes.
2124 jcr->VSS = g_pVSSClient && enable_vss;
2126 /* Run only one at a time */
2130 /* Pickup where string */
2131 args = get_memory(dir->msglen+1);
2134 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2135 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2136 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2137 pm_strcpy(jcr->errmsg, dir->msg);
2138 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2143 use_regexwhere = true;
2145 /* Turn / into nothing */
2146 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2150 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2151 unbash_spaces(args);
2153 /* Keep track of newly created directories to apply them correct attributes */
2154 if (replace == REPLACE_NEVER) {
2155 jcr->keep_path_list = true;
2158 if (use_regexwhere) {
2159 jcr->where_bregexp = get_bregexps(args);
2160 if (!jcr->where_bregexp) {
2161 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2162 free_pool_memory(args);
2166 jcr->where = bstrdup(args);
2169 free_pool_memory(args);
2170 jcr->replace = replace;
2171 jcr->prefix_links = prefix_links;
2173 dir->fsend(OKrestore);
2174 Dmsg1(110, "filed>dird: %s", dir->msg);
2176 jcr->setJobType(JT_RESTORE);
2178 jcr->setJobStatus(JS_Blocked);
2180 if (!open_sd_read_session(jcr)) {
2181 jcr->setJobStatus(JS_ErrorTerminated);
2185 jcr->setJobStatus(JS_Running);
2188 * Do restore of files and data
2190 start_dir_heartbeat(jcr);
2191 generate_daemon_event(jcr, "JobStart");
2192 generate_plugin_event(jcr, bEventStartRestoreJob);
2194 #if defined(WIN32_VSS)
2195 /* START VSS ON WIN32 */
2197 if (!g_pVSSClient->InitializeForRestore(jcr)) {
2199 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2201 //free_and_null_pool_memory(jcr->job_metadata);
2202 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2207 stop_dir_heartbeat(jcr);
2209 jcr->setJobStatus(JS_Terminated);
2210 if (jcr->JobStatus != JS_Terminated) {
2211 bnet_suppress_error_messages(sd, 1);
2215 * Send Close session command to Storage daemon
2217 sd->fsend(read_close, jcr->Ticket);
2218 Dmsg1(100, "filed>stored: %s", sd->msg);
2220 bget_msg(sd); /* get OK */
2222 /* Inform Storage daemon that we are done */
2223 sd->signal(BNET_TERMINATE);
2225 #if defined(WIN32_VSS)
2226 /* STOP VSS ON WIN32 */
2227 /* tell vss to close the restore session */
2228 Dmsg0(100, "About to call CloseRestore\n");
2231 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2233 Dmsg0(100, "Really about to call CloseRestore\n");
2234 if (g_pVSSClient->CloseRestore()) {
2235 Dmsg0(100, "CloseRestore success\n");
2237 /* inform user about writer states */
2238 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2239 int msg_type = M_INFO;
2240 if (g_pVSSClient->GetWriterState(i) < 1) {
2241 //msg_type = M_WARNING;
2244 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2249 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2255 bfree_and_null(jcr->where);
2257 if (jcr->JobErrors) {
2258 jcr->setJobStatus(JS_ErrorTerminated);
2261 Dmsg0(100, "Done in job.c\n");
2264 if (jcr->multi_restore) {
2265 Dmsg0(100, OKstoreend);
2266 dir->fsend(OKstoreend);
2267 ret = 1; /* we continue the loop, waiting for next part */
2269 end_restore_cmd(jcr);
2270 ret = 0; /* we stop here */
2273 if (job_canceled(jcr)) {
2274 ret = 0; /* we stop here */
2280 static int end_restore_cmd(JCR *jcr)
2282 Dmsg0(5, "end_restore_cmd\n");
2283 generate_plugin_event(jcr, bEventEndRestoreJob);
2284 return 0; /* return and terminate command loop */
2287 static int open_sd_read_session(JCR *jcr)
2289 BSOCK *sd = jcr->store_bsock;
2292 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2295 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2296 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2297 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2299 * Open Read Session with Storage daemon
2301 sd->fsend(read_open, "DummyVolume",
2302 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2303 jcr->StartBlock, jcr->EndBlock);
2304 Dmsg1(110, ">stored: %s", sd->msg);
2309 if (bget_msg(sd) >= 0) {
2310 Dmsg1(110, "filed<stored: %s", sd->msg);
2311 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2312 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2315 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2317 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2321 if (!send_bootstrap_file(jcr)) {
2326 * Start read of data with Storage daemon
2328 sd->fsend(read_data, jcr->Ticket);
2329 Dmsg1(110, ">stored: %s", sd->msg);
2334 if (!response(jcr, sd, OK_data, "Read Data")) {
2341 * Destroy the Job Control Record and associated
2342 * resources (sockets).
2344 static void filed_free_jcr(JCR *jcr)
2346 if (jcr->store_bsock) {
2347 jcr->store_bsock->close();
2349 free_bootstrap(jcr);
2350 if (jcr->last_fname) {
2351 free_pool_memory(jcr->last_fname);
2353 free_runscripts(jcr->RunScripts);
2354 delete jcr->RunScripts;
2355 free_path_list(jcr);
2357 if (jcr->JobId != 0)
2358 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2364 * Get response from Storage daemon to a command we
2365 * sent. Check that the response is OK.
2367 * Returns: 0 on failure
2370 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2375 if (bget_msg(sd) > 0) {
2376 Dmsg0(110, sd->msg);
2377 if (strcmp(sd->msg, resp) == 0) {
2381 if (job_canceled(jcr)) {
2382 return 0; /* if canceled avoid useless error messages */
2384 if (is_bnet_error(sd)) {
2385 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2386 cmd, bnet_strerror(sd));
2388 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2389 cmd, resp, sd->msg);
2394 static int send_bootstrap_file(JCR *jcr)
2398 BSOCK *sd = jcr->store_bsock;
2399 const char *bootstrap = "bootstrap\n";
2402 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2403 if (!jcr->RestoreBootstrap) {
2406 bs = fopen(jcr->RestoreBootstrap, "rb");
2409 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2410 jcr->RestoreBootstrap, be.bstrerror());
2411 jcr->setJobStatus(JS_ErrorTerminated);
2414 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2416 while (fgets(buf, sizeof(buf), bs)) {
2417 sd->msglen = Mmsg(sd->msg, "%s", buf);
2420 sd->signal(BNET_EOD);
2422 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2423 jcr->setJobStatus(JS_ErrorTerminated);
2429 free_bootstrap(jcr);