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) || job_canceled(jcr)) { /* do command */
163 /* Note fd->msg command may be destroyed by comm activity */
164 if (jcr->errmsg[0]) {
165 Jmsg1(jcr, M_FATAL, 0, _("Command error with FD, hanging up. %s\n"),
168 Jmsg0(jcr, M_FATAL, 0, _("Command error with FD, hanging up.\n"));
170 set_jcr_job_status(jcr, JS_ErrorTerminated);
176 if (!found) { /* command not found */
177 Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg);
178 Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
183 fd->signal(BNET_TERMINATE); /* signal to FD job is done */
187 * Append Data command
188 * Open Data Channel and receive Data for archiving
189 * Write the Data to the archive device
191 static bool append_data_cmd(JCR *jcr)
193 BSOCK *fd = jcr->file_bsock;
195 Dmsg1(120, "Append data: %s", fd->msg);
196 if (jcr->session_opened) {
197 Dmsg1(110, "<bfiled: %s", fd->msg);
198 jcr->set_JobType(JT_BACKUP);
199 if (do_append_data(jcr)) {
202 pm_strcpy(jcr->errmsg, _("Append data error.\n"));
203 bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
204 fd->fsend(ERROR_append);
207 pm_strcpy(jcr->errmsg, _("Attempt to append on non-open session.\n"));
208 fd->fsend(NOT_opened);
213 static bool append_end_session(JCR *jcr)
215 BSOCK *fd = jcr->file_bsock;
217 Dmsg1(120, "store<file: %s", fd->msg);
218 if (!jcr->session_opened) {
219 pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
220 fd->fsend(NOT_opened);
223 return fd->fsend(OK_end);
228 * Append Open session command
231 static bool append_open_session(JCR *jcr)
233 BSOCK *fd = jcr->file_bsock;
235 Dmsg1(120, "Append open session: %s", fd->msg);
236 if (jcr->session_opened) {
237 pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n"));
242 jcr->session_opened = true;
244 /* Send "Ticket" to File Daemon */
245 fd->fsend(OK_open, jcr->VolSessionId);
246 Dmsg1(110, ">filed: %s", fd->msg);
252 * Append Close session command
253 * Close the append session and send back Statistics
254 * (need to fix statistics)
256 static bool append_close_session(JCR *jcr)
258 BSOCK *fd = jcr->file_bsock;
260 Dmsg1(120, "<filed: %s", fd->msg);
261 if (!jcr->session_opened) {
262 pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
263 fd->fsend(NOT_opened);
266 /* Send final statistics to File daemon */
267 fd->fsend(OK_close, jcr->JobStatus);
268 Dmsg1(120, ">filed: %s", fd->msg);
270 fd->signal(BNET_EOD); /* send EOD to File daemon */
272 jcr->session_opened = false;
278 * Open Data Channel, read the data from
279 * the archive device and send to File
282 static bool read_data_cmd(JCR *jcr)
284 BSOCK *fd = jcr->file_bsock;
286 Dmsg1(120, "Read data: %s", fd->msg);
287 if (jcr->session_opened) {
288 Dmsg1(120, "<bfiled: %s", fd->msg);
289 return do_read_data(jcr);
291 pm_strcpy(jcr->errmsg, _("Attempt to read on non-open session.\n"));
292 fd->fsend(NOT_opened);
298 * Read Open session command
300 * We need to scan for the parameters of the job
303 static bool read_open_session(JCR *jcr)
305 BSOCK *fd = jcr->file_bsock;
307 Dmsg1(120, "%s\n", fd->msg);
308 if (jcr->session_opened) {
309 pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
314 if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
315 &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
316 &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
317 if (jcr->session_opened) {
318 pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
319 fd->fsend(NOT_opened);
322 Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
323 jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
324 jcr->read_VolSessionTime);
325 Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
326 jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
330 jcr->session_opened = true;
331 jcr->set_JobType(JT_RESTORE);
333 /* Send "Ticket" to File Daemon */
334 fd->fsend(OK_open, jcr->VolSessionId);
335 Dmsg1(110, ">filed: %s", fd->msg);
341 * Read Close session command
342 * Close the read session
344 static bool read_close_session(JCR *jcr)
346 BSOCK *fd = jcr->file_bsock;
348 Dmsg1(120, "Read close session: %s\n", fd->msg);
349 if (!jcr->session_opened) {
350 fd->fsend(NOT_opened);
353 /* Send final close msg to File daemon */
354 fd->fsend(OK_close, jcr->JobStatus);
355 Dmsg1(160, ">filed: %s\n", fd->msg);
357 fd->signal(BNET_EOD); /* send EOD to File daemon */
359 jcr->session_opened = false;