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