]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
Rework Mac OS 10.6 mtio.h fix
[bacula/bacula] / bacula / src / stored / fd_cmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  * This file handles commands from the File daemon.
30  *
31  *  Kern Sibbald, MM
32  *
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.
38  *
39  *   Version $Id$
40  *
41  */
42
43 #include "bacula.h"
44 #include "stored.h"
45
46 /* Imported variables */
47 extern STORES *me;
48
49 /* Static variables */
50 static char ferrmsg[]      = "3900 Invalid command\n";
51
52 /* Imported functions */
53 extern bool do_append_data(JCR *jcr);
54 extern bool do_read_data(JCR *jcr);
55
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);
64
65 /* Exported function */
66 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
67
68 struct s_cmds {
69    const char *cmd;
70    bool (*func)(JCR *jcr);
71 };
72
73 /*
74  * The following are the recognized commands from the File daemon
75  */
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 */
85 };
86
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";
89
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";
97
98 /* Information sent to the Director */
99 static char Job_start[] = "3010 Job %s start\n";
100 char Job_end[]   =
101    "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s JobErrors=%u\n";
102
103 /*
104  * Run a File daemon Job -- File daemon already authorized
105  *  Director sends us this command.
106  *
107  * Basic task here is:
108  * - Read a command from the File daemon
109  * - Execute it
110  *
111  */
112 void run_job(JCR *jcr)
113 {
114    BSOCK *dir = jcr->dir_bsock;
115    char ec1[30];
116
117    dir->set_jcr(jcr);
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 */
124    do_fd_commands(jcr);
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 */
132    /* ***FIXME*** remove for production */
133    sm_check(__FILE__, __LINE__, true);
134    return;
135 }
136
137 /*
138  * Now talk to the FD and do what he says
139  */
140 void do_fd_commands(JCR *jcr)
141 {
142    int i;
143    bool found, quit;
144    BSOCK *fd = jcr->file_bsock;
145
146    fd->set_jcr(jcr);
147    for (quit=false; !quit;) {
148       int stat;
149
150       /* Read command coming from the File daemon */
151       stat = fd->recv();
152       if (is_bnet_stop(fd)) {         /* hardeof or error */
153          break;                       /* connection terminated */
154       }
155       if (stat <= 0) {
156          continue;                    /* ignore signals and zero length msgs */
157       }
158       Dmsg1(110, "<filed: %s", fd->msg);
159       found = false;
160       for (i=0; fd_cmds[i].cmd; i++) {
161          if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
162             found = true;               /* indicate command found */
163             jcr->errmsg[0] = 0;
164             if (!fd_cmds[i].func(jcr)) {    /* do command */
165                /* Note fd->msg command may be destroyed by comm activity */
166                if (!job_canceled(jcr)) {
167                   if (jcr->errmsg[0]) {
168                      Jmsg1(jcr, M_FATAL, 0, _("Command error with FD, hanging up. %s\n"),
169                            jcr->errmsg);
170                   } else {
171                      Jmsg0(jcr, M_FATAL, 0, _("Command error with FD, hanging up.\n"));
172                   }
173                   set_jcr_job_status(jcr, JS_ErrorTerminated);
174                }
175                quit = true;
176             }
177             break;
178          }
179       }
180       if (!found) {                   /* command not found */
181          if (!job_canceled(jcr)) {
182             Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg);
183             Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
184          }
185          fd->fsend(ferrmsg);
186          break;
187       }
188    }
189    fd->signal(BNET_TERMINATE);        /* signal to FD job is done */
190 }
191
192 /*
193  *   Append Data command
194  *     Open Data Channel and receive Data for archiving
195  *     Write the Data to the archive device
196  */
197 static bool append_data_cmd(JCR *jcr)
198 {
199    BSOCK *fd = jcr->file_bsock;
200
201    Dmsg1(120, "Append data: %s", fd->msg);
202    if (jcr->session_opened) {
203       Dmsg1(110, "<bfiled: %s", fd->msg);
204       jcr->set_JobType(JT_BACKUP);
205       if (do_append_data(jcr)) {
206          return true;
207       } else {
208          pm_strcpy(jcr->errmsg, _("Append data error.\n"));
209          bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
210          fd->fsend(ERROR_append);
211       }
212    } else {
213       pm_strcpy(jcr->errmsg, _("Attempt to append on non-open session.\n"));
214       fd->fsend(NOT_opened);
215    }
216    return false;
217 }
218
219 static bool append_end_session(JCR *jcr)
220 {
221    BSOCK *fd = jcr->file_bsock;
222
223    Dmsg1(120, "store<file: %s", fd->msg);
224    if (!jcr->session_opened) {
225       pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
226       fd->fsend(NOT_opened);
227       return false;
228    }
229    return fd->fsend(OK_end);
230 }
231
232
233 /*
234  * Append Open session command
235  *
236  */
237 static bool append_open_session(JCR *jcr)
238 {
239    BSOCK *fd = jcr->file_bsock;
240
241    Dmsg1(120, "Append open session: %s", fd->msg);
242    if (jcr->session_opened) {
243       pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n"));
244       fd->fsend(NO_open);
245       return false;
246    }
247
248    jcr->session_opened = true;
249
250    /* Send "Ticket" to File Daemon */
251    fd->fsend(OK_open, jcr->VolSessionId);
252    Dmsg1(110, ">filed: %s", fd->msg);
253
254    return true;
255 }
256
257 /*
258  *   Append Close session command
259  *      Close the append session and send back Statistics
260  *         (need to fix statistics)
261  */
262 static bool append_close_session(JCR *jcr)
263 {
264    BSOCK *fd = jcr->file_bsock;
265
266    Dmsg1(120, "<filed: %s", fd->msg);
267    if (!jcr->session_opened) {
268       pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
269       fd->fsend(NOT_opened);
270       return false;
271    }
272    /* Send final statistics to File daemon */
273    fd->fsend(OK_close, jcr->JobStatus);
274    Dmsg1(120, ">filed: %s", fd->msg);
275
276    fd->signal(BNET_EOD);              /* send EOD to File daemon */
277
278    jcr->session_opened = false;
279    return true;
280 }
281
282 /*
283  *   Read Data command
284  *     Open Data Channel, read the data from
285  *     the archive device and send to File
286  *     daemon.
287  */
288 static bool read_data_cmd(JCR *jcr)
289 {
290    BSOCK *fd = jcr->file_bsock;
291
292    Dmsg1(120, "Read data: %s", fd->msg);
293    if (jcr->session_opened) {
294       Dmsg1(120, "<bfiled: %s", fd->msg);
295       return do_read_data(jcr);
296    } else {
297       pm_strcpy(jcr->errmsg, _("Attempt to read on non-open session.\n"));
298       fd->fsend(NOT_opened);
299       return false;
300    }
301 }
302
303 /*
304  * Read Open session command
305  *
306  *  We need to scan for the parameters of the job
307  *    to be restored.
308  */
309 static bool read_open_session(JCR *jcr)
310 {
311    BSOCK *fd = jcr->file_bsock;
312
313    Dmsg1(120, "%s\n", fd->msg);
314    if (jcr->session_opened) {
315       pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
316       fd->fsend(NO_open);
317       return false;
318    }
319
320    if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
321          &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
322          &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
323       if (jcr->session_opened) {
324          pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n"));
325          fd->fsend(NOT_opened);
326          return false;
327       }
328       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
329          jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
330          jcr->read_VolSessionTime);
331       Dmsg4(100, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
332          jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
333          jcr->read_EndBlock);
334    }
335
336    jcr->session_opened = true;
337    jcr->set_JobType(JT_RESTORE);
338
339    /* Send "Ticket" to File Daemon */
340    fd->fsend(OK_open, jcr->VolSessionId);
341    Dmsg1(110, ">filed: %s", fd->msg);
342
343    return true;
344 }
345
346 /*
347  *   Read Close session command
348  *      Close the read session
349  */
350 static bool read_close_session(JCR *jcr)
351 {
352    BSOCK *fd = jcr->file_bsock;
353
354    Dmsg1(120, "Read close session: %s\n", fd->msg);
355    if (!jcr->session_opened) {
356       fd->fsend(NOT_opened);
357       return false;
358    }
359    /* Send final close msg to File daemon */
360    fd->fsend(OK_close, jcr->JobStatus);
361    Dmsg1(160, ">filed: %s\n", fd->msg);
362
363    fd->signal(BNET_EOD);            /* send EOD to File daemon */
364
365    jcr->session_opened = false;
366    return true;
367 }