2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula File Daemon Job processing
22 * Written by Kern Sibbald, October MM
30 bool win32decomp = false;
31 bool no_win32_write_errors = false;
33 /* Static variables */
34 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
37 const bool have_acl = true;
39 const bool have_acl = false;
43 const bool have_xattr = true;
45 const bool have_xattr = false;
48 extern CLIENT *me; /* our client resource */
50 /* Imported functions */
51 extern int status_cmd(JCR *jcr);
52 extern int qstatus_cmd(JCR *jcr);
53 extern int accurate_cmd(JCR *jcr);
55 /* Forward referenced functions */
56 static int backup_cmd(JCR *jcr);
57 static int component_cmd(JCR *jcr);
58 static int cancel_cmd(JCR *jcr);
59 static int setdebug_cmd(JCR *jcr);
60 static int setbandwidth_cmd(JCR *jcr);
61 static int estimate_cmd(JCR *jcr);
62 static int hello_cmd(JCR *jcr);
63 static int job_cmd(JCR *jcr);
64 static int fileset_cmd(JCR *jcr);
65 static int level_cmd(JCR *jcr);
66 static int verify_cmd(JCR *jcr);
67 static int restore_cmd(JCR *jcr);
68 static int end_restore_cmd(JCR *jcr);
69 static int storage_cmd(JCR *jcr);
70 static int session_cmd(JCR *jcr);
71 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
72 static void filed_free_jcr(JCR *jcr);
73 static int open_sd_read_session(JCR *jcr);
74 static int runscript_cmd(JCR *jcr);
75 static int runbefore_cmd(JCR *jcr);
76 static int runafter_cmd(JCR *jcr);
77 static int runbeforenow_cmd(JCR *jcr);
78 static int restore_object_cmd(JCR *jcr);
79 static int set_options(findFOPTS *fo, const char *opts);
80 static void set_storage_auth_key(JCR *jcr, char *key);
81 static int sm_dump_cmd(JCR *jcr);
82 static int proxy_cmd(JCR *jcr);
83 static int fd_testnetwork_cmd(JCR *jcr);
85 static int exit_cmd(JCR *jcr);
88 /* Exported functions */
90 #define ACCESS_MONITOR 1
91 #define ACCESS_REMOTE 2
94 * The following are the recognized commands from the Director.
96 struct s_cmds cmds[] = {
97 {"backup", backup_cmd, 0},
98 {"cancel", cancel_cmd, ACCESS_REMOTE},
99 {"setdebug=", setdebug_cmd, 0},
100 {"setbandwidth=",setbandwidth_cmd, ACCESS_REMOTE},
101 {"snapshot", snapshot_cmd, 0},
102 {"estimate", estimate_cmd, 0},
103 {"Hello", hello_cmd, 1},
104 {"fileset", fileset_cmd, 0},
105 {"JobId=", job_cmd, 0},
106 {"level = ", level_cmd, 0},
107 {"restore ", restore_cmd, 0},
108 {"endrestore", end_restore_cmd, 0},
109 {"session", session_cmd, 0},
110 {"status", status_cmd, ACCESS_MONITOR|ACCESS_REMOTE},
111 {".status", qstatus_cmd, ACCESS_MONITOR|ACCESS_REMOTE},
112 {"storage ", storage_cmd, 0},
113 {"verify", verify_cmd, 0},
114 {"component", component_cmd, 0},
115 {"RunBeforeNow", runbeforenow_cmd, 0},
116 {"RunBeforeJob", runbefore_cmd, 0},
117 {"RunAfterJob", runafter_cmd, 0},
118 {"Run", runscript_cmd, 0},
119 {"accurate", accurate_cmd, 0},
120 {"restoreobject", restore_object_cmd, 0},
121 {"sm_dump", sm_dump_cmd, 0},
122 {"stop", cancel_cmd, ACCESS_REMOTE},
123 {"proxy", proxy_cmd, ACCESS_REMOTE},
124 {"testnetwork", fd_testnetwork_cmd, 0},
126 {"exit", exit_cmd, 0},
128 {NULL, NULL} /* list terminator */
131 /* Commands received from director that need scanning */
132 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
133 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
134 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
135 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
137 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
138 static char restorefcmd1[] = "restore files=%d replace=%c prelinks=%d where=\n";
140 /* The following restore commands may have a big where=/regexwhere= parameter
141 * the bsscanf is limiting the default %s to 1000c. To allow more than 1000 bytes,
142 * we can specify %xxxxs where xxxx is the size expected in bytes.
144 * So, the code will add %s\n to the end of the following restore commands
146 static char restorecmd[] = "restore replace=%c prelinks=%d where=";
147 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=";
148 static char restorefcmd[] = "restore files=%d replace=%c prelinks=%d where=";
149 static char restorefcmdR[] = "restore files=%d replace=%c prelinks=%d regexwhere=";
151 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
152 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
153 static char endrestoreobjectcmd[] = "restoreobject end\n";
154 static char verifycmd[] = "verify level=%30s";
155 static char estimatecmd[] = "estimate listing=%d";
156 static char runbefore[] = "RunBeforeJob %s";
157 static char runafter[] = "RunAfterJob %s";
158 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
159 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
161 /* Responses sent to Director */
162 static char errmsg[] = "2999 Invalid command\n";
163 static char no_auth[] = "2998 No Authorization\n";
164 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
165 static char OKBandwidth[] = "2000 OK Bandwidth\n";
166 static char OKinc[] = "2000 OK include\n";
167 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
168 static char OKlevel[] = "2000 OK level\n";
169 static char OKbackup[] = "2000 OK backup\n";
170 static char OKverify[] = "2000 OK verify\n";
171 static char OKrestore[] = "2000 OK restore\n";
172 static char OKsession[] = "2000 OK session\n";
173 static char OKstore[] = "2000 OK storage\n";
174 static char OKstoreend[] = "2000 OK storage end\n";
175 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
176 static char OKsetdebug[] = "2000 OK setdebug=%ld trace=%ld hangup=%ld"
177 " blowup=%ld options=%s tags=%s\n";
178 static char BADjob[] = "2901 Bad Job\n";
179 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%d ReadBytes=%lld"
180 " JobBytes=%lld Errors=%d VSS=%d Encrypt=%d"
181 " CommBytes=%lld CompressCommBytes=%lld\n";
182 static char OKRunBefore[] = "2000 OK RunBefore\n";
183 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
184 static char OKRunAfter[] = "2000 OK RunAfter\n";
185 static char OKRunScript[] = "2000 OK RunScript\n";
186 static char BADcmd[] = "2902 Bad %s\n";
187 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
188 static char OKComponentInfo[] = "2000 OK ComponentInfo\n";
191 /* Responses received from Storage Daemon */
192 static char OK_end[] = "3000 OK end\n";
193 static char OK_close[] = "3000 OK close Status = %d\n";
194 static char OK_open[] = "3000 OK open ticket = %d\n";
195 static char OK_data[] = "3000 OK data\n";
196 static char OK_append[] = "3000 OK append data\n";
199 /* Commands sent to Storage Daemon */
200 static char append_open[] = "append open session\n";
201 static char append_data[] = "append data %d\n";
202 static char append_end[] = "append end session %d\n";
203 static char append_close[] = "append close session %d\n";
204 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
205 static char read_data[] = "read data %d\n";
206 static char read_close[] = "read close session %d\n";
207 static char read_ctrl[] = "read control %d\n";
209 /* Should tell us if a command is authorized or not */
210 static bool access_ok(struct s_cmds *cmd, DIRRES* dir)
212 if ((cmd->access & ACCESS_MONITOR) && dir->monitor) {
215 if ((cmd->access & ACCESS_REMOTE) && dir->remote) {
218 if (!dir->remote && !dir->monitor) {
225 * Accept requests from a Director
227 * NOTE! We are running as a separate thread
229 * Send output one line
230 * at a time followed by a zero length transmission.
232 * Return when the connection is terminated or there
235 * Basic task here is:
236 * Authenticate Director (during Hello command).
237 * Accept commands one at a time from the Director
240 * Concerning ClientRunBefore/After, the sequence of events
241 * is rather critical. If they are not done in the right
242 * order one can easily get FD->SD timeouts if the script
245 * The current sequence of events is:
246 * 1. Dir starts job with FD
247 * 2. Dir connects to SD
248 * 3. Dir connects to FD
249 * 4. FD connects to SD
250 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
251 * 6. Dir sends include/exclude
252 * 7. FD sends the file data to SD
253 * 8. SD/FD disconnects while the SD despools data and attributes (optional)
254 * 9. FD runs ClientRunAfterJob
257 static void *handle_director_request(BSOCK *dir)
263 const char jobname[12] = "*Director*";
265 prevent_os_suspensions(); /* do not suspend during backup/restore */
266 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
267 jcr->sd_calls_client_bsock = NULL;
268 jcr->sd_calls_client = false;
269 jcr->dir_bsock = dir;
270 jcr->ff = init_find_files();
271 jcr->start_time = time(NULL);
272 jcr->RunScripts = New(alist(10, not_owned_by_alist));
273 jcr->last_fname = get_pool_memory(PM_FNAME);
274 jcr->last_fname[0] = 0;
275 jcr->client_name = get_memory(strlen(my_name) + 1);
276 pm_strcpy(jcr->client_name, my_name);
277 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
278 jcr->crypto.pki_sign = me->pki_sign;
279 jcr->crypto.pki_encrypt = me->pki_encrypt;
280 jcr->crypto.pki_keypair = me->pki_keypair;
281 jcr->crypto.pki_signers = me->pki_signers;
282 jcr->crypto.pki_recipients = me->pki_recipients;
285 jcr->set_killable(true); /* allow dir to kill/cancel job */
286 /* Initialize SD start condition variable */
287 int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
290 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
293 enable_backup_privileges(NULL, 1 /* ignore_errors */);
295 for (quit=false; !quit;) {
296 if (!first) { /* first call the read is done */
298 if (dir->recv() < 0) {
299 break; /* connection terminated */
302 if (dir->msglen == 0) { /* Bad connection */
306 dir->msg[dir->msglen] = 0;
307 Dmsg1(100, "<dird: %s", dir->msg);
309 for (i=0; cmds[i].cmd; i++) {
310 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
311 found = true; /* indicate command found */
312 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
314 dir->signal(BNET_EOD);
317 if (jcr->authenticated && !access_ok(&cmds[i], jcr->director)) {
318 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
319 dir->fsend(invalid_cmd);
320 dir->signal(BNET_EOD);
323 if ((me->disabled_cmds_array && me->disabled_cmds_array[i]) ||
324 (jcr->director && jcr->director->disabled_cmds_array &&
325 jcr->director->disabled_cmds_array[i])) {
326 Jmsg(jcr, M_FATAL, 0, _("Command: \"%s\" is disabled.\n"), cmds[i].cmd);
330 Dmsg2(100, "Executing %s Dir %s command.\n", cmds[i].cmd, dir->msg);
331 if (!cmds[i].func(jcr)) { /* do command */
332 quit = true; /* error or fully terminated, get out */
333 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
338 if (!found) { /* command not found */
345 /* Inform Storage daemon that we are done */
346 if (jcr->store_bsock) {
347 jcr->store_bsock->signal(BNET_TERMINATE);
350 /* Run the after job */
351 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
353 /* send any queued messages before reporting the jobstatus to the director */
354 dequeue_messages(jcr);
356 if (jcr->JobId) { /* send EndJob if running a job */
357 uint64_t CommBytes, CommCompressedBytes;
358 uint32_t vss, encrypt;
359 /* Send termination status back to Dir */
360 if (jcr->store_bsock) {
361 CommBytes = jcr->store_bsock->CommBytes();
362 CommCompressedBytes = jcr->store_bsock->CommCompressedBytes();
364 CommBytes = CommCompressedBytes = 0;
366 encrypt = jcr->crypto.pki_encrypt;
368 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
369 jcr->ReadBytes, jcr->JobBytes, jcr->JobErrors, vss,
370 encrypt, CommBytes, CommCompressedBytes);
371 //Dmsg0(0, dir->msg);
374 generate_daemon_event(jcr, "JobEnd");
375 generate_plugin_event(jcr, bEventJobEnd);
378 dequeue_messages(jcr); /* send any queued messages, will no longer impact
379 * the job status... */
381 /* Inform Director that we are done */
382 dir->signal(BNET_TERMINATE);
384 free_and_null_pool_memory(jcr->job_metadata);
386 /* Clean up fileset */
387 FF_PKT *ff = jcr->ff;
388 findFILESET *fileset = ff->fileset;
391 /* Delete FileSet Include lists */
392 for (i=0; i<fileset->include_list.size(); i++) {
393 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
394 for (j=0; j<incexe->opts_list.size(); j++) {
395 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
399 for (k=0; k<fo->regex.size(); k++) {
400 regfree((regex_t *)fo->regex.get(k));
402 for (k=0; k<fo->regexdir.size(); k++) {
403 regfree((regex_t *)fo->regexdir.get(k));
405 for (k=0; k<fo->regexfile.size(); k++) {
406 regfree((regex_t *)fo->regexfile.get(k));
409 fo->regexdir.destroy();
410 fo->regexfile.destroy();
412 fo->wilddir.destroy();
413 fo->wildfile.destroy();
414 fo->wildbase.destroy();
416 fo->fstype.destroy();
417 fo->drivetype.destroy();
419 incexe->opts_list.destroy();
420 incexe->name_list.destroy();
421 incexe->plugin_list.destroy();
422 if (incexe->ignoredir) {
423 free(incexe->ignoredir);
426 fileset->include_list.destroy();
428 /* Delete FileSet Exclude lists */
429 for (i=0; i<fileset->exclude_list.size(); i++) {
430 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
431 for (j=0; j<incexe->opts_list.size(); j++) {
432 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
434 fo->regexdir.destroy();
435 fo->regexfile.destroy();
437 fo->wilddir.destroy();
438 fo->wildfile.destroy();
439 fo->wildbase.destroy();
441 fo->fstype.destroy();
442 fo->drivetype.destroy();
444 incexe->opts_list.destroy();
445 incexe->name_list.destroy();
446 incexe->plugin_list.destroy();
447 if (incexe->ignoredir) {
448 free(incexe->ignoredir);
451 fileset->exclude_list.destroy();
455 ff->mount_points.destroy();
456 Dmsg0(100, "Calling term_find_files\n");
457 term_find_files(jcr->ff);
459 Dmsg0(100, "Done with term_find_files\n");
460 pthread_cond_destroy(&jcr->job_start_wait);
461 free_jcr(jcr); /* destroy JCR record */
462 Dmsg0(100, "Done with free_jcr\n");
463 allow_os_suspensions(); /* FD can now be suspended */
465 garbage_collect_memory_pool();
471 * Accept requests from a Director or a Storage daemon
473 void *handle_connection_request(void *caller)
475 BSOCK *bs = (BSOCK *)caller;
477 if (bs->recv() > 0) {
478 if (strncmp(bs->msg, "Ping", 4) == 0) {
479 bs->fsend("2000 Ping OK\n");
483 if (bs->msglen < 25 || bs->msglen > 500) {
486 if (strncmp(bs->msg, "Hello FD: Bacula Storage", 20) ==0) {
487 return handle_storage_connection(bs);
489 if (strncmp(bs->msg, "Hello ", 5) == 0) {
490 return handle_director_request(bs);
494 Dmsg2(100, "Bad command from %s. Len=%d.\n", bs->who(), bs->msglen);
496 char *who = bs->get_peer(addr, sizeof(addr)) ? bs->who() : addr;
497 Jmsg2(NULL, M_FATAL, 0, _("Bad command from %s. Len=%d.\n"), who, bs->msglen);
504 * Test the Network between FD/SD
506 static int fd_testnetwork_cmd(JCR *jcr)
508 bool can_compress, ok=true;
509 BSOCK *sd = jcr->store_bsock;
514 if (!sd || !jcr->dir_bsock) {
517 if (sscanf(jcr->dir_bsock->msg, "testnetwork bytes=%lld", &nb) != 1 || nb <= 0) {
518 sd->fsend("2999 testnetwork command error\n");
522 /* We disable the comline compression, else all numbers will be wrong */
523 can_compress = sd->can_compress();
525 sd->fsend("testnetwork bytes=%lld\n", nb);
526 sd->clear_compress();
528 /* In the first step, we send X bytes to the SD */
529 memset(sd->msg, 0xAA, sizeof_pool_memory(sd->msg));
530 sd->msglen = sizeof_pool_memory(sd->msg);
532 start = get_current_btime();
533 for (nb2 = nb ; nb2 > 0 && ok ; nb2 -= sd->msglen) {
534 if (nb2 < sd->msglen) {
539 sd->signal(BNET_EOD);
540 end = get_current_btime() + 1;
546 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms write_speed=%sB/s\n",
547 nb, end/1000 - start/1000,
548 edit_uint64_with_suffix(nb * 1000000 / (end - start), ed1));
550 /* Now we receive X bytes from the SD */
551 start = get_current_btime();
552 for (nb2 = 0; sd->recv() > 0; nb2 += sd->msglen) { }
553 end = get_current_btime() + 1;
555 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms read_speed=%sB/s\n",
556 nb2, end/1000 - start/1000,
557 edit_uint64_with_suffix(nb2 * 1000000 / (end - start), ed1));
559 jcr->dir_bsock->signal(BNET_CMD_OK);
566 jcr->dir_bsock->fsend("2999 network test failed ERR=%s\n", sd->errmsg);
567 jcr->dir_bsock->signal(BNET_CMD_FAILED);
573 static int proxy_cmd(JCR *jcr)
575 bool OK=true, fdcalled = false;
577 CONSRES *cons = jcr->director->console;
583 cons = (CONSRES *)GetNextRes(R_CONSOLE, NULL);
585 /* Here, dir_bsock is not really the director, this is a console */
586 cons_bsock = connect_director(jcr, cons);
588 jcr->dir_bsock->signal(BNET_ERROR_MSG);
589 jcr->dir_bsock->fsend("2999 proxy error. ERR=%s\n", jcr->errmsg);
590 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
591 /* Error during the connect */
595 /* Inform the console that the command is OK */
596 jcr->dir_bsock->fsend("2000 proxy OK.\n");
597 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
599 maxfd = MAX(cons_bsock->m_fd, jcr->dir_bsock->m_fd) + 1;
601 /* Start to forward events from one to the other
602 * It can be done with 2 threads, or with a select
606 FD_SET((unsigned)cons_bsock->m_fd, &fdset);
607 FD_SET((unsigned)jcr->dir_bsock->m_fd, &fdset);
611 switch ((v = select(maxfd, &fdset, NULL, NULL, &tv))) {
612 case 0: /* timeout */
613 OK = !jcr->is_canceled();
616 Dmsg1(0, "Bad call to select ERR=%d\n", errno);
620 if (cons_bsock->tls && !tls_bsock_probe(cons_bsock)) {
621 /* maybe a session key negotiation waked up the socket */
622 FD_CLR(cons_bsock->m_fd, &fdset);
624 if (jcr->dir_bsock->tls && !tls_bsock_probe(jcr->dir_bsock)) {
625 /* maybe a session key negotiation waked up the socket */
626 FD_CLR(jcr->dir_bsock->m_fd, &fdset);
631 Dmsg1(DT_NETWORK, "select = %d\n", v);
633 if (FD_ISSET(cons_bsock->m_fd, &fdset)) {
634 v = cons_bsock->recv();
635 if (v == BNET_SIGNAL) {
636 if (cons_bsock->msglen == BNET_FDCALLED) {
640 jcr->dir_bsock->signal(cons_bsock->msglen);
644 jcr->dir_bsock->fsend("%s", cons_bsock->msg);
647 /* We should not have such kind of message */
651 if (FD_ISSET(jcr->dir_bsock->m_fd, &fdset)) {
652 v = jcr->dir_bsock->recv();
653 if (v == BNET_SIGNAL) {
654 cons_bsock->signal(jcr->dir_bsock->msglen);
656 cons_bsock->fsend("%s", jcr->dir_bsock->msg);
658 /* We should not have such kind of message */
663 if (cons_bsock->is_error() || jcr->dir_bsock->is_error()) {
666 } while (OK && !jcr->is_canceled());
668 /* Close the socket, nothing more will come */
669 jcr->dir_bsock->signal(BNET_TERMINATE);
670 jcr->dir_bsock->close();
672 handle_connection_request(cons_bsock); /* will release the socket */
674 free_bsock(cons_bsock);
679 static int sm_dump_cmd(JCR *jcr)
682 sm_dump(false, true);
683 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
688 static int exit_cmd(JCR *jcr)
690 jcr->dir_bsock->fsend("2000 exit OK\n");
697 * Hello from Director he must identify himself and provide his
700 static int hello_cmd(JCR *jcr)
702 Dmsg0(120, "Calling Authenticate\n");
703 if (!validate_dir_hello(jcr)) {
706 if (!authenticate_director(jcr)) {
709 Dmsg0(120, "OK Authenticate\n");
710 jcr->authenticated = true;
712 dequeue_messages(jcr); /* dequeue any daemon messages */
719 static int cancel_cmd(JCR *jcr)
721 BSOCK *dir = jcr->dir_bsock;
722 char Job[MAX_NAME_LENGTH];
727 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
728 status = JS_Canceled;
730 } else if (sscanf(dir->msg, "stop Job=%127s", Job) == 1) {
731 status = JS_Incomplete;
734 dir->fsend(_("2902 Error scanning cancel command.\n"));
737 if (!(cjcr=get_jcr_by_full_name(Job))) {
738 dir->fsend(_("2901 Job %s not found.\n"), Job);
740 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
741 cjcr->setJobStatus(status);
742 if (cjcr->store_bsock) {
743 cjcr->store_bsock->cancel();
745 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
747 dir->fsend(_("2001 Job \"%s\" marked to be %s.\n"),
752 dir->signal(BNET_EOD);
757 * Set bandwidth limit as requested by the Director
760 static int setbandwidth_cmd(JCR *jcr)
762 BSOCK *dir = jcr->dir_bsock;
765 char Job[MAX_NAME_LENGTH];
768 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
769 pm_strcpy(jcr->errmsg, dir->msg);
770 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
775 if(!(cjcr=get_jcr_by_full_name(Job))) {
776 dir->fsend(_("2901 Job %s not found.\n"), Job);
778 cjcr->max_bandwidth = bw;
779 if (cjcr->store_bsock) {
780 cjcr->store_bsock->set_bwlimit(bw);
785 } else { /* No job requested, apply globally */
786 me->max_bandwidth_per_job = bw; /* Overwrite directive */
788 cjcr->max_bandwidth = bw;
789 if (cjcr->store_bsock) {
790 cjcr->store_bsock->set_bwlimit(bw);
796 return dir->fsend(OKBandwidth);
800 * Set debug level as requested by the Director
803 static int setdebug_cmd(JCR *jcr)
805 BSOCK *dir = jcr->dir_bsock;
809 int64_t level, level_tags = 0;
814 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
815 tags[0] = options[0] = 0;
816 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld blowup=%ld"
817 " options=%55s tags=%511s",
818 &lvl, &trace, &hangup, &blowup, options, tags);
820 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld",
821 &lvl, &trace, &hangup);
823 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
824 if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace) != 2) {
825 pm_strcpy(jcr->errmsg, dir->msg);
826 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
837 if (!debug_parse_tags(tags, &level_tags)) {
843 debug_level_tags = level_tags;
845 /* Parse specific FD options */
846 for (char *p = options; *p ; p++) {
849 /* Turn on/off ignore bwrite() errors on restore */
850 no_win32_write_errors = true;
853 /* Turn on/off decomp of BackupRead() streams */
859 /* handle other options */
860 set_debug_flags(options);
862 Dmsg6(150, "level=%ld trace=%ld hangup=%ld blowup=%d options=%s tags=%s\n",
863 lvl, get_trace(), get_hangup(), get_blowup(), options, tags);
864 return dir->fsend(OKsetdebug, lvl, get_trace(), get_hangup(),
865 get_blowup(), options, tags);
869 static int estimate_cmd(JCR *jcr)
871 BSOCK *dir = jcr->dir_bsock;
872 char ed1[50], ed2[50];
874 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
875 pm_strcpy(jcr->errmsg, dir->msg);
876 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
877 dir->fsend(_("2992 Bad estimate command.\n"));
881 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
882 edit_uint64_with_commas(jcr->JobBytes, ed2));
883 dir->signal(BNET_EOD);
888 * Get JobId and Storage Daemon Authorization key from Director
890 static int job_cmd(JCR *jcr)
892 BSOCK *dir = jcr->dir_bsock;
893 POOL_MEM sd_auth_key(PM_MESSAGE);
894 sd_auth_key.check_size(dir->msglen);
896 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
897 &jcr->VolSessionId, &jcr->VolSessionTime,
898 sd_auth_key.c_str()) != 5) {
899 pm_strcpy(jcr->errmsg, dir->msg);
900 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
905 set_storage_auth_key(jcr, sd_auth_key.c_str());
906 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
907 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
908 new_plugins(jcr); /* instantiate plugins for this jcr */
909 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
910 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
913 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param, char *buf, int buflen)
918 return jcr->director->hdr.name;
928 static int runbefore_cmd(JCR *jcr)
931 BSOCK *dir = jcr->dir_bsock;
932 POOLMEM *cmd = get_memory(dir->msglen+1);
935 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
936 if (sscanf(dir->msg, runbefore, cmd) != 1) {
937 pm_strcpy(jcr->errmsg, dir->msg);
938 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
939 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
945 /* Run the command now */
946 script = new_runscript();
947 script->set_job_code_callback(job_code_callback_filed);
948 script->set_command(cmd);
949 script->when = SCRIPT_Before;
950 ok = script->run(jcr, "ClientRunBeforeJob");
951 free_runscript(script);
955 dir->fsend(OKRunBefore);
958 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
963 static int runbeforenow_cmd(JCR *jcr)
965 BSOCK *dir = jcr->dir_bsock;
967 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
968 if (job_canceled(jcr)) {
969 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
970 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
973 dir->fsend(OKRunBeforeNow);
974 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
979 static int runafter_cmd(JCR *jcr)
981 BSOCK *dir = jcr->dir_bsock;
982 POOLMEM *msg = get_memory(dir->msglen+1);
985 Dmsg1(100, "runafter_cmd: %s", dir->msg);
986 if (sscanf(dir->msg, runafter, msg) != 1) {
987 pm_strcpy(jcr->errmsg, dir->msg);
988 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
989 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
995 cmd = new_runscript();
996 cmd->set_job_code_callback(job_code_callback_filed);
997 cmd->set_command(msg);
998 cmd->on_success = true;
999 cmd->on_failure = false;
1000 cmd->when = SCRIPT_After;
1002 jcr->RunScripts->append(cmd);
1004 free_pool_memory(msg);
1005 return dir->fsend(OKRunAfter);
1008 static int runscript_cmd(JCR *jcr)
1010 BSOCK *dir = jcr->dir_bsock;
1011 POOLMEM *msg = get_memory(dir->msglen+1);
1012 int on_success, on_failure, fail_on_error;
1014 RUNSCRIPT *cmd = new_runscript() ;
1015 cmd->set_job_code_callback(job_code_callback_filed);
1017 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
1018 /* Note, we cannot sscanf into bools */
1019 if (sscanf(dir->msg, runscript, &on_success,
1024 pm_strcpy(jcr->errmsg, dir->msg);
1025 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
1026 dir->fsend(_("2905 Bad RunScript command.\n"));
1027 free_runscript(cmd);
1031 cmd->on_success = on_success;
1032 cmd->on_failure = on_failure;
1033 cmd->fail_on_error = fail_on_error;
1036 cmd->set_command(msg);
1038 jcr->RunScripts->append(cmd);
1040 free_pool_memory(msg);
1041 return dir->fsend(OKRunScript);
1045 * This reads data sent from the Director from the
1046 * RestoreObject table that allows us to get objects
1047 * that were backed up (VSS .xml data) and are needed
1048 * before starting the restore.
1050 static int restore_object_cmd(JCR *jcr)
1052 BSOCK *dir = jcr->dir_bsock;
1054 restore_object_pkt rop;
1056 memset(&rop, 0, sizeof(rop));
1057 rop.pkt_size = sizeof(rop);
1058 rop.pkt_end = sizeof(rop);
1060 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
1061 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
1062 Dmsg0(20, "Got endrestoreobject\n");
1063 generate_plugin_event(jcr, bEventRestoreObject, NULL);
1064 return dir->fsend(OKRestoreObject);
1067 rop.plugin_name = (char *)malloc(dir->msglen);
1068 *rop.plugin_name = 0;
1070 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
1071 &rop.object_full_len, &rop.object_index,
1072 &rop.object_type, &rop.object_compression, &FileIndex,
1073 rop.plugin_name) != 8) {
1075 /* Old version, no plugin_name */
1076 if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
1077 &rop.object_full_len, &rop.object_index,
1078 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
1079 Dmsg0(5, "Bad restore object command\n");
1080 pm_strcpy(jcr->errmsg, dir->msg);
1081 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
1086 unbash_spaces(rop.plugin_name);
1088 Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
1089 "FI=%d plugin_name=%s\n",
1090 rop.JobId, rop.object_len, rop.object_full_len,
1091 rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
1092 /* Read Object name */
1093 if (dir->recv() < 0) {
1096 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
1097 rop.object_name = bstrdup(dir->msg);
1100 if (dir->recv() < 0) {
1103 /* Transfer object from message buffer, and get new message buffer */
1104 rop.object = dir->msg;
1105 dir->msg = get_pool_memory(PM_MESSAGE);
1107 /* If object is compressed, uncompress it */
1108 if (rop.object_compression == 1) { /* zlib level 9 */
1110 int out_len = rop.object_full_len + 100;
1111 POOLMEM *obj = get_memory(out_len);
1112 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
1113 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
1114 Dmsg1(100, "Zinflate stat=%d\n", stat);
1115 if (out_len != rop.object_full_len) {
1116 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
1117 rop.object_full_len, out_len, rop.object_name);
1119 free_pool_memory(rop.object); /* release compressed object */
1120 rop.object = obj; /* new uncompressed object */
1121 rop.object_len = out_len;
1123 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
1124 /* we still need to do this to detect a vss restore */
1125 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
1126 Dmsg0(100, "got job metadata\n");
1127 jcr->got_metadata = true;
1130 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
1132 if (rop.object_name) {
1133 free(rop.object_name);
1136 free_pool_memory(rop.object);
1138 if (rop.plugin_name) {
1139 free(rop.plugin_name);
1142 Dmsg1(100, "Send: %s", OKRestoreObject);
1146 dir->fsend(_("2909 Bad RestoreObject command.\n"));
1152 static bool init_fileset(JCR *jcr)
1155 findFILESET *fileset;
1164 fileset = (findFILESET *)malloc(sizeof(findFILESET));
1165 memset(fileset, 0, sizeof(findFILESET));
1166 ff->fileset = fileset;
1167 fileset->state = state_none;
1168 fileset->include_list.init(1, true);
1169 fileset->exclude_list.init(1, true);
1173 static void append_file(JCR *jcr, findINCEXE *incexe,
1174 const char *buf, bool is_file)
1177 incexe->name_list.append(new_dlistString(buf));
1178 } else if (me->plugin_directory) {
1179 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
1180 incexe->plugin_list.append(new_dlistString(buf));
1182 Jmsg(jcr, M_FATAL, 0,
1183 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
1189 * Add fname to include/exclude fileset list. First check for
1190 * | and < and if necessary perform command.
1192 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
1194 findFILESET *fileset = jcr->ff->fileset;
1207 p++; /* skip over | */
1208 fn = get_pool_memory(PM_FNAME);
1209 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
1210 bpipe = open_bpipe(fn, 0, "r");
1213 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
1215 free_pool_memory(fn);
1218 free_pool_memory(fn);
1219 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1220 strip_trailing_junk(buf);
1221 append_file(jcr, fileset->incexe, buf, is_file);
1223 if ((stat=close_bpipe(bpipe)) != 0) {
1225 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
1226 p, be.code(stat), be.bstrerror(stat));
1231 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
1232 p++; /* skip over < */
1233 if ((ffd = fopen(p, "rb")) == NULL) {
1235 Jmsg(jcr, M_FATAL, 0,
1236 _("Cannot open FileSet input file: %s. ERR=%s\n"),
1240 while (fgets(buf, sizeof(buf), ffd)) {
1241 strip_trailing_junk(buf);
1242 append_file(jcr, fileset->incexe, buf, is_file);
1247 append_file(jcr, fileset->incexe, fname, is_file);
1252 findINCEXE *get_incexe(JCR *jcr)
1254 if (jcr->ff && jcr->ff->fileset) {
1255 return jcr->ff->fileset->incexe;
1260 void set_incexe(JCR *jcr, findINCEXE *incexe)
1262 findFILESET *fileset = jcr->ff->fileset;
1263 fileset->incexe = incexe;
1268 * Define a new Exclude block in the FileSet
1270 findINCEXE *new_exclude(JCR *jcr)
1272 findFILESET *fileset = jcr->ff->fileset;
1275 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1276 memset(fileset->incexe, 0, sizeof(findINCEXE));
1277 fileset->incexe->opts_list.init(1, true);
1278 fileset->incexe->name_list.init();
1279 fileset->incexe->plugin_list.init();
1280 fileset->exclude_list.append(fileset->incexe);
1281 return fileset->incexe;
1285 * Define a new Include block in the FileSet
1287 findINCEXE *new_include(JCR *jcr)
1289 findFILESET *fileset = jcr->ff->fileset;
1292 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1293 memset(fileset->incexe, 0, sizeof(findINCEXE));
1294 fileset->incexe->opts_list.init(1, true);
1295 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1296 fileset->incexe->plugin_list.init();
1297 fileset->include_list.append(fileset->incexe);
1298 return fileset->incexe;
1302 * Define a new preInclude block in the FileSet
1303 * That is the include is prepended to the other
1304 * Includes. This is used for plugin exclusions.
1306 findINCEXE *new_preinclude(JCR *jcr)
1308 findFILESET *fileset = jcr->ff->fileset;
1310 /* New pre-include */
1311 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1312 memset(fileset->incexe, 0, sizeof(findINCEXE));
1313 fileset->incexe->opts_list.init(1, true);
1314 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1315 fileset->incexe->plugin_list.init();
1316 fileset->include_list.prepend(fileset->incexe);
1317 return fileset->incexe;
1320 static findFOPTS *start_options(FF_PKT *ff)
1322 int state = ff->fileset->state;
1323 findINCEXE *incexe = ff->fileset->incexe;
1325 if (state != state_options) {
1326 ff->fileset->state = state_options;
1327 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1328 memset(fo, 0, sizeof(findFOPTS));
1329 fo->regex.init(1, true);
1330 fo->regexdir.init(1, true);
1331 fo->regexfile.init(1, true);
1332 fo->wild.init(1, true);
1333 fo->wilddir.init(1, true);
1334 fo->wildfile.init(1, true);
1335 fo->wildbase.init(1, true);
1336 fo->base.init(1, true);
1337 fo->fstype.init(1, true);
1338 fo->drivetype.init(1, true);
1339 incexe->current_opts = fo;
1340 incexe->opts_list.append(fo);
1342 return incexe->current_opts;
1346 * Used by plugins to define a new options block
1348 void new_options(JCR *jcr, findINCEXE *incexe)
1351 incexe = jcr->ff->fileset->incexe;
1353 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1354 memset(fo, 0, sizeof(findFOPTS));
1355 fo->regex.init(1, true);
1356 fo->regexdir.init(1, true);
1357 fo->regexfile.init(1, true);
1358 fo->wild.init(1, true);
1359 fo->wilddir.init(1, true);
1360 fo->wildfile.init(1, true);
1361 fo->wildbase.init(1, true);
1362 fo->base.init(1, true);
1363 fo->fstype.init(1, true);
1364 fo->drivetype.init(1, true);
1365 incexe->current_opts = fo;
1366 incexe->opts_list.prepend(fo);
1367 jcr->ff->fileset->state = state_options;
1371 * Add a regex to the current fileset
1373 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1375 findFOPTS *current_opts = start_options(jcr->ff);
1380 preg = (regex_t *)malloc(sizeof(regex_t));
1381 if (current_opts->flags & FO_IGNORECASE) {
1382 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1384 rc = regcomp(preg, item, REG_EXTENDED);
1387 regerror(rc, preg, prbuf, sizeof(prbuf));
1390 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1394 current_opts->regex.append(preg);
1395 } else if (type == 'D') {
1396 current_opts->regexdir.append(preg);
1397 } else if (type == 'F') {
1398 current_opts->regexfile.append(preg);
1402 return state_options;
1406 * Add a wild card to the current fileset
1408 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1410 findFOPTS *current_opts = start_options(jcr->ff);
1413 current_opts->wild.append(bstrdup(item));
1414 } else if (type == 'D') {
1415 current_opts->wilddir.append(bstrdup(item));
1416 } else if (type == 'F') {
1417 current_opts->wildfile.append(bstrdup(item));
1418 } else if (type == 'B') {
1419 current_opts->wildbase.append(bstrdup(item));
1423 return state_options;
1428 * Add options to the current fileset
1430 int add_options_to_fileset(JCR *jcr, const char *item)
1432 findFOPTS *current_opts = start_options(jcr->ff);
1434 set_options(current_opts, item);
1435 return state_options;
1438 static void add_fileset(JCR *jcr, const char *item)
1440 FF_PKT *ff = jcr->ff;
1441 findFILESET *fileset = ff->fileset;
1442 int state = fileset->state;
1443 findFOPTS *current_opts;
1445 /* Get code, optional subcode, and position item past the dividing space */
1446 Dmsg1(100, "%s\n", item);
1451 int subcode = ' '; /* A space is always a valid subcode */
1452 if (item[0] != '\0' && item[0] != ' ') {
1460 /* Skip all lines we receive after an error */
1461 if (state == state_error) {
1462 Dmsg0(100, "State=error return\n");
1467 * The switch tests the code for validity.
1468 * The subcode is always good if it is a space, otherwise we must confirm.
1469 * We set state to state_error first assuming the subcode is invalid,
1470 * requiring state to be set in cases below that handle subcodes.
1472 if (subcode != ' ') {
1473 state = state_error;
1474 Dmsg0(100, "Set state=error or double code.\n");
1478 (void)new_include(jcr);
1481 (void)new_exclude(jcr);
1483 case 'N': /* null */
1486 case 'F': /* file = */
1487 /* File item to include or exclude list */
1488 state = state_include;
1489 add_file_to_fileset(jcr, item, true);
1491 case 'P': /* plugin */
1492 /* Plugin item to include list */
1493 state = state_include;
1494 add_file_to_fileset(jcr, item, false);
1496 case 'R': /* regex */
1497 state = add_regex_to_fileset(jcr, item, subcode);
1500 current_opts = start_options(ff);
1501 current_opts->base.append(bstrdup(item));
1502 state = state_options;
1504 case 'X': /* Filetype or Drive type */
1505 current_opts = start_options(ff);
1506 state = state_options;
1507 if (subcode == ' ') {
1508 current_opts->fstype.append(bstrdup(item));
1509 } else if (subcode == 'D') {
1510 current_opts->drivetype.append(bstrdup(item));
1512 state = state_error;
1515 case 'W': /* wild cards */
1516 state = add_wild_to_fileset(jcr, item, subcode);
1518 case 'O': /* Options */
1519 state = add_options_to_fileset(jcr, item);
1521 case 'Z': /* ignore dir */
1522 state = state_include;
1523 fileset->incexe->ignoredir = bstrdup(item);
1526 current_opts = start_options(ff);
1527 // current_opts->reader = bstrdup(item); /* deprecated */
1528 state = state_options;
1531 current_opts = start_options(ff);
1532 // current_opts->writer = bstrdup(item); /* deprecated */
1533 state = state_options;
1535 case 'G': /* Plugin command for this Option block */
1536 current_opts = start_options(ff);
1537 current_opts->plugin = bstrdup(item);
1538 state = state_options;
1541 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1542 state = state_error;
1545 ff->fileset->state = state;
1548 static bool term_fileset(JCR *jcr)
1550 FF_PKT *ff = jcr->ff;
1552 #ifdef xxx_DEBUG_CODE
1553 findFILESET *fileset = ff->fileset;
1556 for (i=0; i<fileset->include_list.size(); i++) {
1557 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1559 for (j=0; j<incexe->opts_list.size(); j++) {
1560 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1561 for (k=0; k<fo->regex.size(); k++) {
1562 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1564 for (k=0; k<fo->regexdir.size(); k++) {
1565 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1567 for (k=0; k<fo->regexfile.size(); k++) {
1568 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1570 for (k=0; k<fo->wild.size(); k++) {
1571 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1573 for (k=0; k<fo->wilddir.size(); k++) {
1574 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1576 for (k=0; k<fo->wildfile.size(); k++) {
1577 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1579 for (k=0; k<fo->wildbase.size(); k++) {
1580 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1582 for (k=0; k<fo->base.size(); k++) {
1583 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1585 for (k=0; k<fo->fstype.size(); k++) {
1586 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1588 for (k=0; k<fo->drivetype.size(); k++) {
1589 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1592 if (incexe->ignoredir) {
1593 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1596 foreach_dlist(node, &incexe->name_list) {
1597 Dmsg1(400, "F %s\n", node->c_str());
1599 foreach_dlist(node, &incexe->plugin_list) {
1600 Dmsg1(400, "P %s\n", node->c_str());
1603 for (i=0; i<fileset->exclude_list.size(); i++) {
1604 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1606 for (j=0; j<incexe->opts_list.size(); j++) {
1607 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1608 for (k=0; k<fo->regex.size(); k++) {
1609 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1611 for (k=0; k<fo->regexdir.size(); k++) {
1612 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1614 for (k=0; k<fo->regexfile.size(); k++) {
1615 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1617 for (k=0; k<fo->wild.size(); k++) {
1618 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1620 for (k=0; k<fo->wilddir.size(); k++) {
1621 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1623 for (k=0; k<fo->wildfile.size(); k++) {
1624 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1626 for (k=0; k<fo->wildbase.size(); k++) {
1627 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1629 for (k=0; k<fo->base.size(); k++) {
1630 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1632 for (k=0; k<fo->fstype.size(); k++) {
1633 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1635 for (k=0; k<fo->drivetype.size(); k++) {
1636 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1640 foreach_dlist(node, &incexe->name_list) {
1641 Dmsg1(400, "F %s\n", node->c_str());
1643 foreach_dlist(node, &incexe->plugin_list) {
1644 Dmsg1(400, "P %s\n", node->c_str());
1648 return ff->fileset->state != state_error;
1653 * As an optimization, we should do this during
1654 * "compile" time in filed/job.c, and keep only a bit mask
1655 * and the Verify options.
1657 static int set_options(findFOPTS *fo, const char *opts)
1663 // Commented out as it is not backward compatible - KES
1665 for (p=opts; *p; p++) {
1667 case 'a': /* alway replace */
1668 case '0': /* no option */
1671 fo->flags |= FO_EXCLUDE;
1674 fo->flags |= FO_MULTIFS;
1676 case 'h': /* no recursion */
1677 fo->flags |= FO_NO_RECURSION;
1679 case 'H': /* no hard link handling */
1680 fo->flags |= FO_NO_HARDLINK;
1683 fo->flags |= FO_IGNORECASE;
1686 fo->flags |= FO_MD5;
1689 fo->flags |= FO_NOREPLACE;
1691 case 'p': /* use portable data format */
1692 fo->flags |= FO_PORTABLE;
1694 case 'R': /* Resource forks and Finder Info */
1695 fo->flags |= FO_HFSPLUS;
1697 case 'r': /* read fifo */
1698 fo->flags |= FO_READFIFO;
1703 fo->flags |= FO_SHA1;
1708 fo->flags |= FO_SHA256;
1712 fo->flags |= FO_SHA512;
1718 * If 2 or 3 is seen here, SHA2 is not configured, so
1719 * eat the option, and drop back to SHA-1.
1721 if (p[1] == '2' || p[1] == '3') {
1724 fo->flags |= FO_SHA1;
1729 fo->flags |= FO_SPARSE;
1732 fo->flags |= FO_MTIMEONLY;
1735 fo->flags |= FO_KEEPATIME;
1738 fo->flags |= FO_ACL;
1740 case 'V': /* verify options */
1741 /* Copy Verify Options */
1742 for (j=0; *p && *p != ':'; p++) {
1743 fo->VerifyOpts[j] = *p;
1744 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1748 fo->VerifyOpts[j] = 0;
1750 case 'C': /* accurate options */
1751 /* Copy Accurate Options */
1752 for (j=0; *p && *p != ':'; p++) {
1753 fo->AccurateOpts[j] = *p;
1754 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1758 fo->AccurateOpts[j] = 0;
1760 case 'J': /* Basejob options */
1761 /* Copy BaseJob Options */
1762 for (j=0; *p && *p != ':'; p++) {
1763 fo->BaseJobOpts[j] = *p;
1764 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1768 fo->BaseJobOpts[j] = 0;
1770 case 'P': /* strip path */
1773 for (j=0; *p && *p != ':'; p++) {
1775 if (j < (int)sizeof(strip) - 1) {
1780 fo->strip_path = atoi(strip);
1781 fo->flags |= FO_STRIPPATH;
1782 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1785 fo->flags |= FO_IF_NEWER;
1788 fo->flags |= FO_ENHANCEDWILD;
1790 case 'Z': /* compression */
1792 if (*p >= '0' && *p <= '9') {
1793 fo->flags |= FO_COMPRESS;
1794 fo->Compress_algo = COMPRESS_GZIP;
1795 fo->Compress_level = *p - '0';
1797 else if (*p == 'o') {
1798 fo->flags |= FO_COMPRESS;
1799 fo->Compress_algo = COMPRESS_LZO1X;
1800 fo->Compress_level = 1; /* not used with LZO */
1804 fo->flags |= FO_NOATIME;
1807 fo->flags |= FO_CHKCHANGES;
1810 fo->flags |= FO_HONOR_NODUMP;
1813 fo->flags |= FO_XATTR;
1816 Jmsg1(NULL, M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1820 return state_options;
1825 * Director is passing his Fileset
1827 static int fileset_cmd(JCR *jcr)
1829 POOL_MEM buf(PM_MESSAGE);
1830 BSOCK *dir = jcr->dir_bsock;
1833 jcr->Snapshot = (strstr(dir->msg, "snap=1") != NULL);
1834 if (!init_fileset(jcr)) {
1837 while (dir->recv() >= 0) {
1838 strip_trailing_junk(dir->msg);
1839 Dmsg1(500, "Fileset: %s\n", dir->msg);
1840 pm_strcpy(buf, dir->msg);
1841 add_fileset(jcr, buf.c_str());
1843 if (!term_fileset(jcr)) {
1846 rtnstat = dir->fsend(OKinc);
1847 generate_plugin_event(jcr, bEventEndFileSet);
1853 * The Director sends us the component info file, which
1854 * we will in turn pass to the VSS plugin.
1856 static int component_cmd(JCR *jcr)
1858 BSOCK *dir = jcr->dir_bsock;
1860 while (dir->recv() >= 0) {
1861 Dmsg1(200, "filed<dird: component: %s", dir->msg);
1862 generate_plugin_event(jcr, bEventComponentInfo, (void *)dir->msg);
1864 return dir->fsend(OKComponentInfo);
1869 * Get backup level from Director
1871 * Note: there are odd things such as accurate_differential,
1872 * and accurate_incremental that are passed in level, thus
1873 * the calls to strstr() below.
1876 static int level_cmd(JCR *jcr)
1878 BSOCK *dir = jcr->dir_bsock;
1879 POOLMEM *level, *buf = NULL;
1882 level = get_memory(dir->msglen+1);
1883 Dmsg1(10, "level_cmd: %s", dir->msg);
1885 /* keep compatibility with older directors */
1886 if (strstr(dir->msg, "accurate")) {
1887 jcr->accurate = true;
1889 if (strstr(dir->msg, "rerunning")) {
1890 jcr->rerunning = true;
1892 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1895 /* Base backup requested? */
1896 if (strcasecmp(level, "base") == 0) {
1897 jcr->setJobLevel(L_BASE);
1898 /* Full backup requested? */
1899 } else if (strcasecmp(level, "full") == 0) {
1900 jcr->setJobLevel(L_FULL);
1901 } else if (strstr(level, "differential")) {
1902 jcr->setJobLevel(L_DIFFERENTIAL);
1905 } else if (strstr(level, "incremental")) {
1906 jcr->setJobLevel(L_INCREMENTAL);
1910 * We get his UTC since time, then sync the clocks and correct it
1911 * to agree with our clock.
1913 } else if (strcasecmp(level, "since_utime") == 0) {
1914 buf = get_memory(dir->msglen+1);
1915 utime_t since_time, adj;
1916 btime_t his_time, bt_start, rt=0, bt_adj=0, his_time_prev=0, n=0;
1917 if (jcr->getJobLevel() == L_NONE) {
1918 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1920 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1921 buf, &mtime_only, jcr->PrevJob) != 3) {
1922 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1923 buf, &mtime_only) != 2) {
1927 since_time = str_to_uint64(buf); /* this is the since time */
1928 Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1929 char ed1[50], ed2[50];
1931 * Sync clocks by polling him for the time. We take
1932 * 10 samples of his time throwing out the first two.
1934 for (int i=0; i<10; i++) {
1935 bt_start = get_current_btime();
1936 dir->signal(BNET_BTIME); /* poll for time */
1937 if (dir->recv() <= 0) { /* get response */
1940 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1943 his_time = str_to_uint64(buf);
1944 rt = get_current_btime() - bt_start; /* compute round trip time */
1945 /* skip first two results and check for leap second */
1946 /* if any of the FD or DIR went back in time, skip this iteration */
1947 if (i < 2 || (his_time_prev > 0 && his_time < his_time_prev) || rt<0) {
1948 his_time_prev = his_time;
1951 his_time_prev = his_time;
1953 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1954 edit_uint64(bt_start, ed2));
1955 bt_adj += bt_start - his_time - rt/2;
1956 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1959 if (n > 0) { /* Should be 1 in the worst case */
1960 bt_adj = bt_adj / n; /* compute average time */
1961 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1962 adj = btime_to_utime(bt_adj);
1963 since_time += adj; /* adjust for clock difference */
1965 /* Don't notify if time within 3 seconds */
1966 if (adj > 3 || adj < -3) {
1968 if (adj > 600 || adj < -600) {
1973 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1975 dir->signal(BNET_EOD);
1977 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1978 jcr->incremental = 1; /* set incremental or decremental backup */
1979 jcr->mtime = since_time; /* set since time */
1980 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1982 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1990 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1991 return dir->fsend(OKlevel);
1994 pm_strcpy(jcr->errmsg, dir->msg);
1995 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
2004 * Get session parameters from Director -- this is for a Restore command
2005 * This is deprecated. It is now passed via the bsr.
2007 static int session_cmd(JCR *jcr)
2009 BSOCK *dir = jcr->dir_bsock;
2011 Dmsg1(100, "SessionCmd: %s", dir->msg);
2012 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
2013 &jcr->VolSessionId, &jcr->VolSessionTime,
2014 &jcr->StartFile, &jcr->EndFile,
2015 &jcr->StartBlock, &jcr->EndBlock) != 7) {
2016 pm_strcpy(jcr->errmsg, dir->msg);
2017 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
2021 return dir->fsend(OKsession);
2024 static void set_storage_auth_key(JCR *jcr, char *key)
2026 /* if no key don't update anything */
2032 * We can be contacting multiple storage daemons.
2033 * So, make sure that any old jcr->store_bsock is cleaned up.
2035 free_bsock(jcr->store_bsock);
2038 * We can be contacting multiple storage daemons.
2039 * So, make sure that any old jcr->sd_auth_key is cleaned up.
2041 if (jcr->sd_auth_key) {
2043 * If we already have a Authorization key, director can do multi
2046 Dmsg0(5, "set multi_restore=true\n");
2047 jcr->multi_restore = true;
2048 bfree(jcr->sd_auth_key);
2051 jcr->sd_auth_key = bstrdup(key);
2052 Dmsg1(200, "set sd auth key %s\n", jcr->sd_auth_key);
2056 * Get address of storage daemon from Director
2059 static int storage_cmd(JCR *jcr)
2061 int stored_port = 0; /* storage daemon port */
2062 int enable_ssl; /* enable ssl to sd */
2063 POOL_MEM sd_auth_key(PM_MESSAGE);
2064 BSOCK *dir = jcr->dir_bsock;
2067 Dmsg1(100, "StorageCmd: %s", dir->msg);
2068 sd_auth_key.check_size(dir->msglen);
2069 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
2070 &enable_ssl, sd_auth_key.c_str()) == 4) {
2071 Dmsg1(100, "Set auth key %s\n", sd_auth_key.c_str());
2072 set_storage_auth_key(jcr, sd_auth_key.c_str());
2073 } else if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
2074 &stored_port, &enable_ssl) != 3) {
2075 pm_strcpy(jcr->errmsg, dir->msg);
2076 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
2077 Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
2082 /* TODO: see if we put limit on restore and backup... */
2083 if (!jcr->max_bandwidth) {
2084 if (jcr->director->max_bandwidth_per_job) {
2085 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
2087 } else if (me->max_bandwidth_per_job) {
2088 jcr->max_bandwidth = me->max_bandwidth_per_job;
2092 if (stored_port != 0) { /* We are doing the connecting */
2093 Dmsg3(110, "Connect to storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
2095 jcr->sd_calls_client = false;
2097 /* Open command communications with Storage daemon */
2098 /* Try to connect for 1 hour at 10 second intervals */
2099 sd->set_source_address(me->FDsrc_addr);
2100 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
2101 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
2102 /* destroy() OK because sd is local */
2104 Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
2105 jcr->stored_addr, stored_port);
2106 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
2107 jcr->stored_addr, stored_port);
2111 Dmsg0(110, "Connection OK to SD.\n");
2112 jcr->store_bsock = sd;
2113 } else { /* The storage daemon called us */
2116 struct timespec timeout;
2119 free_bsock(jcr->store_bsock);
2120 jcr->sd_calls_client = true;
2123 * Wait for the Storage daemon to contact us to start the Job,
2124 * when he does, we will be released, unless the 30 minutes
2127 gettimeofday(&tv, &tz);
2128 timeout.tv_nsec = tv.tv_usec * 1000;
2129 timeout.tv_sec = tv.tv_sec + 30 * 60; /* wait 30 minutes */
2131 while (jcr->sd_calls_client_bsock == NULL && !jcr->is_job_canceled()) {
2132 errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
2133 if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
2136 Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
2139 Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
2141 /* We should already have a storage connection! */
2142 if (jcr->sd_calls_client_bsock == NULL) {
2143 Pmsg0(000, "Failed connect from Storage daemon. SD bsock=NULL.\n");
2144 Pmsg1(000, "Storagecmd: %s", dir->msg);
2145 Jmsg0(jcr, M_FATAL, 0, _("Failed connect from Storage daemon. SD bsock=NULL.\n"));
2148 if (jcr->is_job_canceled()) {
2151 /* Assign the new socket to the main one */
2153 jcr->store_bsock = jcr->sd_calls_client_bsock;
2154 jcr->sd_calls_client_bsock = NULL;
2157 jcr->store_bsock->set_bwlimit(jcr->max_bandwidth);
2159 if (!send_hello_sd(jcr, jcr->Job)) {
2163 if (!authenticate_storagedaemon(jcr)) {
2166 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
2167 Dmsg0(110, "Authenticated with SD.\n");
2169 /* Send OK to Director */
2170 return dir->fsend(OKstore);
2173 dir->fsend(BADcmd, "storage");
2181 static int backup_cmd(JCR *jcr)
2183 BSOCK *dir = jcr->dir_bsock;
2184 BSOCK *sd = jcr->store_bsock;
2189 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
2190 jcr->JobFiles = FileIndex;
2191 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
2195 * If explicitly requesting FO_ACL or FO_XATTR, fail job if it
2196 * is not available on Client machine
2198 if (jcr->ff->flags & FO_ACL && !(have_acl)) {
2199 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for Client.\n"));
2202 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
2203 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for Client.\n"));
2206 jcr->setJobStatus(JS_Blocked);
2207 jcr->setJobType(JT_BACKUP);
2208 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
2210 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
2211 dir->fsend(BADcmd, "backup");
2215 dir->fsend(OKbackup);
2216 Dmsg1(110, "filed>dird: %s", dir->msg);
2219 * Send Append Open Session to Storage daemon
2221 sd->fsend(append_open);
2222 Dmsg1(110, ">stored: %s", sd->msg);
2224 * Expect to receive back the Ticket number
2226 if (bget_msg(sd) >= 0) {
2227 Dmsg1(110, "<stored: %s", sd->msg);
2228 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2229 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2232 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
2234 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2239 * Send Append data command to Storage daemon
2241 sd->fsend(append_data, jcr->Ticket);
2242 Dmsg1(110, ">stored: %s", sd->msg);
2245 * Expect to get OK data
2247 Dmsg1(110, "<stored: %s", sd->msg);
2248 if (!response(jcr, sd, OK_data, "Append Data")) {
2252 generate_daemon_event(jcr, "JobStart");
2253 generate_plugin_event(jcr, bEventStartBackupJob);
2255 if (jcr->Snapshot) {
2256 Dmsg0(10, "Open a snapshot session\n");
2257 /* TODO: See if we abort the job */
2258 jcr->Snapshot = open_snapshot_backup_session(jcr);
2260 /* Call RunScript just after the Snapshot creation, usually, we restart services */
2261 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2264 * Send Files to Storage daemon
2266 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
2267 if (!blast_data_to_storage_daemon(jcr, NULL)) {
2268 jcr->setJobStatus(JS_ErrorTerminated);
2269 sd->suppress_error_messages(true);
2270 Dmsg0(110, "Error in blast_data.\n");
2272 jcr->setJobStatus(JS_Terminated);
2273 /* Note, the above set status will not override an error */
2274 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
2275 sd->suppress_error_messages(true);
2276 goto cleanup; /* bail out now */
2279 * Expect to get response to append_data from Storage daemon
2281 if (!response(jcr, sd, OK_append, "Append Data")) {
2282 jcr->setJobStatus(JS_ErrorTerminated);
2287 * Send Append End Data to Storage daemon
2289 sd->fsend(append_end, jcr->Ticket);
2291 if (!response(jcr, sd, OK_end, "Append End")) {
2292 jcr->setJobStatus(JS_ErrorTerminated);
2297 * Send Append Close to Storage daemon
2299 sd->fsend(append_close, jcr->Ticket);
2300 while (bget_msg(sd) >= 0) { /* stop on signal or error */
2301 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2303 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2307 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2310 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings ||
2311 SDJobStatus == JS_Incomplete)) {
2312 Jmsg(jcr, M_FATAL, 0, _("Bad status %d %c returned from Storage Daemon.\n"),
2313 SDJobStatus, (char)SDJobStatus);
2318 generate_plugin_event(jcr, bEventEndBackupJob);
2319 return 0; /* return and stop command loop */
2323 * Do a Verify for Director
2326 static int verify_cmd(JCR *jcr)
2328 BSOCK *dir = jcr->dir_bsock;
2329 BSOCK *sd = jcr->store_bsock;
2332 jcr->setJobType(JT_VERIFY);
2333 if (sscanf(dir->msg, verifycmd, level) != 1) {
2334 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2338 if (strcasecmp(level, "init") == 0) {
2339 jcr->setJobLevel(L_VERIFY_INIT);
2340 } else if (strcasecmp(level, "catalog") == 0){
2341 jcr->setJobLevel(L_VERIFY_CATALOG);
2342 } else if (strcasecmp(level, "volume") == 0){
2343 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2344 } else if (strcasecmp(level, "data") == 0){
2345 jcr->setJobLevel(L_VERIFY_DATA);
2346 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2347 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2349 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2353 dir->fsend(OKverify);
2355 generate_daemon_event(jcr, "JobStart");
2356 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2357 generate_plugin_event(jcr, bEventStartVerifyJob);
2359 Dmsg1(110, "filed>dird: %s", dir->msg);
2361 switch (jcr->getJobLevel()) {
2363 case L_VERIFY_CATALOG:
2367 case L_VERIFY_VOLUME_TO_CATALOG:
2368 if (!open_sd_read_session(jcr)) {
2371 start_dir_heartbeat(jcr);
2372 do_verify_volume(jcr);
2373 stop_dir_heartbeat(jcr);
2375 * Send Close session command to Storage daemon
2377 sd->fsend(read_close, jcr->Ticket);
2378 Dmsg1(130, "filed>stored: %s", sd->msg);
2380 /* ****FIXME**** check response */
2381 bget_msg(sd); /* get OK */
2383 /* Inform Storage daemon that we are done */
2384 sd->signal(BNET_TERMINATE);
2387 case L_VERIFY_DISK_TO_CATALOG:
2391 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2395 dir->signal(BNET_EOD);
2396 generate_plugin_event(jcr, bEventEndVerifyJob);
2397 return 0; /* return and terminate command loop */
2401 * Do a Restore for Director
2404 static int restore_cmd(JCR *jcr)
2406 BSOCK *dir = jcr->dir_bsock;
2407 BSOCK *sd = jcr->store_bsock;
2408 POOLMEM *args=NULL, *restore_where=NULL, *restore_rwhere=NULL;
2409 bool use_regexwhere=false;
2412 bool scan_ok = true;
2417 * Scan WHERE (base directory for restore) from command
2419 Dmsg0(100, "restore command\n");
2421 /* Pickup where string */
2422 args = get_memory(dir->msglen+1);
2425 restore_where = get_pool_memory(PM_FNAME);
2426 restore_rwhere = get_pool_memory(PM_FNAME);
2428 /* We don't know the size of where/rwhere in advance,
2429 * where= -> where=%202s\n
2431 Mmsg(restore_where, "%s%%%ds\n", restorefcmd, dir->msglen);
2432 Mmsg(restore_rwhere, "%s%%%ds\n", restorefcmdR, dir->msglen);
2434 Dmsg2(200, "where=%srwhere=%s", restore_where, restore_rwhere);
2436 /* Scan for new form with number of files to restore */
2437 if (sscanf(dir->msg, restore_where, &files, &replace, &prefix_links, args) != 4) {
2438 if (sscanf(dir->msg, restore_rwhere, &files, &replace, &prefix_links, args) != 4) {
2439 if (sscanf(dir->msg, restorefcmd1, &files, &replace, &prefix_links) != 3) {
2442 *args = 0; /* No where argument */
2444 use_regexwhere = true;
2449 jcr->ExpectedFiles = files;
2451 /* Scan for old form without number of files */
2452 jcr->ExpectedFiles = 0;
2454 /* where= -> where=%202s\n */
2455 Mmsg(restore_where, "%s%%%ds\n", restorecmd, dir->msglen);
2456 Mmsg(restore_rwhere, "%s%%%ds\n", restorecmdR, dir->msglen);
2458 if (sscanf(dir->msg, restore_where, &replace, &prefix_links, args) != 3) {
2459 if (sscanf(dir->msg, restore_rwhere, &replace, &prefix_links, args) != 3){
2460 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2461 pm_strcpy(jcr->errmsg, dir->msg);
2462 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2465 *args = 0; /* No where argument */
2467 use_regexwhere = true;
2472 /* Turn / into nothing */
2473 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2477 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2478 unbash_spaces(args);
2480 /* Keep track of newly created directories to apply them correct attributes */
2481 if (replace == REPLACE_NEVER || replace == REPLACE_IFNEWER) {
2482 jcr->keep_path_list = true;
2485 if (use_regexwhere) {
2486 jcr->where_bregexp = get_bregexps(args);
2487 if (!jcr->where_bregexp) {
2488 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2492 jcr->where = bstrdup(args);
2495 jcr->replace = replace;
2496 jcr->prefix_links = prefix_links;
2498 dir->fsend(OKrestore);
2499 Dmsg1(110, "filed>dird: %s", dir->msg);
2501 jcr->setJobType(JT_RESTORE);
2503 jcr->setJobStatus(JS_Blocked);
2505 if (!open_sd_read_session(jcr)) {
2506 jcr->setJobStatus(JS_ErrorTerminated);
2510 jcr->setJobStatus(JS_Running);
2513 * Do restore of files and data
2515 start_dir_heartbeat(jcr);
2516 generate_daemon_event(jcr, "JobStart");
2517 generate_plugin_event(jcr, bEventStartRestoreJob);
2519 if (!jcr->is_canceled()) {
2523 stop_dir_heartbeat(jcr);
2525 jcr->setJobStatus(JS_Terminated);
2526 if (jcr->JobStatus != JS_Terminated) {
2527 sd->suppress_error_messages(true);
2531 * Send Close session command to Storage daemon
2533 sd->fsend(read_close, jcr->Ticket);
2534 Dmsg1(100, "filed>stored: %s", sd->msg);
2536 bget_msg(sd); /* get OK */
2538 /* Inform Storage daemon that we are done */
2539 sd->signal(BNET_TERMINATE);
2542 bfree_and_null(jcr->where);
2544 if (jcr->JobErrors) {
2545 jcr->setJobStatus(JS_ErrorTerminated);
2548 Dmsg0(100, "Done in job.c\n");
2550 if (jcr->multi_restore) {
2551 Dmsg0(100, OKstoreend);
2552 dir->fsend(OKstoreend);
2553 ret = 1; /* we continue the loop, waiting for next part */
2555 ret = 0; /* we stop here */
2558 if (job_canceled(jcr)) {
2559 ret = 0; /* we stop here */
2563 end_restore_cmd(jcr); /* stopping so send bEventEndRestoreJob */
2567 free_and_null_pool_memory(args);
2568 free_and_null_pool_memory(restore_where);
2569 free_and_null_pool_memory(restore_rwhere);
2574 static int end_restore_cmd(JCR *jcr)
2576 Dmsg0(5, "end_restore_cmd\n");
2577 generate_plugin_event(jcr, bEventEndRestoreJob);
2578 return 0; /* return and terminate command loop */
2581 static int open_sd_read_session(JCR *jcr)
2583 BSOCK *sd = jcr->store_bsock;
2586 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2589 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2590 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2591 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2593 * Open Read Session with Storage daemon
2595 sd->fsend(read_open, "DummyVolume",
2596 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2597 jcr->StartBlock, jcr->EndBlock);
2598 Dmsg1(110, ">stored: %s", sd->msg);
2603 if (bget_msg(sd) >= 0) {
2604 Dmsg1(110, "filed<stored: %s", sd->msg);
2605 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2606 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2609 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2611 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2616 * Use interactive session for the current restore
2618 if (jcr->interactive_session) {
2619 sd->fsend(read_ctrl, jcr->Ticket);
2620 Dmsg1(110, ">stored: %s", sd->msg);
2624 * Start read of data with Storage daemon
2626 sd->fsend(read_data, jcr->Ticket);
2627 Dmsg1(110, ">stored: %s", sd->msg);
2632 if (!response(jcr, sd, OK_data, "Read Data")) {
2639 * Destroy the Job Control Record and associated
2640 * resources (sockets).
2642 static void filed_free_jcr(JCR *jcr)
2644 if (jcr->dir_bsock) {
2645 free_bsock(jcr->dir_bsock);
2646 jcr->dir_bsock = NULL;
2648 if (jcr->sd_calls_client_bsock) {
2649 free_bsock(jcr->sd_calls_client_bsock);
2650 jcr->sd_calls_client_bsock = NULL;
2652 if (jcr->store_bsock) {
2653 free_bsock(jcr->store_bsock);
2654 jcr->store_bsock = NULL;
2656 if (jcr->last_fname) {
2657 free_pool_memory(jcr->last_fname);
2659 free_plugins(jcr); /* release instantiated plugins */
2660 free_runscripts(jcr->RunScripts);
2661 delete jcr->RunScripts;
2662 free_path_list(jcr);
2664 if (jcr->JobId != 0) {
2665 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2671 * Get response from Storage daemon to a command we
2672 * sent. Check that the response is OK.
2674 * Returns: 0 on failure
2677 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2684 if ((ret = bget_msg(sd)) > 0) {
2685 Dmsg0(110, sd->msg);
2686 if (strcmp(sd->msg, resp) == 0) {
2690 if (job_canceled(jcr)) {
2691 return 0; /* if canceled avoid useless error messages */
2693 if (sd->is_error()) {
2694 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2695 cmd, sd->bstrerror());
2699 Jmsg4(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got len=%ld msg=\"%s\"\n"),
2700 cmd, resp, sd->msglen, smartdump(sd->msg, sd->msglen, buf, sizeof(buf)));
2702 Jmsg3(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got SIGNAL %s\n"),
2703 cmd, resp, bnet_sig_to_ascii(ret));