2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * This file handles commands from the File daemon.
33 * We get here because the Director has initiated a Job with
34 * the Storage daemon, then done the same with the File daemon,
35 * then when the Storage daemon receives a proper connection from
36 * the File daemon, control is passed here to handle the
37 * subsequent File daemon commands.
46 /* Imported variables */
49 /* Static variables */
50 static char ferrmsg[] = "3900 Invalid command\n";
52 /* Imported functions */
53 extern bool do_append_data(JCR *jcr);
54 extern bool do_read_data(JCR *jcr);
56 /* Forward referenced FD commands */
57 static bool append_open_session(JCR *jcr);
58 static bool append_close_session(JCR *jcr);
59 static bool append_data_cmd(JCR *jcr);
60 static bool append_end_session(JCR *jcr);
61 static bool read_open_session(JCR *jcr);
62 static bool read_data_cmd(JCR *jcr);
63 static bool read_close_session(JCR *jcr);
65 /* Exported function */
66 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
70 bool (*func)(JCR *jcr);
74 * The following are the recognized commands from the File daemon
76 static struct s_cmds fd_cmds[] = {
77 {"append open", append_open_session},
78 {"append data", append_data_cmd},
79 {"append end", append_end_session},
80 {"append close", append_close_session},
81 {"read open", read_open_session},
82 {"read data", read_data_cmd},
83 {"read close", read_close_session},
84 {NULL, NULL} /* list terminator */
87 /* Commands from the File daemon that require additional scanning */
88 static char read_open[] = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
90 /* Responses sent to the File daemon */
91 static char NO_open[] = "3901 Error session already open\n";
92 static char NOT_opened[] = "3902 Error session not opened\n";
93 static char OK_end[] = "3000 OK end\n";
94 static char OK_close[] = "3000 OK close Status = %d\n";
95 static char OK_open[] = "3000 OK open ticket = %d\n";
96 static char ERROR_append[] = "3903 Error append data\n";
98 /* Information sent to the Director */
99 static char Job_start[] = "3010 Job %s start\n";
101 "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s JobErrors=%u\n";
104 * Run a File daemon Job -- File daemon already authorized
105 * Director sends us this command.
107 * Basic task here is:
108 * - Read a command from the File daemon
112 void run_job(JCR *jcr)
114 BSOCK *dir = jcr->dir_bsock;
118 Dmsg1(120, "Start run Job=%s\n", jcr->Job);
119 dir->fsend(Job_start, jcr->Job);
120 jcr->start_time = time(NULL);
121 jcr->run_time = jcr->start_time;
122 set_jcr_job_status(jcr, JS_Running);
123 dir_send_job_status(jcr); /* update director */
125 jcr->end_time = time(NULL);
126 dequeue_messages(jcr); /* send any queued messages */
127 set_jcr_job_status(jcr, JS_Terminated);
128 generate_daemon_event(jcr, "JobEnd");
129 dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
130 edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors);
131 dir->signal(BNET_EOD); /* send EOD to Director daemon */
136 * Now talk to the FD and do what he says
138 void do_fd_commands(JCR *jcr)
142 BSOCK *fd = jcr->file_bsock;
145 for (quit=false; !quit;) {
148 /* Read command coming from the File daemon */
150 if (is_bnet_stop(fd)) { /* hardeof or error */
151 break; /* connection terminated */
154 continue; /* ignore signals and zero length msgs */
156 Dmsg1(110, "<filed: %s", fd->msg);
158 for (i=0; fd_cmds[i].cmd; i++) {
159 if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
160 found = true; /* indicate command found */
162 if (!fd_cmds[i].func(jcr)) { /* do command */
163 /* Note fd->msg command may be destroyed by comm activity */
164 if (!job_canceled(jcr)) {
165 if (jcr->errmsg[0]) {
166 Jmsg1(jcr, M_FATAL, 0, _("Command error with FD, hanging up. %s\n"),
169 Jmsg0(jcr, M_FATAL, 0, _("Command error with FD, hanging up.\n"));
171 set_jcr_job_status(jcr, JS_ErrorTerminated);
178 if (!found) { /* command not found */
179 Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg);
180 Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
185 fd->signal(BNET_TERMINATE); /* signal to FD job is done */
189 * Append Data command
190 * Open Data Channel and receive Data for archiving
191 * Write the Data to the archive device
193 static bool append_data_cmd(JCR *jcr)
195 BSOCK *fd = jcr->file_bsock;
197 Dmsg1(120, "Append data: %s", fd->msg);
198 if (jcr->session_opened) {
199 Dmsg1(110, "<bfiled: %s", fd->msg);
200 jcr->set_JobType(JT_BACKUP);
201 if (do_append_data(jcr)) {
204 pm_strcpy(jcr->errmsg, _("Append data error.\n"));
205 bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
206 fd->fsend(ERROR_append);
209 pm_strcpy(jcr->errmsg, _("Attempt to append on non-open session.\n"));
210 fd->fsend(NOT_opened);
215 static bool append_end_session(JCR *jcr)
217 BSOCK *fd = jcr->file_bsock;
219 Dmsg1(120, "store<file: %s", fd->msg);
220 if (!jcr->session_opened) {
221 pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
222 fd->fsend(NOT_opened);
225 return fd->fsend(OK_end);
230 * Append Open session command
233 static bool append_open_session(JCR *jcr)
235 BSOCK *fd = jcr->file_bsock;
237 Dmsg1(120, "Append open session: %s", fd->msg);
238 if (jcr->session_opened) {
239 pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n"));
244 jcr->session_opened = true;
246 /* Send "Ticket" to File Daemon */
247 fd->fsend(OK_open, jcr->VolSessionId);
248 Dmsg1(110, ">filed: %s", fd->msg);
254 * Append Close session command
255 * Close the append session and send back Statistics
256 * (need to fix statistics)
258 static bool append_close_session(JCR *jcr)
260 BSOCK *fd = jcr->file_bsock;
262 Dmsg1(120, "<filed: %s", fd->msg);
263 if (!jcr->session_opened) {
264 pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
265 fd->fsend(NOT_opened);
268 /* Send final statistics to File daemon */
269 fd->fsend(OK_close, jcr->JobStatus);
270 Dmsg1(120, ">filed: %s", fd->msg);
272 fd->signal(BNET_EOD); /* send EOD to File daemon */
274 jcr->session_opened = false;
280 * Open Data Channel, read the data from
281 * the archive device and send to File
284 static bool read_data_cmd(JCR *jcr)
286 BSOCK *fd = jcr->file_bsock;
288 Dmsg1(120, "Read data: %s", fd->msg);
289 if (jcr->session_opened) {
290 Dmsg1(120, "<bfiled: %s", fd->msg);
291 return do_read_data(jcr);
293 pm_strcpy(jcr->errmsg, _("Attempt to read on non-open session.\n"));
294 fd->fsend(NOT_opened);
300 * Read Open session command
302 * We need to scan for the parameters of the job
305 static bool read_open_session(JCR *jcr)
307 BSOCK *fd = jcr->file_bsock;
309 Dmsg1(120, "%s\n", fd->msg);
310 if (jcr->session_opened) {
311 pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
316 if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
317 &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
318 &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
319 if (jcr->session_opened) {
320 pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
321 fd->fsend(NOT_opened);
324 Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
325 jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
326 jcr->read_VolSessionTime);
327 Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
328 jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
332 jcr->session_opened = true;
333 jcr->set_JobType(JT_RESTORE);
335 /* Send "Ticket" to File Daemon */
336 fd->fsend(OK_open, jcr->VolSessionId);
337 Dmsg1(110, ">filed: %s", fd->msg);
343 * Read Close session command
344 * Close the read session
346 static bool read_close_session(JCR *jcr)
348 BSOCK *fd = jcr->file_bsock;
350 Dmsg1(120, "Read close session: %s\n", fd->msg);
351 if (!jcr->session_opened) {
352 fd->fsend(NOT_opened);
355 /* Send final close msg to File daemon */
356 fd->fsend(OK_close, jcr->JobStatus);
357 Dmsg1(160, ">filed: %s\n", fd->msg);
359 fd->signal(BNET_EOD); /* send EOD to File daemon */
361 jcr->session_opened = false;