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 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
34 bool win32decomp = false;
35 bool no_win32_write_errors = false;
37 /* Static variables */
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
41 const bool have_win32 = true;
43 const bool have_win32 = false;
47 const bool have_acl = true;
49 const bool have_acl = false;
53 const bool have_xattr = true;
55 const bool have_xattr = false;
58 extern CLIENT *me; /* our client resource */
60 /* Imported functions */
61 extern int status_cmd(JCR *jcr);
62 extern int qstatus_cmd(JCR *jcr);
63 extern int accurate_cmd(JCR *jcr);
65 /* Forward referenced functions */
66 static int backup_cmd(JCR *jcr);
67 static int component_cmd(JCR *jcr);
68 static int cancel_cmd(JCR *jcr);
69 static int setdebug_cmd(JCR *jcr);
70 static int setbandwidth_cmd(JCR *jcr);
71 static int estimate_cmd(JCR *jcr);
72 static int hello_cmd(JCR *jcr);
73 static int job_cmd(JCR *jcr);
74 static int fileset_cmd(JCR *jcr);
75 static int level_cmd(JCR *jcr);
76 static int verify_cmd(JCR *jcr);
77 static int restore_cmd(JCR *jcr);
78 static int end_restore_cmd(JCR *jcr);
79 static int storage_cmd(JCR *jcr);
80 static int session_cmd(JCR *jcr);
81 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
82 static void filed_free_jcr(JCR *jcr);
83 static int open_sd_read_session(JCR *jcr);
84 static int runscript_cmd(JCR *jcr);
85 static int runbefore_cmd(JCR *jcr);
86 static int runafter_cmd(JCR *jcr);
87 static int runbeforenow_cmd(JCR *jcr);
88 static int restore_object_cmd(JCR *jcr);
89 static int set_options(findFOPTS *fo, const char *opts);
90 static void set_storage_auth_key(JCR *jcr, char *key);
91 static int sm_dump_cmd(JCR *jcr);
92 static int proxy_cmd(JCR *jcr);
93 static int fd_testnetwork_cmd(JCR *jcr);
95 static int exit_cmd(JCR *jcr);
98 /* Exported functions */
100 #define ACCESS_MONITOR 1
101 #define ACCESS_REMOTE 2
104 * The following are the recognized commands from the Director.
106 struct s_cmds cmds[] = {
107 {"backup", backup_cmd, 0},
108 {"cancel", cancel_cmd, ACCESS_REMOTE},
109 {"setdebug=", setdebug_cmd, 0},
110 {"setbandwidth=",setbandwidth_cmd, ACCESS_REMOTE},
111 {"snapshot", snapshot_cmd, 0},
112 {"estimate", estimate_cmd, 0},
113 {"Hello", hello_cmd, 1},
114 {"fileset", fileset_cmd, 0},
115 {"JobId=", job_cmd, 0},
116 {"level = ", level_cmd, 0},
117 {"restore ", restore_cmd, 0},
118 {"endrestore", end_restore_cmd, 0},
119 {"session", session_cmd, 0},
120 {"status", status_cmd, ACCESS_MONITOR|ACCESS_REMOTE},
121 {".status", qstatus_cmd, ACCESS_MONITOR|ACCESS_REMOTE},
122 {"storage ", storage_cmd, 0},
123 {"verify", verify_cmd, 0},
124 {"component", component_cmd, 0},
125 {"RunBeforeNow", runbeforenow_cmd, 0},
126 {"RunBeforeJob", runbefore_cmd, 0},
127 {"RunAfterJob", runafter_cmd, 0},
128 {"Run", runscript_cmd, 0},
129 {"accurate", accurate_cmd, 0},
130 {"restoreobject", restore_object_cmd, 0},
131 {"sm_dump", sm_dump_cmd, 0},
132 {"stop", cancel_cmd, ACCESS_REMOTE},
133 {"proxy", proxy_cmd, ACCESS_REMOTE},
134 {"testnetwork", fd_testnetwork_cmd, 0},
136 {"exit", exit_cmd, 0},
138 {NULL, NULL} /* list terminator */
141 /* Commands received from director that need scanning */
142 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
143 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
144 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
145 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
147 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
148 static char restorefcmd1[] = "restore files=%d replace=%c prelinks=%d where=\n";
150 /* The following restore commands may have a big where=/regexwhere= parameter
151 * the bsscanf is limiting the default %s to 1000c. To allow more than 1000 bytes,
152 * we can specify %xxxxs where xxxx is the size expected in bytes.
154 * So, the code will add %s\n to the end of the following restore commands
156 static char restorecmd[] = "restore replace=%c prelinks=%d where=";
157 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=";
158 static char restorefcmd[] = "restore files=%d replace=%c prelinks=%d where=";
159 static char restorefcmdR[] = "restore files=%d replace=%c prelinks=%d regexwhere=";
161 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
162 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
163 static char endrestoreobjectcmd[] = "restoreobject end\n";
164 static char verifycmd[] = "verify level=%30s";
165 static char estimatecmd[] = "estimate listing=%d";
166 static char runbefore[] = "RunBeforeJob %s";
167 static char runafter[] = "RunAfterJob %s";
168 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
169 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
171 /* Responses sent to Director */
172 static char errmsg[] = "2999 Invalid command\n";
173 static char no_auth[] = "2998 No Authorization\n";
174 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
175 static char OKBandwidth[] = "2000 OK Bandwidth\n";
176 static char OKinc[] = "2000 OK include\n";
177 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
178 static char OKlevel[] = "2000 OK level\n";
179 static char OKbackup[] = "2000 OK backup\n";
180 static char OKverify[] = "2000 OK verify\n";
181 static char OKrestore[] = "2000 OK restore\n";
182 static char OKsession[] = "2000 OK session\n";
183 static char OKstore[] = "2000 OK storage\n";
184 static char OKstoreend[] = "2000 OK storage end\n";
185 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
186 static char OKsetdebug[] = "2000 OK setdebug=%ld trace=%ld hangup=%ld"
187 " blowup=%ld options=%s tags=%s\n";
188 static char BADjob[] = "2901 Bad Job\n";
189 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%d ReadBytes=%lld"
190 " JobBytes=%lld Errors=%d VSS=%d Encrypt=%d"
191 " CommBytes=%lld CompressCommBytes=%lld\n";
192 static char OKRunBefore[] = "2000 OK RunBefore\n";
193 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
194 static char OKRunAfter[] = "2000 OK RunAfter\n";
195 static char OKRunScript[] = "2000 OK RunScript\n";
196 static char BADcmd[] = "2902 Bad %s\n";
197 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
198 static char OKComponentInfo[] = "2000 OK ComponentInfo\n";
201 /* Responses received from Storage Daemon */
202 static char OK_end[] = "3000 OK end\n";
203 static char OK_close[] = "3000 OK close Status = %d\n";
204 static char OK_open[] = "3000 OK open ticket = %d\n";
205 static char OK_data[] = "3000 OK data\n";
206 static char OK_append[] = "3000 OK append data\n";
209 /* Commands sent to Storage Daemon */
210 static char append_open[] = "append open session\n";
211 static char append_data[] = "append data %d\n";
212 static char append_end[] = "append end session %d\n";
213 static char append_close[] = "append close session %d\n";
214 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
215 static char read_data[] = "read data %d\n";
216 static char read_close[] = "read close session %d\n";
217 static char read_ctrl[] = "read control %d\n";
219 /* Should tell us if a command is authorized or not */
220 static bool access_ok(struct s_cmds *cmd, DIRRES* dir)
222 if ((cmd->access & ACCESS_MONITOR) && dir->monitor) {
225 if ((cmd->access & ACCESS_REMOTE) && dir->remote) {
228 if (!dir->remote && !dir->monitor) {
235 * Accept requests from a Director
237 * NOTE! We are running as a separate thread
239 * Send output one line
240 * at a time followed by a zero length transmission.
242 * Return when the connection is terminated or there
245 * Basic task here is:
246 * Authenticate Director (during Hello command).
247 * Accept commands one at a time from the Director
250 * Concerning ClientRunBefore/After, the sequence of events
251 * is rather critical. If they are not done in the right
252 * order one can easily get FD->SD timeouts if the script
255 * The current sequence of events is:
256 * 1. Dir starts job with FD
257 * 2. Dir connects to SD
258 * 3. Dir connects to FD
259 * 4. FD connects to SD
260 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
261 * 6. Dir sends include/exclude
262 * 7. FD sends the file data to SD
263 * 8. SD/FD disconnects while the SD despools data and attributes (optional)
264 * 9. FD runs ClientRunAfterJob
267 static void *handle_director_request(BSOCK *dir)
273 const char jobname[12] = "*Director*";
275 prevent_os_suspensions(); /* do not suspend during backup/restore */
276 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
277 jcr->sd_calls_client_bsock = NULL;
278 jcr->sd_calls_client = false;
279 jcr->dir_bsock = dir;
280 jcr->ff = init_find_files();
281 jcr->start_time = time(NULL);
282 jcr->RunScripts = New(alist(10, not_owned_by_alist));
283 jcr->last_fname = get_pool_memory(PM_FNAME);
284 jcr->last_fname[0] = 0;
285 jcr->client_name = get_memory(strlen(my_name) + 1);
286 pm_strcpy(jcr->client_name, my_name);
287 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
288 jcr->crypto.pki_sign = me->pki_sign;
289 jcr->crypto.pki_encrypt = me->pki_encrypt;
290 jcr->crypto.pki_keypair = me->pki_keypair;
291 jcr->crypto.pki_signers = me->pki_signers;
292 jcr->crypto.pki_recipients = me->pki_recipients;
295 jcr->set_killable(true); /* allow dir to kill/cancel job */
296 /* Initialize SD start condition variable */
297 int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
300 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
303 enable_backup_privileges(NULL, 1 /* ignore_errors */);
305 for (quit=false; !quit;) {
306 if (!first) { /* first call the read is done */
308 if (dir->recv() < 0) {
309 break; /* connection terminated */
312 if (dir->msglen == 0) { /* Bad connection */
316 dir->msg[dir->msglen] = 0;
317 Dmsg1(100, "<dird: %s", dir->msg);
319 for (i=0; cmds[i].cmd; i++) {
320 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
321 found = true; /* indicate command found */
322 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
324 dir->signal(BNET_EOD);
327 if (jcr->authenticated && !access_ok(&cmds[i], jcr->director)) {
328 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
329 dir->fsend(invalid_cmd);
330 dir->signal(BNET_EOD);
333 if ((me->disabled_cmds_array && me->disabled_cmds_array[i]) ||
334 (jcr->director && jcr->director->disabled_cmds_array &&
335 jcr->director->disabled_cmds_array[i])) {
336 Jmsg(jcr, M_FATAL, 0, _("Command: \"%s\" is disabled.\n"), cmds[i].cmd);
340 Dmsg2(100, "Executing %s Dir %s command.\n", cmds[i].cmd, dir->msg);
341 if (!cmds[i].func(jcr)) { /* do command */
342 quit = true; /* error or fully terminated, get out */
343 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
348 if (!found) { /* command not found */
355 /* Inform Storage daemon that we are done */
356 if (jcr->store_bsock) {
357 jcr->store_bsock->signal(BNET_TERMINATE);
360 /* Run the after job */
361 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
363 /* send any queued messages before reporting the jobstatus to the director */
364 dequeue_messages(jcr);
366 if (jcr->JobId) { /* send EndJob if running a job */
367 uint64_t CommBytes, CommCompressedBytes;
368 uint32_t vss, encrypt;
369 /* Send termination status back to Dir */
370 if (jcr->store_bsock) {
371 CommBytes = jcr->store_bsock->CommBytes();
372 CommCompressedBytes = jcr->store_bsock->CommCompressedBytes();
374 CommBytes = CommCompressedBytes = 0;
376 encrypt = jcr->crypto.pki_encrypt;
378 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
379 jcr->ReadBytes, jcr->JobBytes, jcr->JobErrors, vss,
380 encrypt, CommBytes, CommCompressedBytes);
381 //Dmsg0(0, dir->msg);
384 generate_daemon_event(jcr, "JobEnd");
385 generate_plugin_event(jcr, bEventJobEnd);
388 dequeue_messages(jcr); /* send any queued messages, will no longer impact
389 * the job status... */
391 /* Inform Director that we are done */
392 dir->signal(BNET_TERMINATE);
394 free_and_null_pool_memory(jcr->job_metadata);
396 /* Clean up fileset */
397 FF_PKT *ff = jcr->ff;
398 findFILESET *fileset = ff->fileset;
401 /* Delete FileSet Include lists */
402 for (i=0; i<fileset->include_list.size(); i++) {
403 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
404 for (j=0; j<incexe->opts_list.size(); j++) {
405 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
409 for (k=0; k<fo->regex.size(); k++) {
410 regfree((regex_t *)fo->regex.get(k));
412 for (k=0; k<fo->regexdir.size(); k++) {
413 regfree((regex_t *)fo->regexdir.get(k));
415 for (k=0; k<fo->regexfile.size(); k++) {
416 regfree((regex_t *)fo->regexfile.get(k));
419 fo->regexdir.destroy();
420 fo->regexfile.destroy();
422 fo->wilddir.destroy();
423 fo->wildfile.destroy();
424 fo->wildbase.destroy();
426 fo->fstype.destroy();
427 fo->drivetype.destroy();
429 incexe->opts_list.destroy();
430 incexe->name_list.destroy();
431 incexe->plugin_list.destroy();
432 if (incexe->ignoredir) {
433 free(incexe->ignoredir);
436 fileset->include_list.destroy();
438 /* Delete FileSet Exclude lists */
439 for (i=0; i<fileset->exclude_list.size(); i++) {
440 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
441 for (j=0; j<incexe->opts_list.size(); j++) {
442 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
444 fo->regexdir.destroy();
445 fo->regexfile.destroy();
447 fo->wilddir.destroy();
448 fo->wildfile.destroy();
449 fo->wildbase.destroy();
451 fo->fstype.destroy();
452 fo->drivetype.destroy();
454 incexe->opts_list.destroy();
455 incexe->name_list.destroy();
456 incexe->plugin_list.destroy();
457 if (incexe->ignoredir) {
458 free(incexe->ignoredir);
461 fileset->exclude_list.destroy();
465 ff->mount_points.destroy();
466 Dmsg0(100, "Calling term_find_files\n");
467 term_find_files(jcr->ff);
469 Dmsg0(100, "Done with term_find_files\n");
470 pthread_cond_destroy(&jcr->job_start_wait);
471 free_jcr(jcr); /* destroy JCR record */
472 Dmsg0(100, "Done with free_jcr\n");
473 allow_os_suspensions(); /* FD can now be suspended */
475 garbage_collect_memory_pool();
481 * Accept requests from a Director or a Storage daemon
483 void *handle_connection_request(void *caller)
485 BSOCK *bs = (BSOCK *)caller;
487 if (bs->recv() > 0) {
488 if (strncmp(bs->msg, "Ping", 4) == 0) {
489 bs->fsend("2000 Ping OK\n");
493 if (bs->msglen < 25 || bs->msglen > 500) {
496 if (strncmp(bs->msg, "Hello FD: Bacula Storage", 20) ==0) {
497 return handle_storage_connection(bs);
499 if (strncmp(bs->msg, "Hello ", 5) == 0) {
500 return handle_director_request(bs);
504 Dmsg2(100, "Bad command from %s. Len=%d.\n", bs->who(), bs->msglen);
506 char *who = bs->get_peer(addr, sizeof(addr)) ? bs->who() : addr;
507 Jmsg2(NULL, M_FATAL, 0, _("Bad command from %s. Len=%d.\n"), who, bs->msglen);
514 * Test the Network between FD/SD
516 static int fd_testnetwork_cmd(JCR *jcr)
518 bool can_compress, ok=true;
519 BSOCK *sd = jcr->store_bsock;
524 if (!sd || !jcr->dir_bsock) {
527 if (sscanf(jcr->dir_bsock->msg, "testnetwork bytes=%lld", &nb) != 1 || nb <= 0) {
528 sd->fsend("2999 testnetwork command error\n");
532 /* We disable the comline compression, else all numbers will be wrong */
533 can_compress = sd->can_compress();
535 sd->fsend("testnetwork bytes=%lld\n", nb);
536 sd->clear_compress();
538 /* In the first step, we send X bytes to the SD */
539 memset(sd->msg, 0xAA, sizeof_pool_memory(sd->msg));
540 sd->msglen = sizeof_pool_memory(sd->msg);
542 start = get_current_btime();
543 for (nb2 = nb ; nb2 > 0 && ok ; nb2 -= sd->msglen) {
544 if (nb2 < sd->msglen) {
549 sd->signal(BNET_EOD);
550 end = get_current_btime() + 1;
556 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms write_speed=%sB/s\n",
557 nb, end/1000 - start/1000,
558 edit_uint64_with_suffix(nb * 1000000 / (end - start), ed1));
560 /* Now we receive X bytes from the SD */
561 start = get_current_btime();
562 for (nb2 = 0; sd->recv() > 0; nb2 += sd->msglen) { }
563 end = get_current_btime() + 1;
565 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms read_speed=%sB/s\n",
566 nb2, end/1000 - start/1000,
567 edit_uint64_with_suffix(nb2 * 1000000 / (end - start), ed1));
569 jcr->dir_bsock->signal(BNET_CMD_OK);
576 jcr->dir_bsock->fsend("2999 network test failed ERR=%s\n", sd->errmsg);
577 jcr->dir_bsock->signal(BNET_CMD_FAILED);
583 static int proxy_cmd(JCR *jcr)
585 bool OK=true, fdcalled = false;
587 CONSRES *cons = jcr->director->console;
593 cons = (CONSRES *)GetNextRes(R_CONSOLE, NULL);
595 /* Here, dir_bsock is not really the director, this is a console */
596 cons_bsock = connect_director(jcr, cons);
598 jcr->dir_bsock->signal(BNET_ERROR_MSG);
599 jcr->dir_bsock->fsend("2999 proxy error. ERR=%s\n", jcr->errmsg);
600 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
601 /* Error during the connect */
605 /* Inform the console that the command is OK */
606 jcr->dir_bsock->fsend("2000 proxy OK.\n");
607 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
609 maxfd = MAX(cons_bsock->m_fd, jcr->dir_bsock->m_fd) + 1;
611 /* Start to forward events from one to the other
612 * It can be done with 2 threads, or with a select
616 FD_SET((unsigned)cons_bsock->m_fd, &fdset);
617 FD_SET((unsigned)jcr->dir_bsock->m_fd, &fdset);
621 switch ((v = select(maxfd, &fdset, NULL, NULL, &tv))) {
622 case 0: /* timeout */
623 OK = !jcr->is_canceled();
626 Dmsg1(0, "Bad call to select ERR=%d\n", errno);
630 if (cons_bsock->tls && !tls_bsock_probe(cons_bsock)) {
631 /* maybe a session key negotiation waked up the socket */
632 FD_CLR(cons_bsock->m_fd, &fdset);
634 if (jcr->dir_bsock->tls && !tls_bsock_probe(jcr->dir_bsock)) {
635 /* maybe a session key negotiation waked up the socket */
636 FD_CLR(jcr->dir_bsock->m_fd, &fdset);
641 Dmsg1(DT_NETWORK, "select = %d\n", v);
643 if (FD_ISSET(cons_bsock->m_fd, &fdset)) {
644 v = cons_bsock->recv();
645 if (v == BNET_SIGNAL) {
646 if (cons_bsock->msglen == BNET_FDCALLED) {
650 jcr->dir_bsock->signal(cons_bsock->msglen);
654 jcr->dir_bsock->fsend("%s", cons_bsock->msg);
657 /* We should not have such kind of message */
661 if (FD_ISSET(jcr->dir_bsock->m_fd, &fdset)) {
662 v = jcr->dir_bsock->recv();
663 if (v == BNET_SIGNAL) {
664 cons_bsock->signal(jcr->dir_bsock->msglen);
666 cons_bsock->fsend("%s", jcr->dir_bsock->msg);
668 /* We should not have such kind of message */
673 if (cons_bsock->is_error() || jcr->dir_bsock->is_error()) {
676 } while (OK && !jcr->is_canceled());
678 /* Close the socket, nothing more will come */
679 jcr->dir_bsock->signal(BNET_TERMINATE);
680 jcr->dir_bsock->close();
682 handle_connection_request(cons_bsock); /* will release the socket */
684 free_bsock(cons_bsock);
689 static int sm_dump_cmd(JCR *jcr)
692 sm_dump(false, true);
693 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
698 static int exit_cmd(JCR *jcr)
700 jcr->dir_bsock->fsend("2000 exit OK\n");
707 * Hello from Director he must identify himself and provide his
710 static int hello_cmd(JCR *jcr)
712 Dmsg0(120, "Calling Authenticate\n");
713 if (!validate_dir_hello(jcr)) {
716 if (!authenticate_director(jcr)) {
719 Dmsg0(120, "OK Authenticate\n");
720 jcr->authenticated = true;
722 dequeue_messages(jcr); /* dequeue any daemon messages */
729 static int cancel_cmd(JCR *jcr)
731 BSOCK *dir = jcr->dir_bsock;
732 char Job[MAX_NAME_LENGTH];
737 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
738 status = JS_Canceled;
740 } else if (sscanf(dir->msg, "stop Job=%127s", Job) == 1) {
741 status = JS_Incomplete;
744 dir->fsend(_("2902 Error scanning cancel command.\n"));
747 if (!(cjcr=get_jcr_by_full_name(Job))) {
748 dir->fsend(_("2901 Job %s not found.\n"), Job);
750 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
751 cjcr->setJobStatus(status);
752 if (cjcr->store_bsock) {
753 cjcr->store_bsock->cancel();
755 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
757 dir->fsend(_("2001 Job \"%s\" marked to be %s.\n"),
762 dir->signal(BNET_EOD);
767 * Set bandwidth limit as requested by the Director
770 static int setbandwidth_cmd(JCR *jcr)
772 BSOCK *dir = jcr->dir_bsock;
775 char Job[MAX_NAME_LENGTH];
778 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
779 pm_strcpy(jcr->errmsg, dir->msg);
780 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
785 if(!(cjcr=get_jcr_by_full_name(Job))) {
786 dir->fsend(_("2901 Job %s not found.\n"), Job);
788 cjcr->max_bandwidth = bw;
789 if (cjcr->store_bsock) {
790 cjcr->store_bsock->set_bwlimit(bw);
795 } else { /* No job requested, apply globally */
796 me->max_bandwidth_per_job = bw; /* Overwrite directive */
798 cjcr->max_bandwidth = bw;
799 if (cjcr->store_bsock) {
800 cjcr->store_bsock->set_bwlimit(bw);
806 return dir->fsend(OKBandwidth);
810 * Set debug level as requested by the Director
813 static int setdebug_cmd(JCR *jcr)
815 BSOCK *dir = jcr->dir_bsock;
819 int64_t level, level_tags = 0;
824 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
825 tags[0] = options[0] = 0;
826 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld blowup=%ld"
827 " options=%55s tags=%511s",
828 &lvl, &trace, &hangup, &blowup, options, tags);
830 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld",
831 &lvl, &trace, &hangup);
833 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
834 if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace) != 2) {
835 pm_strcpy(jcr->errmsg, dir->msg);
836 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
847 if (!debug_parse_tags(tags, &level_tags)) {
853 debug_level_tags = level_tags;
855 /* Parse specific FD options */
856 for (char *p = options; *p ; p++) {
859 /* Turn on/off ignore bwrite() errors on restore */
860 no_win32_write_errors = true;
863 /* Turn on/off decomp of BackupRead() streams */
869 /* handle other options */
870 set_debug_flags(options);
872 Dmsg6(150, "level=%ld trace=%ld hangup=%ld blowup=%d options=%s tags=%s\n",
873 lvl, get_trace(), get_hangup(), get_blowup(), options, tags);
874 return dir->fsend(OKsetdebug, lvl, get_trace(), get_hangup(),
875 get_blowup(), options, tags);
879 static int estimate_cmd(JCR *jcr)
881 BSOCK *dir = jcr->dir_bsock;
882 char ed1[50], ed2[50];
884 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
885 pm_strcpy(jcr->errmsg, dir->msg);
886 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
887 dir->fsend(_("2992 Bad estimate command.\n"));
891 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
892 edit_uint64_with_commas(jcr->JobBytes, ed2));
893 dir->signal(BNET_EOD);
898 * Get JobId and Storage Daemon Authorization key from Director
900 static int job_cmd(JCR *jcr)
902 BSOCK *dir = jcr->dir_bsock;
903 POOL_MEM sd_auth_key(PM_MESSAGE);
904 sd_auth_key.check_size(dir->msglen);
906 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
907 &jcr->VolSessionId, &jcr->VolSessionTime,
908 sd_auth_key.c_str()) != 5) {
909 pm_strcpy(jcr->errmsg, dir->msg);
910 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
915 set_storage_auth_key(jcr, sd_auth_key.c_str());
916 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
917 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
918 new_plugins(jcr); /* instantiate plugins for this jcr */
919 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
921 return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
923 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
927 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param, char *buf, int buflen)
932 return jcr->director->hdr.name;
942 static int runbefore_cmd(JCR *jcr)
945 BSOCK *dir = jcr->dir_bsock;
946 POOLMEM *cmd = get_memory(dir->msglen+1);
949 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
950 if (sscanf(dir->msg, runbefore, cmd) != 1) {
951 pm_strcpy(jcr->errmsg, dir->msg);
952 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
953 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
959 /* Run the command now */
960 script = new_runscript();
961 script->set_job_code_callback(job_code_callback_filed);
962 script->set_command(cmd);
963 script->when = SCRIPT_Before;
964 ok = script->run(jcr, "ClientRunBeforeJob");
965 free_runscript(script);
969 dir->fsend(OKRunBefore);
972 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
977 static int runbeforenow_cmd(JCR *jcr)
979 BSOCK *dir = jcr->dir_bsock;
981 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
982 if (job_canceled(jcr)) {
983 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
984 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
987 dir->fsend(OKRunBeforeNow);
988 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
993 static int runafter_cmd(JCR *jcr)
995 BSOCK *dir = jcr->dir_bsock;
996 POOLMEM *msg = get_memory(dir->msglen+1);
999 Dmsg1(100, "runafter_cmd: %s", dir->msg);
1000 if (sscanf(dir->msg, runafter, msg) != 1) {
1001 pm_strcpy(jcr->errmsg, dir->msg);
1002 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
1003 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
1009 cmd = new_runscript();
1010 cmd->set_job_code_callback(job_code_callback_filed);
1011 cmd->set_command(msg);
1012 cmd->on_success = true;
1013 cmd->on_failure = false;
1014 cmd->when = SCRIPT_After;
1016 jcr->RunScripts->append(cmd);
1018 free_pool_memory(msg);
1019 return dir->fsend(OKRunAfter);
1022 static int runscript_cmd(JCR *jcr)
1024 BSOCK *dir = jcr->dir_bsock;
1025 POOLMEM *msg = get_memory(dir->msglen+1);
1026 int on_success, on_failure, fail_on_error;
1028 RUNSCRIPT *cmd = new_runscript() ;
1029 cmd->set_job_code_callback(job_code_callback_filed);
1031 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
1032 /* Note, we cannot sscanf into bools */
1033 if (sscanf(dir->msg, runscript, &on_success,
1038 pm_strcpy(jcr->errmsg, dir->msg);
1039 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
1040 dir->fsend(_("2905 Bad RunScript command.\n"));
1041 free_runscript(cmd);
1045 cmd->on_success = on_success;
1046 cmd->on_failure = on_failure;
1047 cmd->fail_on_error = fail_on_error;
1050 cmd->set_command(msg);
1052 jcr->RunScripts->append(cmd);
1054 free_pool_memory(msg);
1055 return dir->fsend(OKRunScript);
1059 * This reads data sent from the Director from the
1060 * RestoreObject table that allows us to get objects
1061 * that were backed up (VSS .xml data) and are needed
1062 * before starting the restore.
1064 static int restore_object_cmd(JCR *jcr)
1066 BSOCK *dir = jcr->dir_bsock;
1068 restore_object_pkt rop;
1070 memset(&rop, 0, sizeof(rop));
1071 rop.pkt_size = sizeof(rop);
1072 rop.pkt_end = sizeof(rop);
1074 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
1075 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
1076 Dmsg0(20, "Got endrestoreobject\n");
1077 generate_plugin_event(jcr, bEventRestoreObject, NULL);
1078 return dir->fsend(OKRestoreObject);
1081 rop.plugin_name = (char *)malloc(dir->msglen);
1082 *rop.plugin_name = 0;
1084 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
1085 &rop.object_full_len, &rop.object_index,
1086 &rop.object_type, &rop.object_compression, &FileIndex,
1087 rop.plugin_name) != 8) {
1089 /* Old version, no plugin_name */
1090 if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
1091 &rop.object_full_len, &rop.object_index,
1092 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
1093 Dmsg0(5, "Bad restore object command\n");
1094 pm_strcpy(jcr->errmsg, dir->msg);
1095 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
1100 unbash_spaces(rop.plugin_name);
1102 Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
1103 "FI=%d plugin_name=%s\n",
1104 rop.JobId, rop.object_len, rop.object_full_len,
1105 rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
1106 /* Read Object name */
1107 if (dir->recv() < 0) {
1110 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
1111 rop.object_name = bstrdup(dir->msg);
1114 if (dir->recv() < 0) {
1117 /* Transfer object from message buffer, and get new message buffer */
1118 rop.object = dir->msg;
1119 dir->msg = get_pool_memory(PM_MESSAGE);
1121 /* If object is compressed, uncompress it */
1122 if (rop.object_compression == 1) { /* zlib level 9 */
1124 int out_len = rop.object_full_len + 100;
1125 POOLMEM *obj = get_memory(out_len);
1126 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
1127 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
1128 Dmsg1(100, "Zinflate stat=%d\n", stat);
1129 if (out_len != rop.object_full_len) {
1130 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
1131 rop.object_full_len, out_len, rop.object_name);
1133 free_pool_memory(rop.object); /* release compressed object */
1134 rop.object = obj; /* new uncompressed object */
1135 rop.object_len = out_len;
1137 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
1138 /* we still need to do this to detect a vss restore */
1139 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
1140 Dmsg0(100, "got job metadata\n");
1141 jcr->got_metadata = true;
1144 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
1146 if (rop.object_name) {
1147 free(rop.object_name);
1150 free_pool_memory(rop.object);
1152 if (rop.plugin_name) {
1153 free(rop.plugin_name);
1156 Dmsg1(100, "Send: %s", OKRestoreObject);
1160 dir->fsend(_("2909 Bad RestoreObject command.\n"));
1166 static bool init_fileset(JCR *jcr)
1169 findFILESET *fileset;
1178 fileset = (findFILESET *)malloc(sizeof(findFILESET));
1179 memset(fileset, 0, sizeof(findFILESET));
1180 ff->fileset = fileset;
1181 fileset->state = state_none;
1182 fileset->include_list.init(1, true);
1183 fileset->exclude_list.init(1, true);
1187 static void append_file(JCR *jcr, findINCEXE *incexe,
1188 const char *buf, bool is_file)
1192 /* Special case for / under Win32,
1193 * user is requesting to include all local drives
1195 if (strcmp(buf, "/") == 0) {
1196 //list_drives(&incexe->name_list);
1199 incexe->name_list.append(new_dlistString(buf));
1202 incexe->name_list.append(new_dlistString(buf));
1203 #endif /* HAVE_WIN32 */
1205 } else if (me->plugin_directory) {
1206 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
1207 incexe->plugin_list.append(new_dlistString(buf));
1209 Jmsg(jcr, M_FATAL, 0,
1210 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
1216 * Add fname to include/exclude fileset list. First check for
1217 * | and < and if necessary perform command.
1219 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
1221 findFILESET *fileset = jcr->ff->fileset;
1234 p++; /* skip over | */
1235 fn = get_pool_memory(PM_FNAME);
1236 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
1237 bpipe = open_bpipe(fn, 0, "r");
1240 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
1242 free_pool_memory(fn);
1245 free_pool_memory(fn);
1246 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1247 strip_trailing_junk(buf);
1248 append_file(jcr, fileset->incexe, buf, is_file);
1250 if ((stat=close_bpipe(bpipe)) != 0) {
1252 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
1253 p, be.code(stat), be.bstrerror(stat));
1258 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
1259 p++; /* skip over < */
1260 if ((ffd = fopen(p, "rb")) == NULL) {
1262 Jmsg(jcr, M_FATAL, 0,
1263 _("Cannot open FileSet input file: %s. ERR=%s\n"),
1267 while (fgets(buf, sizeof(buf), ffd)) {
1268 strip_trailing_junk(buf);
1269 append_file(jcr, fileset->incexe, buf, is_file);
1274 append_file(jcr, fileset->incexe, fname, is_file);
1279 findINCEXE *get_incexe(JCR *jcr)
1281 if (jcr->ff && jcr->ff->fileset) {
1282 return jcr->ff->fileset->incexe;
1287 void set_incexe(JCR *jcr, findINCEXE *incexe)
1289 findFILESET *fileset = jcr->ff->fileset;
1290 fileset->incexe = incexe;
1295 * Define a new Exclude block in the FileSet
1297 findINCEXE *new_exclude(JCR *jcr)
1299 findFILESET *fileset = jcr->ff->fileset;
1302 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1303 memset(fileset->incexe, 0, sizeof(findINCEXE));
1304 fileset->incexe->opts_list.init(1, true);
1305 fileset->incexe->name_list.init();
1306 fileset->incexe->plugin_list.init();
1307 fileset->exclude_list.append(fileset->incexe);
1308 return fileset->incexe;
1312 * Define a new Include block in the FileSet
1314 findINCEXE *new_include(JCR *jcr)
1316 findFILESET *fileset = jcr->ff->fileset;
1319 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1320 memset(fileset->incexe, 0, sizeof(findINCEXE));
1321 fileset->incexe->opts_list.init(1, true);
1322 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1323 fileset->incexe->plugin_list.init();
1324 fileset->include_list.append(fileset->incexe);
1325 return fileset->incexe;
1329 * Define a new preInclude block in the FileSet
1330 * That is the include is prepended to the other
1331 * Includes. This is used for plugin exclusions.
1333 findINCEXE *new_preinclude(JCR *jcr)
1335 findFILESET *fileset = jcr->ff->fileset;
1337 /* New pre-include */
1338 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1339 memset(fileset->incexe, 0, sizeof(findINCEXE));
1340 fileset->incexe->opts_list.init(1, true);
1341 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1342 fileset->incexe->plugin_list.init();
1343 fileset->include_list.prepend(fileset->incexe);
1344 return fileset->incexe;
1347 static findFOPTS *start_options(FF_PKT *ff)
1349 int state = ff->fileset->state;
1350 findINCEXE *incexe = ff->fileset->incexe;
1352 if (state != state_options) {
1353 ff->fileset->state = state_options;
1354 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1355 memset(fo, 0, sizeof(findFOPTS));
1356 fo->regex.init(1, true);
1357 fo->regexdir.init(1, true);
1358 fo->regexfile.init(1, true);
1359 fo->wild.init(1, true);
1360 fo->wilddir.init(1, true);
1361 fo->wildfile.init(1, true);
1362 fo->wildbase.init(1, true);
1363 fo->base.init(1, true);
1364 fo->fstype.init(1, true);
1365 fo->drivetype.init(1, true);
1366 incexe->current_opts = fo;
1367 incexe->opts_list.append(fo);
1369 return incexe->current_opts;
1373 * Used by plugins to define a new options block
1375 void new_options(JCR *jcr, findINCEXE *incexe)
1378 incexe = jcr->ff->fileset->incexe;
1380 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1381 memset(fo, 0, sizeof(findFOPTS));
1382 fo->regex.init(1, true);
1383 fo->regexdir.init(1, true);
1384 fo->regexfile.init(1, true);
1385 fo->wild.init(1, true);
1386 fo->wilddir.init(1, true);
1387 fo->wildfile.init(1, true);
1388 fo->wildbase.init(1, true);
1389 fo->base.init(1, true);
1390 fo->fstype.init(1, true);
1391 fo->drivetype.init(1, true);
1392 incexe->current_opts = fo;
1393 incexe->opts_list.prepend(fo);
1394 jcr->ff->fileset->state = state_options;
1398 * Add a regex to the current fileset
1400 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1402 findFOPTS *current_opts = start_options(jcr->ff);
1407 preg = (regex_t *)malloc(sizeof(regex_t));
1408 if (current_opts->flags & FO_IGNORECASE) {
1409 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1411 rc = regcomp(preg, item, REG_EXTENDED);
1414 regerror(rc, preg, prbuf, sizeof(prbuf));
1417 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1421 current_opts->regex.append(preg);
1422 } else if (type == 'D') {
1423 current_opts->regexdir.append(preg);
1424 } else if (type == 'F') {
1425 current_opts->regexfile.append(preg);
1429 return state_options;
1433 * Add a wild card to the current fileset
1435 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1437 findFOPTS *current_opts = start_options(jcr->ff);
1440 current_opts->wild.append(bstrdup(item));
1441 } else if (type == 'D') {
1442 current_opts->wilddir.append(bstrdup(item));
1443 } else if (type == 'F') {
1444 current_opts->wildfile.append(bstrdup(item));
1445 } else if (type == 'B') {
1446 current_opts->wildbase.append(bstrdup(item));
1450 return state_options;
1455 * Add options to the current fileset
1457 int add_options_to_fileset(JCR *jcr, const char *item)
1459 findFOPTS *current_opts = start_options(jcr->ff);
1461 set_options(current_opts, item);
1462 return state_options;
1465 static void add_fileset(JCR *jcr, const char *item)
1467 FF_PKT *ff = jcr->ff;
1468 findFILESET *fileset = ff->fileset;
1469 int state = fileset->state;
1470 findFOPTS *current_opts;
1472 /* Get code, optional subcode, and position item past the dividing space */
1473 Dmsg1(100, "%s\n", item);
1478 int subcode = ' '; /* A space is always a valid subcode */
1479 if (item[0] != '\0' && item[0] != ' ') {
1487 /* Skip all lines we receive after an error */
1488 if (state == state_error) {
1489 Dmsg0(100, "State=error return\n");
1494 * The switch tests the code for validity.
1495 * The subcode is always good if it is a space, otherwise we must confirm.
1496 * We set state to state_error first assuming the subcode is invalid,
1497 * requiring state to be set in cases below that handle subcodes.
1499 if (subcode != ' ') {
1500 state = state_error;
1501 Dmsg0(100, "Set state=error or double code.\n");
1505 (void)new_include(jcr);
1508 (void)new_exclude(jcr);
1510 case 'N': /* null */
1513 case 'F': /* file = */
1514 /* File item to include or exclude list */
1515 state = state_include;
1516 add_file_to_fileset(jcr, item, true);
1518 case 'P': /* plugin */
1519 /* Plugin item to include list */
1520 state = state_include;
1521 add_file_to_fileset(jcr, item, false);
1523 case 'R': /* regex */
1524 state = add_regex_to_fileset(jcr, item, subcode);
1527 current_opts = start_options(ff);
1528 current_opts->base.append(bstrdup(item));
1529 state = state_options;
1531 case 'X': /* Filetype or Drive type */
1532 current_opts = start_options(ff);
1533 state = state_options;
1534 if (subcode == ' ') {
1535 current_opts->fstype.append(bstrdup(item));
1536 } else if (subcode == 'D') {
1537 current_opts->drivetype.append(bstrdup(item));
1539 state = state_error;
1542 case 'W': /* wild cards */
1543 state = add_wild_to_fileset(jcr, item, subcode);
1545 case 'O': /* Options */
1546 state = add_options_to_fileset(jcr, item);
1548 case 'Z': /* ignore dir */
1549 state = state_include;
1550 fileset->incexe->ignoredir = bstrdup(item);
1553 current_opts = start_options(ff);
1554 // current_opts->reader = bstrdup(item); /* deprecated */
1555 state = state_options;
1558 current_opts = start_options(ff);
1559 // current_opts->writer = bstrdup(item); /* deprecated */
1560 state = state_options;
1562 case 'G': /* Plugin command for this Option block */
1563 current_opts = start_options(ff);
1564 current_opts->plugin = bstrdup(item);
1565 state = state_options;
1568 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1569 state = state_error;
1572 ff->fileset->state = state;
1575 static bool term_fileset(JCR *jcr)
1577 FF_PKT *ff = jcr->ff;
1579 #ifdef xxx_DEBUG_CODE
1580 findFILESET *fileset = ff->fileset;
1583 for (i=0; i<fileset->include_list.size(); i++) {
1584 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1586 for (j=0; j<incexe->opts_list.size(); j++) {
1587 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1588 for (k=0; k<fo->regex.size(); k++) {
1589 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1591 for (k=0; k<fo->regexdir.size(); k++) {
1592 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1594 for (k=0; k<fo->regexfile.size(); k++) {
1595 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1597 for (k=0; k<fo->wild.size(); k++) {
1598 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1600 for (k=0; k<fo->wilddir.size(); k++) {
1601 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1603 for (k=0; k<fo->wildfile.size(); k++) {
1604 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1606 for (k=0; k<fo->wildbase.size(); k++) {
1607 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1609 for (k=0; k<fo->base.size(); k++) {
1610 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1612 for (k=0; k<fo->fstype.size(); k++) {
1613 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1615 for (k=0; k<fo->drivetype.size(); k++) {
1616 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1619 if (incexe->ignoredir) {
1620 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1623 foreach_dlist(node, &incexe->name_list) {
1624 Dmsg1(400, "F %s\n", node->c_str());
1626 foreach_dlist(node, &incexe->plugin_list) {
1627 Dmsg1(400, "P %s\n", node->c_str());
1630 for (i=0; i<fileset->exclude_list.size(); i++) {
1631 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1633 for (j=0; j<incexe->opts_list.size(); j++) {
1634 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1635 for (k=0; k<fo->regex.size(); k++) {
1636 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1638 for (k=0; k<fo->regexdir.size(); k++) {
1639 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1641 for (k=0; k<fo->regexfile.size(); k++) {
1642 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1644 for (k=0; k<fo->wild.size(); k++) {
1645 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1647 for (k=0; k<fo->wilddir.size(); k++) {
1648 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1650 for (k=0; k<fo->wildfile.size(); k++) {
1651 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1653 for (k=0; k<fo->wildbase.size(); k++) {
1654 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1656 for (k=0; k<fo->base.size(); k++) {
1657 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1659 for (k=0; k<fo->fstype.size(); k++) {
1660 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1662 for (k=0; k<fo->drivetype.size(); k++) {
1663 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1667 foreach_dlist(node, &incexe->name_list) {
1668 Dmsg1(400, "F %s\n", node->c_str());
1670 foreach_dlist(node, &incexe->plugin_list) {
1671 Dmsg1(400, "P %s\n", node->c_str());
1675 return ff->fileset->state != state_error;
1680 * As an optimization, we should do this during
1681 * "compile" time in filed/job.c, and keep only a bit mask
1682 * and the Verify options.
1684 static int set_options(findFOPTS *fo, const char *opts)
1690 // Commented out as it is not backward compatible - KES
1692 for (p=opts; *p; p++) {
1694 case 'a': /* alway replace */
1695 case '0': /* no option */
1698 fo->flags |= FO_EXCLUDE;
1701 fo->flags |= FO_MULTIFS;
1703 case 'h': /* no recursion */
1704 fo->flags |= FO_NO_RECURSION;
1706 case 'H': /* no hard link handling */
1707 fo->flags |= FO_NO_HARDLINK;
1710 fo->flags |= FO_IGNORECASE;
1713 fo->flags |= FO_MD5;
1716 fo->flags |= FO_NOREPLACE;
1718 case 'p': /* use portable data format */
1719 fo->flags |= FO_PORTABLE;
1721 case 'R': /* Resource forks and Finder Info */
1722 fo->flags |= FO_HFSPLUS;
1724 case 'r': /* read fifo */
1725 fo->flags |= FO_READFIFO;
1730 fo->flags |= FO_SHA1;
1735 fo->flags |= FO_SHA256;
1739 fo->flags |= FO_SHA512;
1745 * If 2 or 3 is seen here, SHA2 is not configured, so
1746 * eat the option, and drop back to SHA-1.
1748 if (p[1] == '2' || p[1] == '3') {
1751 fo->flags |= FO_SHA1;
1756 fo->flags |= FO_SPARSE;
1759 fo->flags |= FO_MTIMEONLY;
1762 fo->flags |= FO_KEEPATIME;
1765 fo->flags |= FO_ACL;
1767 case 'V': /* verify options */
1768 /* Copy Verify Options */
1769 for (j=0; *p && *p != ':'; p++) {
1770 fo->VerifyOpts[j] = *p;
1771 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1775 fo->VerifyOpts[j] = 0;
1777 case 'C': /* accurate options */
1778 /* Copy Accurate Options */
1779 for (j=0; *p && *p != ':'; p++) {
1780 fo->AccurateOpts[j] = *p;
1781 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1785 fo->AccurateOpts[j] = 0;
1787 case 'J': /* Basejob options */
1788 /* Copy BaseJob Options */
1789 for (j=0; *p && *p != ':'; p++) {
1790 fo->BaseJobOpts[j] = *p;
1791 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1795 fo->BaseJobOpts[j] = 0;
1797 case 'P': /* strip path */
1800 for (j=0; *p && *p != ':'; p++) {
1802 if (j < (int)sizeof(strip) - 1) {
1807 fo->strip_path = atoi(strip);
1808 fo->flags |= FO_STRIPPATH;
1809 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1812 fo->flags |= FO_IF_NEWER;
1815 fo->flags |= FO_ENHANCEDWILD;
1817 case 'Z': /* compression */
1819 if (*p >= '0' && *p <= '9') {
1820 fo->flags |= FO_COMPRESS;
1821 fo->Compress_algo = COMPRESS_GZIP;
1822 fo->Compress_level = *p - '0';
1824 else if (*p == 'o') {
1825 fo->flags |= FO_COMPRESS;
1826 fo->Compress_algo = COMPRESS_LZO1X;
1827 fo->Compress_level = 1; /* not used with LZO */
1831 fo->flags |= FO_NOATIME;
1834 fo->flags |= FO_CHKCHANGES;
1837 fo->flags |= FO_HONOR_NODUMP;
1840 fo->flags |= FO_XATTR;
1843 Jmsg1(NULL, M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1847 return state_options;
1852 * Director is passing his Fileset
1854 static int fileset_cmd(JCR *jcr)
1856 POOL_MEM buf(PM_MESSAGE);
1857 BSOCK *dir = jcr->dir_bsock;
1861 jcr->Snapshot = (strstr(dir->msg, "vss=1") != NULL);
1863 jcr->Snapshot = (strstr(dir->msg, "snap=1") != NULL);
1865 if (!init_fileset(jcr)) {
1868 while (dir->recv() >= 0) {
1869 strip_trailing_junk(dir->msg);
1870 Dmsg1(500, "Fileset: %s\n", dir->msg);
1871 pm_strcpy(buf, dir->msg);
1872 add_fileset(jcr, buf.c_str());
1874 if (!term_fileset(jcr)) {
1877 rtnstat = dir->fsend(OKinc);
1878 generate_plugin_event(jcr, bEventEndFileSet);
1884 * The Director sends us the component info file, which
1885 * we will in turn pass to the VSS plugin.
1887 static int component_cmd(JCR *jcr)
1889 BSOCK *dir = jcr->dir_bsock;
1891 while (dir->recv() >= 0) {
1892 Dmsg1(200, "filed<dird: component: %s", dir->msg);
1893 generate_plugin_event(jcr, bEventComponentInfo, (void *)dir->msg);
1895 return dir->fsend(OKComponentInfo);
1900 * Get backup level from Director
1902 * Note: there are odd things such as accurate_differential,
1903 * and accurate_incremental that are passed in level, thus
1904 * the calls to strstr() below.
1907 static int level_cmd(JCR *jcr)
1909 BSOCK *dir = jcr->dir_bsock;
1910 POOLMEM *level, *buf = NULL;
1913 level = get_memory(dir->msglen+1);
1914 Dmsg1(10, "level_cmd: %s", dir->msg);
1916 /* keep compatibility with older directors */
1917 if (strstr(dir->msg, "accurate")) {
1918 jcr->accurate = true;
1920 if (strstr(dir->msg, "rerunning")) {
1921 jcr->rerunning = true;
1923 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1926 /* Base backup requested? */
1927 if (strcasecmp(level, "base") == 0) {
1928 jcr->setJobLevel(L_BASE);
1929 /* Full backup requested? */
1930 } else if (strcasecmp(level, "full") == 0) {
1931 jcr->setJobLevel(L_FULL);
1932 } else if (strstr(level, "differential")) {
1933 jcr->setJobLevel(L_DIFFERENTIAL);
1936 } else if (strstr(level, "incremental")) {
1937 jcr->setJobLevel(L_INCREMENTAL);
1941 * We get his UTC since time, then sync the clocks and correct it
1942 * to agree with our clock.
1944 } else if (strcasecmp(level, "since_utime") == 0) {
1945 buf = get_memory(dir->msglen+1);
1946 utime_t since_time, adj;
1947 btime_t his_time, bt_start, rt=0, bt_adj=0, his_time_prev=0, n=0;
1948 if (jcr->getJobLevel() == L_NONE) {
1949 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1951 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1952 buf, &mtime_only, jcr->PrevJob) != 3) {
1953 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1954 buf, &mtime_only) != 2) {
1958 since_time = str_to_uint64(buf); /* this is the since time */
1959 Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1960 char ed1[50], ed2[50];
1962 * Sync clocks by polling him for the time. We take
1963 * 10 samples of his time throwing out the first two.
1965 for (int i=0; i<10; i++) {
1966 bt_start = get_current_btime();
1967 dir->signal(BNET_BTIME); /* poll for time */
1968 if (dir->recv() <= 0) { /* get response */
1971 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1974 his_time = str_to_uint64(buf);
1975 rt = get_current_btime() - bt_start; /* compute round trip time */
1976 /* skip first two results and check for leap second */
1977 /* if any of the FD or DIR went back in time, skip this iteration */
1978 if (i < 2 || (his_time_prev > 0 && his_time < his_time_prev) || rt<0) {
1979 his_time_prev = his_time;
1982 his_time_prev = his_time;
1984 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1985 edit_uint64(bt_start, ed2));
1986 bt_adj += bt_start - his_time - rt/2;
1987 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1990 if (n > 0) { /* Should be 1 in the worst case */
1991 bt_adj = bt_adj / n; /* compute average time */
1992 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1993 adj = btime_to_utime(bt_adj);
1994 since_time += adj; /* adjust for clock difference */
1996 /* Don't notify if time within 3 seconds */
1997 if (adj > 3 || adj < -3) {
1999 if (adj > 600 || adj < -600) {
2004 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
2006 dir->signal(BNET_EOD);
2008 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
2009 jcr->incremental = 1; /* set incremental or decremental backup */
2010 jcr->mtime = since_time; /* set since time */
2011 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
2013 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
2021 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
2022 return dir->fsend(OKlevel);
2025 pm_strcpy(jcr->errmsg, dir->msg);
2026 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
2035 * Get session parameters from Director -- this is for a Restore command
2036 * This is deprecated. It is now passed via the bsr.
2038 static int session_cmd(JCR *jcr)
2040 BSOCK *dir = jcr->dir_bsock;
2042 Dmsg1(100, "SessionCmd: %s", dir->msg);
2043 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
2044 &jcr->VolSessionId, &jcr->VolSessionTime,
2045 &jcr->StartFile, &jcr->EndFile,
2046 &jcr->StartBlock, &jcr->EndBlock) != 7) {
2047 pm_strcpy(jcr->errmsg, dir->msg);
2048 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
2052 return dir->fsend(OKsession);
2055 static void set_storage_auth_key(JCR *jcr, char *key)
2057 /* if no key don't update anything */
2063 * We can be contacting multiple storage daemons.
2064 * So, make sure that any old jcr->store_bsock is cleaned up.
2066 free_bsock(jcr->store_bsock);
2069 * We can be contacting multiple storage daemons.
2070 * So, make sure that any old jcr->sd_auth_key is cleaned up.
2072 if (jcr->sd_auth_key) {
2074 * If we already have a Authorization key, director can do multi
2077 Dmsg0(5, "set multi_restore=true\n");
2078 jcr->multi_restore = true;
2079 bfree(jcr->sd_auth_key);
2082 jcr->sd_auth_key = bstrdup(key);
2083 Dmsg1(200, "set sd auth key %s\n", jcr->sd_auth_key);
2087 * Get address of storage daemon from Director
2090 static int storage_cmd(JCR *jcr)
2092 int stored_port = 0; /* storage daemon port */
2093 int enable_ssl; /* enable ssl to sd */
2094 POOL_MEM sd_auth_key(PM_MESSAGE);
2095 BSOCK *dir = jcr->dir_bsock;
2098 Dmsg1(100, "StorageCmd: %s", dir->msg);
2099 sd_auth_key.check_size(dir->msglen);
2100 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
2101 &enable_ssl, sd_auth_key.c_str()) == 4) {
2102 Dmsg1(100, "Set auth key %s\n", sd_auth_key.c_str());
2103 set_storage_auth_key(jcr, sd_auth_key.c_str());
2104 } else if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
2105 &stored_port, &enable_ssl) != 3) {
2106 pm_strcpy(jcr->errmsg, dir->msg);
2107 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
2108 Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
2113 /* TODO: see if we put limit on restore and backup... */
2114 if (!jcr->max_bandwidth) {
2115 if (jcr->director->max_bandwidth_per_job) {
2116 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
2118 } else if (me->max_bandwidth_per_job) {
2119 jcr->max_bandwidth = me->max_bandwidth_per_job;
2123 if (stored_port != 0) { /* We are doing the connecting */
2124 Dmsg3(110, "Connect to storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
2126 jcr->sd_calls_client = false;
2128 /* Open command communications with Storage daemon */
2129 /* Try to connect for 1 hour at 10 second intervals */
2130 sd->set_source_address(me->FDsrc_addr);
2131 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
2132 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
2133 /* destroy() OK because sd is local */
2135 Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
2136 jcr->stored_addr, stored_port);
2137 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
2138 jcr->stored_addr, stored_port);
2142 Dmsg0(110, "Connection OK to SD.\n");
2143 jcr->store_bsock = sd;
2144 } else { /* The storage daemon called us */
2147 struct timespec timeout;
2150 free_bsock(jcr->store_bsock);
2151 jcr->sd_calls_client = true;
2154 * Wait for the Storage daemon to contact us to start the Job,
2155 * when he does, we will be released, unless the 30 minutes
2158 gettimeofday(&tv, &tz);
2159 timeout.tv_nsec = tv.tv_usec * 1000;
2160 timeout.tv_sec = tv.tv_sec + 30 * 60; /* wait 30 minutes */
2162 while (jcr->sd_calls_client_bsock == NULL && !jcr->is_job_canceled()) {
2163 errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
2164 if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
2167 Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
2170 Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
2172 /* We should already have a storage connection! */
2173 if (jcr->sd_calls_client_bsock == NULL) {
2174 Pmsg0(000, "Failed connect from Storage daemon. SD bsock=NULL.\n");
2175 Pmsg1(000, "Storagecmd: %s", dir->msg);
2176 Jmsg0(jcr, M_FATAL, 0, _("Failed connect from Storage daemon. SD bsock=NULL.\n"));
2179 if (jcr->is_job_canceled()) {
2182 /* Assign the new socket to the main one */
2184 jcr->store_bsock = jcr->sd_calls_client_bsock;
2185 jcr->sd_calls_client_bsock = NULL;
2188 jcr->store_bsock->set_bwlimit(jcr->max_bandwidth);
2190 if (!send_hello_sd(jcr, jcr->Job)) {
2194 if (!authenticate_storagedaemon(jcr)) {
2197 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
2198 Dmsg0(110, "Authenticated with SD.\n");
2200 /* Send OK to Director */
2201 return dir->fsend(OKstore);
2204 dir->fsend(BADcmd, "storage");
2209 /* TODO: merge find.c ? */
2210 static bool is_excluded(findFILESET *fileset, char *path)
2212 int fnm_flags=FNM_CASEFOLD;
2215 /* Now apply the Exclude { } directive */
2216 for (int i=0; i<fileset->exclude_list.size(); i++) {
2217 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
2220 foreach_dlist(node, &incexe->name_list) {
2221 char *fname = node->c_str();
2222 Dmsg2(DT_VOLUME|50, "Testing %s against %s\n", path, fname);
2223 if (fnmatch(fname, path, fnmode|fnm_flags) == 0) {
2224 Dmsg1(050, "Reject wild2: %s\n", path);
2227 /* On windows, the path separator is a bit complex to handle. For
2228 * example, in fnmatch(), \ is written as \\\\ in the config file / is
2229 * different from \ So we have our own little strcmp for filenames
2233 for (p = path; *p && *fname && same ; p++, fname++) {
2234 if (!((IsPathSeparator(*p) && IsPathSeparator(*fname)) ||
2235 (tolower(*p) == tolower(*fname)))) {
2236 same = false; /* Stop after the first one */
2241 /* End of the for loop, strings looks to be identical */
2242 Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2246 /* Looks to be the same string, but with a trailing slash */
2247 if (fname[0] && IsPathSeparator(fname[0]) && fname[1] == '\0'
2250 Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2259 * For VSS we need to know which windows drives
2260 * are used, because we create a snapshot of all used
2261 * drives before operation
2265 get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
2269 findFILESET *fileset = ff->fileset;
2274 mtab.get(); /* read the disk structure */
2276 /* Keep this part for compatibility reasons */
2277 strcpy(drive, "c:\\");
2278 for (int i=0; szDrives[i] ; i++) {
2279 drive[0] = szDrives[i];
2280 if (mtab.addInSnapshotSet(drive)) { /* When all volumes are selected, we can stop */
2281 Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2289 for (int i=0; i<fileset->include_list.size(); i++) {
2292 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
2294 /* look through all files */
2295 foreach_dlist(node, &incexe->name_list) {
2296 char *fname = node->c_str();
2297 if (mtab.addInSnapshotSet(fname)) {
2298 /* When all volumes are selected, we can stop */
2299 Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2304 foreach_alist(fo, &incexe->opts_list) {
2305 flags |= fo->flags; /* We are looking for FO_MULTIFS and recurse */
2309 /* TODO: it needs to be done Include by Include, but in the worst case,
2310 * we take too much snapshots...
2312 if (flags & FO_MULTIFS) {
2313 /* Need to add subdirectories */
2314 POOLMEM *fn = get_pool_memory(PM_FNAME);
2315 MTabEntry *elt, *elt2;
2318 Dmsg0(DT_VOLUME|50, "OneFS is set, looking for remaining volumes\n");
2320 foreach_rblist(elt, mtab.entries) {
2321 if (elt->in_SnapshotSet) {
2322 continue; /* Already in */
2324 /* A volume can have multiple mount points */
2325 for (wchar_t *p = elt->first() ; p && *p ; p = elt->next(p)) {
2326 wchar_2_UTF8(&fn, p);
2328 Dmsg1(DT_VOLUME|50, "Looking for path %s\n", fn);
2330 /* First case, root drive (c:/, e:/, d:/), not a submount point */
2333 Dmsg1(DT_VOLUME|50, "Skiping %s\n", fn);
2337 /* First thing is to look in the exclude list to see if this directory
2338 * is explicitely excluded
2340 if (is_excluded(fileset, fn)) {
2341 Dmsg1(DT_VOLUME|50, "Looks to be excluded %s\n", fn);
2346 * will look c:/, then c:/vol/, then c:/vol2/ and if one of them
2347 * is selected, the sub volume will be directly marked.
2349 for (char *p1 = fn ; *p1 && !elt->in_SnapshotSet ; p1++) {
2350 if (IsPathSeparator(*p1)) {
2355 /* We look for the previous directory, and if marked, we mark
2356 * the current one as well
2358 Dmsg1(DT_VOLUME|50, "Looking for %s\n", fn);
2359 elt2 = mtab.search(fn);
2360 if (elt2 && elt2->in_SnapshotSet) {
2361 Dmsg0(DT_VOLUME|50, "Put volume in SnapshotSet\n");
2362 elt->setInSnapshotSet();
2365 *(p1 + 1) = c; /* restore path separator */
2370 free_pool_memory(fn);
2373 /* Now, we look the volume list to know which one to include */
2375 foreach_rblist(elt, mtab.entries) {
2376 if (elt->in_SnapshotSet) {
2377 Dmsg1(DT_VOLUME|50,"Adding volume in mount_points list %ls\n",elt->volumeName);
2379 ff->mount_points.append(bwcsdup(elt->volumeName));
2386 #endif /* HAVE_WIN32 */
2391 static int backup_cmd(JCR *jcr)
2393 BSOCK *dir = jcr->dir_bsock;
2394 BSOCK *sd = jcr->store_bsock;
2399 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
2400 jcr->JobFiles = FileIndex;
2401 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
2405 * If explicitly requesting FO_ACL or FO_XATTR, fail job if it
2406 * is not available on Client machine
2408 if (jcr->ff->flags & FO_ACL && !(have_acl||have_win32)) {
2409 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for Client.\n"));
2412 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
2413 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for Client.\n"));
2416 jcr->setJobStatus(JS_Blocked);
2417 jcr->setJobType(JT_BACKUP);
2418 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
2420 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
2421 dir->fsend(BADcmd, "backup");
2425 dir->fsend(OKbackup);
2426 Dmsg1(110, "filed>dird: %s", dir->msg);
2429 * Send Append Open Session to Storage daemon
2431 sd->fsend(append_open);
2432 Dmsg1(110, ">stored: %s", sd->msg);
2434 * Expect to receive back the Ticket number
2436 if (bget_msg(sd) >= 0) {
2437 Dmsg1(110, "<stored: %s", sd->msg);
2438 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2439 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2442 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
2444 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2449 * Send Append data command to Storage daemon
2451 sd->fsend(append_data, jcr->Ticket);
2452 Dmsg1(110, ">stored: %s", sd->msg);
2455 * Expect to get OK data
2457 Dmsg1(110, "<stored: %s", sd->msg);
2458 if (!response(jcr, sd, OK_data, "Append Data")) {
2462 generate_daemon_event(jcr, "JobStart");
2463 generate_plugin_event(jcr, bEventStartBackupJob);
2465 if (jcr->Snapshot) {
2466 #if defined(WIN32_VSS)
2468 /* START VSS ON WIN32 */
2469 jcr->pVSSClient = VSSInit();
2470 if (jcr->pVSSClient->InitializeForBackup(jcr)) {
2471 generate_plugin_event(jcr, bEventVssBackupAddComponents);
2472 /* tell vss which drives to snapshot */
2473 char szWinDriveLetters[27];
2474 *szWinDriveLetters=0;
2475 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
2476 if (get_win32_driveletters(jcr, jcr->ff, szWinDriveLetters)) {
2477 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\"\n"),
2478 jcr->pVSSClient->GetDriverName());
2480 if (!jcr->pVSSClient->CreateSnapshots(&jcr->ff->mount_points)) {
2482 Jmsg(jcr, M_FATAL, 0, _("VSS CreateSnapshots failed. ERR=%s\n"),
2485 /* inform user about writer states */
2486 for (int i=0; i < (int)jcr->pVSSClient->GetWriterCount(); i++) {
2487 if (jcr->pVSSClient->GetWriterState(i) < 1) {
2488 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"),
2489 jcr->pVSSClient->GetWriterInfo(i));
2494 Jmsg(jcr, M_WARNING, 0, _("No drive letters found for generating VSS snapshots.\n"));
2498 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"),
2503 Dmsg0(10, "Open a snapshot session\n");
2504 /* TODO: See if we abort the job */
2505 jcr->Snapshot = open_snapshot_backup_session(jcr);
2508 /* Call RunScript just after the Snapshot creation, usually, we restart services */
2509 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2512 * Send Files to Storage daemon
2514 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
2515 if (!blast_data_to_storage_daemon(jcr, NULL)) {
2516 jcr->setJobStatus(JS_ErrorTerminated);
2517 sd->suppress_error_messages(true);
2518 Dmsg0(110, "Error in blast_data.\n");
2520 jcr->setJobStatus(JS_Terminated);
2521 /* Note, the above set status will not override an error */
2522 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
2523 sd->suppress_error_messages(true);
2524 goto cleanup; /* bail out now */
2527 * Expect to get response to append_data from Storage daemon
2529 if (!response(jcr, sd, OK_append, "Append Data")) {
2530 jcr->setJobStatus(JS_ErrorTerminated);
2535 * Send Append End Data to Storage daemon
2537 sd->fsend(append_end, jcr->Ticket);
2539 if (!response(jcr, sd, OK_end, "Append End")) {
2540 jcr->setJobStatus(JS_ErrorTerminated);
2545 * Send Append Close to Storage daemon
2547 sd->fsend(append_close, jcr->Ticket);
2548 while (bget_msg(sd) >= 0) { /* stop on signal or error */
2549 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2551 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2555 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2558 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings ||
2559 SDJobStatus == JS_Incomplete)) {
2560 Jmsg(jcr, M_FATAL, 0, _("Bad status %d %c returned from Storage Daemon.\n"),
2561 SDJobStatus, (char)SDJobStatus);
2566 #if defined(WIN32_VSS)
2567 if (jcr->Snapshot) {
2568 Win32ConvCleanupCache();
2569 if (jcr->pVSSClient) {
2570 jcr->pVSSClient->DestroyWriterInfo();
2574 generate_plugin_event(jcr, bEventEndBackupJob);
2575 return 0; /* return and stop command loop */
2579 * Do a Verify for Director
2582 static int verify_cmd(JCR *jcr)
2584 BSOCK *dir = jcr->dir_bsock;
2585 BSOCK *sd = jcr->store_bsock;
2588 jcr->setJobType(JT_VERIFY);
2589 if (sscanf(dir->msg, verifycmd, level) != 1) {
2590 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2594 if (strcasecmp(level, "init") == 0) {
2595 jcr->setJobLevel(L_VERIFY_INIT);
2596 } else if (strcasecmp(level, "catalog") == 0){
2597 jcr->setJobLevel(L_VERIFY_CATALOG);
2598 } else if (strcasecmp(level, "volume") == 0){
2599 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2600 } else if (strcasecmp(level, "data") == 0){
2601 jcr->setJobLevel(L_VERIFY_DATA);
2602 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2603 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2605 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2609 dir->fsend(OKverify);
2611 generate_daemon_event(jcr, "JobStart");
2612 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2613 generate_plugin_event(jcr, bEventStartVerifyJob);
2615 Dmsg1(110, "filed>dird: %s", dir->msg);
2617 switch (jcr->getJobLevel()) {
2619 case L_VERIFY_CATALOG:
2623 case L_VERIFY_VOLUME_TO_CATALOG:
2624 if (!open_sd_read_session(jcr)) {
2627 start_dir_heartbeat(jcr);
2628 do_verify_volume(jcr);
2629 stop_dir_heartbeat(jcr);
2631 * Send Close session command to Storage daemon
2633 sd->fsend(read_close, jcr->Ticket);
2634 Dmsg1(130, "filed>stored: %s", sd->msg);
2636 /* ****FIXME**** check response */
2637 bget_msg(sd); /* get OK */
2639 /* Inform Storage daemon that we are done */
2640 sd->signal(BNET_TERMINATE);
2643 case L_VERIFY_DISK_TO_CATALOG:
2647 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2651 dir->signal(BNET_EOD);
2652 generate_plugin_event(jcr, bEventEndVerifyJob);
2653 return 0; /* return and terminate command loop */
2657 * Do a Restore for Director
2660 static int restore_cmd(JCR *jcr)
2662 BSOCK *dir = jcr->dir_bsock;
2663 BSOCK *sd = jcr->store_bsock;
2664 POOLMEM *args=NULL, *restore_where=NULL, *restore_rwhere=NULL;
2665 bool use_regexwhere=false;
2668 bool scan_ok = true;
2673 * Scan WHERE (base directory for restore) from command
2675 Dmsg0(100, "restore command\n");
2676 #if defined(WIN32_VSS)
2679 * No need to enable VSS for restore if we do not have plugin
2682 jcr->Snapshot = jcr->got_metadata;
2685 /* Pickup where string */
2686 args = get_memory(dir->msglen+1);
2689 restore_where = get_pool_memory(PM_FNAME);
2690 restore_rwhere = get_pool_memory(PM_FNAME);
2692 /* We don't know the size of where/rwhere in advance,
2693 * where= -> where=%202s\n
2695 Mmsg(restore_where, "%s%%%ds\n", restorefcmd, dir->msglen);
2696 Mmsg(restore_rwhere, "%s%%%ds\n", restorefcmdR, dir->msglen);
2698 Dmsg2(200, "where=%srwhere=%s", restore_where, restore_rwhere);
2700 /* Scan for new form with number of files to restore */
2701 if (sscanf(dir->msg, restore_where, &files, &replace, &prefix_links, args) != 4) {
2702 if (sscanf(dir->msg, restore_rwhere, &files, &replace, &prefix_links, args) != 4) {
2703 if (sscanf(dir->msg, restorefcmd1, &files, &replace, &prefix_links) != 3) {
2706 *args = 0; /* No where argument */
2708 use_regexwhere = true;
2713 jcr->ExpectedFiles = files;
2715 /* Scan for old form without number of files */
2716 jcr->ExpectedFiles = 0;
2718 /* where= -> where=%202s\n */
2719 Mmsg(restore_where, "%s%%%ds\n", restorecmd, dir->msglen);
2720 Mmsg(restore_rwhere, "%s%%%ds\n", restorecmdR, dir->msglen);
2722 if (sscanf(dir->msg, restore_where, &replace, &prefix_links, args) != 3) {
2723 if (sscanf(dir->msg, restore_rwhere, &replace, &prefix_links, args) != 3){
2724 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2725 pm_strcpy(jcr->errmsg, dir->msg);
2726 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2729 jcr->RegexWhere = bstrdup(args);
2730 *args = 0; /* No where argument */
2732 use_regexwhere = true;
2737 /* Turn / into nothing */
2738 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2742 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2743 unbash_spaces(args);
2745 /* Keep track of newly created directories to apply them correct attributes */
2746 if (replace == REPLACE_NEVER || replace == REPLACE_IFNEWER) {
2747 jcr->keep_path_list = true;
2750 if (use_regexwhere) {
2751 jcr->where_bregexp = get_bregexps(args);
2752 if (!jcr->where_bregexp) {
2753 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2757 jcr->where = bstrdup(args);
2760 jcr->replace = replace;
2761 jcr->prefix_links = prefix_links;
2763 dir->fsend(OKrestore);
2764 Dmsg1(110, "filed>dird: %s", dir->msg);
2766 jcr->setJobType(JT_RESTORE);
2768 jcr->setJobStatus(JS_Blocked);
2770 if (!open_sd_read_session(jcr)) {
2771 jcr->setJobStatus(JS_ErrorTerminated);
2775 jcr->setJobStatus(JS_Running);
2778 * Do restore of files and data
2780 start_dir_heartbeat(jcr);
2781 generate_daemon_event(jcr, "JobStart");
2782 generate_plugin_event(jcr, bEventStartRestoreJob);
2784 #if defined(WIN32_VSS)
2785 /* START VSS ON WIN32 */
2786 if (jcr->Snapshot) {
2787 jcr->pVSSClient = VSSInit();
2788 if (!jcr->pVSSClient->InitializeForRestore(jcr)) {
2790 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2792 //free_and_null_pool_memory(jcr->job_metadata);
2793 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2797 if (!jcr->is_canceled()) {
2801 stop_dir_heartbeat(jcr);
2803 jcr->setJobStatus(JS_Terminated);
2804 if (jcr->JobStatus != JS_Terminated) {
2805 sd->suppress_error_messages(true);
2809 * Send Close session command to Storage daemon
2811 sd->fsend(read_close, jcr->Ticket);
2812 Dmsg1(100, "filed>stored: %s", sd->msg);
2814 bget_msg(sd); /* get OK */
2816 /* Inform Storage daemon that we are done */
2817 sd->signal(BNET_TERMINATE);
2819 #if defined(WIN32_VSS)
2820 /* STOP VSS ON WIN32 */
2821 /* tell vss to close the restore session */
2822 Dmsg0(100, "About to call CloseRestore\n");
2823 if (jcr->Snapshot) {
2825 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2827 Dmsg0(100, "Really about to call CloseRestore\n");
2828 if (jcr->pVSSClient->CloseRestore()) {
2829 Dmsg0(100, "CloseRestore success\n");
2831 /* inform user about writer states */
2832 for (int i=0; i<(int)jcr->pVSSClient->GetWriterCount(); i++) {
2833 int msg_type = M_INFO;
2834 if (jcr->pVSSClient->GetWriterState(i) < 1) {
2835 //msg_type = M_WARNING;
2838 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"),
2839 jcr->pVSSClient->GetWriterInfo(i));
2844 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2850 bfree_and_null(jcr->where);
2851 bfree_and_null(jcr->RegexWhere);
2853 if (jcr->JobErrors) {
2854 jcr->setJobStatus(JS_ErrorTerminated);
2857 Dmsg0(100, "Done in job.c\n");
2859 if (jcr->multi_restore) {
2860 Dmsg0(100, OKstoreend);
2861 dir->fsend(OKstoreend);
2862 ret = 1; /* we continue the loop, waiting for next part */
2864 ret = 0; /* we stop here */
2867 if (job_canceled(jcr)) {
2868 ret = 0; /* we stop here */
2872 end_restore_cmd(jcr); /* stopping so send bEventEndRestoreJob */
2876 free_and_null_pool_memory(args);
2877 free_and_null_pool_memory(restore_where);
2878 free_and_null_pool_memory(restore_rwhere);
2883 static int end_restore_cmd(JCR *jcr)
2885 Dmsg0(5, "end_restore_cmd\n");
2886 generate_plugin_event(jcr, bEventEndRestoreJob);
2887 return 0; /* return and terminate command loop */
2890 static int open_sd_read_session(JCR *jcr)
2892 BSOCK *sd = jcr->store_bsock;
2895 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2898 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2899 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2900 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2902 * Open Read Session with Storage daemon
2904 sd->fsend(read_open, "DummyVolume",
2905 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2906 jcr->StartBlock, jcr->EndBlock);
2907 Dmsg1(110, ">stored: %s", sd->msg);
2912 if (bget_msg(sd) >= 0) {
2913 Dmsg1(110, "filed<stored: %s", sd->msg);
2914 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2915 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2918 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2920 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2925 * Use interactive session for the current restore
2927 if (jcr->interactive_session) {
2928 sd->fsend(read_ctrl, jcr->Ticket);
2929 Dmsg1(110, ">stored: %s", sd->msg);
2933 * Start read of data with Storage daemon
2935 sd->fsend(read_data, jcr->Ticket);
2936 Dmsg1(110, ">stored: %s", sd->msg);
2941 if (!response(jcr, sd, OK_data, "Read Data")) {
2948 * Destroy the Job Control Record and associated
2949 * resources (sockets).
2951 static void filed_free_jcr(JCR *jcr)
2953 if (jcr->dir_bsock) {
2954 free_bsock(jcr->dir_bsock);
2955 jcr->dir_bsock = NULL;
2957 if (jcr->sd_calls_client_bsock) {
2958 free_bsock(jcr->sd_calls_client_bsock);
2959 jcr->sd_calls_client_bsock = NULL;
2961 if (jcr->store_bsock) {
2962 free_bsock(jcr->store_bsock);
2963 jcr->store_bsock = NULL;
2965 if (jcr->last_fname) {
2966 free_pool_memory(jcr->last_fname);
2969 VSSCleanup(jcr->pVSSClient);
2971 free_plugins(jcr); /* release instantiated plugins */
2972 free_runscripts(jcr->RunScripts);
2973 delete jcr->RunScripts;
2974 free_path_list(jcr);
2976 if (jcr->JobId != 0) {
2977 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2983 * Get response from Storage daemon to a command we
2984 * sent. Check that the response is OK.
2986 * Returns: 0 on failure
2989 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2996 if ((ret = bget_msg(sd)) > 0) {
2997 Dmsg0(110, sd->msg);
2998 if (strcmp(sd->msg, resp) == 0) {
3002 if (job_canceled(jcr)) {
3003 return 0; /* if canceled avoid useless error messages */
3005 if (sd->is_error()) {
3006 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
3007 cmd, sd->bstrerror());
3011 Jmsg4(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got len=%ld msg=\"%s\"\n"),
3012 cmd, resp, sd->msglen, smartdump(sd->msg, sd->msglen, buf, sizeof(buf)));
3014 Jmsg3(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got SIGNAL %s\n"),
3015 cmd, resp, bnet_sig_to_ascii(ret));