2 * This file handles commands from the File daemon.
6 * We get here because the Director has initiated a Job with
7 * the Storage daemon, then done the same with the File daemon,
8 * then when the Storage daemon receives a proper connection from
9 * the File daemon, control is passed here to handle the
10 * subsequent File daemon commands.
16 Copyright (C) 2000-2006 Kern Sibbald
18 This program is free software; you can redistribute it and/or
19 modify it under the terms of the GNU General Public License
20 version 2 as amended with additional clauses defined in the
21 file LICENSE in the main source directory.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 the file LICENSE for additional details.
33 /* Imported variables */
36 /* Static variables */
37 static char ferrmsg[] = "3900 Invalid command\n";
39 /* Imported functions */
40 extern bool do_append_data(JCR *jcr);
41 extern bool do_read_data(JCR *jcr);
43 /* Forward referenced FD commands */
44 static bool append_open_session(JCR *jcr);
45 static bool append_close_session(JCR *jcr);
46 static bool append_data_cmd(JCR *jcr);
47 static bool append_end_session(JCR *jcr);
48 static bool read_open_session(JCR *jcr);
49 static bool read_data_cmd(JCR *jcr);
50 static bool read_close_session(JCR *jcr);
51 static bool bootstrap_cmd(JCR *jcr);
53 /* Exported function */
54 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
58 bool (*func)(JCR *jcr);
62 * The following are the recognized commands from the File daemon
64 static struct s_cmds fd_cmds[] = {
65 {"append open", append_open_session},
66 {"append data", append_data_cmd},
67 {"append end", append_end_session},
68 {"append close", append_close_session},
69 {"read open", read_open_session},
70 {"read data", read_data_cmd},
71 {"read close", read_close_session},
72 {"bootstrap", bootstrap_cmd},
73 {NULL, NULL} /* list terminator */
76 /* Commands from the File daemon that require additional scanning */
77 static char read_open[] = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
79 /* Responses sent to the File daemon */
80 static char NO_open[] = "3901 Error session already open\n";
81 static char NOT_opened[] = "3902 Error session not opened\n";
82 static char OK_end[] = "3000 OK end\n";
83 static char OK_close[] = "3000 OK close Status = %d\n";
84 static char OK_open[] = "3000 OK open ticket = %d\n";
85 static char OK_append[] = "3000 OK append data\n";
86 static char ERROR_append[] = "3903 Error append data\n";
87 static char OK_bootstrap[] = "3000 OK bootstrap\n";
88 static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
90 /* Information sent to the Director */
91 static char Job_start[] = "3010 Job %s start\n";
93 "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n";
96 * Run a File daemon Job -- File daemon already authorized
99 * - Read a command from the File daemon
103 void run_job(JCR *jcr)
107 BSOCK *fd = jcr->file_bsock;
108 BSOCK *dir = jcr->dir_bsock;
114 Dmsg1(120, "Start run Job=%s\n", jcr->Job);
115 bnet_fsend(dir, Job_start, jcr->Job);
116 jcr->start_time = time(NULL);
117 jcr->run_time = jcr->start_time;
118 set_jcr_job_status(jcr, JS_Running);
119 dir_send_job_status(jcr); /* update director */
120 for (quit=false; !quit;) {
123 /* Read command coming from the File daemon */
124 stat = bnet_recv(fd);
125 if (is_bnet_stop(fd)) { /* hardeof or error */
126 break; /* connection terminated */
129 continue; /* ignore signals and zero length msgs */
131 Dmsg1(110, "<filed: %s", fd->msg);
133 for (i=0; fd_cmds[i].cmd; i++) {
134 if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
135 found = true; /* indicate command found */
136 if (!fd_cmds[i].func(jcr) || job_canceled(jcr)) { /* do command */
137 set_jcr_job_status(jcr, JS_ErrorTerminated);
143 if (!found) { /* command not found */
144 Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
145 bnet_fsend(fd, ferrmsg);
149 bnet_sig(fd, BNET_TERMINATE); /* signal to FD job is done */
150 jcr->end_time = time(NULL);
151 dequeue_messages(jcr); /* send any queued messages */
152 set_jcr_job_status(jcr, JS_Terminated);
153 generate_daemon_event(jcr, "JobEnd");
154 bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
155 edit_uint64(jcr->JobBytes, ec1));
156 bnet_sig(dir, BNET_EOD); /* send EOD to Director daemon */
162 * Append Data command
163 * Open Data Channel and receive Data for archiving
164 * Write the Data to the archive device
166 static bool append_data_cmd(JCR *jcr)
168 BSOCK *fd = jcr->file_bsock;
170 Dmsg1(120, "Append data: %s", fd->msg);
171 if (jcr->session_opened) {
172 Dmsg1(110, "<bfiled: %s", fd->msg);
173 jcr->JobType = JT_BACKUP;
174 if (do_append_data(jcr)) {
175 return bnet_fsend(fd, OK_append);
177 bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
178 bnet_fsend(fd, ERROR_append);
181 bnet_fsend(fd, NOT_opened);
186 static bool append_end_session(JCR *jcr)
188 BSOCK *fd = jcr->file_bsock;
190 Dmsg1(120, "store<file: %s", fd->msg);
191 if (!jcr->session_opened) {
192 bnet_fsend(fd, NOT_opened);
195 set_jcr_job_status(jcr, JS_Terminated);
196 return bnet_fsend(fd, OK_end);
201 * Append Open session command
204 static bool append_open_session(JCR *jcr)
206 BSOCK *fd = jcr->file_bsock;
208 Dmsg1(120, "Append open session: %s", fd->msg);
209 if (jcr->session_opened) {
210 bnet_fsend(fd, NO_open);
214 jcr->session_opened = true;
216 /* Send "Ticket" to File Daemon */
217 bnet_fsend(fd, OK_open, jcr->VolSessionId);
218 Dmsg1(110, ">filed: %s", fd->msg);
224 * Append Close session command
225 * Close the append session and send back Statistics
226 * (need to fix statistics)
228 static bool append_close_session(JCR *jcr)
230 BSOCK *fd = jcr->file_bsock;
232 Dmsg1(120, "<filed: %s", fd->msg);
233 if (!jcr->session_opened) {
234 bnet_fsend(fd, NOT_opened);
237 /* Send final statistics to File daemon */
238 bnet_fsend(fd, OK_close, jcr->JobStatus);
239 Dmsg1(120, ">filed: %s", fd->msg);
241 bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */
243 jcr->session_opened = false;
249 * Open Data Channel, read the data from
250 * the archive device and send to File
253 static bool read_data_cmd(JCR *jcr)
255 BSOCK *fd = jcr->file_bsock;
257 Dmsg1(120, "Read data: %s", fd->msg);
258 if (jcr->session_opened) {
259 Dmsg1(120, "<bfiled: %s", fd->msg);
260 return do_read_data(jcr);
262 bnet_fsend(fd, NOT_opened);
268 * Read Open session command
270 * We need to scan for the parameters of the job
273 static bool read_open_session(JCR *jcr)
275 BSOCK *fd = jcr->file_bsock;
277 Dmsg1(120, "%s\n", fd->msg);
278 if (jcr->session_opened) {
279 bnet_fsend(fd, NO_open);
283 if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
284 &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
285 &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
286 if (jcr->session_opened) {
287 bnet_fsend(fd, NOT_opened);
290 Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
291 jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
292 jcr->read_VolSessionTime);
293 Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
294 jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
298 jcr->session_opened = true;
299 jcr->JobType = JT_RESTORE;
301 /* Send "Ticket" to File Daemon */
302 bnet_fsend(fd, OK_open, jcr->VolSessionId);
303 Dmsg1(110, ">filed: %s", fd->msg);
308 static bool bootstrap_cmd(JCR *jcr)
310 return get_bootstrap_file(jcr, jcr->file_bsock);
313 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
314 static uint32_t bsr_uniq = 0;
316 bool get_bootstrap_file(JCR *jcr, BSOCK *sock)
318 POOLMEM *fname = get_pool_memory(PM_FNAME);
322 if (jcr->RestoreBootstrap) {
323 unlink(jcr->RestoreBootstrap);
324 free_pool_memory(jcr->RestoreBootstrap);
328 Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
331 Dmsg1(400, "bootstrap=%s\n", fname);
332 jcr->RestoreBootstrap = fname;
333 bs = fopen(fname, "a+b"); /* create file */
335 Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
336 jcr->RestoreBootstrap, strerror(errno));
339 while (bnet_recv(sock) >= 0) {
340 Dmsg1(400, "stored<filed: bootstrap file %s", sock->msg);
341 fputs(sock->msg, bs);
344 jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
346 Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
349 if (debug_level > 20) {
350 dump_bsr(jcr->bsr, true);
355 unlink(jcr->RestoreBootstrap);
356 free_pool_memory(jcr->RestoreBootstrap);
357 jcr->RestoreBootstrap = NULL;
359 bnet_fsend(sock, ERROR_bootstrap);
362 return bnet_fsend(sock, OK_bootstrap);
367 * Read Close session command
368 * Close the read session
370 static bool read_close_session(JCR *jcr)
372 BSOCK *fd = jcr->file_bsock;
374 Dmsg1(120, "Read close session: %s\n", fd->msg);
375 if (!jcr->session_opened) {
376 bnet_fsend(fd, NOT_opened);
379 /* Send final statistics to File daemon */
380 bnet_fsend(fd, OK_close);
381 Dmsg1(160, ">filed: %s\n", fd->msg);
383 bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */
385 jcr->session_opened = false;