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",
1606 buf, &mtime_only) != 2) {
1609 since_time = str_to_uint64(buf); /* this is the since time */
1610 Dmsg1(100, "since_time=%lld\n", since_time);
1611 char ed1[50], ed2[50];
1613 * Sync clocks by polling him for the time. We take
1614 * 10 samples of his time throwing out the first two.
1616 for (int i=0; i<10; i++) {
1617 bt_start = get_current_btime();
1618 dir->signal(BNET_BTIME); /* poll for time */
1619 if (dir->recv() <= 0) { /* get response */
1622 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1625 if (i < 2) { /* toss first two results */
1628 his_time = str_to_uint64(buf);
1629 rt = get_current_btime() - bt_start; /* compute round trip time */
1630 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1631 edit_uint64(bt_start, ed2));
1632 bt_adj += bt_start - his_time - rt/2;
1633 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1636 bt_adj = bt_adj / 8; /* compute average time */
1637 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1638 adj = btime_to_utime(bt_adj);
1639 since_time += adj; /* adjust for clock difference */
1640 /* Don't notify if time within 3 seconds */
1641 if (adj > 3 || adj < -3) {
1643 if (adj > 600 || adj < -600) {
1648 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1650 dir->signal(BNET_EOD);
1652 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1653 jcr->incremental = 1; /* set incremental or decremental backup */
1654 jcr->mtime = since_time; /* set since time */
1655 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1657 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1665 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1666 return dir->fsend(OKlevel);
1669 pm_strcpy(jcr->errmsg, dir->msg);
1670 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1679 * Get session parameters from Director -- this is for a Restore command
1680 * This is deprecated. It is now passed via the bsr.
1682 static int session_cmd(JCR *jcr)
1684 BSOCK *dir = jcr->dir_bsock;
1686 Dmsg1(100, "SessionCmd: %s", dir->msg);
1687 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1688 &jcr->VolSessionId, &jcr->VolSessionTime,
1689 &jcr->StartFile, &jcr->EndFile,
1690 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1691 pm_strcpy(jcr->errmsg, dir->msg);
1692 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1696 return dir->fsend(OKsession);
1699 static void set_storage_auth_key(JCR *jcr, char *key)
1701 /* if no key don't update anything */
1707 * We can be contacting multiple storage daemons.
1708 * So, make sure that any old jcr->store_bsock is cleaned up.
1710 if (jcr->store_bsock) {
1711 jcr->store_bsock->destroy();
1712 jcr->store_bsock = NULL;
1716 * We can be contacting multiple storage daemons.
1717 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1719 if (jcr->sd_auth_key) {
1721 * If we already have a Authorization key, director can do multi
1724 Dmsg0(5, "set multi_restore=true\n");
1725 jcr->multi_restore = true;
1726 bfree(jcr->sd_auth_key);
1729 jcr->sd_auth_key = bstrdup(key);
1730 Dmsg0(5, "set sd auth key\n");
1734 * Get address of storage daemon from Director
1737 static int storage_cmd(JCR *jcr)
1739 int stored_port; /* storage daemon port */
1740 int enable_ssl; /* enable ssl to sd */
1741 POOL_MEM sd_auth_key(PM_MESSAGE);
1742 BSOCK *dir = jcr->dir_bsock;
1743 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1746 Dmsg1(100, "StorageCmd: %s", dir->msg);
1747 sd_auth_key.check_size(dir->msglen);
1748 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1749 &enable_ssl, sd_auth_key.c_str()) != 4) {
1750 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1751 &stored_port, &enable_ssl) != 3) {
1752 pm_strcpy(jcr->errmsg, dir->msg);
1753 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1758 set_storage_auth_key(jcr, sd_auth_key.c_str());
1760 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1762 /* Open command communications with Storage daemon */
1763 /* Try to connect for 1 hour at 10 second intervals */
1765 sd->set_source_address(me->FDsrc_addr);
1767 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1768 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1774 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1775 jcr->stored_addr, stored_port);
1776 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1777 jcr->stored_addr, stored_port);
1780 Dmsg0(110, "Connection OK to SD.\n");
1782 jcr->store_bsock = sd;
1784 sd->fsend("Hello Start Job %s\n", jcr->Job);
1785 if (!authenticate_storagedaemon(jcr)) {
1786 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1789 Dmsg0(110, "Authenticated with SD.\n");
1791 /* Send OK to Director */
1792 return dir->fsend(OKstore);
1795 dir->fsend(BADcmd, "storage");
1804 static int backup_cmd(JCR *jcr)
1806 BSOCK *dir = jcr->dir_bsock;
1807 BSOCK *sd = jcr->store_bsock;
1812 #if defined(WIN32_VSS)
1813 // capture state here, if client is backed up by multiple directors
1814 // and one enables vss and the other does not then enable_vss can change
1815 // between here and where its evaluated after the job completes.
1816 jcr->VSS = g_pVSSClient && enable_vss;
1818 /* Run only one at a time */
1823 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1824 jcr->JobFiles = FileIndex;
1825 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1829 * Validate some options given to the backup make sense for the compiled in
1830 * options of this filed.
1832 if (jcr->ff->flags & FO_ACL && !have_acl) {
1833 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1836 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1837 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1841 jcr->setJobStatus(JS_Blocked);
1842 jcr->setJobType(JT_BACKUP);
1843 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1846 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1847 dir->fsend(BADcmd, "backup");
1851 dir->fsend(OKbackup);
1852 Dmsg1(110, "filed>dird: %s", dir->msg);
1855 * Send Append Open Session to Storage daemon
1857 sd->fsend(append_open);
1858 Dmsg1(110, ">stored: %s", sd->msg);
1860 * Expect to receive back the Ticket number
1862 if (bget_msg(sd) >= 0) {
1863 Dmsg1(110, "<stored: %s", sd->msg);
1864 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1865 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1868 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1870 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1875 * Send Append data command to Storage daemon
1877 sd->fsend(append_data, jcr->Ticket);
1878 Dmsg1(110, ">stored: %s", sd->msg);
1881 * Expect to get OK data
1883 Dmsg1(110, "<stored: %s", sd->msg);
1884 if (!response(jcr, sd, OK_data, "Append Data")) {
1888 generate_daemon_event(jcr, "JobStart");
1889 generate_plugin_event(jcr, bEventStartBackupJob);
1891 #if defined(WIN32_VSS)
1892 /* START VSS ON WIN32 */
1894 if (g_pVSSClient->InitializeForBackup(jcr)) {
1895 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1896 /* tell vss which drives to snapshot */
1897 char szWinDriveLetters[27];
1898 *szWinDriveLetters=0;
1899 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1900 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1901 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1902 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1903 Jmsg(jcr, M_FATAL, 0, _("CreateSGenerate VSS snapshots failed.\n"));
1905 /* tell user if snapshot creation of a specific drive failed */
1907 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1908 if (islower(szWinDriveLetters[i])) {
1909 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1912 /* inform user about writer states */
1913 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1914 if (g_pVSSClient->GetWriterState(i) < 1) {
1915 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1920 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1923 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly.\n"));
1925 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1930 * Send Files to Storage daemon
1932 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1933 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1934 jcr->setJobStatus(JS_ErrorTerminated);
1935 bnet_suppress_error_messages(sd, 1);
1936 Dmsg0(110, "Error in blast_data.\n");
1938 jcr->setJobStatus(JS_Terminated);
1939 /* Note, the above set status will not override an error */
1940 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1941 bnet_suppress_error_messages(sd, 1);
1942 goto cleanup; /* bail out now */
1945 * Expect to get response to append_data from Storage daemon
1947 if (!response(jcr, sd, OK_append, "Append Data")) {
1948 jcr->setJobStatus(JS_ErrorTerminated);
1953 * Send Append End Data to Storage daemon
1955 sd->fsend(append_end, jcr->Ticket);
1957 if (!response(jcr, sd, OK_end, "Append End")) {
1958 jcr->setJobStatus(JS_ErrorTerminated);
1963 * Send Append Close to Storage daemon
1965 sd->fsend(append_close, jcr->Ticket);
1966 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1967 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1969 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1973 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1976 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1977 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1983 #if defined(WIN32_VSS)
1985 Win32ConvCleanupCache();
1986 g_pVSSClient->DestroyWriterInfo();
1991 generate_plugin_event(jcr, bEventEndBackupJob);
1992 return 0; /* return and stop command loop */
1996 * Do a Verify for Director
1999 static int verify_cmd(JCR *jcr)
2001 BSOCK *dir = jcr->dir_bsock;
2002 BSOCK *sd = jcr->store_bsock;
2005 jcr->setJobType(JT_VERIFY);
2006 if (sscanf(dir->msg, verifycmd, level) != 1) {
2007 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2011 if (strcasecmp(level, "init") == 0) {
2012 jcr->setJobLevel(L_VERIFY_INIT);
2013 } else if (strcasecmp(level, "catalog") == 0){
2014 jcr->setJobLevel(L_VERIFY_CATALOG);
2015 } else if (strcasecmp(level, "volume") == 0){
2016 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2017 } else if (strcasecmp(level, "data") == 0){
2018 jcr->setJobLevel(L_VERIFY_DATA);
2019 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2020 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2022 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2026 dir->fsend(OKverify);
2028 generate_daemon_event(jcr, "JobStart");
2029 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2030 generate_plugin_event(jcr, bEventStartVerifyJob);
2032 Dmsg1(110, "filed>dird: %s", dir->msg);
2034 switch (jcr->getJobLevel()) {
2036 case L_VERIFY_CATALOG:
2039 case L_VERIFY_VOLUME_TO_CATALOG:
2040 if (!open_sd_read_session(jcr)) {
2043 start_dir_heartbeat(jcr);
2044 do_verify_volume(jcr);
2045 stop_dir_heartbeat(jcr);
2047 * Send Close session command to Storage daemon
2049 sd->fsend(read_close, jcr->Ticket);
2050 Dmsg1(130, "filed>stored: %s", sd->msg);
2052 /* ****FIXME**** check response */
2053 bget_msg(sd); /* get OK */
2055 /* Inform Storage daemon that we are done */
2056 sd->signal(BNET_TERMINATE);
2059 case L_VERIFY_DISK_TO_CATALOG:
2063 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2067 dir->signal(BNET_EOD);
2068 generate_plugin_event(jcr, bEventEndVerifyJob);
2069 return 0; /* return and terminate command loop */
2074 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2076 switch (init_type) {
2077 case VSS_INIT_RESTORE_AFTER_INIT:
2078 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2080 case VSS_INIT_RESTORE_AFTER_GATHER:
2081 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2092 * Do a Restore for Director
2095 static int restore_cmd(JCR *jcr)
2097 BSOCK *dir = jcr->dir_bsock;
2098 BSOCK *sd = jcr->store_bsock;
2100 bool use_regexwhere=false;
2105 * Scan WHERE (base directory for restore) from command
2107 Dmsg0(100, "restore command\n");
2108 #if defined(WIN32_VSS)
2111 * No need to enable VSS for restore if we do not have plugin
2114 enable_vss = jcr->job_metadata != NULL;
2115 jcr->job_metadata = NULL;
2117 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2118 // capture state here, if client is backed up by multiple directors
2119 // and one enables vss and the other does not then enable_vss can change
2120 // between here and where its evaluated after the job completes.
2121 jcr->VSS = g_pVSSClient && enable_vss;
2123 /* Run only one at a time */
2127 /* Pickup where string */
2128 args = get_memory(dir->msglen+1);
2131 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2132 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2133 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2134 pm_strcpy(jcr->errmsg, dir->msg);
2135 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2140 use_regexwhere = true;
2142 /* Turn / into nothing */
2143 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2147 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2148 unbash_spaces(args);
2150 /* Keep track of newly created directories to apply them correct attributes */
2151 if (replace == REPLACE_NEVER) {
2152 jcr->keep_path_list = true;
2155 if (use_regexwhere) {
2156 jcr->where_bregexp = get_bregexps(args);
2157 if (!jcr->where_bregexp) {
2158 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2159 free_pool_memory(args);
2163 jcr->where = bstrdup(args);
2166 free_pool_memory(args);
2167 jcr->replace = replace;
2168 jcr->prefix_links = prefix_links;
2170 dir->fsend(OKrestore);
2171 Dmsg1(110, "filed>dird: %s", dir->msg);
2173 jcr->setJobType(JT_RESTORE);
2175 jcr->setJobStatus(JS_Blocked);
2177 if (!open_sd_read_session(jcr)) {
2178 jcr->setJobStatus(JS_ErrorTerminated);
2182 jcr->setJobStatus(JS_Running);
2185 * Do restore of files and data
2187 start_dir_heartbeat(jcr);
2188 generate_daemon_event(jcr, "JobStart");
2189 generate_plugin_event(jcr, bEventStartRestoreJob);
2191 #if defined(WIN32_VSS)
2192 /* START VSS ON WIN32 */
2194 if (!g_pVSSClient->InitializeForRestore(jcr)) {
2196 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2198 //free_and_null_pool_memory(jcr->job_metadata);
2199 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2204 stop_dir_heartbeat(jcr);
2206 jcr->setJobStatus(JS_Terminated);
2207 if (jcr->JobStatus != JS_Terminated) {
2208 bnet_suppress_error_messages(sd, 1);
2212 * Send Close session command to Storage daemon
2214 sd->fsend(read_close, jcr->Ticket);
2215 Dmsg1(100, "filed>stored: %s", sd->msg);
2217 bget_msg(sd); /* get OK */
2219 /* Inform Storage daemon that we are done */
2220 sd->signal(BNET_TERMINATE);
2222 #if defined(WIN32_VSS)
2223 /* STOP VSS ON WIN32 */
2224 /* tell vss to close the restore session */
2225 Dmsg0(100, "About to call CloseRestore\n");
2228 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2230 Dmsg0(100, "Really about to call CloseRestore\n");
2231 if (g_pVSSClient->CloseRestore()) {
2232 Dmsg0(100, "CloseRestore success\n");
2234 /* inform user about writer states */
2235 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2236 int msg_type = M_INFO;
2237 if (g_pVSSClient->GetWriterState(i) < 1) {
2238 //msg_type = M_WARNING;
2241 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2246 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2252 bfree_and_null(jcr->where);
2254 if (jcr->JobErrors) {
2255 jcr->setJobStatus(JS_ErrorTerminated);
2258 Dmsg0(100, "Done in job.c\n");
2261 if (jcr->multi_restore) {
2262 Dmsg0(100, OKstoreend);
2263 dir->fsend(OKstoreend);
2264 ret = 1; /* we continue the loop, waiting for next part */
2266 end_restore_cmd(jcr);
2267 ret = 0; /* we stop here */
2270 if (job_canceled(jcr)) {
2271 ret = 0; /* we stop here */
2277 static int end_restore_cmd(JCR *jcr)
2279 Dmsg0(5, "end_restore_cmd\n");
2280 generate_plugin_event(jcr, bEventEndRestoreJob);
2281 return 0; /* return and terminate command loop */
2284 static int open_sd_read_session(JCR *jcr)
2286 BSOCK *sd = jcr->store_bsock;
2289 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2292 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2293 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2294 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2296 * Open Read Session with Storage daemon
2298 sd->fsend(read_open, "DummyVolume",
2299 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2300 jcr->StartBlock, jcr->EndBlock);
2301 Dmsg1(110, ">stored: %s", sd->msg);
2306 if (bget_msg(sd) >= 0) {
2307 Dmsg1(110, "filed<stored: %s", sd->msg);
2308 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2309 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2312 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2314 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2318 if (!send_bootstrap_file(jcr)) {
2323 * Start read of data with Storage daemon
2325 sd->fsend(read_data, jcr->Ticket);
2326 Dmsg1(110, ">stored: %s", sd->msg);
2331 if (!response(jcr, sd, OK_data, "Read Data")) {
2338 * Destroy the Job Control Record and associated
2339 * resources (sockets).
2341 static void filed_free_jcr(JCR *jcr)
2343 if (jcr->store_bsock) {
2344 jcr->store_bsock->close();
2346 free_bootstrap(jcr);
2347 if (jcr->last_fname) {
2348 free_pool_memory(jcr->last_fname);
2350 free_runscripts(jcr->RunScripts);
2351 delete jcr->RunScripts;
2352 free_path_list(jcr);
2354 if (jcr->JobId != 0)
2355 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2361 * Get response from Storage daemon to a command we
2362 * sent. Check that the response is OK.
2364 * Returns: 0 on failure
2367 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2372 if (bget_msg(sd) > 0) {
2373 Dmsg0(110, sd->msg);
2374 if (strcmp(sd->msg, resp) == 0) {
2378 if (job_canceled(jcr)) {
2379 return 0; /* if canceled avoid useless error messages */
2381 if (is_bnet_error(sd)) {
2382 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2383 cmd, bnet_strerror(sd));
2385 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2386 cmd, resp, sd->msg);
2391 static int send_bootstrap_file(JCR *jcr)
2395 BSOCK *sd = jcr->store_bsock;
2396 const char *bootstrap = "bootstrap\n";
2399 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2400 if (!jcr->RestoreBootstrap) {
2403 bs = fopen(jcr->RestoreBootstrap, "rb");
2406 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2407 jcr->RestoreBootstrap, be.bstrerror());
2408 jcr->setJobStatus(JS_ErrorTerminated);
2411 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2413 while (fgets(buf, sizeof(buf), bs)) {
2414 sd->msglen = Mmsg(sd->msg, "%s", buf);
2417 sd->signal(BNET_EOD);
2419 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2420 jcr->setJobStatus(JS_ErrorTerminated);
2426 free_bootstrap(jcr);