]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
0387f2399eb7e30bc050ef7d3f08d296cd070cd4
[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) || job_canceled(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    generate_daemon_event(jcr, "JobEnd");
158    bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
159       edit_uint64(jcr->JobBytes, ec1));
160    bnet_sig(dir, BNET_EOD);           /* send EOD to Director daemon */
161    return;
162 }
163
164
165 /*
166  *   Append Data command
167  *     Open Data Channel and receive Data for archiving
168  *     Write the Data to the archive device
169  */
170 static bool append_data_cmd(JCR *jcr)
171 {
172    BSOCK *fd = jcr->file_bsock;
173
174    Dmsg1(120, "Append data: %s", fd->msg);
175    if (jcr->session_opened) {
176       Dmsg1(110, "<bfiled: %s", fd->msg);
177       jcr->JobType = JT_BACKUP;
178       if (do_append_data(jcr)) {
179          return bnet_fsend(fd, OK_append);
180       } else {
181          bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
182          bnet_fsend(fd, ERROR_append);
183       }
184    } else {
185       bnet_fsend(fd, NOT_opened);
186    }
187    return false;
188 }
189
190 static bool append_end_session(JCR *jcr)
191 {
192    BSOCK *fd = jcr->file_bsock;
193
194    Dmsg1(120, "store<file: %s", fd->msg);
195    if (!jcr->session_opened) {
196       bnet_fsend(fd, NOT_opened);
197       return false;
198    }
199    set_jcr_job_status(jcr, JS_Terminated);
200    return bnet_fsend(fd, OK_end);
201 }
202
203
204 /*
205  * Append Open session command
206  *
207  */
208 static bool append_open_session(JCR *jcr)
209 {
210    BSOCK *fd = jcr->file_bsock;
211
212    Dmsg1(120, "Append open session: %s", fd->msg);
213    if (jcr->session_opened) {
214       bnet_fsend(fd, NO_open);
215       return false;
216    }
217
218    jcr->session_opened = true;
219
220    /* Send "Ticket" to File Daemon */
221    bnet_fsend(fd, OK_open, jcr->VolSessionId);
222    Dmsg1(110, ">filed: %s", fd->msg);
223
224    return true;
225 }
226
227 /*
228  *   Append Close session command
229  *      Close the append session and send back Statistics
230  *         (need to fix statistics)
231  */
232 static bool append_close_session(JCR *jcr)
233 {
234    BSOCK *fd = jcr->file_bsock;
235
236    Dmsg1(120, "<filed: %s", fd->msg);
237    if (!jcr->session_opened) {
238       bnet_fsend(fd, NOT_opened);
239       return false;
240    }
241    /* Send final statistics to File daemon */
242    bnet_fsend(fd, OK_close, jcr->JobStatus);
243    Dmsg1(120, ">filed: %s", fd->msg);
244
245    bnet_sig(fd, BNET_EOD);            /* send EOD to File daemon */
246
247    jcr->session_opened = false;
248    return true;
249 }
250
251 /*
252  *   Read Data command
253  *     Open Data Channel, read the data from
254  *     the archive device and send to File
255  *     daemon.
256  */
257 static bool read_data_cmd(JCR *jcr)
258 {
259    BSOCK *fd = jcr->file_bsock;
260
261    Dmsg1(120, "Read data: %s", fd->msg);
262    if (jcr->session_opened) {
263       Dmsg1(120, "<bfiled: %s", fd->msg);
264       return do_read_data(jcr);
265    } else {
266       bnet_fsend(fd, NOT_opened);
267       return false;
268    }
269 }
270
271 /*
272  * Read Open session command
273  *
274  *  We need to scan for the parameters of the job
275  *    to be restored.
276  */
277 static bool read_open_session(JCR *jcr)
278 {
279    BSOCK *fd = jcr->file_bsock;
280
281    Dmsg1(120, "%s\n", fd->msg);
282    if (jcr->session_opened) {
283       bnet_fsend(fd, NO_open);
284       return false;
285    }
286
287    if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
288          &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
289          &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
290       if (jcr->session_opened) {
291          bnet_fsend(fd, NOT_opened);
292          return false;
293       }
294       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
295          jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
296          jcr->read_VolSessionTime);
297       Dmsg4(100, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
298          jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
299          jcr->read_EndBlock);
300    }
301
302    jcr->session_opened = true;
303    jcr->JobType = JT_RESTORE;
304
305    /* Send "Ticket" to File Daemon */
306    bnet_fsend(fd, OK_open, jcr->VolSessionId);
307    Dmsg1(110, ">filed: %s", fd->msg);
308
309    return true;
310 }
311
312 bool bootstrap_cmd(JCR *jcr)
313 {
314    BSOCK *fd = jcr->file_bsock;
315    POOLMEM *fname = get_pool_memory(PM_FNAME);
316    FILE *bs;
317    bool ok = false;
318
319    if (jcr->RestoreBootstrap) {
320       unlink(jcr->RestoreBootstrap);
321       free_pool_memory(jcr->RestoreBootstrap);
322    }
323    Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
324       jcr->Job);
325    Dmsg1(400, "bootstrap=%s\n", fname);
326    jcr->RestoreBootstrap = fname;
327    bs = fopen(fname, "a+");           /* create file */
328    if (!bs) {
329       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
330          jcr->RestoreBootstrap, strerror(errno));
331       goto bail_out;
332    }
333    while (bnet_recv(fd) >= 0) {
334        Dmsg1(400, "stored<filed: bootstrap file %s", fd->msg);
335        fputs(fd->msg, bs);
336    }
337    fclose(bs);
338    jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
339    if (!jcr->bsr) {
340       Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
341       goto bail_out;
342    }
343    if (debug_level > 20) {
344       dump_bsr(jcr->bsr, true);
345    }
346    ok = true;
347
348 bail_out:
349    unlink(jcr->RestoreBootstrap);
350    free_pool_memory(jcr->RestoreBootstrap);
351    jcr->RestoreBootstrap = NULL;
352    if (!ok) {
353       bnet_fsend(fd, ERROR_bootstrap);
354       return false;
355    }
356    return bnet_fsend(fd, OK_bootstrap);
357 }
358
359
360 /*
361  *   Read Close session command
362  *      Close the read session
363  */
364 static bool read_close_session(JCR *jcr)
365 {
366    BSOCK *fd = jcr->file_bsock;
367
368    Dmsg1(120, "Read close session: %s\n", fd->msg);
369    if (!jcr->session_opened) {
370       bnet_fsend(fd, NOT_opened);
371       return false;
372    }
373    /* Send final statistics to File daemon */
374    bnet_fsend(fd, OK_close);
375    Dmsg1(160, ">filed: %s\n", fd->msg);
376
377    bnet_sig(fd, BNET_EOD);          /* send EOD to File daemon */
378
379    jcr->session_opened = false;
380    return true;
381 }