]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
- Add copyright to title page of manual so it is clear.
[bacula/bacula] / bacula / src / stored / fd_cmds.c
1 /*
2  * This file handles commands from the File daemon.
3  *
4  *  Kern Sibbald, MM
5  *
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.
11  *
12  *   Version $Id$
13  *
14  */
15 /*
16    Copyright (C) 2000-2005 Kern Sibbald
17
18    This program is free software; you can redistribute it and/or
19    modify it under the terms of the GNU General Public License as
20    published by the Free Software Foundation; either version 2 of
21    the License, or (at your option) any later version.
22
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 GNU
26    General Public License for more details.
27
28    You should have received a copy of the GNU General Public
29    License along with this program; if not, write to the Free
30    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31    MA 02111-1307, USA.
32
33  */
34
35 #include "bacula.h"
36 #include "stored.h"
37
38 /* Imported variables */
39 extern STORES *me;
40
41 /* Static variables */
42 static char ferrmsg[]      = "3900 Invalid command\n";
43
44 /* Imported functions */
45 extern bool do_append_data(JCR *jcr);
46 extern bool do_read_data(JCR *jcr);
47
48 /* Forward referenced FD commands */
49 static bool append_open_session(JCR *jcr);
50 static bool append_close_session(JCR *jcr);
51 static bool append_data_cmd(JCR *jcr);
52 static bool append_end_session(JCR *jcr);
53 static bool read_open_session(JCR *jcr);
54 static bool read_data_cmd(JCR *jcr);
55 static bool read_close_session(JCR *jcr);
56
57 /* Exported function */
58 bool bootstrap_cmd(JCR *jcr);
59
60 struct s_cmds {
61    const char *cmd;
62    bool (*func)(JCR *jcr);
63 };
64
65 /*
66  * The following are the recognized commands from the File daemon
67  */
68 static struct s_cmds fd_cmds[] = {
69    {"append open",  append_open_session},
70    {"append data",  append_data_cmd},
71    {"append end",   append_end_session},
72    {"append close", append_close_session},
73    {"read open",    read_open_session},
74    {"read data",    read_data_cmd},
75    {"read close",   read_close_session},
76    {"bootstrap",    bootstrap_cmd},
77    {NULL,           NULL}                  /* list terminator */
78 };
79
80 /* Commands from the File daemon that require additional scanning */
81 static char read_open[]       = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
82
83 /* Responses sent to the File daemon */
84 static char NO_open[]         = "3901 Error session already open\n";
85 static char NOT_opened[]      = "3902 Error session not opened\n";
86 static char OK_end[]          = "3000 OK end\n";
87 static char OK_close[]        = "3000 OK close Status = %d\n";
88 static char OK_open[]         = "3000 OK open ticket = %d\n";
89 static char OK_append[]       = "3000 OK append data\n";
90 static char ERROR_append[]    = "3903 Error append data\n";
91 static char OK_bootstrap[]    = "3000 OK bootstrap\n";
92 static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
93
94 /* Information sent to the Director */
95 static char Job_start[] = "3010 Job %s start\n";
96 static char Job_end[]   =
97    "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n";
98
99 /*
100  * Run a File daemon Job -- File daemon already authorized
101  *
102  * Basic task here is:
103  * - Read a command from the File daemon
104  * - Execute it
105  *
106  */
107 void run_job(JCR *jcr)
108 {
109    int i;
110    bool found, quit;
111    BSOCK *fd = jcr->file_bsock;
112    BSOCK *dir = jcr->dir_bsock;
113    char ec1[30];
114
115
116    fd->jcr = jcr;
117    dir->jcr = jcr;
118    Dmsg1(120, "Start run Job=%s\n", jcr->Job);
119    bnet_fsend(dir, 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    for (quit=false; !quit;) {
125       int stat;
126
127       /* Read command coming from the File daemon */
128       stat = bnet_recv(fd);
129       if (is_bnet_stop(fd)) {         /* hardeof or error */
130          break;                       /* connection terminated */
131       }
132       if (stat <= 0) {
133          continue;                    /* ignore signals and zero length msgs */
134       }
135       Dmsg1(110, "<filed: %s", fd->msg);
136       found = false;
137       for (i=0; fd_cmds[i].cmd; i++) {
138          if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
139             found = true;               /* indicate command found */
140             if (!fd_cmds[i].func(jcr)) {    /* do command */
141                set_jcr_job_status(jcr, JS_ErrorTerminated);
142                quit = true;
143             }
144             break;
145          }
146       }
147       if (!found) {                   /* command not found */
148          Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
149          bnet_fsend(fd, ferrmsg);
150          break;
151       }
152    }
153    bnet_sig(fd, BNET_TERMINATE);      /* signal to FD job is done */
154    jcr->end_time = time(NULL);
155    dequeue_messages(jcr);             /* send any queued messages */
156    set_jcr_job_status(jcr, JS_Terminated);
157    bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
158       edit_uint64(jcr->JobBytes, ec1));
159    bnet_sig(dir, BNET_EOD);           /* send EOD to Director daemon */
160    return;
161 }
162
163
164 /*
165  *   Append Data command
166  *     Open Data Channel and receive Data for archiving
167  *     Write the Data to the archive device
168  */
169 static bool append_data_cmd(JCR *jcr)
170 {
171    BSOCK *fd = jcr->file_bsock;
172
173    Dmsg1(120, "Append data: %s", fd->msg);
174    if (jcr->session_opened) {
175       Dmsg1(110, "<bfiled: %s", fd->msg);
176       jcr->JobType = JT_BACKUP;
177       if (do_append_data(jcr)) {
178          return bnet_fsend(fd, OK_append);
179       } else {
180          bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
181          bnet_fsend(fd, ERROR_append);
182       }
183    } else {
184       bnet_fsend(fd, NOT_opened);
185    }
186    return false;
187 }
188
189 static bool append_end_session(JCR *jcr)
190 {
191    BSOCK *fd = jcr->file_bsock;
192
193    Dmsg1(120, "store<file: %s", fd->msg);
194    if (!jcr->session_opened) {
195       bnet_fsend(fd, NOT_opened);
196       return false;
197    }
198    set_jcr_job_status(jcr, JS_Terminated);
199    return bnet_fsend(fd, OK_end);
200 }
201
202
203 /*
204  * Append Open session command
205  *
206  */
207 static bool append_open_session(JCR *jcr)
208 {
209    BSOCK *fd = jcr->file_bsock;
210
211    Dmsg1(120, "Append open session: %s", fd->msg);
212    if (jcr->session_opened) {
213       bnet_fsend(fd, NO_open);
214       return false;
215    }
216
217    jcr->session_opened = true;
218
219    /* Send "Ticket" to File Daemon */
220    bnet_fsend(fd, OK_open, jcr->VolSessionId);
221    Dmsg1(110, ">filed: %s", fd->msg);
222
223    return true;
224 }
225
226 /*
227  *   Append Close session command
228  *      Close the append session and send back Statistics
229  *         (need to fix statistics)
230  */
231 static bool append_close_session(JCR *jcr)
232 {
233    BSOCK *fd = jcr->file_bsock;
234
235    Dmsg1(120, "<filed: %s", fd->msg);
236    if (!jcr->session_opened) {
237       bnet_fsend(fd, NOT_opened);
238       return false;
239    }
240    /* Send final statistics to File daemon */
241    bnet_fsend(fd, OK_close, jcr->JobStatus);
242    Dmsg1(120, ">filed: %s", fd->msg);
243
244    bnet_sig(fd, BNET_EOD);            /* send EOD to File daemon */
245
246    jcr->session_opened = false;
247    return true;
248 }
249
250 /*
251  *   Read Data command
252  *     Open Data Channel, read the data from
253  *     the archive device and send to File
254  *     daemon.
255  */
256 static bool read_data_cmd(JCR *jcr)
257 {
258    BSOCK *fd = jcr->file_bsock;
259
260    Dmsg1(120, "Read data: %s", fd->msg);
261    if (jcr->session_opened) {
262       Dmsg1(120, "<bfiled: %s", fd->msg);
263       return do_read_data(jcr);
264    } else {
265       bnet_fsend(fd, NOT_opened);
266       return false;
267    }
268 }
269
270 /*
271  * Read Open session command
272  *
273  *  We need to scan for the parameters of the job
274  *    to be restored.
275  */
276 static bool read_open_session(JCR *jcr)
277 {
278    BSOCK *fd = jcr->file_bsock;
279
280    Dmsg1(120, "%s\n", fd->msg);
281    if (jcr->session_opened) {
282       bnet_fsend(fd, NO_open);
283       return false;
284    }
285
286    if (sscanf(fd->msg, read_open, jcr->dcr->VolumeName, &jcr->read_VolSessionId,
287          &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
288          &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
289       if (jcr->session_opened) {
290          bnet_fsend(fd, NOT_opened);
291          return false;
292       }
293       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
294          jcr->JobId, jcr->dcr->VolumeName, jcr->read_VolSessionId,
295          jcr->read_VolSessionTime);
296       Dmsg4(100, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
297          jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
298          jcr->read_EndBlock);
299    }
300
301    jcr->session_opened = true;
302    jcr->JobType = JT_RESTORE;
303
304    /* Send "Ticket" to File Daemon */
305    bnet_fsend(fd, OK_open, jcr->VolSessionId);
306    Dmsg1(110, ">filed: %s", fd->msg);
307
308    return true;
309 }
310
311 bool bootstrap_cmd(JCR *jcr)
312 {
313    BSOCK *fd = jcr->file_bsock;
314    POOLMEM *fname = get_pool_memory(PM_FNAME);
315    FILE *bs;
316    bool ok = false;
317
318    if (jcr->RestoreBootstrap) {
319       unlink(jcr->RestoreBootstrap);
320       free_pool_memory(jcr->RestoreBootstrap);
321    }
322    Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
323       jcr->Job);
324    Dmsg1(400, "bootstrap=%s\n", fname);
325    jcr->RestoreBootstrap = fname;
326    bs = fopen(fname, "a+");           /* create file */
327    if (!bs) {
328       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
329          jcr->RestoreBootstrap, strerror(errno));
330       goto bail_out;
331    }
332    while (bnet_recv(fd) >= 0) {
333        Dmsg1(400, "stored<filed: bootstrap file %s\n", fd->msg);
334        fputs(fd->msg, bs);
335    }
336    fclose(bs);
337    jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
338    if (!jcr->bsr) {
339       Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
340       goto bail_out;
341    }
342    if (debug_level > 20) {
343       dump_bsr(jcr->bsr, true);
344    }
345    ok = true;
346
347 bail_out:
348    unlink(jcr->RestoreBootstrap);
349    free_pool_memory(jcr->RestoreBootstrap);
350    jcr->RestoreBootstrap = NULL;
351    if (!ok) {
352       bnet_fsend(fd, ERROR_bootstrap);
353       return false;
354    }
355    return bnet_fsend(fd, OK_bootstrap);
356 }
357
358
359 /*
360  *   Read Close session command
361  *      Close the read session
362  */
363 static bool read_close_session(JCR *jcr)
364 {
365    BSOCK *fd = jcr->file_bsock;
366
367    Dmsg1(120, "Read close session: %s\n", fd->msg);
368    if (!jcr->session_opened) {
369       bnet_fsend(fd, NOT_opened);
370       return false;
371    }
372    /* Send final statistics to File daemon */
373    bnet_fsend(fd, OK_close);
374    Dmsg1(160, ">filed: %s\n", fd->msg);
375
376    bnet_sig(fd, BNET_EOD);          /* send EOD to File daemon */
377
378    jcr->session_opened = false;
379    return true;
380 }