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
38 #if defined(WIN32_VSS)
41 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int enable_vss = 0;
46 * As Windows saves ACLs as part of the standard backup stream
47 * we just pretend here that is has implicit acl support.
49 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
50 const bool have_acl = true;
52 const bool have_acl = false;
55 #if defined(HAVE_XATTR)
56 const bool have_xattr = true;
58 const bool have_xattr = false;
61 extern CLIENT *me; /* our client resource */
63 /* Imported functions */
64 extern int status_cmd(JCR *jcr);
65 extern int qstatus_cmd(JCR *jcr);
66 extern int accurate_cmd(JCR *jcr);
68 /* Forward referenced functions */
69 static int backup_cmd(JCR *jcr);
70 static int bootstrap_cmd(JCR *jcr);
71 static int cancel_cmd(JCR *jcr);
72 static int setdebug_cmd(JCR *jcr);
73 static int estimate_cmd(JCR *jcr);
74 static int hello_cmd(JCR *jcr);
75 static int job_cmd(JCR *jcr);
76 static int fileset_cmd(JCR *jcr);
77 static int level_cmd(JCR *jcr);
78 static int verify_cmd(JCR *jcr);
79 static int restore_cmd(JCR *jcr);
80 static int end_restore_cmd(JCR *jcr);
81 static int storage_cmd(JCR *jcr);
82 static int session_cmd(JCR *jcr);
83 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
84 static void filed_free_jcr(JCR *jcr);
85 static int open_sd_read_session(JCR *jcr);
86 static int send_bootstrap_file(JCR *jcr);
87 static int runscript_cmd(JCR *jcr);
88 static int runbefore_cmd(JCR *jcr);
89 static int runafter_cmd(JCR *jcr);
90 static int runbeforenow_cmd(JCR *jcr);
91 static int restore_object_cmd(JCR *jcr);
92 static int set_options(findFOPTS *fo, const char *opts);
93 static void set_storage_auth_key(JCR *jcr, char *key);
94 static int sm_dump_cmd(JCR *jcr);
96 static int exit_cmd(JCR *jcr);
99 /* Exported functions */
104 int monitoraccess; /* specify if monitors have access to this function */
108 * The following are the recognized commands from the Director.
110 static struct s_cmds cmds[] = {
111 {"backup", backup_cmd, 0},
112 {"cancel", cancel_cmd, 0},
113 {"setdebug=", setdebug_cmd, 0},
114 {"estimate", estimate_cmd, 0},
115 {"Hello", hello_cmd, 1},
116 {"fileset", fileset_cmd, 0},
117 {"JobId=", job_cmd, 0},
118 {"level = ", level_cmd, 0},
119 {"restore ", restore_cmd, 0},
120 {"endrestore", end_restore_cmd, 0},
121 {"session", session_cmd, 0},
122 {"status", status_cmd, 1},
123 {".status", qstatus_cmd, 1},
124 {"storage ", storage_cmd, 0},
125 {"verify", verify_cmd, 0},
126 {"bootstrap", bootstrap_cmd, 0},
127 {"RunBeforeNow", runbeforenow_cmd, 0},
128 {"RunBeforeJob", runbefore_cmd, 0},
129 {"RunAfterJob", runafter_cmd, 0},
130 {"Run", runscript_cmd, 0},
131 {"accurate", accurate_cmd, 0},
132 {"restoreobject", restore_object_cmd, 0},
133 {"sm_dump", sm_dump_cmd, 0},
135 {"exit", exit_cmd, 0},
137 {NULL, NULL} /* list terminator */
140 /* Commands received from director that need scanning */
141 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
142 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
143 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
144 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
145 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
146 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
147 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
148 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
149 static char endrestoreobjectcmd[] = "restoreobject end\n";
150 static char verifycmd[] = "verify level=%30s";
151 static char estimatecmd[] = "estimate listing=%d";
152 static char runbefore[] = "RunBeforeJob %s";
153 static char runafter[] = "RunAfterJob %s";
154 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
156 /* Responses sent to Director */
157 static char errmsg[] = "2999 Invalid command\n";
158 static char no_auth[] = "2998 No Authorization\n";
159 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
160 static char OKinc[] = "2000 OK include\n";
161 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
162 static char OKlevel[] = "2000 OK level\n";
163 static char OKbackup[] = "2000 OK backup\n";
164 static char OKbootstrap[] = "2000 OK bootstrap\n";
165 static char OKverify[] = "2000 OK verify\n";
166 static char OKrestore[] = "2000 OK restore\n";
167 static char OKsession[] = "2000 OK session\n";
168 static char OKstore[] = "2000 OK storage\n";
169 static char OKstoreend[] = "2000 OK storage end\n";
170 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
171 static char OKsetdebug[] = "2000 OK setdebug=%d trace=%d hangup=%d\n";
172 static char BADjob[] = "2901 Bad Job\n";
173 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
174 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
175 static char OKRunBefore[] = "2000 OK RunBefore\n";
176 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
177 static char OKRunAfter[] = "2000 OK RunAfter\n";
178 static char OKRunScript[] = "2000 OK RunScript\n";
179 static char BADcmd[] = "2902 Bad %s\n";
180 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
183 /* Responses received from Storage Daemon */
184 static char OK_end[] = "3000 OK end\n";
185 static char OK_close[] = "3000 OK close Status = %d\n";
186 static char OK_open[] = "3000 OK open ticket = %d\n";
187 static char OK_data[] = "3000 OK data\n";
188 static char OK_append[] = "3000 OK append data\n";
189 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
192 /* Commands sent to Storage Daemon */
193 static char append_open[] = "append open session\n";
194 static char append_data[] = "append data %d\n";
195 static char append_end[] = "append end session %d\n";
196 static char append_close[] = "append close session %d\n";
197 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
198 static char read_data[] = "read data %d\n";
199 static char read_close[] = "read close session %d\n";
202 * Accept requests from a Director
204 * NOTE! We are running as a separate thread
206 * Send output one line
207 * at a time followed by a zero length transmission.
209 * Return when the connection is terminated or there
212 * Basic task here is:
213 * Authenticate Director (during Hello command).
214 * Accept commands one at a time from the Director
217 * Concerning ClientRunBefore/After, the sequence of events
218 * is rather critical. If they are not done in the right
219 * order one can easily get FD->SD timeouts if the script
222 * The current sequence of events is:
223 * 1. Dir starts job with FD
224 * 2. Dir connects to SD
225 * 3. Dir connects to FD
226 * 4. FD connects to SD
227 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
228 * 6. Dir sends include/exclude
229 * 7. FD sends data to SD
230 * 8. SD/FD disconnects while SD despools data and attributes (optional)
231 * 9. FD runs ClientRunAfterJob
234 void *handle_client_request(void *dirp)
239 BSOCK *dir = (BSOCK *)dirp;
240 const char jobname[12] = "*Director*";
243 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
244 jcr->dir_bsock = dir;
245 jcr->ff = init_find_files();
246 // save_cwd.save(jcr);
247 jcr->start_time = time(NULL);
248 jcr->RunScripts = New(alist(10, not_owned_by_alist));
249 jcr->last_fname = get_pool_memory(PM_FNAME);
250 jcr->last_fname[0] = 0;
251 jcr->client_name = get_memory(strlen(my_name) + 1);
252 pm_strcpy(jcr->client_name, my_name);
253 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
254 jcr->crypto.pki_sign = me->pki_sign;
255 jcr->crypto.pki_encrypt = me->pki_encrypt;
256 jcr->crypto.pki_keypair = me->pki_keypair;
257 jcr->crypto.pki_signers = me->pki_signers;
258 jcr->crypto.pki_recipients = me->pki_recipients;
260 enable_backup_privileges(NULL, 1 /* ignore_errors */);
262 /**********FIXME******* add command handler error code */
264 for (quit=false; !quit;) {
266 if (dir->recv() < 0) {
267 break; /* connection terminated */
269 dir->msg[dir->msglen] = 0;
270 Dmsg1(100, "<dird: %s", dir->msg);
272 for (i=0; cmds[i].cmd; i++) {
273 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
274 found = true; /* indicate command found */
275 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
277 dir->signal(BNET_EOD);
280 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
281 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
282 dir->fsend(invalid_cmd);
283 dir->signal(BNET_EOD);
286 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
287 if (!cmds[i].func(jcr)) { /* do command */
288 quit = true; /* error or fully terminated, get out */
289 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
294 if (!found) { /* command not found */
301 /* Inform Storage daemon that we are done */
302 if (jcr->store_bsock) {
303 jcr->store_bsock->signal(BNET_TERMINATE);
306 /* Run the after job */
307 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
309 if (jcr->JobId) { /* send EndJob if running a job */
310 char ed1[50], ed2[50];
311 /* Send termination status back to Dir */
312 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
313 edit_uint64(jcr->ReadBytes, ed1),
314 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
315 jcr->crypto.pki_encrypt);
316 Dmsg1(110, "End FD msg: %s\n", dir->msg);
319 generate_daemon_event(jcr, "JobEnd");
320 generate_plugin_event(jcr, bEventJobEnd);
322 dequeue_messages(jcr); /* send any queued messages */
324 /* Inform Director that we are done */
325 dir->signal(BNET_TERMINATE);
327 free_plugins(jcr); /* release instantiated plugins */
328 free_and_null_pool_memory(jcr->job_metadata);
330 /* Clean up fileset */
331 FF_PKT *ff = jcr->ff;
332 findFILESET *fileset = ff->fileset;
335 /* Delete FileSet Include lists */
336 for (i=0; i<fileset->include_list.size(); i++) {
337 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
338 for (j=0; j<incexe->opts_list.size(); j++) {
339 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
340 for (k=0; k<fo->regex.size(); k++) {
341 regfree((regex_t *)fo->regex.get(k));
343 for (k=0; k<fo->regexdir.size(); k++) {
344 regfree((regex_t *)fo->regexdir.get(k));
346 for (k=0; k<fo->regexfile.size(); k++) {
347 regfree((regex_t *)fo->regexfile.get(k));
350 fo->regexdir.destroy();
351 fo->regexfile.destroy();
353 fo->wilddir.destroy();
354 fo->wildfile.destroy();
355 fo->wildbase.destroy();
357 fo->fstype.destroy();
358 fo->drivetype.destroy();
360 incexe->opts_list.destroy();
361 incexe->name_list.destroy();
362 incexe->plugin_list.destroy();
363 if (incexe->ignoredir) {
364 free(incexe->ignoredir);
367 fileset->include_list.destroy();
369 /* Delete FileSet Exclude lists */
370 for (i=0; i<fileset->exclude_list.size(); i++) {
371 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
372 for (j=0; j<incexe->opts_list.size(); j++) {
373 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
375 fo->regexdir.destroy();
376 fo->regexfile.destroy();
378 fo->wilddir.destroy();
379 fo->wildfile.destroy();
380 fo->wildbase.destroy();
382 fo->fstype.destroy();
383 fo->drivetype.destroy();
385 incexe->opts_list.destroy();
386 incexe->name_list.destroy();
387 incexe->plugin_list.destroy();
388 if (incexe->ignoredir) {
389 free(incexe->ignoredir);
392 fileset->exclude_list.destroy();
396 Dmsg0(100, "Calling term_find_files\n");
397 term_find_files(jcr->ff);
398 // save_cwd.restore(jcr);
399 // save_cwd.release();
401 Dmsg0(100, "Done with term_find_files\n");
402 free_jcr(jcr); /* destroy JCR record */
403 Dmsg0(100, "Done with free_jcr\n");
405 garbage_collect_memory_pool();
409 static int sm_dump_cmd(JCR *jcr)
412 sm_dump(false, true);
413 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
418 static int exit_cmd(JCR *jcr)
420 jcr->dir_bsock->fsend("2000 exit OK\n");
428 * Hello from Director he must identify himself and provide his
431 static int hello_cmd(JCR *jcr)
433 Dmsg0(120, "Calling Authenticate\n");
434 if (!authenticate_director(jcr)) {
437 Dmsg0(120, "OK Authenticate\n");
438 jcr->authenticated = true;
445 static int cancel_cmd(JCR *jcr)
447 BSOCK *dir = jcr->dir_bsock;
448 char Job[MAX_NAME_LENGTH];
451 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
452 if (!(cjcr=get_jcr_by_full_name(Job))) {
453 dir->fsend(_("2901 Job %s not found.\n"), Job);
455 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
456 set_jcr_job_status(cjcr, JS_Canceled);
457 if (cjcr->store_bsock) {
458 cjcr->store_bsock->set_timed_out();
459 cjcr->store_bsock->set_terminated();
460 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
463 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
466 dir->fsend(_("2902 Error scanning cancel command.\n"));
468 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);
546 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
549 static int runbefore_cmd(JCR *jcr)
552 BSOCK *dir = jcr->dir_bsock;
553 POOLMEM *cmd = get_memory(dir->msglen+1);
556 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
557 if (sscanf(dir->msg, runbefore, cmd) != 1) {
558 pm_strcpy(jcr->errmsg, dir->msg);
559 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
560 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
566 /* Run the command now */
567 script = new_runscript();
568 script->set_command(cmd);
569 script->when = SCRIPT_Before;
570 ok = script->run(jcr, "ClientRunBeforeJob");
571 free_runscript(script);
575 dir->fsend(OKRunBefore);
578 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
583 static int runbeforenow_cmd(JCR *jcr)
585 BSOCK *dir = jcr->dir_bsock;
587 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
588 if (job_canceled(jcr)) {
589 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
590 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
593 dir->fsend(OKRunBeforeNow);
594 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
599 static int runafter_cmd(JCR *jcr)
601 BSOCK *dir = jcr->dir_bsock;
602 POOLMEM *msg = get_memory(dir->msglen+1);
605 Dmsg1(100, "runafter_cmd: %s", dir->msg);
606 if (sscanf(dir->msg, runafter, msg) != 1) {
607 pm_strcpy(jcr->errmsg, dir->msg);
608 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
609 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
615 cmd = new_runscript();
616 cmd->set_command(msg);
617 cmd->on_success = true;
618 cmd->on_failure = false;
619 cmd->when = SCRIPT_After;
621 jcr->RunScripts->append(cmd);
623 free_pool_memory(msg);
624 return dir->fsend(OKRunAfter);
627 static int runscript_cmd(JCR *jcr)
629 BSOCK *dir = jcr->dir_bsock;
630 POOLMEM *msg = get_memory(dir->msglen+1);
631 int on_success, on_failure, fail_on_error;
633 RUNSCRIPT *cmd = new_runscript() ;
635 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
636 /* Note, we cannot sscanf into bools */
637 if (sscanf(dir->msg, runscript, &on_success,
642 pm_strcpy(jcr->errmsg, dir->msg);
643 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
644 dir->fsend(_("2905 Bad RunScript command.\n"));
649 cmd->on_success = on_success;
650 cmd->on_failure = on_failure;
651 cmd->fail_on_error = fail_on_error;
654 cmd->set_command(msg);
656 jcr->RunScripts->append(cmd);
658 free_pool_memory(msg);
659 return dir->fsend(OKRunScript);
663 * This reads data sent from the Director from the
664 * RestoreObject table that allows us to get objects
665 * that were backed up (VSS .xml data) and are needed
666 * before starting the restore.
668 static int restore_object_cmd(JCR *jcr)
670 BSOCK *dir = jcr->dir_bsock;
672 restore_object_pkt rop;
674 memset(&rop, 0, sizeof(rop));
675 rop.pkt_size = sizeof(rop);
676 rop.pkt_end = sizeof(rop);
677 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
678 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
679 generate_plugin_event(jcr, bEventRestoreObject, NULL);
680 return dir->fsend(OKRestoreObject);
683 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
684 &rop.object_full_len, &rop.object_index,
685 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
686 Dmsg0(5, "Bad restore object command\n");
687 pm_strcpy(jcr->errmsg, dir->msg);
688 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
692 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
693 rop.JobId, rop.object_len, rop.object_full_len,
694 rop.object_index, rop.object_type, FileIndex);
695 /* Read Object name */
696 if (dir->recv() < 0) {
699 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
700 rop.object_name = bstrdup(dir->msg);
703 if (dir->recv() < 0) {
706 /* Transfer object from message buffer, and get new message buffer */
707 rop.object = dir->msg;
708 dir->msg = get_pool_memory(PM_MESSAGE);
710 /* If object is compressed, uncompress it */
711 if (rop.object_compression == 1) { /* zlib level 9 */
713 int out_len = rop.object_full_len + 100;
714 POOLMEM *obj = get_memory(out_len);
715 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
716 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
717 Dmsg1(100, "Zinflate stat=%d\n", stat);
718 if (out_len != rop.object_full_len) {
719 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
720 rop.object_full_len, out_len, rop.object_name);
722 free_pool_memory(rop.object); /* release compressed object */
723 rop.object = obj; /* new uncompressed object */
724 rop.object_len = out_len;
726 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
727 /* Special Job meta data */
728 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
729 Dmsg0(100, "got job metadata\n");
730 free_and_null_pool_memory(jcr->job_metadata);
731 jcr->job_metadata = rop.object;
735 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
738 if (rop.object_name) {
739 free(rop.object_name);
742 free_pool_memory(rop.object);
745 Dmsg1(100, "Send: %s", OKRestoreObject);
749 dir->fsend(_("2909 Bad RestoreObject command.\n"));
755 static bool init_fileset(JCR *jcr)
758 findFILESET *fileset;
767 fileset = (findFILESET *)malloc(sizeof(findFILESET));
768 memset(fileset, 0, sizeof(findFILESET));
769 ff->fileset = fileset;
770 fileset->state = state_none;
771 fileset->include_list.init(1, true);
772 fileset->exclude_list.init(1, true);
776 static void append_file(JCR *jcr, findINCEXE *incexe,
777 const char *buf, bool is_file)
780 incexe->name_list.append(new_dlistString(buf));
782 } else if (me->plugin_directory) {
783 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
784 incexe->plugin_list.append(new_dlistString(buf));
787 Jmsg(jcr, M_FATAL, 0,
788 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
794 * Add fname to include/exclude fileset list. First check for
795 * | and < and if necessary perform command.
797 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
799 findFILESET *fileset = jcr->ff->fileset;
812 p++; /* skip over | */
813 fn = get_pool_memory(PM_FNAME);
814 fn = edit_job_codes(jcr, fn, p, "");
815 bpipe = open_bpipe(fn, 0, "r");
818 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
820 free_pool_memory(fn);
823 free_pool_memory(fn);
824 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
825 strip_trailing_junk(buf);
826 append_file(jcr, fileset->incexe, buf, is_file);
828 if ((stat=close_bpipe(bpipe)) != 0) {
830 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
831 p, be.code(stat), be.bstrerror(stat));
836 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
837 p++; /* skip over < */
838 if ((ffd = fopen(p, "rb")) == NULL) {
840 Jmsg(jcr, M_FATAL, 0,
841 _("Cannot open FileSet input file: %s. ERR=%s\n"),
845 while (fgets(buf, sizeof(buf), ffd)) {
846 strip_trailing_junk(buf);
847 append_file(jcr, fileset->incexe, buf, is_file);
852 append_file(jcr, fileset->incexe, fname, is_file);
857 void set_incexe(JCR *jcr, findINCEXE *incexe)
859 findFILESET *fileset = jcr->ff->fileset;
860 fileset->incexe = incexe;
865 * Define a new Exclude block in the FileSet
867 findINCEXE *new_exclude(JCR *jcr)
869 findFILESET *fileset = jcr->ff->fileset;
872 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
873 memset(fileset->incexe, 0, sizeof(findINCEXE));
874 fileset->incexe->opts_list.init(1, true);
875 fileset->incexe->name_list.init();
876 fileset->incexe->plugin_list.init();
877 fileset->exclude_list.append(fileset->incexe);
878 return fileset->incexe;
882 * Define a new Include block in the FileSet
884 findINCEXE *new_include(JCR *jcr)
886 findFILESET *fileset = jcr->ff->fileset;
889 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
890 memset(fileset->incexe, 0, sizeof(findINCEXE));
891 fileset->incexe->opts_list.init(1, true);
892 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
893 fileset->incexe->plugin_list.init();
894 fileset->include_list.append(fileset->incexe);
895 return fileset->incexe;
899 * Define a new preInclude block in the FileSet
900 * That is the include is prepended to the other
901 * Includes. This is used for plugin exclusions.
903 findINCEXE *new_preinclude(JCR *jcr)
905 findFILESET *fileset = jcr->ff->fileset;
907 /* New pre-include */
908 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
909 memset(fileset->incexe, 0, sizeof(findINCEXE));
910 fileset->incexe->opts_list.init(1, true);
911 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
912 fileset->incexe->plugin_list.init();
913 fileset->include_list.prepend(fileset->incexe);
914 return fileset->incexe;
917 static findFOPTS *start_options(FF_PKT *ff)
919 int state = ff->fileset->state;
920 findINCEXE *incexe = ff->fileset->incexe;
922 if (state != state_options) {
923 ff->fileset->state = state_options;
924 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
925 memset(fo, 0, sizeof(findFOPTS));
926 fo->regex.init(1, true);
927 fo->regexdir.init(1, true);
928 fo->regexfile.init(1, true);
929 fo->wild.init(1, true);
930 fo->wilddir.init(1, true);
931 fo->wildfile.init(1, true);
932 fo->wildbase.init(1, true);
933 fo->base.init(1, true);
934 fo->fstype.init(1, true);
935 fo->drivetype.init(1, true);
936 incexe->current_opts = fo;
937 incexe->opts_list.append(fo);
939 return incexe->current_opts;
943 * Used by plugins to define a new options block
945 void new_options(JCR *jcr, findINCEXE *incexe)
948 incexe = jcr->ff->fileset->incexe;
950 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
951 memset(fo, 0, sizeof(findFOPTS));
952 fo->regex.init(1, true);
953 fo->regexdir.init(1, true);
954 fo->regexfile.init(1, true);
955 fo->wild.init(1, true);
956 fo->wilddir.init(1, true);
957 fo->wildfile.init(1, true);
958 fo->wildbase.init(1, true);
959 fo->base.init(1, true);
960 fo->fstype.init(1, true);
961 fo->drivetype.init(1, true);
962 incexe->current_opts = fo;
963 incexe->opts_list.prepend(fo);
964 jcr->ff->fileset->state = state_options;
968 * Add a regex to the current fileset
970 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
972 findFOPTS *current_opts = start_options(jcr->ff);
977 preg = (regex_t *)malloc(sizeof(regex_t));
978 if (current_opts->flags & FO_IGNORECASE) {
979 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
981 rc = regcomp(preg, item, REG_EXTENDED);
984 regerror(rc, preg, prbuf, sizeof(prbuf));
987 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
991 current_opts->regex.append(preg);
992 } else if (type == 'D') {
993 current_opts->regexdir.append(preg);
994 } else if (type == 'F') {
995 current_opts->regexfile.append(preg);
999 return state_options;
1003 * Add a wild card to the current fileset
1005 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1007 findFOPTS *current_opts = start_options(jcr->ff);
1010 current_opts->wild.append(bstrdup(item));
1011 } else if (type == 'D') {
1012 current_opts->wilddir.append(bstrdup(item));
1013 } else if (type == 'F') {
1014 current_opts->wildfile.append(bstrdup(item));
1015 } else if (type == 'B') {
1016 current_opts->wildbase.append(bstrdup(item));
1020 return state_options;
1025 * Add options to the current fileset
1027 int add_options_to_fileset(JCR *jcr, const char *item)
1029 findFOPTS *current_opts = start_options(jcr->ff);
1031 set_options(current_opts, item);
1032 return state_options;
1035 static void add_fileset(JCR *jcr, const char *item)
1037 FF_PKT *ff = jcr->ff;
1038 findFILESET *fileset = ff->fileset;
1039 int state = fileset->state;
1040 findFOPTS *current_opts;
1042 /* Get code, optional subcode, and position item past the dividing space */
1043 Dmsg1(100, "%s\n", item);
1048 int subcode = ' '; /* A space is always a valid subcode */
1049 if (item[0] != '\0' && item[0] != ' ') {
1057 /* Skip all lines we receive after an error */
1058 if (state == state_error) {
1059 Dmsg0(100, "State=error return\n");
1064 * The switch tests the code for validity.
1065 * The subcode is always good if it is a space, otherwise we must confirm.
1066 * We set state to state_error first assuming the subcode is invalid,
1067 * requiring state to be set in cases below that handle subcodes.
1069 if (subcode != ' ') {
1070 state = state_error;
1071 Dmsg0(100, "Set state=error or double code.\n");
1075 (void)new_include(jcr);
1078 (void)new_exclude(jcr);
1080 case 'N': /* null */
1083 case 'F': /* file = */
1084 /* File item to include or exclude list */
1085 state = state_include;
1086 add_file_to_fileset(jcr, item, true);
1088 case 'P': /* plugin */
1089 /* Plugin item to include list */
1090 state = state_include;
1091 add_file_to_fileset(jcr, item, false);
1093 case 'R': /* regex */
1094 state = add_regex_to_fileset(jcr, item, subcode);
1097 current_opts = start_options(ff);
1098 current_opts->base.append(bstrdup(item));
1099 state = state_options;
1101 case 'X': /* Filetype or Drive type */
1102 current_opts = start_options(ff);
1103 state = state_options;
1104 if (subcode == ' ') {
1105 current_opts->fstype.append(bstrdup(item));
1106 } else if (subcode == 'D') {
1107 current_opts->drivetype.append(bstrdup(item));
1109 state = state_error;
1112 case 'W': /* wild cards */
1113 state = add_wild_to_fileset(jcr, item, subcode);
1115 case 'O': /* Options */
1116 state = add_options_to_fileset(jcr, item);
1118 case 'Z': /* ignore dir */
1119 state = state_include;
1120 fileset->incexe->ignoredir = bstrdup(item);
1123 current_opts = start_options(ff);
1124 // current_opts->reader = bstrdup(item); /* deprecated */
1125 state = state_options;
1128 current_opts = start_options(ff);
1129 // current_opts->writer = bstrdup(item); /* deprecated */
1130 state = state_options;
1133 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1134 state = state_error;
1137 ff->fileset->state = state;
1140 static bool term_fileset(JCR *jcr)
1142 FF_PKT *ff = jcr->ff;
1144 #ifdef xxx_DEBUG_CODE
1145 findFILESET *fileset = ff->fileset;
1148 for (i=0; i<fileset->include_list.size(); i++) {
1149 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1151 for (j=0; j<incexe->opts_list.size(); j++) {
1152 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1153 for (k=0; k<fo->regex.size(); k++) {
1154 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1156 for (k=0; k<fo->regexdir.size(); k++) {
1157 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1159 for (k=0; k<fo->regexfile.size(); k++) {
1160 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1162 for (k=0; k<fo->wild.size(); k++) {
1163 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1165 for (k=0; k<fo->wilddir.size(); k++) {
1166 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1168 for (k=0; k<fo->wildfile.size(); k++) {
1169 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1171 for (k=0; k<fo->wildbase.size(); k++) {
1172 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1174 for (k=0; k<fo->base.size(); k++) {
1175 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1177 for (k=0; k<fo->fstype.size(); k++) {
1178 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1180 for (k=0; k<fo->drivetype.size(); k++) {
1181 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1184 if (incexe->ignoredir) {
1185 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1188 foreach_dlist(node, &incexe->name_list) {
1189 Dmsg1(400, "F %s\n", node->c_str());
1191 foreach_dlist(node, &incexe->plugin_list) {
1192 Dmsg1(400, "P %s\n", node->c_str());
1195 for (i=0; i<fileset->exclude_list.size(); i++) {
1196 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1198 for (j=0; j<incexe->opts_list.size(); j++) {
1199 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1200 for (k=0; k<fo->regex.size(); k++) {
1201 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1203 for (k=0; k<fo->regexdir.size(); k++) {
1204 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1206 for (k=0; k<fo->regexfile.size(); k++) {
1207 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1209 for (k=0; k<fo->wild.size(); k++) {
1210 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1212 for (k=0; k<fo->wilddir.size(); k++) {
1213 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1215 for (k=0; k<fo->wildfile.size(); k++) {
1216 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1218 for (k=0; k<fo->wildbase.size(); k++) {
1219 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1221 for (k=0; k<fo->base.size(); k++) {
1222 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1224 for (k=0; k<fo->fstype.size(); k++) {
1225 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1227 for (k=0; k<fo->drivetype.size(); k++) {
1228 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1232 foreach_dlist(node, incexe->name_list) {
1233 Dmsg1(400, "F %s\n", node->c_str());
1235 foreach_dlist(node, &incexe->plugin_list) {
1236 Dmsg1(400, "P %s\n", node->c_str());
1240 return ff->fileset->state != state_error;
1245 * As an optimization, we should do this during
1246 * "compile" time in filed/job.c, and keep only a bit mask
1247 * and the Verify options.
1249 static int set_options(findFOPTS *fo, const char *opts)
1255 // Commented out as it is not backward compatible - KES
1257 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1260 for (p=opts; *p; p++) {
1262 case 'a': /* alway replace */
1263 case '0': /* no option */
1266 fo->flags |= FO_EXCLUDE;
1269 fo->flags |= FO_MULTIFS;
1271 case 'h': /* no recursion */
1272 fo->flags |= FO_NO_RECURSION;
1274 case 'H': /* no hard link handling */
1275 fo->flags |= FO_NO_HARDLINK;
1278 fo->flags |= FO_IGNORECASE;
1281 fo->flags |= FO_MD5;
1284 fo->flags |= FO_NOREPLACE;
1286 case 'p': /* use portable data format */
1287 fo->flags |= FO_PORTABLE;
1289 case 'R': /* Resource forks and Finder Info */
1290 fo->flags |= FO_HFSPLUS;
1292 case 'r': /* read fifo */
1293 fo->flags |= FO_READFIFO;
1298 fo->flags |= FO_SHA1;
1303 fo->flags |= FO_SHA256;
1307 fo->flags |= FO_SHA512;
1313 * If 2 or 3 is seen here, SHA2 is not configured, so
1314 * eat the option, and drop back to SHA-1.
1316 if (p[1] == '2' || p[1] == '3') {
1319 fo->flags |= FO_SHA1;
1324 fo->flags |= FO_SPARSE;
1327 fo->flags |= FO_MTIMEONLY;
1330 fo->flags |= FO_KEEPATIME;
1333 fo->flags |= FO_ACL;
1335 case 'V': /* verify options */
1336 /* Copy Verify Options */
1337 for (j=0; *p && *p != ':'; p++) {
1338 fo->VerifyOpts[j] = *p;
1339 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1343 fo->VerifyOpts[j] = 0;
1345 case 'C': /* accurate options */
1346 /* Copy Accurate Options */
1347 for (j=0; *p && *p != ':'; p++) {
1348 fo->AccurateOpts[j] = *p;
1349 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1353 fo->AccurateOpts[j] = 0;
1355 case 'J': /* Basejob options */
1356 /* Copy BaseJob Options */
1357 for (j=0; *p && *p != ':'; p++) {
1358 fo->BaseJobOpts[j] = *p;
1359 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1363 fo->BaseJobOpts[j] = 0;
1365 case 'P': /* strip path */
1368 for (j=0; *p && *p != ':'; p++) {
1370 if (j < (int)sizeof(strip) - 1) {
1375 fo->strip_path = atoi(strip);
1376 fo->flags |= FO_STRIPPATH;
1377 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1380 fo->flags |= FO_IF_NEWER;
1383 fo->flags |= FO_ENHANCEDWILD;
1385 case 'Z': /* gzip compression */
1386 fo->flags |= FO_GZIP;
1387 fo->GZIP_level = *++p - '0';
1390 fo->flags |= FO_NOATIME;
1393 fo->flags |= FO_CHKCHANGES;
1396 fo->flags |= FO_HONOR_NODUMP;
1399 fo->flags |= FO_XATTR;
1402 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1406 return state_options;
1411 * Director is passing his Fileset
1413 static int fileset_cmd(JCR *jcr)
1415 BSOCK *dir = jcr->dir_bsock;
1418 #if defined(WIN32_VSS)
1421 sscanf(dir->msg, "fileset vss=%d", &vss);
1425 if (!init_fileset(jcr)) {
1428 while (dir->recv() >= 0) {
1429 strip_trailing_junk(dir->msg);
1430 Dmsg1(500, "Fileset: %s\n", dir->msg);
1431 add_fileset(jcr, dir->msg);
1433 if (!term_fileset(jcr)) {
1436 rtnstat = dir->fsend(OKinc);
1437 generate_plugin_event(jcr, bEventEndFileSet);
1441 static void free_bootstrap(JCR *jcr)
1443 if (jcr->RestoreBootstrap) {
1444 unlink(jcr->RestoreBootstrap);
1445 free_pool_memory(jcr->RestoreBootstrap);
1446 jcr->RestoreBootstrap = NULL;
1451 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1452 static uint32_t bsr_uniq = 0;
1455 * The Director sends us the bootstrap file, which
1456 * we will in turn pass to the SD.
1457 * Deprecated. The bsr is now sent directly from the
1458 * Director to the SD.
1460 static int bootstrap_cmd(JCR *jcr)
1462 BSOCK *dir = jcr->dir_bsock;
1463 POOLMEM *fname = get_pool_memory(PM_FNAME);
1466 free_bootstrap(jcr);
1469 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1470 jcr->Job, bsr_uniq);
1472 Dmsg1(400, "bootstrap=%s\n", fname);
1473 jcr->RestoreBootstrap = fname;
1474 bs = fopen(fname, "a+b"); /* create file */
1477 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1478 jcr->RestoreBootstrap, be.bstrerror());
1480 * Suck up what he is sending to us so that he will then
1481 * read our error message.
1483 while (dir->recv() >= 0)
1485 free_bootstrap(jcr);
1486 set_jcr_job_status(jcr, JS_ErrorTerminated);
1490 while (dir->recv() >= 0) {
1491 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1492 fputs(dir->msg, bs);
1496 * Note, do not free the bootstrap yet -- it needs to be
1499 return dir->fsend(OKbootstrap);
1504 * Get backup level from Director
1507 static int level_cmd(JCR *jcr)
1509 BSOCK *dir = jcr->dir_bsock;
1510 POOLMEM *level, *buf = NULL;
1513 level = get_memory(dir->msglen+1);
1514 Dmsg1(10, "level_cmd: %s", dir->msg);
1516 /* keep compatibility with older directors */
1517 if (strstr(dir->msg, "accurate")) {
1518 jcr->accurate = true;
1520 if (strstr(dir->msg, "incomplete")) {
1521 jcr->incomplete = true;
1523 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1526 /* Base backup requested? */
1527 if (strcmp(level, "base") == 0) {
1528 jcr->set_JobLevel(L_BASE);
1529 /* Full backup requested? */
1530 } else if (strcmp(level, "full") == 0) {
1531 jcr->set_JobLevel(L_FULL);
1532 } else if (strstr(level, "differential")) {
1533 jcr->set_JobLevel(L_DIFFERENTIAL);
1536 } else if (strstr(level, "incremental")) {
1537 jcr->set_JobLevel(L_INCREMENTAL);
1541 * We get his UTC since time, then sync the clocks and correct it
1542 * to agree with our clock.
1544 } else if (strcmp(level, "since_utime") == 0) {
1545 buf = get_memory(dir->msglen+1);
1546 utime_t since_time, adj;
1547 btime_t his_time, bt_start, rt=0, bt_adj=0;
1548 if (jcr->getJobLevel() == L_NONE) {
1549 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1551 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1552 buf, &mtime_only) != 2) {
1555 since_time = str_to_uint64(buf); /* this is the since time */
1556 Dmsg1(100, "since_time=%lld\n", since_time);
1557 char ed1[50], ed2[50];
1559 * Sync clocks by polling him for the time. We take
1560 * 10 samples of his time throwing out the first two.
1562 for (int i=0; i<10; i++) {
1563 bt_start = get_current_btime();
1564 dir->signal(BNET_BTIME); /* poll for time */
1565 if (dir->recv() <= 0) { /* get response */
1568 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1571 if (i < 2) { /* toss first two results */
1574 his_time = str_to_uint64(buf);
1575 rt = get_current_btime() - bt_start; /* compute round trip time */
1576 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1577 edit_uint64(bt_start, ed2));
1578 bt_adj += bt_start - his_time - rt/2;
1579 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1582 bt_adj = bt_adj / 8; /* compute average time */
1583 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1584 adj = btime_to_utime(bt_adj);
1585 since_time += adj; /* adjust for clock difference */
1586 /* Don't notify if time within 3 seconds */
1587 if (adj > 3 || adj < -3) {
1589 if (adj > 600 || adj < -600) {
1594 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1596 dir->signal(BNET_EOD);
1598 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1599 jcr->incremental = 1; /* set incremental or decremental backup */
1600 jcr->mtime = since_time; /* set since time */
1601 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1603 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1611 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1612 return dir->fsend(OKlevel);
1615 pm_strcpy(jcr->errmsg, dir->msg);
1616 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1625 * Get session parameters from Director -- this is for a Restore command
1626 * This is deprecated. It is now passed via the bsr.
1628 static int session_cmd(JCR *jcr)
1630 BSOCK *dir = jcr->dir_bsock;
1632 Dmsg1(100, "SessionCmd: %s", dir->msg);
1633 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1634 &jcr->VolSessionId, &jcr->VolSessionTime,
1635 &jcr->StartFile, &jcr->EndFile,
1636 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1637 pm_strcpy(jcr->errmsg, dir->msg);
1638 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1642 return dir->fsend(OKsession);
1645 static void set_storage_auth_key(JCR *jcr, char *key)
1647 /* if no key don't update anything */
1653 * We can be contacting multiple storage daemons.
1654 * So, make sure that any old jcr->store_bsock is cleaned up.
1656 if (jcr->store_bsock) {
1657 jcr->store_bsock->destroy();
1658 jcr->store_bsock = NULL;
1662 * We can be contacting multiple storage daemons.
1663 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1665 if (jcr->sd_auth_key) {
1667 * If we already have a Authorization key, director can do multi
1670 Dmsg0(5, "set multi_restore=true\n");
1671 jcr->multi_restore = true;
1672 bfree(jcr->sd_auth_key);
1675 jcr->sd_auth_key = bstrdup(key);
1676 Dmsg0(5, "set sd auth key\n");
1680 * Get address of storage daemon from Director
1683 static int storage_cmd(JCR *jcr)
1685 int stored_port; /* storage daemon port */
1686 int enable_ssl; /* enable ssl to sd */
1687 POOL_MEM sd_auth_key(PM_MESSAGE);
1688 BSOCK *dir = jcr->dir_bsock;
1689 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1692 Dmsg1(100, "StorageCmd: %s", dir->msg);
1693 sd_auth_key.check_size(dir->msglen);
1694 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1695 &enable_ssl, sd_auth_key.c_str()) != 4) {
1696 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1697 &stored_port, &enable_ssl) != 3) {
1698 pm_strcpy(jcr->errmsg, dir->msg);
1699 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1704 set_storage_auth_key(jcr, sd_auth_key.c_str());
1706 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1708 /* Open command communications with Storage daemon */
1709 /* Try to connect for 1 hour at 10 second intervals */
1711 sd->set_source_address(me->FDsrc_addr);
1712 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1713 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1719 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1720 jcr->stored_addr, stored_port);
1721 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1722 jcr->stored_addr, stored_port);
1725 Dmsg0(110, "Connection OK to SD.\n");
1727 jcr->store_bsock = sd;
1729 sd->fsend("Hello Start Job %s\n", jcr->Job);
1730 if (!authenticate_storagedaemon(jcr)) {
1731 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1734 Dmsg0(110, "Authenticated with SD.\n");
1736 /* Send OK to Director */
1737 return dir->fsend(OKstore);
1740 dir->fsend(BADcmd, "storage");
1749 static int backup_cmd(JCR *jcr)
1751 BSOCK *dir = jcr->dir_bsock;
1752 BSOCK *sd = jcr->store_bsock;
1757 #if defined(WIN32_VSS)
1758 // capture state here, if client is backed up by multiple directors
1759 // and one enables vss and the other does not then enable_vss can change
1760 // between here and where its evaluated after the job completes.
1761 jcr->VSS = g_pVSSClient && enable_vss;
1763 /* Run only one at a time */
1768 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1769 jcr->JobFiles = FileIndex;
1770 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1774 * Validate some options given to the backup make sense for the compiled in
1775 * options of this filed.
1777 if (jcr->ff->flags & FO_ACL && !have_acl) {
1778 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1781 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1782 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1786 set_jcr_job_status(jcr, JS_Blocked);
1787 jcr->set_JobType(JT_BACKUP);
1788 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1791 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1792 dir->fsend(BADcmd, "backup");
1796 dir->fsend(OKbackup);
1797 Dmsg1(110, "filed>dird: %s", dir->msg);
1800 * Send Append Open Session to Storage daemon
1802 sd->fsend(append_open);
1803 Dmsg1(110, ">stored: %s", sd->msg);
1805 * Expect to receive back the Ticket number
1807 if (bget_msg(sd) >= 0) {
1808 Dmsg1(110, "<stored: %s", sd->msg);
1809 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1810 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1813 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1815 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1820 * Send Append data command to Storage daemon
1822 sd->fsend(append_data, jcr->Ticket);
1823 Dmsg1(110, ">stored: %s", sd->msg);
1826 * Expect to get OK data
1828 Dmsg1(110, "<stored: %s", sd->msg);
1829 if (!response(jcr, sd, OK_data, "Append Data")) {
1833 generate_daemon_event(jcr, "JobStart");
1834 generate_plugin_event(jcr, bEventStartBackupJob);
1836 #if defined(WIN32_VSS)
1837 /* START VSS ON WIN32 */
1839 if (g_pVSSClient->InitializeForBackup(jcr)) {
1840 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1841 /* tell vss which drives to snapshot */
1842 char szWinDriveLetters[27];
1843 *szWinDriveLetters=0;
1844 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1845 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1846 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1847 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1849 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1851 /* tell user if snapshot creation of a specific drive failed */
1853 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1854 if (islower(szWinDriveLetters[i])) {
1855 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1858 /* inform user about writer states */
1859 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1860 if (g_pVSSClient->GetWriterState(i) < 1) {
1861 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1866 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1870 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"), be.bstrerror());
1872 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1877 * Send Files to Storage daemon
1879 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1880 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1881 set_jcr_job_status(jcr, JS_ErrorTerminated);
1882 bnet_suppress_error_messages(sd, 1);
1883 Dmsg0(110, "Error in blast_data.\n");
1885 set_jcr_job_status(jcr, JS_Terminated);
1886 /* Note, the above set status will not override an error */
1887 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1888 bnet_suppress_error_messages(sd, 1);
1889 goto cleanup; /* bail out now */
1892 * Expect to get response to append_data from Storage daemon
1894 if (!response(jcr, sd, OK_append, "Append Data")) {
1895 set_jcr_job_status(jcr, JS_ErrorTerminated);
1900 * Send Append End Data to Storage daemon
1902 sd->fsend(append_end, jcr->Ticket);
1904 if (!response(jcr, sd, OK_end, "Append End")) {
1905 set_jcr_job_status(jcr, JS_ErrorTerminated);
1910 * Send Append Close to Storage daemon
1912 sd->fsend(append_close, jcr->Ticket);
1913 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1914 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1916 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1920 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1923 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1924 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1930 #if defined(WIN32_VSS)
1932 Win32ConvCleanupCache();
1933 g_pVSSClient->DestroyWriterInfo();
1938 generate_plugin_event(jcr, bEventEndBackupJob);
1939 return 0; /* return and stop command loop */
1943 * Do a Verify for Director
1946 static int verify_cmd(JCR *jcr)
1948 BSOCK *dir = jcr->dir_bsock;
1949 BSOCK *sd = jcr->store_bsock;
1952 jcr->set_JobType(JT_VERIFY);
1953 if (sscanf(dir->msg, verifycmd, level) != 1) {
1954 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1958 if (strcasecmp(level, "init") == 0) {
1959 jcr->set_JobLevel(L_VERIFY_INIT);
1960 } else if (strcasecmp(level, "catalog") == 0){
1961 jcr->set_JobLevel(L_VERIFY_CATALOG);
1962 } else if (strcasecmp(level, "volume") == 0){
1963 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1964 } else if (strcasecmp(level, "data") == 0){
1965 jcr->set_JobLevel(L_VERIFY_DATA);
1966 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1967 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1969 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1973 dir->fsend(OKverify);
1975 generate_daemon_event(jcr, "JobStart");
1976 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1977 generate_plugin_event(jcr, bEventStartVerifyJob);
1979 Dmsg1(110, "filed>dird: %s", dir->msg);
1981 switch (jcr->getJobLevel()) {
1983 case L_VERIFY_CATALOG:
1986 case L_VERIFY_VOLUME_TO_CATALOG:
1987 if (!open_sd_read_session(jcr)) {
1990 start_dir_heartbeat(jcr);
1991 do_verify_volume(jcr);
1992 stop_dir_heartbeat(jcr);
1994 * Send Close session command to Storage daemon
1996 sd->fsend(read_close, jcr->Ticket);
1997 Dmsg1(130, "filed>stored: %s", sd->msg);
1999 /* ****FIXME**** check response */
2000 bget_msg(sd); /* get OK */
2002 /* Inform Storage daemon that we are done */
2003 sd->signal(BNET_TERMINATE);
2006 case L_VERIFY_DISK_TO_CATALOG:
2010 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2014 dir->signal(BNET_EOD);
2015 generate_plugin_event(jcr, bEventEndVerifyJob);
2016 return 0; /* return and terminate command loop */
2020 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2022 switch (init_type) {
2023 case VSS_INIT_RESTORE_AFTER_INIT:
2024 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2026 case VSS_INIT_RESTORE_AFTER_GATHER:
2027 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2037 * Do a Restore for Director
2040 static int restore_cmd(JCR *jcr)
2042 BSOCK *dir = jcr->dir_bsock;
2043 BSOCK *sd = jcr->store_bsock;
2045 bool use_regexwhere=false;
2050 * Scan WHERE (base directory for restore) from command
2052 Dmsg0(100, "restore command\n");
2053 #if defined(WIN32_VSS)
2056 * No need to enable VSS for restore if we do not have plugin
2059 enable_vss = jcr->job_metadata != NULL;
2061 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2062 // capture state here, if client is backed up by multiple directors
2063 // and one enables vss and the other does not then enable_vss can change
2064 // between here and where its evaluated after the job completes.
2065 jcr->VSS = g_pVSSClient && enable_vss;
2067 /* Run only one at a time */
2071 /* Pickup where string */
2072 args = get_memory(dir->msglen+1);
2075 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2076 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2077 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2078 pm_strcpy(jcr->errmsg, dir->msg);
2079 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2084 use_regexwhere = true;
2086 /* Turn / into nothing */
2087 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2091 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2092 unbash_spaces(args);
2094 if (use_regexwhere) {
2095 jcr->where_bregexp = get_bregexps(args);
2096 if (!jcr->where_bregexp) {
2097 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2098 free_pool_memory(args);
2102 jcr->where = bstrdup(args);
2105 free_pool_memory(args);
2106 jcr->replace = replace;
2107 jcr->prefix_links = prefix_links;
2109 dir->fsend(OKrestore);
2110 Dmsg1(110, "filed>dird: %s", dir->msg);
2112 jcr->set_JobType(JT_RESTORE);
2114 set_jcr_job_status(jcr, JS_Blocked);
2116 if (!open_sd_read_session(jcr)) {
2117 set_jcr_job_status(jcr, JS_ErrorTerminated);
2121 set_jcr_job_status(jcr, JS_Running);
2124 * Do restore of files and data
2126 start_dir_heartbeat(jcr);
2127 generate_daemon_event(jcr, "JobStart");
2128 generate_plugin_event(jcr, bEventStartRestoreJob);
2130 #if defined(WIN32_VSS)
2131 /* START VSS ON WIN32 */
2133 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2134 (WCHAR *)jcr->job_metadata)) {
2136 /* inform user about writer states */
2138 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2139 if (g_pVSSClient->GetWriterState(i) < 1) {
2140 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2146 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2147 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2151 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2153 free_and_null_pool_memory(jcr->job_metadata);
2154 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2159 stop_dir_heartbeat(jcr);
2161 set_jcr_job_status(jcr, JS_Terminated);
2162 if (jcr->JobStatus != JS_Terminated) {
2163 bnet_suppress_error_messages(sd, 1);
2167 * Send Close session command to Storage daemon
2169 sd->fsend(read_close, jcr->Ticket);
2170 Dmsg1(100, "filed>stored: %s", sd->msg);
2172 bget_msg(sd); /* get OK */
2174 /* Inform Storage daemon that we are done */
2175 sd->signal(BNET_TERMINATE);
2177 #if defined(WIN32_VSS)
2178 /* STOP VSS ON WIN32 */
2179 /* tell vss to close the restore session */
2180 Dmsg0(100, "About to call CloseRestore\n");
2182 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2183 Dmsg0(100, "Really about to call CloseRestore\n");
2184 if (g_pVSSClient->CloseRestore()) {
2185 Dmsg0(100, "CloseRestore success\n");
2186 /* inform user about writer states */
2187 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2188 int msg_type = M_INFO;
2189 if (g_pVSSClient->GetWriterState(i) < 1) {
2190 //msg_type = M_WARNING;
2193 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2197 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2203 bfree_and_null(jcr->where);
2205 if (jcr->JobErrors) {
2206 set_jcr_job_status(jcr, JS_ErrorTerminated);
2209 Dmsg0(100, "Done in job.c\n");
2212 if (jcr->multi_restore) {
2213 Dmsg0(100, OKstoreend);
2214 dir->fsend(OKstoreend);
2215 ret = 1; /* we continue the loop, waiting for next part */
2217 end_restore_cmd(jcr);
2218 ret = 0; /* we stop here */
2221 if (job_canceled(jcr)) {
2222 ret = 0; /* we stop here */
2228 static int end_restore_cmd(JCR *jcr)
2230 Dmsg0(5, "end_restore_cmd\n");
2231 generate_plugin_event(jcr, bEventEndRestoreJob);
2232 return 0; /* return and terminate command loop */
2235 static int open_sd_read_session(JCR *jcr)
2237 BSOCK *sd = jcr->store_bsock;
2240 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2243 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2244 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2245 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2247 * Open Read Session with Storage daemon
2249 sd->fsend(read_open, "DummyVolume",
2250 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2251 jcr->StartBlock, jcr->EndBlock);
2252 Dmsg1(110, ">stored: %s", sd->msg);
2257 if (bget_msg(sd) >= 0) {
2258 Dmsg1(110, "filed<stored: %s", sd->msg);
2259 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2260 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2263 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2265 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2269 if (!send_bootstrap_file(jcr)) {
2274 * Start read of data with Storage daemon
2276 sd->fsend(read_data, jcr->Ticket);
2277 Dmsg1(110, ">stored: %s", sd->msg);
2282 if (!response(jcr, sd, OK_data, "Read Data")) {
2289 * Destroy the Job Control Record and associated
2290 * resources (sockets).
2292 static void filed_free_jcr(JCR *jcr)
2294 if (jcr->store_bsock) {
2295 jcr->store_bsock->close();
2297 free_bootstrap(jcr);
2298 if (jcr->last_fname) {
2299 free_pool_memory(jcr->last_fname);
2301 free_runscripts(jcr->RunScripts);
2302 delete jcr->RunScripts;
2304 if (jcr->JobId != 0)
2305 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2311 * Get response from Storage daemon to a command we
2312 * sent. Check that the response is OK.
2314 * Returns: 0 on failure
2317 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2322 if (bget_msg(sd) > 0) {
2323 Dmsg0(110, sd->msg);
2324 if (strcmp(sd->msg, resp) == 0) {
2328 if (job_canceled(jcr)) {
2329 return 0; /* if canceled avoid useless error messages */
2331 if (is_bnet_error(sd)) {
2332 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2333 cmd, bnet_strerror(sd));
2335 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2336 cmd, resp, sd->msg);
2341 static int send_bootstrap_file(JCR *jcr)
2345 BSOCK *sd = jcr->store_bsock;
2346 const char *bootstrap = "bootstrap\n";
2349 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2350 if (!jcr->RestoreBootstrap) {
2353 bs = fopen(jcr->RestoreBootstrap, "rb");
2356 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2357 jcr->RestoreBootstrap, be.bstrerror());
2358 set_jcr_job_status(jcr, JS_ErrorTerminated);
2361 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2363 while (fgets(buf, sizeof(buf), bs)) {
2364 sd->msglen = Mmsg(sd->msg, "%s", buf);
2367 sd->signal(BNET_EOD);
2369 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2370 set_jcr_job_status(jcr, JS_ErrorTerminated);
2376 free_bootstrap(jcr);