2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 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 Bacula® is a registered trademark of Kern Sibbald.
17 * Bacula File Daemon Job processing
19 * Written by Kern Sibbald, October MM
28 bool win32decomp = false;
29 bool no_win32_write_errors = false;
30 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
33 * As Windows saves ACLs as part of the standard backup stream
34 * we just pretend here that is has implicit acl support.
36 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
37 const bool have_acl = true;
39 const bool have_acl = false;
42 #if defined(HAVE_XATTR)
43 const bool have_xattr = true;
45 const bool have_xattr = false;
48 extern CLIENT *me; /* our client resource */
50 /* Imported functions */
51 extern int status_cmd(JCR *jcr);
52 extern int qstatus_cmd(JCR *jcr);
53 extern int accurate_cmd(JCR *jcr);
55 /* Forward referenced functions */
56 static int backup_cmd(JCR *jcr);
57 static int cancel_cmd(JCR *jcr);
58 static int setdebug_cmd(JCR *jcr);
59 static int setbandwidth_cmd(JCR *jcr);
60 static int estimate_cmd(JCR *jcr);
61 static int hello_cmd(JCR *jcr);
62 static int job_cmd(JCR *jcr);
63 static int fileset_cmd(JCR *jcr);
64 static int level_cmd(JCR *jcr);
65 static int verify_cmd(JCR *jcr);
66 static int restore_cmd(JCR *jcr);
67 static int end_restore_cmd(JCR *jcr);
68 static int storage_cmd(JCR *jcr);
69 static int session_cmd(JCR *jcr);
70 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
71 static void filed_free_jcr(JCR *jcr);
72 static int open_sd_read_session(JCR *jcr);
73 static int runscript_cmd(JCR *jcr);
74 static int runbefore_cmd(JCR *jcr);
75 static int runafter_cmd(JCR *jcr);
76 static int runbeforenow_cmd(JCR *jcr);
77 static int restore_object_cmd(JCR *jcr);
78 static int set_options(findFOPTS *fo, const char *opts);
79 static void set_storage_auth_key(JCR *jcr, char *key);
80 static int sm_dump_cmd(JCR *jcr);
82 static int exit_cmd(JCR *jcr);
85 /* Exported functions */
89 * The following are the recognized commands from the Director.
91 struct s_cmds cmds[] = {
92 {"backup", backup_cmd, 0},
93 {"cancel", cancel_cmd, 0},
94 {"setdebug=", setdebug_cmd, 0},
95 {"setbandwidth=",setbandwidth_cmd, 0},
96 {"estimate", estimate_cmd, 0},
97 {"Hello", hello_cmd, 1},
98 {"fileset", fileset_cmd, 0},
99 {"JobId=", job_cmd, 0},
100 {"level = ", level_cmd, 0},
101 {"restore ", restore_cmd, 0},
102 {"endrestore", end_restore_cmd, 0},
103 {"session", session_cmd, 0},
104 {"status", status_cmd, 1},
105 {".status", qstatus_cmd, 1},
106 {"storage ", storage_cmd, 0},
107 {"verify", verify_cmd, 0},
108 {"RunBeforeNow", runbeforenow_cmd, 0},
109 {"RunBeforeJob", runbefore_cmd, 0},
110 {"RunAfterJob", runafter_cmd, 0},
111 {"Run", runscript_cmd, 0},
112 {"accurate", accurate_cmd, 0},
113 {"restoreobject", restore_object_cmd, 0},
114 {"sm_dump", sm_dump_cmd, 0},
116 {"exit", exit_cmd, 0},
118 {NULL, NULL} /* list terminator */
121 /* Commands received from director that need scanning */
122 static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
123 static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
124 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
125 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
127 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
128 static char restorefcmd1[] = "restore files=%d replace=%c prelinks=%d where=\n";
130 /* The following restore commands may have a big where=/regexwhere= parameter
131 * the bsscanf is limiting the default %s to 1000c. To allow more than 1000 bytes,
132 * we can specify %xxxxs where xxxx is the size expected in bytes.
134 * So, the code will add %s\n to the end of the following restore commands
136 static char restorecmd[] = "restore replace=%c prelinks=%d where=";
137 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=";
138 static char restorefcmd[] = "restore files=%d replace=%c prelinks=%d where=";
139 static char restorefcmdR[] = "restore files=%d replace=%c prelinks=%d regexwhere=";
141 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
142 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
143 static char endrestoreobjectcmd[] = "restoreobject end\n";
144 static char verifycmd[] = "verify level=%30s";
145 static char estimatecmd[] = "estimate listing=%d";
146 static char runbefore[] = "RunBeforeJob %s";
147 static char runafter[] = "RunAfterJob %s";
148 static char runscript[] = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
149 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
151 /* Responses sent to Director */
152 static char errmsg[] = "2999 Invalid command\n";
153 static char no_auth[] = "2998 No Authorization\n";
154 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
155 static char OKBandwidth[] = "2000 OK Bandwidth\n";
156 static char OKinc[] = "2000 OK include\n";
157 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
158 static char OKlevel[] = "2000 OK level\n";
159 static char OKbackup[] = "2000 OK backup\n";
160 static char OKverify[] = "2000 OK verify\n";
161 static char OKrestore[] = "2000 OK restore\n";
162 static char OKsession[] = "2000 OK session\n";
163 static char OKstore[] = "2000 OK storage\n";
164 static char OKstoreend[] = "2000 OK storage end\n";
165 static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
166 static char OKsetdebug[] = "2000 OK setdebug=%ld trace=%ld hangup=%ld options=%s tags=%s\n";
167 static char BADjob[] = "2901 Bad Job\n";
168 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%d ReadBytes=%lld"
169 " JobBytes=%lld Errors=%d VSS=%d Encrypt=%d\n";
170 static char OKRunBefore[] = "2000 OK RunBefore\n";
171 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
172 static char OKRunAfter[] = "2000 OK RunAfter\n";
173 static char OKRunScript[] = "2000 OK RunScript\n";
174 static char BADcmd[] = "2902 Bad %s\n";
175 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
178 /* Responses received from Storage Daemon */
179 static char OK_end[] = "3000 OK end\n";
180 static char OK_close[] = "3000 OK close Status = %d\n";
181 static char OK_open[] = "3000 OK open ticket = %d\n";
182 static char OK_data[] = "3000 OK data\n";
183 static char OK_append[] = "3000 OK append data\n";
186 /* Commands sent to Storage Daemon */
187 static char append_open[] = "append open session\n";
188 static char append_data[] = "append data %d\n";
189 static char append_end[] = "append end session %d\n";
190 static char append_close[] = "append close session %d\n";
191 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
192 static char read_data[] = "read data %d\n";
193 static char read_close[] = "read close session %d\n";
196 * Accept requests from a Director
198 * NOTE! We are running as a separate thread
200 * Send output one line
201 * at a time followed by a zero length transmission.
203 * Return when the connection is terminated or there
206 * Basic task here is:
207 * Authenticate Director (during Hello command).
208 * Accept commands one at a time from the Director
211 * Concerning ClientRunBefore/After, the sequence of events
212 * is rather critical. If they are not done in the right
213 * order one can easily get FD->SD timeouts if the script
216 * The current sequence of events is:
217 * 1. Dir starts job with FD
218 * 2. Dir connects to SD
219 * 3. Dir connects to FD
220 * 4. FD connects to SD
221 * 5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
222 * 6. Dir sends include/exclude
223 * 7. FD sends data to SD
224 * 8. SD/FD disconnects while SD despools data and attributes (optional)
225 * 9. FD runs ClientRunAfterJob
228 static void *handle_director_request(BSOCK *dir)
234 const char jobname[12] = "*Director*";
236 jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
237 jcr->sd_calls_client = false;
238 jcr->dir_bsock = dir;
239 jcr->ff = init_find_files();
240 jcr->start_time = time(NULL);
241 jcr->RunScripts = New(alist(10, not_owned_by_alist));
242 jcr->last_fname = get_pool_memory(PM_FNAME);
243 jcr->last_fname[0] = 0;
244 jcr->client_name = get_memory(strlen(my_name) + 1);
245 pm_strcpy(jcr->client_name, my_name);
246 bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
247 jcr->crypto.pki_sign = me->pki_sign;
248 jcr->crypto.pki_encrypt = me->pki_encrypt;
249 jcr->crypto.pki_keypair = me->pki_keypair;
250 jcr->crypto.pki_signers = me->pki_signers;
251 jcr->crypto.pki_recipients = me->pki_recipients;
253 /* Initialize SD start condition variable */
254 int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
257 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
261 enable_backup_privileges(NULL, 1 /* ignore_errors */);
263 for (quit=false; !quit;) {
264 if (!first) { /* first call the read is done */
266 if (dir->recv() < 0) {
267 break; /* connection terminated */
270 if (dir->msglen == 0) { /* Bad connection */
274 dir->msg[dir->msglen] = 0;
275 Dmsg1(100, "<dird: %s", dir->msg);
277 for (i=0; cmds[i].cmd; i++) {
278 if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
279 found = true; /* indicate command found */
280 if (!jcr->authenticated && cmds[i].func != hello_cmd) {
282 dir->signal(BNET_EOD);
285 if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) {
286 Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
287 dir->fsend(invalid_cmd);
288 dir->signal(BNET_EOD);
291 if ((me->disabled_cmds_array && me->disabled_cmds_array[i]) ||
292 (jcr->director && jcr->director->disabled_cmds_array &&
293 jcr->director->disabled_cmds_array[i])) {
294 Jmsg(jcr, M_FATAL, 0, _("Command: \"%s\" is disabled.\n"), cmds[i].cmd);
298 Dmsg1(100, "Executing Dir %s command.\n", dir->msg);
299 if (!cmds[i].func(jcr)) { /* do command */
300 quit = true; /* error or fully terminated, get out */
301 Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
306 if (!found) { /* command not found */
313 /* Inform Storage daemon that we are done */
314 if (jcr->store_bsock) {
315 jcr->store_bsock->signal(BNET_TERMINATE);
318 /* Run the after job */
319 run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
321 if (jcr->JobId) { /* send EndJob if running a job */
322 uint32_t vss, encrypt;
323 encrypt = jcr->crypto.pki_encrypt;
325 dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
326 jcr->ReadBytes, jcr->JobBytes, jcr->JobErrors, vss,
328 //Dmsg0(0/*110*/, dir->msg);
331 generate_daemon_event(jcr, "JobEnd");
332 generate_plugin_event(jcr, bEventJobEnd);
335 dequeue_messages(jcr); /* send any queued messages */
337 /* Inform Director that we are done */
338 dir->signal(BNET_TERMINATE);
340 free_plugins(jcr); /* release instantiated plugins */
341 free_and_null_pool_memory(jcr->job_metadata);
343 /* Clean up fileset */
344 FF_PKT *ff = jcr->ff;
345 findFILESET *fileset = ff->fileset;
348 /* Delete FileSet Include lists */
349 for (i=0; i<fileset->include_list.size(); i++) {
350 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
351 for (j=0; j<incexe->opts_list.size(); j++) {
352 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
356 for (k=0; k<fo->regex.size(); k++) {
357 regfree((regex_t *)fo->regex.get(k));
359 for (k=0; k<fo->regexdir.size(); k++) {
360 regfree((regex_t *)fo->regexdir.get(k));
362 for (k=0; k<fo->regexfile.size(); k++) {
363 regfree((regex_t *)fo->regexfile.get(k));
366 fo->regexdir.destroy();
367 fo->regexfile.destroy();
369 fo->wilddir.destroy();
370 fo->wildfile.destroy();
371 fo->wildbase.destroy();
373 fo->fstype.destroy();
374 fo->drivetype.destroy();
376 incexe->opts_list.destroy();
377 incexe->name_list.destroy();
378 incexe->plugin_list.destroy();
379 if (incexe->ignoredir) {
380 free(incexe->ignoredir);
383 fileset->include_list.destroy();
385 /* Delete FileSet Exclude lists */
386 for (i=0; i<fileset->exclude_list.size(); i++) {
387 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
388 for (j=0; j<incexe->opts_list.size(); j++) {
389 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
391 fo->regexdir.destroy();
392 fo->regexfile.destroy();
394 fo->wilddir.destroy();
395 fo->wildfile.destroy();
396 fo->wildbase.destroy();
398 fo->fstype.destroy();
399 fo->drivetype.destroy();
401 incexe->opts_list.destroy();
402 incexe->name_list.destroy();
403 incexe->plugin_list.destroy();
404 if (incexe->ignoredir) {
405 free(incexe->ignoredir);
408 fileset->exclude_list.destroy();
412 Dmsg0(100, "Calling term_find_files\n");
413 term_find_files(jcr->ff);
415 Dmsg0(100, "Done with term_find_files\n");
416 pthread_cond_destroy(&jcr->job_start_wait);
417 free_jcr(jcr); /* destroy JCR record */
418 Dmsg0(100, "Done with free_jcr\n");
420 garbage_collect_memory_pool();
425 * Note, we handle the initial connection request here.
426 * We only get the jobname and the SD version, then we
427 * return, authentication will be done when the Director
428 * sends the storage command -- as is usually the case.
429 * This should be called only once by the SD.
431 static void *handle_storage_request(BSOCK *sd)
438 if (sscanf(sd->msg, "Hello FD: Bacula Storage calling Start Job %127s %d\n",
439 job_name, &sd_version) != 2) {
440 Jmsg(NULL, M_FATAL, 0, _("SD connect failed: Bad Hello command\n"));
443 Dmsg1(110, "Got a SD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf),
444 (utime_t)time(NULL)));
445 Dmsg1(50, "%s", sd->msg);
447 if (!(jcr=get_jcr_by_full_name(job_name))) {
448 Jmsg1(NULL, M_FATAL, 0, _("SD connect failed: Job name not found: %s\n"), job_name);
449 Dmsg1(3, "**** Job \"%s\" not found.\n", job_name);
454 Dmsg1(150, "Found Job %s\n", job_name);
456 jcr->store_bsock = sd;
457 jcr->store_bsock->set_jcr(jcr);
459 if (!jcr->max_bandwidth) {
460 if (jcr->director->max_bandwidth_per_job) {
461 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
463 } else if (me->max_bandwidth_per_job) {
464 jcr->max_bandwidth = me->max_bandwidth_per_job;
467 sd->set_bwlimit(jcr->max_bandwidth);
468 pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
474 * Accept requests from a Director or a Storage daemon
476 void *handle_connection_request(void *caller)
478 BSOCK *bs = (BSOCK *)caller;
480 if (bs->recv() > 0) {
481 if (strncmp(bs->msg, "Ping", 4) == 0) {
482 bs->fsend("2000 Ping OK\n");
486 if (bs->msglen < 25 || bs->msglen > 500) {
489 Dmsg1(100, "Got: %s", bs->msg);
490 if (strncmp(bs->msg, "Hello Director", 14) == 0) {
491 return handle_director_request(bs);
493 if (strncmp(bs->msg, "Hello FD: Bacula Storage", 20) ==0) {
494 return handle_storage_request(bs);
498 Dmsg2(100, "Bad command from %s. Len=%d.\n", bs->who(), bs->msglen);
500 char *who = bs->get_peer(addr, sizeof(addr)) ? bs->who() : addr;
501 Jmsg2(NULL, M_FATAL, 0, _("Bad command from %s. Len=%d.\n"), who, bs->msglen);
506 static int sm_dump_cmd(JCR *jcr)
509 sm_dump(false, true);
510 jcr->dir_bsock->fsend("2000 sm_dump OK\n");
515 static int exit_cmd(JCR *jcr)
517 jcr->dir_bsock->fsend("2000 exit OK\n");
525 * Hello from Director he must identify himself and provide his
528 static int hello_cmd(JCR *jcr)
530 Dmsg0(120, "Calling Authenticate\n");
531 if (!authenticate_director(jcr)) {
534 Dmsg0(120, "OK Authenticate\n");
535 jcr->authenticated = true;
543 static int cancel_cmd(JCR *jcr)
545 BSOCK *dir = jcr->dir_bsock;
546 char Job[MAX_NAME_LENGTH];
551 if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
552 status = JS_Canceled;
555 dir->fsend(_("2902 Error scanning cancel command.\n"));
558 if (!(cjcr=get_jcr_by_full_name(Job))) {
559 dir->fsend(_("2901 Job %s not found.\n"), Job);
561 generate_plugin_event(cjcr, bEventCancelCommand, NULL);
562 cjcr->setJobStatus(status);
563 if (cjcr->store_bsock) {
564 cjcr->store_bsock->set_timed_out();
565 cjcr->store_bsock->set_terminated();
566 cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
569 dir->fsend(_("2001 Job \"%s\" marked to be %s.\n"),
574 dir->signal(BNET_EOD);
579 * Set bandwidth limit as requested by the Director
582 static int setbandwidth_cmd(JCR *jcr)
584 BSOCK *dir = jcr->dir_bsock;
587 char Job[MAX_NAME_LENGTH];
590 if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
591 pm_strcpy(jcr->errmsg, dir->msg);
592 dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
597 if(!(cjcr=get_jcr_by_full_name(Job))) {
598 dir->fsend(_("2901 Job %s not found.\n"), Job);
600 cjcr->max_bandwidth = bw;
601 if (cjcr->store_bsock) {
602 cjcr->store_bsock->set_bwlimit(bw);
607 } else { /* No job requested, apply globally */
608 me->max_bandwidth_per_job = bw; /* Overwrite directive */
610 cjcr->max_bandwidth = bw;
611 if (cjcr->store_bsock) {
612 cjcr->store_bsock->set_bwlimit(bw);
618 return dir->fsend(OKBandwidth);
622 * Set debug level as requested by the Director
625 static int setdebug_cmd(JCR *jcr)
627 BSOCK *dir = jcr->dir_bsock;
628 int32_t trace, hangup, lvl;
634 Dmsg1(50, "setdebug_cmd: %s", dir->msg);
635 tags[0] = options[0] = 0;
636 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld options=%55s tags=%511s",
637 &lvl, &trace, &hangup, options, tags);
639 scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld",
640 &lvl, &trace, &hangup);
642 Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
643 if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace) != 2) {
644 pm_strcpy(jcr->errmsg, dir->msg);
645 dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
655 if (!debug_parse_tags(tags, &level)) {
662 /* handle other options */
663 set_debug_flags(options);
665 Dmsg5(150, "level=%ld trace=%ld hangup=%ld options=%s tags=%s\n",
666 lvl, get_trace(), get_hangup(), options, tags);
667 return dir->fsend(OKsetdebug, lvl, get_trace(), get_hangup(), options, tags);
671 static int estimate_cmd(JCR *jcr)
673 BSOCK *dir = jcr->dir_bsock;
674 char ed1[50], ed2[50];
676 if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
677 pm_strcpy(jcr->errmsg, dir->msg);
678 Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
679 dir->fsend(_("2992 Bad estimate command.\n"));
683 dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
684 edit_uint64_with_commas(jcr->JobBytes, ed2));
685 dir->signal(BNET_EOD);
690 * Get JobId and Storage Daemon Authorization key from Director
692 static int job_cmd(JCR *jcr)
694 BSOCK *dir = jcr->dir_bsock;
695 POOL_MEM sd_auth_key(PM_MESSAGE);
696 sd_auth_key.check_size(dir->msglen);
698 if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
699 &jcr->VolSessionId, &jcr->VolSessionTime,
700 sd_auth_key.c_str()) != 5) {
701 pm_strcpy(jcr->errmsg, dir->msg);
702 Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
706 set_storage_auth_key(jcr, sd_auth_key.c_str());
707 Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
708 Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
709 new_plugins(jcr); /* instantiate plugins for this jcr */
710 generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
711 return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
714 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param)
719 return jcr->director->hdr.name;
727 static int runbefore_cmd(JCR *jcr)
730 BSOCK *dir = jcr->dir_bsock;
731 POOLMEM *cmd = get_memory(dir->msglen+1);
734 Dmsg1(100, "runbefore_cmd: %s", dir->msg);
735 if (sscanf(dir->msg, runbefore, cmd) != 1) {
736 pm_strcpy(jcr->errmsg, dir->msg);
737 Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
738 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
744 /* Run the command now */
745 script = new_runscript();
746 script->set_job_code_callback(job_code_callback_filed);
747 script->set_command(cmd);
748 script->when = SCRIPT_Before;
749 ok = script->run(jcr, "ClientRunBeforeJob");
750 free_runscript(script);
754 dir->fsend(OKRunBefore);
757 dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
762 static int runbeforenow_cmd(JCR *jcr)
764 BSOCK *dir = jcr->dir_bsock;
766 run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
767 if (job_canceled(jcr)) {
768 dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
769 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
772 dir->fsend(OKRunBeforeNow);
773 Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
778 static int runafter_cmd(JCR *jcr)
780 BSOCK *dir = jcr->dir_bsock;
781 POOLMEM *msg = get_memory(dir->msglen+1);
784 Dmsg1(100, "runafter_cmd: %s", dir->msg);
785 if (sscanf(dir->msg, runafter, msg) != 1) {
786 pm_strcpy(jcr->errmsg, dir->msg);
787 Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
788 dir->fsend(_("2905 Bad RunAfterJob command.\n"));
794 cmd = new_runscript();
795 cmd->set_job_code_callback(job_code_callback_filed);
796 cmd->set_command(msg);
797 cmd->on_success = true;
798 cmd->on_failure = false;
799 cmd->when = SCRIPT_After;
801 jcr->RunScripts->append(cmd);
803 free_pool_memory(msg);
804 return dir->fsend(OKRunAfter);
807 static int runscript_cmd(JCR *jcr)
809 BSOCK *dir = jcr->dir_bsock;
810 POOLMEM *msg = get_memory(dir->msglen+1);
811 int on_success, on_failure, fail_on_error;
813 RUNSCRIPT *cmd = new_runscript() ;
814 cmd->set_job_code_callback(job_code_callback_filed);
816 Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
817 /* Note, we cannot sscanf into bools */
818 if (sscanf(dir->msg, runscript, &on_success,
823 pm_strcpy(jcr->errmsg, dir->msg);
824 Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
825 dir->fsend(_("2905 Bad RunScript command.\n"));
830 cmd->on_success = on_success;
831 cmd->on_failure = on_failure;
832 cmd->fail_on_error = fail_on_error;
835 cmd->set_command(msg);
837 jcr->RunScripts->append(cmd);
839 free_pool_memory(msg);
840 return dir->fsend(OKRunScript);
844 * This reads data sent from the Director from the
845 * RestoreObject table that allows us to get objects
846 * that were backed up (VSS .xml data) and are needed
847 * before starting the restore.
849 static int restore_object_cmd(JCR *jcr)
851 BSOCK *dir = jcr->dir_bsock;
853 restore_object_pkt rop;
855 memset(&rop, 0, sizeof(rop));
856 rop.pkt_size = sizeof(rop);
857 rop.pkt_end = sizeof(rop);
859 Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
860 if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
861 Dmsg0(20, "Got endrestoreobject\n");
862 generate_plugin_event(jcr, bEventRestoreObject, NULL);
863 return dir->fsend(OKRestoreObject);
866 rop.plugin_name = (char *)malloc(dir->msglen);
867 *rop.plugin_name = 0;
869 if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
870 &rop.object_full_len, &rop.object_index,
871 &rop.object_type, &rop.object_compression, &FileIndex,
872 rop.plugin_name) != 8) {
874 /* Old version, no plugin_name */
875 if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
876 &rop.object_full_len, &rop.object_index,
877 &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
878 Dmsg0(5, "Bad restore object command\n");
879 pm_strcpy(jcr->errmsg, dir->msg);
880 Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
885 unbash_spaces(rop.plugin_name);
887 Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
888 "FI=%d plugin_name=%s\n",
889 rop.JobId, rop.object_len, rop.object_full_len,
890 rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
891 /* Read Object name */
892 if (dir->recv() < 0) {
895 Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
896 rop.object_name = bstrdup(dir->msg);
899 if (dir->recv() < 0) {
902 /* Transfer object from message buffer, and get new message buffer */
903 rop.object = dir->msg;
904 dir->msg = get_pool_memory(PM_MESSAGE);
906 /* If object is compressed, uncompress it */
907 if (rop.object_compression == 1) { /* zlib level 9 */
909 int out_len = rop.object_full_len + 100;
910 POOLMEM *obj = get_memory(out_len);
911 Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
912 stat = Zinflate(rop.object, rop.object_len, obj, out_len);
913 Dmsg1(100, "Zinflate stat=%d\n", stat);
914 if (out_len != rop.object_full_len) {
915 Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
916 rop.object_full_len, out_len, rop.object_name);
918 free_pool_memory(rop.object); /* release compressed object */
919 rop.object = obj; /* new uncompressed object */
920 rop.object_len = out_len;
922 Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
923 /* we still need to do this to detect a vss restore */
924 if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
925 Dmsg0(100, "got job metadata\n");
926 jcr->got_metadata = true;
929 generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
931 if (rop.object_name) {
932 free(rop.object_name);
935 free_pool_memory(rop.object);
937 if (rop.plugin_name) {
938 free(rop.plugin_name);
941 Dmsg1(100, "Send: %s", OKRestoreObject);
945 dir->fsend(_("2909 Bad RestoreObject command.\n"));
951 static bool init_fileset(JCR *jcr)
954 findFILESET *fileset;
963 fileset = (findFILESET *)malloc(sizeof(findFILESET));
964 memset(fileset, 0, sizeof(findFILESET));
965 ff->fileset = fileset;
966 fileset->state = state_none;
967 fileset->include_list.init(1, true);
968 fileset->exclude_list.init(1, true);
972 static void append_file(JCR *jcr, findINCEXE *incexe,
973 const char *buf, bool is_file)
976 incexe->name_list.append(new_dlistString(buf));
978 } else if (me->plugin_directory) {
979 generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
980 incexe->plugin_list.append(new_dlistString(buf));
983 Jmsg(jcr, M_FATAL, 0,
984 _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
990 * Add fname to include/exclude fileset list. First check for
991 * | and < and if necessary perform command.
993 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
995 findFILESET *fileset = jcr->ff->fileset;
1008 p++; /* skip over | */
1009 fn = get_pool_memory(PM_FNAME);
1010 fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
1011 bpipe = open_bpipe(fn, 0, "r");
1014 Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
1016 free_pool_memory(fn);
1019 free_pool_memory(fn);
1020 while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1021 strip_trailing_junk(buf);
1022 append_file(jcr, fileset->incexe, buf, is_file);
1024 if ((stat=close_bpipe(bpipe)) != 0) {
1026 Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
1027 p, be.code(stat), be.bstrerror(stat));
1032 Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
1033 p++; /* skip over < */
1034 if ((ffd = fopen(p, "rb")) == NULL) {
1036 Jmsg(jcr, M_FATAL, 0,
1037 _("Cannot open FileSet input file: %s. ERR=%s\n"),
1041 while (fgets(buf, sizeof(buf), ffd)) {
1042 strip_trailing_junk(buf);
1043 append_file(jcr, fileset->incexe, buf, is_file);
1048 append_file(jcr, fileset->incexe, fname, is_file);
1053 findINCEXE *get_incexe(JCR *jcr)
1055 if (jcr->ff && jcr->ff->fileset) {
1056 return jcr->ff->fileset->incexe;
1061 void set_incexe(JCR *jcr, findINCEXE *incexe)
1063 findFILESET *fileset = jcr->ff->fileset;
1064 fileset->incexe = incexe;
1069 * Define a new Exclude block in the FileSet
1071 findINCEXE *new_exclude(JCR *jcr)
1073 findFILESET *fileset = jcr->ff->fileset;
1076 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1077 memset(fileset->incexe, 0, sizeof(findINCEXE));
1078 fileset->incexe->opts_list.init(1, true);
1079 fileset->incexe->name_list.init();
1080 fileset->incexe->plugin_list.init();
1081 fileset->exclude_list.append(fileset->incexe);
1082 return fileset->incexe;
1086 * Define a new Include block in the FileSet
1088 findINCEXE *new_include(JCR *jcr)
1090 findFILESET *fileset = jcr->ff->fileset;
1093 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1094 memset(fileset->incexe, 0, sizeof(findINCEXE));
1095 fileset->incexe->opts_list.init(1, true);
1096 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1097 fileset->incexe->plugin_list.init();
1098 fileset->include_list.append(fileset->incexe);
1099 return fileset->incexe;
1103 * Define a new preInclude block in the FileSet
1104 * That is the include is prepended to the other
1105 * Includes. This is used for plugin exclusions.
1107 findINCEXE *new_preinclude(JCR *jcr)
1109 findFILESET *fileset = jcr->ff->fileset;
1111 /* New pre-include */
1112 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
1113 memset(fileset->incexe, 0, sizeof(findINCEXE));
1114 fileset->incexe->opts_list.init(1, true);
1115 fileset->incexe->name_list.init(); /* for dlist; was 1,true for alist */
1116 fileset->incexe->plugin_list.init();
1117 fileset->include_list.prepend(fileset->incexe);
1118 return fileset->incexe;
1121 static findFOPTS *start_options(FF_PKT *ff)
1123 int state = ff->fileset->state;
1124 findINCEXE *incexe = ff->fileset->incexe;
1126 if (state != state_options) {
1127 ff->fileset->state = state_options;
1128 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1129 memset(fo, 0, sizeof(findFOPTS));
1130 fo->regex.init(1, true);
1131 fo->regexdir.init(1, true);
1132 fo->regexfile.init(1, true);
1133 fo->wild.init(1, true);
1134 fo->wilddir.init(1, true);
1135 fo->wildfile.init(1, true);
1136 fo->wildbase.init(1, true);
1137 fo->base.init(1, true);
1138 fo->fstype.init(1, true);
1139 fo->drivetype.init(1, true);
1140 incexe->current_opts = fo;
1141 incexe->opts_list.append(fo);
1143 return incexe->current_opts;
1147 * Used by plugins to define a new options block
1149 void new_options(JCR *jcr, findINCEXE *incexe)
1152 incexe = jcr->ff->fileset->incexe;
1154 findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
1155 memset(fo, 0, sizeof(findFOPTS));
1156 fo->regex.init(1, true);
1157 fo->regexdir.init(1, true);
1158 fo->regexfile.init(1, true);
1159 fo->wild.init(1, true);
1160 fo->wilddir.init(1, true);
1161 fo->wildfile.init(1, true);
1162 fo->wildbase.init(1, true);
1163 fo->base.init(1, true);
1164 fo->fstype.init(1, true);
1165 fo->drivetype.init(1, true);
1166 incexe->current_opts = fo;
1167 incexe->opts_list.prepend(fo);
1168 jcr->ff->fileset->state = state_options;
1172 * Add a regex to the current fileset
1174 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1176 findFOPTS *current_opts = start_options(jcr->ff);
1181 preg = (regex_t *)malloc(sizeof(regex_t));
1182 if (current_opts->flags & FO_IGNORECASE) {
1183 rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1185 rc = regcomp(preg, item, REG_EXTENDED);
1188 regerror(rc, preg, prbuf, sizeof(prbuf));
1191 Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1195 current_opts->regex.append(preg);
1196 } else if (type == 'D') {
1197 current_opts->regexdir.append(preg);
1198 } else if (type == 'F') {
1199 current_opts->regexfile.append(preg);
1203 return state_options;
1207 * Add a wild card to the current fileset
1209 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1211 findFOPTS *current_opts = start_options(jcr->ff);
1214 current_opts->wild.append(bstrdup(item));
1215 } else if (type == 'D') {
1216 current_opts->wilddir.append(bstrdup(item));
1217 } else if (type == 'F') {
1218 current_opts->wildfile.append(bstrdup(item));
1219 } else if (type == 'B') {
1220 current_opts->wildbase.append(bstrdup(item));
1224 return state_options;
1229 * Add options to the current fileset
1231 int add_options_to_fileset(JCR *jcr, const char *item)
1233 findFOPTS *current_opts = start_options(jcr->ff);
1235 set_options(current_opts, item);
1236 return state_options;
1239 static void add_fileset(JCR *jcr, const char *item)
1241 FF_PKT *ff = jcr->ff;
1242 findFILESET *fileset = ff->fileset;
1243 int state = fileset->state;
1244 findFOPTS *current_opts;
1246 /* Get code, optional subcode, and position item past the dividing space */
1247 Dmsg1(100, "%s\n", item);
1252 int subcode = ' '; /* A space is always a valid subcode */
1253 if (item[0] != '\0' && item[0] != ' ') {
1261 /* Skip all lines we receive after an error */
1262 if (state == state_error) {
1263 Dmsg0(100, "State=error return\n");
1268 * The switch tests the code for validity.
1269 * The subcode is always good if it is a space, otherwise we must confirm.
1270 * We set state to state_error first assuming the subcode is invalid,
1271 * requiring state to be set in cases below that handle subcodes.
1273 if (subcode != ' ') {
1274 state = state_error;
1275 Dmsg0(100, "Set state=error or double code.\n");
1279 (void)new_include(jcr);
1282 (void)new_exclude(jcr);
1284 case 'N': /* null */
1287 case 'F': /* file = */
1288 /* File item to include or exclude list */
1289 state = state_include;
1290 add_file_to_fileset(jcr, item, true);
1292 case 'P': /* plugin */
1293 /* Plugin item to include list */
1294 state = state_include;
1295 add_file_to_fileset(jcr, item, false);
1297 case 'R': /* regex */
1298 state = add_regex_to_fileset(jcr, item, subcode);
1301 current_opts = start_options(ff);
1302 current_opts->base.append(bstrdup(item));
1303 state = state_options;
1305 case 'X': /* Filetype or Drive type */
1306 current_opts = start_options(ff);
1307 state = state_options;
1308 if (subcode == ' ') {
1309 current_opts->fstype.append(bstrdup(item));
1310 } else if (subcode == 'D') {
1311 current_opts->drivetype.append(bstrdup(item));
1313 state = state_error;
1316 case 'W': /* wild cards */
1317 state = add_wild_to_fileset(jcr, item, subcode);
1319 case 'O': /* Options */
1320 state = add_options_to_fileset(jcr, item);
1322 case 'Z': /* ignore dir */
1323 state = state_include;
1324 fileset->incexe->ignoredir = bstrdup(item);
1327 current_opts = start_options(ff);
1328 // current_opts->reader = bstrdup(item); /* deprecated */
1329 state = state_options;
1332 current_opts = start_options(ff);
1333 // current_opts->writer = bstrdup(item); /* deprecated */
1334 state = state_options;
1336 case 'G': /* Plugin command for this Option block */
1337 current_opts = start_options(ff);
1338 current_opts->plugin = bstrdup(item);
1339 state = state_options;
1342 Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1343 state = state_error;
1346 ff->fileset->state = state;
1349 static bool term_fileset(JCR *jcr)
1351 FF_PKT *ff = jcr->ff;
1353 #ifdef xxx_DEBUG_CODE
1354 findFILESET *fileset = ff->fileset;
1357 for (i=0; i<fileset->include_list.size(); i++) {
1358 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1360 for (j=0; j<incexe->opts_list.size(); j++) {
1361 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1362 for (k=0; k<fo->regex.size(); k++) {
1363 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1365 for (k=0; k<fo->regexdir.size(); k++) {
1366 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1368 for (k=0; k<fo->regexfile.size(); k++) {
1369 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1371 for (k=0; k<fo->wild.size(); k++) {
1372 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1374 for (k=0; k<fo->wilddir.size(); k++) {
1375 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1377 for (k=0; k<fo->wildfile.size(); k++) {
1378 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1380 for (k=0; k<fo->wildbase.size(); k++) {
1381 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1383 for (k=0; k<fo->base.size(); k++) {
1384 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1386 for (k=0; k<fo->fstype.size(); k++) {
1387 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1389 for (k=0; k<fo->drivetype.size(); k++) {
1390 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1393 if (incexe->ignoredir) {
1394 Dmsg1(400, "Z %s\n", incexe->ignoredir);
1397 foreach_dlist(node, &incexe->name_list) {
1398 Dmsg1(400, "F %s\n", node->c_str());
1400 foreach_dlist(node, &incexe->plugin_list) {
1401 Dmsg1(400, "P %s\n", node->c_str());
1404 for (i=0; i<fileset->exclude_list.size(); i++) {
1405 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1407 for (j=0; j<incexe->opts_list.size(); j++) {
1408 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1409 for (k=0; k<fo->regex.size(); k++) {
1410 Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1412 for (k=0; k<fo->regexdir.size(); k++) {
1413 Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1415 for (k=0; k<fo->regexfile.size(); k++) {
1416 Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1418 for (k=0; k<fo->wild.size(); k++) {
1419 Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1421 for (k=0; k<fo->wilddir.size(); k++) {
1422 Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1424 for (k=0; k<fo->wildfile.size(); k++) {
1425 Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1427 for (k=0; k<fo->wildbase.size(); k++) {
1428 Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1430 for (k=0; k<fo->base.size(); k++) {
1431 Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1433 for (k=0; k<fo->fstype.size(); k++) {
1434 Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1436 for (k=0; k<fo->drivetype.size(); k++) {
1437 Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1441 foreach_dlist(node, &incexe->name_list) {
1442 Dmsg1(400, "F %s\n", node->c_str());
1444 foreach_dlist(node, &incexe->plugin_list) {
1445 Dmsg1(400, "P %s\n", node->c_str());
1449 return ff->fileset->state != state_error;
1454 * As an optimization, we should do this during
1455 * "compile" time in filed/job.c, and keep only a bit mask
1456 * and the Verify options.
1458 static int set_options(findFOPTS *fo, const char *opts)
1464 for (p=opts; *p; p++) {
1466 case 'a': /* alway replace */
1467 case '0': /* no option */
1470 fo->flags |= FO_EXCLUDE;
1473 fo->flags |= FO_MULTIFS;
1475 case 'h': /* no recursion */
1476 fo->flags |= FO_NO_RECURSION;
1478 case 'H': /* no hard link handling */
1479 fo->flags |= FO_NO_HARDLINK;
1482 fo->flags |= FO_IGNORECASE;
1485 fo->flags |= FO_MD5;
1488 fo->flags |= FO_NOREPLACE;
1490 case 'p': /* use portable data format */
1491 fo->flags |= FO_PORTABLE;
1493 case 'R': /* Resource forks and Finder Info */
1494 fo->flags |= FO_HFSPLUS;
1496 case 'r': /* read fifo */
1497 fo->flags |= FO_READFIFO;
1502 fo->flags |= FO_SHA1;
1507 fo->flags |= FO_SHA256;
1511 fo->flags |= FO_SHA512;
1517 * If 2 or 3 is seen here, SHA2 is not configured, so
1518 * eat the option, and drop back to SHA-1.
1520 if (p[1] == '2' || p[1] == '3') {
1523 fo->flags |= FO_SHA1;
1528 fo->flags |= FO_SPARSE;
1531 fo->flags |= FO_MTIMEONLY;
1534 fo->flags |= FO_KEEPATIME;
1537 fo->flags |= FO_ACL;
1539 case 'V': /* verify options */
1540 /* Copy Verify Options */
1541 for (j=0; *p && *p != ':'; p++) {
1542 fo->VerifyOpts[j] = *p;
1543 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1547 fo->VerifyOpts[j] = 0;
1549 case 'C': /* accurate options */
1550 /* Copy Accurate Options */
1551 for (j=0; *p && *p != ':'; p++) {
1552 fo->AccurateOpts[j] = *p;
1553 if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1557 fo->AccurateOpts[j] = 0;
1559 case 'J': /* Basejob options */
1560 /* Copy BaseJob Options */
1561 for (j=0; *p && *p != ':'; p++) {
1562 fo->BaseJobOpts[j] = *p;
1563 if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1567 fo->BaseJobOpts[j] = 0;
1569 case 'P': /* strip path */
1572 for (j=0; *p && *p != ':'; p++) {
1574 if (j < (int)sizeof(strip) - 1) {
1579 fo->strip_path = atoi(strip);
1580 fo->flags |= FO_STRIPPATH;
1581 Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1584 fo->flags |= FO_IF_NEWER;
1587 fo->flags |= FO_ENHANCEDWILD;
1589 case 'Z': /* compression */
1591 if (*p >= '0' && *p <= '9') {
1592 fo->flags |= FO_COMPRESS;
1593 fo->Compress_algo = COMPRESS_GZIP;
1594 fo->Compress_level = *p - '0';
1596 else if (*p == 'o') {
1597 fo->flags |= FO_COMPRESS;
1598 fo->Compress_algo = COMPRESS_LZO1X;
1599 fo->Compress_level = 1; /* not used with LZO */
1603 fo->flags |= FO_NOATIME;
1606 fo->flags |= FO_CHKCHANGES;
1609 fo->flags |= FO_HONOR_NODUMP;
1612 fo->flags |= FO_XATTR;
1615 Jmsg1(NULL, M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1619 return state_options;
1624 * Director is passing his Fileset
1626 static int fileset_cmd(JCR *jcr)
1628 POOL_MEM buf(PM_MESSAGE);
1629 BSOCK *dir = jcr->dir_bsock;
1632 if (!init_fileset(jcr)) {
1635 while (dir->recv() >= 0) {
1636 strip_trailing_junk(dir->msg);
1637 Dmsg1(500, "Fileset: %s\n", dir->msg);
1638 pm_strcpy(buf, dir->msg);
1639 add_fileset(jcr, buf.c_str());
1641 if (!term_fileset(jcr)) {
1644 rtnstat = dir->fsend(OKinc);
1645 generate_plugin_event(jcr, bEventEndFileSet);
1652 * Get backup level from Director
1654 * Note: there are odd things such as accurate_differential,
1655 * and accurate_incremental that are passed in level, thus
1656 * the calls to strstr() below.
1659 static int level_cmd(JCR *jcr)
1661 BSOCK *dir = jcr->dir_bsock;
1662 POOLMEM *level, *buf = NULL;
1665 level = get_memory(dir->msglen+1);
1666 Dmsg1(10, "level_cmd: %s", dir->msg);
1668 /* keep compatibility with older directors */
1669 if (strstr(dir->msg, "accurate")) {
1670 jcr->accurate = true;
1672 if (strstr(dir->msg, "rerunning")) {
1673 jcr->rerunning = true;
1675 if (sscanf(dir->msg, "level = %s ", level) != 1) {
1678 /* Base backup requested? */
1679 if (strcasecmp(level, "base") == 0) {
1680 jcr->setJobLevel(L_BASE);
1681 /* Full backup requested? */
1682 } else if (strcasecmp(level, "full") == 0) {
1683 jcr->setJobLevel(L_FULL);
1684 } else if (strstr(level, "differential")) {
1685 jcr->setJobLevel(L_DIFFERENTIAL);
1688 } else if (strstr(level, "incremental")) {
1689 jcr->setJobLevel(L_INCREMENTAL);
1693 * We get his UTC since time, then sync the clocks and correct it
1694 * to agree with our clock.
1696 } else if (strcasecmp(level, "since_utime") == 0) {
1697 buf = get_memory(dir->msglen+1);
1698 utime_t since_time, adj;
1699 btime_t his_time, bt_start, rt=0, bt_adj=0;
1700 if (jcr->getJobLevel() == L_NONE) {
1701 jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1703 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1704 buf, &mtime_only, jcr->PrevJob) != 3) {
1705 if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1706 buf, &mtime_only) != 2) {
1710 since_time = str_to_uint64(buf); /* this is the since time */
1711 Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1712 char ed1[50], ed2[50];
1714 * Sync clocks by polling him for the time. We take
1715 * 10 samples of his time throwing out the first two.
1717 for (int i=0; i<10; i++) {
1718 bt_start = get_current_btime();
1719 dir->signal(BNET_BTIME); /* poll for time */
1720 if (dir->recv() <= 0) { /* get response */
1723 if (sscanf(dir->msg, "btime %s", buf) != 1) {
1726 if (i < 2) { /* toss first two results */
1729 his_time = str_to_uint64(buf);
1730 rt = get_current_btime() - bt_start; /* compute round trip time */
1731 Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1732 edit_uint64(bt_start, ed2));
1733 bt_adj += bt_start - his_time - rt/2;
1734 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1737 bt_adj = bt_adj / 8; /* compute average time */
1738 Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1739 adj = btime_to_utime(bt_adj);
1740 since_time += adj; /* adjust for clock difference */
1741 /* Don't notify if time within 3 seconds */
1742 if (adj > 3 || adj < -3) {
1744 if (adj > 600 || adj < -600) {
1749 Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
1751 dir->signal(BNET_EOD);
1753 Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1754 jcr->incremental = 1; /* set incremental or decremental backup */
1755 jcr->mtime = since_time; /* set since time */
1756 generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
1758 Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1766 generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1767 return dir->fsend(OKlevel);
1770 pm_strcpy(jcr->errmsg, dir->msg);
1771 Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1780 * Get session parameters from Director -- this is for a Restore command
1781 * This is deprecated. It is now passed via the bsr.
1783 static int session_cmd(JCR *jcr)
1785 BSOCK *dir = jcr->dir_bsock;
1787 Dmsg1(100, "SessionCmd: %s", dir->msg);
1788 if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
1789 &jcr->VolSessionId, &jcr->VolSessionTime,
1790 &jcr->StartFile, &jcr->EndFile,
1791 &jcr->StartBlock, &jcr->EndBlock) != 7) {
1792 pm_strcpy(jcr->errmsg, dir->msg);
1793 Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1797 return dir->fsend(OKsession);
1800 static void set_storage_auth_key(JCR *jcr, char *key)
1802 /* if no key don't update anything */
1808 * We can be contacting multiple storage daemons.
1809 * So, make sure that any old jcr->store_bsock is cleaned up.
1811 if (jcr->store_bsock) {
1812 jcr->store_bsock->destroy();
1813 jcr->store_bsock = NULL;
1817 * We can be contacting multiple storage daemons.
1818 * So, make sure that any old jcr->sd_auth_key is cleaned up.
1820 if (jcr->sd_auth_key) {
1822 * If we already have a Authorization key, director can do multi
1825 Dmsg0(5, "set multi_restore=true\n");
1826 jcr->multi_restore = true;
1827 bfree(jcr->sd_auth_key);
1830 jcr->sd_auth_key = bstrdup(key);
1831 Dmsg1(5, "set sd auth key %s\n", jcr->sd_auth_key);
1835 * Get address of storage daemon from Director
1838 static int storage_cmd(JCR *jcr)
1840 int stored_port = 0; /* storage daemon port */
1841 int enable_ssl; /* enable ssl to sd */
1842 POOL_MEM sd_auth_key(PM_MESSAGE);
1843 BSOCK *dir = jcr->dir_bsock;
1846 Dmsg1(100, "StorageCmd: %s", dir->msg);
1847 sd_auth_key.check_size(dir->msglen);
1848 if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
1849 &enable_ssl, sd_auth_key.c_str()) == 4) {
1850 Dmsg1(100, "Set auth key %s\n", sd_auth_key.c_str());
1851 set_storage_auth_key(jcr, sd_auth_key.c_str());
1852 } else if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
1853 &stored_port, &enable_ssl) != 3) {
1854 pm_strcpy(jcr->errmsg, dir->msg);
1855 Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1856 Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
1861 /* TODO: see if we put limit on restore and backup... */
1862 if (!jcr->max_bandwidth) {
1863 if (jcr->director->max_bandwidth_per_job) {
1864 jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
1866 } else if (me->max_bandwidth_per_job) {
1867 jcr->max_bandwidth = me->max_bandwidth_per_job;
1871 if (stored_port != 0) {
1872 jcr->sd_calls_client = false; /* We are doing the connecting */
1873 Dmsg3(110, "Connect to storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
1876 /* Open command communications with Storage daemon */
1877 /* Try to connect for 1 hour at 10 second intervals */
1878 sd->set_source_address(me->FDsrc_addr);
1879 if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1880 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
1881 /* destroy() OK because sd is local */
1883 Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1884 jcr->stored_addr, stored_port);
1885 Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
1886 jcr->stored_addr, stored_port);
1890 Dmsg0(110, "Connection OK to SD.\n");
1891 jcr->store_bsock = sd;
1892 } else { /* The storage daemon called us */
1895 struct timespec timeout;
1898 jcr->sd_calls_client = true;
1900 * Wait for the Storage daemon to contact us to start the Job,
1901 * when he does, we will be released, unless the 30 minutes
1904 gettimeofday(&tv, &tz);
1905 timeout.tv_nsec = tv.tv_usec * 1000;
1906 timeout.tv_sec = tv.tv_sec + 30 * 60; /* wait 30 minutes */
1908 while (jcr->store_bsock == NULL && !jcr->is_job_canceled()) {
1909 errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
1910 if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
1913 Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
1916 Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
1918 /* We should already have a storage connection! */
1919 if (jcr->store_bsock == NULL) {
1920 Pmsg0(000, "Failed connect from Storage daemon. SD bsock=NULL.\n");
1921 Pmsg1(000, "Storagecmd: %s", dir->msg);
1922 Jmsg0(jcr, M_FATAL, 0, _("Failed connect from Storage daemon. SD bsock=NULL.\n"));
1925 if (jcr->is_job_canceled()) {
1929 jcr->store_bsock->set_bwlimit(jcr->max_bandwidth);
1931 if (!authenticate_storagedaemon(jcr)) {
1934 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
1935 Dmsg0(110, "Authenticated with SD.\n");
1937 /* Send OK to Director */
1938 return dir->fsend(OKstore);
1941 dir->fsend(BADcmd, "storage");
1949 static int backup_cmd(JCR *jcr)
1951 BSOCK *dir = jcr->dir_bsock;
1952 BSOCK *sd = jcr->store_bsock;
1957 if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1958 jcr->JobFiles = FileIndex;
1959 Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1963 * Validate some options given to the backup make sense for the compiled in
1964 * options of this filed.
1966 if (jcr->ff->flags & FO_ACL && !have_acl) {
1967 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
1970 if (jcr->ff->flags & FO_XATTR && !have_xattr) {
1971 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
1975 jcr->setJobStatus(JS_Blocked);
1976 jcr->setJobType(JT_BACKUP);
1977 Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
1980 Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
1981 dir->fsend(BADcmd, "backup");
1985 dir->fsend(OKbackup);
1986 Dmsg1(110, "filed>dird: %s", dir->msg);
1989 * Send Append Open Session to Storage daemon
1991 sd->fsend(append_open);
1992 Dmsg1(110, ">stored: %s", sd->msg);
1994 * Expect to receive back the Ticket number
1996 if (bget_msg(sd) >= 0) {
1997 Dmsg1(110, "<stored: %s", sd->msg);
1998 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
1999 Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2002 Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
2004 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2009 * Send Append data command to Storage daemon
2011 sd->fsend(append_data, jcr->Ticket);
2012 Dmsg1(110, ">stored: %s", sd->msg);
2015 * Expect to get OK data
2017 Dmsg1(110, "<stored: %s", sd->msg);
2018 if (!response(jcr, sd, OK_data, "Append Data")) {
2022 generate_daemon_event(jcr, "JobStart");
2023 generate_plugin_event(jcr, bEventStartBackupJob);
2026 * Send Files to Storage daemon
2028 Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
2029 if (!blast_data_to_storage_daemon(jcr, NULL)) {
2030 jcr->setJobStatus(JS_ErrorTerminated);
2031 sd->suppress_error_messages(true);
2032 Dmsg0(110, "Error in blast_data.\n");
2034 jcr->setJobStatus(JS_Terminated);
2035 /* Note, the above set status will not override an error */
2036 if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
2037 sd->suppress_error_messages(true);
2038 goto cleanup; /* bail out now */
2041 * Expect to get response to append_data from Storage daemon
2043 if (!response(jcr, sd, OK_append, "Append Data")) {
2044 jcr->setJobStatus(JS_ErrorTerminated);
2049 * Send Append End Data to Storage daemon
2051 sd->fsend(append_end, jcr->Ticket);
2053 if (!response(jcr, sd, OK_end, "Append End")) {
2054 jcr->setJobStatus(JS_ErrorTerminated);
2059 * Send Append Close to Storage daemon
2061 sd->fsend(append_close, jcr->Ticket);
2062 while (bget_msg(sd) >= 0) { /* stop on signal or error */
2063 if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2065 Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2069 Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2072 if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
2073 Jmsg(jcr, M_FATAL, 0, _("Bad status %d %c returned from Storage Daemon.\n"),
2074 SDJobStatus, (char)SDJobStatus);
2079 generate_plugin_event(jcr, bEventEndBackupJob);
2080 return 0; /* return and stop command loop */
2084 * Do a Verify for Director
2087 static int verify_cmd(JCR *jcr)
2089 BSOCK *dir = jcr->dir_bsock;
2090 BSOCK *sd = jcr->store_bsock;
2093 jcr->setJobType(JT_VERIFY);
2094 if (sscanf(dir->msg, verifycmd, level) != 1) {
2095 dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2099 if (strcasecmp(level, "init") == 0) {
2100 jcr->setJobLevel(L_VERIFY_INIT);
2101 } else if (strcasecmp(level, "catalog") == 0){
2102 jcr->setJobLevel(L_VERIFY_CATALOG);
2103 } else if (strcasecmp(level, "volume") == 0){
2104 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2105 } else if (strcasecmp(level, "data") == 0){
2106 jcr->setJobLevel(L_VERIFY_DATA);
2107 } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2108 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2110 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2114 dir->fsend(OKverify);
2116 generate_daemon_event(jcr, "JobStart");
2117 generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2118 generate_plugin_event(jcr, bEventStartVerifyJob);
2120 Dmsg1(110, "filed>dird: %s", dir->msg);
2122 switch (jcr->getJobLevel()) {
2124 case L_VERIFY_CATALOG:
2127 case L_VERIFY_VOLUME_TO_CATALOG:
2128 if (!open_sd_read_session(jcr)) {
2131 start_dir_heartbeat(jcr);
2132 do_verify_volume(jcr);
2133 stop_dir_heartbeat(jcr);
2135 * Send Close session command to Storage daemon
2137 sd->fsend(read_close, jcr->Ticket);
2138 Dmsg1(130, "filed>stored: %s", sd->msg);
2140 /* ****FIXME**** check response */
2141 bget_msg(sd); /* get OK */
2143 /* Inform Storage daemon that we are done */
2144 sd->signal(BNET_TERMINATE);
2147 case L_VERIFY_DISK_TO_CATALOG:
2151 dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2155 dir->signal(BNET_EOD);
2156 generate_plugin_event(jcr, bEventEndVerifyJob);
2157 return 0; /* return and terminate command loop */
2161 * Do a Restore for Director
2164 static int restore_cmd(JCR *jcr)
2166 BSOCK *dir = jcr->dir_bsock;
2167 BSOCK *sd = jcr->store_bsock;
2168 POOLMEM *args=NULL, *restore_where=NULL, *restore_rwhere=NULL;
2169 bool use_regexwhere=false;
2172 bool scan_ok = true;
2177 * Scan WHERE (base directory for restore) from command
2179 Dmsg0(100, "restore command\n");
2181 /* Pickup where string */
2182 args = get_memory(dir->msglen+1);
2185 restore_where = get_pool_memory(PM_FNAME);
2186 restore_rwhere = get_pool_memory(PM_FNAME);
2188 /* We don't know the size of where/rwhere in advance,
2189 * where= -> where=%202s\n
2191 Mmsg(restore_where, "%s%%%ds\n", restorefcmd, dir->msglen);
2192 Mmsg(restore_rwhere, "%s%%%ds\n", restorefcmdR, dir->msglen);
2194 Dmsg2(200, "where=%srwhere=%s", restore_where, restore_rwhere);
2196 /* Scan for new form with number of files to restore */
2197 if (sscanf(dir->msg, restore_where, &files, &replace, &prefix_links, args) != 4) {
2198 if (sscanf(dir->msg, restore_rwhere, &files, &replace, &prefix_links, args) != 4) {
2199 if (sscanf(dir->msg, restorefcmd1, &files, &replace, &prefix_links) != 3) {
2202 *args = 0; /* No where argument */
2204 use_regexwhere = true;
2209 jcr->ExpectedFiles = files;
2211 /* Scan for old form without number of files */
2212 jcr->ExpectedFiles = 0;
2214 /* where= -> where=%202s\n */
2215 Mmsg(restore_where, "%s%%%ds\n", restorecmd, dir->msglen);
2216 Mmsg(restore_rwhere, "%s%%%ds\n", restorecmdR, dir->msglen);
2218 if (sscanf(dir->msg, restore_where, &replace, &prefix_links, args) != 3) {
2219 if (sscanf(dir->msg, restore_rwhere, &replace, &prefix_links, args) != 3){
2220 if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2221 pm_strcpy(jcr->errmsg, dir->msg);
2222 Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2225 *args = 0; /* No where argument */
2227 use_regexwhere = true;
2232 /* Turn / into nothing */
2233 if (IsPathSeparator(args[0]) && args[1] == '\0') {
2237 Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2238 unbash_spaces(args);
2240 /* Keep track of newly created directories to apply them correct attributes */
2241 if (replace == REPLACE_NEVER || replace == REPLACE_IFNEWER) {
2242 jcr->keep_path_list = true;
2245 if (use_regexwhere) {
2246 jcr->where_bregexp = get_bregexps(args);
2247 if (!jcr->where_bregexp) {
2248 Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2252 jcr->where = bstrdup(args);
2255 jcr->replace = replace;
2256 jcr->prefix_links = prefix_links;
2258 dir->fsend(OKrestore);
2259 Dmsg1(110, "filed>dird: %s", dir->msg);
2261 jcr->setJobType(JT_RESTORE);
2263 jcr->setJobStatus(JS_Blocked);
2265 if (!open_sd_read_session(jcr)) {
2266 jcr->setJobStatus(JS_ErrorTerminated);
2270 jcr->setJobStatus(JS_Running);
2273 * Do restore of files and data
2275 start_dir_heartbeat(jcr);
2276 generate_daemon_event(jcr, "JobStart");
2277 generate_plugin_event(jcr, bEventStartRestoreJob);
2280 stop_dir_heartbeat(jcr);
2282 jcr->setJobStatus(JS_Terminated);
2283 if (jcr->JobStatus != JS_Terminated) {
2284 sd->suppress_error_messages(true);
2288 * Send Close session command to Storage daemon
2290 sd->fsend(read_close, jcr->Ticket);
2291 Dmsg1(100, "filed>stored: %s", sd->msg);
2293 bget_msg(sd); /* get OK */
2295 /* Inform Storage daemon that we are done */
2296 sd->signal(BNET_TERMINATE);
2300 bfree_and_null(jcr->where);
2302 if (jcr->JobErrors) {
2303 jcr->setJobStatus(JS_ErrorTerminated);
2306 Dmsg0(100, "Done in job.c\n");
2308 if (jcr->multi_restore) {
2309 Dmsg0(100, OKstoreend);
2310 dir->fsend(OKstoreend);
2311 ret = 1; /* we continue the loop, waiting for next part */
2313 ret = 0; /* we stop here */
2316 if (job_canceled(jcr)) {
2317 ret = 0; /* we stop here */
2321 end_restore_cmd(jcr); /* stopping so send bEventEndRestoreJob */
2325 free_and_null_pool_memory(args);
2326 free_and_null_pool_memory(restore_where);
2327 free_and_null_pool_memory(restore_rwhere);
2332 static int end_restore_cmd(JCR *jcr)
2334 Dmsg0(5, "end_restore_cmd\n");
2335 generate_plugin_event(jcr, bEventEndRestoreJob);
2336 return 0; /* return and terminate command loop */
2339 static int open_sd_read_session(JCR *jcr)
2341 BSOCK *sd = jcr->store_bsock;
2344 Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2347 Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2348 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2349 Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2351 * Open Read Session with Storage daemon
2353 sd->fsend(read_open, "DummyVolume",
2354 jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2355 jcr->StartBlock, jcr->EndBlock);
2356 Dmsg1(110, ">stored: %s", sd->msg);
2361 if (bget_msg(sd) >= 0) {
2362 Dmsg1(110, "filed<stored: %s", sd->msg);
2363 if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2364 Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2367 Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2369 Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2374 * Start read of data with Storage daemon
2376 sd->fsend(read_data, jcr->Ticket);
2377 Dmsg1(110, ">stored: %s", sd->msg);
2382 if (!response(jcr, sd, OK_data, "Read Data")) {
2389 * Destroy the Job Control Record and associated
2390 * resources (sockets).
2392 static void filed_free_jcr(JCR *jcr)
2394 free_bsock(jcr->dir_bsock);
2395 free_bsock(jcr->store_bsock);
2396 if (jcr->last_fname) {
2397 free_pool_memory(jcr->last_fname);
2399 free_runscripts(jcr->RunScripts);
2400 delete jcr->RunScripts;
2401 free_path_list(jcr);
2403 if (jcr->JobId != 0)
2404 write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2410 * Get response from Storage daemon to a command we
2411 * sent. Check that the response is OK.
2413 * Returns: 0 on failure
2416 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2421 if (bget_msg(sd) > 0) {
2422 Dmsg0(110, sd->msg);
2423 if (strcmp(sd->msg, resp) == 0) {
2427 if (job_canceled(jcr)) {
2428 return 0; /* if canceled avoid useless error messages */
2430 if (sd->is_error()) {
2431 Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
2432 cmd, sd->bstrerror());
2434 Jmsg3(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got %s\n"),
2435 cmd, resp, sd->msg);