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);
585 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
588 static int runbefore_cmd(JCR *jcr)
591 BSOCK *dir = jcr->dir_bsock;
592 POOLMEM *cmd = get_memory(dir->msglen+1);
595 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
596 if (sscanf(dir->msg, runbefore, cmd) != 1) {
597 pm_strcpy(jcr->errmsg, dir->msg);
598 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
599 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
605 /* Run the command now */
606 script = new_runscript();
607 script->set_command(cmd);
608 script->when = SCRIPT_Before;
609 ok = script->run(jcr, "ClientRunBeforeJob");
610 free_runscript(script);
614 dir->fsend(OKRunBefore);
617 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
622 static int runbeforenow_cmd(JCR *jcr)
624 BSOCK *dir = jcr->dir_bsock;
626 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
627 if (job_canceled(jcr)) {
628 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
629 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
632 dir->fsend(OKRunBeforeNow);
633 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
638 static int runafter_cmd(JCR *jcr)
640 BSOCK *dir = jcr->dir_bsock;
641 POOLMEM *msg = get_memory(dir->msglen+1);
644 Dmsg1(100, "runafter_cmd: %s", dir->msg);
645 if (sscanf(dir->msg, runafter, msg) != 1) {
646 pm_strcpy(jcr->errmsg, dir->msg);
647 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
648 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
654 cmd = new_runscript();
655 cmd->set_command(msg);
656 cmd->on_success = true;
657 cmd->on_failure = false;
658 cmd->when = SCRIPT_After;
660 jcr->RunScripts->append(cmd);
662 free_pool_memory(msg);
663 return dir->fsend(OKRunAfter);
666 static int runscript_cmd(JCR *jcr)
668 BSOCK *dir = jcr->dir_bsock;
669 POOLMEM *msg = get_memory(dir->msglen+1);
670 int on_success, on_failure, fail_on_error;
672 RUNSCRIPT *cmd = new_runscript() ;
674 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
675 /* Note, we cannot sscanf into bools */
676 if (sscanf(dir->msg, runscript, &on_success,
681 pm_strcpy(jcr->errmsg, dir->msg);
682 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
683 dir->fsend(_("2905 Bad RunScript command.\n"));
688 cmd->on_success = on_success;
689 cmd->on_failure = on_failure;
690 cmd->fail_on_error = fail_on_error;
693 cmd->set_command(msg);
695 jcr->RunScripts->append(cmd);
697 free_pool_memory(msg);
698 return dir->fsend(OKRunScript);
702 * This reads data sent from the Director from the
703 * RestoreObject table that allows us to get objects
704 * that were backed up (VSS .xml data) and are needed
705 * before starting the restore.
707 static int restore_object_cmd(JCR *jcr)
709 BSOCK *dir = jcr->dir_bsock;
711 restore_object_pkt rop;
713 memset(&rop, 0, sizeof(rop));
714 rop.pkt_size = sizeof(rop);
715 rop.pkt_end = sizeof(rop);
716 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
717 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
718 generate_plugin_event(jcr, bEventRestoreObject, NULL);
719 return dir->fsend(OKRestoreObject);
722 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
723 &rop.object_full_len, &rop.object_index,
724 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
725 Dmsg0(5, "Bad restore object command\n");
726 pm_strcpy(jcr->errmsg, dir->msg);
727 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
731 Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
732 rop.JobId, rop.object_len, rop.object_full_len,
733 rop.object_index, rop.object_type, FileIndex);
734 /* Read Object name */
735 if (dir->recv() < 0) {
738 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
739 rop.object_name = bstrdup(dir->msg);
742 if (dir->recv() < 0) {
745 /* Transfer object from message buffer, and get new message buffer */
746 rop.object = dir->msg;
747 dir->msg = get_pool_memory(PM_MESSAGE);
749 /* If object is compressed, uncompress it */
750 if (rop.object_compression == 1) { /* zlib level 9 */
752 int out_len = rop.object_full_len + 100;
753 POOLMEM *obj = get_memory(out_len);
754 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
755 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
756 Dmsg1(100, "Zinflate stat=%d\n", stat);
757 if (out_len != rop.object_full_len) {
758 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
759 rop.object_full_len, out_len, rop.object_name);
761 free_pool_memory(rop.object); /* release compressed object */
762 rop.object = obj; /* new uncompressed object */
763 rop.object_len = out_len;
765 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
766 /* Special Job meta data */
767 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
768 Dmsg0(100, "got job metadata\n");
769 free_and_null_pool_memory(jcr->job_metadata);
770 jcr->job_metadata = rop.object;
774 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
777 if (rop.object_name) {
778 free(rop.object_name);
781 free_pool_memory(rop.object);
784 Dmsg1(100, "Send: %s", OKRestoreObject);
788 dir->fsend(_("2909 Bad RestoreObject command.\n"));
794 static bool init_fileset(JCR *jcr)
797 findFILESET *fileset;
806 fileset = (findFILESET *)malloc(sizeof(findFILESET));
807 memset(fileset, 0, sizeof(findFILESET));
808 ff->fileset = fileset;
809 fileset->state = state_none;
810 fileset->include_list.init(1, true);
811 fileset->exclude_list.init(1, true);
815 static void append_file(JCR *jcr, findINCEXE *incexe,
816 const char *buf, bool is_file)
819 incexe->name_list.append(new_dlistString(buf));
821 } else if (me->plugin_directory) {
822 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
823 incexe->plugin_list.append(new_dlistString(buf));
826 Jmsg(jcr, M_FATAL, 0,
827 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
833 * Add fname to include/exclude fileset list. First check for
834 * | and < and if necessary perform command.
836 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
838 findFILESET *fileset = jcr->ff->fileset;
851 p++; /* skip over | */
852 fn = get_pool_memory(PM_FNAME);
853 fn = edit_job_codes(jcr, fn, p, "");
854 bpipe = open_bpipe(fn, 0, "r");
857 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
859 free_pool_memory(fn);
862 free_pool_memory(fn);
863 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
864 strip_trailing_junk(buf);
865 append_file(jcr, fileset->incexe, buf, is_file);
867 if ((stat=close_bpipe(bpipe)) != 0) {
869 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
870 p, be.code(stat), be.bstrerror(stat));
875 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
876 p++; /* skip over < */
877 if ((ffd = fopen(p, "rb")) == NULL) {
879 Jmsg(jcr, M_FATAL, 0,
880 _("Cannot open FileSet input file: %s. ERR=%s\n"),
884 while (fgets(buf, sizeof(buf), ffd)) {
885 strip_trailing_junk(buf);
886 append_file(jcr, fileset->incexe, buf, is_file);
891 append_file(jcr, fileset->incexe, fname, is_file);
896 void set_incexe(JCR *jcr, findINCEXE *incexe)
898 findFILESET *fileset = jcr->ff->fileset;
899 fileset->incexe = incexe;
904 * Define a new Exclude block in the FileSet
906 findINCEXE *new_exclude(JCR *jcr)
908 findFILESET *fileset = jcr->ff->fileset;
911 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
912 memset(fileset->incexe, 0, sizeof(findINCEXE));
913 fileset->incexe->opts_list.init(1, true);
914 fileset->incexe->name_list.init();
915 fileset->incexe->plugin_list.init();
916 fileset->exclude_list.append(fileset->incexe);
917 return fileset->incexe;
921 * Define a new Include block in the FileSet
923 findINCEXE *new_include(JCR *jcr)
925 findFILESET *fileset = jcr->ff->fileset;
928 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
929 memset(fileset->incexe, 0, sizeof(findINCEXE));
930 fileset->incexe->opts_list.init(1, true);
931 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
932 fileset->incexe->plugin_list.init();
933 fileset->include_list.append(fileset->incexe);
934 return fileset->incexe;
938 * Define a new preInclude block in the FileSet
939 * That is the include is prepended to the other
940 * Includes. This is used for plugin exclusions.
942 findINCEXE *new_preinclude(JCR *jcr)
944 findFILESET *fileset = jcr->ff->fileset;
946 /* New pre-include */
947 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
948 memset(fileset->incexe, 0, sizeof(findINCEXE));
949 fileset->incexe->opts_list.init(1, true);
950 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
951 fileset->incexe->plugin_list.init();
952 fileset->include_list.prepend(fileset->incexe);
953 return fileset->incexe;
956 static findFOPTS *start_options(FF_PKT *ff)
958 int state = ff->fileset->state;
959 findINCEXE *incexe = ff->fileset->incexe;
961 if (state != state_options) {
962 ff->fileset->state = state_options;
963 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
964 memset(fo, 0, sizeof(findFOPTS));
965 fo->regex.init(1, true);
966 fo->regexdir.init(1, true);
967 fo->regexfile.init(1, true);
968 fo->wild.init(1, true);
969 fo->wilddir.init(1, true);
970 fo->wildfile.init(1, true);
971 fo->wildbase.init(1, true);
972 fo->base.init(1, true);
973 fo->fstype.init(1, true);
974 fo->drivetype.init(1, true);
975 incexe->current_opts = fo;
976 incexe->opts_list.append(fo);
978 return incexe->current_opts;
982 * Used by plugins to define a new options block
984 void new_options(JCR *jcr, findINCEXE *incexe)
987 incexe = jcr->ff->fileset->incexe;
989 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
990 memset(fo, 0, sizeof(findFOPTS));
991 fo->regex.init(1, true);
992 fo->regexdir.init(1, true);
993 fo->regexfile.init(1, true);
994 fo->wild.init(1, true);
995 fo->wilddir.init(1, true);
996 fo->wildfile.init(1, true);
997 fo->wildbase.init(1, true);
998 fo->base.init(1, true);
999 fo->fstype.init(1, true);
1000 fo->drivetype.init(1, true);
1001 incexe->current_opts = fo;
1002 incexe->opts_list.prepend(fo);
1003 jcr->ff->fileset->state = state_options;
1007 * Add a regex to the current fileset
1009 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1011 findFOPTS *current_opts = start_options(jcr->ff);
1016 preg = (regex_t *)malloc(sizeof(regex_t));
1017 if (current_opts->flags & FO_IGNORECASE) {
1018 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1020 rc = regcomp(preg, item, REG_EXTENDED);
1023 regerror(rc, preg, prbuf, sizeof(prbuf));
1026 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1030 current_opts->regex.append(preg);
1031 } else if (type == 'D') {
1032 current_opts->regexdir.append(preg);
1033 } else if (type == 'F') {
1034 current_opts->regexfile.append(preg);
1038 return state_options;
1042 * Add a wild card to the current fileset
1044 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1046 findFOPTS *current_opts = start_options(jcr->ff);
1049 current_opts->wild.append(bstrdup(item));
1050 } else if (type == 'D') {
1051 current_opts->wilddir.append(bstrdup(item));
1052 } else if (type == 'F') {
1053 current_opts->wildfile.append(bstrdup(item));
1054 } else if (type == 'B') {
1055 current_opts->wildbase.append(bstrdup(item));
1059 return state_options;
1064 * Add options to the current fileset
1066 int add_options_to_fileset(JCR *jcr, const char *item)
1068 findFOPTS *current_opts = start_options(jcr->ff);
1070 set_options(current_opts, item);
1071 return state_options;
1074 static void add_fileset(JCR *jcr, const char *item)
1076 FF_PKT *ff = jcr->ff;
1077 findFILESET *fileset = ff->fileset;
1078 int state = fileset->state;
1079 findFOPTS *current_opts;
1081 /* Get code, optional subcode, and position item past the dividing space */
1082 Dmsg1(100, "%s\n", item);
1087 int subcode = ' '; /* A space is always a valid subcode */
1088 if (item[0] != '\0' && item[0] != ' ') {
1096 /* Skip all lines we receive after an error */
1097 if (state == state_error) {
1098 Dmsg0(100, "State=error return\n");
1103 * The switch tests the code for validity.
1104 * The subcode is always good if it is a space, otherwise we must confirm.
1105 * We set state to state_error first assuming the subcode is invalid,
1106 * requiring state to be set in cases below that handle subcodes.
1108 if (subcode != ' ') {
1109 state = state_error;
1110 Dmsg0(100, "Set state=error or double code.\n");
1114 (void)new_include(jcr);
1117 (void)new_exclude(jcr);
1119 case 'N': /* null */
1122 case 'F': /* file = */
1123 /* File item to include or exclude list */
1124 state = state_include;
1125 add_file_to_fileset(jcr, item, true);
1127 case 'P': /* plugin */
1128 /* Plugin item to include list */
1129 state = state_include;
1130 add_file_to_fileset(jcr, item, false);
1132 case 'R': /* regex */
1133 state = add_regex_to_fileset(jcr, item, subcode);
1136 current_opts = start_options(ff);
1137 current_opts->base.append(bstrdup(item));
1138 state = state_options;
1140 case 'X': /* Filetype or Drive type */
1141 current_opts = start_options(ff);
1142 state = state_options;
1143 if (subcode == ' ') {
1144 current_opts->fstype.append(bstrdup(item));
1145 } else if (subcode == 'D') {
1146 current_opts->drivetype.append(bstrdup(item));
1148 state = state_error;
1151 case 'W': /* wild cards */
1152 state = add_wild_to_fileset(jcr, item, subcode);
1154 case 'O': /* Options */
1155 state = add_options_to_fileset(jcr, item);
1157 case 'Z': /* ignore dir */
1158 state = state_include;
1159 fileset->incexe->ignoredir = bstrdup(item);
1162 current_opts = start_options(ff);
1163 // current_opts->reader = bstrdup(item); /* deprecated */
1164 state = state_options;
1167 current_opts = start_options(ff);
1168 // current_opts->writer = bstrdup(item); /* deprecated */
1169 state = state_options;
1172 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1173 state = state_error;
1176 ff->fileset->state = state;
1179 static bool term_fileset(JCR *jcr)
1181 FF_PKT *ff = jcr->ff;
1183 #ifdef xxx_DEBUG_CODE
1184 findFILESET *fileset = ff->fileset;
1187 for (i=0; i<fileset->include_list.size(); i++) {
1188 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1190 for (j=0; j<incexe->opts_list.size(); j++) {
1191 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1192 for (k=0; k<fo->regex.size(); k++) {
1193 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1195 for (k=0; k<fo->regexdir.size(); k++) {
1196 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1198 for (k=0; k<fo->regexfile.size(); k++) {
1199 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1201 for (k=0; k<fo->wild.size(); k++) {
1202 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1204 for (k=0; k<fo->wilddir.size(); k++) {
1205 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1207 for (k=0; k<fo->wildfile.size(); k++) {
1208 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1210 for (k=0; k<fo->wildbase.size(); k++) {
1211 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1213 for (k=0; k<fo->base.size(); k++) {
1214 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1216 for (k=0; k<fo->fstype.size(); k++) {
1217 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1219 for (k=0; k<fo->drivetype.size(); k++) {
1220 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1223 if (incexe->ignoredir) {
1224 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1227 foreach_dlist(node, &incexe->name_list) {
1228 Dmsg1(400, "F %s\n", node->c_str());
1230 foreach_dlist(node, &incexe->plugin_list) {
1231 Dmsg1(400, "P %s\n", node->c_str());
1234 for (i=0; i<fileset->exclude_list.size(); i++) {
1235 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1237 for (j=0; j<incexe->opts_list.size(); j++) {
1238 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1239 for (k=0; k<fo->regex.size(); k++) {
1240 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1242 for (k=0; k<fo->regexdir.size(); k++) {
1243 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1245 for (k=0; k<fo->regexfile.size(); k++) {
1246 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1248 for (k=0; k<fo->wild.size(); k++) {
1249 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1251 for (k=0; k<fo->wilddir.size(); k++) {
1252 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1254 for (k=0; k<fo->wildfile.size(); k++) {
1255 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1257 for (k=0; k<fo->wildbase.size(); k++) {
1258 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1260 for (k=0; k<fo->base.size(); k++) {
1261 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1263 for (k=0; k<fo->fstype.size(); k++) {
1264 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1266 for (k=0; k<fo->drivetype.size(); k++) {
1267 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1271 foreach_dlist(node, incexe->name_list) {
1272 Dmsg1(400, "F %s\n", node->c_str());
1274 foreach_dlist(node, &incexe->plugin_list) {
1275 Dmsg1(400, "P %s\n", node->c_str());
1279 return ff->fileset->state != state_error;
1284 * As an optimization, we should do this during
1285 * "compile" time in filed/job.c, and keep only a bit mask
1286 * and the Verify options.
1288 static int set_options(findFOPTS *fo, const char *opts)
1294 // Commented out as it is not backward compatible - KES
1296 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1299 for (p=opts; *p; p++) {
1301 case 'a': /* alway replace */
1302 case '0': /* no option */
1305 fo->flags |= FO_EXCLUDE;
1308 fo->flags |= FO_MULTIFS;
1310 case 'h': /* no recursion */
1311 fo->flags |= FO_NO_RECURSION;
1313 case 'H': /* no hard link handling */
1314 fo->flags |= FO_NO_HARDLINK;
1317 fo->flags |= FO_IGNORECASE;
1320 fo->flags |= FO_MD5;
1323 fo->flags |= FO_NOREPLACE;
1325 case 'p': /* use portable data format */
1326 fo->flags |= FO_PORTABLE;
1328 case 'R': /* Resource forks and Finder Info */
1329 fo->flags |= FO_HFSPLUS;
1331 case 'r': /* read fifo */
1332 fo->flags |= FO_READFIFO;
1337 fo->flags |= FO_SHA1;
1342 fo->flags |= FO_SHA256;
1346 fo->flags |= FO_SHA512;
1352 * If 2 or 3 is seen here, SHA2 is not configured, so
1353 * eat the option, and drop back to SHA-1.
1355 if (p[1] == '2' || p[1] == '3') {
1358 fo->flags |= FO_SHA1;
1363 fo->flags |= FO_SPARSE;
1366 fo->flags |= FO_MTIMEONLY;
1369 fo->flags |= FO_KEEPATIME;
1372 fo->flags |= FO_ACL;
1374 case 'V': /* verify options */
1375 /* Copy Verify Options */
1376 for (j=0; *p && *p != ':'; p++) {
1377 fo->VerifyOpts[j] = *p;
1378 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1382 fo->VerifyOpts[j] = 0;
1384 case 'C': /* accurate options */
1385 /* Copy Accurate Options */
1386 for (j=0; *p && *p != ':'; p++) {
1387 fo->AccurateOpts[j] = *p;
1388 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1392 fo->AccurateOpts[j] = 0;
1394 case 'J': /* Basejob options */
1395 /* Copy BaseJob Options */
1396 for (j=0; *p && *p != ':'; p++) {
1397 fo->BaseJobOpts[j] = *p;
1398 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1402 fo->BaseJobOpts[j] = 0;
1404 case 'P': /* strip path */
1407 for (j=0; *p && *p != ':'; p++) {
1409 if (j < (int)sizeof(strip) - 1) {
1414 fo->strip_path = atoi(strip);
1415 fo->flags |= FO_STRIPPATH;
1416 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1419 fo->flags |= FO_IF_NEWER;
1422 fo->flags |= FO_ENHANCEDWILD;
1424 case 'Z': /* gzip compression */
1425 fo->flags |= FO_GZIP;
1426 fo->GZIP_level = *++p - '0';
1429 fo->flags |= FO_NOATIME;
1432 fo->flags |= FO_CHKCHANGES;
1435 fo->flags |= FO_HONOR_NODUMP;
1438 fo->flags |= FO_XATTR;
1441 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1445 return state_options;
1450 * Director is passing his Fileset
1452 static int fileset_cmd(JCR *jcr)
1454 BSOCK *dir = jcr->dir_bsock;
1457 #if defined(WIN32_VSS)
1460 sscanf(dir->msg, "fileset vss=%d", &vss);
1464 if (!init_fileset(jcr)) {
1467 while (dir->recv() >= 0) {
1468 strip_trailing_junk(dir->msg);
1469 Dmsg1(500, "Fileset: %s\n", dir->msg);
1470 add_fileset(jcr, dir->msg);
1472 if (!term_fileset(jcr)) {
1475 rtnstat = dir->fsend(OKinc);
1476 generate_plugin_event(jcr, bEventEndFileSet);
1480 static void free_bootstrap(JCR *jcr)
1482 if (jcr->RestoreBootstrap) {
1483 unlink(jcr->RestoreBootstrap);
1484 free_pool_memory(jcr->RestoreBootstrap);
1485 jcr->RestoreBootstrap = NULL;
1490 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1491 static uint32_t bsr_uniq = 0;
1494 * The Director sends us the bootstrap file, which
1495 * we will in turn pass to the SD.
1496 * Deprecated. The bsr is now sent directly from the
1497 * Director to the SD.
1499 static int bootstrap_cmd(JCR *jcr)
1501 BSOCK *dir = jcr->dir_bsock;
1502 POOLMEM *fname = get_pool_memory(PM_FNAME);
1505 free_bootstrap(jcr);
1508 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1509 jcr->Job, bsr_uniq);
1511 Dmsg1(400, "bootstrap=%s\n", fname);
1512 jcr->RestoreBootstrap = fname;
1513 bs = fopen(fname, "a+b"); /* create file */
1516 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1517 jcr->RestoreBootstrap, be.bstrerror());
1519 * Suck up what he is sending to us so that he will then
1520 * read our error message.
1522 while (dir->recv() >= 0)
1524 free_bootstrap(jcr);
1525 jcr->setJobStatus(JS_ErrorTerminated);
1529 while (dir->recv() >= 0) {
1530 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1531 fputs(dir->msg, bs);
1535 * Note, do not free the bootstrap yet -- it needs to be
1538 return dir->fsend(OKbootstrap);
1543 * Get backup level from Director
1546 static int level_cmd(JCR *jcr)
1548 BSOCK *dir = jcr->dir_bsock;
1549 POOLMEM *level, *buf = NULL;
1552 level = get_memory(dir->msglen+1);
1553 Dmsg1(10, "level_cmd: %s", dir->msg);
1555 /* keep compatibility with older directors */
1556 if (strstr(dir->msg, "accurate")) {
1557 jcr->accurate = true;
1559 if (strstr(dir->msg, "incomplete")) {
1560 jcr->incomplete = true;
1562 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1565 /* Base backup requested? */
1566 if (strcmp(level, "base") == 0) {
1567 jcr->setJobLevel(L_BASE);
1568 /* Full backup requested? */
1569 } else if (strcmp(level, "full") == 0) {
1570 jcr->setJobLevel(L_FULL);
1571 } else if (strstr(level, "differential")) {
1572 jcr->setJobLevel(L_DIFFERENTIAL);
1575 } else if (strstr(level, "incremental")) {
1576 jcr->setJobLevel(L_INCREMENTAL);
1580 * We get his UTC since time, then sync the clocks and correct it
1581 * to agree with our clock.
1583 } else if (strcmp(level, "since_utime") == 0) {
1584 buf = get_memory(dir->msglen+1);
1585 utime_t since_time, adj;
1586 btime_t his_time, bt_start, rt=0, bt_adj=0;
1587 if (jcr->getJobLevel() == L_NONE) {
1588 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1590 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1591 buf, &mtime_only) != 2) {
1594 since_time = str_to_uint64(buf); /* this is the since time */
1595 Dmsg1(100, "since_time=%lld\n", since_time);
1596 char ed1[50], ed2[50];
1598 * Sync clocks by polling him for the time. We take
1599 * 10 samples of his time throwing out the first two.
1601 for (int i=0; i<10; i++) {
1602 bt_start = get_current_btime();
1603 dir->signal(BNET_BTIME); /* poll for time */
1604 if (dir->recv() <= 0) { /* get response */
1607 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1610 if (i < 2) { /* toss first two results */
1613 his_time = str_to_uint64(buf);
1614 rt = get_current_btime() - bt_start; /* compute round trip time */
1615 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1616 edit_uint64(bt_start, ed2));
1617 bt_adj += bt_start - his_time - rt/2;
1618 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1621 bt_adj = bt_adj / 8; /* compute average time */
1622 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1623 adj = btime_to_utime(bt_adj);
1624 since_time += adj; /* adjust for clock difference */
1625 /* Don't notify if time within 3 seconds */
1626 if (adj > 3 || adj < -3) {
1628 if (adj > 600 || adj < -600) {
1633 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1635 dir->signal(BNET_EOD);
1637 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1638 jcr->incremental = 1; /* set incremental or decremental backup */
1639 jcr->mtime = since_time; /* set since time */
1640 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1642 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1650 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1651 return dir->fsend(OKlevel);
1654 pm_strcpy(jcr->errmsg, dir->msg);
1655 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1664 * Get session parameters from Director -- this is for a Restore command
1665 * This is deprecated. It is now passed via the bsr.
1667 static int session_cmd(JCR *jcr)
1669 BSOCK *dir = jcr->dir_bsock;
1671 Dmsg1(100, "SessionCmd: %s", dir->msg);
1672 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1673 &jcr->VolSessionId, &jcr->VolSessionTime,
1674 &jcr->StartFile, &jcr->EndFile,
1675 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1676 pm_strcpy(jcr->errmsg, dir->msg);
1677 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1681 return dir->fsend(OKsession);
1684 static void set_storage_auth_key(JCR *jcr, char *key)
1686 /* if no key don't update anything */
1692 * We can be contacting multiple storage daemons.
1693 * So, make sure that any old jcr->store_bsock is cleaned up.
1695 if (jcr->store_bsock) {
1696 jcr->store_bsock->destroy();
1697 jcr->store_bsock = NULL;
1701 * We can be contacting multiple storage daemons.
1702 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1704 if (jcr->sd_auth_key) {
1706 * If we already have a Authorization key, director can do multi
1709 Dmsg0(5, "set multi_restore=true\n");
1710 jcr->multi_restore = true;
1711 bfree(jcr->sd_auth_key);
1714 jcr->sd_auth_key = bstrdup(key);
1715 Dmsg0(5, "set sd auth key\n");
1719 * Get address of storage daemon from Director
1722 static int storage_cmd(JCR *jcr)
1724 int stored_port; /* storage daemon port */
1725 int enable_ssl; /* enable ssl to sd */
1726 POOL_MEM sd_auth_key(PM_MESSAGE);
1727 BSOCK *dir = jcr->dir_bsock;
1728 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1731 Dmsg1(100, "StorageCmd: %s", dir->msg);
1732 sd_auth_key.check_size(dir->msglen);
1733 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1734 &enable_ssl, sd_auth_key.c_str()) != 4) {
1735 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1736 &stored_port, &enable_ssl) != 3) {
1737 pm_strcpy(jcr->errmsg, dir->msg);
1738 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1743 set_storage_auth_key(jcr, sd_auth_key.c_str());
1745 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1747 /* Open command communications with Storage daemon */
1748 /* Try to connect for 1 hour at 10 second intervals */
1750 sd->set_source_address(me->FDsrc_addr);
1752 /* TODO: see if we put limit on restore and backup... */
1753 if (!jcr->max_bandwidth) {
1754 if (jcr->director->max_bandwidth_per_job) {
1755 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
1757 } else if (me->max_bandwidth_per_job) {
1758 jcr->max_bandwidth = me->max_bandwidth_per_job;
1761 sd->set_bwlimit(jcr->max_bandwidth);
1763 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1764 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1770 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1771 jcr->stored_addr, stored_port);
1772 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1773 jcr->stored_addr, stored_port);
1776 Dmsg0(110, "Connection OK to SD.\n");
1778 jcr->store_bsock = sd;
1780 sd->fsend("Hello Start Job %s\n", jcr->Job);
1781 if (!authenticate_storagedaemon(jcr)) {
1782 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1785 Dmsg0(110, "Authenticated with SD.\n");
1787 /* Send OK to Director */
1788 return dir->fsend(OKstore);
1791 dir->fsend(BADcmd, "storage");
1800 static int backup_cmd(JCR *jcr)
1802 BSOCK *dir = jcr->dir_bsock;
1803 BSOCK *sd = jcr->store_bsock;
1808 #if defined(WIN32_VSS)
1809 // capture state here, if client is backed up by multiple directors
1810 // and one enables vss and the other does not then enable_vss can change
1811 // between here and where its evaluated after the job completes.
1812 jcr->VSS = g_pVSSClient && enable_vss;
1814 /* Run only one at a time */
1819 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1820 jcr->JobFiles = FileIndex;
1821 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1825 * Validate some options given to the backup make sense for the compiled in
1826 * options of this filed.
1828 if (jcr->ff->flags & FO_ACL && !have_acl) {
1829 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1832 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1833 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1837 jcr->setJobStatus(JS_Blocked);
1838 jcr->setJobType(JT_BACKUP);
1839 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1842 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1843 dir->fsend(BADcmd, "backup");
1847 dir->fsend(OKbackup);
1848 Dmsg1(110, "filed>dird: %s", dir->msg);
1851 * Send Append Open Session to Storage daemon
1853 sd->fsend(append_open);
1854 Dmsg1(110, ">stored: %s", sd->msg);
1856 * Expect to receive back the Ticket number
1858 if (bget_msg(sd) >= 0) {
1859 Dmsg1(110, "<stored: %s", sd->msg);
1860 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1861 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1864 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1866 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1871 * Send Append data command to Storage daemon
1873 sd->fsend(append_data, jcr->Ticket);
1874 Dmsg1(110, ">stored: %s", sd->msg);
1877 * Expect to get OK data
1879 Dmsg1(110, "<stored: %s", sd->msg);
1880 if (!response(jcr, sd, OK_data, "Append Data")) {
1884 generate_daemon_event(jcr, "JobStart");
1885 generate_plugin_event(jcr, bEventStartBackupJob);
1887 #if defined(WIN32_VSS)
1888 /* START VSS ON WIN32 */
1890 if (g_pVSSClient->InitializeForBackup(jcr)) {
1891 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1892 /* tell vss which drives to snapshot */
1893 char szWinDriveLetters[27];
1894 *szWinDriveLetters=0;
1895 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
1896 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1897 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1898 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1900 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
1902 /* tell user if snapshot creation of a specific drive failed */
1904 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1905 if (islower(szWinDriveLetters[i])) {
1906 Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"), szWinDriveLetters[i]);
1909 /* inform user about writer states */
1910 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1911 if (g_pVSSClient->GetWriterState(i) < 1) {
1912 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1917 Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
1921 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"), be.bstrerror());
1923 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1928 * Send Files to Storage daemon
1930 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1931 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1932 jcr->setJobStatus(JS_ErrorTerminated);
1933 bnet_suppress_error_messages(sd, 1);
1934 Dmsg0(110, "Error in blast_data.\n");
1936 jcr->setJobStatus(JS_Terminated);
1937 /* Note, the above set status will not override an error */
1938 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1939 bnet_suppress_error_messages(sd, 1);
1940 goto cleanup; /* bail out now */
1943 * Expect to get response to append_data from Storage daemon
1945 if (!response(jcr, sd, OK_append, "Append Data")) {
1946 jcr->setJobStatus(JS_ErrorTerminated);
1951 * Send Append End Data to Storage daemon
1953 sd->fsend(append_end, jcr->Ticket);
1955 if (!response(jcr, sd, OK_end, "Append End")) {
1956 jcr->setJobStatus(JS_ErrorTerminated);
1961 * Send Append Close to Storage daemon
1963 sd->fsend(append_close, jcr->Ticket);
1964 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1965 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1967 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1971 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1974 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1975 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1981 #if defined(WIN32_VSS)
1983 Win32ConvCleanupCache();
1984 g_pVSSClient->DestroyWriterInfo();
1989 generate_plugin_event(jcr, bEventEndBackupJob);
1990 return 0; /* return and stop command loop */
1994 * Do a Verify for Director
1997 static int verify_cmd(JCR *jcr)
1999 BSOCK *dir = jcr->dir_bsock;
2000 BSOCK *sd = jcr->store_bsock;
2003 jcr->setJobType(JT_VERIFY);
2004 if (sscanf(dir->msg, verifycmd, level) != 1) {
2005 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2009 if (strcasecmp(level, "init") == 0) {
2010 jcr->setJobLevel(L_VERIFY_INIT);
2011 } else if (strcasecmp(level, "catalog") == 0){
2012 jcr->setJobLevel(L_VERIFY_CATALOG);
2013 } else if (strcasecmp(level, "volume") == 0){
2014 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2015 } else if (strcasecmp(level, "data") == 0){
2016 jcr->setJobLevel(L_VERIFY_DATA);
2017 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2018 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2020 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2024 dir->fsend(OKverify);
2026 generate_daemon_event(jcr, "JobStart");
2027 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
2028 generate_plugin_event(jcr, bEventStartVerifyJob);
2030 Dmsg1(110, "filed>dird: %s", dir->msg);
2032 switch (jcr->getJobLevel()) {
2034 case L_VERIFY_CATALOG:
2037 case L_VERIFY_VOLUME_TO_CATALOG:
2038 if (!open_sd_read_session(jcr)) {
2041 start_dir_heartbeat(jcr);
2042 do_verify_volume(jcr);
2043 stop_dir_heartbeat(jcr);
2045 * Send Close session command to Storage daemon
2047 sd->fsend(read_close, jcr->Ticket);
2048 Dmsg1(130, "filed>stored: %s", sd->msg);
2050 /* ****FIXME**** check response */
2051 bget_msg(sd); /* get OK */
2053 /* Inform Storage daemon that we are done */
2054 sd->signal(BNET_TERMINATE);
2057 case L_VERIFY_DISK_TO_CATALOG:
2061 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2065 dir->signal(BNET_EOD);
2066 generate_plugin_event(jcr, bEventEndVerifyJob);
2067 return 0; /* return and terminate command loop */
2071 static bool vss_restore_init_callback(JCR *jcr, int init_type)
2073 switch (init_type) {
2074 case VSS_INIT_RESTORE_AFTER_INIT:
2075 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
2077 case VSS_INIT_RESTORE_AFTER_GATHER:
2078 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
2088 * Do a Restore for Director
2091 static int restore_cmd(JCR *jcr)
2093 BSOCK *dir = jcr->dir_bsock;
2094 BSOCK *sd = jcr->store_bsock;
2096 bool use_regexwhere=false;
2101 * Scan WHERE (base directory for restore) from command
2103 Dmsg0(100, "restore command\n");
2104 #if defined(WIN32_VSS)
2107 * No need to enable VSS for restore if we do not have plugin
2110 enable_vss = jcr->job_metadata != NULL;
2112 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
2113 // capture state here, if client is backed up by multiple directors
2114 // and one enables vss and the other does not then enable_vss can change
2115 // between here and where its evaluated after the job completes.
2116 jcr->VSS = g_pVSSClient && enable_vss;
2118 /* Run only one at a time */
2122 /* Pickup where string */
2123 args = get_memory(dir->msglen+1);
2126 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2127 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
2128 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2129 pm_strcpy(jcr->errmsg, dir->msg);
2130 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2135 use_regexwhere = true;
2137 /* Turn / into nothing */
2138 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2142 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2143 unbash_spaces(args);
2145 if (use_regexwhere) {
2146 jcr->where_bregexp = get_bregexps(args);
2147 if (!jcr->where_bregexp) {
2148 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2149 free_pool_memory(args);
2153 jcr->where = bstrdup(args);
2156 free_pool_memory(args);
2157 jcr->replace = replace;
2158 jcr->prefix_links = prefix_links;
2160 dir->fsend(OKrestore);
2161 Dmsg1(110, "filed>dird: %s", dir->msg);
2163 jcr->setJobType(JT_RESTORE);
2165 jcr->setJobStatus(JS_Blocked);
2167 if (!open_sd_read_session(jcr)) {
2168 jcr->setJobStatus(JS_ErrorTerminated);
2172 jcr->setJobStatus(JS_Running);
2175 * Do restore of files and data
2177 start_dir_heartbeat(jcr);
2178 generate_daemon_event(jcr, "JobStart");
2179 generate_plugin_event(jcr, bEventStartRestoreJob);
2181 #if defined(WIN32_VSS)
2182 /* START VSS ON WIN32 */
2184 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
2185 (WCHAR *)jcr->job_metadata)) {
2187 /* inform user about writer states */
2189 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
2190 if (g_pVSSClient->GetWriterState(i) < 1) {
2191 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
2197 int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
2198 write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
2202 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2204 free_and_null_pool_memory(jcr->job_metadata);
2205 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2210 stop_dir_heartbeat(jcr);
2212 jcr->setJobStatus(JS_Terminated);
2213 if (jcr->JobStatus != JS_Terminated) {
2214 bnet_suppress_error_messages(sd, 1);
2218 * Send Close session command to Storage daemon
2220 sd->fsend(read_close, jcr->Ticket);
2221 Dmsg1(100, "filed>stored: %s", sd->msg);
2223 bget_msg(sd); /* get OK */
2225 /* Inform Storage daemon that we are done */
2226 sd->signal(BNET_TERMINATE);
2228 #if defined(WIN32_VSS)
2229 /* STOP VSS ON WIN32 */
2230 /* tell vss to close the restore session */
2231 Dmsg0(100, "About to call CloseRestore\n");
2233 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2234 Dmsg0(100, "Really about to call CloseRestore\n");
2235 if (g_pVSSClient->CloseRestore()) {
2236 Dmsg0(100, "CloseRestore success\n");
2237 /* inform user about writer states */
2238 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2239 int msg_type = M_INFO;
2240 if (g_pVSSClient->GetWriterState(i) < 1) {
2241 //msg_type = M_WARNING;
2244 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2248 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2254 bfree_and_null(jcr->where);
2256 if (jcr->JobErrors) {
2257 jcr->setJobStatus(JS_ErrorTerminated);
2260 Dmsg0(100, "Done in job.c\n");
2263 if (jcr->multi_restore) {
2264 Dmsg0(100, OKstoreend);
2265 dir->fsend(OKstoreend);
2266 ret = 1; /* we continue the loop, waiting for next part */
2268 end_restore_cmd(jcr);
2269 ret = 0; /* we stop here */
2272 if (job_canceled(jcr)) {
2273 ret = 0; /* we stop here */
2279 static int end_restore_cmd(JCR *jcr)
2281 Dmsg0(5, "end_restore_cmd\n");
2282 generate_plugin_event(jcr, bEventEndRestoreJob);
2283 return 0; /* return and terminate command loop */
2286 static int open_sd_read_session(JCR *jcr)
2288 BSOCK *sd = jcr->store_bsock;
2291 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2294 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2295 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2296 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2298 * Open Read Session with Storage daemon
2300 sd->fsend(read_open, "DummyVolume",
2301 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2302 jcr->StartBlock, jcr->EndBlock);
2303 Dmsg1(110, ">stored: %s", sd->msg);
2308 if (bget_msg(sd) >= 0) {
2309 Dmsg1(110, "filed<stored: %s", sd->msg);
2310 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2311 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2314 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2316 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2320 if (!send_bootstrap_file(jcr)) {
2325 * Start read of data with Storage daemon
2327 sd->fsend(read_data, jcr->Ticket);
2328 Dmsg1(110, ">stored: %s", sd->msg);
2333 if (!response(jcr, sd, OK_data, "Read Data")) {
2340 * Destroy the Job Control Record and associated
2341 * resources (sockets).
2343 static void filed_free_jcr(JCR *jcr)
2345 if (jcr->store_bsock) {
2346 jcr->store_bsock->close();
2348 free_bootstrap(jcr);
2349 if (jcr->last_fname) {
2350 free_pool_memory(jcr->last_fname);
2352 free_runscripts(jcr->RunScripts);
2353 delete jcr->RunScripts;
2355 if (jcr->JobId != 0)
2356 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2362 * Get response from Storage daemon to a command we
2363 * sent. Check that the response is OK.
2365 * Returns: 0 on failure
2368 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2373 if (bget_msg(sd) > 0) {
2374 Dmsg0(110, sd->msg);
2375 if (strcmp(sd->msg, resp) == 0) {
2379 if (job_canceled(jcr)) {
2380 return 0; /* if canceled avoid useless error messages */
2382 if (is_bnet_error(sd)) {
2383 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2384 cmd, bnet_strerror(sd));
2386 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2387 cmd, resp, sd->msg);
2392 static int send_bootstrap_file(JCR *jcr)
2396 BSOCK *sd = jcr->store_bsock;
2397 const char *bootstrap = "bootstrap\n";
2400 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2401 if (!jcr->RestoreBootstrap) {
2404 bs = fopen(jcr->RestoreBootstrap, "rb");
2407 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2408 jcr->RestoreBootstrap, be.bstrerror());
2409 jcr->setJobStatus(JS_ErrorTerminated);
2412 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2414 while (fgets(buf, sizeof(buf), bs)) {
2415 sd->msglen = Mmsg(sd->msg, "%s", buf);
2418 sd->signal(BNET_EOD);
2420 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2421 jcr->setJobStatus(JS_ErrorTerminated);
2427 free_bootstrap(jcr);