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 /* Plugin driver can return drive letters */
1903 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1904 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1905 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1906 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1907 Jmsg(jcr, M_FATAL, 0, _("CreateSGenerate VSS snapshots failed.\n"));
1909 /* tell user if snapshot creation of a specific drive failed */
1911 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1912 if (islower(szWinDriveLetters[i])) {
1913 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1916 /* inform user about writer states */
1917 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1918 if (g_pVSSClient->GetWriterState(i) < 1) {
1919 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1924 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1927 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly.\n"));
1929 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1934 * Send Files to Storage daemon
1936 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1937 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1938 jcr->setJobStatus(JS_ErrorTerminated);
1939 bnet_suppress_error_messages(sd, 1);
1940 Dmsg0(110, "Error in blast_data.\n");
1942 jcr->setJobStatus(JS_Terminated);
1943 /* Note, the above set status will not override an error */
1944 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1945 bnet_suppress_error_messages(sd, 1);
1946 goto cleanup; /* bail out now */
1949 * Expect to get response to append_data from Storage daemon
1951 if (!response(jcr, sd, OK_append, "Append Data")) {
1952 jcr->setJobStatus(JS_ErrorTerminated);
1957 * Send Append End Data to Storage daemon
1959 sd->fsend(append_end, jcr->Ticket);
1961 if (!response(jcr, sd, OK_end, "Append End")) {
1962 jcr->setJobStatus(JS_ErrorTerminated);
1967 * Send Append Close to Storage daemon
1969 sd->fsend(append_close, jcr->Ticket);
1970 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1971 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1973 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1977 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1980 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1981 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1987 #if defined(WIN32_VSS)
1989 Win32ConvCleanupCache();
1990 g_pVSSClient->DestroyWriterInfo();
1995 generate_plugin_event(jcr, bEventEndBackupJob);
1996 return 0; /* return and stop command loop */
2000 * Do a Verify for Director
2003 static int verify_cmd(JCR *jcr)
2005 BSOCK *dir = jcr->dir_bsock;
2006 BSOCK *sd = jcr->store_bsock;
2009 jcr->setJobType(JT_VERIFY);
2010 if (sscanf(dir->msg, verifycmd, level) != 1) {
2011 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2015 if (strcasecmp(level, "init") == 0) {
2016 jcr->setJobLevel(L_VERIFY_INIT);
2017 } else if (strcasecmp(level, "catalog") == 0){
2018 jcr->setJobLevel(L_VERIFY_CATALOG);
2019 } else if (strcasecmp(level, "volume") == 0){
2020 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2021 } else if (strcasecmp(level, "data") == 0){
2022 jcr->setJobLevel(L_VERIFY_DATA);
2023 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2024 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2026 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2030 dir->fsend(OKverify);
2032 generate_daemon_event(jcr, "JobStart");
2033 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2034 generate_plugin_event(jcr, bEventStartVerifyJob);
2036 Dmsg1(110, "filed>dird: %s", dir->msg);
2038 switch (jcr->getJobLevel()) {
2040 case L_VERIFY_CATALOG:
2043 case L_VERIFY_VOLUME_TO_CATALOG:
2044 if (!open_sd_read_session(jcr)) {
2047 start_dir_heartbeat(jcr);
2048 do_verify_volume(jcr);
2049 stop_dir_heartbeat(jcr);
2051 * Send Close session command to Storage daemon
2053 sd->fsend(read_close, jcr->Ticket);
2054 Dmsg1(130, "filed>stored: %s", sd->msg);
2056 /* ****FIXME**** check response */
2057 bget_msg(sd); /* get OK */
2059 /* Inform Storage daemon that we are done */
2060 sd->signal(BNET_TERMINATE);
2063 case L_VERIFY_DISK_TO_CATALOG:
2067 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2071 dir->signal(BNET_EOD);
2072 generate_plugin_event(jcr, bEventEndVerifyJob);
2073 return 0; /* return and terminate command loop */
2078 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2080 switch (init_type) {
2081 case VSS_INIT_RESTORE_AFTER_INIT:
2082 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2084 case VSS_INIT_RESTORE_AFTER_GATHER:
2085 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2096 * Do a Restore for Director
2099 static int restore_cmd(JCR *jcr)
2101 BSOCK *dir = jcr->dir_bsock;
2102 BSOCK *sd = jcr->store_bsock;
2104 bool use_regexwhere=false;
2109 * Scan WHERE (base directory for restore) from command
2111 Dmsg0(100, "restore command\n");
2112 #if defined(WIN32_VSS)
2115 * No need to enable VSS for restore if we do not have plugin
2118 enable_vss = jcr->job_metadata != NULL;
2119 jcr->job_metadata = NULL;
2121 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2122 // capture state here, if client is backed up by multiple directors
2123 // and one enables vss and the other does not then enable_vss can change
2124 // between here and where its evaluated after the job completes.
2125 jcr->VSS = g_pVSSClient && enable_vss;
2127 /* Run only one at a time */
2131 /* Pickup where string */
2132 args = get_memory(dir->msglen+1);
2135 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2136 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2137 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2138 pm_strcpy(jcr->errmsg, dir->msg);
2139 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2144 use_regexwhere = true;
2146 /* Turn / into nothing */
2147 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2151 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2152 unbash_spaces(args);
2154 /* Keep track of newly created directories to apply them correct attributes */
2155 if (replace == REPLACE_NEVER) {
2156 jcr->keep_path_list = true;
2159 if (use_regexwhere) {
2160 jcr->where_bregexp = get_bregexps(args);
2161 if (!jcr->where_bregexp) {
2162 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2163 free_pool_memory(args);
2167 jcr->where = bstrdup(args);
2170 free_pool_memory(args);
2171 jcr->replace = replace;
2172 jcr->prefix_links = prefix_links;
2174 dir->fsend(OKrestore);
2175 Dmsg1(110, "filed>dird: %s", dir->msg);
2177 jcr->setJobType(JT_RESTORE);
2179 jcr->setJobStatus(JS_Blocked);
2181 if (!open_sd_read_session(jcr)) {
2182 jcr->setJobStatus(JS_ErrorTerminated);
2186 jcr->setJobStatus(JS_Running);
2189 * Do restore of files and data
2191 start_dir_heartbeat(jcr);
2192 generate_daemon_event(jcr, "JobStart");
2193 generate_plugin_event(jcr, bEventStartRestoreJob);
2195 #if defined(WIN32_VSS)
2196 /* START VSS ON WIN32 */
2198 if (!g_pVSSClient->InitializeForRestore(jcr)) {
2200 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2202 //free_and_null_pool_memory(jcr->job_metadata);
2203 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2208 stop_dir_heartbeat(jcr);
2210 jcr->setJobStatus(JS_Terminated);
2211 if (jcr->JobStatus != JS_Terminated) {
2212 bnet_suppress_error_messages(sd, 1);
2216 * Send Close session command to Storage daemon
2218 sd->fsend(read_close, jcr->Ticket);
2219 Dmsg1(100, "filed>stored: %s", sd->msg);
2221 bget_msg(sd); /* get OK */
2223 /* Inform Storage daemon that we are done */
2224 sd->signal(BNET_TERMINATE);
2226 #if defined(WIN32_VSS)
2227 /* STOP VSS ON WIN32 */
2228 /* tell vss to close the restore session */
2229 Dmsg0(100, "About to call CloseRestore\n");
2232 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2234 Dmsg0(100, "Really about to call CloseRestore\n");
2235 if (g_pVSSClient->CloseRestore()) {
2236 Dmsg0(100, "CloseRestore success\n");
2238 /* inform user about writer states */
2239 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2240 int msg_type = M_INFO;
2241 if (g_pVSSClient->GetWriterState(i) < 1) {
2242 //msg_type = M_WARNING;
2245 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2250 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2256 bfree_and_null(jcr->where);
2258 if (jcr->JobErrors) {
2259 jcr->setJobStatus(JS_ErrorTerminated);
2262 Dmsg0(100, "Done in job.c\n");
2265 if (jcr->multi_restore) {
2266 Dmsg0(100, OKstoreend);
2267 dir->fsend(OKstoreend);
2268 ret = 1; /* we continue the loop, waiting for next part */
2270 end_restore_cmd(jcr);
2271 ret = 0; /* we stop here */
2274 if (job_canceled(jcr)) {
2275 ret = 0; /* we stop here */
2281 static int end_restore_cmd(JCR *jcr)
2283 Dmsg0(5, "end_restore_cmd\n");
2284 generate_plugin_event(jcr, bEventEndRestoreJob);
2285 return 0; /* return and terminate command loop */
2288 static int open_sd_read_session(JCR *jcr)
2290 BSOCK *sd = jcr->store_bsock;
2293 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2296 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2297 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2298 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2300 * Open Read Session with Storage daemon
2302 sd->fsend(read_open, "DummyVolume",
2303 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2304 jcr->StartBlock, jcr->EndBlock);
2305 Dmsg1(110, ">stored: %s", sd->msg);
2310 if (bget_msg(sd) >= 0) {
2311 Dmsg1(110, "filed<stored: %s", sd->msg);
2312 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2313 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2316 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2318 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2322 if (!send_bootstrap_file(jcr)) {
2327 * Start read of data with Storage daemon
2329 sd->fsend(read_data, jcr->Ticket);
2330 Dmsg1(110, ">stored: %s", sd->msg);
2335 if (!response(jcr, sd, OK_data, "Read Data")) {
2342 * Destroy the Job Control Record and associated
2343 * resources (sockets).
2345 static void filed_free_jcr(JCR *jcr)
2347 if (jcr->store_bsock) {
2348 jcr->store_bsock->close();
2350 free_bootstrap(jcr);
2351 if (jcr->last_fname) {
2352 free_pool_memory(jcr->last_fname);
2354 free_runscripts(jcr->RunScripts);
2355 delete jcr->RunScripts;
2356 free_path_list(jcr);
2358 if (jcr->JobId != 0)
2359 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2365 * Get response from Storage daemon to a command we
2366 * sent. Check that the response is OK.
2368 * Returns: 0 on failure
2371 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2376 if (bget_msg(sd) > 0) {
2377 Dmsg0(110, sd->msg);
2378 if (strcmp(sd->msg, resp) == 0) {
2382 if (job_canceled(jcr)) {
2383 return 0; /* if canceled avoid useless error messages */
2385 if (is_bnet_error(sd)) {
2386 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2387 cmd, bnet_strerror(sd));
2389 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2390 cmd, resp, sd->msg);
2395 static int send_bootstrap_file(JCR *jcr)
2399 BSOCK *sd = jcr->store_bsock;
2400 const char *bootstrap = "bootstrap\n";
2403 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2404 if (!jcr->RestoreBootstrap) {
2407 bs = fopen(jcr->RestoreBootstrap, "rb");
2410 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2411 jcr->RestoreBootstrap, be.bstrerror());
2412 jcr->setJobStatus(JS_ErrorTerminated);
2415 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2417 while (fgets(buf, sizeof(buf), bs)) {
2418 sd->msglen = Mmsg(sd->msg, "%s", buf);
2421 sd->signal(BNET_EOD);
2423 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2424 jcr->setJobStatus(JS_ErrorTerminated);
2430 free_bootstrap(jcr);