2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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
38 #if defined(WIN32_VSS)
41 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int enable_vss = 0;
46 * As Windows saves ACLs as part of the standard backup stream
47 * we just pretend here that is has implicit acl support.
49 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
50 const bool have_acl = true;
52 const bool have_acl = false;
55 #if defined(HAVE_XATTR)
56 const bool have_xattr = true;
58 const bool have_xattr = false;
61 extern CLIENT *me; /* our client resource */
63 /* Imported functions */
64 extern int status_cmd(JCR *jcr);
65 extern int qstatus_cmd(JCR *jcr);
66 extern int accurate_cmd(JCR *jcr);
68 /* Forward referenced functions */
69 static int backup_cmd(JCR *jcr);
70 static int bootstrap_cmd(JCR *jcr);
71 static int cancel_cmd(JCR *jcr);
72 static int setdebug_cmd(JCR *jcr);
73 static int setbandwidth_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 {"setbandwidth=",setbandwidth_cmd, 0},
116 {"estimate", estimate_cmd, 0},
117 {"Hello", hello_cmd, 1},
118 {"fileset", fileset_cmd, 0},
119 {"JobId=", job_cmd, 0},
120 {"level = ", level_cmd, 0},
121 {"restore ", restore_cmd, 0},
122 {"endrestore", end_restore_cmd, 0},
123 {"session", session_cmd, 0},
124 {"status", status_cmd, 1},
125 {".status", qstatus_cmd, 1},
126 {"storage ", storage_cmd, 0},
127 {"verify", verify_cmd, 0},
128 {"bootstrap", bootstrap_cmd, 0},
129 {"RunBeforeNow", runbeforenow_cmd, 0},
130 {"RunBeforeJob", runbefore_cmd, 0},
131 {"RunAfterJob", runafter_cmd, 0},
132 {"Run", runscript_cmd, 0},
133 {"accurate", accurate_cmd, 0},
134 {"restoreobject", restore_object_cmd, 0},
135 {"sm_dump", sm_dump_cmd, 0},
137 {"exit", exit_cmd, 0},
139 {NULL, NULL} /* list terminator */
142 /* Commands received from director that need scanning */
143 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
144 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
145 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
146 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
147 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
148 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
149 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
150 static char restoreobjcmd[] = "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";
157 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
159 /* Responses sent to Director */
160 static char errmsg[] = "2999 Invalid command\n";
161 static char no_auth[] = "2998 No Authorization\n";
162 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
163 static char OKBandwidth[] = "2000 OK Bandwidth\n";
164 static char OKinc[] = "2000 OK include\n";
165 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
166 static char OKlevel[] = "2000 OK level\n";
167 static char OKbackup[] = "2000 OK backup\n";
168 static char OKbootstrap[] = "2000 OK bootstrap\n";
169 static char OKverify[] = "2000 OK verify\n";
170 static char OKrestore[] = "2000 OK restore\n";
171 static char OKsession[] = "2000 OK session\n";
172 static char OKstore[] = "2000 OK storage\n";
173 static char OKstoreend[] = "2000 OK storage end\n";
174 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
175 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
176 static char BADjob[] = "2901 Bad Job\n";
177 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
178 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
179 static char OKRunBefore[] = "2000 OK RunBefore\n";
180 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
181 static char OKRunAfter[] = "2000 OK RunAfter\n";
182 static char OKRunScript[] = "2000 OK RunScript\n";
183 static char BADcmd[] = "2902 Bad %s\n";
184 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
187 /* Responses received from Storage Daemon */
188 static char OK_end[] = "3000 OK end\n";
189 static char OK_close[] = "3000 OK close Status = %d\n";
190 static char OK_open[] = "3000 OK open ticket = %d\n";
191 static char OK_data[] = "3000 OK data\n";
192 static char OK_append[] = "3000 OK append data\n";
193 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
196 /* Commands sent to Storage Daemon */
197 static char append_open[] = "append open session\n";
198 static char append_data[] = "append data %d\n";
199 static char append_end[] = "append end session %d\n";
200 static char append_close[] = "append close session %d\n";
201 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
202 static char read_data[] = "read data %d\n";
203 static char read_close[] = "read close session %d\n";
206 * Accept requests from a Director
208 * NOTE! We are running as a separate thread
210 * Send output one line
211 * at a time followed by a zero length transmission.
213 * Return when the connection is terminated or there
216 * Basic task here is:
217 * Authenticate Director (during Hello command).
218 * Accept commands one at a time from the Director
221 * Concerning ClientRunBefore/After, the sequence of events
222 * is rather critical. If they are not done in the right
223 * order one can easily get FD->SD timeouts if the script
226 * The current sequence of events is:
227 * 1. Dir starts job with FD
228 * 2. Dir connects to SD
229 * 3. Dir connects to FD
230 * 4. FD connects to SD
231 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
232 * 6. Dir sends include/exclude
233 * 7. FD sends data to SD
234 * 8. SD/FD disconnects while SD despools data and attributes (optional)
235 * 9. FD runs ClientRunAfterJob
238 void *handle_client_request(void *dirp)
243 BSOCK *dir = (BSOCK *)dirp;
244 const char jobname[12] = "*Director*";
247 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
248 jcr->dir_bsock = dir;
249 jcr->ff = init_find_files();
250 // save_cwd.save(jcr);
251 jcr->start_time = time(NULL);
252 jcr->RunScripts = New(alist(10, not_owned_by_alist));
253 jcr->last_fname = get_pool_memory(PM_FNAME);
254 jcr->last_fname[0] = 0;
255 jcr->client_name = get_memory(strlen(my_name) + 1);
256 pm_strcpy(jcr->client_name, my_name);
257 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
258 jcr->crypto.pki_sign = me->pki_sign;
259 jcr->crypto.pki_encrypt = me->pki_encrypt;
260 jcr->crypto.pki_keypair = me->pki_keypair;
261 jcr->crypto.pki_signers = me->pki_signers;
262 jcr->crypto.pki_recipients = me->pki_recipients;
264 enable_backup_privileges(NULL, 1 /* ignore_errors */);
266 /**********FIXME******* add command handler error code */
268 for (quit=false; !quit;) {
270 if (dir->recv() < 0) {
271 break; /* connection terminated */
273 dir->msg[dir->msglen] = 0;
274 Dmsg1(100, "<dird: %s", dir->msg);
276 for (i=0; cmds[i].cmd; i++) {
277 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
278 found = true; /* indicate command found */
279 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
281 dir->signal(BNET_EOD);
284 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
285 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
286 dir->fsend(invalid_cmd);
287 dir->signal(BNET_EOD);
290 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
291 if (!cmds[i].func(jcr)) { /* do command */
292 quit = true; /* error or fully terminated, get out */
293 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
298 if (!found) { /* command not found */
305 /* Inform Storage daemon that we are done */
306 if (jcr->store_bsock) {
307 jcr->store_bsock->signal(BNET_TERMINATE);
310 /* Run the after job */
311 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
313 if (jcr->JobId) { /* send EndJob if running a job */
314 char ed1[50], ed2[50];
315 /* Send termination status back to Dir */
316 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
317 edit_uint64(jcr->ReadBytes, ed1),
318 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
319 jcr->crypto.pki_encrypt);
320 Dmsg1(110, "End FD msg: %s\n", dir->msg);
323 generate_daemon_event(jcr, "JobEnd");
324 generate_plugin_event(jcr, bEventJobEnd);
326 dequeue_messages(jcr); /* send any queued messages */
328 /* Inform Director that we are done */
329 dir->signal(BNET_TERMINATE);
331 free_plugins(jcr); /* release instantiated plugins */
332 free_and_null_pool_memory(jcr->job_metadata);
334 /* Clean up fileset */
335 FF_PKT *ff = jcr->ff;
336 findFILESET *fileset = ff->fileset;
339 /* Delete FileSet Include lists */
340 for (i=0; i<fileset->include_list.size(); i++) {
341 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
342 for (j=0; j<incexe->opts_list.size(); j++) {
343 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
344 for (k=0; k<fo->regex.size(); k++) {
345 regfree((regex_t *)fo->regex.get(k));
347 for (k=0; k<fo->regexdir.size(); k++) {
348 regfree((regex_t *)fo->regexdir.get(k));
350 for (k=0; k<fo->regexfile.size(); k++) {
351 regfree((regex_t *)fo->regexfile.get(k));
354 fo->regexdir.destroy();
355 fo->regexfile.destroy();
357 fo->wilddir.destroy();
358 fo->wildfile.destroy();
359 fo->wildbase.destroy();
361 fo->fstype.destroy();
362 fo->drivetype.destroy();
364 incexe->opts_list.destroy();
365 incexe->name_list.destroy();
366 incexe->plugin_list.destroy();
367 if (incexe->ignoredir) {
368 free(incexe->ignoredir);
371 fileset->include_list.destroy();
373 /* Delete FileSet Exclude lists */
374 for (i=0; i<fileset->exclude_list.size(); i++) {
375 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
376 for (j=0; j<incexe->opts_list.size(); j++) {
377 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
379 fo->regexdir.destroy();
380 fo->regexfile.destroy();
382 fo->wilddir.destroy();
383 fo->wildfile.destroy();
384 fo->wildbase.destroy();
386 fo->fstype.destroy();
387 fo->drivetype.destroy();
389 incexe->opts_list.destroy();
390 incexe->name_list.destroy();
391 incexe->plugin_list.destroy();
392 if (incexe->ignoredir) {
393 free(incexe->ignoredir);
396 fileset->exclude_list.destroy();
400 Dmsg0(100, "Calling term_find_files\n");
401 term_find_files(jcr->ff);
402 // save_cwd.restore(jcr);
403 // save_cwd.release();
405 Dmsg0(100, "Done with term_find_files\n");
406 free_jcr(jcr); /* destroy JCR record */
407 Dmsg0(100, "Done with free_jcr\n");
409 garbage_collect_memory_pool();
413 static int sm_dump_cmd(JCR *jcr)
416 sm_dump(false, true);
417 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
422 static int exit_cmd(JCR *jcr)
424 jcr->dir_bsock->fsend("2000 exit OK\n");
432 * Hello from Director he must identify himself and provide his
435 static int hello_cmd(JCR *jcr)
437 Dmsg0(120, "Calling Authenticate\n");
438 if (!authenticate_director(jcr)) {
441 Dmsg0(120, "OK Authenticate\n");
442 jcr->authenticated = true;
449 static int cancel_cmd(JCR *jcr)
451 BSOCK *dir = jcr->dir_bsock;
452 char Job[MAX_NAME_LENGTH];
455 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
456 if (!(cjcr=get_jcr_by_full_name(Job))) {
457 dir->fsend(_("2901 Job %s not found.\n"), Job);
459 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
460 set_jcr_job_status(cjcr, JS_Canceled);
461 if (cjcr->store_bsock) {
462 cjcr->store_bsock->set_timed_out();
463 cjcr->store_bsock->set_terminated();
464 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
467 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
470 dir->fsend(_("2902 Error scanning cancel command.\n"));
472 dir->signal(BNET_EOD);
477 * Set bandwidth limit as requested by the Director
480 static int setbandwidth_cmd(JCR *jcr)
482 BSOCK *dir = jcr->dir_bsock;
485 char Job[MAX_NAME_LENGTH];
488 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
489 pm_strcpy(jcr->errmsg, dir->msg);
490 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
495 if(!(cjcr=get_jcr_by_full_name(Job))) {
496 dir->fsend(_("2901 Job %s not found.\n"), Job);
498 cjcr->max_bandwidth = bw;
499 if (cjcr->store_bsock) {
500 cjcr->store_bsock->set_bwlimit(bw);
505 } else { /* No job requested, apply globally */
506 me->max_bandwidth_per_job = bw; /* Overwrite directive */
509 return dir->fsend(OKBandwidth);
513 * Set debug level as requested by the Director
516 static int setdebug_cmd(JCR *jcr)
518 BSOCK *dir = jcr->dir_bsock;
519 int level, trace_flag;
521 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
522 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
523 pm_strcpy(jcr->errmsg, dir->msg);
524 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
528 set_trace(trace_flag);
529 return dir->fsend(OKsetdebug, level);
533 static int estimate_cmd(JCR *jcr)
535 BSOCK *dir = jcr->dir_bsock;
536 char ed1[50], ed2[50];
538 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
539 pm_strcpy(jcr->errmsg, dir->msg);
540 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
541 dir->fsend(_("2992 Bad estimate command.\n"));
545 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
546 edit_uint64_with_commas(jcr->JobBytes, ed2));
547 dir->signal(BNET_EOD);
552 * Get JobId and Storage Daemon Authorization key from Director
554 static int job_cmd(JCR *jcr)
556 BSOCK *dir = jcr->dir_bsock;
557 POOL_MEM sd_auth_key(PM_MESSAGE);
558 sd_auth_key.check_size(dir->msglen);
560 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
561 &jcr->VolSessionId, &jcr->VolSessionTime,
562 sd_auth_key.c_str()) != 5) {
563 pm_strcpy(jcr->errmsg, dir->msg);
564 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
568 set_storage_auth_key(jcr, sd_auth_key.c_str());
569 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
570 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
571 new_plugins(jcr); /* instantiate plugins for this jcr */
572 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
573 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
576 static int runbefore_cmd(JCR *jcr)
579 BSOCK *dir = jcr->dir_bsock;
580 POOLMEM *cmd = get_memory(dir->msglen+1);
583 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
584 if (sscanf(dir->msg, runbefore, cmd) != 1) {
585 pm_strcpy(jcr->errmsg, dir->msg);
586 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
587 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
593 /* Run the command now */
594 script = new_runscript();
595 script->set_command(cmd);
596 script->when = SCRIPT_Before;
597 ok = script->run(jcr, "ClientRunBeforeJob");
598 free_runscript(script);
602 dir->fsend(OKRunBefore);
605 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
610 static int runbeforenow_cmd(JCR *jcr)
612 BSOCK *dir = jcr->dir_bsock;
614 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
615 if (job_canceled(jcr)) {
616 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
617 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
620 dir->fsend(OKRunBeforeNow);
621 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
626 static int runafter_cmd(JCR *jcr)
628 BSOCK *dir = jcr->dir_bsock;
629 POOLMEM *msg = get_memory(dir->msglen+1);
632 Dmsg1(100, "runafter_cmd: %s", dir->msg);
633 if (sscanf(dir->msg, runafter, msg) != 1) {
634 pm_strcpy(jcr->errmsg, dir->msg);
635 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
636 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
642 cmd = new_runscript();
643 cmd->set_command(msg);
644 cmd->on_success = true;
645 cmd->on_failure = false;
646 cmd->when = SCRIPT_After;
648 jcr->RunScripts->append(cmd);
650 free_pool_memory(msg);
651 return dir->fsend(OKRunAfter);
654 static int runscript_cmd(JCR *jcr)
656 BSOCK *dir = jcr->dir_bsock;
657 POOLMEM *msg = get_memory(dir->msglen+1);
658 int on_success, on_failure, fail_on_error;
660 RUNSCRIPT *cmd = new_runscript() ;
662 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
663 /* Note, we cannot sscanf into bools */
664 if (sscanf(dir->msg, runscript, &on_success,
669 pm_strcpy(jcr->errmsg, dir->msg);
670 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
671 dir->fsend(_("2905 Bad RunScript command.\n"));
676 cmd->on_success = on_success;
677 cmd->on_failure = on_failure;
678 cmd->fail_on_error = fail_on_error;
681 cmd->set_command(msg);
683 jcr->RunScripts->append(cmd);
685 free_pool_memory(msg);
686 return dir->fsend(OKRunScript);
690 * This reads data sent from the Director from the
691 * RestoreObject table that allows us to get objects
692 * that were backed up (VSS .xml data) and are needed
693 * before starting the restore.
695 static int restore_object_cmd(JCR *jcr)
697 BSOCK *dir = jcr->dir_bsock;
699 restore_object_pkt rop;
701 memset(&rop, 0, sizeof(rop));
702 rop.pkt_size = sizeof(rop);
703 rop.pkt_end = sizeof(rop);
704 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
705 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
706 generate_plugin_event(jcr, bEventRestoreObject, NULL);
707 return dir->fsend(OKRestoreObject);
710 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
711 &rop.object_full_len, &rop.object_index,
712 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
713 Dmsg0(5, "Bad restore object command\n");
714 pm_strcpy(jcr->errmsg, dir->msg);
715 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
719 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
720 rop.JobId, rop.object_len, rop.object_full_len,
721 rop.object_index, rop.object_type, FileIndex);
722 /* Read Object name */
723 if (dir->recv() < 0) {
726 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
727 rop.object_name = bstrdup(dir->msg);
730 if (dir->recv() < 0) {
733 /* Transfer object from message buffer, and get new message buffer */
734 rop.object = dir->msg;
735 dir->msg = get_pool_memory(PM_MESSAGE);
737 /* If object is compressed, uncompress it */
738 if (rop.object_compression == 1) { /* zlib level 9 */
740 int out_len = rop.object_full_len + 100;
741 POOLMEM *obj = get_memory(out_len);
742 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
743 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
744 Dmsg1(100, "Zinflate stat=%d\n", stat);
745 if (out_len != rop.object_full_len) {
746 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
747 rop.object_full_len, out_len, rop.object_name);
749 free_pool_memory(rop.object); /* release compressed object */
750 rop.object = obj; /* new uncompressed object */
751 rop.object_len = out_len;
753 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
754 /* Special Job meta data */
755 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
756 Dmsg0(100, "got job metadata\n");
757 free_and_null_pool_memory(jcr->job_metadata);
758 jcr->job_metadata = rop.object;
762 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
765 if (rop.object_name) {
766 free(rop.object_name);
769 free_pool_memory(rop.object);
772 Dmsg1(100, "Send: %s", OKRestoreObject);
776 dir->fsend(_("2909 Bad RestoreObject command.\n"));
782 static bool init_fileset(JCR *jcr)
785 findFILESET *fileset;
794 fileset = (findFILESET *)malloc(sizeof(findFILESET));
795 memset(fileset, 0, sizeof(findFILESET));
796 ff->fileset = fileset;
797 fileset->state = state_none;
798 fileset->include_list.init(1, true);
799 fileset->exclude_list.init(1, true);
803 static void append_file(JCR *jcr, findINCEXE *incexe,
804 const char *buf, bool is_file)
807 incexe->name_list.append(new_dlistString(buf));
809 } else if (me->plugin_directory) {
810 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
811 incexe->plugin_list.append(new_dlistString(buf));
814 Jmsg(jcr, M_FATAL, 0,
815 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
821 * Add fname to include/exclude fileset list. First check for
822 * | and < and if necessary perform command.
824 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
826 findFILESET *fileset = jcr->ff->fileset;
839 p++; /* skip over | */
840 fn = get_pool_memory(PM_FNAME);
841 fn = edit_job_codes(jcr, fn, p, "");
842 bpipe = open_bpipe(fn, 0, "r");
845 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
847 free_pool_memory(fn);
850 free_pool_memory(fn);
851 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
852 strip_trailing_junk(buf);
853 append_file(jcr, fileset->incexe, buf, is_file);
855 if ((stat=close_bpipe(bpipe)) != 0) {
857 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
858 p, be.code(stat), be.bstrerror(stat));
863 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
864 p++; /* skip over < */
865 if ((ffd = fopen(p, "rb")) == NULL) {
867 Jmsg(jcr, M_FATAL, 0,
868 _("Cannot open FileSet input file: %s. ERR=%s\n"),
872 while (fgets(buf, sizeof(buf), ffd)) {
873 strip_trailing_junk(buf);
874 append_file(jcr, fileset->incexe, buf, is_file);
879 append_file(jcr, fileset->incexe, fname, is_file);
884 void set_incexe(JCR *jcr, findINCEXE *incexe)
886 findFILESET *fileset = jcr->ff->fileset;
887 fileset->incexe = incexe;
892 * Define a new Exclude block in the FileSet
894 findINCEXE *new_exclude(JCR *jcr)
896 findFILESET *fileset = jcr->ff->fileset;
899 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
900 memset(fileset->incexe, 0, sizeof(findINCEXE));
901 fileset->incexe->opts_list.init(1, true);
902 fileset->incexe->name_list.init();
903 fileset->incexe->plugin_list.init();
904 fileset->exclude_list.append(fileset->incexe);
905 return fileset->incexe;
909 * Define a new Include block in the FileSet
911 findINCEXE *new_include(JCR *jcr)
913 findFILESET *fileset = jcr->ff->fileset;
916 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
917 memset(fileset->incexe, 0, sizeof(findINCEXE));
918 fileset->incexe->opts_list.init(1, true);
919 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
920 fileset->incexe->plugin_list.init();
921 fileset->include_list.append(fileset->incexe);
922 return fileset->incexe;
926 * Define a new preInclude block in the FileSet
927 * That is the include is prepended to the other
928 * Includes. This is used for plugin exclusions.
930 findINCEXE *new_preinclude(JCR *jcr)
932 findFILESET *fileset = jcr->ff->fileset;
934 /* New pre-include */
935 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
936 memset(fileset->incexe, 0, sizeof(findINCEXE));
937 fileset->incexe->opts_list.init(1, true);
938 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
939 fileset->incexe->plugin_list.init();
940 fileset->include_list.prepend(fileset->incexe);
941 return fileset->incexe;
944 static findFOPTS *start_options(FF_PKT *ff)
946 int state = ff->fileset->state;
947 findINCEXE *incexe = ff->fileset->incexe;
949 if (state != state_options) {
950 ff->fileset->state = state_options;
951 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
952 memset(fo, 0, sizeof(findFOPTS));
953 fo->regex.init(1, true);
954 fo->regexdir.init(1, true);
955 fo->regexfile.init(1, true);
956 fo->wild.init(1, true);
957 fo->wilddir.init(1, true);
958 fo->wildfile.init(1, true);
959 fo->wildbase.init(1, true);
960 fo->base.init(1, true);
961 fo->fstype.init(1, true);
962 fo->drivetype.init(1, true);
963 incexe->current_opts = fo;
964 incexe->opts_list.append(fo);
966 return incexe->current_opts;
970 * Used by plugins to define a new options block
972 void new_options(JCR *jcr, findINCEXE *incexe)
975 incexe = jcr->ff->fileset->incexe;
977 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
978 memset(fo, 0, sizeof(findFOPTS));
979 fo->regex.init(1, true);
980 fo->regexdir.init(1, true);
981 fo->regexfile.init(1, true);
982 fo->wild.init(1, true);
983 fo->wilddir.init(1, true);
984 fo->wildfile.init(1, true);
985 fo->wildbase.init(1, true);
986 fo->base.init(1, true);
987 fo->fstype.init(1, true);
988 fo->drivetype.init(1, true);
989 incexe->current_opts = fo;
990 incexe->opts_list.prepend(fo);
991 jcr->ff->fileset->state = state_options;
995 * Add a regex to the current fileset
997 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
999 findFOPTS *current_opts = start_options(jcr->ff);
1004 preg = (regex_t *)malloc(sizeof(regex_t));
1005 if (current_opts->flags & FO_IGNORECASE) {
1006 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1008 rc = regcomp(preg, item, REG_EXTENDED);
1011 regerror(rc, preg, prbuf, sizeof(prbuf));
1014 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1018 current_opts->regex.append(preg);
1019 } else if (type == 'D') {
1020 current_opts->regexdir.append(preg);
1021 } else if (type == 'F') {
1022 current_opts->regexfile.append(preg);
1026 return state_options;
1030 * Add a wild card to the current fileset
1032 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1034 findFOPTS *current_opts = start_options(jcr->ff);
1037 current_opts->wild.append(bstrdup(item));
1038 } else if (type == 'D') {
1039 current_opts->wilddir.append(bstrdup(item));
1040 } else if (type == 'F') {
1041 current_opts->wildfile.append(bstrdup(item));
1042 } else if (type == 'B') {
1043 current_opts->wildbase.append(bstrdup(item));
1047 return state_options;
1052 * Add options to the current fileset
1054 int add_options_to_fileset(JCR *jcr, const char *item)
1056 findFOPTS *current_opts = start_options(jcr->ff);
1058 set_options(current_opts, item);
1059 return state_options;
1062 static void add_fileset(JCR *jcr, const char *item)
1064 FF_PKT *ff = jcr->ff;
1065 findFILESET *fileset = ff->fileset;
1066 int state = fileset->state;
1067 findFOPTS *current_opts;
1069 /* Get code, optional subcode, and position item past the dividing space */
1070 Dmsg1(100, "%s\n", item);
1075 int subcode = ' '; /* A space is always a valid subcode */
1076 if (item[0] != '\0' && item[0] != ' ') {
1084 /* Skip all lines we receive after an error */
1085 if (state == state_error) {
1086 Dmsg0(100, "State=error return\n");
1091 * The switch tests the code for validity.
1092 * The subcode is always good if it is a space, otherwise we must confirm.
1093 * We set state to state_error first assuming the subcode is invalid,
1094 * requiring state to be set in cases below that handle subcodes.
1096 if (subcode != ' ') {
1097 state = state_error;
1098 Dmsg0(100, "Set state=error or double code.\n");
1102 (void)new_include(jcr);
1105 (void)new_exclude(jcr);
1107 case 'N': /* null */
1110 case 'F': /* file = */
1111 /* File item to include or exclude list */
1112 state = state_include;
1113 add_file_to_fileset(jcr, item, true);
1115 case 'P': /* plugin */
1116 /* Plugin item to include list */
1117 state = state_include;
1118 add_file_to_fileset(jcr, item, false);
1120 case 'R': /* regex */
1121 state = add_regex_to_fileset(jcr, item, subcode);
1124 current_opts = start_options(ff);
1125 current_opts->base.append(bstrdup(item));
1126 state = state_options;
1128 case 'X': /* Filetype or Drive type */
1129 current_opts = start_options(ff);
1130 state = state_options;
1131 if (subcode == ' ') {
1132 current_opts->fstype.append(bstrdup(item));
1133 } else if (subcode == 'D') {
1134 current_opts->drivetype.append(bstrdup(item));
1136 state = state_error;
1139 case 'W': /* wild cards */
1140 state = add_wild_to_fileset(jcr, item, subcode);
1142 case 'O': /* Options */
1143 state = add_options_to_fileset(jcr, item);
1145 case 'Z': /* ignore dir */
1146 state = state_include;
1147 fileset->incexe->ignoredir = bstrdup(item);
1150 current_opts = start_options(ff);
1151 // current_opts->reader = bstrdup(item); /* deprecated */
1152 state = state_options;
1155 current_opts = start_options(ff);
1156 // current_opts->writer = bstrdup(item); /* deprecated */
1157 state = state_options;
1160 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1161 state = state_error;
1164 ff->fileset->state = state;
1167 static bool term_fileset(JCR *jcr)
1169 FF_PKT *ff = jcr->ff;
1171 #ifdef xxx_DEBUG_CODE
1172 findFILESET *fileset = ff->fileset;
1175 for (i=0; i<fileset->include_list.size(); i++) {
1176 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1178 for (j=0; j<incexe->opts_list.size(); j++) {
1179 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1180 for (k=0; k<fo->regex.size(); k++) {
1181 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1183 for (k=0; k<fo->regexdir.size(); k++) {
1184 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1186 for (k=0; k<fo->regexfile.size(); k++) {
1187 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1189 for (k=0; k<fo->wild.size(); k++) {
1190 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1192 for (k=0; k<fo->wilddir.size(); k++) {
1193 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1195 for (k=0; k<fo->wildfile.size(); k++) {
1196 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1198 for (k=0; k<fo->wildbase.size(); k++) {
1199 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1201 for (k=0; k<fo->base.size(); k++) {
1202 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1204 for (k=0; k<fo->fstype.size(); k++) {
1205 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1207 for (k=0; k<fo->drivetype.size(); k++) {
1208 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1211 if (incexe->ignoredir) {
1212 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1215 foreach_dlist(node, &incexe->name_list) {
1216 Dmsg1(400, "F %s\n", node->c_str());
1218 foreach_dlist(node, &incexe->plugin_list) {
1219 Dmsg1(400, "P %s\n", node->c_str());
1222 for (i=0; i<fileset->exclude_list.size(); i++) {
1223 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1225 for (j=0; j<incexe->opts_list.size(); j++) {
1226 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1227 for (k=0; k<fo->regex.size(); k++) {
1228 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1230 for (k=0; k<fo->regexdir.size(); k++) {
1231 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1233 for (k=0; k<fo->regexfile.size(); k++) {
1234 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1236 for (k=0; k<fo->wild.size(); k++) {
1237 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1239 for (k=0; k<fo->wilddir.size(); k++) {
1240 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1242 for (k=0; k<fo->wildfile.size(); k++) {
1243 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1245 for (k=0; k<fo->wildbase.size(); k++) {
1246 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1248 for (k=0; k<fo->base.size(); k++) {
1249 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1251 for (k=0; k<fo->fstype.size(); k++) {
1252 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1254 for (k=0; k<fo->drivetype.size(); k++) {
1255 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1259 foreach_dlist(node, incexe->name_list) {
1260 Dmsg1(400, "F %s\n", node->c_str());
1262 foreach_dlist(node, &incexe->plugin_list) {
1263 Dmsg1(400, "P %s\n", node->c_str());
1267 return ff->fileset->state != state_error;
1272 * As an optimization, we should do this during
1273 * "compile" time in filed/job.c, and keep only a bit mask
1274 * and the Verify options.
1276 static int set_options(findFOPTS *fo, const char *opts)
1282 // Commented out as it is not backward compatible - KES
1284 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1287 for (p=opts; *p; p++) {
1289 case 'a': /* alway replace */
1290 case '0': /* no option */
1293 fo->flags |= FO_EXCLUDE;
1296 fo->flags |= FO_MULTIFS;
1298 case 'h': /* no recursion */
1299 fo->flags |= FO_NO_RECURSION;
1301 case 'H': /* no hard link handling */
1302 fo->flags |= FO_NO_HARDLINK;
1305 fo->flags |= FO_IGNORECASE;
1308 fo->flags |= FO_MD5;
1311 fo->flags |= FO_NOREPLACE;
1313 case 'p': /* use portable data format */
1314 fo->flags |= FO_PORTABLE;
1316 case 'R': /* Resource forks and Finder Info */
1317 fo->flags |= FO_HFSPLUS;
1319 case 'r': /* read fifo */
1320 fo->flags |= FO_READFIFO;
1325 fo->flags |= FO_SHA1;
1330 fo->flags |= FO_SHA256;
1334 fo->flags |= FO_SHA512;
1340 * If 2 or 3 is seen here, SHA2 is not configured, so
1341 * eat the option, and drop back to SHA-1.
1343 if (p[1] == '2' || p[1] == '3') {
1346 fo->flags |= FO_SHA1;
1351 fo->flags |= FO_SPARSE;
1354 fo->flags |= FO_MTIMEONLY;
1357 fo->flags |= FO_KEEPATIME;
1360 fo->flags |= FO_ACL;
1362 case 'V': /* verify options */
1363 /* Copy Verify Options */
1364 for (j=0; *p && *p != ':'; p++) {
1365 fo->VerifyOpts[j] = *p;
1366 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1370 fo->VerifyOpts[j] = 0;
1372 case 'C': /* accurate options */
1373 /* Copy Accurate Options */
1374 for (j=0; *p && *p != ':'; p++) {
1375 fo->AccurateOpts[j] = *p;
1376 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1380 fo->AccurateOpts[j] = 0;
1382 case 'J': /* Basejob options */
1383 /* Copy BaseJob Options */
1384 for (j=0; *p && *p != ':'; p++) {
1385 fo->BaseJobOpts[j] = *p;
1386 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1390 fo->BaseJobOpts[j] = 0;
1392 case 'P': /* strip path */
1395 for (j=0; *p && *p != ':'; p++) {
1397 if (j < (int)sizeof(strip) - 1) {
1402 fo->strip_path = atoi(strip);
1403 fo->flags |= FO_STRIPPATH;
1404 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1407 fo->flags |= FO_IF_NEWER;
1410 fo->flags |= FO_ENHANCEDWILD;
1412 case 'Z': /* gzip compression */
1413 fo->flags |= FO_GZIP;
1414 fo->GZIP_level = *++p - '0';
1417 fo->flags |= FO_NOATIME;
1420 fo->flags |= FO_CHKCHANGES;
1423 fo->flags |= FO_HONOR_NODUMP;
1426 fo->flags |= FO_XATTR;
1429 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1433 return state_options;
1438 * Director is passing his Fileset
1440 static int fileset_cmd(JCR *jcr)
1442 BSOCK *dir = jcr->dir_bsock;
1445 #if defined(WIN32_VSS)
1448 sscanf(dir->msg, "fileset vss=%d", &vss);
1452 if (!init_fileset(jcr)) {
1455 while (dir->recv() >= 0) {
1456 strip_trailing_junk(dir->msg);
1457 Dmsg1(500, "Fileset: %s\n", dir->msg);
1458 add_fileset(jcr, dir->msg);
1460 if (!term_fileset(jcr)) {
1463 rtnstat = dir->fsend(OKinc);
1464 generate_plugin_event(jcr, bEventEndFileSet);
1468 static void free_bootstrap(JCR *jcr)
1470 if (jcr->RestoreBootstrap) {
1471 unlink(jcr->RestoreBootstrap);
1472 free_pool_memory(jcr->RestoreBootstrap);
1473 jcr->RestoreBootstrap = NULL;
1478 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1479 static uint32_t bsr_uniq = 0;
1482 * The Director sends us the bootstrap file, which
1483 * we will in turn pass to the SD.
1484 * Deprecated. The bsr is now sent directly from the
1485 * Director to the SD.
1487 static int bootstrap_cmd(JCR *jcr)
1489 BSOCK *dir = jcr->dir_bsock;
1490 POOLMEM *fname = get_pool_memory(PM_FNAME);
1493 free_bootstrap(jcr);
1496 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1497 jcr->Job, bsr_uniq);
1499 Dmsg1(400, "bootstrap=%s\n", fname);
1500 jcr->RestoreBootstrap = fname;
1501 bs = fopen(fname, "a+b"); /* create file */
1504 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1505 jcr->RestoreBootstrap, be.bstrerror());
1507 * Suck up what he is sending to us so that he will then
1508 * read our error message.
1510 while (dir->recv() >= 0)
1512 free_bootstrap(jcr);
1513 set_jcr_job_status(jcr, JS_ErrorTerminated);
1517 while (dir->recv() >= 0) {
1518 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1519 fputs(dir->msg, bs);
1523 * Note, do not free the bootstrap yet -- it needs to be
1526 return dir->fsend(OKbootstrap);
1531 * Get backup level from Director
1534 static int level_cmd(JCR *jcr)
1536 BSOCK *dir = jcr->dir_bsock;
1537 POOLMEM *level, *buf = NULL;
1540 level = get_memory(dir->msglen+1);
1541 Dmsg1(100, "level_cmd: %s", dir->msg);
1543 /* keep compatibility with older directors */
1544 if (strstr(dir->msg, "accurate")) {
1545 jcr->accurate = true;
1547 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1550 /* Base backup requested? */
1551 if (strcmp(level, "base") == 0) {
1552 jcr->set_JobLevel(L_BASE);
1553 /* Full backup requested? */
1554 } else if (strcmp(level, "full") == 0) {
1555 jcr->set_JobLevel(L_FULL);
1556 } else if (strstr(level, "differential")) {
1557 jcr->set_JobLevel(L_DIFFERENTIAL);
1560 } else if (strstr(level, "incremental")) {
1561 jcr->set_JobLevel(L_INCREMENTAL);
1565 * We get his UTC since time, then sync the clocks and correct it
1566 * to agree with our clock.
1568 } else if (strcmp(level, "since_utime") == 0) {
1569 buf = get_memory(dir->msglen+1);
1570 utime_t since_time, adj;
1571 btime_t his_time, bt_start, rt=0, bt_adj=0;
1572 if (jcr->getJobLevel() == L_NONE) {
1573 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1575 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1576 buf, &mtime_only) != 2) {
1579 since_time = str_to_uint64(buf); /* this is the since time */
1580 Dmsg1(100, "since_time=%lld\n", since_time);
1581 char ed1[50], ed2[50];
1583 * Sync clocks by polling him for the time. We take
1584 * 10 samples of his time throwing out the first two.
1586 for (int i=0; i<10; i++) {
1587 bt_start = get_current_btime();
1588 dir->signal(BNET_BTIME); /* poll for time */
1589 if (dir->recv() <= 0) { /* get response */
1592 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1595 if (i < 2) { /* toss first two results */
1598 his_time = str_to_uint64(buf);
1599 rt = get_current_btime() - bt_start; /* compute round trip time */
1600 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1601 edit_uint64(bt_start, ed2));
1602 bt_adj += bt_start - his_time - rt/2;
1603 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1606 bt_adj = bt_adj / 8; /* compute average time */
1607 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1608 adj = btime_to_utime(bt_adj);
1609 since_time += adj; /* adjust for clock difference */
1610 /* Don't notify if time within 3 seconds */
1611 if (adj > 3 || adj < -3) {
1613 if (adj > 600 || adj < -600) {
1618 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1620 dir->signal(BNET_EOD);
1622 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1623 jcr->incremental = 1; /* set incremental or decremental backup */
1624 jcr->mtime = since_time; /* set since time */
1625 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1627 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1635 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1636 return dir->fsend(OKlevel);
1639 pm_strcpy(jcr->errmsg, dir->msg);
1640 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1649 * Get session parameters from Director -- this is for a Restore command
1650 * This is deprecated. It is now passed via the bsr.
1652 static int session_cmd(JCR *jcr)
1654 BSOCK *dir = jcr->dir_bsock;
1656 Dmsg1(100, "SessionCmd: %s", dir->msg);
1657 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1658 &jcr->VolSessionId, &jcr->VolSessionTime,
1659 &jcr->StartFile, &jcr->EndFile,
1660 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1661 pm_strcpy(jcr->errmsg, dir->msg);
1662 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1666 return dir->fsend(OKsession);
1669 static void set_storage_auth_key(JCR *jcr, char *key)
1671 /* if no key don't update anything */
1677 * We can be contacting multiple storage daemons.
1678 * So, make sure that any old jcr->store_bsock is cleaned up.
1680 if (jcr->store_bsock) {
1681 jcr->store_bsock->destroy();
1682 jcr->store_bsock = NULL;
1686 * We can be contacting multiple storage daemons.
1687 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1689 if (jcr->sd_auth_key) {
1691 * If we already have a Authorization key, director can do multi
1694 Dmsg0(5, "set multi_restore=true\n");
1695 jcr->multi_restore = true;
1696 bfree(jcr->sd_auth_key);
1699 jcr->sd_auth_key = bstrdup(key);
1700 Dmsg0(5, "set sd auth key\n");
1704 * Get address of storage daemon from Director
1707 static int storage_cmd(JCR *jcr)
1709 int stored_port; /* storage daemon port */
1710 int enable_ssl; /* enable ssl to sd */
1711 POOL_MEM sd_auth_key(PM_MESSAGE);
1712 BSOCK *dir = jcr->dir_bsock;
1713 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1716 Dmsg1(100, "StorageCmd: %s", dir->msg);
1717 sd_auth_key.check_size(dir->msglen);
1718 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1719 &enable_ssl, sd_auth_key.c_str()) != 4) {
1720 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1721 &stored_port, &enable_ssl) != 3) {
1722 pm_strcpy(jcr->errmsg, dir->msg);
1723 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1728 set_storage_auth_key(jcr, sd_auth_key.c_str());
1730 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1732 /* Open command communications with Storage daemon */
1733 /* Try to connect for 1 hour at 10 second intervals */
1735 sd->set_source_address(me->FDsrc_addr);
1737 /* TODO: see if we put limit on restore and backup... */
1738 if (!jcr->max_bandwidth) {
1739 if (jcr->director->max_bandwidth_per_job) {
1740 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
1742 } else if (me->max_bandwidth_per_job) {
1743 jcr->max_bandwidth = me->max_bandwidth_per_job;
1746 sd->set_bwlimit(jcr->max_bandwidth);
1748 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1749 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1755 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1756 jcr->stored_addr, stored_port);
1757 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1758 jcr->stored_addr, stored_port);
1761 Dmsg0(110, "Connection OK to SD.\n");
1763 jcr->store_bsock = sd;
1765 sd->fsend("Hello Start Job %s\n", jcr->Job);
1766 if (!authenticate_storagedaemon(jcr)) {
1767 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1770 Dmsg0(110, "Authenticated with SD.\n");
1772 /* Send OK to Director */
1773 return dir->fsend(OKstore);
1776 dir->fsend(BADcmd, "storage");
1785 static int backup_cmd(JCR *jcr)
1787 BSOCK *dir = jcr->dir_bsock;
1788 BSOCK *sd = jcr->store_bsock;
1792 #if defined(WIN32_VSS)
1793 // capture state here, if client is backed up by multiple directors
1794 // and one enables vss and the other does not then enable_vss can change
1795 // between here and where its evaluated after the job completes.
1796 jcr->VSS = g_pVSSClient && enable_vss;
1798 /* Run only one at a time */
1804 * Validate some options given to the backup make sense for the compiled in
1805 * options of this filed.
1807 if (jcr->ff->flags & FO_ACL && !have_acl) {
1808 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1811 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1812 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1816 set_jcr_job_status(jcr, JS_Blocked);
1817 jcr->set_JobType(JT_BACKUP);
1818 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1821 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1822 dir->fsend(BADcmd, "backup");
1826 dir->fsend(OKbackup);
1827 Dmsg1(110, "filed>dird: %s", dir->msg);
1830 * Send Append Open Session to Storage daemon
1832 sd->fsend(append_open);
1833 Dmsg1(110, ">stored: %s", sd->msg);
1835 * Expect to receive back the Ticket number
1837 if (bget_msg(sd) >= 0) {
1838 Dmsg1(110, "<stored: %s", sd->msg);
1839 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1840 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1843 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1845 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1850 * Send Append data command to Storage daemon
1852 sd->fsend(append_data, jcr->Ticket);
1853 Dmsg1(110, ">stored: %s", sd->msg);
1856 * Expect to get OK data
1858 Dmsg1(110, "<stored: %s", sd->msg);
1859 if (!response(jcr, sd, OK_data, "Append Data")) {
1863 generate_daemon_event(jcr, "JobStart");
1864 generate_plugin_event(jcr, bEventStartBackupJob);
1866 #if defined(WIN32_VSS)
1867 /* START VSS ON WIN32 */
1869 if (g_pVSSClient->InitializeForBackup(jcr)) {
1870 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1871 /* tell vss which drives to snapshot */
1872 char szWinDriveLetters[27];
1873 *szWinDriveLetters=0;
1874 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1875 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1876 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1877 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1879 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1881 /* tell user if snapshot creation of a specific drive failed */
1883 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1884 if (islower(szWinDriveLetters[i])) {
1885 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1888 /* inform user about writer states */
1889 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1890 if (g_pVSSClient->GetWriterState(i) < 1) {
1891 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1896 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1900 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"), be.bstrerror());
1902 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1907 * Send Files to Storage daemon
1909 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1910 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1911 set_jcr_job_status(jcr, JS_ErrorTerminated);
1912 bnet_suppress_error_messages(sd, 1);
1913 Dmsg0(110, "Error in blast_data.\n");
1915 set_jcr_job_status(jcr, JS_Terminated);
1916 /* Note, the above set status will not override an error */
1917 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1918 bnet_suppress_error_messages(sd, 1);
1919 goto cleanup; /* bail out now */
1922 * Expect to get response to append_data from Storage daemon
1924 if (!response(jcr, sd, OK_append, "Append Data")) {
1925 set_jcr_job_status(jcr, JS_ErrorTerminated);
1930 * Send Append End Data to Storage daemon
1932 sd->fsend(append_end, jcr->Ticket);
1934 if (!response(jcr, sd, OK_end, "Append End")) {
1935 set_jcr_job_status(jcr, JS_ErrorTerminated);
1940 * Send Append Close to Storage daemon
1942 sd->fsend(append_close, jcr->Ticket);
1943 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1944 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1946 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1950 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1953 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1954 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1960 #if defined(WIN32_VSS)
1962 Win32ConvCleanupCache();
1963 g_pVSSClient->DestroyWriterInfo();
1968 generate_plugin_event(jcr, bEventEndBackupJob);
1969 return 0; /* return and stop command loop */
1973 * Do a Verify for Director
1976 static int verify_cmd(JCR *jcr)
1978 BSOCK *dir = jcr->dir_bsock;
1979 BSOCK *sd = jcr->store_bsock;
1982 jcr->set_JobType(JT_VERIFY);
1983 if (sscanf(dir->msg, verifycmd, level) != 1) {
1984 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1988 if (strcasecmp(level, "init") == 0) {
1989 jcr->set_JobLevel(L_VERIFY_INIT);
1990 } else if (strcasecmp(level, "catalog") == 0){
1991 jcr->set_JobLevel(L_VERIFY_CATALOG);
1992 } else if (strcasecmp(level, "volume") == 0){
1993 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1994 } else if (strcasecmp(level, "data") == 0){
1995 jcr->set_JobLevel(L_VERIFY_DATA);
1996 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1997 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1999 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2003 dir->fsend(OKverify);
2005 generate_daemon_event(jcr, "JobStart");
2006 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
2007 generate_plugin_event(jcr, bEventStartVerifyJob);
2009 Dmsg1(110, "filed>dird: %s", dir->msg);
2011 switch (jcr->getJobLevel()) {
2013 case L_VERIFY_CATALOG:
2016 case L_VERIFY_VOLUME_TO_CATALOG:
2017 if (!open_sd_read_session(jcr)) {
2020 start_dir_heartbeat(jcr);
2021 do_verify_volume(jcr);
2022 stop_dir_heartbeat(jcr);
2024 * Send Close session command to Storage daemon
2026 sd->fsend(read_close, jcr->Ticket);
2027 Dmsg1(130, "filed>stored: %s", sd->msg);
2029 /* ****FIXME**** check response */
2030 bget_msg(sd); /* get OK */
2032 /* Inform Storage daemon that we are done */
2033 sd->signal(BNET_TERMINATE);
2036 case L_VERIFY_DISK_TO_CATALOG:
2040 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2044 dir->signal(BNET_EOD);
2045 generate_plugin_event(jcr, bEventEndVerifyJob);
2046 return 0; /* return and terminate command loop */
2050 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2052 switch (init_type) {
2053 case VSS_INIT_RESTORE_AFTER_INIT:
2054 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2056 case VSS_INIT_RESTORE_AFTER_GATHER:
2057 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2067 * Do a Restore for Director
2070 static int restore_cmd(JCR *jcr)
2072 BSOCK *dir = jcr->dir_bsock;
2073 BSOCK *sd = jcr->store_bsock;
2075 bool use_regexwhere=false;
2080 * Scan WHERE (base directory for restore) from command
2082 Dmsg0(100, "restore command\n");
2083 #if defined(WIN32_VSS)
2086 * No need to enable VSS for restore if we do not have plugin
2089 enable_vss = jcr->job_metadata != NULL;
2091 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2092 // capture state here, if client is backed up by multiple directors
2093 // and one enables vss and the other does not then enable_vss can change
2094 // between here and where its evaluated after the job completes.
2095 jcr->VSS = g_pVSSClient && enable_vss;
2097 /* Run only one at a time */
2101 /* Pickup where string */
2102 args = get_memory(dir->msglen+1);
2105 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2106 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2107 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2108 pm_strcpy(jcr->errmsg, dir->msg);
2109 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2114 use_regexwhere = true;
2116 /* Turn / into nothing */
2117 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2121 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2122 unbash_spaces(args);
2124 if (use_regexwhere) {
2125 jcr->where_bregexp = get_bregexps(args);
2126 if (!jcr->where_bregexp) {
2127 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2128 free_pool_memory(args);
2132 jcr->where = bstrdup(args);
2135 free_pool_memory(args);
2136 jcr->replace = replace;
2137 jcr->prefix_links = prefix_links;
2139 dir->fsend(OKrestore);
2140 Dmsg1(110, "filed>dird: %s", dir->msg);
2142 jcr->set_JobType(JT_RESTORE);
2144 set_jcr_job_status(jcr, JS_Blocked);
2146 if (!open_sd_read_session(jcr)) {
2147 set_jcr_job_status(jcr, JS_ErrorTerminated);
2151 set_jcr_job_status(jcr, JS_Running);
2154 * Do restore of files and data
2156 start_dir_heartbeat(jcr);
2157 generate_daemon_event(jcr, "JobStart");
2158 generate_plugin_event(jcr, bEventStartRestoreJob);
2160 #if defined(WIN32_VSS)
2161 /* START VSS ON WIN32 */
2163 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2164 (WCHAR *)jcr->job_metadata)) {
2166 /* inform user about writer states */
2168 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2169 if (g_pVSSClient->GetWriterState(i) < 1) {
2170 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2176 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2177 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2181 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2183 free_and_null_pool_memory(jcr->job_metadata);
2184 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2189 stop_dir_heartbeat(jcr);
2191 set_jcr_job_status(jcr, JS_Terminated);
2192 if (jcr->JobStatus != JS_Terminated) {
2193 bnet_suppress_error_messages(sd, 1);
2197 * Send Close session command to Storage daemon
2199 sd->fsend(read_close, jcr->Ticket);
2200 Dmsg1(100, "filed>stored: %s", sd->msg);
2202 bget_msg(sd); /* get OK */
2204 /* Inform Storage daemon that we are done */
2205 sd->signal(BNET_TERMINATE);
2207 #if defined(WIN32_VSS)
2208 /* STOP VSS ON WIN32 */
2209 /* tell vss to close the restore session */
2210 Dmsg0(100, "About to call CloseRestore\n");
2212 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2213 Dmsg0(100, "Really about to call CloseRestore\n");
2214 if (g_pVSSClient->CloseRestore()) {
2215 Dmsg0(100, "CloseRestore success\n");
2216 /* inform user about writer states */
2217 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2218 int msg_type = M_INFO;
2219 if (g_pVSSClient->GetWriterState(i) < 1) {
2220 //msg_type = M_WARNING;
2223 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2227 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2233 bfree_and_null(jcr->where);
2235 if (jcr->JobErrors) {
2236 set_jcr_job_status(jcr, JS_ErrorTerminated);
2239 Dmsg0(100, "Done in job.c\n");
2242 if (jcr->multi_restore) {
2243 Dmsg0(100, OKstoreend);
2244 dir->fsend(OKstoreend);
2245 ret = 1; /* we continue the loop, waiting for next part */
2247 end_restore_cmd(jcr);
2248 ret = 0; /* we stop here */
2251 if (job_canceled(jcr)) {
2252 ret = 0; /* we stop here */
2258 static int end_restore_cmd(JCR *jcr)
2260 Dmsg0(5, "end_restore_cmd\n");
2261 generate_plugin_event(jcr, bEventEndRestoreJob);
2262 return 0; /* return and terminate command loop */
2265 static int open_sd_read_session(JCR *jcr)
2267 BSOCK *sd = jcr->store_bsock;
2270 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2273 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2274 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2275 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2277 * Open Read Session with Storage daemon
2279 sd->fsend(read_open, "DummyVolume",
2280 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2281 jcr->StartBlock, jcr->EndBlock);
2282 Dmsg1(110, ">stored: %s", sd->msg);
2287 if (bget_msg(sd) >= 0) {
2288 Dmsg1(110, "filed<stored: %s", sd->msg);
2289 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2290 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2293 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2295 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2299 if (!send_bootstrap_file(jcr)) {
2304 * Start read of data with Storage daemon
2306 sd->fsend(read_data, jcr->Ticket);
2307 Dmsg1(110, ">stored: %s", sd->msg);
2312 if (!response(jcr, sd, OK_data, "Read Data")) {
2319 * Destroy the Job Control Record and associated
2320 * resources (sockets).
2322 static void filed_free_jcr(JCR *jcr)
2324 if (jcr->store_bsock) {
2325 jcr->store_bsock->close();
2327 free_bootstrap(jcr);
2328 if (jcr->last_fname) {
2329 free_pool_memory(jcr->last_fname);
2331 free_runscripts(jcr->RunScripts);
2332 delete jcr->RunScripts;
2334 if (jcr->JobId != 0)
2335 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2341 * Get response from Storage daemon to a command we
2342 * sent. Check that the response is OK.
2344 * Returns: 0 on failure
2347 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2352 if (bget_msg(sd) > 0) {
2353 Dmsg0(110, sd->msg);
2354 if (strcmp(sd->msg, resp) == 0) {
2358 if (job_canceled(jcr)) {
2359 return 0; /* if canceled avoid useless error messages */
2361 if (is_bnet_error(sd)) {
2362 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2363 cmd, bnet_strerror(sd));
2365 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2366 cmd, resp, sd->msg);
2371 static int send_bootstrap_file(JCR *jcr)
2375 BSOCK *sd = jcr->store_bsock;
2376 const char *bootstrap = "bootstrap\n";
2379 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2380 if (!jcr->RestoreBootstrap) {
2383 bs = fopen(jcr->RestoreBootstrap, "rb");
2386 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2387 jcr->RestoreBootstrap, be.bstrerror());
2388 set_jcr_job_status(jcr, JS_ErrorTerminated);
2391 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2393 while (fgets(buf, sizeof(buf), bs)) {
2394 sd->msglen = Mmsg(sd->msg, "%s", buf);
2397 sd->signal(BNET_EOD);
2399 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2400 set_jcr_job_status(jcr, JS_ErrorTerminated);
2406 free_bootstrap(jcr);