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\n";
150 static char endrestoreobjectcmd[] = "restoreobject end\n";
151 static char verifycmd[] = "verify level=%30s";
152 static char estimatecmd[] = "estimate listing=%d";
153 static char runbefore[] = "RunBeforeJob %s";
154 static char runafter[] = "RunAfterJob %s";
155 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
157 /* Responses sent to Director */
158 static char errmsg[] = "2999 Invalid command\n";
159 static char no_auth[] = "2998 No Authorization\n";
160 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
161 static char OKinc[] = "2000 OK include\n";
162 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
163 static char OKlevel[] = "2000 OK level\n";
164 static char OKbackup[] = "2000 OK backup\n";
165 static char OKbootstrap[] = "2000 OK bootstrap\n";
166 static char OKverify[] = "2000 OK verify\n";
167 static char OKrestore[] = "2000 OK restore\n";
168 static char OKsession[] = "2000 OK session\n";
169 static char OKstore[] = "2000 OK storage\n";
170 static char OKstoreend[] = "2000 OK storage end\n";
171 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
172 static char OKsetdebug[] = "2000 OK setdebug=%d trace=%d hangup=%d\n";
173 static char BADjob[] = "2901 Bad Job\n";
174 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
175 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
176 static char OKRunBefore[] = "2000 OK RunBefore\n";
177 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
178 static char OKRunAfter[] = "2000 OK RunAfter\n";
179 static char OKRunScript[] = "2000 OK RunScript\n";
180 static char BADcmd[] = "2902 Bad %s\n";
181 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
184 /* Responses received from Storage Daemon */
185 static char OK_end[] = "3000 OK end\n";
186 static char OK_close[] = "3000 OK close Status = %d\n";
187 static char OK_open[] = "3000 OK open ticket = %d\n";
188 static char OK_data[] = "3000 OK data\n";
189 static char OK_append[] = "3000 OK append data\n";
190 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
193 /* Commands sent to Storage Daemon */
194 static char append_open[] = "append open session\n";
195 static char append_data[] = "append data %d\n";
196 static char append_end[] = "append end session %d\n";
197 static char append_close[] = "append close session %d\n";
198 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
199 static char read_data[] = "read data %d\n";
200 static char read_close[] = "read close session %d\n";
203 * Accept requests from a Director
205 * NOTE! We are running as a separate thread
207 * Send output one line
208 * at a time followed by a zero length transmission.
210 * Return when the connection is terminated or there
213 * Basic task here is:
214 * Authenticate Director (during Hello command).
215 * Accept commands one at a time from the Director
218 * Concerning ClientRunBefore/After, the sequence of events
219 * is rather critical. If they are not done in the right
220 * order one can easily get FD->SD timeouts if the script
223 * The current sequence of events is:
224 * 1. Dir starts job with FD
225 * 2. Dir connects to SD
226 * 3. Dir connects to FD
227 * 4. FD connects to SD
228 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
229 * 6. Dir sends include/exclude
230 * 7. FD sends data to SD
231 * 8. SD/FD disconnects while SD despools data and attributes (optional)
232 * 9. FD runs ClientRunAfterJob
235 void *handle_client_request(void *dirp)
240 BSOCK *dir = (BSOCK *)dirp;
241 const char jobname[12] = "*Director*";
244 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
245 jcr->dir_bsock = dir;
246 jcr->ff = init_find_files();
247 // save_cwd.save(jcr);
248 jcr->start_time = time(NULL);
249 jcr->RunScripts = New(alist(10, not_owned_by_alist));
250 jcr->last_fname = get_pool_memory(PM_FNAME);
251 jcr->last_fname[0] = 0;
252 jcr->client_name = get_memory(strlen(my_name) + 1);
253 pm_strcpy(jcr->client_name, my_name);
254 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
255 jcr->crypto.pki_sign = me->pki_sign;
256 jcr->crypto.pki_encrypt = me->pki_encrypt;
257 jcr->crypto.pki_keypair = me->pki_keypair;
258 jcr->crypto.pki_signers = me->pki_signers;
259 jcr->crypto.pki_recipients = me->pki_recipients;
261 enable_backup_privileges(NULL, 1 /* ignore_errors */);
263 /**********FIXME******* add command handler error code */
265 for (quit=false; !quit;) {
267 if (dir->recv() < 0) {
268 break; /* connection terminated */
270 dir->msg[dir->msglen] = 0;
271 Dmsg1(100, "<dird: %s", dir->msg);
273 for (i=0; cmds[i].cmd; i++) {
274 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
275 found = true; /* indicate command found */
276 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
278 dir->signal(BNET_EOD);
281 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
282 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
283 dir->fsend(invalid_cmd);
284 dir->signal(BNET_EOD);
287 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
288 if (!cmds[i].func(jcr)) { /* do command */
289 quit = true; /* error or fully terminated, get out */
290 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
295 if (!found) { /* command not found */
302 /* Inform Storage daemon that we are done */
303 if (jcr->store_bsock) {
304 jcr->store_bsock->signal(BNET_TERMINATE);
307 /* Run the after job */
308 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
310 if (jcr->JobId) { /* send EndJob if running a job */
311 char ed1[50], ed2[50];
312 /* Send termination status back to Dir */
313 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
314 edit_uint64(jcr->ReadBytes, ed1),
315 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
316 jcr->crypto.pki_encrypt);
317 Dmsg1(110, "End FD msg: %s\n", dir->msg);
320 generate_daemon_event(jcr, "JobEnd");
321 generate_plugin_event(jcr, bEventJobEnd);
323 dequeue_messages(jcr); /* send any queued messages */
325 /* Inform Director that we are done */
326 dir->signal(BNET_TERMINATE);
328 free_plugins(jcr); /* release instantiated plugins */
329 free_and_null_pool_memory(jcr->job_metadata);
331 /* Clean up fileset */
332 FF_PKT *ff = jcr->ff;
333 findFILESET *fileset = ff->fileset;
336 /* Delete FileSet Include lists */
337 for (i=0; i<fileset->include_list.size(); i++) {
338 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
339 for (j=0; j<incexe->opts_list.size(); j++) {
340 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
341 for (k=0; k<fo->regex.size(); k++) {
342 regfree((regex_t *)fo->regex.get(k));
344 for (k=0; k<fo->regexdir.size(); k++) {
345 regfree((regex_t *)fo->regexdir.get(k));
347 for (k=0; k<fo->regexfile.size(); k++) {
348 regfree((regex_t *)fo->regexfile.get(k));
351 fo->regexdir.destroy();
352 fo->regexfile.destroy();
354 fo->wilddir.destroy();
355 fo->wildfile.destroy();
356 fo->wildbase.destroy();
358 fo->fstype.destroy();
359 fo->drivetype.destroy();
361 incexe->opts_list.destroy();
362 incexe->name_list.destroy();
363 incexe->plugin_list.destroy();
364 if (incexe->ignoredir) {
365 free(incexe->ignoredir);
368 fileset->include_list.destroy();
370 /* Delete FileSet Exclude lists */
371 for (i=0; i<fileset->exclude_list.size(); i++) {
372 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
373 for (j=0; j<incexe->opts_list.size(); j++) {
374 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
376 fo->regexdir.destroy();
377 fo->regexfile.destroy();
379 fo->wilddir.destroy();
380 fo->wildfile.destroy();
381 fo->wildbase.destroy();
383 fo->fstype.destroy();
384 fo->drivetype.destroy();
386 incexe->opts_list.destroy();
387 incexe->name_list.destroy();
388 incexe->plugin_list.destroy();
389 if (incexe->ignoredir) {
390 free(incexe->ignoredir);
393 fileset->exclude_list.destroy();
397 Dmsg0(100, "Calling term_find_files\n");
398 term_find_files(jcr->ff);
399 // save_cwd.restore(jcr);
400 // save_cwd.release();
402 Dmsg0(100, "Done with term_find_files\n");
403 free_jcr(jcr); /* destroy JCR record */
404 Dmsg0(100, "Done with free_jcr\n");
406 garbage_collect_memory_pool();
410 static int sm_dump_cmd(JCR *jcr)
413 sm_dump(false, true);
414 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
419 static int exit_cmd(JCR *jcr)
421 jcr->dir_bsock->fsend("2000 exit OK\n");
429 * Hello from Director he must identify himself and provide his
432 static int hello_cmd(JCR *jcr)
434 Dmsg0(120, "Calling Authenticate\n");
435 if (!authenticate_director(jcr)) {
438 Dmsg0(120, "OK Authenticate\n");
439 jcr->authenticated = true;
446 static int cancel_cmd(JCR *jcr)
448 BSOCK *dir = jcr->dir_bsock;
449 char Job[MAX_NAME_LENGTH];
452 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
453 if (!(cjcr=get_jcr_by_full_name(Job))) {
454 dir->fsend(_("2901 Job %s not found.\n"), Job);
456 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
457 cjcr->setJobStatus(JS_Canceled);
458 if (cjcr->store_bsock) {
459 cjcr->store_bsock->set_timed_out();
460 cjcr->store_bsock->set_terminated();
461 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
464 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
467 dir->fsend(_("2902 Error scanning cancel command.\n"));
469 dir->signal(BNET_EOD);
474 * Set debug level as requested by the Director
477 static int setdebug_cmd(JCR *jcr)
479 BSOCK *dir = jcr->dir_bsock;
480 int32_t level, trace, hangup;
483 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
484 scan = sscanf(dir->msg, "setdebug=%d trace=%d hangup=%d",
485 &level, &trace, &hangup);
487 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
488 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace) != 2) {
489 pm_strcpy(jcr->errmsg, dir->msg);
490 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
501 Dmsg3(50, "level=%d trace=%d hangup=%d\n", level, get_trace(), get_hangup());
502 return dir->fsend(OKsetdebug, level, get_trace(), get_hangup());
506 static int estimate_cmd(JCR *jcr)
508 BSOCK *dir = jcr->dir_bsock;
509 char ed1[50], ed2[50];
511 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
512 pm_strcpy(jcr->errmsg, dir->msg);
513 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
514 dir->fsend(_("2992 Bad estimate command.\n"));
518 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
519 edit_uint64_with_commas(jcr->JobBytes, ed2));
520 dir->signal(BNET_EOD);
525 * Get JobId and Storage Daemon Authorization key from Director
527 static int job_cmd(JCR *jcr)
529 BSOCK *dir = jcr->dir_bsock;
530 POOL_MEM sd_auth_key(PM_MESSAGE);
531 sd_auth_key.check_size(dir->msglen);
533 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
534 &jcr->VolSessionId, &jcr->VolSessionTime,
535 sd_auth_key.c_str()) != 5) {
536 pm_strcpy(jcr->errmsg, dir->msg);
537 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
541 set_storage_auth_key(jcr, sd_auth_key.c_str());
542 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
543 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
544 new_plugins(jcr); /* instantiate plugins for this jcr */
545 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
547 return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
549 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
553 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param)
558 return jcr->director->hdr.name;
566 static int runbefore_cmd(JCR *jcr)
569 BSOCK *dir = jcr->dir_bsock;
570 POOLMEM *cmd = get_memory(dir->msglen+1);
573 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
574 if (sscanf(dir->msg, runbefore, cmd) != 1) {
575 pm_strcpy(jcr->errmsg, dir->msg);
576 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
577 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
583 /* Run the command now */
584 script = new_runscript();
585 script->set_job_code_callback(job_code_callback_filed);
586 script->set_command(cmd);
587 script->when = SCRIPT_Before;
588 ok = script->run(jcr, "ClientRunBeforeJob");
589 free_runscript(script);
593 dir->fsend(OKRunBefore);
596 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
601 static int runbeforenow_cmd(JCR *jcr)
603 BSOCK *dir = jcr->dir_bsock;
605 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
606 if (job_canceled(jcr)) {
607 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
608 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
611 dir->fsend(OKRunBeforeNow);
612 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
617 static int runafter_cmd(JCR *jcr)
619 BSOCK *dir = jcr->dir_bsock;
620 POOLMEM *msg = get_memory(dir->msglen+1);
623 Dmsg1(100, "runafter_cmd: %s", dir->msg);
624 if (sscanf(dir->msg, runafter, msg) != 1) {
625 pm_strcpy(jcr->errmsg, dir->msg);
626 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
627 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
633 cmd = new_runscript();
634 cmd->set_job_code_callback(job_code_callback_filed);
635 cmd->set_command(msg);
636 cmd->on_success = true;
637 cmd->on_failure = false;
638 cmd->when = SCRIPT_After;
640 jcr->RunScripts->append(cmd);
642 free_pool_memory(msg);
643 return dir->fsend(OKRunAfter);
646 static int runscript_cmd(JCR *jcr)
648 BSOCK *dir = jcr->dir_bsock;
649 POOLMEM *msg = get_memory(dir->msglen+1);
650 int on_success, on_failure, fail_on_error;
652 RUNSCRIPT *cmd = new_runscript() ;
653 cmd->set_job_code_callback(job_code_callback_filed);
655 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
656 /* Note, we cannot sscanf into bools */
657 if (sscanf(dir->msg, runscript, &on_success,
662 pm_strcpy(jcr->errmsg, dir->msg);
663 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
664 dir->fsend(_("2905 Bad RunScript command.\n"));
669 cmd->on_success = on_success;
670 cmd->on_failure = on_failure;
671 cmd->fail_on_error = fail_on_error;
674 cmd->set_command(msg);
676 jcr->RunScripts->append(cmd);
678 free_pool_memory(msg);
679 return dir->fsend(OKRunScript);
683 * This reads data sent from the Director from the
684 * RestoreObject table that allows us to get objects
685 * that were backed up (VSS .xml data) and are needed
686 * before starting the restore.
688 static int restore_object_cmd(JCR *jcr)
690 BSOCK *dir = jcr->dir_bsock;
692 restore_object_pkt rop;
694 memset(&rop, 0, sizeof(rop));
695 rop.pkt_size = sizeof(rop);
696 rop.pkt_end = sizeof(rop);
697 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
698 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
699 generate_plugin_event(jcr, bEventRestoreObject, NULL);
700 return dir->fsend(OKRestoreObject);
703 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
704 &rop.object_full_len, &rop.object_index,
705 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
706 Dmsg0(5, "Bad restore object command\n");
707 pm_strcpy(jcr->errmsg, dir->msg);
708 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
712 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
713 rop.JobId, rop.object_len, rop.object_full_len,
714 rop.object_index, rop.object_type, FileIndex);
715 /* Read Object name */
716 if (dir->recv() < 0) {
719 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
720 rop.object_name = bstrdup(dir->msg);
723 if (dir->recv() < 0) {
726 /* Transfer object from message buffer, and get new message buffer */
727 rop.object = dir->msg;
728 dir->msg = get_pool_memory(PM_MESSAGE);
730 /* If object is compressed, uncompress it */
731 if (rop.object_compression == 1) { /* zlib level 9 */
733 int out_len = rop.object_full_len + 100;
734 POOLMEM *obj = get_memory(out_len);
735 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
736 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
737 Dmsg1(100, "Zinflate stat=%d\n", stat);
738 if (out_len != rop.object_full_len) {
739 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
740 rop.object_full_len, out_len, rop.object_name);
742 free_pool_memory(rop.object); /* release compressed object */
743 rop.object = obj; /* new uncompressed object */
744 rop.object_len = out_len;
746 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
747 /* Special Job meta data */
748 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
749 Dmsg0(100, "got job metadata\n");
750 free_and_null_pool_memory(jcr->job_metadata);
751 jcr->job_metadata = rop.object;
755 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
758 if (rop.object_name) {
759 free(rop.object_name);
762 free_pool_memory(rop.object);
765 Dmsg1(100, "Send: %s", OKRestoreObject);
769 dir->fsend(_("2909 Bad RestoreObject command.\n"));
775 static bool init_fileset(JCR *jcr)
778 findFILESET *fileset;
787 fileset = (findFILESET *)malloc(sizeof(findFILESET));
788 memset(fileset, 0, sizeof(findFILESET));
789 ff->fileset = fileset;
790 fileset->state = state_none;
791 fileset->include_list.init(1, true);
792 fileset->exclude_list.init(1, true);
796 static void append_file(JCR *jcr, findINCEXE *incexe,
797 const char *buf, bool is_file)
800 incexe->name_list.append(new_dlistString(buf));
802 } else if (me->plugin_directory) {
803 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
804 incexe->plugin_list.append(new_dlistString(buf));
807 Jmsg(jcr, M_FATAL, 0,
808 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
814 * Add fname to include/exclude fileset list. First check for
815 * | and < and if necessary perform command.
817 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
819 findFILESET *fileset = jcr->ff->fileset;
832 p++; /* skip over | */
833 fn = get_pool_memory(PM_FNAME);
834 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
835 bpipe = open_bpipe(fn, 0, "r");
838 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
840 free_pool_memory(fn);
843 free_pool_memory(fn);
844 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
845 strip_trailing_junk(buf);
846 append_file(jcr, fileset->incexe, buf, is_file);
848 if ((stat=close_bpipe(bpipe)) != 0) {
850 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
851 p, be.code(stat), be.bstrerror(stat));
856 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
857 p++; /* skip over < */
858 if ((ffd = fopen(p, "rb")) == NULL) {
860 Jmsg(jcr, M_FATAL, 0,
861 _("Cannot open FileSet input file: %s. ERR=%s\n"),
865 while (fgets(buf, sizeof(buf), ffd)) {
866 strip_trailing_junk(buf);
867 append_file(jcr, fileset->incexe, buf, is_file);
872 append_file(jcr, fileset->incexe, fname, is_file);
877 void set_incexe(JCR *jcr, findINCEXE *incexe)
879 findFILESET *fileset = jcr->ff->fileset;
880 fileset->incexe = incexe;
885 * Define a new Exclude block in the FileSet
887 findINCEXE *new_exclude(JCR *jcr)
889 findFILESET *fileset = jcr->ff->fileset;
892 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
893 memset(fileset->incexe, 0, sizeof(findINCEXE));
894 fileset->incexe->opts_list.init(1, true);
895 fileset->incexe->name_list.init();
896 fileset->incexe->plugin_list.init();
897 fileset->exclude_list.append(fileset->incexe);
898 return fileset->incexe;
902 * Define a new Include block in the FileSet
904 findINCEXE *new_include(JCR *jcr)
906 findFILESET *fileset = jcr->ff->fileset;
909 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
910 memset(fileset->incexe, 0, sizeof(findINCEXE));
911 fileset->incexe->opts_list.init(1, true);
912 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
913 fileset->incexe->plugin_list.init();
914 fileset->include_list.append(fileset->incexe);
915 return fileset->incexe;
919 * Define a new preInclude block in the FileSet
920 * That is the include is prepended to the other
921 * Includes. This is used for plugin exclusions.
923 findINCEXE *new_preinclude(JCR *jcr)
925 findFILESET *fileset = jcr->ff->fileset;
927 /* New pre-include */
928 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
929 memset(fileset->incexe, 0, sizeof(findINCEXE));
930 fileset->incexe->opts_list.init(1, true);
931 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
932 fileset->incexe->plugin_list.init();
933 fileset->include_list.prepend(fileset->incexe);
934 return fileset->incexe;
937 static findFOPTS *start_options(FF_PKT *ff)
939 int state = ff->fileset->state;
940 findINCEXE *incexe = ff->fileset->incexe;
942 if (state != state_options) {
943 ff->fileset->state = state_options;
944 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
945 memset(fo, 0, sizeof(findFOPTS));
946 fo->regex.init(1, true);
947 fo->regexdir.init(1, true);
948 fo->regexfile.init(1, true);
949 fo->wild.init(1, true);
950 fo->wilddir.init(1, true);
951 fo->wildfile.init(1, true);
952 fo->wildbase.init(1, true);
953 fo->base.init(1, true);
954 fo->fstype.init(1, true);
955 fo->drivetype.init(1, true);
956 incexe->current_opts = fo;
957 incexe->opts_list.append(fo);
959 return incexe->current_opts;
963 * Used by plugins to define a new options block
965 void new_options(JCR *jcr, findINCEXE *incexe)
968 incexe = jcr->ff->fileset->incexe;
970 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
971 memset(fo, 0, sizeof(findFOPTS));
972 fo->regex.init(1, true);
973 fo->regexdir.init(1, true);
974 fo->regexfile.init(1, true);
975 fo->wild.init(1, true);
976 fo->wilddir.init(1, true);
977 fo->wildfile.init(1, true);
978 fo->wildbase.init(1, true);
979 fo->base.init(1, true);
980 fo->fstype.init(1, true);
981 fo->drivetype.init(1, true);
982 incexe->current_opts = fo;
983 incexe->opts_list.prepend(fo);
984 jcr->ff->fileset->state = state_options;
988 * Add a regex to the current fileset
990 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
992 findFOPTS *current_opts = start_options(jcr->ff);
997 preg = (regex_t *)malloc(sizeof(regex_t));
998 if (current_opts->flags & FO_IGNORECASE) {
999 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1001 rc = regcomp(preg, item, REG_EXTENDED);
1004 regerror(rc, preg, prbuf, sizeof(prbuf));
1007 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1011 current_opts->regex.append(preg);
1012 } else if (type == 'D') {
1013 current_opts->regexdir.append(preg);
1014 } else if (type == 'F') {
1015 current_opts->regexfile.append(preg);
1019 return state_options;
1023 * Add a wild card to the current fileset
1025 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1027 findFOPTS *current_opts = start_options(jcr->ff);
1030 current_opts->wild.append(bstrdup(item));
1031 } else if (type == 'D') {
1032 current_opts->wilddir.append(bstrdup(item));
1033 } else if (type == 'F') {
1034 current_opts->wildfile.append(bstrdup(item));
1035 } else if (type == 'B') {
1036 current_opts->wildbase.append(bstrdup(item));
1040 return state_options;
1045 * Add options to the current fileset
1047 int add_options_to_fileset(JCR *jcr, const char *item)
1049 findFOPTS *current_opts = start_options(jcr->ff);
1051 set_options(current_opts, item);
1052 return state_options;
1055 static void add_fileset(JCR *jcr, const char *item)
1057 FF_PKT *ff = jcr->ff;
1058 findFILESET *fileset = ff->fileset;
1059 int state = fileset->state;
1060 findFOPTS *current_opts;
1062 /* Get code, optional subcode, and position item past the dividing space */
1063 Dmsg1(100, "%s\n", item);
1068 int subcode = ' '; /* A space is always a valid subcode */
1069 if (item[0] != '\0' && item[0] != ' ') {
1077 /* Skip all lines we receive after an error */
1078 if (state == state_error) {
1079 Dmsg0(100, "State=error return\n");
1084 * The switch tests the code for validity.
1085 * The subcode is always good if it is a space, otherwise we must confirm.
1086 * We set state to state_error first assuming the subcode is invalid,
1087 * requiring state to be set in cases below that handle subcodes.
1089 if (subcode != ' ') {
1090 state = state_error;
1091 Dmsg0(100, "Set state=error or double code.\n");
1095 (void)new_include(jcr);
1098 (void)new_exclude(jcr);
1100 case 'N': /* null */
1103 case 'F': /* file = */
1104 /* File item to include or exclude list */
1105 state = state_include;
1106 add_file_to_fileset(jcr, item, true);
1108 case 'P': /* plugin */
1109 /* Plugin item to include list */
1110 state = state_include;
1111 add_file_to_fileset(jcr, item, false);
1113 case 'R': /* regex */
1114 state = add_regex_to_fileset(jcr, item, subcode);
1117 current_opts = start_options(ff);
1118 current_opts->base.append(bstrdup(item));
1119 state = state_options;
1121 case 'X': /* Filetype or Drive type */
1122 current_opts = start_options(ff);
1123 state = state_options;
1124 if (subcode == ' ') {
1125 current_opts->fstype.append(bstrdup(item));
1126 } else if (subcode == 'D') {
1127 current_opts->drivetype.append(bstrdup(item));
1129 state = state_error;
1132 case 'W': /* wild cards */
1133 state = add_wild_to_fileset(jcr, item, subcode);
1135 case 'O': /* Options */
1136 state = add_options_to_fileset(jcr, item);
1138 case 'Z': /* ignore dir */
1139 state = state_include;
1140 fileset->incexe->ignoredir = bstrdup(item);
1143 current_opts = start_options(ff);
1144 // current_opts->reader = bstrdup(item); /* deprecated */
1145 state = state_options;
1148 current_opts = start_options(ff);
1149 // current_opts->writer = bstrdup(item); /* deprecated */
1150 state = state_options;
1153 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1154 state = state_error;
1157 ff->fileset->state = state;
1160 static bool term_fileset(JCR *jcr)
1162 FF_PKT *ff = jcr->ff;
1164 #ifdef xxx_DEBUG_CODE
1165 findFILESET *fileset = ff->fileset;
1168 for (i=0; i<fileset->include_list.size(); i++) {
1169 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1171 for (j=0; j<incexe->opts_list.size(); j++) {
1172 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1173 for (k=0; k<fo->regex.size(); k++) {
1174 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1176 for (k=0; k<fo->regexdir.size(); k++) {
1177 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1179 for (k=0; k<fo->regexfile.size(); k++) {
1180 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1182 for (k=0; k<fo->wild.size(); k++) {
1183 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1185 for (k=0; k<fo->wilddir.size(); k++) {
1186 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1188 for (k=0; k<fo->wildfile.size(); k++) {
1189 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1191 for (k=0; k<fo->wildbase.size(); k++) {
1192 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1194 for (k=0; k<fo->base.size(); k++) {
1195 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1197 for (k=0; k<fo->fstype.size(); k++) {
1198 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1200 for (k=0; k<fo->drivetype.size(); k++) {
1201 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1204 if (incexe->ignoredir) {
1205 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1208 foreach_dlist(node, &incexe->name_list) {
1209 Dmsg1(400, "F %s\n", node->c_str());
1211 foreach_dlist(node, &incexe->plugin_list) {
1212 Dmsg1(400, "P %s\n", node->c_str());
1215 for (i=0; i<fileset->exclude_list.size(); i++) {
1216 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1218 for (j=0; j<incexe->opts_list.size(); j++) {
1219 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1220 for (k=0; k<fo->regex.size(); k++) {
1221 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1223 for (k=0; k<fo->regexdir.size(); k++) {
1224 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1226 for (k=0; k<fo->regexfile.size(); k++) {
1227 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1229 for (k=0; k<fo->wild.size(); k++) {
1230 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1232 for (k=0; k<fo->wilddir.size(); k++) {
1233 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1235 for (k=0; k<fo->wildfile.size(); k++) {
1236 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1238 for (k=0; k<fo->wildbase.size(); k++) {
1239 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1241 for (k=0; k<fo->base.size(); k++) {
1242 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1244 for (k=0; k<fo->fstype.size(); k++) {
1245 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1247 for (k=0; k<fo->drivetype.size(); k++) {
1248 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1252 foreach_dlist(node, &incexe->name_list) {
1253 Dmsg1(400, "F %s\n", node->c_str());
1255 foreach_dlist(node, &incexe->plugin_list) {
1256 Dmsg1(400, "P %s\n", node->c_str());
1260 return ff->fileset->state != state_error;
1265 * As an optimization, we should do this during
1266 * "compile" time in filed/job.c, and keep only a bit mask
1267 * and the Verify options.
1269 static int set_options(findFOPTS *fo, const char *opts)
1275 // Commented out as it is not backward compatible - KES
1277 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1280 for (p=opts; *p; p++) {
1282 case 'a': /* alway replace */
1283 case '0': /* no option */
1286 fo->flags |= FO_EXCLUDE;
1289 fo->flags |= FO_MULTIFS;
1291 case 'h': /* no recursion */
1292 fo->flags |= FO_NO_RECURSION;
1294 case 'H': /* no hard link handling */
1295 fo->flags |= FO_NO_HARDLINK;
1298 fo->flags |= FO_IGNORECASE;
1301 fo->flags |= FO_MD5;
1304 fo->flags |= FO_NOREPLACE;
1306 case 'p': /* use portable data format */
1307 fo->flags |= FO_PORTABLE;
1309 case 'R': /* Resource forks and Finder Info */
1310 fo->flags |= FO_HFSPLUS;
1312 case 'r': /* read fifo */
1313 fo->flags |= FO_READFIFO;
1318 fo->flags |= FO_SHA1;
1323 fo->flags |= FO_SHA256;
1327 fo->flags |= FO_SHA512;
1333 * If 2 or 3 is seen here, SHA2 is not configured, so
1334 * eat the option, and drop back to SHA-1.
1336 if (p[1] == '2' || p[1] == '3') {
1339 fo->flags |= FO_SHA1;
1344 fo->flags |= FO_SPARSE;
1347 fo->flags |= FO_MTIMEONLY;
1350 fo->flags |= FO_KEEPATIME;
1353 fo->flags |= FO_ACL;
1355 case 'V': /* verify options */
1356 /* Copy Verify Options */
1357 for (j=0; *p && *p != ':'; p++) {
1358 fo->VerifyOpts[j] = *p;
1359 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1363 fo->VerifyOpts[j] = 0;
1365 case 'C': /* accurate options */
1366 /* Copy Accurate Options */
1367 for (j=0; *p && *p != ':'; p++) {
1368 fo->AccurateOpts[j] = *p;
1369 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1373 fo->AccurateOpts[j] = 0;
1375 case 'J': /* Basejob options */
1376 /* Copy BaseJob Options */
1377 for (j=0; *p && *p != ':'; p++) {
1378 fo->BaseJobOpts[j] = *p;
1379 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1383 fo->BaseJobOpts[j] = 0;
1385 case 'P': /* strip path */
1388 for (j=0; *p && *p != ':'; p++) {
1390 if (j < (int)sizeof(strip) - 1) {
1395 fo->strip_path = atoi(strip);
1396 fo->flags |= FO_STRIPPATH;
1397 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1400 fo->flags |= FO_IF_NEWER;
1403 fo->flags |= FO_ENHANCEDWILD;
1405 case 'Z': /* compression */
1407 if (*p >= '0' && *p <= '9') {
1408 fo->flags |= FO_COMPRESS;
1409 fo->Compress_algo = COMPRESS_GZIP;
1410 fo->Compress_level = *p - '0';
1412 else if (*p == 'o') {
1413 fo->flags |= FO_COMPRESS;
1414 fo->Compress_algo = COMPRESS_LZO1X;
1415 fo->Compress_level = 1; /* not used with LZO */
1419 fo->flags |= FO_NOATIME;
1422 fo->flags |= FO_CHKCHANGES;
1425 fo->flags |= FO_HONOR_NODUMP;
1428 fo->flags |= FO_XATTR;
1431 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1435 return state_options;
1440 * Director is passing his Fileset
1442 static int fileset_cmd(JCR *jcr)
1444 BSOCK *dir = jcr->dir_bsock;
1447 #if defined(WIN32_VSS)
1450 sscanf(dir->msg, "fileset vss=%d", &vss);
1454 if (!init_fileset(jcr)) {
1457 while (dir->recv() >= 0) {
1458 strip_trailing_junk(dir->msg);
1459 Dmsg1(500, "Fileset: %s\n", dir->msg);
1460 add_fileset(jcr, dir->msg);
1462 if (!term_fileset(jcr)) {
1465 rtnstat = dir->fsend(OKinc);
1466 generate_plugin_event(jcr, bEventEndFileSet);
1470 static void free_bootstrap(JCR *jcr)
1472 if (jcr->RestoreBootstrap) {
1473 unlink(jcr->RestoreBootstrap);
1474 free_pool_memory(jcr->RestoreBootstrap);
1475 jcr->RestoreBootstrap = NULL;
1480 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1481 static uint32_t bsr_uniq = 0;
1484 * The Director sends us the bootstrap file, which
1485 * we will in turn pass to the SD.
1486 * Deprecated. The bsr is now sent directly from the
1487 * Director to the SD.
1489 static int bootstrap_cmd(JCR *jcr)
1491 BSOCK *dir = jcr->dir_bsock;
1492 POOLMEM *fname = get_pool_memory(PM_FNAME);
1495 free_bootstrap(jcr);
1498 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1499 jcr->Job, bsr_uniq);
1501 Dmsg1(400, "bootstrap=%s\n", fname);
1502 jcr->RestoreBootstrap = fname;
1503 bs = fopen(fname, "a+b"); /* create file */
1506 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1507 jcr->RestoreBootstrap, be.bstrerror());
1509 * Suck up what he is sending to us so that he will then
1510 * read our error message.
1512 while (dir->recv() >= 0)
1514 free_bootstrap(jcr);
1515 jcr->setJobStatus(JS_ErrorTerminated);
1519 while (dir->recv() >= 0) {
1520 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1521 fputs(dir->msg, bs);
1525 * Note, do not free the bootstrap yet -- it needs to be
1528 return dir->fsend(OKbootstrap);
1533 * Get backup level from Director
1536 static int level_cmd(JCR *jcr)
1538 BSOCK *dir = jcr->dir_bsock;
1539 POOLMEM *level, *buf = NULL;
1542 level = get_memory(dir->msglen+1);
1543 Dmsg1(10, "level_cmd: %s", dir->msg);
1545 /* keep compatibility with older directors */
1546 if (strstr(dir->msg, "accurate")) {
1547 jcr->accurate = true;
1549 if (strstr(dir->msg, "rerunning")) {
1550 jcr->rerunning = true;
1552 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1555 /* Base backup requested? */
1556 if (strcmp(level, "base") == 0) {
1557 jcr->setJobLevel(L_BASE);
1558 /* Full backup requested? */
1559 } else if (strcmp(level, "full") == 0) {
1560 jcr->setJobLevel(L_FULL);
1561 } else if (strstr(level, "differential")) {
1562 jcr->setJobLevel(L_DIFFERENTIAL);
1565 } else if (strstr(level, "incremental")) {
1566 jcr->setJobLevel(L_INCREMENTAL);
1570 * We get his UTC since time, then sync the clocks and correct it
1571 * to agree with our clock.
1573 } else if (strcmp(level, "since_utime") == 0) {
1574 buf = get_memory(dir->msglen+1);
1575 utime_t since_time, adj;
1576 btime_t his_time, bt_start, rt=0, bt_adj=0;
1577 if (jcr->getJobLevel() == L_NONE) {
1578 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1580 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1581 buf, &mtime_only) != 2) {
1584 since_time = str_to_uint64(buf); /* this is the since time */
1585 Dmsg1(100, "since_time=%lld\n", since_time);
1586 char ed1[50], ed2[50];
1588 * Sync clocks by polling him for the time. We take
1589 * 10 samples of his time throwing out the first two.
1591 for (int i=0; i<10; i++) {
1592 bt_start = get_current_btime();
1593 dir->signal(BNET_BTIME); /* poll for time */
1594 if (dir->recv() <= 0) { /* get response */
1597 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1600 if (i < 2) { /* toss first two results */
1603 his_time = str_to_uint64(buf);
1604 rt = get_current_btime() - bt_start; /* compute round trip time */
1605 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1606 edit_uint64(bt_start, ed2));
1607 bt_adj += bt_start - his_time - rt/2;
1608 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1611 bt_adj = bt_adj / 8; /* compute average time */
1612 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1613 adj = btime_to_utime(bt_adj);
1614 since_time += adj; /* adjust for clock difference */
1615 /* Don't notify if time within 3 seconds */
1616 if (adj > 3 || adj < -3) {
1618 if (adj > 600 || adj < -600) {
1623 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1625 dir->signal(BNET_EOD);
1627 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1628 jcr->incremental = 1; /* set incremental or decremental backup */
1629 jcr->mtime = since_time; /* set since time */
1630 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1632 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1640 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1641 return dir->fsend(OKlevel);
1644 pm_strcpy(jcr->errmsg, dir->msg);
1645 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1654 * Get session parameters from Director -- this is for a Restore command
1655 * This is deprecated. It is now passed via the bsr.
1657 static int session_cmd(JCR *jcr)
1659 BSOCK *dir = jcr->dir_bsock;
1661 Dmsg1(100, "SessionCmd: %s", dir->msg);
1662 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1663 &jcr->VolSessionId, &jcr->VolSessionTime,
1664 &jcr->StartFile, &jcr->EndFile,
1665 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1666 pm_strcpy(jcr->errmsg, dir->msg);
1667 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1671 return dir->fsend(OKsession);
1674 static void set_storage_auth_key(JCR *jcr, char *key)
1676 /* if no key don't update anything */
1682 * We can be contacting multiple storage daemons.
1683 * So, make sure that any old jcr->store_bsock is cleaned up.
1685 if (jcr->store_bsock) {
1686 jcr->store_bsock->destroy();
1687 jcr->store_bsock = NULL;
1691 * We can be contacting multiple storage daemons.
1692 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1694 if (jcr->sd_auth_key) {
1696 * If we already have a Authorization key, director can do multi
1699 Dmsg0(5, "set multi_restore=true\n");
1700 jcr->multi_restore = true;
1701 bfree(jcr->sd_auth_key);
1704 jcr->sd_auth_key = bstrdup(key);
1705 Dmsg0(5, "set sd auth key\n");
1709 * Get address of storage daemon from Director
1712 static int storage_cmd(JCR *jcr)
1714 int stored_port; /* storage daemon port */
1715 int enable_ssl; /* enable ssl to sd */
1716 POOL_MEM sd_auth_key(PM_MESSAGE);
1717 BSOCK *dir = jcr->dir_bsock;
1718 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1721 Dmsg1(100, "StorageCmd: %s", dir->msg);
1722 sd_auth_key.check_size(dir->msglen);
1723 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1724 &enable_ssl, sd_auth_key.c_str()) != 4) {
1725 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1726 &stored_port, &enable_ssl) != 3) {
1727 pm_strcpy(jcr->errmsg, dir->msg);
1728 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1733 set_storage_auth_key(jcr, sd_auth_key.c_str());
1735 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1737 /* Open command communications with Storage daemon */
1738 /* Try to connect for 1 hour at 10 second intervals */
1740 sd->set_source_address(me->FDsrc_addr);
1744 >>>>>>> caaa5db... Implement RestoreObject for sqlite + cleanups
1745 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1746 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1752 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1753 jcr->stored_addr, stored_port);
1754 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1755 jcr->stored_addr, stored_port);
1758 Dmsg0(110, "Connection OK to SD.\n");
1760 jcr->store_bsock = sd;
1762 sd->fsend("Hello Start Job %s\n", jcr->Job);
1763 if (!authenticate_storagedaemon(jcr)) {
1764 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1767 Dmsg0(110, "Authenticated with SD.\n");
1769 /* Send OK to Director */
1770 return dir->fsend(OKstore);
1773 dir->fsend(BADcmd, "storage");
1782 static int backup_cmd(JCR *jcr)
1784 BSOCK *dir = jcr->dir_bsock;
1785 BSOCK *sd = jcr->store_bsock;
1790 #if defined(WIN32_VSS)
1791 // capture state here, if client is backed up by multiple directors
1792 // and one enables vss and the other does not then enable_vss can change
1793 // between here and where its evaluated after the job completes.
1794 jcr->VSS = g_pVSSClient && enable_vss;
1796 /* Run only one at a time */
1801 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1802 jcr->JobFiles = FileIndex;
1803 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1807 * Validate some options given to the backup make sense for the compiled in
1808 * options of this filed.
1810 if (jcr->ff->flags & FO_ACL && !have_acl) {
1811 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1814 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1815 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1819 jcr->setJobStatus(JS_Blocked);
1820 jcr->setJobType(JT_BACKUP);
1821 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1824 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1825 dir->fsend(BADcmd, "backup");
1829 dir->fsend(OKbackup);
1830 Dmsg1(110, "filed>dird: %s", dir->msg);
1833 * Send Append Open Session to Storage daemon
1835 sd->fsend(append_open);
1836 Dmsg1(110, ">stored: %s", sd->msg);
1838 * Expect to receive back the Ticket number
1840 if (bget_msg(sd) >= 0) {
1841 Dmsg1(110, "<stored: %s", sd->msg);
1842 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1843 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1846 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1848 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1853 * Send Append data command to Storage daemon
1855 sd->fsend(append_data, jcr->Ticket);
1856 Dmsg1(110, ">stored: %s", sd->msg);
1859 * Expect to get OK data
1861 Dmsg1(110, "<stored: %s", sd->msg);
1862 if (!response(jcr, sd, OK_data, "Append Data")) {
1866 generate_daemon_event(jcr, "JobStart");
1867 generate_plugin_event(jcr, bEventStartBackupJob);
1869 #if defined(WIN32_VSS)
1870 /* START VSS ON WIN32 */
1872 if (g_pVSSClient->InitializeForBackup(jcr)) {
1873 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1874 /* tell vss which drives to snapshot */
1875 char szWinDriveLetters[27];
1876 *szWinDriveLetters=0;
1877 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1878 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1879 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1880 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1882 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1884 /* tell user if snapshot creation of a specific drive failed */
1886 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1887 if (islower(szWinDriveLetters[i])) {
1888 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1891 /* inform user about writer states */
1892 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1893 if (g_pVSSClient->GetWriterState(i) < 1) {
1894 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1899 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1903 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"), be.bstrerror());
1905 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1910 * Send Files to Storage daemon
1912 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1913 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1914 jcr->setJobStatus(JS_ErrorTerminated);
1915 bnet_suppress_error_messages(sd, 1);
1916 Dmsg0(110, "Error in blast_data.\n");
1918 jcr->setJobStatus(JS_Terminated);
1919 /* Note, the above set status will not override an error */
1920 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1921 bnet_suppress_error_messages(sd, 1);
1922 goto cleanup; /* bail out now */
1925 * Expect to get response to append_data from Storage daemon
1927 if (!response(jcr, sd, OK_append, "Append Data")) {
1928 jcr->setJobStatus(JS_ErrorTerminated);
1933 * Send Append End Data to Storage daemon
1935 sd->fsend(append_end, jcr->Ticket);
1937 if (!response(jcr, sd, OK_end, "Append End")) {
1938 jcr->setJobStatus(JS_ErrorTerminated);
1943 * Send Append Close to Storage daemon
1945 sd->fsend(append_close, jcr->Ticket);
1946 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1947 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1949 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1953 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1956 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1957 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1963 #if defined(WIN32_VSS)
1965 Win32ConvCleanupCache();
1966 g_pVSSClient->DestroyWriterInfo();
1971 generate_plugin_event(jcr, bEventEndBackupJob);
1972 return 0; /* return and stop command loop */
1976 * Do a Verify for Director
1979 static int verify_cmd(JCR *jcr)
1981 BSOCK *dir = jcr->dir_bsock;
1982 BSOCK *sd = jcr->store_bsock;
1985 jcr->setJobType(JT_VERIFY);
1986 if (sscanf(dir->msg, verifycmd, level) != 1) {
1987 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1991 if (strcasecmp(level, "init") == 0) {
1992 jcr->setJobLevel(L_VERIFY_INIT);
1993 } else if (strcasecmp(level, "catalog") == 0){
1994 jcr->setJobLevel(L_VERIFY_CATALOG);
1995 } else if (strcasecmp(level, "volume") == 0){
1996 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1997 } else if (strcasecmp(level, "data") == 0){
1998 jcr->setJobLevel(L_VERIFY_DATA);
1999 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2000 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2002 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2006 dir->fsend(OKverify);
2008 generate_daemon_event(jcr, "JobStart");
2009 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2010 generate_plugin_event(jcr, bEventStartVerifyJob);
2012 Dmsg1(110, "filed>dird: %s", dir->msg);
2014 switch (jcr->getJobLevel()) {
2016 case L_VERIFY_CATALOG:
2019 case L_VERIFY_VOLUME_TO_CATALOG:
2020 if (!open_sd_read_session(jcr)) {
2023 start_dir_heartbeat(jcr);
2024 do_verify_volume(jcr);
2025 stop_dir_heartbeat(jcr);
2027 * Send Close session command to Storage daemon
2029 sd->fsend(read_close, jcr->Ticket);
2030 Dmsg1(130, "filed>stored: %s", sd->msg);
2032 /* ****FIXME**** check response */
2033 bget_msg(sd); /* get OK */
2035 /* Inform Storage daemon that we are done */
2036 sd->signal(BNET_TERMINATE);
2039 case L_VERIFY_DISK_TO_CATALOG:
2043 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2047 dir->signal(BNET_EOD);
2048 generate_plugin_event(jcr, bEventEndVerifyJob);
2049 return 0; /* return and terminate command loop */
2053 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2055 switch (init_type) {
2056 case VSS_INIT_RESTORE_AFTER_INIT:
2057 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2059 case VSS_INIT_RESTORE_AFTER_GATHER:
2060 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2070 * Do a Restore for Director
2073 static int restore_cmd(JCR *jcr)
2075 BSOCK *dir = jcr->dir_bsock;
2076 BSOCK *sd = jcr->store_bsock;
2078 bool use_regexwhere=false;
2083 * Scan WHERE (base directory for restore) from command
2085 Dmsg0(100, "restore command\n");
2086 #if defined(WIN32_VSS)
2089 * No need to enable VSS for restore if we do not have plugin
2092 enable_vss = jcr->job_metadata != NULL;
2094 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2095 // capture state here, if client is backed up by multiple directors
2096 // and one enables vss and the other does not then enable_vss can change
2097 // between here and where its evaluated after the job completes.
2098 jcr->VSS = g_pVSSClient && enable_vss;
2100 /* Run only one at a time */
2104 /* Pickup where string */
2105 args = get_memory(dir->msglen+1);
2108 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2109 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2110 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2111 pm_strcpy(jcr->errmsg, dir->msg);
2112 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2117 use_regexwhere = true;
2119 /* Turn / into nothing */
2120 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2124 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2125 unbash_spaces(args);
2127 if (use_regexwhere) {
2128 jcr->where_bregexp = get_bregexps(args);
2129 if (!jcr->where_bregexp) {
2130 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2131 free_pool_memory(args);
2135 jcr->where = bstrdup(args);
2138 free_pool_memory(args);
2139 jcr->replace = replace;
2140 jcr->prefix_links = prefix_links;
2142 dir->fsend(OKrestore);
2143 Dmsg1(110, "filed>dird: %s", dir->msg);
2145 jcr->setJobType(JT_RESTORE);
2147 jcr->setJobStatus(JS_Blocked);
2149 if (!open_sd_read_session(jcr)) {
2150 jcr->setJobStatus(JS_ErrorTerminated);
2154 jcr->setJobStatus(JS_Running);
2157 * Do restore of files and data
2159 start_dir_heartbeat(jcr);
2160 generate_daemon_event(jcr, "JobStart");
2161 generate_plugin_event(jcr, bEventStartRestoreJob);
2163 #if defined(WIN32_VSS)
2164 /* START VSS ON WIN32 */
2166 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2167 (WCHAR *)jcr->job_metadata)) {
2169 /* inform user about writer states */
2171 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2172 if (g_pVSSClient->GetWriterState(i) < 1) {
2173 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2179 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2180 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2184 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2186 free_and_null_pool_memory(jcr->job_metadata);
2187 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2192 stop_dir_heartbeat(jcr);
2194 jcr->setJobStatus(JS_Terminated);
2195 if (jcr->JobStatus != JS_Terminated) {
2196 bnet_suppress_error_messages(sd, 1);
2200 * Send Close session command to Storage daemon
2202 sd->fsend(read_close, jcr->Ticket);
2203 Dmsg1(100, "filed>stored: %s", sd->msg);
2205 bget_msg(sd); /* get OK */
2207 /* Inform Storage daemon that we are done */
2208 sd->signal(BNET_TERMINATE);
2210 #if defined(WIN32_VSS)
2211 /* STOP VSS ON WIN32 */
2212 /* tell vss to close the restore session */
2213 Dmsg0(100, "About to call CloseRestore\n");
2215 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2216 Dmsg0(100, "Really about to call CloseRestore\n");
2217 if (g_pVSSClient->CloseRestore()) {
2218 Dmsg0(100, "CloseRestore success\n");
2219 /* inform user about writer states */
2220 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2221 int msg_type = M_INFO;
2222 if (g_pVSSClient->GetWriterState(i) < 1) {
2223 //msg_type = M_WARNING;
2226 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2230 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2236 bfree_and_null(jcr->where);
2238 if (jcr->JobErrors) {
2239 jcr->setJobStatus(JS_ErrorTerminated);
2242 Dmsg0(100, "Done in job.c\n");
2245 if (jcr->multi_restore) {
2246 Dmsg0(100, OKstoreend);
2247 dir->fsend(OKstoreend);
2248 ret = 1; /* we continue the loop, waiting for next part */
2250 end_restore_cmd(jcr);
2251 ret = 0; /* we stop here */
2254 if (job_canceled(jcr)) {
2255 ret = 0; /* we stop here */
2261 static int end_restore_cmd(JCR *jcr)
2263 Dmsg0(5, "end_restore_cmd\n");
2264 generate_plugin_event(jcr, bEventEndRestoreJob);
2265 return 0; /* return and terminate command loop */
2268 static int open_sd_read_session(JCR *jcr)
2270 BSOCK *sd = jcr->store_bsock;
2273 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2276 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2277 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2278 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2280 * Open Read Session with Storage daemon
2282 sd->fsend(read_open, "DummyVolume",
2283 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2284 jcr->StartBlock, jcr->EndBlock);
2285 Dmsg1(110, ">stored: %s", sd->msg);
2290 if (bget_msg(sd) >= 0) {
2291 Dmsg1(110, "filed<stored: %s", sd->msg);
2292 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2293 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2296 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2298 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2302 if (!send_bootstrap_file(jcr)) {
2307 * Start read of data with Storage daemon
2309 sd->fsend(read_data, jcr->Ticket);
2310 Dmsg1(110, ">stored: %s", sd->msg);
2315 if (!response(jcr, sd, OK_data, "Read Data")) {
2322 * Destroy the Job Control Record and associated
2323 * resources (sockets).
2325 static void filed_free_jcr(JCR *jcr)
2327 if (jcr->store_bsock) {
2328 jcr->store_bsock->close();
2330 free_bootstrap(jcr);
2331 if (jcr->last_fname) {
2332 free_pool_memory(jcr->last_fname);
2334 free_runscripts(jcr->RunScripts);
2335 delete jcr->RunScripts;
2337 if (jcr->JobId != 0)
2338 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2344 * Get response from Storage daemon to a command we
2345 * sent. Check that the response is OK.
2347 * Returns: 0 on failure
2350 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2355 if (bget_msg(sd) > 0) {
2356 Dmsg0(110, sd->msg);
2357 if (strcmp(sd->msg, resp) == 0) {
2361 if (job_canceled(jcr)) {
2362 return 0; /* if canceled avoid useless error messages */
2364 if (is_bnet_error(sd)) {
2365 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2366 cmd, bnet_strerror(sd));
2368 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2369 cmd, resp, sd->msg);
2374 static int send_bootstrap_file(JCR *jcr)
2378 BSOCK *sd = jcr->store_bsock;
2379 const char *bootstrap = "bootstrap\n";
2382 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2383 if (!jcr->RestoreBootstrap) {
2386 bs = fopen(jcr->RestoreBootstrap, "rb");
2389 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2390 jcr->RestoreBootstrap, be.bstrerror());
2391 jcr->setJobStatus(JS_ErrorTerminated);
2394 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2396 while (fgets(buf, sizeof(buf), bs)) {
2397 sd->msglen = Mmsg(sd->msg, "%s", buf);
2400 sd->signal(BNET_EOD);
2402 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2403 jcr->setJobStatus(JS_ErrorTerminated);
2409 free_bootstrap(jcr);