2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 two of the GNU 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 General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula File Daemon Job processing
31 * Kern Sibbald, October MM
38 #if defined(WIN32_VSS)
41 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int enable_vss = 0;
46 * As Windows saves ACLs as part of the standard backup stream
47 * we just pretend here that is has implicit acl support.
49 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
50 const bool have_acl = true;
52 const bool have_acl = false;
55 #if defined(HAVE_XATTR)
56 const bool have_xattr = true;
58 const bool have_xattr = false;
61 extern CLIENT *me; /* our client resource */
63 /* Imported functions */
64 extern int status_cmd(JCR *jcr);
65 extern int qstatus_cmd(JCR *jcr);
66 extern int accurate_cmd(JCR *jcr);
68 /* Forward referenced functions */
69 static int backup_cmd(JCR *jcr);
70 static int bootstrap_cmd(JCR *jcr);
71 static int cancel_cmd(JCR *jcr);
72 static int setdebug_cmd(JCR *jcr);
73 static int estimate_cmd(JCR *jcr);
74 static int hello_cmd(JCR *jcr);
75 static int job_cmd(JCR *jcr);
76 static int fileset_cmd(JCR *jcr);
77 static int level_cmd(JCR *jcr);
78 static int verify_cmd(JCR *jcr);
79 static int restore_cmd(JCR *jcr);
80 static int end_restore_cmd(JCR *jcr);
81 static int storage_cmd(JCR *jcr);
82 static int session_cmd(JCR *jcr);
83 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
84 static void filed_free_jcr(JCR *jcr);
85 static int open_sd_read_session(JCR *jcr);
86 static int send_bootstrap_file(JCR *jcr);
87 static int runscript_cmd(JCR *jcr);
88 static int runbefore_cmd(JCR *jcr);
89 static int runafter_cmd(JCR *jcr);
90 static int runbeforenow_cmd(JCR *jcr);
91 static int restore_object_cmd(JCR *jcr);
92 static void set_options(findFOPTS *fo, const char *opts);
93 static void set_storage_auth_key(JCR *jcr, char *key);
95 /* Exported functions */
100 int monitoraccess; /* specify if monitors have access to this function */
104 * The following are the recognized commands from the Director.
106 static struct s_cmds cmds[] = {
107 {"backup", backup_cmd, 0},
108 {"cancel", cancel_cmd, 0},
109 {"setdebug=", setdebug_cmd, 0},
110 {"estimate", estimate_cmd, 0},
111 {"Hello", hello_cmd, 1},
112 {"fileset", fileset_cmd, 0},
113 {"JobId=", job_cmd, 0},
114 {"level = ", level_cmd, 0},
115 {"restore ", restore_cmd, 0},
116 {"endrestore", end_restore_cmd, 0},
117 {"session", session_cmd, 0},
118 {"status", status_cmd, 1},
119 {".status", qstatus_cmd, 1},
120 {"storage ", storage_cmd, 0},
121 {"verify", verify_cmd, 0},
122 {"bootstrap", bootstrap_cmd, 0},
123 {"RunBeforeNow", runbeforenow_cmd, 0},
124 {"RunBeforeJob", runbefore_cmd, 0},
125 {"RunAfterJob", runafter_cmd, 0},
126 {"Run", runscript_cmd, 0},
127 {"accurate", accurate_cmd, 0},
128 {"restoreobject", restore_object_cmd, 0},
129 {NULL, NULL} /* list terminator */
132 /* Commands received from director that need scanning */
133 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
134 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
135 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
136 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
137 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
138 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
139 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
140 static char restoreobjcmd[] = "restoreobject JobId=%u ObjLen=%d ObjInx=%d ObjType=%d FI=%d\n";
141 static char endrestoreobjectcmd[] = "restoreobject end\n";
142 static char verifycmd[] = "verify level=%30s";
143 static char estimatecmd[] = "estimate listing=%d";
144 static char runbefore[] = "RunBeforeJob %s";
145 static char runafter[] = "RunAfterJob %s";
146 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
148 /* Responses sent to Director */
149 static char errmsg[] = "2999 Invalid command\n";
150 static char no_auth[] = "2998 No Authorization\n";
151 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
152 static char OKinc[] = "2000 OK include\n";
153 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
154 static char OKlevel[] = "2000 OK level\n";
155 static char OKbackup[] = "2000 OK backup\n";
156 static char OKbootstrap[] = "2000 OK bootstrap\n";
157 static char OKverify[] = "2000 OK verify\n";
158 static char OKrestore[] = "2000 OK restore\n";
159 static char OKsession[] = "2000 OK session\n";
160 static char OKstore[] = "2000 OK storage\n";
161 static char OKstoreend[] = "2000 OK storage end\n";
162 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
163 static char OKsetdebug[] = "2000 OK setdebug=%d\n";
164 static char BADjob[] = "2901 Bad Job\n";
165 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
166 " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
167 static char OKRunBefore[] = "2000 OK RunBefore\n";
168 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
169 static char OKRunAfter[] = "2000 OK RunAfter\n";
170 static char OKRunScript[] = "2000 OK RunScript\n";
171 static char BADcmd[] = "2902 Bad %s\n";
172 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
175 /* Responses received from Storage Daemon */
176 static char OK_end[] = "3000 OK end\n";
177 static char OK_close[] = "3000 OK close Status = %d\n";
178 static char OK_open[] = "3000 OK open ticket = %d\n";
179 static char OK_data[] = "3000 OK data\n";
180 static char OK_append[] = "3000 OK append data\n";
181 static char OKSDbootstrap[]= "3000 OK bootstrap\n";
184 /* Commands sent to Storage Daemon */
185 static char append_open[] = "append open session\n";
186 static char append_data[] = "append data %d\n";
187 static char append_end[] = "append end session %d\n";
188 static char append_close[] = "append close session %d\n";
189 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
190 static char read_data[] = "read data %d\n";
191 static char read_close[] = "read close session %d\n";
194 * Accept requests from a Director
196 * NOTE! We are running as a separate thread
198 * Send output one line
199 * at a time followed by a zero length transmission.
201 * Return when the connection is terminated or there
204 * Basic task here is:
205 * Authenticate Director (during Hello command).
206 * Accept commands one at a time from the Director
209 * Concerning ClientRunBefore/After, the sequence of events
210 * is rather critical. If they are not done in the right
211 * order one can easily get FD->SD timeouts if the script
214 * The current sequence of events is:
215 * 1. Dir starts job with FD
216 * 2. Dir connects to SD
217 * 3. Dir connects to FD
218 * 4. FD connects to SD
219 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
220 * 6. Dir sends include/exclude
221 * 7. FD sends data to SD
222 * 8. SD/FD disconnects while SD despools data and attributes (optional)
223 * 9. FD runs ClientRunAfterJob
226 void *handle_client_request(void *dirp)
231 BSOCK *dir = (BSOCK *)dirp;
232 const char jobname[12] = "*Director*";
235 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
236 jcr->dir_bsock = dir;
237 jcr->ff = init_find_files();
238 // save_cwd.save(jcr);
239 jcr->start_time = time(NULL);
240 jcr->RunScripts = New(alist(10, not_owned_by_alist));
241 jcr->last_fname = get_pool_memory(PM_FNAME);
242 jcr->last_fname[0] = 0;
243 jcr->client_name = get_memory(strlen(my_name) + 1);
244 pm_strcpy(jcr->client_name, my_name);
245 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
246 jcr->crypto.pki_sign = me->pki_sign;
247 jcr->crypto.pki_encrypt = me->pki_encrypt;
248 jcr->crypto.pki_keypair = me->pki_keypair;
249 jcr->crypto.pki_signers = me->pki_signers;
250 jcr->crypto.pki_recipients = me->pki_recipients;
252 enable_backup_privileges(NULL, 1 /* ignore_errors */);
254 /**********FIXME******* add command handler error code */
256 for (quit=false; !quit;) {
258 if (dir->recv() < 0) {
259 break; /* connection terminated */
261 dir->msg[dir->msglen] = 0;
262 Dmsg1(100, "<dird: %s", dir->msg);
264 for (i=0; cmds[i].cmd; i++) {
265 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
266 found = true; /* indicate command found */
267 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
269 dir->signal(BNET_EOD);
272 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
273 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
274 dir->fsend(invalid_cmd);
275 dir->signal(BNET_EOD);
278 Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
279 if (!cmds[i].func(jcr)) { /* do command */
280 quit = true; /* error or fully terminated, get out */
281 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
286 if (!found) { /* command not found */
293 /* Inform Storage daemon that we are done */
294 if (jcr->store_bsock) {
295 jcr->store_bsock->signal(BNET_TERMINATE);
298 /* Run the after job */
299 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
301 if (jcr->JobId) { /* send EndJob if running a job */
302 char ed1[50], ed2[50];
303 /* Send termination status back to Dir */
304 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
305 edit_uint64(jcr->ReadBytes, ed1),
306 edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors, jcr->VSS,
307 jcr->crypto.pki_encrypt);
308 Dmsg1(110, "End FD msg: %s\n", dir->msg);
311 generate_daemon_event(jcr, "JobEnd");
312 generate_plugin_event(jcr, bEventJobEnd);
314 dequeue_messages(jcr); /* send any queued messages */
316 /* Inform Director that we are done */
317 dir->signal(BNET_TERMINATE);
319 free_plugins(jcr); /* release instantiated plugins */
320 free_and_null_pool_memory(jcr->job_metadata);
322 /* Clean up fileset */
323 FF_PKT *ff = jcr->ff;
324 findFILESET *fileset = ff->fileset;
327 /* Delete FileSet Include lists */
328 for (i=0; i<fileset->include_list.size(); i++) {
329 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
330 for (j=0; j<incexe->opts_list.size(); j++) {
331 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
332 for (k=0; k<fo->regex.size(); k++) {
333 regfree((regex_t *)fo->regex.get(k));
335 for (k=0; k<fo->regexdir.size(); k++) {
336 regfree((regex_t *)fo->regexdir.get(k));
338 for (k=0; k<fo->regexfile.size(); k++) {
339 regfree((regex_t *)fo->regexfile.get(k));
342 fo->regexdir.destroy();
343 fo->regexfile.destroy();
345 fo->wilddir.destroy();
346 fo->wildfile.destroy();
347 fo->wildbase.destroy();
349 fo->fstype.destroy();
350 fo->drivetype.destroy();
352 incexe->opts_list.destroy();
353 incexe->name_list.destroy();
354 incexe->plugin_list.destroy();
355 if (incexe->ignoredir) {
356 free(incexe->ignoredir);
359 fileset->include_list.destroy();
361 /* Delete FileSet Exclude lists */
362 for (i=0; i<fileset->exclude_list.size(); i++) {
363 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
364 for (j=0; j<incexe->opts_list.size(); j++) {
365 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
367 fo->regexdir.destroy();
368 fo->regexfile.destroy();
370 fo->wilddir.destroy();
371 fo->wildfile.destroy();
372 fo->wildbase.destroy();
374 fo->fstype.destroy();
375 fo->drivetype.destroy();
377 incexe->opts_list.destroy();
378 incexe->name_list.destroy();
379 incexe->plugin_list.destroy();
380 if (incexe->ignoredir) {
381 free(incexe->ignoredir);
384 fileset->exclude_list.destroy();
388 Dmsg0(100, "Calling term_find_files\n");
389 term_find_files(jcr->ff);
390 // save_cwd.restore(jcr);
391 // save_cwd.release();
393 Dmsg0(100, "Done with term_find_files\n");
394 free_jcr(jcr); /* destroy JCR record */
395 Dmsg0(100, "Done with free_jcr\n");
401 * Hello from Director he must identify himself and provide his
404 static int hello_cmd(JCR *jcr)
406 Dmsg0(120, "Calling Authenticate\n");
407 if (!authenticate_director(jcr)) {
410 Dmsg0(120, "OK Authenticate\n");
411 jcr->authenticated = true;
418 static int cancel_cmd(JCR *jcr)
420 BSOCK *dir = jcr->dir_bsock;
421 char Job[MAX_NAME_LENGTH];
424 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
425 if (!(cjcr=get_jcr_by_full_name(Job))) {
426 dir->fsend(_("2901 Job %s not found.\n"), Job);
428 if (cjcr->store_bsock) {
429 cjcr->store_bsock->set_timed_out();
430 cjcr->store_bsock->set_terminated();
431 pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
433 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
434 set_jcr_job_status(cjcr, JS_Canceled);
436 dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
439 dir->fsend(_("2902 Error scanning cancel command.\n"));
441 dir->signal(BNET_EOD);
447 * Set debug level as requested by the Director
450 static int setdebug_cmd(JCR *jcr)
452 BSOCK *dir = jcr->dir_bsock;
453 int level, trace_flag;
455 Dmsg1(110, "setdebug_cmd: %s", dir->msg);
456 if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
457 pm_strcpy(jcr->errmsg, dir->msg);
458 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
462 set_trace(trace_flag);
463 return dir->fsend(OKsetdebug, level);
467 static int estimate_cmd(JCR *jcr)
469 BSOCK *dir = jcr->dir_bsock;
470 char ed1[50], ed2[50];
472 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
473 pm_strcpy(jcr->errmsg, dir->msg);
474 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
475 dir->fsend(_("2992 Bad estimate command.\n"));
479 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
480 edit_uint64_with_commas(jcr->JobBytes, ed2));
481 dir->signal(BNET_EOD);
486 * Get JobId and Storage Daemon Authorization key from Director
488 static int job_cmd(JCR *jcr)
490 BSOCK *dir = jcr->dir_bsock;
491 POOL_MEM sd_auth_key(PM_MESSAGE);
492 sd_auth_key.check_size(dir->msglen);
494 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
495 &jcr->VolSessionId, &jcr->VolSessionTime,
496 sd_auth_key.c_str()) != 5) {
497 pm_strcpy(jcr->errmsg, dir->msg);
498 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
502 set_storage_auth_key(jcr, sd_auth_key.c_str());
503 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
504 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
505 new_plugins(jcr); /* instantiate plugins for this jcr */
506 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
507 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
510 static int runbefore_cmd(JCR *jcr)
513 BSOCK *dir = jcr->dir_bsock;
514 POOLMEM *cmd = get_memory(dir->msglen+1);
517 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
518 if (sscanf(dir->msg, runbefore, cmd) != 1) {
519 pm_strcpy(jcr->errmsg, dir->msg);
520 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
521 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
527 /* Run the command now */
528 script = new_runscript();
529 script->set_command(cmd);
530 script->when = SCRIPT_Before;
531 ok = script->run(jcr, "ClientRunBeforeJob");
532 free_runscript(script);
536 dir->fsend(OKRunBefore);
539 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
544 static int runbeforenow_cmd(JCR *jcr)
546 BSOCK *dir = jcr->dir_bsock;
548 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
549 if (job_canceled(jcr)) {
550 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
551 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
554 dir->fsend(OKRunBeforeNow);
555 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
560 static int runafter_cmd(JCR *jcr)
562 BSOCK *dir = jcr->dir_bsock;
563 POOLMEM *msg = get_memory(dir->msglen+1);
566 Dmsg1(100, "runafter_cmd: %s", dir->msg);
567 if (sscanf(dir->msg, runafter, msg) != 1) {
568 pm_strcpy(jcr->errmsg, dir->msg);
569 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
570 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
576 cmd = new_runscript();
577 cmd->set_command(msg);
578 cmd->on_success = true;
579 cmd->on_failure = false;
580 cmd->when = SCRIPT_After;
582 jcr->RunScripts->append(cmd);
584 free_pool_memory(msg);
585 return dir->fsend(OKRunAfter);
588 static int runscript_cmd(JCR *jcr)
590 BSOCK *dir = jcr->dir_bsock;
591 POOLMEM *msg = get_memory(dir->msglen+1);
592 int on_success, on_failure, fail_on_error;
594 RUNSCRIPT *cmd = new_runscript() ;
596 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
597 /* Note, we cannot sscanf into bools */
598 if (sscanf(dir->msg, runscript, &on_success,
603 pm_strcpy(jcr->errmsg, dir->msg);
604 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
605 dir->fsend(_("2905 Bad RunScript command.\n"));
610 cmd->on_success = on_success;
611 cmd->on_failure = on_failure;
612 cmd->fail_on_error = fail_on_error;
615 cmd->set_command(msg);
617 jcr->RunScripts->append(cmd);
619 free_pool_memory(msg);
620 return dir->fsend(OKRunScript);
623 static int restore_object_cmd(JCR *jcr)
625 BSOCK *dir = jcr->dir_bsock;
626 POOLMEM *msg = get_memory(dir->msglen+1);
628 restore_object_pkt rop;
630 memset(&rop, 0, sizeof(rop));
631 rop.pkt_size = sizeof(rop);
632 rop.pkt_end = sizeof(rop);
633 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
634 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
635 generate_plugin_event(jcr, bEventRestoreObject, NULL);
637 return dir->fsend(OKRestoreObject);
640 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
641 &rop.object_index, &rop.object_type, &FileIndex) != 5) {
642 Dmsg0(5, "Bad restore object command\n");
643 pm_strcpy(jcr->errmsg, dir->msg);
644 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
648 // Dmsg5(000, "Recv object: JobId=%u objlen=%d objinx=%d objtype=%d FI=%d\n",
649 // JobId, object_len, object_index, object_type, FileIndex);
650 /* Read Object name */
651 if (dir->recv() < 0) {
654 // Dmsg2(000, "Recv Fname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
655 rop.object_name = bstrdup(dir->msg);
657 // Dmsg2(000, "Recv Path object: len=%d Path=%s\n", dir->msglen, dir->msg);
660 if (dir->recv() < 0) {
663 rop.object = dir->msg;
664 // Dmsg2(000, "Recv Object: len=%d Object=%s\n", dir->msglen, dir->msg);
666 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
667 Dmsg0(000, "got job metadata\n");
668 free_and_null_pool_memory(jcr->job_metadata);
669 jcr->job_metadata = rop.object;
673 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
676 if (rop.object_name) {
677 free(rop.object_name);
680 dir->msg = get_pool_memory(PM_MESSAGE);
684 Dmsg1(100, "Send: %s", OKRestoreObject);
688 dir->fsend(_("2909 Bad RestoreObject command.\n"));
695 static bool init_fileset(JCR *jcr)
698 findFILESET *fileset;
707 fileset = (findFILESET *)malloc(sizeof(findFILESET));
708 memset(fileset, 0, sizeof(findFILESET));
709 ff->fileset = fileset;
710 fileset->state = state_none;
711 fileset->include_list.init(1, true);
712 fileset->exclude_list.init(1, true);
716 static findFOPTS *start_options(FF_PKT *ff)
718 int state = ff->fileset->state;
719 findINCEXE *incexe = ff->fileset->incexe;
721 if (state != state_options) {
722 ff->fileset->state = state_options;
723 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
724 memset(fo, 0, sizeof(findFOPTS));
725 fo->regex.init(1, true);
726 fo->regexdir.init(1, true);
727 fo->regexfile.init(1, true);
728 fo->wild.init(1, true);
729 fo->wilddir.init(1, true);
730 fo->wildfile.init(1, true);
731 fo->wildbase.init(1, true);
732 fo->base.init(1, true);
733 fo->fstype.init(1, true);
734 fo->drivetype.init(1, true);
735 incexe->current_opts = fo;
736 incexe->opts_list.append(fo);
738 return incexe->current_opts;
743 * Add fname to include/exclude fileset list. First check for
744 * | and < and if necessary perform command.
746 void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
761 p++; /* skip over | */
762 fn = get_pool_memory(PM_FNAME);
763 fn = edit_job_codes(jcr, fn, p, "");
764 bpipe = open_bpipe(fn, 0, "r");
767 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
769 free_pool_memory(fn);
772 free_pool_memory(fn);
773 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
774 strip_trailing_junk(buf);
776 fileset->incexe->name_list.append(new_dlistString(buf));
778 fileset->incexe->plugin_list.append(new_dlistString(buf));
781 if ((stat=close_bpipe(bpipe)) != 0) {
783 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
784 p, be.code(stat), be.bstrerror(stat));
789 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
790 p++; /* skip over < */
791 if ((ffd = fopen(p, "rb")) == NULL) {
793 Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
797 while (fgets(buf, sizeof(buf), ffd)) {
798 strip_trailing_junk(buf);
799 Dmsg1(100, "%s\n", buf);
801 fileset->incexe->name_list.append(new_dlistString(buf));
803 fileset->incexe->plugin_list.append(new_dlistString(buf));
810 fileset->incexe->name_list.append(new_dlistString(fname));
812 if (me->plugin_directory) {
813 fileset->incexe->plugin_list.append(new_dlistString(fname));
815 Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
824 * Define a new Exclude block in the FileSet
826 findFILESET *new_exclude(JCR *jcr)
828 FF_PKT *ff = jcr->ff;
829 findFILESET *fileset = ff->fileset;
832 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
833 memset(fileset->incexe, 0, sizeof(findINCEXE));
834 fileset->incexe->opts_list.init(1, true);
835 fileset->incexe->name_list.init();
836 fileset->incexe->plugin_list.init();
837 fileset->exclude_list.append(fileset->incexe);
842 static void add_fileset(JCR *jcr, const char *item)
844 FF_PKT *ff = jcr->ff;
845 findFILESET *fileset = ff->fileset;
846 int state = fileset->state;
847 findFOPTS *current_opts;
849 /* Get code, optional subcode, and position item past the dividing space */
850 Dmsg1(100, "%s\n", item);
855 int subcode = ' '; /* A space is always a valid subcode */
856 if (item[0] != '\0' && item[0] != ' ') {
864 /* Skip all lines we receive after an error */
865 if (state == state_error) {
866 Dmsg0(100, "State=error return\n");
871 * The switch tests the code for validity.
872 * The subcode is always good if it is a space, otherwise we must confirm.
873 * We set state to state_error first assuming the subcode is invalid,
874 * requiring state to be set in cases below that handle subcodes.
876 if (subcode != ' ') {
878 Dmsg0(100, "Set state=error or double code.\n");
883 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
884 memset(fileset->incexe, 0, sizeof(findINCEXE));
885 fileset->incexe->opts_list.init(1, true);
886 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
887 fileset->incexe->plugin_list.init();
888 fileset->include_list.append(fileset->incexe);
891 fileset = new_exclude(jcr);
897 /* File item to include or exclude list */
898 state = state_include;
899 add_file_to_fileset(jcr, item, fileset, true);
902 /* Plugin item to include list */
903 state = state_include;
904 add_file_to_fileset(jcr, item, fileset, false);
907 current_opts = start_options(ff);
911 preg = (regex_t *)malloc(sizeof(regex_t));
912 if (current_opts->flags & FO_IGNORECASE) {
913 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
915 rc = regcomp(preg, item, REG_EXTENDED);
918 regerror(rc, preg, prbuf, sizeof(prbuf));
921 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
925 state = state_options;
926 if (subcode == ' ') {
927 current_opts->regex.append(preg);
928 } else if (subcode == 'D') {
929 current_opts->regexdir.append(preg);
930 } else if (subcode == 'F') {
931 current_opts->regexfile.append(preg);
937 current_opts = start_options(ff);
938 current_opts->base.append(bstrdup(item));
939 state = state_options;
942 current_opts = start_options(ff);
943 state = state_options;
944 if (subcode == ' ') {
945 current_opts->fstype.append(bstrdup(item));
946 } else if (subcode == 'D') {
947 current_opts->drivetype.append(bstrdup(item));
953 current_opts = start_options(ff);
954 state = state_options;
955 if (subcode == ' ') {
956 current_opts->wild.append(bstrdup(item));
957 } else if (subcode == 'D') {
958 current_opts->wilddir.append(bstrdup(item));
959 } else if (subcode == 'F') {
960 current_opts->wildfile.append(bstrdup(item));
961 } else if (subcode == 'B') {
962 current_opts->wildbase.append(bstrdup(item));
968 current_opts = start_options(ff);
969 set_options(current_opts, item);
970 state = state_options;
973 state = state_include;
974 fileset->incexe->ignoredir = bstrdup(item);
977 current_opts = start_options(ff);
978 // current_opts->reader = bstrdup(item);
979 state = state_options;
982 current_opts = start_options(ff);
983 // current_opts->writer = bstrdup(item);
984 state = state_options;
987 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
991 ff->fileset->state = state;
994 static bool term_fileset(JCR *jcr)
996 FF_PKT *ff = jcr->ff;
998 #ifdef xxx_DEBUG_CODE
999 findFILESET *fileset = ff->fileset;
1002 for (i=0; i<fileset->include_list.size(); i++) {
1003 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1005 for (j=0; j<incexe->opts_list.size(); j++) {
1006 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1007 for (k=0; k<fo->regex.size(); k++) {
1008 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1010 for (k=0; k<fo->regexdir.size(); k++) {
1011 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1013 for (k=0; k<fo->regexfile.size(); k++) {
1014 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1016 for (k=0; k<fo->wild.size(); k++) {
1017 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1019 for (k=0; k<fo->wilddir.size(); k++) {
1020 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1022 for (k=0; k<fo->wildfile.size(); k++) {
1023 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1025 for (k=0; k<fo->wildbase.size(); k++) {
1026 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1028 for (k=0; k<fo->base.size(); k++) {
1029 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1031 for (k=0; k<fo->fstype.size(); k++) {
1032 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1034 for (k=0; k<fo->drivetype.size(); k++) {
1035 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1038 if (incexe->ignoredir) {
1039 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1042 foreach_dlist(node, &incexe->name_list) {
1043 Dmsg1(400, "F %s\n", node->c_str());
1045 foreach_dlist(node, &incexe->plugin_list) {
1046 Dmsg1(400, "P %s\n", node->c_str());
1049 for (i=0; i<fileset->exclude_list.size(); i++) {
1050 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1052 for (j=0; j<incexe->opts_list.size(); j++) {
1053 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1054 for (k=0; k<fo->regex.size(); k++) {
1055 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1057 for (k=0; k<fo->regexdir.size(); k++) {
1058 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1060 for (k=0; k<fo->regexfile.size(); k++) {
1061 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1063 for (k=0; k<fo->wild.size(); k++) {
1064 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1066 for (k=0; k<fo->wilddir.size(); k++) {
1067 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1069 for (k=0; k<fo->wildfile.size(); k++) {
1070 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1072 for (k=0; k<fo->wildbase.size(); k++) {
1073 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1075 for (k=0; k<fo->base.size(); k++) {
1076 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1078 for (k=0; k<fo->fstype.size(); k++) {
1079 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1081 for (k=0; k<fo->drivetype.size(); k++) {
1082 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1086 foreach_dlist(node, incexe->name_list) {
1087 Dmsg1(400, "F %s\n", node->c_str());
1089 foreach_dlist(node, &incexe->plugin_list) {
1090 Dmsg1(400, "P %s\n", node->c_str());
1094 return ff->fileset->state != state_error;
1099 * As an optimization, we should do this during
1100 * "compile" time in filed/job.c, and keep only a bit mask
1101 * and the Verify options.
1103 static void set_options(findFOPTS *fo, const char *opts)
1109 // Commented out as it is not backward compatible - KES
1111 // fo->flags |= FO_IGNORECASE; /* always ignorecase under windows */
1114 for (p=opts; *p; p++) {
1116 case 'a': /* alway replace */
1117 case '0': /* no option */
1120 fo->flags |= FO_EXCLUDE;
1123 fo->flags |= FO_MULTIFS;
1125 case 'h': /* no recursion */
1126 fo->flags |= FO_NO_RECURSION;
1128 case 'H': /* no hard link handling */
1129 fo->flags |= FO_NO_HARDLINK;
1132 fo->flags |= FO_IGNORECASE;
1135 fo->flags |= FO_MD5;
1138 fo->flags |= FO_NOREPLACE;
1140 case 'p': /* use portable data format */
1141 fo->flags |= FO_PORTABLE;
1143 case 'R': /* Resource forks and Finder Info */
1144 fo->flags |= FO_HFSPLUS;
1145 case 'r': /* read fifo */
1146 fo->flags |= FO_READFIFO;
1151 fo->flags |= FO_SHA1;
1156 fo->flags |= FO_SHA256;
1160 fo->flags |= FO_SHA512;
1166 * If 2 or 3 is seen here, SHA2 is not configured, so
1167 * eat the option, and drop back to SHA-1.
1169 if (p[1] == '2' || p[1] == '3') {
1172 fo->flags |= FO_SHA1;
1177 fo->flags |= FO_SPARSE;
1180 fo->flags |= FO_MTIMEONLY;
1183 fo->flags |= FO_KEEPATIME;
1186 fo->flags |= FO_ACL;
1188 case 'V': /* verify options */
1189 /* Copy Verify Options */
1190 for (j=0; *p && *p != ':'; p++) {
1191 fo->VerifyOpts[j] = *p;
1192 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1196 fo->VerifyOpts[j] = 0;
1198 case 'C': /* accurate options */
1199 /* Copy Accurate Options */
1200 for (j=0; *p && *p != ':'; p++) {
1201 fo->AccurateOpts[j] = *p;
1202 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1206 fo->AccurateOpts[j] = 0;
1208 case 'J': /* Basejob options */
1209 /* Copy BaseJob Options */
1210 for (j=0; *p && *p != ':'; p++) {
1211 fo->BaseJobOpts[j] = *p;
1212 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1216 fo->BaseJobOpts[j] = 0;
1218 case 'P': /* strip path */
1221 for (j=0; *p && *p != ':'; p++) {
1223 if (j < (int)sizeof(strip) - 1) {
1228 fo->strip_path = atoi(strip);
1229 fo->flags |= FO_STRIPPATH;
1230 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1233 fo->flags |= FO_IF_NEWER;
1236 fo->flags |= FO_ENHANCEDWILD;
1238 case 'Z': /* gzip compression */
1239 fo->flags |= FO_GZIP;
1240 fo->GZIP_level = *++p - '0';
1243 fo->flags |= FO_NOATIME;
1246 fo->flags |= FO_CHKCHANGES;
1249 fo->flags |= FO_HONOR_NODUMP;
1252 fo->flags |= FO_XATTR;
1255 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1263 * Director is passing his Fileset
1265 static int fileset_cmd(JCR *jcr)
1267 BSOCK *dir = jcr->dir_bsock;
1269 #if defined(WIN32_VSS)
1272 sscanf(dir->msg, "fileset vss=%d", &vss);
1276 if (!init_fileset(jcr)) {
1279 while (dir->recv() >= 0) {
1280 strip_trailing_junk(dir->msg);
1281 Dmsg1(500, "Fileset: %s\n", dir->msg);
1282 add_fileset(jcr, dir->msg);
1284 if (!term_fileset(jcr)) {
1287 return dir->fsend(OKinc);
1290 static void free_bootstrap(JCR *jcr)
1292 if (jcr->RestoreBootstrap) {
1293 unlink(jcr->RestoreBootstrap);
1294 free_pool_memory(jcr->RestoreBootstrap);
1295 jcr->RestoreBootstrap = NULL;
1300 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1301 static uint32_t bsr_uniq = 0;
1304 * The Director sends us the bootstrap file, which
1305 * we will in turn pass to the SD.
1306 * Deprecated. The bsr is now sent directly from the
1307 * Director to the SD.
1309 static int bootstrap_cmd(JCR *jcr)
1311 BSOCK *dir = jcr->dir_bsock;
1312 POOLMEM *fname = get_pool_memory(PM_FNAME);
1315 free_bootstrap(jcr);
1318 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
1319 jcr->Job, bsr_uniq);
1321 Dmsg1(400, "bootstrap=%s\n", fname);
1322 jcr->RestoreBootstrap = fname;
1323 bs = fopen(fname, "a+b"); /* create file */
1326 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1327 jcr->RestoreBootstrap, be.bstrerror());
1329 * Suck up what he is sending to us so that he will then
1330 * read our error message.
1332 while (dir->recv() >= 0)
1334 free_bootstrap(jcr);
1335 set_jcr_job_status(jcr, JS_ErrorTerminated);
1339 while (dir->recv() >= 0) {
1340 Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1341 fputs(dir->msg, bs);
1345 * Note, do not free the bootstrap yet -- it needs to be
1348 return dir->fsend(OKbootstrap);
1353 * Get backup level from Director
1356 static int level_cmd(JCR *jcr)
1358 BSOCK *dir = jcr->dir_bsock;
1359 POOLMEM *level, *buf = NULL;
1362 level = get_memory(dir->msglen+1);
1363 Dmsg1(100, "level_cmd: %s", dir->msg);
1365 /* keep compatibility with older directors */
1366 if (strstr(dir->msg, "accurate")) {
1367 jcr->accurate = true;
1369 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1372 /* Base backup requested? */
1373 if (strcmp(level, "base") == 0) {
1374 jcr->set_JobLevel(L_BASE);
1375 /* Full backup requested? */
1376 } else if (strcmp(level, "full") == 0) {
1377 jcr->set_JobLevel(L_FULL);
1378 } else if (strstr(level, "differential")) {
1379 jcr->set_JobLevel(L_DIFFERENTIAL);
1382 } else if (strstr(level, "incremental")) {
1383 jcr->set_JobLevel(L_INCREMENTAL);
1387 * We get his UTC since time, then sync the clocks and correct it
1388 * to agree with our clock.
1390 } else if (strcmp(level, "since_utime") == 0) {
1391 buf = get_memory(dir->msglen+1);
1392 utime_t since_time, adj;
1393 btime_t his_time, bt_start, rt=0, bt_adj=0;
1394 if (jcr->getJobLevel() == L_NONE) {
1395 jcr->set_JobLevel(L_SINCE); /* if no other job level set, do it now */
1397 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1398 buf, &mtime_only) != 2) {
1401 since_time = str_to_uint64(buf); /* this is the since time */
1402 Dmsg1(100, "since_time=%lld\n", since_time);
1403 char ed1[50], ed2[50];
1405 * Sync clocks by polling him for the time. We take
1406 * 10 samples of his time throwing out the first two.
1408 for (int i=0; i<10; i++) {
1409 bt_start = get_current_btime();
1410 dir->signal(BNET_BTIME); /* poll for time */
1411 if (dir->recv() <= 0) { /* get response */
1414 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1417 if (i < 2) { /* toss first two results */
1420 his_time = str_to_uint64(buf);
1421 rt = get_current_btime() - bt_start; /* compute round trip time */
1422 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1423 edit_uint64(bt_start, ed2));
1424 bt_adj += bt_start - his_time - rt/2;
1425 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1428 bt_adj = bt_adj / 8; /* compute average time */
1429 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1430 adj = btime_to_utime(bt_adj);
1431 since_time += adj; /* adjust for clock difference */
1432 /* Don't notify if time within 3 seconds */
1433 if (adj > 3 || adj < -3) {
1435 if (adj > 600 || adj < -600) {
1440 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1442 dir->signal(BNET_EOD);
1444 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1445 jcr->incremental = 1; /* set incremental or decremental backup */
1446 jcr->mtime = since_time; /* set since time */
1447 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1449 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1457 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1458 return dir->fsend(OKlevel);
1461 pm_strcpy(jcr->errmsg, dir->msg);
1462 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1471 * Get session parameters from Director -- this is for a Restore command
1472 * This is deprecated. It is now passed via the bsr.
1474 static int session_cmd(JCR *jcr)
1476 BSOCK *dir = jcr->dir_bsock;
1478 Dmsg1(100, "SessionCmd: %s", dir->msg);
1479 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1480 &jcr->VolSessionId, &jcr->VolSessionTime,
1481 &jcr->StartFile, &jcr->EndFile,
1482 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1483 pm_strcpy(jcr->errmsg, dir->msg);
1484 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1488 return dir->fsend(OKsession);
1491 static void set_storage_auth_key(JCR *jcr, char *key)
1493 /* if no key don't update anything */
1499 * We can be contacting multiple storage daemons.
1500 * So, make sure that any old jcr->store_bsock is cleaned up.
1502 if (jcr->store_bsock) {
1503 jcr->store_bsock->destroy();
1504 jcr->store_bsock = NULL;
1508 * We can be contacting multiple storage daemons.
1509 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1511 if (jcr->sd_auth_key) {
1513 * If we already have a Authorization key, director can do multi
1516 Dmsg0(5, "set multi_restore=true\n");
1517 jcr->multi_restore = true;
1518 bfree(jcr->sd_auth_key);
1521 jcr->sd_auth_key = bstrdup(key);
1522 Dmsg0(5, "set sd auth key\n");
1526 * Get address of storage daemon from Director
1529 static int storage_cmd(JCR *jcr)
1531 int stored_port; /* storage daemon port */
1532 int enable_ssl; /* enable ssl to sd */
1533 POOL_MEM sd_auth_key(PM_MESSAGE);
1534 BSOCK *dir = jcr->dir_bsock;
1535 BSOCK *sd = new_bsock(); /* storage daemon bsock */
1538 Dmsg1(100, "StorageCmd: %s", dir->msg);
1539 sd_auth_key.check_size(dir->msglen);
1540 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1541 &enable_ssl, sd_auth_key.c_str()) != 4) {
1542 if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1543 &stored_port, &enable_ssl) != 3) {
1544 pm_strcpy(jcr->errmsg, dir->msg);
1545 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1550 set_storage_auth_key(jcr, sd_auth_key.c_str());
1552 Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1554 /* Open command communications with Storage daemon */
1555 /* Try to connect for 1 hour at 10 second intervals */
1557 sd->set_source_address(me->FDsrc_addr);
1558 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1559 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1565 Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1566 jcr->stored_addr, stored_port);
1567 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1568 jcr->stored_addr, stored_port);
1571 Dmsg0(110, "Connection OK to SD.\n");
1573 jcr->store_bsock = sd;
1575 sd->fsend("Hello Start Job %s\n", jcr->Job);
1576 if (!authenticate_storagedaemon(jcr)) {
1577 Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1580 Dmsg0(110, "Authenticated with SD.\n");
1582 /* Send OK to Director */
1583 return dir->fsend(OKstore);
1586 dir->fsend(BADcmd, "storage");
1595 static int backup_cmd(JCR *jcr)
1597 BSOCK *dir = jcr->dir_bsock;
1598 BSOCK *sd = jcr->store_bsock;
1602 #if defined(WIN32_VSS)
1603 // capture state here, if client is backed up by multiple directors
1604 // and one enables vss and the other does not then enable_vss can change
1605 // between here and where its evaluated after the job completes.
1606 jcr->VSS = g_pVSSClient && enable_vss;
1608 /* Run only one at a time */
1614 * Validate some options given to the backup make sense for the compiled in
1615 * options of this filed.
1617 if (jcr->ff->flags & FO_ACL && !have_acl) {
1618 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1621 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1622 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1626 set_jcr_job_status(jcr, JS_Blocked);
1627 jcr->set_JobType(JT_BACKUP);
1628 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1631 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1632 dir->fsend(BADcmd, "backup");
1636 dir->fsend(OKbackup);
1637 Dmsg1(110, "filed>dird: %s", dir->msg);
1640 * Send Append Open Session to Storage daemon
1642 sd->fsend(append_open);
1643 Dmsg1(110, ">stored: %s", sd->msg);
1645 * Expect to receive back the Ticket number
1647 if (bget_msg(sd) >= 0) {
1648 Dmsg1(110, "<stored: %s", sd->msg);
1649 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1650 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
1653 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
1655 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
1660 * Send Append data command to Storage daemon
1662 sd->fsend(append_data, jcr->Ticket);
1663 Dmsg1(110, ">stored: %s", sd->msg);
1666 * Expect to get OK data
1668 Dmsg1(110, "<stored: %s", sd->msg);
1669 if (!response(jcr, sd, OK_data, "Append Data")) {
1673 generate_daemon_event(jcr, "JobStart");
1674 generate_plugin_event(jcr, bEventStartBackupJob);
1676 #if defined(WIN32_VSS)
1677 /* START VSS ON WIN32 */
1679 if (g_pVSSClient->InitializeForBackup(jcr)) {
1680 generate_plugin_event(jcr, bEventVssBackupAddComponents);
1681 /* tell vss which drives to snapshot */
1682 char szWinDriveLetters[27];
1683 if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
1684 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
1685 if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {
1686 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
1689 /* tell user if snapshot creation of a specific drive failed */
1691 for (i=0; i < (int)strlen(szWinDriveLetters); i++) {
1692 if (islower(szWinDriveLetters[i])) {
1693 Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]);
1697 /* inform user about writer states */
1698 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)
1699 if (g_pVSSClient->GetWriterState(i) < 1) {
1700 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));
1705 Jmsg(jcr, M_INFO, 0, _("No drive letters found for generating VSS snapshots.\n"));
1709 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1711 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1716 * Send Files to Storage daemon
1718 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
1719 if (!blast_data_to_storage_daemon(jcr, NULL)) {
1720 set_jcr_job_status(jcr, JS_ErrorTerminated);
1721 bnet_suppress_error_messages(sd, 1);
1722 Dmsg0(110, "Error in blast_data.\n");
1724 set_jcr_job_status(jcr, JS_Terminated);
1725 /* Note, the above set status will not override an error */
1726 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
1727 bnet_suppress_error_messages(sd, 1);
1728 goto cleanup; /* bail out now */
1731 * Expect to get response to append_data from Storage daemon
1733 if (!response(jcr, sd, OK_append, "Append Data")) {
1734 set_jcr_job_status(jcr, JS_ErrorTerminated);
1739 * Send Append End Data to Storage daemon
1741 sd->fsend(append_end, jcr->Ticket);
1743 if (!response(jcr, sd, OK_end, "Append End")) {
1744 set_jcr_job_status(jcr, JS_ErrorTerminated);
1749 * Send Append Close to Storage daemon
1751 sd->fsend(append_close, jcr->Ticket);
1752 while (bget_msg(sd) >= 0) { /* stop on signal or error */
1753 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
1755 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
1759 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
1762 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
1763 Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
1769 #if defined(WIN32_VSS)
1771 Win32ConvCleanupCache();
1776 generate_plugin_event(jcr, bEventEndBackupJob);
1777 return 0; /* return and stop command loop */
1781 * Do a Verify for Director
1784 static int verify_cmd(JCR *jcr)
1786 BSOCK *dir = jcr->dir_bsock;
1787 BSOCK *sd = jcr->store_bsock;
1790 jcr->set_JobType(JT_VERIFY);
1791 if (sscanf(dir->msg, verifycmd, level) != 1) {
1792 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
1796 if (strcasecmp(level, "init") == 0) {
1797 jcr->set_JobLevel(L_VERIFY_INIT);
1798 } else if (strcasecmp(level, "catalog") == 0){
1799 jcr->set_JobLevel(L_VERIFY_CATALOG);
1800 } else if (strcasecmp(level, "volume") == 0){
1801 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1802 } else if (strcasecmp(level, "data") == 0){
1803 jcr->set_JobLevel(L_VERIFY_DATA);
1804 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
1805 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
1807 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1811 dir->fsend(OKverify);
1813 generate_daemon_event(jcr, "JobStart");
1814 generate_plugin_event(jcr, bEventLevel, (void *)jcr->getJobLevel());
1815 generate_plugin_event(jcr, bEventStartVerifyJob);
1817 Dmsg1(110, "filed>dird: %s", dir->msg);
1819 switch (jcr->getJobLevel()) {
1821 case L_VERIFY_CATALOG:
1824 case L_VERIFY_VOLUME_TO_CATALOG:
1825 if (!open_sd_read_session(jcr)) {
1828 start_dir_heartbeat(jcr);
1829 do_verify_volume(jcr);
1830 stop_dir_heartbeat(jcr);
1832 * Send Close session command to Storage daemon
1834 sd->fsend(read_close, jcr->Ticket);
1835 Dmsg1(130, "filed>stored: %s", sd->msg);
1837 /* ****FIXME**** check response */
1838 bget_msg(sd); /* get OK */
1840 /* Inform Storage daemon that we are done */
1841 sd->signal(BNET_TERMINATE);
1844 case L_VERIFY_DISK_TO_CATALOG:
1848 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
1852 dir->signal(BNET_EOD);
1853 generate_plugin_event(jcr, bEventEndVerifyJob);
1854 return 0; /* return and terminate command loop */
1858 static bool vss_restore_init_callback(JCR *jcr, int init_type)
1860 switch (init_type) {
1861 case VSS_INIT_RESTORE_AFTER_INIT:
1862 generate_plugin_event(jcr, bEventVssRestoreLoadComponentMetadata);
1864 case VSS_INIT_RESTORE_AFTER_GATHER:
1865 generate_plugin_event(jcr, bEventVssRestoreSetComponentsSelected);
1875 * Do a Restore for Director
1878 static int restore_cmd(JCR *jcr)
1880 BSOCK *dir = jcr->dir_bsock;
1881 BSOCK *sd = jcr->store_bsock;
1883 bool use_regexwhere=false;
1888 * Scan WHERE (base directory for restore) from command
1890 Dmsg0(100, "restore command\n");
1891 #if defined(WIN32_VSS)
1893 /* TODO: this should be given from the director */
1896 Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
1897 // capture state here, if client is backed up by multiple directors
1898 // and one enables vss and the other does not then enable_vss can change
1899 // between here and where its evaluated after the job completes.
1900 jcr->VSS = g_pVSSClient && enable_vss;
1902 /* Run only one at a time */
1906 /* Pickup where string */
1907 args = get_memory(dir->msglen+1);
1910 if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
1911 if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3){
1912 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
1913 pm_strcpy(jcr->errmsg, dir->msg);
1914 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
1919 use_regexwhere = true;
1921 /* Turn / into nothing */
1922 if (IsPathSeparator(args[0]) && args[1] == '\0') {
1926 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
1927 unbash_spaces(args);
1929 if (use_regexwhere) {
1930 jcr->where_bregexp = get_bregexps(args);
1931 if (!jcr->where_bregexp) {
1932 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
1933 free_pool_memory(args);
1937 jcr->where = bstrdup(args);
1940 free_pool_memory(args);
1941 jcr->replace = replace;
1942 jcr->prefix_links = prefix_links;
1944 dir->fsend(OKrestore);
1945 Dmsg1(110, "filed>dird: %s", dir->msg);
1947 jcr->set_JobType(JT_RESTORE);
1949 set_jcr_job_status(jcr, JS_Blocked);
1951 if (!open_sd_read_session(jcr)) {
1952 set_jcr_job_status(jcr, JS_ErrorTerminated);
1956 set_jcr_job_status(jcr, JS_Running);
1959 * Do restore of files and data
1961 start_dir_heartbeat(jcr);
1962 generate_daemon_event(jcr, "JobStart");
1963 generate_plugin_event(jcr, bEventStartRestoreJob);
1965 #if defined(WIN32_VSS)
1966 /* START VSS ON WIN32 */
1968 if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
1969 (WCHAR *)jcr->job_metadata)) {
1970 /* inform user about writer states */
1972 for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
1973 int msg_type = M_INFO;
1974 if (g_pVSSClient->GetWriterState(i) < 1) {
1975 msg_type = M_WARNING;
1978 if (g_pVSSClient->GetWriterState(i) < 1) {
1979 Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
1985 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
1987 free_and_null_pool_memory(jcr->job_metadata);
1988 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
1993 stop_dir_heartbeat(jcr);
1995 set_jcr_job_status(jcr, JS_Terminated);
1996 if (jcr->JobStatus != JS_Terminated) {
1997 bnet_suppress_error_messages(sd, 1);
2001 * Send Close session command to Storage daemon
2003 sd->fsend(read_close, jcr->Ticket);
2004 Dmsg1(100, "filed>stored: %s", sd->msg);
2006 bget_msg(sd); /* get OK */
2008 /* Inform Storage daemon that we are done */
2009 sd->signal(BNET_TERMINATE);
2011 #if defined(WIN32_VSS)
2012 /* STOP VSS ON WIN32 */
2013 /* tell vss to close the restore session */
2014 Dmsg0(0, "About to call CloseRestore\n");
2016 Dmsg0(0, "Really about to call CloseRestore\n");
2017 if (g_pVSSClient->CloseRestore()) {
2018 Dmsg0(0, "CloseRestore success\n");
2019 /* inform user about writer states */
2020 for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
2021 int msg_type = M_INFO;
2022 if (g_pVSSClient->GetWriterState(i) < 1) {
2023 msg_type = M_WARNING;
2026 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
2030 Dmsg1(0, "CloseRestore fail - %08x\n", errno);
2036 bfree_and_null(jcr->where);
2038 if (jcr->JobErrors) {
2039 set_jcr_job_status(jcr, JS_ErrorTerminated);
2042 Dmsg0(100, "Done in job.c\n");
2045 if (jcr->multi_restore) {
2046 Dmsg0(100, OKstoreend);
2047 dir->fsend(OKstoreend);
2048 ret = 1; /* we continue the loop, waiting for next part */
2050 end_restore_cmd(jcr);
2051 ret = 0; /* we stop here */
2057 static int end_restore_cmd(JCR *jcr)
2059 Dmsg0(5, "end_restore_cmd\n");
2060 generate_plugin_event(jcr, bEventEndRestoreJob);
2061 return 0; /* return and terminate command loop */
2064 static int open_sd_read_session(JCR *jcr)
2066 BSOCK *sd = jcr->store_bsock;
2069 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2072 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2073 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2074 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2076 * Open Read Session with Storage daemon
2078 sd->fsend(read_open, "DummyVolume",
2079 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2080 jcr->StartBlock, jcr->EndBlock);
2081 Dmsg1(110, ">stored: %s", sd->msg);
2086 if (bget_msg(sd) >= 0) {
2087 Dmsg1(110, "filed<stored: %s", sd->msg);
2088 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2089 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2092 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2094 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2098 if (!send_bootstrap_file(jcr)) {
2103 * Start read of data with Storage daemon
2105 sd->fsend(read_data, jcr->Ticket);
2106 Dmsg1(110, ">stored: %s", sd->msg);
2111 if (!response(jcr, sd, OK_data, "Read Data")) {
2118 * Destroy the Job Control Record and associated
2119 * resources (sockets).
2121 static void filed_free_jcr(JCR *jcr)
2123 if (jcr->store_bsock) {
2124 jcr->store_bsock->close();
2126 free_bootstrap(jcr);
2127 if (jcr->last_fname) {
2128 free_pool_memory(jcr->last_fname);
2130 free_runscripts(jcr->RunScripts);
2131 delete jcr->RunScripts;
2133 if (jcr->JobId != 0)
2134 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2140 * Get response from Storage daemon to a command we
2141 * sent. Check that the response is OK.
2143 * Returns: 0 on failure
2146 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2151 if (bget_msg(sd) > 0) {
2152 Dmsg0(110, sd->msg);
2153 if (strcmp(sd->msg, resp) == 0) {
2157 if (job_canceled(jcr)) {
2158 return 0; /* if canceled avoid useless error messages */
2160 if (is_bnet_error(sd)) {
2161 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2162 cmd, bnet_strerror(sd));
2164 Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2165 cmd, resp, sd->msg);
2170 static int send_bootstrap_file(JCR *jcr)
2174 BSOCK *sd = jcr->store_bsock;
2175 const char *bootstrap = "bootstrap\n";
2178 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
2179 if (!jcr->RestoreBootstrap) {
2182 bs = fopen(jcr->RestoreBootstrap, "rb");
2185 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
2186 jcr->RestoreBootstrap, be.bstrerror());
2187 set_jcr_job_status(jcr, JS_ErrorTerminated);
2190 sd->msglen = pm_strcpy(sd->msg, bootstrap);
2192 while (fgets(buf, sizeof(buf), bs)) {
2193 sd->msglen = Mmsg(sd->msg, "%s", buf);
2196 sd->signal(BNET_EOD);
2198 if (!response(jcr, sd, OKSDbootstrap, "Bootstrap")) {
2199 set_jcr_job_status(jcr, JS_ErrorTerminated);
2205 free_bootstrap(jcr);