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 setbandwidth_cmd(JCR *jcr);
74 static int estimate_cmd(JCR *jcr);
75 static int hello_cmd(JCR *jcr);
76 static int job_cmd(JCR *jcr);
77 static int fileset_cmd(JCR *jcr);
78 static int level_cmd(JCR *jcr);
79 static int verify_cmd(JCR *jcr);
80 static int restore_cmd(JCR *jcr);
81 static int end_restore_cmd(JCR *jcr);
82 static int storage_cmd(JCR *jcr);
83 static int session_cmd(JCR *jcr);
84 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
85 static void filed_free_jcr(JCR *jcr);
86 static int open_sd_read_session(JCR *jcr);
87 static int send_bootstrap_file(JCR *jcr);
88 static int runscript_cmd(JCR *jcr);
89 static int runbefore_cmd(JCR *jcr);
90 static int runafter_cmd(JCR *jcr);
91 static int runbeforenow_cmd(JCR *jcr);
92 static int restore_object_cmd(JCR *jcr);
93 static int set_options(findFOPTS *fo, const char *opts);
94 static void set_storage_auth_key(JCR *jcr, char *key);
95 static int sm_dump_cmd(JCR *jcr);
97 static int exit_cmd(JCR *jcr);
100 /* Exported functions */
105 int monitoraccess; /* specify if monitors have access to this function */
109 * The following are the recognized commands from the Director.
111 static struct s_cmds cmds[] = {
112 {"backup", backup_cmd, 0},
113 {"cancel", cancel_cmd, 0},
114 {"setdebug=", setdebug_cmd, 0},
115 {"setbandwidth=",setbandwidth_cmd, 0},
116 {"estimate", estimate_cmd, 0},
117 {"Hello", hello_cmd, 1},
118 {"fileset", fileset_cmd, 0},
119 {"JobId=", job_cmd, 0},
120 {"level = ", level_cmd, 0},
121 {"restore ", restore_cmd, 0},
122 {"endrestore", end_restore_cmd, 0},
123 {"session", session_cmd, 0},
124 {"status", status_cmd, 1},
125 {".status", qstatus_cmd, 1},
126 {"storage ", storage_cmd, 0},
127 {"verify", verify_cmd, 0},
128 {"bootstrap", bootstrap_cmd, 0},
129 {"RunBeforeNow", runbeforenow_cmd, 0},
130 {"RunBeforeJob", runbefore_cmd, 0},
131 {"RunAfterJob", runafter_cmd, 0},
132 {"Run", runscript_cmd, 0},
133 {"accurate", accurate_cmd, 0},
134 {"restoreobject", restore_object_cmd, 0},
135 {"sm_dump", sm_dump_cmd, 0},
137 {"exit", exit_cmd, 0},
139 {NULL, NULL} /* list terminator */
142 /* Commands received from director that need scanning */
143 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
144 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
145 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
146 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
147 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
148 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
149 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
150 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
151 static char endrestoreobjectcmd[] = "restoreobject end\n";
152 static char verifycmd[] = "verify level=%30s";
153 static char estimatecmd[] = "estimate listing=%d";
154 static char runbefore[] = "RunBeforeJob %s";
155 static char runafter[] = "RunAfterJob %s";
156 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
157 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
159 /* Responses sent to Director */
160 static char errmsg[] = "2999 Invalid command\n";
161 static char no_auth[] = "2998 No Authorization\n";
162 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
163 static char OKBandwidth[] = "2000 OK Bandwidth\n";
164 static char OKinc[] = "2000 OK include\n";
165 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
166 static char OKlevel[] = "2000 OK level\n";
167 static char OKbackup[] = "2000 OK backup\n";
168 static char OKbootstrap[] = "2000 OK bootstrap\n";
169 static char OKverify[] = "2000 OK verify\n";
170 static char OKrestore[] = "2000 OK restore\n";
171 static char OKsession[] = "2000 OK session\n";
172 static char OKstore[] = "2000 OK storage\n";
173 static char OKstoreend[] = "2000 OK storage end\n";
174 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
175 static char OKsetdebug[] = "2000 OK setdebug=%d trace=%d hangup=%d\n";
176 static char BADjob[] = "2901 Bad Job\n";
177 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
178 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
179 static char OKRunBefore[] = "2000 OK RunBefore\n";
180 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
181 static char OKRunAfter[] = "2000 OK RunAfter\n";
182 static char OKRunScript[] = "2000 OK RunScript\n";
183 static char BADcmd[] = "2902 Bad %s\n";
184 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
187 /* Responses received from Storage Daemon */
188 static char OK_end[] = "3000 OK end\n";
189 static char OK_close[] = "3000 OK close Status = %d\n";
190 static char OK_open[] = "3000 OK open ticket = %d\n";
191 static char OK_data[] = "3000 OK data\n";
192 static char OK_append[] = "3000 OK append data\n";
193 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
196 /* Commands sent to Storage Daemon */
197 static char append_open[] = "append open session\n";
198 static char append_data[] = "append data %d\n";
199 static char append_end[] = "append end session %d\n";
200 static char append_close[] = "append close session %d\n";
201 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
202 static char read_data[] = "read data %d\n";
203 static char read_close[] = "read close session %d\n";
206 * Accept requests from a Director
208 * NOTE! We are running as a separate thread
210 * Send output one line
211 * at a time followed by a zero length transmission.
213 * Return when the connection is terminated or there
216 * Basic task here is:
217 * Authenticate Director (during Hello command).
218 * Accept commands one at a time from the Director
221 * Concerning ClientRunBefore/After, the sequence of events
222 * is rather critical. If they are not done in the right
223 * order one can easily get FD->SD timeouts if the script
226 * The current sequence of events is:
227 * 1. Dir starts job with FD
228 * 2. Dir connects to SD
229 * 3. Dir connects to FD
230 * 4. FD connects to SD
231 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
232 * 6. Dir sends include/exclude
233 * 7. FD sends data to SD
234 * 8. SD/FD disconnects while SD despools data and attributes (optional)
235 * 9. FD runs ClientRunAfterJob
238 void *handle_client_request(void *dirp)
243 BSOCK *dir = (BSOCK *)dirp;
244 const char jobname[12] = "*Director*";
247 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
248 jcr->dir_bsock = dir;
249 jcr->ff = init_find_files();
250 // save_cwd.save(jcr);
251 jcr->start_time = time(NULL);
252 jcr->RunScripts = New(alist(10, not_owned_by_alist));
253 jcr->last_fname = get_pool_memory(PM_FNAME);
254 jcr->last_fname[0] = 0;
255 jcr->client_name = get_memory(strlen(my_name) + 1);
256 pm_strcpy(jcr->client_name, my_name);
257 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
258 jcr->crypto.pki_sign = me->pki_sign;
259 jcr->crypto.pki_encrypt = me->pki_encrypt;
260 jcr->crypto.pki_keypair = me->pki_keypair;
261 jcr->crypto.pki_signers = me->pki_signers;
262 jcr->crypto.pki_recipients = me->pki_recipients;
264 enable_backup_privileges(NULL, 1 /* ignore_errors */);
266 /**********FIXME******* add command handler error code */
268 for (quit=false; !quit;) {
270 if (dir->recv() < 0) {
271 break; /* connection terminated */
273 dir->msg[dir->msglen] = 0;
274 Dmsg1(100, "<dird: %s", dir->msg);
276 for (i=0; cmds[i].cmd; i++) {
277 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
278 found = true; /* indicate command found */
279 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
281 dir->signal(BNET_EOD);
284 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
285 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
286 dir->fsend(invalid_cmd);
287 dir->signal(BNET_EOD);
290 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
291 if (!cmds[i].func(jcr)) { /* do command */
292 quit = true; /* error or fully terminated, get out */
293 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
298 if (!found) { /* command not found */
305 /* Inform Storage daemon that we are done */
306 if (jcr->store_bsock) {
307 jcr->store_bsock->signal(BNET_TERMINATE);
310 /* Run the after job */
311 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
313 if (jcr->JobId) { /* send EndJob if running a job */
314 char ed1[50], ed2[50];
315 /* Send termination status back to Dir */
316 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
317 edit_uint64(jcr->ReadBytes, ed1),
318 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
319 jcr->crypto.pki_encrypt);
320 Dmsg1(110, "End FD msg: %s\n", dir->msg);
323 generate_daemon_event(jcr, "JobEnd");
324 generate_plugin_event(jcr, bEventJobEnd);
326 dequeue_messages(jcr); /* send any queued messages */
328 /* Inform Director that we are done */
329 dir->signal(BNET_TERMINATE);
331 free_plugins(jcr); /* release instantiated plugins */
332 free_and_null_pool_memory(jcr->job_metadata);
334 /* Clean up fileset */
335 FF_PKT *ff = jcr->ff;
336 findFILESET *fileset = ff->fileset;
339 /* Delete FileSet Include lists */
340 for (i=0; i<fileset->include_list.size(); i++) {
341 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
342 for (j=0; j<incexe->opts_list.size(); j++) {
343 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
344 for (k=0; k<fo->regex.size(); k++) {
345 regfree((regex_t *)fo->regex.get(k));
347 for (k=0; k<fo->regexdir.size(); k++) {
348 regfree((regex_t *)fo->regexdir.get(k));
350 for (k=0; k<fo->regexfile.size(); k++) {
351 regfree((regex_t *)fo->regexfile.get(k));
354 fo->regexdir.destroy();
355 fo->regexfile.destroy();
357 fo->wilddir.destroy();
358 fo->wildfile.destroy();
359 fo->wildbase.destroy();
361 fo->fstype.destroy();
362 fo->drivetype.destroy();
364 incexe->opts_list.destroy();
365 incexe->name_list.destroy();
366 incexe->plugin_list.destroy();
367 if (incexe->ignoredir) {
368 free(incexe->ignoredir);
371 fileset->include_list.destroy();
373 /* Delete FileSet Exclude lists */
374 for (i=0; i<fileset->exclude_list.size(); i++) {
375 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
376 for (j=0; j<incexe->opts_list.size(); j++) {
377 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
379 fo->regexdir.destroy();
380 fo->regexfile.destroy();
382 fo->wilddir.destroy();
383 fo->wildfile.destroy();
384 fo->wildbase.destroy();
386 fo->fstype.destroy();
387 fo->drivetype.destroy();
389 incexe->opts_list.destroy();
390 incexe->name_list.destroy();
391 incexe->plugin_list.destroy();
392 if (incexe->ignoredir) {
393 free(incexe->ignoredir);
396 fileset->exclude_list.destroy();
400 Dmsg0(100, "Calling term_find_files\n");
401 term_find_files(jcr->ff);
402 // save_cwd.restore(jcr);
403 // save_cwd.release();
405 Dmsg0(100, "Done with term_find_files\n");
406 free_jcr(jcr); /* destroy JCR record */
407 Dmsg0(100, "Done with free_jcr\n");
409 garbage_collect_memory_pool();
413 static int sm_dump_cmd(JCR *jcr)
416 sm_dump(false, true);
417 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
422 static int exit_cmd(JCR *jcr)
424 jcr->dir_bsock->fsend("2000 exit OK\n");
432 * Hello from Director he must identify himself and provide his
435 static int hello_cmd(JCR *jcr)
437 Dmsg0(120, "Calling Authenticate\n");
438 if (!authenticate_director(jcr)) {
441 Dmsg0(120, "OK Authenticate\n");
442 jcr->authenticated = true;
449 static int cancel_cmd(JCR *jcr)
451 BSOCK *dir = jcr->dir_bsock;
452 char Job[MAX_NAME_LENGTH];
455 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
456 if (!(cjcr=get_jcr_by_full_name(Job))) {
457 dir->fsend(_("2901 Job %s not found.\n"), Job);
459 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
460 cjcr->setJobStatus(JS_Canceled);
461 if (cjcr->store_bsock) {
462 cjcr->store_bsock->set_timed_out();
463 cjcr->store_bsock->set_terminated();
464 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
467 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
470 dir->fsend(_("2902 Error scanning cancel command.\n"));
472 dir->signal(BNET_EOD);
477 * Set bandwidth limit as requested by the Director
480 static int setbandwidth_cmd(JCR *jcr)
482 BSOCK *dir = jcr->dir_bsock;
485 char Job[MAX_NAME_LENGTH];
488 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
489 pm_strcpy(jcr->errmsg, dir->msg);
490 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
495 if(!(cjcr=get_jcr_by_full_name(Job))) {
496 dir->fsend(_("2901 Job %s not found.\n"), Job);
498 cjcr->max_bandwidth = bw;
499 if (cjcr->store_bsock) {
500 cjcr->store_bsock->set_bwlimit(bw);
505 } else { /* No job requested, apply globally */
506 me->max_bandwidth_per_job = bw; /* Overwrite directive */
509 return dir->fsend(OKBandwidth);
513 * Set debug level as requested by the Director
516 static int setdebug_cmd(JCR *jcr)
518 BSOCK *dir = jcr->dir_bsock;
519 int32_t level, trace, hangup;
522 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
523 scan = sscanf(dir->msg, "setdebug=%d trace=%d hangup=%d",
524 &level, &trace, &hangup);
526 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
527 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace) != 2) {
528 pm_strcpy(jcr->errmsg, dir->msg);
529 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
540 Dmsg3(50, "level=%d trace=%d hangup=%d\n", level, get_trace(), get_hangup());
541 return dir->fsend(OKsetdebug, level, get_trace(), get_hangup());
545 static int estimate_cmd(JCR *jcr)
547 BSOCK *dir = jcr->dir_bsock;
548 char ed1[50], ed2[50];
550 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
551 pm_strcpy(jcr->errmsg, dir->msg);
552 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
553 dir->fsend(_("2992 Bad estimate command.\n"));
557 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
558 edit_uint64_with_commas(jcr->JobBytes, ed2));
559 dir->signal(BNET_EOD);
564 * Get JobId and Storage Daemon Authorization key from Director
566 static int job_cmd(JCR *jcr)
568 BSOCK *dir = jcr->dir_bsock;
569 POOL_MEM sd_auth_key(PM_MESSAGE);
570 sd_auth_key.check_size(dir->msglen);
572 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
573 &jcr->VolSessionId, &jcr->VolSessionTime,
574 sd_auth_key.c_str()) != 5) {
575 pm_strcpy(jcr->errmsg, dir->msg);
576 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
580 set_storage_auth_key(jcr, sd_auth_key.c_str());
581 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
582 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
583 new_plugins(jcr); /* instantiate plugins for this jcr */
584 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
586 return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
588 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
592 static int runbefore_cmd(JCR *jcr)
595 BSOCK *dir = jcr->dir_bsock;
596 POOLMEM *cmd = get_memory(dir->msglen+1);
599 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
600 if (sscanf(dir->msg, runbefore, cmd) != 1) {
601 pm_strcpy(jcr->errmsg, dir->msg);
602 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
603 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
609 /* Run the command now */
610 script = new_runscript();
611 script->set_command(cmd);
612 script->when = SCRIPT_Before;
613 ok = script->run(jcr, "ClientRunBeforeJob");
614 free_runscript(script);
618 dir->fsend(OKRunBefore);
621 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
626 static int runbeforenow_cmd(JCR *jcr)
628 BSOCK *dir = jcr->dir_bsock;
630 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
631 if (job_canceled(jcr)) {
632 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
633 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
636 dir->fsend(OKRunBeforeNow);
637 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
642 static int runafter_cmd(JCR *jcr)
644 BSOCK *dir = jcr->dir_bsock;
645 POOLMEM *msg = get_memory(dir->msglen+1);
648 Dmsg1(100, "runafter_cmd: %s", dir->msg);
649 if (sscanf(dir->msg, runafter, msg) != 1) {
650 pm_strcpy(jcr->errmsg, dir->msg);
651 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
652 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
658 cmd = new_runscript();
659 cmd->set_command(msg);
660 cmd->on_success = true;
661 cmd->on_failure = false;
662 cmd->when = SCRIPT_After;
664 jcr->RunScripts->append(cmd);
666 free_pool_memory(msg);
667 return dir->fsend(OKRunAfter);
670 static int runscript_cmd(JCR *jcr)
672 BSOCK *dir = jcr->dir_bsock;
673 POOLMEM *msg = get_memory(dir->msglen+1);
674 int on_success, on_failure, fail_on_error;
676 RUNSCRIPT *cmd = new_runscript() ;
678 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
679 /* Note, we cannot sscanf into bools */
680 if (sscanf(dir->msg, runscript, &on_success,
685 pm_strcpy(jcr->errmsg, dir->msg);
686 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
687 dir->fsend(_("2905 Bad RunScript command.\n"));
692 cmd->on_success = on_success;
693 cmd->on_failure = on_failure;
694 cmd->fail_on_error = fail_on_error;
697 cmd->set_command(msg);
699 jcr->RunScripts->append(cmd);
701 free_pool_memory(msg);
702 return dir->fsend(OKRunScript);
706 * This reads data sent from the Director from the
707 * RestoreObject table that allows us to get objects
708 * that were backed up (VSS .xml data) and are needed
709 * before starting the restore.
711 static int restore_object_cmd(JCR *jcr)
713 BSOCK *dir = jcr->dir_bsock;
715 restore_object_pkt rop;
717 memset(&rop, 0, sizeof(rop));
718 rop.pkt_size = sizeof(rop);
719 rop.pkt_end = sizeof(rop);
720 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
721 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
722 generate_plugin_event(jcr, bEventRestoreObject, NULL);
723 return dir->fsend(OKRestoreObject);
726 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
727 &rop.object_full_len, &rop.object_index,
728 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
729 Dmsg0(5, "Bad restore object command\n");
730 pm_strcpy(jcr->errmsg, dir->msg);
731 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
735 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
736 rop.JobId, rop.object_len, rop.object_full_len,
737 rop.object_index, rop.object_type, FileIndex);
738 /* Read Object name */
739 if (dir->recv() < 0) {
742 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
743 rop.object_name = bstrdup(dir->msg);
746 if (dir->recv() < 0) {
749 /* Transfer object from message buffer, and get new message buffer */
750 rop.object = dir->msg;
751 dir->msg = get_pool_memory(PM_MESSAGE);
753 /* If object is compressed, uncompress it */
754 if (rop.object_compression == 1) { /* zlib level 9 */
756 int out_len = rop.object_full_len + 100;
757 POOLMEM *obj = get_memory(out_len);
758 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
759 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
760 Dmsg1(100, "Zinflate stat=%d\n", stat);
761 if (out_len != rop.object_full_len) {
762 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
763 rop.object_full_len, out_len, rop.object_name);
765 free_pool_memory(rop.object); /* release compressed object */
766 rop.object = obj; /* new uncompressed object */
767 rop.object_len = out_len;
769 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
770 /* Special Job meta data */
771 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
772 Dmsg0(100, "got job metadata\n");
773 free_and_null_pool_memory(jcr->job_metadata);
774 jcr->job_metadata = rop.object;
778 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
781 if (rop.object_name) {
782 free(rop.object_name);
785 free_pool_memory(rop.object);
788 Dmsg1(100, "Send: %s", OKRestoreObject);
792 dir->fsend(_("2909 Bad RestoreObject command.\n"));
798 static bool init_fileset(JCR *jcr)
801 findFILESET *fileset;
810 fileset = (findFILESET *)malloc(sizeof(findFILESET));
811 memset(fileset, 0, sizeof(findFILESET));
812 ff->fileset = fileset;
813 fileset->state = state_none;
814 fileset->include_list.init(1, true);
815 fileset->exclude_list.init(1, true);
819 static void append_file(JCR *jcr, findINCEXE *incexe,
820 const char *buf, bool is_file)
823 incexe->name_list.append(new_dlistString(buf));
825 } else if (me->plugin_directory) {
826 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
827 incexe->plugin_list.append(new_dlistString(buf));
830 Jmsg(jcr, M_FATAL, 0,
831 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
837 * Add fname to include/exclude fileset list. First check for
838 * | and < and if necessary perform command.
840 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
842 findFILESET *fileset = jcr->ff->fileset;
855 p++; /* skip over | */
856 fn = get_pool_memory(PM_FNAME);
857 fn = edit_job_codes(jcr, fn, p, "");
858 bpipe = open_bpipe(fn, 0, "r");
861 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
863 free_pool_memory(fn);
866 free_pool_memory(fn);
867 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
868 strip_trailing_junk(buf);
869 append_file(jcr, fileset->incexe, buf, is_file);
871 if ((stat=close_bpipe(bpipe)) != 0) {
873 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
874 p, be.code(stat), be.bstrerror(stat));
879 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
880 p++; /* skip over < */
881 if ((ffd = fopen(p, "rb")) == NULL) {
883 Jmsg(jcr, M_FATAL, 0,
884 _("Cannot open FileSet input file: %s. ERR=%s\n"),
888 while (fgets(buf, sizeof(buf), ffd)) {
889 strip_trailing_junk(buf);
890 append_file(jcr, fileset->incexe, buf, is_file);
895 append_file(jcr, fileset->incexe, fname, is_file);
900 void set_incexe(JCR *jcr, findINCEXE *incexe)
902 findFILESET *fileset = jcr->ff->fileset;
903 fileset->incexe = incexe;
908 * Define a new Exclude block in the FileSet
910 findINCEXE *new_exclude(JCR *jcr)
912 findFILESET *fileset = jcr->ff->fileset;
915 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
916 memset(fileset->incexe, 0, sizeof(findINCEXE));
917 fileset->incexe->opts_list.init(1, true);
918 fileset->incexe->name_list.init();
919 fileset->incexe->plugin_list.init();
920 fileset->exclude_list.append(fileset->incexe);
921 return fileset->incexe;
925 * Define a new Include block in the FileSet
927 findINCEXE *new_include(JCR *jcr)
929 findFILESET *fileset = jcr->ff->fileset;
932 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
933 memset(fileset->incexe, 0, sizeof(findINCEXE));
934 fileset->incexe->opts_list.init(1, true);
935 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
936 fileset->incexe->plugin_list.init();
937 fileset->include_list.append(fileset->incexe);
938 return fileset->incexe;
942 * Define a new preInclude block in the FileSet
943 * That is the include is prepended to the other
944 * Includes. This is used for plugin exclusions.
946 findINCEXE *new_preinclude(JCR *jcr)
948 findFILESET *fileset = jcr->ff->fileset;
950 /* New pre-include */
951 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
952 memset(fileset->incexe, 0, sizeof(findINCEXE));
953 fileset->incexe->opts_list.init(1, true);
954 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
955 fileset->incexe->plugin_list.init();
956 fileset->include_list.prepend(fileset->incexe);
957 return fileset->incexe;
960 static findFOPTS *start_options(FF_PKT *ff)
962 int state = ff->fileset->state;
963 findINCEXE *incexe = ff->fileset->incexe;
965 if (state != state_options) {
966 ff->fileset->state = state_options;
967 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
968 memset(fo, 0, sizeof(findFOPTS));
969 fo->regex.init(1, true);
970 fo->regexdir.init(1, true);
971 fo->regexfile.init(1, true);
972 fo->wild.init(1, true);
973 fo->wilddir.init(1, true);
974 fo->wildfile.init(1, true);
975 fo->wildbase.init(1, true);
976 fo->base.init(1, true);
977 fo->fstype.init(1, true);
978 fo->drivetype.init(1, true);
979 incexe->current_opts = fo;
980 incexe->opts_list.append(fo);
982 return incexe->current_opts;
986 * Used by plugins to define a new options block
988 void new_options(JCR *jcr, findINCEXE *incexe)
991 incexe = jcr->ff->fileset->incexe;
993 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
994 memset(fo, 0, sizeof(findFOPTS));
995 fo->regex.init(1, true);
996 fo->regexdir.init(1, true);
997 fo->regexfile.init(1, true);
998 fo->wild.init(1, true);
999 fo->wilddir.init(1, true);
1000 fo->wildfile.init(1, true);
1001 fo->wildbase.init(1, true);
1002 fo->base.init(1, true);
1003 fo->fstype.init(1, true);
1004 fo->drivetype.init(1, true);
1005 incexe->current_opts = fo;
1006 incexe->opts_list.prepend(fo);
1007 jcr->ff->fileset->state = state_options;
1011 * Add a regex to the current fileset
1013 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1015 findFOPTS *current_opts = start_options(jcr->ff);
1020 preg = (regex_t *)malloc(sizeof(regex_t));
1021 if (current_opts->flags & FO_IGNORECASE) {
1022 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1024 rc = regcomp(preg, item, REG_EXTENDED);
1027 regerror(rc, preg, prbuf, sizeof(prbuf));
1030 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1034 current_opts->regex.append(preg);
1035 } else if (type == 'D') {
1036 current_opts->regexdir.append(preg);
1037 } else if (type == 'F') {
1038 current_opts->regexfile.append(preg);
1042 return state_options;
1046 * Add a wild card to the current fileset
1048 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1050 findFOPTS *current_opts = start_options(jcr->ff);
1053 current_opts->wild.append(bstrdup(item));
1054 } else if (type == 'D') {
1055 current_opts->wilddir.append(bstrdup(item));
1056 } else if (type == 'F') {
1057 current_opts->wildfile.append(bstrdup(item));
1058 } else if (type == 'B') {
1059 current_opts->wildbase.append(bstrdup(item));
1063 return state_options;
1068 * Add options to the current fileset
1070 int add_options_to_fileset(JCR *jcr, const char *item)
1072 findFOPTS *current_opts = start_options(jcr->ff);
1074 set_options(current_opts, item);
1075 return state_options;
1078 static void add_fileset(JCR *jcr, const char *item)
1080 FF_PKT *ff = jcr->ff;
1081 findFILESET *fileset = ff->fileset;
1082 int state = fileset->state;
1083 findFOPTS *current_opts;
1085 /* Get code, optional subcode, and position item past the dividing space */
1086 Dmsg1(100, "%s\n", item);
1091 int subcode = ' '; /* A space is always a valid subcode */
1092 if (item[0] != '\0' && item[0] != ' ') {
1100 /* Skip all lines we receive after an error */
1101 if (state == state_error) {
1102 Dmsg0(100, "State=error return\n");
1107 * The switch tests the code for validity.
1108 * The subcode is always good if it is a space, otherwise we must confirm.
1109 * We set state to state_error first assuming the subcode is invalid,
1110 * requiring state to be set in cases below that handle subcodes.
1112 if (subcode != ' ') {
1113 state = state_error;
1114 Dmsg0(100, "Set state=error or double code.\n");
1118 (void)new_include(jcr);
1121 (void)new_exclude(jcr);
1123 case 'N': /* null */
1126 case 'F': /* file = */
1127 /* File item to include or exclude list */
1128 state = state_include;
1129 add_file_to_fileset(jcr, item, true);
1131 case 'P': /* plugin */
1132 /* Plugin item to include list */
1133 state = state_include;
1134 add_file_to_fileset(jcr, item, false);
1136 case 'R': /* regex */
1137 state = add_regex_to_fileset(jcr, item, subcode);
1140 current_opts = start_options(ff);
1141 current_opts->base.append(bstrdup(item));
1142 state = state_options;
1144 case 'X': /* Filetype or Drive type */
1145 current_opts = start_options(ff);
1146 state = state_options;
1147 if (subcode == ' ') {
1148 current_opts->fstype.append(bstrdup(item));
1149 } else if (subcode == 'D') {
1150 current_opts->drivetype.append(bstrdup(item));
1152 state = state_error;
1155 case 'W': /* wild cards */
1156 state = add_wild_to_fileset(jcr, item, subcode);
1158 case 'O': /* Options */
1159 state = add_options_to_fileset(jcr, item);
1161 case 'Z': /* ignore dir */
1162 state = state_include;
1163 fileset->incexe->ignoredir = bstrdup(item);
1166 current_opts = start_options(ff);
1167 // current_opts->reader = bstrdup(item); /* deprecated */
1168 state = state_options;
1171 current_opts = start_options(ff);
1172 // current_opts->writer = bstrdup(item); /* deprecated */
1173 state = state_options;
1176 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1177 state = state_error;
1180 ff->fileset->state = state;
1183 static bool term_fileset(JCR *jcr)
1185 FF_PKT *ff = jcr->ff;
1187 #ifdef xxx_DEBUG_CODE
1188 findFILESET *fileset = ff->fileset;
1191 for (i=0; i<fileset->include_list.size(); i++) {
1192 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1194 for (j=0; j<incexe->opts_list.size(); j++) {
1195 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1196 for (k=0; k<fo->regex.size(); k++) {
1197 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1199 for (k=0; k<fo->regexdir.size(); k++) {
1200 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1202 for (k=0; k<fo->regexfile.size(); k++) {
1203 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1205 for (k=0; k<fo->wild.size(); k++) {
1206 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1208 for (k=0; k<fo->wilddir.size(); k++) {
1209 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1211 for (k=0; k<fo->wildfile.size(); k++) {
1212 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1214 for (k=0; k<fo->wildbase.size(); k++) {
1215 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1217 for (k=0; k<fo->base.size(); k++) {
1218 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1220 for (k=0; k<fo->fstype.size(); k++) {
1221 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1223 for (k=0; k<fo->drivetype.size(); k++) {
1224 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1227 if (incexe->ignoredir) {
1228 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1231 foreach_dlist(node, &incexe->name_list) {
1232 Dmsg1(400, "F %s\n", node->c_str());
1234 foreach_dlist(node, &incexe->plugin_list) {
1235 Dmsg1(400, "P %s\n", node->c_str());
1238 for (i=0; i<fileset->exclude_list.size(); i++) {
1239 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1241 for (j=0; j<incexe->opts_list.size(); j++) {
1242 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1243 for (k=0; k<fo->regex.size(); k++) {
1244 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1246 for (k=0; k<fo->regexdir.size(); k++) {
1247 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1249 for (k=0; k<fo->regexfile.size(); k++) {
1250 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1252 for (k=0; k<fo->wild.size(); k++) {
1253 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1255 for (k=0; k<fo->wilddir.size(); k++) {
1256 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1258 for (k=0; k<fo->wildfile.size(); k++) {
1259 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1261 for (k=0; k<fo->wildbase.size(); k++) {
1262 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1264 for (k=0; k<fo->base.size(); k++) {
1265 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1267 for (k=0; k<fo->fstype.size(); k++) {
1268 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1270 for (k=0; k<fo->drivetype.size(); k++) {
1271 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1275 foreach_dlist(node, incexe->name_list) {
1276 Dmsg1(400, "F %s\n", node->c_str());
1278 foreach_dlist(node, &incexe->plugin_list) {
1279 Dmsg1(400, "P %s\n", node->c_str());
1283 return ff->fileset->state != state_error;
1288 * As an optimization, we should do this during
1289 * "compile" time in filed/job.c, and keep only a bit mask
1290 * and the Verify options.
1292 static int set_options(findFOPTS *fo, const char *opts)
1298 // Commented out as it is not backward compatible - KES
1300 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1303 for (p=opts; *p; p++) {
1305 case 'a': /* alway replace */
1306 case '0': /* no option */
1309 fo->flags |= FO_EXCLUDE;
1312 fo->flags |= FO_MULTIFS;
1314 case 'h': /* no recursion */
1315 fo->flags |= FO_NO_RECURSION;
1317 case 'H': /* no hard link handling */
1318 fo->flags |= FO_NO_HARDLINK;
1321 fo->flags |= FO_IGNORECASE;
1324 fo->flags |= FO_MD5;
1327 fo->flags |= FO_NOREPLACE;
1329 case 'p': /* use portable data format */
1330 fo->flags |= FO_PORTABLE;
1332 case 'R': /* Resource forks and Finder Info */
1333 fo->flags |= FO_HFSPLUS;
1335 case 'r': /* read fifo */
1336 fo->flags |= FO_READFIFO;
1341 fo->flags |= FO_SHA1;
1346 fo->flags |= FO_SHA256;
1350 fo->flags |= FO_SHA512;
1356 * If 2 or 3 is seen here, SHA2 is not configured, so
1357 * eat the option, and drop back to SHA-1.
1359 if (p[1] == '2' || p[1] == '3') {
1362 fo->flags |= FO_SHA1;
1367 fo->flags |= FO_SPARSE;
1370 fo->flags |= FO_MTIMEONLY;
1373 fo->flags |= FO_KEEPATIME;
1376 fo->flags |= FO_ACL;
1378 case 'V': /* verify options */
1379 /* Copy Verify Options */
1380 for (j=0; *p && *p != ':'; p++) {
1381 fo->VerifyOpts[j] = *p;
1382 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1386 fo->VerifyOpts[j] = 0;
1388 case 'C': /* accurate options */
1389 /* Copy Accurate Options */
1390 for (j=0; *p && *p != ':'; p++) {
1391 fo->AccurateOpts[j] = *p;
1392 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1396 fo->AccurateOpts[j] = 0;
1398 case 'J': /* Basejob options */
1399 /* Copy BaseJob Options */
1400 for (j=0; *p && *p != ':'; p++) {
1401 fo->BaseJobOpts[j] = *p;
1402 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1406 fo->BaseJobOpts[j] = 0;
1408 case 'P': /* strip path */
1411 for (j=0; *p && *p != ':'; p++) {
1413 if (j < (int)sizeof(strip) - 1) {
1418 fo->strip_path = atoi(strip);
1419 fo->flags |= FO_STRIPPATH;
1420 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1423 fo->flags |= FO_IF_NEWER;
1426 fo->flags |= FO_ENHANCEDWILD;
1428 case 'Z': /* gzip compression */
1429 fo->flags |= FO_GZIP;
1430 fo->GZIP_level = *++p - '0';
1433 fo->flags |= FO_NOATIME;
1436 fo->flags |= FO_CHKCHANGES;
1439 fo->flags |= FO_HONOR_NODUMP;
1442 fo->flags |= FO_XATTR;
1445 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1449 return state_options;
1454 * Director is passing his Fileset
1456 static int fileset_cmd(JCR *jcr)
1458 BSOCK *dir = jcr->dir_bsock;
1461 #if defined(WIN32_VSS)
1464 sscanf(dir->msg, "fileset vss=%d", &vss);
1468 if (!init_fileset(jcr)) {
1471 while (dir->recv() >= 0) {
1472 strip_trailing_junk(dir->msg);
1473 Dmsg1(500, "Fileset: %s\n", dir->msg);
1474 add_fileset(jcr, dir->msg);
1476 if (!term_fileset(jcr)) {
1479 rtnstat = dir->fsend(OKinc);
1480 generate_plugin_event(jcr, bEventEndFileSet);
1484 static void free_bootstrap(JCR *jcr)
1486 if (jcr->RestoreBootstrap) {
1487 unlink(jcr->RestoreBootstrap);
1488 free_pool_memory(jcr->RestoreBootstrap);
1489 jcr->RestoreBootstrap = NULL;
1494 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1495 static uint32_t bsr_uniq = 0;
1498 * The Director sends us the bootstrap file, which
1499 * we will in turn pass to the SD.
1500 * Deprecated. The bsr is now sent directly from the
1501 * Director to the SD.
1503 static int bootstrap_cmd(JCR *jcr)
1505 BSOCK *dir = jcr->dir_bsock;
1506 POOLMEM *fname = get_pool_memory(PM_FNAME);
1509 free_bootstrap(jcr);
1512 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1513 jcr->Job, bsr_uniq);
1515 Dmsg1(400, "bootstrap=%s\n", fname);
1516 jcr->RestoreBootstrap = fname;
1517 bs = fopen(fname, "a+b"); /* create file */
1520 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1521 jcr->RestoreBootstrap, be.bstrerror());
1523 * Suck up what he is sending to us so that he will then
1524 * read our error message.
1526 while (dir->recv() >= 0)
1528 free_bootstrap(jcr);
1529 jcr->setJobStatus(JS_ErrorTerminated);
1533 while (dir->recv() >= 0) {
1534 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1535 fputs(dir->msg, bs);
1539 * Note, do not free the bootstrap yet -- it needs to be
1542 return dir->fsend(OKbootstrap);
1547 * Get backup level from Director
1550 static int level_cmd(JCR *jcr)
1552 BSOCK *dir = jcr->dir_bsock;
1553 POOLMEM *level, *buf = NULL;
1556 level = get_memory(dir->msglen+1);
1557 Dmsg1(10, "level_cmd: %s", dir->msg);
1559 /* keep compatibility with older directors */
1560 if (strstr(dir->msg, "accurate")) {
1561 jcr->accurate = true;
1563 if (strstr(dir->msg, "rerunning")) {
1564 jcr->rerunning = true;
1566 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1569 /* Base backup requested? */
1570 if (strcmp(level, "base") == 0) {
1571 jcr->setJobLevel(L_BASE);
1572 /* Full backup requested? */
1573 } else if (strcmp(level, "full") == 0) {
1574 jcr->setJobLevel(L_FULL);
1575 } else if (strstr(level, "differential")) {
1576 jcr->setJobLevel(L_DIFFERENTIAL);
1579 } else if (strstr(level, "incremental")) {
1580 jcr->setJobLevel(L_INCREMENTAL);
1584 * We get his UTC since time, then sync the clocks and correct it
1585 * to agree with our clock.
1587 } else if (strcmp(level, "since_utime") == 0) {
1588 buf = get_memory(dir->msglen+1);
1589 utime_t since_time, adj;
1590 btime_t his_time, bt_start, rt=0, bt_adj=0;
1591 if (jcr->getJobLevel() == L_NONE) {
1592 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1594 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1595 buf, &mtime_only) != 2) {
1598 since_time = str_to_uint64(buf); /* this is the since time */
1599 Dmsg1(100, "since_time=%lld\n", since_time);
1600 char ed1[50], ed2[50];
1602 * Sync clocks by polling him for the time. We take
1603 * 10 samples of his time throwing out the first two.
1605 for (int i=0; i<10; i++) {
1606 bt_start = get_current_btime();
1607 dir->signal(BNET_BTIME); /* poll for time */
1608 if (dir->recv() <= 0) { /* get response */
1611 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1614 if (i < 2) { /* toss first two results */
1617 his_time = str_to_uint64(buf);
1618 rt = get_current_btime() - bt_start; /* compute round trip time */
1619 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1620 edit_uint64(bt_start, ed2));
1621 bt_adj += bt_start - his_time - rt/2;
1622 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1625 bt_adj = bt_adj / 8; /* compute average time */
1626 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1627 adj = btime_to_utime(bt_adj);
1628 since_time += adj; /* adjust for clock difference */
1629 /* Don't notify if time within 3 seconds */
1630 if (adj > 3 || adj < -3) {
1632 if (adj > 600 || adj < -600) {
1637 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1639 dir->signal(BNET_EOD);
1641 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1642 jcr->incremental = 1; /* set incremental or decremental backup */
1643 jcr->mtime = since_time; /* set since time */
1644 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1646 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1654 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1655 return dir->fsend(OKlevel);
1658 pm_strcpy(jcr->errmsg, dir->msg);
1659 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1668 * Get session parameters from Director -- this is for a Restore command
1669 * This is deprecated. It is now passed via the bsr.
1671 static int session_cmd(JCR *jcr)
1673 BSOCK *dir = jcr->dir_bsock;
1675 Dmsg1(100, "SessionCmd: %s", dir->msg);
1676 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1677 &jcr->VolSessionId, &jcr->VolSessionTime,
1678 &jcr->StartFile, &jcr->EndFile,
1679 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1680 pm_strcpy(jcr->errmsg, dir->msg);
1681 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1685 return dir->fsend(OKsession);
1688 static void set_storage_auth_key(JCR *jcr, char *key)
1690 /* if no key don't update anything */
1696 * We can be contacting multiple storage daemons.
1697 * So, make sure that any old jcr->store_bsock is cleaned up.
1699 if (jcr->store_bsock) {
1700 jcr->store_bsock->destroy();
1701 jcr->store_bsock = NULL;
1705 * We can be contacting multiple storage daemons.
1706 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1708 if (jcr->sd_auth_key) {
1710 * If we already have a Authorization key, director can do multi
1713 Dmsg0(5, "set multi_restore=true\n");
1714 jcr->multi_restore = true;
1715 bfree(jcr->sd_auth_key);
1718 jcr->sd_auth_key = bstrdup(key);
1719 Dmsg0(5, "set sd auth key\n");
1723 * Get address of storage daemon from Director
1726 static int storage_cmd(JCR *jcr)
1728 int stored_port; /* storage daemon port */
1729 int enable_ssl; /* enable ssl to sd */
1730 POOL_MEM sd_auth_key(PM_MESSAGE);
1731 BSOCK *dir = jcr->dir_bsock;
1732 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1735 Dmsg1(100, "StorageCmd: %s", dir->msg);
1736 sd_auth_key.check_size(dir->msglen);
1737 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1738 &enable_ssl, sd_auth_key.c_str()) != 4) {
1739 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1740 &stored_port, &enable_ssl) != 3) {
1741 pm_strcpy(jcr->errmsg, dir->msg);
1742 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1747 set_storage_auth_key(jcr, sd_auth_key.c_str());
1749 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1751 /* Open command communications with Storage daemon */
1752 /* Try to connect for 1 hour at 10 second intervals */
1754 sd->set_source_address(me->FDsrc_addr);
1756 /* TODO: see if we put limit on restore and backup... */
1757 if (!jcr->max_bandwidth) {
1758 if (jcr->director->max_bandwidth_per_job) {
1759 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
1761 } else if (me->max_bandwidth_per_job) {
1762 jcr->max_bandwidth = me->max_bandwidth_per_job;
1765 sd->set_bwlimit(jcr->max_bandwidth);
1767 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1768 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1774 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1775 jcr->stored_addr, stored_port);
1776 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1777 jcr->stored_addr, stored_port);
1780 Dmsg0(110, "Connection OK to SD.\n");
1782 jcr->store_bsock = sd;
1784 sd->fsend("Hello Start Job %s\n", jcr->Job);
1785 if (!authenticate_storagedaemon(jcr)) {
1786 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1789 Dmsg0(110, "Authenticated with SD.\n");
1791 /* Send OK to Director */
1792 return dir->fsend(OKstore);
1795 dir->fsend(BADcmd, "storage");
1804 static int backup_cmd(JCR *jcr)
1806 BSOCK *dir = jcr->dir_bsock;
1807 BSOCK *sd = jcr->store_bsock;
1812 #if defined(WIN32_VSS)
1813 // capture state here, if client is backed up by multiple directors
1814 // and one enables vss and the other does not then enable_vss can change
1815 // between here and where its evaluated after the job completes.
1816 jcr->VSS = g_pVSSClient && enable_vss;
1818 /* Run only one at a time */
1823 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1824 jcr->JobFiles = FileIndex;
1825 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1829 * Validate some options given to the backup make sense for the compiled in
1830 * options of this filed.
1832 if (jcr->ff->flags & FO_ACL && !have_acl) {
1833 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1836 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1837 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1841 jcr->setJobStatus(JS_Blocked);
1842 jcr->setJobType(JT_BACKUP);
1843 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1846 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1847 dir->fsend(BADcmd, "backup");
1851 dir->fsend(OKbackup);
1852 Dmsg1(110, "filed>dird: %s", dir->msg);
1855 * Send Append Open Session to Storage daemon
1857 sd->fsend(append_open);
1858 Dmsg1(110, ">stored: %s", sd->msg);
1860 * Expect to receive back the Ticket number
1862 if (bget_msg(sd) >= 0) {
1863 Dmsg1(110, "<stored: %s", sd->msg);
1864 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1865 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1868 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1870 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1875 * Send Append data command to Storage daemon
1877 sd->fsend(append_data, jcr->Ticket);
1878 Dmsg1(110, ">stored: %s", sd->msg);
1881 * Expect to get OK data
1883 Dmsg1(110, "<stored: %s", sd->msg);
1884 if (!response(jcr, sd, OK_data, "Append Data")) {
1888 generate_daemon_event(jcr, "JobStart");
1889 generate_plugin_event(jcr, bEventStartBackupJob);
1891 #if defined(WIN32_VSS)
1892 /* START VSS ON WIN32 */
1894 if (g_pVSSClient->InitializeForBackup(jcr)) {
1895 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1896 /* tell vss which drives to snapshot */
1897 char szWinDriveLetters[27];
1898 *szWinDriveLetters=0;
1899 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1900 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1901 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1902 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1904 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1906 /* tell user if snapshot creation of a specific drive failed */
1908 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1909 if (islower(szWinDriveLetters[i])) {
1910 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1913 /* inform user about writer states */
1914 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1915 if (g_pVSSClient->GetWriterState(i) < 1) {
1916 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1921 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1925 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"), be.bstrerror());
1927 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1932 * Send Files to Storage daemon
1934 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1935 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1936 jcr->setJobStatus(JS_ErrorTerminated);
1937 bnet_suppress_error_messages(sd, 1);
1938 Dmsg0(110, "Error in blast_data.\n");
1940 jcr->setJobStatus(JS_Terminated);
1941 /* Note, the above set status will not override an error */
1942 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1943 bnet_suppress_error_messages(sd, 1);
1944 goto cleanup; /* bail out now */
1947 * Expect to get response to append_data from Storage daemon
1949 if (!response(jcr, sd, OK_append, "Append Data")) {
1950 jcr->setJobStatus(JS_ErrorTerminated);
1955 * Send Append End Data to Storage daemon
1957 sd->fsend(append_end, jcr->Ticket);
1959 if (!response(jcr, sd, OK_end, "Append End")) {
1960 jcr->setJobStatus(JS_ErrorTerminated);
1965 * Send Append Close to Storage daemon
1967 sd->fsend(append_close, jcr->Ticket);
1968 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1969 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1971 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1975 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1978 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1979 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1985 #if defined(WIN32_VSS)
1987 Win32ConvCleanupCache();
1988 g_pVSSClient->DestroyWriterInfo();
1993 generate_plugin_event(jcr, bEventEndBackupJob);
1994 return 0; /* return and stop command loop */
1998 * Do a Verify for Director
2001 static int verify_cmd(JCR *jcr)
2003 BSOCK *dir = jcr->dir_bsock;
2004 BSOCK *sd = jcr->store_bsock;
2007 jcr->setJobType(JT_VERIFY);
2008 if (sscanf(dir->msg, verifycmd, level) != 1) {
2009 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2013 if (strcasecmp(level, "init") == 0) {
2014 jcr->setJobLevel(L_VERIFY_INIT);
2015 } else if (strcasecmp(level, "catalog") == 0){
2016 jcr->setJobLevel(L_VERIFY_CATALOG);
2017 } else if (strcasecmp(level, "volume") == 0){
2018 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2019 } else if (strcasecmp(level, "data") == 0){
2020 jcr->setJobLevel(L_VERIFY_DATA);
2021 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2022 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2024 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2028 dir->fsend(OKverify);
2030 generate_daemon_event(jcr, "JobStart");
2031 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
2032 generate_plugin_event(jcr, bEventStartVerifyJob);
2034 Dmsg1(110, "filed>dird: %s", dir->msg);
2036 switch (jcr->getJobLevel()) {
2038 case L_VERIFY_CATALOG:
2041 case L_VERIFY_VOLUME_TO_CATALOG:
2042 if (!open_sd_read_session(jcr)) {
2045 start_dir_heartbeat(jcr);
2046 do_verify_volume(jcr);
2047 stop_dir_heartbeat(jcr);
2049 * Send Close session command to Storage daemon
2051 sd->fsend(read_close, jcr->Ticket);
2052 Dmsg1(130, "filed>stored: %s", sd->msg);
2054 /* ****FIXME**** check response */
2055 bget_msg(sd); /* get OK */
2057 /* Inform Storage daemon that we are done */
2058 sd->signal(BNET_TERMINATE);
2061 case L_VERIFY_DISK_TO_CATALOG:
2065 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2069 dir->signal(BNET_EOD);
2070 generate_plugin_event(jcr, bEventEndVerifyJob);
2071 return 0; /* return and terminate command loop */
2075 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2077 switch (init_type) {
2078 case VSS_INIT_RESTORE_AFTER_INIT:
2079 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2081 case VSS_INIT_RESTORE_AFTER_GATHER:
2082 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2092 * Do a Restore for Director
2095 static int restore_cmd(JCR *jcr)
2097 BSOCK *dir = jcr->dir_bsock;
2098 BSOCK *sd = jcr->store_bsock;
2100 bool use_regexwhere=false;
2105 * Scan WHERE (base directory for restore) from command
2107 Dmsg0(100, "restore command\n");
2108 #if defined(WIN32_VSS)
2111 * No need to enable VSS for restore if we do not have plugin
2114 enable_vss = jcr->job_metadata != NULL;
2116 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2117 // capture state here, if client is backed up by multiple directors
2118 // and one enables vss and the other does not then enable_vss can change
2119 // between here and where its evaluated after the job completes.
2120 jcr->VSS = g_pVSSClient && enable_vss;
2122 /* Run only one at a time */
2126 /* Pickup where string */
2127 args = get_memory(dir->msglen+1);
2130 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2131 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2132 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2133 pm_strcpy(jcr->errmsg, dir->msg);
2134 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2139 use_regexwhere = true;
2141 /* Turn / into nothing */
2142 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2146 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2147 unbash_spaces(args);
2149 if (use_regexwhere) {
2150 jcr->where_bregexp = get_bregexps(args);
2151 if (!jcr->where_bregexp) {
2152 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2153 free_pool_memory(args);
2157 jcr->where = bstrdup(args);
2160 free_pool_memory(args);
2161 jcr->replace = replace;
2162 jcr->prefix_links = prefix_links;
2164 dir->fsend(OKrestore);
2165 Dmsg1(110, "filed>dird: %s", dir->msg);
2167 jcr->setJobType(JT_RESTORE);
2169 jcr->setJobStatus(JS_Blocked);
2171 if (!open_sd_read_session(jcr)) {
2172 jcr->setJobStatus(JS_ErrorTerminated);
2176 jcr->setJobStatus(JS_Running);
2179 * Do restore of files and data
2181 start_dir_heartbeat(jcr);
2182 generate_daemon_event(jcr, "JobStart");
2183 generate_plugin_event(jcr, bEventStartRestoreJob);
2185 #if defined(WIN32_VSS)
2186 /* START VSS ON WIN32 */
2188 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2189 (WCHAR *)jcr->job_metadata)) {
2191 /* inform user about writer states */
2193 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2194 if (g_pVSSClient->GetWriterState(i) < 1) {
2195 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2201 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2202 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2206 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2208 free_and_null_pool_memory(jcr->job_metadata);
2209 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2214 stop_dir_heartbeat(jcr);
2216 jcr->setJobStatus(JS_Terminated);
2217 if (jcr->JobStatus != JS_Terminated) {
2218 bnet_suppress_error_messages(sd, 1);
2222 * Send Close session command to Storage daemon
2224 sd->fsend(read_close, jcr->Ticket);
2225 Dmsg1(100, "filed>stored: %s", sd->msg);
2227 bget_msg(sd); /* get OK */
2229 /* Inform Storage daemon that we are done */
2230 sd->signal(BNET_TERMINATE);
2232 #if defined(WIN32_VSS)
2233 /* STOP VSS ON WIN32 */
2234 /* tell vss to close the restore session */
2235 Dmsg0(100, "About to call CloseRestore\n");
2237 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2238 Dmsg0(100, "Really about to call CloseRestore\n");
2239 if (g_pVSSClient->CloseRestore()) {
2240 Dmsg0(100, "CloseRestore success\n");
2241 /* inform user about writer states */
2242 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2243 int msg_type = M_INFO;
2244 if (g_pVSSClient->GetWriterState(i) < 1) {
2245 //msg_type = M_WARNING;
2248 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2252 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2258 bfree_and_null(jcr->where);
2260 if (jcr->JobErrors) {
2261 jcr->setJobStatus(JS_ErrorTerminated);
2264 Dmsg0(100, "Done in job.c\n");
2267 if (jcr->multi_restore) {
2268 Dmsg0(100, OKstoreend);
2269 dir->fsend(OKstoreend);
2270 ret = 1; /* we continue the loop, waiting for next part */
2272 end_restore_cmd(jcr);
2273 ret = 0; /* we stop here */
2276 if (job_canceled(jcr)) {
2277 ret = 0; /* we stop here */
2283 static int end_restore_cmd(JCR *jcr)
2285 Dmsg0(5, "end_restore_cmd\n");
2286 generate_plugin_event(jcr, bEventEndRestoreJob);
2287 return 0; /* return and terminate command loop */
2290 static int open_sd_read_session(JCR *jcr)
2292 BSOCK *sd = jcr->store_bsock;
2295 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2298 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2299 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2300 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2302 * Open Read Session with Storage daemon
2304 sd->fsend(read_open, "DummyVolume",
2305 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2306 jcr->StartBlock, jcr->EndBlock);
2307 Dmsg1(110, ">stored: %s", sd->msg);
2312 if (bget_msg(sd) >= 0) {
2313 Dmsg1(110, "filed<stored: %s", sd->msg);
2314 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2315 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2318 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2320 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2324 if (!send_bootstrap_file(jcr)) {
2329 * Start read of data with Storage daemon
2331 sd->fsend(read_data, jcr->Ticket);
2332 Dmsg1(110, ">stored: %s", sd->msg);
2337 if (!response(jcr, sd, OK_data, "Read Data")) {
2344 * Destroy the Job Control Record and associated
2345 * resources (sockets).
2347 static void filed_free_jcr(JCR *jcr)
2349 if (jcr->store_bsock) {
2350 jcr->store_bsock->close();
2352 free_bootstrap(jcr);
2353 if (jcr->last_fname) {
2354 free_pool_memory(jcr->last_fname);
2356 free_runscripts(jcr->RunScripts);
2357 delete jcr->RunScripts;
2359 if (jcr->JobId != 0)
2360 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2366 * Get response from Storage daemon to a command we
2367 * sent. Check that the response is OK.
2369 * Returns: 0 on failure
2372 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2377 if (bget_msg(sd) > 0) {
2378 Dmsg0(110, sd->msg);
2379 if (strcmp(sd->msg, resp) == 0) {
2383 if (job_canceled(jcr)) {
2384 return 0; /* if canceled avoid useless error messages */
2386 if (is_bnet_error(sd)) {
2387 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2388 cmd, bnet_strerror(sd));
2390 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2391 cmd, resp, sd->msg);
2396 static int send_bootstrap_file(JCR *jcr)
2400 BSOCK *sd = jcr->store_bsock;
2401 const char *bootstrap = "bootstrap\n";
2404 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2405 if (!jcr->RestoreBootstrap) {
2408 bs = fopen(jcr->RestoreBootstrap, "rb");
2411 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2412 jcr->RestoreBootstrap, be.bstrerror());
2413 jcr->setJobStatus(JS_ErrorTerminated);
2416 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2418 while (fgets(buf, sizeof(buf), bs)) {
2419 sd->msglen = Mmsg(sd->msg, "%s", buf);
2422 sd->signal(BNET_EOD);
2424 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2425 jcr->setJobStatus(JS_ErrorTerminated);
2431 free_bootstrap(jcr);