1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
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.
8
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.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Bacula File Daemon Job processing
21 *
22 * Written by Kern Sibbald, October MM
23 */
24
25 #include "bacula.h"
26 #include "filed.h"
27 #include "ch.h"
28 #ifdef WIN32_VSS
29 #include "vss.h"
30 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 #endif
32
33 /* Globals */
34 bool win32decomp = false;
35 bool no_win32_write_errors = false;
36
37 /* Static variables */
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 #ifdef HAVE_WIN32
41 const bool have_win32 = true;
42 #else
43 const bool have_win32 = false;
44 #endif
45
46 #ifdef HAVE_ACL
47 const bool have_acl = true;
48 #else
49 const bool have_acl = false;
50 #endif
51
52 #if HAVE_XATTR
53 const bool have_xattr = true;
54 #else
55 const bool have_xattr = false;
56 #endif
57
58 extern CLIENT *me; /* our client resource */
59
60 /* Imported functions */
61 extern int status_cmd(JCR *jcr);
62 extern int qstatus_cmd(JCR *jcr);
63 extern int accurate_cmd(JCR *jcr);
64 extern int collect_cmd(JCR *jcr);
65
66 /* Forward referenced functions */
67 static int backup_cmd(JCR *jcr);
68 static int component_cmd(JCR *jcr);
69 static int cancel_cmd(JCR *jcr);
70 static int setdebug_cmd(JCR *jcr);
71 static int setbandwidth_cmd(JCR *jcr);
72 static int estimate_cmd(JCR *jcr);
73 static int hello_cmd(JCR *jcr);
74 static int job_cmd(JCR *jcr);
75 static int fileset_cmd(JCR *jcr);
76 static int level_cmd(JCR *jcr);
77 static int verify_cmd(JCR *jcr);
78 static int restore_cmd(JCR *jcr);
79 static int end_restore_cmd(JCR *jcr);
80 static int storage_cmd(JCR *jcr);
81 static int session_cmd(JCR *jcr);
82 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
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);
94 #ifdef DEVELOPER
95 static int exit_cmd(JCR *jcr);
96 #endif
97
98 /* Exported functions */
99
100 #define ACCESS_MONITOR 1
101 #define ACCESS_REMOTE 2
102
103 /*
104 * The following are the recognized commands from the Director.
105 */
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},
135 {"statistics", collect_cmd, 0},
136 #ifdef DEVELOPER
137 {"exit", exit_cmd, 0},
138 #endif
139 {NULL, NULL} /* list terminator */
140 };
141
142 /* Commands received from director that need scanning */
143 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
144 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
145 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
146 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
147
148 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
149 static char restorefcmd1[] = "restore files=%d replace=%c prelinks=%d where=\n";
150
151 /* The following restore commands may have a big where=/regexwhere= parameter
152 * the bsscanf is limiting the default %s to 1000c. To allow more than 1000 bytes,
153 * we can specify %xxxxs where xxxx is the size expected in bytes.
154 *
155 * So, the code will add %s\n to the end of the following restore commands
156 */
157 static char restorecmd[] = "restore replace=%c prelinks=%d where=";
158 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=";
159 static char restorefcmd[] = "restore files=%d replace=%c prelinks=%d where=";
160 static char restorefcmdR[] = "restore files=%d replace=%c prelinks=%d regexwhere=";
161
162 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
163 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
164 static char endrestoreobjectcmd[] = "restoreobject end\n";
165 static char verifycmd[] = "verify level=%30s";
166 static char estimatecmd[] = "estimate listing=%d";
167 static char runbefore[] = "RunBeforeJob %s";
168 static char runafter[] = "RunAfterJob %s";
169 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
170 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
171
172 /* Responses sent to Director */
173 static char errmsg[] = "2999 Invalid command\n";
174 static char no_auth[] = "2998 No Authorization\n";
175 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
176 static char OKBandwidth[] = "2000 OK Bandwidth\n";
177 static char OKinc[] = "2000 OK include\n";
178 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
179 static char OKlevel[] = "2000 OK level\n";
180 static char OKbackup[] = "2000 OK backup\n";
181 static char OKverify[] = "2000 OK verify\n";
182 static char OKrestore[] = "2000 OK restore\n";
183 static char OKsession[] = "2000 OK session\n";
184 static char OKstore[] = "2000 OK storage\n";
185 static char OKstoreend[] = "2000 OK storage end\n";
186 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
187 static char OKsetdebug[] = "2000 OK setdebug=%ld trace=%ld hangup=%ld"
188 " blowup=%ld options=%s tags=%s\n";
189 static char BADjob[] = "2901 Bad Job\n";
190 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%d ReadBytes=%lld"
191 " JobBytes=%lld Errors=%d VSS=%d Encrypt=%d"
192 " CommBytes=%lld CompressCommBytes=%lld\n";
193 static char OKRunBefore[] = "2000 OK RunBefore\n";
194 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
195 static char OKRunAfter[] = "2000 OK RunAfter\n";
196 static char OKRunScript[] = "2000 OK RunScript\n";
197 static char BADcmd[] = "2902 Bad %s\n";
198 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
199 static char OKComponentInfo[] = "2000 OK ComponentInfo\n";
200
201
202 /* Responses received from Storage Daemon */
203 static char OK_end[] = "3000 OK end\n";
204 static char OK_close[] = "3000 OK close Status = %d\n";
205 static char OK_open[] = "3000 OK open ticket = %d\n";
206 static char OK_data[] = "3000 OK data\n";
207 static char OK_append[] = "3000 OK append data\n";
208
209
210 /* Commands sent to Storage Daemon */
211 static char append_open[] = "append open session\n";
212 static char append_data[] = "append data %d\n";
213 static char append_end[] = "append end session %d\n";
214 static char append_close[] = "append close session %d\n";
215 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
216 static char read_data[] = "read data %d\n";
217 static char read_close[] = "read close session %d\n";
218 static char read_ctrl[] = "read control %d\n";
219
220 /* Should tell us if a command is authorized or not */
access_ok(struct s_cmds * cmd,DIRRES * dir)221 static bool access_ok(struct s_cmds *cmd, DIRRES* dir)
222 {
223 if ((cmd->access & ACCESS_MONITOR) && dir->monitor) {
224 return true;
225 }
226 if ((cmd->access & ACCESS_REMOTE) && dir->remote) {
227 return true;
228 }
229 if (!dir->remote && !dir->monitor) {
230 return true;
231 }
232 return false;
233 }
234
235 /*
236 * Accept requests from a Director
237 *
238 * NOTE! We are running as a separate thread
239 *
240 * Send output one line
241 * at a time followed by a zero length transmission.
242 *
243 * Return when the connection is terminated or there
244 * is an error.
245 *
246 * Basic task here is:
247 * Authenticate Director (during Hello command).
248 * Accept commands one at a time from the Director
249 * and execute them.
250 *
251 * Concerning ClientRunBefore/After, the sequence of events
252 * is rather critical. If they are not done in the right
253 * order one can easily get FD->SD timeouts if the script
254 * runs a long time.
255 *
256 * The current sequence of events is:
257 * 1. Dir starts job with FD
258 * 2. Dir connects to SD
259 * 3. Dir connects to FD
260 * 4. FD connects to SD
261 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
262 * 6. Dir sends include/exclude
263 * 7. FD sends the file data to SD
264 * 8. SD/FD disconnects while the SD despools data and attributes (optional)
265 * 9. FD runs ClientRunAfterJob
266 */
267
handle_director_request(BSOCK * dir)268 static void *handle_director_request(BSOCK *dir)
269 {
270 int i;
271 bool found, quit;
272 bool first = true;
273 JCR *jcr;
274 const char jobname[12] = "*Director*";
275 suspendres_t suspend;
276
277 prevent_os_suspensions(suspend); /* do not suspend during backup/restore */
278 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
279 jcr->sd_calls_client_bsock = NULL;
280 jcr->sd_calls_client = false;
281 jcr->dir_bsock = dir;
282 jcr->ff = init_find_files();
283 jcr->start_time = time(NULL);
284 jcr->RunScripts = New(alist(10, not_owned_by_alist));
285 jcr->last_fname = get_pool_memory(PM_FNAME);
286 jcr->last_fname[0] = 0;
287 jcr->client_name = get_memory(strlen(my_name) + 1);
288 pm_strcpy(jcr->client_name, my_name);
289 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
290 jcr->crypto.pki_sign = me->pki_sign;
291 jcr->crypto.pki_encrypt = me->pki_encrypt;
292 jcr->crypto.pki_keypair = me->pki_keypair;
293 jcr->crypto.pki_signers = me->pki_signers;
294 jcr->crypto.pki_recipients = me->pki_recipients;
295
296 dir->set_jcr(jcr);
297 jcr->set_killable(true); /* allow dir to kill/cancel job */
298 /* Initialize SD start condition variable */
299 int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
300 if (errstat != 0) {
301 berrno be;
302 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
303 goto bail_out;
304 }
305 enable_backup_privileges(NULL, 1 /* ignore_errors */);
306
307 for (quit=false; !quit;) {
308 jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE; /* overriden by some commands */
309 if (!first) { /* first call the read is done */
310 /* Read command */
311 if (dir->recv() < 0) {
312 break; /* connection terminated */
313 }
314 }
315 if (dir->msglen == 0) { /* Bad connection */
316 break;
317 }
318 first = false;
319 dir->msg[dir->msglen] = 0;
320 Dmsg1(100, "<dird: %s\n", dir->msg);
321 found = false;
322 for (i=0; cmds[i].cmd; i++) {
323 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
324 found = true; /* indicate command found */
325 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
326 dir->fsend(no_auth);
327 dir->signal(BNET_EOD);
328 break;
329 }
330 if (jcr->authenticated && !access_ok(&cmds[i], jcr->director)) {
331 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
332 dir->fsend(invalid_cmd);
333 dir->signal(BNET_EOD);
334 break;
335 }
336 if ((me->disabled_cmds_array && me->disabled_cmds_array[i]) ||
337 (jcr->director && jcr->director->disabled_cmds_array &&
338 jcr->director->disabled_cmds_array[i])) {
339 Jmsg(jcr, M_FATAL, 0, _("Command: \"%s\" is disabled.\n"), cmds[i].cmd);
340 quit = true;
341 break;
342 }
343 Dmsg2(100, "Executing %s Dir %s command.\n", cmds[i].cmd, dir->msg);
344 if (!cmds[i].func(jcr)) { /* do command */
345 quit = true; /* error or fully terminated, get out */
346 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
347 }
348 break;
349 }
350 }
351 if (!found) { /* command not found */
352 dir->fsend(errmsg);
353 quit = true;
354 break;
355 }
356 }
357
358 /* Inform Storage daemon that we are done */
359 if (jcr->store_bsock) {
360 jcr->store_bsock->signal(BNET_TERMINATE);
361 }
362
363 /* Run the after job */
364 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
365
366 /* send any queued messages before reporting the jobstatus to the director */
367 dequeue_messages(jcr);
368
369 if (jcr->JobId) { /* send EndJob if running a job */
370 uint64_t CommBytes, CommCompressedBytes;
371 uint32_t vss, encrypt;
372 /* Send termination status back to Dir */
373 if (jcr->store_bsock) {
374 CommBytes = jcr->store_bsock->CommBytes();
375 CommCompressedBytes = jcr->store_bsock->CommCompressedBytes();
376 } else {
377 CommBytes = CommCompressedBytes = 0;
378 }
379 encrypt = jcr->crypto.pki_encrypt;
380 vss = jcr->Snapshot;
381 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
382 jcr->ReadBytes, jcr->JobBytes, jcr->JobErrors, vss,
383 encrypt, CommBytes, CommCompressedBytes);
384 //Dmsg0(0, dir->msg);
385 }
386
387 generate_daemon_event(jcr, "JobEnd");
388 generate_plugin_event(jcr, bEventJobEnd);
389
390 bail_out:
391 dequeue_messages(jcr); /* send any queued messages, will no longer impact
392 * the job status... */
393 dequeue_daemon_messages(jcr);
394
395 /* Inform Director that we are done */
396 dir->signal(BNET_TERMINATE);
397
398 free_and_null_pool_memory(jcr->job_metadata);
399
400 /* Clean up fileset */
401 FF_PKT *ff = jcr->ff;
402 findFILESET *fileset = ff->fileset;
403 if (fileset) {
404 int i, j, k;
405 /* Delete FileSet Include lists */
406 for (i=0; i<fileset->include_list.size(); i++) {
407 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
408 for (j=0; j<incexe->opts_list.size(); j++) {
409 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
410 if (fo->plugin) {
411 free(fo->plugin);
412 }
413 for (k=0; k<fo->regex.size(); k++) {
414 regfree((regex_t *)fo->regex.get(k));
415 }
416 for (k=0; k<fo->regexdir.size(); k++) {
417 regfree((regex_t *)fo->regexdir.get(k));
418 }
419 for (k=0; k<fo->regexfile.size(); k++) {
420 regfree((regex_t *)fo->regexfile.get(k));
421 }
422 fo->regex.destroy();
423 fo->regexdir.destroy();
424 fo->regexfile.destroy();
425 fo->wild.destroy();
426 fo->wilddir.destroy();
427 fo->wildfile.destroy();
428 fo->wildbase.destroy();
429 fo->base.destroy();
430 fo->fstype.destroy();
431 fo->drivetype.destroy();
432 }
433 incexe->opts_list.destroy();
434 incexe->name_list.destroy();
435 incexe->plugin_list.destroy();
436 if (incexe->ignoredir) {
437 free(incexe->ignoredir);
438 }
439 }
440 fileset->include_list.destroy();
441
442 /* Delete FileSet Exclude lists */
443 for (i=0; i<fileset->exclude_list.size(); i++) {
444 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
445 for (j=0; j<incexe->opts_list.size(); j++) {
446 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
447 fo->regex.destroy();
448 fo->regexdir.destroy();
449 fo->regexfile.destroy();
450 fo->wild.destroy();
451 fo->wilddir.destroy();
452 fo->wildfile.destroy();
453 fo->wildbase.destroy();
454 fo->base.destroy();
455 fo->fstype.destroy();
456 fo->drivetype.destroy();
457 }
458 incexe->opts_list.destroy();
459 incexe->name_list.destroy();
460 incexe->plugin_list.destroy();
461 if (incexe->ignoredir) {
462 free(incexe->ignoredir);
463 }
464 }
465 fileset->exclude_list.destroy();
466 free(fileset);
467 }
468 ff->fileset = NULL;
469 ff->mount_points.destroy();
470 Dmsg0(100, "Calling term_find_files\n");
471 term_find_files(jcr->ff);
472 jcr->ff = NULL;
473 Dmsg0(100, "Done with term_find_files\n");
474 pthread_cond_destroy(&jcr->job_start_wait);
475 free_jcr(jcr); /* destroy JCR record */
476 Dmsg0(100, "Done with free_jcr\n");
477 allow_os_suspensions(suspend); /* FD can now be suspended */
478 Dsm_check(100);
479 garbage_collect_memory_pool();
480 return NULL;
481 }
482
483
484 /*
485 * Accept requests from a Director or a Storage daemon
486 */
handle_connection_request(void * caller)487 void *handle_connection_request(void *caller)
488 {
489 BSOCK *bs = (BSOCK *)caller;
490
491 if (bs->recv() > 0) {
492 if (strncmp(bs->msg, "Ping", 4) == 0) {
493 bs->fsend("2000 Ping OK\n");
494 bs->destroy();
495 return NULL;
496 }
497 if (bs->msglen < 25 || bs->msglen > 500) {
498 goto bail_out;
499 }
500 if (strncmp(bs->msg, "Hello FD: Bacula Storage", 20) ==0) {
501 return handle_storage_connection(bs);
502 }
503 if (strncmp(bs->msg, "Hello ", 5) == 0) {
504 return handle_director_request(bs);
505 }
506 }
507 bail_out:
508 Dmsg2(100, "Bad command from %s. Len=%d.\n", bs->who(), bs->msglen);
509 char addr[64];
510 char *who = bs->get_peer(addr, sizeof(addr)) ? bs->who() : addr;
511 Qmsg2(NULL, M_SECURITY, 0, _("FD expecting Hello got bad command from %s. Len=%d.\n"), who, bs->msglen);
512 sleep(5);
513 bs->destroy();
514 return NULL;
515 }
516
517
518 /*
519 * Test the Network between FD/SD
520 */
fd_testnetwork_cmd(JCR * jcr)521 static int fd_testnetwork_cmd(JCR *jcr)
522 {
523 bool can_compress, ok=true;
524 BSOCK *sd = jcr->store_bsock;
525 int64_t nb=0, nb2=0;
526 char ed1[50];
527 btime_t start, end;
528
529 if (!sd || !jcr->dir_bsock) {
530 return 1;
531 }
532 if (sscanf(jcr->dir_bsock->msg, "testnetwork bytes=%lld", &nb) != 1 || nb <= 0) {
533 sd->fsend("2999 testnetwork command error\n");
534 return 1;
535 }
536
537 /* We disable the comline compression, else all numbers will be wrong */
538 can_compress = sd->can_compress();
539
540 sd->fsend("testnetwork bytes=%lld\n", nb);
541 sd->clear_compress();
542
543 /* In the first step, we send X bytes to the SD */
544 memset(sd->msg, 0xAA, sizeof_pool_memory(sd->msg));
545 sd->msglen = sizeof_pool_memory(sd->msg);
546
547 start = get_current_btime();
548 for (nb2 = nb ; nb2 > 0 && ok ; nb2 -= sd->msglen) {
549 if (nb2 < sd->msglen) {
550 sd->msglen = nb2;
551 }
552 ok = sd->send();
553 }
554 sd->signal(BNET_EOD);
555 end = get_current_btime() + 1;
556
557 if (!ok) {
558 goto bail_out;
559 }
560
561 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms write_speed=%sB/s\n",
562 nb, end/1000 - start/1000,
563 edit_uint64_with_suffix(nb * 1000000 / (end - start), ed1));
564
565 /* Now we receive X bytes from the SD */
566 start = get_current_btime();
567 for (nb2 = 0; sd->recv() > 0; nb2 += sd->msglen) { }
568 end = get_current_btime() + 1;
569
570 jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms read_speed=%sB/s\n",
571 nb2, end/1000 - start/1000,
572 edit_uint64_with_suffix(nb2 * 1000000 / (end - start), ed1));
573
574 jcr->dir_bsock->signal(BNET_CMD_OK);
575
576 bail_out:
577 if (can_compress) {
578 sd->set_compress();
579 }
580 if (!ok) {
581 jcr->dir_bsock->fsend("2999 network test failed ERR=%s\n", sd->errmsg);
582 jcr->dir_bsock->signal(BNET_CMD_FAILED);
583 }
584
585 return 1;
586 }
587
proxy_cmd(JCR * jcr)588 static int proxy_cmd(JCR *jcr)
589 {
590 bool OK=true, fdcalled = false;
591 BSOCK *cons_bsock;
592 CONSRES *cons = jcr->director->console;
593 int v, maxfd;
594 fd_set fdset;
595 struct timeval tv;
596
597 if (!cons) {
598 cons = (CONSRES *)GetNextRes(R_CONSOLE, NULL);
599 }
600 /* Here, dir_bsock is not really the director, this is a console */
601 cons_bsock = connect_director(jcr, cons);
602 if (!cons_bsock) {
603 jcr->dir_bsock->signal(BNET_ERROR_MSG);
604 jcr->dir_bsock->fsend("2999 proxy error. ERR=%s\n", jcr->errmsg);
605 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
606 /* Error during the connect */
607 return 1;
608 }
609
610 /* Inform the console that the command is OK */
611 jcr->dir_bsock->fsend("2000 proxy OK.\n");
612 jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
613
614 maxfd = MAX(cons_bsock->m_fd, jcr->dir_bsock->m_fd) + 1;
615
616 /* Start to forward events from one to the other
617 * It can be done with 2 threads, or with a select
618 */
619 do {
620 FD_ZERO(&fdset);
621 FD_SET((unsigned)cons_bsock->m_fd, &fdset);
622 FD_SET((unsigned)jcr->dir_bsock->m_fd, &fdset);
623
624 tv.tv_sec = 5;
625 tv.tv_usec = 0;
626 switch ((v = select(maxfd, &fdset, NULL, NULL, &tv))) {
627 case 0: /* timeout */
628 OK = !jcr->is_canceled();
629 break;
630 case -1:
631 Dmsg1(0, "Bad call to select ERR=%d\n", errno);
632 OK = false;
633 default:
634 #ifdef HAVE_TLS
635 if (cons_bsock->tls && !tls_bsock_probe(cons_bsock)) {
636 /* maybe a session key negotiation waked up the socket */
637 FD_CLR(cons_bsock->m_fd, &fdset);
638 }
639 if (jcr->dir_bsock->tls && !tls_bsock_probe(jcr->dir_bsock)) {
640 /* maybe a session key negotiation waked up the socket */
641 FD_CLR(jcr->dir_bsock->m_fd, &fdset);
642 }
643 #endif
644 break;
645 }
646 Dmsg1(DT_NETWORK, "select = %d\n", v);
647 if (OK) {
648 if (FD_ISSET(cons_bsock->m_fd, &fdset)) {
649 v = cons_bsock->recv();
650 if (v == BNET_SIGNAL) {
651 if (cons_bsock->msglen == BNET_FDCALLED) {
652 OK = false;
653 fdcalled = true;
654 } else {
655 jcr->dir_bsock->signal(cons_bsock->msglen);
656 }
657
658 } else if (v >= 0) {
659 jcr->dir_bsock->fsend("%s", cons_bsock->msg);
660
661 } else {
662 /* We should not have such kind of message */
663 OK = false;
664 }
665 }
666 if (FD_ISSET(jcr->dir_bsock->m_fd, &fdset)) {
667 v = jcr->dir_bsock->recv();
668 if (v == BNET_SIGNAL) {
669 cons_bsock->signal(jcr->dir_bsock->msglen);
670 } else if (v >= 0) {
671 cons_bsock->fsend("%s", jcr->dir_bsock->msg);
672 } else {
673 /* We should not have such kind of message */
674 OK = false;
675 }
676 }
677 }
678 if (cons_bsock->is_error() || jcr->dir_bsock->is_error()) {
679 OK = false;
680 }
681 } while (OK && !jcr->is_canceled());
682
683 /* Close the socket, nothing more will come */
684 jcr->dir_bsock->signal(BNET_TERMINATE);
685 jcr->dir_bsock->close();
686 if (fdcalled) {
687 handle_connection_request(cons_bsock); /* will release the socket */
688 } else {
689 free_bsock(cons_bsock);
690 }
691 return 1;
692 }
693
sm_dump_cmd(JCR * jcr)694 static int sm_dump_cmd(JCR *jcr)
695 {
696 close_memory_pool();
697 sm_dump(false, true);
698 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
699 return 1;
700 }
701
702 #ifdef DEVELOPER
exit_cmd(JCR * jcr)703 static int exit_cmd(JCR *jcr)
704 {
705 jcr->dir_bsock->fsend("2000 exit OK\n");
706 terminate_filed(0);
707 return 0;
708 }
709 #endif
710
711 /*
712 * Hello from Director he must identify himself and provide his
713 * password.
714 */
hello_cmd(JCR * jcr)715 static int hello_cmd(JCR *jcr)
716 {
717 Dmsg0(120, "Calling Authenticate\n");
718 if (!validate_dir_hello(jcr)) {
719 return 0;
720 }
721 if (!authenticate_director(jcr)) {
722 return 0;
723 }
724 Dmsg0(120, "OK Authenticate\n");
725 jcr->authenticated = true;
726
727 dequeue_messages(jcr); /* dequeue any daemon messages */
728 return 1;
729 }
730
731 /*
732 * Cancel a Job
733 */
cancel_cmd(JCR * jcr)734 static int cancel_cmd(JCR *jcr)
735 {
736 BSOCK *dir = jcr->dir_bsock;
737 char Job[MAX_NAME_LENGTH];
738 JCR *cjcr;
739 int status;
740 const char *reason;
741
742 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
743 status = JS_Canceled;
744 reason = "canceled";
745 } else if (sscanf(dir->msg, "stop Job=%127s", Job) == 1) {
746 status = JS_Incomplete;
747 reason = "stopped";
748 } else {
749 dir->fsend(_("2902 Error scanning cancel command.\n"));
750 goto bail_out;
751 }
752 if (!(cjcr=get_jcr_by_full_name(Job))) {
753 dir->fsend(_("2901 Job %s not found.\n"), Job);
754 } else {
755 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
756 cjcr->setJobStatus(status);
757 if (cjcr->store_bsock) {
758 cjcr->store_bsock->cancel();
759 }
760 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
761 free_jcr(cjcr);
762 dir->fsend(_("2001 Job \"%s\" marked to be %s.\n"),
763 Job, reason);
764 }
765
766 bail_out:
767 dir->signal(BNET_EOD);
768 return 1;
769 }
770
771 /**
772 * Set bandwidth limit as requested by the Director
773 *
774 */
setbandwidth_cmd(JCR * jcr)775 static int setbandwidth_cmd(JCR *jcr)
776 {
777 BSOCK *dir = jcr->dir_bsock;
778 int64_t bw=0;
779 JCR *cjcr;
780 char Job[MAX_NAME_LENGTH];
781 *Job=0;
782
783 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
784 pm_strcpy(jcr->errmsg, dir->msg);
785 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
786 return 0;
787 }
788
789 if (*Job) {
790 if(!(cjcr=get_jcr_by_full_name(Job))) {
791 dir->fsend(_("2901 Job %s not found.\n"), Job);
792 } else {
793 cjcr->max_bandwidth = bw;
794 if (cjcr->store_bsock) {
795 cjcr->store_bsock->set_bwlimit(bw);
796 }
797 free_jcr(cjcr);
798 }
799
800 } else { /* No job requested, apply globally */
801 me->max_bandwidth_per_job = bw; /* Overwrite directive */
802 foreach_jcr(cjcr) {
803 cjcr->max_bandwidth = bw;
804 if (cjcr->store_bsock) {
805 cjcr->store_bsock->set_bwlimit(bw);
806 }
807 }
808 endeach_jcr(cjcr);
809 }
810
811 return dir->fsend(OKBandwidth);
812 }
813
814 /**
815 * Set debug level as requested by the Director
816 *
817 */
setdebug_cmd(JCR * jcr)818 static int setdebug_cmd(JCR *jcr)
819 {
820 BSOCK *dir = jcr->dir_bsock;
821 int32_t trace, lvl;
822 int32_t hangup = -1;
823 int32_t blowup = -1;
824 int64_t level, level_tags = 0;
825 int scan;
826 char options[60];
827 char tags[512];
828
829 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
830 tags[0] = options[0] = 0;
831 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld blowup=%ld"
832 " options=%55s tags=%511s",
833 &lvl, &trace, &hangup, &blowup, options, tags);
834 if (scan != 6) {
835 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld",
836 &lvl, &trace, &hangup);
837 if (scan != 3) {
838 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
839 if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace) != 2) {
840 pm_strcpy(jcr->errmsg, dir->msg);
841 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
842 return 0;
843 } else {
844 hangup = -1;
845 }
846 }
847 }
848 level = lvl;
849 set_trace(trace);
850 set_hangup(hangup);
851 set_blowup(blowup);
852 if (!debug_parse_tags(tags, &level_tags)) {
853 *tags = 0;
854 }
855 if (level >= 0) {
856 debug_level = level;
857 }
858 debug_level_tags = level_tags;
859
860 /* Parse specific FD options */
861 for (char *p = options; *p ; p++) {
862 switch(*p) {
863 case 'i':
864 /* Turn on/off ignore bwrite() errors on restore */
865 no_win32_write_errors = true;
866 break;
867 case 'd':
868 /* Turn on/off decomp of BackupRead() streams */
869 win32decomp = true;
870 break;
871 }
872 }
873
874 /* handle other options */
875 set_debug_flags(options);
876
877 Dmsg6(150, "level=%ld trace=%ld hangup=%ld blowup=%d options=%s tags=%s\n",
878 lvl, get_trace(), get_hangup(), get_blowup(), options, tags);
879 return dir->fsend(OKsetdebug, lvl, get_trace(), get_hangup(),
880 get_blowup(), options, tags);
881 }
882
883
estimate_cmd(JCR * jcr)884 static int estimate_cmd(JCR *jcr)
885 {
886 BSOCK *dir = jcr->dir_bsock;
887 char ed1[50], ed2[50];
888
889 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
890 pm_strcpy(jcr->errmsg, dir->msg);
891 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
892 dir->fsend(_("2992 Bad estimate command.\n"));
893 return 0;
894 }
895 make_estimate(jcr);
896 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
897 edit_uint64_with_commas(jcr->JobBytes, ed2));
898 dir->signal(BNET_EOD);
899 return 1;
900 }
901
902 /**
903 * Get JobId and Storage Daemon Authorization key from Director
904 */
job_cmd(JCR * jcr)905 static int job_cmd(JCR *jcr)
906 {
907 BSOCK *dir = jcr->dir_bsock;
908 POOL_MEM sd_auth_key(PM_MESSAGE);
909 sd_auth_key.check_size(dir->msglen);
910
911 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
912 &jcr->VolSessionId, &jcr->VolSessionTime,
913 sd_auth_key.c_str()) != 5) {
914 pm_strcpy(jcr->errmsg, dir->msg);
915 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
916 dir->fsend(BADjob);
917 return 0;
918 }
919 set_jcr_in_tsd(jcr);
920 set_storage_auth_key(jcr, sd_auth_key.c_str());
921 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
922 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
923 new_plugins(jcr); /* instantiate plugins for this jcr */
924 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
925 #ifdef HAVE_WIN32
926 return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
927 #else
928 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
929 #endif
930 }
931
job_code_callback_filed(JCR * jcr,const char * param,char * buf,int buflen)932 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param, char *buf, int buflen)
933 {
934 switch (param[0]) {
935 case 'D':
936 if (jcr->director) {
937 return jcr->director->hdr.name;
938 }
939 break;
940 case 'S':
941 return jcr->PrevJob;
942 }
943 return NULL;
944
945 }
946
runbefore_cmd(JCR * jcr)947 static int runbefore_cmd(JCR *jcr)
948 {
949 bool ok;
950 BSOCK *dir = jcr->dir_bsock;
951 POOLMEM *cmd = get_memory(dir->msglen+1);
952 RUNSCRIPT *script;
953
954 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
955 if (sscanf(dir->msg, runbefore, cmd) != 1) {
956 pm_strcpy(jcr->errmsg, dir->msg);
957 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
958 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
959 free_memory(cmd);
960 return 0;
961 }
962 unbash_spaces(cmd);
963
964 /* Run the command now */
965 script = new_runscript();
966 script->set_job_code_callback(job_code_callback_filed);
967 script->set_command(cmd);
968 script->when = SCRIPT_Before;
969 ok = script->run(jcr, "ClientRunBeforeJob");
970 free_runscript(script);
971
972 free_memory(cmd);
973 if (ok) {
974 dir->fsend(OKRunBefore);
975 return 1;
976 } else {
977 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
978 return 0;
979 }
980 }
981
runbeforenow_cmd(JCR * jcr)982 static int runbeforenow_cmd(JCR *jcr)
983 {
984 BSOCK *dir = jcr->dir_bsock;
985
986 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
987 if (job_canceled(jcr)) {
988 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
989 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
990 return 0;
991 } else {
992 dir->fsend(OKRunBeforeNow);
993 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
994 return 1;
995 }
996 }
997
runafter_cmd(JCR * jcr)998 static int runafter_cmd(JCR *jcr)
999 {
1000 BSOCK *dir = jcr->dir_bsock;
1001 POOLMEM *msg = get_memory(dir->msglen+1);
1002 RUNSCRIPT *cmd;
1003
1004 Dmsg1(100, "runafter_cmd: %s", dir->msg);
1005 if (sscanf(dir->msg, runafter, msg) != 1) {
1006 pm_strcpy(jcr->errmsg, dir->msg);
1007 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
1008 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
1009 free_memory(msg);
1010 return 0;
1011 }
1012 unbash_spaces(msg);
1013
1014 cmd = new_runscript();
1015 cmd->set_job_code_callback(job_code_callback_filed);
1016 cmd->set_command(msg);
1017 cmd->on_success = true;
1018 cmd->on_failure = false;
1019 cmd->when = SCRIPT_After;
1020
1021 jcr->RunScripts->append(cmd);
1022
1023 free_pool_memory(msg);
1024 return dir->fsend(OKRunAfter);
1025 }
1026
runscript_cmd(JCR * jcr)1027 static int runscript_cmd(JCR *jcr)
1028 {
1029 BSOCK *dir = jcr->dir_bsock;
1030 POOLMEM *msg = get_memory(dir->msglen+1);
1031 int on_success, on_failure, fail_on_error;
1032
1033 RUNSCRIPT *cmd = new_runscript() ;
1034 cmd->set_job_code_callback(job_code_callback_filed);
1035
1036 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
1037 /* Note, we cannot sscanf into bools */
1038 if (sscanf(dir->msg, runscript, &on_success,
1039 &on_failure,
1040 &fail_on_error,
1041 &cmd->when,
1042 msg) != 5) {
1043 pm_strcpy(jcr->errmsg, dir->msg);
1044 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
1045 dir->fsend(_("2905 Bad RunScript command.\n"));
1046 free_runscript(cmd);
1047 free_memory(msg);
1048 return 0;
1049 }
1050 cmd->on_success = on_success;
1051 cmd->on_failure = on_failure;
1052 cmd->fail_on_error = fail_on_error;
1053 unbash_spaces(msg);
1054
1055 cmd->set_command(msg);
1056 cmd->debug();
1057 jcr->RunScripts->append(cmd);
1058
1059 free_pool_memory(msg);
1060 return dir->fsend(OKRunScript);
1061 }
1062
1063 /*
1064 * This reads data sent from the Director from the
1065 * RestoreObject table that allows us to get objects
1066 * that were backed up (VSS .xml data) and are needed
1067 * before starting the restore.
1068 */
restore_object_cmd(JCR * jcr)1069 static int restore_object_cmd(JCR *jcr)
1070 {
1071 BSOCK *dir = jcr->dir_bsock;
1072 int32_t FileIndex;
1073 restore_object_pkt rop;
1074
1075 memset(&rop, 0, sizeof(rop));
1076 rop.pkt_size = sizeof(rop);
1077 rop.pkt_end = sizeof(rop);
1078
1079 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
1080 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
1081 Dmsg0(20, "Got endrestoreobject\n");
1082 generate_plugin_event(jcr, bEventRestoreObject, NULL);
1083 return dir->fsend(OKRestoreObject);
1084 }
1085
1086 rop.plugin_name = (char *)malloc(dir->msglen);
1087 *rop.plugin_name = 0;
1088
1089 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
1090 &rop.object_full_len, &rop.object_index,
1091 &rop.object_type, &rop.object_compression, &FileIndex,
1092 rop.plugin_name) != 8) {
1093
1094 /* Old version, no plugin_name */
1095 if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
1096 &rop.object_full_len, &rop.object_index,
1097 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
1098 Dmsg0(5, "Bad restore object command\n");
1099 pm_strcpy(jcr->errmsg, dir->msg);
1100 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
1101 goto bail_out;
1102 }
1103 }
1104
1105 unbash_spaces(rop.plugin_name);
1106
1107 Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
1108 "FI=%d plugin_name=%s\n",
1109 rop.JobId, rop.object_len, rop.object_full_len,
1110 rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
1111 /* Read Object name */
1112 if (dir->recv() < 0) {
1113 goto bail_out;
1114 }
1115 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
1116 rop.object_name = bstrdup(dir->msg);
1117
1118 /* Read Object */
1119 if (dir->recv() < 0) {
1120 goto bail_out;
1121 }
1122 /* Transfer object from message buffer, and get new message buffer */
1123 rop.object = dir->msg;
1124 dir->msg = get_pool_memory(PM_MESSAGE);
1125
1126 /* If object is compressed, uncompress it */
1127 if (rop.object_compression == 1) { /* zlib level 9 */
1128 int stat;
1129 int out_len = rop.object_full_len + 100;
1130 POOLMEM *obj = get_memory(out_len);
1131 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
1132 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
1133 Dmsg1(100, "Zinflate stat=%d\n", stat);
1134 if (out_len != rop.object_full_len) {
1135 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
1136 rop.object_full_len, out_len, rop.object_name);
1137 }
1138 free_pool_memory(rop.object); /* release compressed object */
1139 rop.object = obj; /* new uncompressed object */
1140 rop.object_len = out_len;
1141 }
1142 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
1143 /* we still need to do this to detect a vss restore */
1144 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
1145 Dmsg0(100, "got job metadata\n");
1146 jcr->got_metadata = true;
1147 }
1148
1149 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
1150
1151 if (rop.object_name) {
1152 free(rop.object_name);
1153 }
1154 if (rop.object) {
1155 free_pool_memory(rop.object);
1156 }
1157 if (rop.plugin_name) {
1158 free(rop.plugin_name);
1159 }
1160
1161 Dmsg1(100, "Send: %s", OKRestoreObject);
1162 return 1;
1163
1164 bail_out:
1165 dir->fsend(_("2909 Bad RestoreObject command.\n"));
1166 return 0;
1167
1168 }
1169
1170
init_fileset(JCR * jcr)1171 static bool init_fileset(JCR *jcr)
1172 {
1173 FF_PKT *ff;
1174 findFILESET *fileset;
1175
1176 if (!jcr->ff) {
1177 return false;
1178 }
1179 ff = jcr->ff;
1180 if (ff->fileset) {
1181 return false;
1182 }
1183 fileset = (findFILESET *)bmalloc(sizeof(findFILESET));
1184 ff->fileset = fileset;
1185 fileset->state = state_none;
1186 fileset->include_list.init(1, true);
1187 fileset->exclude_list.init(1, true);
1188 return true;
1189 }
1190
append_file(JCR * jcr,findINCEXE * incexe,const char * buf,bool is_file)1191 static void append_file(JCR *jcr, findINCEXE *incexe,
1192 const char *buf, bool is_file)
1193 {
1194 if (is_file) {
1195 #ifdef HAVE_WIN32
1196 /* Special case for / under Win32,
1197 * user is requesting to include all local drives
1198 */
1199 if (strcmp(buf, "/") == 0) {
1200 //list_drives(&incexe->name_list);
1201
1202 } else {
1203 incexe->name_list.append(new_dlistString(buf));
1204 }
1205 #else
1206 incexe->name_list.append(new_dlistString(buf));
1207 #endif /* HAVE_WIN32 */
1208
1209 } else if (me->plugin_directory) {
1210 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
1211 incexe->plugin_list.append(new_dlistString(buf));
1212 } else {
1213 Jmsg(jcr, M_FATAL, 0,
1214 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
1215 buf);
1216 }
1217 }
1218
1219 /**
1220 * Add fname to include/exclude fileset list. First check for
1221 * | and < and if necessary perform command.
1222 */
add_file_to_fileset(JCR * jcr,const char * fname,bool is_file)1223 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
1224 {
1225 findFILESET *fileset = jcr->ff->fileset;
1226 char *p;
1227 BPIPE *bpipe;
1228 POOLMEM *fn;
1229 FILE *ffd;
1230 char buf[1000];
1231 int ch;
1232 int stat;
1233
1234 p = (char *)fname;
1235 ch = (uint8_t)*p;
1236 switch (ch) {
1237 case '|':
1238 Dmsg1(100, "Doing | of '%s' include on client.\n", p + 1);
1239 p++; /* skip over | */
1240 fn = get_pool_memory(PM_FNAME);
1241 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
1242 bpipe = open_bpipe(fn, 0, "r");
1243 if (!bpipe) {
1244 berrno be;
1245 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
1246 p, be.bstrerror());
1247 free_pool_memory(fn);
1248 return;
1249 }
1250 free_pool_memory(fn);
1251 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1252 strip_trailing_junk(buf);
1253 if (*buf) { /* Avoid empty lines */
1254 append_file(jcr, fileset->incexe, buf, is_file);
1255 }
1256 }
1257 if ((stat=close_bpipe(bpipe)) != 0) {
1258 berrno be;
1259 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
1260 p, be.code(stat), be.bstrerror(stat));
1261 return;
1262 }
1263 break;
1264 case '<':
1265 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
1266 p++; /* skip over < */
1267 if ((ffd = fopen(p, "rb")) == NULL) {
1268 berrno be;
1269 Jmsg(jcr, M_FATAL, 0,
1270 _("Cannot open FileSet input file: %s. ERR=%s\n"),
1271 p, be.bstrerror());
1272 return;
1273 }
1274 while (fgets(buf, sizeof(buf), ffd)) {
1275 strip_trailing_junk(buf);
1276 append_file(jcr, fileset->incexe, buf, is_file);
1277 }
1278 fclose(ffd);
1279 break;
1280 default:
1281 append_file(jcr, fileset->incexe, fname, is_file);
1282 break;
1283 }
1284 }
1285
get_incexe(JCR * jcr)1286 findINCEXE *get_incexe(JCR *jcr)
1287 {
1288 if (jcr->ff && jcr->ff->fileset) {
1289 return jcr->ff->fileset->incexe;
1290 }
1291 return NULL;
1292 }
1293
set_incexe(JCR * jcr,findINCEXE * incexe)1294 void set_incexe(JCR *jcr, findINCEXE *incexe)
1295 {
1296 findFILESET *fileset = jcr->ff->fileset;
1297 fileset->incexe = incexe;
1298 }
1299
1300
1301 /**
1302 * Define a new Exclude block in the FileSet
1303 */
new_exclude(JCR * jcr)1304 findINCEXE *new_exclude(JCR *jcr)
1305 {
1306 findFILESET *fileset = jcr->ff->fileset;
1307
1308 /* New exclude */
1309 fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1310 fileset->incexe->opts_list.init(1, true);
1311 fileset->incexe->name_list.init();
1312 fileset->incexe->plugin_list.init();
1313 fileset->exclude_list.append(fileset->incexe);
1314 return fileset->incexe;
1315 }
1316
1317 /**
1318 * Define a new Include block in the FileSet
1319 */
new_include(JCR * jcr)1320 findINCEXE *new_include(JCR *jcr)
1321 {
1322 findFILESET *fileset = jcr->ff->fileset;
1323
1324 /* New include */
1325 fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1326 fileset->incexe->opts_list.init(1, true);
1327 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1328 fileset->incexe->plugin_list.init();
1329 fileset->include_list.append(fileset->incexe);
1330 return fileset->incexe;
1331 }
1332
1333 /**
1334 * Define a new preInclude block in the FileSet
1335 * That is the include is prepended to the other
1336 * Includes. This is used for plugin exclusions.
1337 */
new_preinclude(JCR * jcr)1338 findINCEXE *new_preinclude(JCR *jcr)
1339 {
1340 findFILESET *fileset = jcr->ff->fileset;
1341
1342 /* New pre-include */
1343 fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1344 fileset->incexe->opts_list.init(1, true);
1345 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1346 fileset->incexe->plugin_list.init();
1347 fileset->include_list.prepend(fileset->incexe);
1348 return fileset->incexe;
1349 }
1350
start_options(FF_PKT * ff)1351 static findFOPTS *start_options(FF_PKT *ff)
1352 {
1353 int state = ff->fileset->state;
1354 findINCEXE *incexe = ff->fileset->incexe;
1355
1356 if (state != state_options) {
1357 ff->fileset->state = state_options;
1358 findFOPTS *fo = (findFOPTS *)bmalloc(sizeof(findFOPTS));
1359 fo->regex.init(1, true);
1360 fo->regexdir.init(1, true);
1361 fo->regexfile.init(1, true);
1362 fo->wild.init(1, true);
1363 fo->wilddir.init(1, true);
1364 fo->wildfile.init(1, true);
1365 fo->wildbase.init(1, true);
1366 fo->base.init(1, true);
1367 fo->fstype.init(1, true);
1368 fo->drivetype.init(1, true);
1369 incexe->current_opts = fo;
1370 incexe->opts_list.append(fo);
1371 }
1372 return incexe->current_opts;
1373 }
1374
1375 /*
1376 * Used by plugins to define a new options block
1377 */
new_options(JCR * jcr,findINCEXE * incexe)1378 void new_options(JCR *jcr, findINCEXE *incexe)
1379 {
1380 if (!incexe) {
1381 incexe = jcr->ff->fileset->incexe;
1382 }
1383 findFOPTS *fo = (findFOPTS *)bmalloc(sizeof(findFOPTS));
1384 fo->regex.init(1, true);
1385 fo->regexdir.init(1, true);
1386 fo->regexfile.init(1, true);
1387 fo->wild.init(1, true);
1388 fo->wilddir.init(1, true);
1389 fo->wildfile.init(1, true);
1390 fo->wildbase.init(1, true);
1391 fo->base.init(1, true);
1392 fo->fstype.init(1, true);
1393 fo->drivetype.init(1, true);
1394 incexe->current_opts = fo;
1395 incexe->opts_list.prepend(fo);
1396 jcr->ff->fileset->state = state_options;
1397 }
1398
1399 /**
1400 * Add a regex to the current fileset
1401 */
add_regex_to_fileset(JCR * jcr,const char * item,int type)1402 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1403 {
1404 findFOPTS *current_opts = start_options(jcr->ff);
1405 regex_t *preg;
1406 int rc;
1407 char prbuf[500];
1408
1409 preg = (regex_t *)malloc(sizeof(regex_t));
1410 if (current_opts->flags & FO_IGNORECASE) {
1411 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1412 } else {
1413 rc = regcomp(preg, item, REG_EXTENDED);
1414 }
1415 if (rc != 0) {
1416 regerror(rc, preg, prbuf, sizeof(prbuf));
1417 regfree(preg);
1418 free(preg);
1419 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1420 return state_error;
1421 }
1422 if (type == ' ') {
1423 current_opts->regex.append(preg);
1424 } else if (type == 'D') {
1425 current_opts->regexdir.append(preg);
1426 } else if (type == 'F') {
1427 current_opts->regexfile.append(preg);
1428 } else {
1429 return state_error;
1430 }
1431 return state_options;
1432 }
1433
1434 /**
1435 * Add a wild card to the current fileset
1436 */
add_wild_to_fileset(JCR * jcr,const char * item,int type)1437 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1438 {
1439 findFOPTS *current_opts = start_options(jcr->ff);
1440
1441 if (type == ' ') {
1442 current_opts->wild.append(bstrdup(item));
1443 } else if (type == 'D') {
1444 current_opts->wilddir.append(bstrdup(item));
1445 } else if (type == 'F') {
1446 current_opts->wildfile.append(bstrdup(item));
1447 } else if (type == 'B') {
1448 current_opts->wildbase.append(bstrdup(item));
1449 } else {
1450 return state_error;
1451 }
1452 return state_options;
1453 }
1454
1455
1456 /**
1457 * Add options to the current fileset
1458 */
add_options_to_fileset(JCR * jcr,const char * item)1459 int add_options_to_fileset(JCR *jcr, const char *item)
1460 {
1461 findFOPTS *current_opts = start_options(jcr->ff);
1462
1463 set_options(current_opts, item);
1464 return state_options;
1465 }
1466
add_fileset(JCR * jcr,const char * item)1467 static void add_fileset(JCR *jcr, const char *item)
1468 {
1469 FF_PKT *ff = jcr->ff;
1470 findFILESET *fileset = ff->fileset;
1471 int state = fileset->state;
1472 findFOPTS *current_opts;
1473
1474 /* Get code, optional subcode, and position item past the dividing space */
1475 Dmsg1(100, "%s\n", item);
1476 int code = item[0];
1477 if (code != '\0') {
1478 ++item;
1479 }
1480 int subcode = ' '; /* A space is always a valid subcode */
1481 if (item[0] != '\0' && item[0] != ' ') {
1482 subcode = item[0];
1483 ++item;
1484 }
1485 if (*item == ' ') {
1486 ++item;
1487 }
1488
1489 /* Skip all lines we receive after an error */
1490 if (state == state_error) {
1491 Dmsg0(100, "State=error return\n");
1492 return;
1493 }
1494
1495 /**
1496 * The switch tests the code for validity.
1497 * The subcode is always good if it is a space, otherwise we must confirm.
1498 * We set state to state_error first assuming the subcode is invalid,
1499 * requiring state to be set in cases below that handle subcodes.
1500 */
1501 if (subcode != ' ') {
1502 state = state_error;
1503 Dmsg0(100, "Set state=error or double code.\n");
1504 }
1505 switch (code) {
1506 case 'I':
1507 (void)new_include(jcr);
1508 break;
1509 case 'E':
1510 (void)new_exclude(jcr);
1511 break;
1512 case 'N': /* null */
1513 state = state_none;
1514 break;
1515 case 'F': /* file = */
1516 /* File item to include or exclude list */
1517 state = state_include;
1518 add_file_to_fileset(jcr, item, true);
1519 break;
1520 case 'P': /* plugin */
1521 /* Plugin item to include list */
1522 state = state_include;
1523 add_file_to_fileset(jcr, item, false);
1524 break;
1525 case 'R': /* regex */
1526 state = add_regex_to_fileset(jcr, item, subcode);
1527 break;
1528 case 'B':
1529 current_opts = start_options(ff);
1530 current_opts->base.append(bstrdup(item));
1531 state = state_options;
1532 break;
1533 case 'X': /* Filetype or Drive type */
1534 current_opts = start_options(ff);
1535 state = state_options;
1536 if (subcode == ' ') {
1537 current_opts->fstype.append(bstrdup(item));
1538 } else if (subcode == 'D') {
1539 current_opts->drivetype.append(bstrdup(item));
1540 } else {
1541 state = state_error;
1542 }
1543 break;
1544 case 'W': /* wild cards */
1545 state = add_wild_to_fileset(jcr, item, subcode);
1546 break;
1547 case 'O': /* Options */
1548 state = add_options_to_fileset(jcr, item);
1549 break;
1550 case 'Z': /* ignore dir */
1551 state = state_include;
1552 fileset->incexe->ignoredir = bstrdup(item);
1553 break;
1554 case 'D':
1555 current_opts = start_options(ff);
1556 // current_opts->reader = bstrdup(item); /* deprecated */
1557 state = state_options;
1558 break;
1559 case 'T':
1560 current_opts = start_options(ff);
1561 // current_opts->writer = bstrdup(item); /* deprecated */
1562 state = state_options;
1563 break;
1564 case 'G': /* Plugin command for this Option block */
1565 current_opts = start_options(ff);
1566 current_opts->plugin = bstrdup(item);
1567 state = state_options;
1568 break;
1569 default:
1570 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1571 state = state_error;
1572 break;
1573 }
1574 ff->fileset->state = state;
1575 }
1576
term_fileset(JCR * jcr)1577 static bool term_fileset(JCR *jcr)
1578 {
1579 FF_PKT *ff = jcr->ff;
1580
1581 #ifdef xxx_DEBUG_CODE
1582 findFILESET *fileset = ff->fileset;
1583 int i, j, k;
1584
1585 for (i=0; i<fileset->include_list.size(); i++) {
1586 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1587 Dmsg0(400, "I\n");
1588 for (j=0; j<incexe->opts_list.size(); j++) {
1589 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1590 for (k=0; k<fo->regex.size(); k++) {
1591 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1592 }
1593 for (k=0; k<fo->regexdir.size(); k++) {
1594 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1595 }
1596 for (k=0; k<fo->regexfile.size(); k++) {
1597 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1598 }
1599 for (k=0; k<fo->wild.size(); k++) {
1600 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1601 }
1602 for (k=0; k<fo->wilddir.size(); k++) {
1603 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1604 }
1605 for (k=0; k<fo->wildfile.size(); k++) {
1606 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1607 }
1608 for (k=0; k<fo->wildbase.size(); k++) {
1609 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1610 }
1611 for (k=0; k<fo->base.size(); k++) {
1612 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1613 }
1614 for (k=0; k<fo->fstype.size(); k++) {
1615 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1616 }
1617 for (k=0; k<fo->drivetype.size(); k++) {
1618 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1619 }
1620 }
1621 if (incexe->ignoredir) {
1622 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1623 }
1624 dlistString *node;
1625 foreach_dlist(node, &incexe->name_list) {
1626 Dmsg1(400, "F %s\n", node->c_str());
1627 }
1628 foreach_dlist(node, &incexe->plugin_list) {
1629 Dmsg1(400, "P %s\n", node->c_str());
1630 }
1631 }
1632 for (i=0; i<fileset->exclude_list.size(); i++) {
1633 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1634 Dmsg0(400, "E\n");
1635 for (j=0; j<incexe->opts_list.size(); j++) {
1636 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1637 for (k=0; k<fo->regex.size(); k++) {
1638 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1639 }
1640 for (k=0; k<fo->regexdir.size(); k++) {
1641 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1642 }
1643 for (k=0; k<fo->regexfile.size(); k++) {
1644 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1645 }
1646 for (k=0; k<fo->wild.size(); k++) {
1647 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1648 }
1649 for (k=0; k<fo->wilddir.size(); k++) {
1650 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1651 }
1652 for (k=0; k<fo->wildfile.size(); k++) {
1653 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1654 }
1655 for (k=0; k<fo->wildbase.size(); k++) {
1656 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1657 }
1658 for (k=0; k<fo->base.size(); k++) {
1659 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1660 }
1661 for (k=0; k<fo->fstype.size(); k++) {
1662 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1663 }
1664 for (k=0; k<fo->drivetype.size(); k++) {
1665 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1666 }
1667 }
1668 dlistString *node;
1669 foreach_dlist(node, &incexe->name_list) {
1670 Dmsg1(400, "F %s\n", node->c_str());
1671 }
1672 foreach_dlist(node, &incexe->plugin_list) {
1673 Dmsg1(400, "P %s\n", node->c_str());
1674 }
1675 }
1676 #endif
1677 return ff->fileset->state != state_error;
1678 }
1679
1680
1681 /**
1682 * As an optimization, we should do this during
1683 * "compile" time in filed/job.c, and keep only a bit mask
1684 * and the Verify options.
1685 */
set_options(findFOPTS * fo,const char * opts)1686 static int set_options(findFOPTS *fo, const char *opts)
1687 {
1688 int j;
1689 const char *p;
1690 char strip[100];
1691
1692 // Commented out as it is not backward compatible - KES
1693
1694 for (p=opts; *p; p++) {
1695 switch (*p) {
1696 case 'a': /* alway replace */
1697 case '0': /* no option */
1698 break;
1699 case 'e':
1700 fo->flags |= FO_EXCLUDE;
1701 break;
1702 case 'f':
1703 fo->flags |= FO_MULTIFS;
1704 break;
1705 case 'h': /* no recursion */
1706 fo->flags |= FO_NO_RECURSION;
1707 break;
1708 case 'H': /* no hard link handling */
1709 fo->flags |= FO_NO_HARDLINK;
1710 break;
1711 case 'i':
1712 fo->flags |= FO_IGNORECASE;
1713 break;
1714 case 'M': /* MD5 */
1715 fo->flags |= FO_MD5;
1716 break;
1717 case 'n':
1718 fo->flags |= FO_NOREPLACE;
1719 break;
1720 case 'p': /* use portable data format */
1721 fo->flags |= FO_PORTABLE;
1722 break;
1723 case 'R': /* Resource forks and Finder Info */
1724 fo->flags |= FO_HFSPLUS;
1725 break;
1726 case 'r': /* read fifo */
1727 fo->flags |= FO_READFIFO;
1728 break;
1729 case 'S':
1730 switch(*(p + 1)) {
1731 case '1':
1732 fo->flags |= FO_SHA1;
1733 p++;
1734 break;
1735 #ifdef HAVE_SHA2
1736 case '2':
1737 fo->flags |= FO_SHA256;
1738 p++;
1739 break;
1740 case '3':
1741 fo->flags |= FO_SHA512;
1742 p++;
1743 break;
1744 #endif
1745 default:
1746 /*
1747 * If 2 or 3 is seen here, SHA2 is not configured, so
1748 * eat the option, and drop back to SHA-1.
1749 */
1750 if (p[1] == '2' || p[1] == '3') {
1751 p++;
1752 }
1753 fo->flags |= FO_SHA1;
1754 break;
1755 }
1756 break;
1757 case 's':
1758 fo->flags |= FO_SPARSE;
1759 break;
1760 case 'm':
1761 fo->flags |= FO_MTIMEONLY;
1762 break;
1763 case 'k':
1764 fo->flags |= FO_KEEPATIME;
1765 break;
1766 case 'A':
1767 fo->flags |= FO_ACL;
1768 break;
1769 case 'V': /* verify options */
1770 /* Copy Verify Options */
1771 for (j=0; *p && *p != ':'; p++) {
1772 fo->VerifyOpts[j] = *p;
1773 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1774 j++;
1775 }
1776 }
1777 fo->VerifyOpts[j] = 0;
1778 break;
1779 case 'C': /* accurate options */
1780 /* Copy Accurate Options */
1781 for (j=0; *p && *p != ':'; p++) {
1782 fo->AccurateOpts[j] = *p;
1783 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1784 j++;
1785 }
1786 }
1787 fo->AccurateOpts[j] = 0;
1788 break;
1789 case 'J': /* Basejob options */
1790 /* Copy BaseJob Options */
1791 for (j=0; *p && *p != ':'; p++) {
1792 fo->BaseJobOpts[j] = *p;
1793 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1794 j++;
1795 }
1796 }
1797 fo->BaseJobOpts[j] = 0;
1798 break;
1799 case 'P': /* strip path */
1800 /* Get integer */
1801 p++; /* skip P */
1802 for (j=0; *p && *p != ':'; p++) {
1803 strip[j] = *p;
1804 if (j < (int)sizeof(strip) - 1) {
1805 j++;
1806 }
1807 }
1808 strip[j] = 0;
1809 fo->strip_path = atoi(strip);
1810 fo->flags |= FO_STRIPPATH;
1811 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1812 break;
1813 case 'w':
1814 fo->flags |= FO_IF_NEWER;
1815 break;
1816 case 'W':
1817 fo->flags |= FO_ENHANCEDWILD;
1818 break;
1819 case 'Z': /* compression */
1820 p++; /* skip Z */
1821 if (*p >= '0' && *p <= '9') {
1822 fo->flags |= FO_COMPRESS;
1823 fo->Compress_algo = COMPRESS_GZIP;
1824 fo->Compress_level = *p - '0';
1825 }
1826 else if (*p == 'o') {
1827 fo->flags |= FO_COMPRESS;
1828 fo->Compress_algo = COMPRESS_LZO1X;
1829 fo->Compress_level = 1; /* not used with LZO */
1830 }
1831 break;
1832 case 'K':
1833 fo->flags |= FO_NOATIME;
1834 break;
1835 case 'c':
1836 fo->flags |= FO_CHKCHANGES;
1837 break;
1838 case 'N':
1839 fo->flags |= FO_HONOR_NODUMP;
1840 break;
1841 case 'X':
1842 fo->flags |= FO_XATTR;
1843 break;
1844 default:
1845 Jmsg1(NULL, M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1846 break;
1847 }
1848 }
1849 return state_options;
1850 }
1851
1852
1853 /**
1854 * Director is passing his Fileset
1855 */
fileset_cmd(JCR * jcr)1856 static int fileset_cmd(JCR *jcr)
1857 {
1858 POOL_MEM buf(PM_MESSAGE);
1859 BSOCK *dir = jcr->dir_bsock;
1860 int rtnstat;
1861
1862 #if HAVE_WIN32
1863 jcr->Snapshot = (strstr(dir->msg, "vss=1") != NULL);
1864 #else
1865 jcr->Snapshot = (strstr(dir->msg, "snap=1") != NULL);
1866 #endif
1867 if (!init_fileset(jcr)) {
1868 return 0;
1869 }
1870 while (dir->recv() >= 0) {
1871 strip_trailing_junk(dir->msg);
1872 Dmsg1(500, "Fileset: %s\n", dir->msg);
1873 pm_strcpy(buf, dir->msg);
1874 add_fileset(jcr, buf.c_str());
1875 }
1876 if (!term_fileset(jcr)) {
1877 return 0;
1878 }
1879 rtnstat = dir->fsend(OKinc);
1880 generate_plugin_event(jcr, bEventEndFileSet);
1881 return rtnstat;
1882 }
1883
1884
1885 /*
1886 * The Director sends us the component info file, which
1887 * we will in turn pass to the VSS plugin.
1888 */
component_cmd(JCR * jcr)1889 static int component_cmd(JCR *jcr)
1890 {
1891 BSOCK *dir = jcr->dir_bsock;
1892
1893 while (dir->recv() >= 0) {
1894 Dmsg1(200, "filed<dird: component: %s", dir->msg);
1895 generate_plugin_event(jcr, bEventComponentInfo, (void *)dir->msg);
1896 }
1897 return dir->fsend(OKComponentInfo);
1898 }
1899
1900
1901 /**
1902 * Get backup level from Director
1903 *
1904 * Note: there are odd things such as accurate_differential,
1905 * and accurate_incremental that are passed in level, thus
1906 * the calls to strstr() below.
1907 *
1908 */
level_cmd(JCR * jcr)1909 static int level_cmd(JCR *jcr)
1910 {
1911 BSOCK *dir = jcr->dir_bsock;
1912 POOLMEM *level, *buf = NULL;
1913 int mtime_only;
1914
1915 level = get_memory(dir->msglen+1);
1916 Dmsg1(10, "level_cmd: %s", dir->msg);
1917
1918 /* keep compatibility with older directors */
1919 if (strstr(dir->msg, "accurate")) {
1920 jcr->accurate = true;
1921 }
1922 if (strstr(dir->msg, "rerunning")) {
1923 jcr->rerunning = true;
1924 }
1925 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1926 goto bail_out;
1927 }
1928 /* Base backup requested? */
1929 if (strcasecmp(level, "base") == 0) {
1930 jcr->setJobLevel(L_BASE);
1931 /* Full backup requested? */
1932 } else if (strcasecmp(level, "full") == 0) {
1933 jcr->setJobLevel(L_FULL);
1934 } else if (strstr(level, "differential")) {
1935 jcr->setJobLevel(L_DIFFERENTIAL);
1936 free_memory(level);
1937 return 1;
1938 } else if (strstr(level, "incremental")) {
1939 jcr->setJobLevel(L_INCREMENTAL);
1940 free_memory(level);
1941 return 1;
1942 /*
1943 * We get his UTC since time, then sync the clocks and correct it
1944 * to agree with our clock.
1945 */
1946 } else if (strcasecmp(level, "since_utime") == 0) {
1947 buf = get_memory(dir->msglen+1);
1948 utime_t since_time, adj;
1949 btime_t his_time, bt_start, rt=0, bt_adj=0, his_time_prev=0, n=0;
1950 if (jcr->getJobLevel() == L_NONE) {
1951 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1952 }
1953 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1954 buf, &mtime_only, jcr->PrevJob) != 3) {
1955 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1956 buf, &mtime_only) != 2) {
1957 goto bail_out;
1958 }
1959 }
1960 since_time = str_to_uint64(buf); /* this is the since time */
1961 Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1962 char ed1[50], ed2[50];
1963 /*
1964 * Sync clocks by polling him for the time. We take
1965 * 10 samples of his time throwing out the first two.
1966 */
1967 for (int i=0; i<10; i++) {
1968 bt_start = get_current_btime();
1969 dir->signal(BNET_BTIME); /* poll for time */
1970 if (dir->recv() <= 0) { /* get response */
1971 goto bail_out;
1972 }
1973 if (sscanf(dir->msg, "btime %50s", buf) != 1) {
1974 goto bail_out;
1975 }
1976 his_time = str_to_uint64(buf);
1977 rt = get_current_btime() - bt_start; /* compute round trip time */
1978 /* skip first two results and check for leap second */
1979 /* if any of the FD or DIR went back in time, skip this iteration */
1980 if (i < 2 || (his_time_prev > 0 && his_time < his_time_prev) || rt<0) {
1981 his_time_prev = his_time;
1982 continue;
1983 }
1984 his_time_prev = his_time;
1985 n++;
1986 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1987 edit_uint64(bt_start, ed2));
1988 bt_adj += bt_start - his_time - rt/2;
1989 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1990 }
1991 adj = 0;
1992 if (n > 0) { /* Should be 1 in the worst case */
1993 bt_adj = bt_adj / n; /* compute average time */
1994 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1995 adj = btime_to_utime(bt_adj);
1996 since_time += adj; /* adjust for clock difference */
1997 }
1998 /* Don't notify if time within 3 seconds */
1999 if (adj > 3 || adj < -3) {
2000 int type;
2001 if (adj > 600 || adj < -600) {
2002 type = M_WARNING;
2003 } else {
2004 type = M_INFO;
2005 }
2006 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
2007 }
2008 dir->signal(BNET_EOD);
2009
2010 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
2011 jcr->incremental = 1; /* set incremental or decremental backup */
2012 jcr->mtime = since_time; /* set since time */
2013 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
2014 } else {
2015 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
2016 free_memory(level);
2017 return 0;
2018 }
2019 free_memory(level);
2020 if (buf) {
2021 free_memory(buf);
2022 }
2023 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
2024 return dir->fsend(OKlevel);
2025
2026 bail_out:
2027 pm_strcpy(jcr->errmsg, dir->msg);
2028 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
2029 free_memory(level);
2030 if (buf) {
2031 free_memory(buf);
2032 }
2033 return 0;
2034 }
2035
2036 /**
2037 * Get session parameters from Director -- this is for a Restore command
2038 * This is deprecated. It is now passed via the bsr.
2039 */
session_cmd(JCR * jcr)2040 static int session_cmd(JCR *jcr)
2041 {
2042 BSOCK *dir = jcr->dir_bsock;
2043
2044 Dmsg1(100, "SessionCmd: %s", dir->msg);
2045 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
2046 &jcr->VolSessionId, &jcr->VolSessionTime,
2047 &jcr->StartFile, &jcr->EndFile,
2048 &jcr->StartBlock, &jcr->EndBlock) != 7) {
2049 pm_strcpy(jcr->errmsg, dir->msg);
2050 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
2051 return 0;
2052 }
2053
2054 return dir->fsend(OKsession);
2055 }
2056
set_storage_auth_key(JCR * jcr,char * key)2057 static void set_storage_auth_key(JCR *jcr, char *key)
2058 {
2059 /* if no key don't update anything */
2060 if (!*key) {
2061 return;
2062 }
2063
2064 /**
2065 * We can be contacting multiple storage daemons.
2066 * So, make sure that any old jcr->store_bsock is cleaned up.
2067 */
2068 free_bsock(jcr->store_bsock);
2069
2070 /**
2071 * We can be contacting multiple storage daemons.
2072 * So, make sure that any old jcr->sd_auth_key is cleaned up.
2073 */
2074 if (jcr->sd_auth_key) {
2075 /*
2076 * If we already have a Authorization key, director can do multi
2077 * storage restore
2078 */
2079 Dmsg0(5, "set multi_restore=true\n");
2080 jcr->multi_restore = true;
2081 bfree(jcr->sd_auth_key);
2082 }
2083
2084 jcr->sd_auth_key = bstrdup(key);
2085 Dmsg1(200, "set sd auth key %s\n", jcr->sd_auth_key);
2086 }
2087
2088 /**
2089 * Get address of storage daemon from Director
2090 *
2091 */
storage_cmd(JCR * jcr)2092 static int storage_cmd(JCR *jcr)
2093 {
2094 int stored_port = 0; /* storage daemon port */
2095 int enable_ssl; /* enable ssl to sd */
2096 POOL_MEM sd_auth_key(PM_MESSAGE);
2097 BSOCK *dir = jcr->dir_bsock;
2098 BSOCK *sd;
2099
2100 Dmsg1(100, "StorageCmd: %s", dir->msg);
2101 sd_auth_key.check_size(dir->msglen);
2102 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
2103 &enable_ssl, sd_auth_key.c_str()) == 4) {
2104 Dmsg1(100, "Set auth key %s\n", sd_auth_key.c_str());
2105 set_storage_auth_key(jcr, sd_auth_key.c_str());
2106 } else if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
2107 &stored_port, &enable_ssl) != 3) {
2108 pm_strcpy(jcr->errmsg, dir->msg);
2109 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
2110 Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
2111 goto bail_out;
2112 }
2113
2114
2115 /* TODO: see if we put limit on restore and backup... */
2116 if (!jcr->max_bandwidth) {
2117 if (jcr->director->max_bandwidth_per_job) {
2118 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
2119
2120 } else if (me->max_bandwidth_per_job) {
2121 jcr->max_bandwidth = me->max_bandwidth_per_job;
2122 }
2123 }
2124
2125 if (stored_port != 0) { /* We are doing the connecting */
2126 Dmsg3(110, "Connect to storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
2127 enable_ssl);
2128 jcr->sd_calls_client = false;
2129 sd = new_bsock();
2130 /* Open command communications with Storage daemon */
2131 /* Try to connect for 1 hour at 10 second intervals */
2132 sd->set_source_address(me->FDsrc_addr);
2133 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
2134 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
2135 /* destroy() OK because sd is local */
2136 sd->destroy();
2137 Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
2138 jcr->stored_addr, stored_port);
2139 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
2140 jcr->stored_addr, stored_port);
2141 goto bail_out;
2142 }
2143
2144 Dmsg0(110, "Connection OK to SD.\n");
2145 jcr->store_bsock = sd;
2146 } else { /* The storage daemon called us */
2147 struct timeval tv;
2148 struct timezone tz;
2149 struct timespec timeout;
2150 int errstat;
2151
2152 free_bsock(jcr->store_bsock);
2153 jcr->sd_calls_client = true;
2154
2155 /*
2156 * Wait for the Storage daemon to contact us to start the Job,
2157 * when he does, we will be released, unless the 30 minutes
2158 * expires.
2159 */
2160 gettimeofday(&tv, &tz);
2161 timeout.tv_nsec = tv.tv_usec * 1000;
2162 timeout.tv_sec = tv.tv_sec + 30 * 60; /* wait 30 minutes */
2163 P(mutex);
2164 while (jcr->sd_calls_client_bsock == NULL && !jcr->is_job_canceled()) {
2165 errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
2166 if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
2167 break;
2168 }
2169 Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
2170 }
2171 V(mutex);
2172 Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
2173
2174 /* We should already have a storage connection! */
2175 if (jcr->sd_calls_client_bsock == NULL) {
2176 Pmsg0(000, "Failed connect from Storage daemon. SD bsock=NULL.\n");
2177 Pmsg1(000, "Storagecmd: %s", dir->msg);
2178 Jmsg0(jcr, M_FATAL, 0, _("Failed connect from Storage daemon. SD bsock=NULL.\n"));
2179 goto bail_out;
2180 }
2181 if (jcr->is_job_canceled()) {
2182 goto bail_out;
2183 }
2184 /* Assign the new socket to the main one */
2185 jcr->lock_auth();
2186 jcr->store_bsock = jcr->sd_calls_client_bsock;
2187 jcr->sd_calls_client_bsock = NULL;
2188 jcr->unlock_auth();
2189 }
2190 jcr->store_bsock->set_bwlimit(jcr->max_bandwidth);
2191
2192 if (!send_hello_sd(jcr, jcr->Job)) {
2193 goto bail_out;
2194 }
2195
2196 if (!authenticate_storagedaemon(jcr)) {
2197 goto bail_out;
2198 }
2199 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
2200 Dmsg0(110, "Authenticated with SD.\n");
2201
2202 /* Send OK to Director */
2203 return dir->fsend(OKstore);
2204
2205 bail_out:
2206 dir->fsend(BADcmd, "storage");
2207 return 0;
2208 }
2209
2210 #ifdef HAVE_WIN32
2211 /* TODO: merge find.c ? */
is_excluded(findFILESET * fileset,char * path)2212 static bool is_excluded(findFILESET *fileset, char *path)
2213 {
2214 int fnm_flags=FNM_CASEFOLD;
2215 int fnmode=0;
2216
2217 /* Now apply the Exclude { } directive */
2218 for (int i=0; i<fileset->exclude_list.size(); i++) {
2219 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
2220 dlistString *node;
2221
2222 foreach_dlist(node, &incexe->name_list) {
2223 char *fname = node->c_str();
2224 Dmsg2(DT_VOLUME|50, "Testing %s against %s\n", path, fname);
2225 if (fnmatch(fname, path, fnmode|fnm_flags) == 0) {
2226 Dmsg1(050, "Reject wild2: %s\n", path);
2227 return true;
2228 }
2229 /* On windows, the path separator is a bit complex to handle. For
2230 * example, in fnmatch(), \ is written as \\\\ in the config file / is
2231 * different from \ So we have our own little strcmp for filenames
2232 */
2233 char *p;
2234 bool same=true;
2235 for (p = path; *p && *fname && same ; p++, fname++) {
2236 if (!((IsPathSeparator(*p) && IsPathSeparator(*fname)) ||
2237 (tolower(*p) == tolower(*fname)))) {
2238 same = false; /* Stop after the first one */
2239 }
2240 }
2241
2242 if (same) {
2243 /* End of the for loop, strings looks to be identical */
2244 Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2245 return true;
2246 }
2247
2248 /* Looks to be the same string, but with a trailing slash */
2249 if (fname[0] && IsPathSeparator(fname[0]) && fname[1] == '\0'
2250 && p[0] == '\0')
2251 {
2252 Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2253 return true;
2254 }
2255 }
2256 }
2257 return false;
2258 }
2259
2260 /*
2261 * For VSS we need to know which windows drives
2262 * are used, because we create a snapshot of all used
2263 * drives before operation
2264 *
2265 */
2266 static int
get_win32_driveletters(JCR * jcr,FF_PKT * ff,char * szDrives)2267 get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
2268 {
2269 int nCount = 0;
2270
2271 findFILESET *fileset = ff->fileset;
2272 int flags = 0;
2273 char drive[4];
2274
2275 MTab mtab;
2276 mtab.get(); /* read the disk structure */
2277
2278 /* Keep this part for compatibility reasons */
2279 strcpy(drive, "c:\\");
2280 for (int i=0; szDrives[i] ; i++) {
2281 drive[0] = szDrives[i];
2282 if (mtab.addInSnapshotSet(drive)) { /* When all volumes are selected, we can stop */
2283 Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2284 goto all_included;
2285 }
2286 }
2287
2288 if (fileset) {
2289 dlistString *node;
2290
2291 for (int i=0; i<fileset->include_list.size(); i++) {
2292
2293 findFOPTS *fo;
2294 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
2295
2296 /* look through all files */
2297 foreach_dlist(node, &incexe->name_list) {
2298 char *fname = node->c_str();
2299 if (mtab.addInSnapshotSet(fname)) {
2300 /* When all volumes are selected, we can stop */
2301 Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2302 goto all_included;
2303 }
2304 }
2305
2306 foreach_alist(fo, &incexe->opts_list) {
2307 flags |= fo->flags; /* We are looking for FO_MULTIFS and recurse */
2308 }
2309 }
2310
2311 /* TODO: it needs to be done Include by Include, but in the worst case,
2312 * we take too much snapshots...
2313 */
2314 if (flags & FO_MULTIFS) {
2315 /* Need to add subdirectories */
2316 POOLMEM *fn = get_pool_memory(PM_FNAME);
2317 MTabEntry *elt, *elt2;
2318 int len;
2319
2320 Dmsg0(DT_VOLUME|50, "OneFS is set, looking for remaining volumes\n");
2321
2322 foreach_rblist(elt, mtab.entries) {
2323 if (elt->in_SnapshotSet) {
2324 continue; /* Already in */
2325 }
2326 /* A volume can have multiple mount points */
2327 for (wchar_t *p = elt->first() ; p && *p ; p = elt->next(p)) {
2328 wchar_2_UTF8(&fn, p);
2329
2330 Dmsg1(DT_VOLUME|50, "Looking for path %s\n", fn);
2331
2332 /* First case, root drive (c:/, e:/, d:/), not a submount point */
2333 len = strlen(fn);
2334 if (len <= 3) {
2335 Dmsg1(DT_VOLUME|50, "Skiping %s\n", fn);
2336 continue;
2337 }
2338
2339 /* First thing is to look in the exclude list to see if this directory
2340 * is explicitely excluded
2341 */
2342 if (is_excluded(fileset, fn)) {
2343 Dmsg1(DT_VOLUME|50, "Looks to be excluded %s\n", fn);
2344 continue;
2345 }
2346
2347 /* c:/vol/vol2/vol3
2348 * will look c:/, then c:/vol/, then c:/vol2/ and if one of them
2349 * is selected, the sub volume will be directly marked.
2350 */
2351 for (char *p1 = fn ; *p1 && !elt->in_SnapshotSet ; p1++) {
2352 if (IsPathSeparator(*p1)) {
2353
2354 char c = *(p1 + 1);
2355 *(p1 + 1) = 0;
2356
2357 /* We look for the previous directory, and if marked, we mark
2358 * the current one as well
2359 */
2360 Dmsg1(DT_VOLUME|50, "Looking for %s\n", fn);
2361 elt2 = mtab.search(fn);
2362 if (elt2 && elt2->in_SnapshotSet) {
2363 Dmsg0(DT_VOLUME|50, "Put volume in SnapshotSet\n");
2364 elt->setInSnapshotSet();
2365 }
2366
2367 *(p1 + 1) = c; /* restore path separator */
2368 }
2369 }
2370 }
2371 }
2372 free_pool_memory(fn);
2373 }
2374 all_included:
2375 /* Now, we look the volume list to know which one to include */
2376 MTabEntry *elt;
2377 foreach_rblist(elt, mtab.entries) {
2378 if (elt->in_SnapshotSet) {
2379 Dmsg1(DT_VOLUME|50,"Adding volume in mount_points list %ls\n",elt->volumeName);
2380 nCount++;
2381 ff->mount_points.append(bwcsdup(elt->volumeName));
2382 }
2383 }
2384 }
2385
2386 return nCount;
2387 }
2388 #endif /* HAVE_WIN32 */
2389
2390 /*
2391 * Do a backup.
2392 */
backup_cmd(JCR * jcr)2393 static int backup_cmd(JCR *jcr)
2394 {
2395 BSOCK *dir = jcr->dir_bsock;
2396 BSOCK *sd = jcr->store_bsock;
2397 int ok = 0;
2398 int SDJobStatus;
2399 int32_t FileIndex;
2400
2401 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
2402 jcr->JobFiles = FileIndex;
2403 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
2404 }
2405
2406 /*
2407 * If explicitly requesting FO_ACL or FO_XATTR, fail job if it
2408 * is not available on Client machine
2409 */
2410 if (jcr->ff->flags & FO_ACL && !(have_acl||have_win32)) {
2411 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for Client.\n"));
2412 goto cleanup;
2413 }
2414 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
2415 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for Client.\n"));
2416 goto cleanup;
2417 }
2418 jcr->setJobStatus(JS_Blocked);
2419 jcr->setJobType(JT_BACKUP);
2420 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
2421 if (sd == NULL) {
2422 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
2423 dir->fsend(BADcmd, "backup");
2424 goto cleanup;
2425 }
2426
2427 dir->fsend(OKbackup);
2428 Dmsg1(110, "filed>dird: %s", dir->msg);
2429
2430 /*
2431 * Send Append Open Session to Storage daemon
2432 */
2433 sd->fsend(append_open);
2434 Dmsg1(110, ">stored: %s", sd->msg);
2435 /**
2436 * Expect to receive back the Ticket number
2437 */
2438 if (bget_msg(sd) >= 0) {
2439 Dmsg1(110, "<stored: %s", sd->msg);
2440 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2441 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2442 goto cleanup;
2443 }
2444 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
2445 } else {
2446 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2447 goto cleanup;
2448 }
2449
2450 /**
2451 * Send Append data command to Storage daemon
2452 */
2453 sd->fsend(append_data, jcr->Ticket);
2454 Dmsg1(110, ">stored: %s", sd->msg);
2455
2456 /**
2457 * Expect to get OK data
2458 */
2459 Dmsg1(110, "<stored: %s", sd->msg);
2460 if (!response(jcr, sd, OK_data, "Append Data")) {
2461 goto cleanup;
2462 }
2463
2464 generate_daemon_event(jcr, "JobStart");
2465 generate_plugin_event(jcr, bEventStartBackupJob);
2466
2467 if (jcr->Snapshot) {
2468 #if defined(WIN32_VSS)
2469 P(vss_mutex);
2470 /* START VSS ON WIN32 */
2471 jcr->pVSSClient = VSSInit();
2472 if (jcr->pVSSClient->InitializeForBackup(jcr)) {
2473 generate_plugin_event(jcr, bEventVssBackupAddComponents);
2474 /* tell vss which drives to snapshot */
2475 char szWinDriveLetters[27];
2476 *szWinDriveLetters=0;
2477 generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
2478 if (get_win32_driveletters(jcr, jcr->ff, szWinDriveLetters)) {
2479 Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\"\n"),
2480 jcr->pVSSClient->GetDriverName());
2481
2482 if (!jcr->pVSSClient->CreateSnapshots(&jcr->ff->mount_points)) {
2483 berrno be;
2484 Jmsg(jcr, M_FATAL, 0, _("VSS CreateSnapshots failed. ERR=%s\n"),
2485 be.bstrerror());
2486 } else {
2487 /* inform user about writer states */
2488 for (int i=0; i < (int)jcr->pVSSClient->GetWriterCount(); i++) {
2489 if (jcr->pVSSClient->GetWriterState(i) < 1) {
2490 Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"),
2491 jcr->pVSSClient->GetWriterInfo(i));
2492 }
2493 }
2494 }
2495 } else {
2496 Jmsg(jcr, M_WARNING, 0, _("No drive letters found for generating VSS snapshots.\n"));
2497 }
2498 } else {
2499 berrno be;
2500 Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"),
2501 be.bstrerror());
2502 }
2503 V(vss_mutex);
2504 #else
2505 Dmsg0(10, "Open a snapshot session\n");
2506 /* TODO: See if we abort the job */
2507 jcr->Snapshot = open_snapshot_backup_session(jcr);
2508 #endif
2509 }
2510 /* Call RunScript just after the Snapshot creation, usually, we restart services */
2511 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2512
2513 /*
2514 * Send Files to Storage daemon
2515 */
2516 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
2517 if (!blast_data_to_storage_daemon(jcr, NULL)) {
2518 jcr->setJobStatus(JS_ErrorTerminated);
2519 sd->suppress_error_messages(true);
2520 Dmsg0(110, "Error in blast_data.\n");
2521 } else {
2522 jcr->setJobStatus(JS_Terminated);
2523 /* Note, the above set status will not override an error */
2524 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
2525 sd->suppress_error_messages(true);
2526 goto cleanup; /* bail out now */
2527 }
2528 /**
2529 * Expect to get response to append_data from Storage daemon
2530 */
2531 if (!response(jcr, sd, OK_append, "Append Data")) {
2532 jcr->setJobStatus(JS_ErrorTerminated);
2533 goto cleanup;
2534 }
2535
2536 /**
2537 * Send Append End Data to Storage daemon
2538 */
2539 sd->fsend(append_end, jcr->Ticket);
2540 /* Get end OK */
2541 if (!response(jcr, sd, OK_end, "Append End")) {
2542 jcr->setJobStatus(JS_ErrorTerminated);
2543 goto cleanup;
2544 }
2545
2546 /**
2547 * Send Append Close to Storage daemon
2548 */
2549 sd->fsend(append_close, jcr->Ticket);
2550 while (bget_msg(sd) >= 0) { /* stop on signal or error */
2551 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2552 ok = 1;
2553 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2554 }
2555 }
2556 if (!ok) {
2557 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2558 goto cleanup;
2559 }
2560 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings ||
2561 SDJobStatus == JS_Incomplete)) {
2562 Jmsg(jcr, M_FATAL, 0, _("Bad status %d %c returned from Storage Daemon.\n"),
2563 SDJobStatus, (char)SDJobStatus);
2564 }
2565 }
2566
2567 cleanup:
2568 #if defined(WIN32_VSS)
2569 if (jcr->Snapshot) {
2570 Win32ConvCleanupCache();
2571 if (jcr->pVSSClient) {
2572 jcr->pVSSClient->DestroyWriterInfo();
2573 }
2574 }
2575 #endif
2576 generate_plugin_event(jcr, bEventEndBackupJob);
2577 return 0; /* return and stop command loop */
2578 }
2579
2580 /**
2581 * Do a Verify for Director
2582 *
2583 */
verify_cmd(JCR * jcr)2584 static int verify_cmd(JCR *jcr)
2585 {
2586 BSOCK *dir = jcr->dir_bsock;
2587 BSOCK *sd = jcr->store_bsock;
2588 char level[100];
2589
2590 jcr->setJobType(JT_VERIFY);
2591 if (sscanf(dir->msg, verifycmd, level) != 1) {
2592 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2593 return 0;
2594 }
2595
2596 if (strcasecmp(level, "init") == 0) {
2597 jcr->setJobLevel(L_VERIFY_INIT);
2598 } else if (strcasecmp(level, "catalog") == 0){
2599 jcr->setJobLevel(L_VERIFY_CATALOG);
2600 } else if (strcasecmp(level, "volume") == 0){
2601 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2602 } else if (strcasecmp(level, "data") == 0){
2603 jcr->setJobLevel(L_VERIFY_DATA);
2604 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2605 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2606 } else {
2607 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2608 return 0;
2609 }
2610
2611 dir->fsend(OKverify);
2612
2613 generate_daemon_event(jcr, "JobStart");
2614 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2615 generate_plugin_event(jcr, bEventStartVerifyJob);
2616
2617 Dmsg1(110, "filed>dird: %s", dir->msg);
2618
2619 switch (jcr->getJobLevel()) {
2620 case L_VERIFY_INIT:
2621 case L_VERIFY_CATALOG:
2622 do_verify(jcr);
2623 break;
2624 case L_VERIFY_DATA:
2625 case L_VERIFY_VOLUME_TO_CATALOG:
2626 if (!open_sd_read_session(jcr)) {
2627 return 0;
2628 }
2629 start_dir_heartbeat(jcr);
2630 do_verify_volume(jcr);
2631 stop_dir_heartbeat(jcr);
2632 /*
2633 * Send Close session command to Storage daemon
2634 */
2635 sd->fsend(read_close, jcr->Ticket);
2636 Dmsg1(130, "filed>stored: %s", sd->msg);
2637
2638 /* ****FIXME**** check response */
2639 bget_msg(sd); /* get OK */
2640
2641 /* Inform Storage daemon that we are done */
2642 sd->signal(BNET_TERMINATE);
2643
2644 break;
2645 case L_VERIFY_DISK_TO_CATALOG:
2646 do_verify(jcr);
2647 break;
2648 default:
2649 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2650 return 0;
2651 }
2652
2653 dir->signal(BNET_EOD);
2654 generate_plugin_event(jcr, bEventEndVerifyJob);
2655 return 0; /* return and terminate command loop */
2656 }
2657
2658 /*
2659 * Do a Restore for Director
2660 *
2661 */
restore_cmd(JCR * jcr)2662 static int restore_cmd(JCR *jcr)
2663 {
2664 BSOCK *dir = jcr->dir_bsock;
2665 BSOCK *sd = jcr->store_bsock;
2666 POOLMEM *args=NULL, *restore_where=NULL, *restore_rwhere=NULL;
2667 bool use_regexwhere=false;
2668 int prefix_links;
2669 char replace;
2670 bool scan_ok = true;
2671 int files;
2672 int ret = 0;
2673
2674 /**
2675 * Scan WHERE (base directory for restore) from command
2676 */
2677 Dmsg0(100, "restore command\n");
2678 #if defined(WIN32_VSS)
2679
2680 /**
2681 * No need to enable VSS for restore if we do not have plugin
2682 * data to restore
2683 */
2684 jcr->Snapshot = jcr->got_metadata;
2685 #endif
2686
2687 /* Pickup where string */
2688 args = get_memory(dir->msglen+1);
2689 *args = 0;
2690
2691 restore_where = get_pool_memory(PM_FNAME);
2692 restore_rwhere = get_pool_memory(PM_FNAME);
2693
2694 /* We don't know the size of where/rwhere in advance,
2695 * where= -> where=%202s\n
2696 */
2697 Mmsg(restore_where, "%s%%%ds\n", restorefcmd, dir->msglen);
2698 Mmsg(restore_rwhere, "%s%%%ds\n", restorefcmdR, dir->msglen);
2699
2700 Dmsg2(200, "where=%srwhere=%s", restore_where, restore_rwhere);
2701
2702 /* Scan for new form with number of files to restore */
2703 if (sscanf(dir->msg, restore_where, &files, &replace, &prefix_links, args) != 4) {
2704 if (sscanf(dir->msg, restore_rwhere, &files, &replace, &prefix_links, args) != 4) {
2705 if (sscanf(dir->msg, restorefcmd1, &files, &replace, &prefix_links) != 3) {
2706 scan_ok = false;
2707 }
2708 *args = 0; /* No where argument */
2709 } else {
2710 use_regexwhere = true;
2711 }
2712 }
2713
2714 if (scan_ok) {
2715 jcr->ExpectedFiles = files;
2716 } else {
2717 /* Scan for old form without number of files */
2718 jcr->ExpectedFiles = 0;
2719
2720 /* where= -> where=%202s\n */
2721 Mmsg(restore_where, "%s%%%ds\n", restorecmd, dir->msglen);
2722 Mmsg(restore_rwhere, "%s%%%ds\n", restorecmdR, dir->msglen);
2723
2724 if (sscanf(dir->msg, restore_where, &replace, &prefix_links, args) != 3) {
2725 if (sscanf(dir->msg, restore_rwhere, &replace, &prefix_links, args) != 3){
2726 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2727 pm_strcpy(jcr->errmsg, dir->msg);
2728 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2729 goto free_mempool;
2730 }
2731 *args = 0; /* No where argument */
2732 } else {
2733 use_regexwhere = true;
2734 }
2735 }
2736 }
2737
2738 /* Turn / into nothing */
2739 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2740 args[0] = '\0';
2741 }
2742
2743 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2744 unbash_spaces(args);
2745
2746 /* Keep track of newly created directories to apply them correct attributes */
2747 if (replace == REPLACE_NEVER || replace == REPLACE_IFNEWER) {
2748 jcr->keep_path_list = true;
2749 }
2750
2751 if (use_regexwhere) {
2752 jcr->where_bregexp = get_bregexps(args);
2753 if (!jcr->where_bregexp) {
2754 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2755 goto free_mempool;
2756 }
2757 jcr->RegexWhere = bstrdup(args);
2758 } else {
2759 jcr->where = bstrdup(args);
2760 }
2761
2762 jcr->replace = replace;
2763 jcr->prefix_links = prefix_links;
2764
2765 dir->fsend(OKrestore);
2766 Dmsg1(110, "filed>dird: %s", dir->msg);
2767
2768 jcr->setJobType(JT_RESTORE);
2769
2770 jcr->setJobStatus(JS_Blocked);
2771
2772 if (!open_sd_read_session(jcr)) {
2773 jcr->setJobStatus(JS_ErrorTerminated);
2774 goto bail_out;
2775 }
2776
2777 jcr->setJobStatus(JS_Running);
2778
2779 /**
2780 * Do restore of files and data
2781 */
2782 start_dir_heartbeat(jcr);
2783 generate_daemon_event(jcr, "JobStart");
2784 generate_plugin_event(jcr, bEventStartRestoreJob);
2785
2786 #if defined(WIN32_VSS)
2787 /* START VSS ON WIN32 */
2788 if (jcr->Snapshot) {
2789 jcr->pVSSClient = VSSInit();
2790 if (!jcr->pVSSClient->InitializeForRestore(jcr)) {
2791 berrno be;
2792 Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2793 }
2794 //free_and_null_pool_memory(jcr->job_metadata);
2795 run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2796 }
2797 #endif
2798
2799 if (!jcr->is_canceled()) {
2800 do_restore(jcr);
2801 }
2802
2803 stop_dir_heartbeat(jcr);
2804
2805 jcr->setJobStatus(JS_Terminated);
2806 if (jcr->JobStatus != JS_Terminated) {
2807 sd->suppress_error_messages(true);
2808 }
2809
2810 /**
2811 * Send Close session command to Storage daemon
2812 */
2813 sd->fsend(read_close, jcr->Ticket);
2814 Dmsg1(100, "filed>stored: %s", sd->msg);
2815
2816 bget_msg(sd); /* get OK */
2817
2818 /* Inform Storage daemon that we are done */
2819 sd->signal(BNET_TERMINATE);
2820
2821 #if defined(WIN32_VSS)
2822 /* STOP VSS ON WIN32 */
2823 /* tell vss to close the restore session */
2824 Dmsg0(100, "About to call CloseRestore\n");
2825 if (jcr->Snapshot) {
2826 #if 0
2827 generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2828 #endif
2829 Dmsg0(100, "Really about to call CloseRestore\n");
2830 if (jcr->pVSSClient->CloseRestore()) {
2831 Dmsg0(100, "CloseRestore success\n");
2832 #if 0
2833 /* inform user about writer states */
2834 for (int i=0; i<(int)jcr->pVSSClient->GetWriterCount(); i++) {
2835 int msg_type = M_INFO;
2836 if (jcr->pVSSClient->GetWriterState(i) < 1) {
2837 //msg_type = M_WARNING;
2838 //jcr->JobErrors++;
2839 }
2840 Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"),
2841 jcr->pVSSClient->GetWriterInfo(i));
2842 }
2843 #endif
2844 }
2845 else {
2846 Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2847 }
2848 }
2849 #endif
2850
2851 bail_out:
2852 bfree_and_null(jcr->where);
2853 bfree_and_null(jcr->RegexWhere);
2854
2855 Dmsg0(100, "Done in job.c\n");
2856
2857 if (jcr->multi_restore) {
2858 Dmsg0(100, OKstoreend);
2859 dir->fsend(OKstoreend);
2860 ret = 1; /* we continue the loop, waiting for next part */
2861 } else {
2862 ret = 0; /* we stop here */
2863 }
2864
2865 if (job_canceled(jcr)) {
2866 ret = 0; /* we stop here */
2867 }
2868
2869 if (ret == 0) {
2870 end_restore_cmd(jcr); /* stopping so send bEventEndRestoreJob */
2871 }
2872
2873 free_mempool:
2874 free_and_null_pool_memory(args);
2875 free_and_null_pool_memory(restore_where);
2876 free_and_null_pool_memory(restore_rwhere);
2877
2878 return ret;
2879 }
2880
end_restore_cmd(JCR * jcr)2881 static int end_restore_cmd(JCR *jcr)
2882 {
2883 Dmsg0(5, "end_restore_cmd\n");
2884 if (jcr->JobErrors) {
2885 jcr->setJobStatus(JS_ErrorTerminated);
2886 }
2887 generate_plugin_event(jcr, bEventEndRestoreJob);
2888 return 0; /* return and terminate command loop */
2889 }
2890
open_sd_read_session(JCR * jcr)2891 static int open_sd_read_session(JCR *jcr)
2892 {
2893 BSOCK *sd = jcr->store_bsock;
2894
2895 if (!sd) {
2896 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2897 return 0;
2898 }
2899 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2900 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2901 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2902 /*
2903 * Open Read Session with Storage daemon
2904 */
2905 sd->fsend(read_open, "DummyVolume",
2906 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2907 jcr->StartBlock, jcr->EndBlock);
2908 Dmsg1(110, ">stored: %s", sd->msg);
2909
2910 /*
2911 * Get ticket number
2912 */
2913 if (bget_msg(sd) >= 0) {
2914 Dmsg1(110, "filed<stored: %s", sd->msg);
2915 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2916 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2917 return 0;
2918 }
2919 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2920 } else {
2921 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2922 return 0;
2923 }
2924
2925 /*
2926 * Use interactive session for the current restore
2927 */
2928 if (jcr->interactive_session) {
2929 sd->fsend(read_ctrl, jcr->Ticket);
2930 Dmsg1(110, ">stored: %s", sd->msg);
2931 }
2932
2933 /*
2934 * Start read of data with Storage daemon
2935 */
2936 sd->fsend(read_data, jcr->Ticket);
2937 Dmsg1(110, ">stored: %s", sd->msg);
2938
2939 /*
2940 * Get OK data
2941 */
2942 if (!response(jcr, sd, OK_data, "Read Data")) {
2943 return 0;
2944 }
2945 return 1;
2946 }
2947
2948 /**
2949 * Destroy the Job Control Record and associated
2950 * resources (sockets).
2951 */
filed_free_jcr(JCR * jcr)2952 void filed_free_jcr(JCR *jcr)
2953 {
2954 if (jcr->dir_bsock) {
2955 free_bsock(jcr->dir_bsock);
2956 jcr->dir_bsock = NULL;
2957 }
2958 if (jcr->sd_calls_client_bsock) {
2959 free_bsock(jcr->sd_calls_client_bsock);
2960 jcr->sd_calls_client_bsock = NULL;
2961 }
2962 if (jcr->store_bsock) {
2963 free_bsock(jcr->store_bsock);
2964 jcr->store_bsock = NULL;
2965 }
2966 if (jcr->last_fname) {
2967 free_pool_memory(jcr->last_fname);
2968 }
2969 #ifdef WIN32_VSS
2970 VSSCleanup(jcr->pVSSClient);
2971 #endif
2972 free_plugins(jcr); /* release instantiated plugins */
2973 free_runscripts(jcr->RunScripts);
2974 delete jcr->RunScripts;
2975 free_path_list(jcr);
2976
2977 if (jcr->JobId != 0) {
2978 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2979 }
2980 return;
2981 }
2982
2983 /**
2984 * Get response from Storage daemon to a command we
2985 * sent. Check that the response is OK.
2986 *
2987 * Returns: 0 on failure
2988 * 1 on success
2989 */
response(JCR * jcr,BSOCK * sd,char * resp,const char * cmd)2990 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2991 {
2992 int ret;
2993
2994 if (sd->errors) {
2995 return 0;
2996 }
2997 if ((ret = bget_msg(sd)) > 0) {
2998 Dmsg0(110, sd->msg);
2999 if (strcmp(sd->msg, resp) == 0) {
3000 return 1;
3001 }
3002 }
3003 if (job_canceled(jcr)) {
3004 return 0; /* if canceled avoid useless error messages */
3005 }
3006 if (sd->is_error()) {
3007 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
3008 cmd, sd->bstrerror());
3009 } else {
3010 char buf[256];
3011 if (ret > 0) {
3012 Jmsg4(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got len=%ld msg=\"%s\"\n"),
3013 cmd, resp, sd->msglen, smartdump(sd->msg, sd->msglen, buf, sizeof(buf)));
3014 } else {
3015 Jmsg3(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got SIGNAL %s\n"),
3016 cmd, resp, bnet_sig_to_ascii(ret));
3017 }
3018 }
3019 return 0;
3020 }
3021