]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
Update disk seek debug code
[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    Bacula® - The Network Backup Solution
17
18    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
19
20    The main author of Bacula is Kern Sibbald, with contributions from
21    many others, a complete list can be found in the file AUTHORS.
22    This program is Free Software; you can redistribute it and/or
23    modify it under the terms of version two of the GNU General Public
24    License as published by the Free Software Foundation plus additions
25    that are listed in the file LICENSE.
26
27    This program is distributed in the hope that it will be useful, but
28    WITHOUT ANY WARRANTY; without even the implied warranty of
29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30    General Public License for more details.
31
32    You should have received a copy of the GNU General Public License
33    along with this program; if not, write to the Free Software
34    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35    02110-1301, USA.
36
37    Bacula® is a registered trademark of John Walker.
38    The licensor of Bacula is the Free Software Foundation Europe
39    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
40    Switzerland, email:ftf@fsfeurope.org.
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 static bool bootstrap_cmd(JCR *jcr);
65
66 /* Exported function */
67 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
68
69 struct s_cmds {
70    const char *cmd;
71    bool (*func)(JCR *jcr);
72 };
73
74 /*
75  * The following are the recognized commands from the File daemon
76  */
77 static struct s_cmds fd_cmds[] = {
78    {"append open",  append_open_session},
79    {"append data",  append_data_cmd},
80    {"append end",   append_end_session},
81    {"append close", append_close_session},
82    {"read open",    read_open_session},
83    {"read data",    read_data_cmd},
84    {"read close",   read_close_session},
85    {"bootstrap",    bootstrap_cmd},
86    {NULL,           NULL}                  /* list terminator */
87 };
88
89 /* Commands from the File daemon that require additional scanning */
90 static char read_open[]       = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
91
92 /* Responses sent to the File daemon */
93 static char NO_open[]         = "3901 Error session already open\n";
94 static char NOT_opened[]      = "3902 Error session not opened\n";
95 static char OK_end[]          = "3000 OK end\n";
96 static char OK_close[]        = "3000 OK close Status = %d\n";
97 static char OK_open[]         = "3000 OK open ticket = %d\n";
98 static char OK_append[]       = "3000 OK append data\n";
99 static char ERROR_append[]    = "3903 Error append data\n";
100 static char OK_bootstrap[]    = "3000 OK bootstrap\n";
101 static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
102
103 /* Information sent to the Director */
104 static char Job_start[] = "3010 Job %s start\n";
105 char Job_end[]   =
106    "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n";
107
108 /*
109  * Run a File daemon Job -- File daemon already authorized
110  *
111  * Basic task here is:
112  * - Read a command from the File daemon
113  * - Execute it
114  *
115  */
116 void run_job(JCR *jcr)
117 {
118    int i;
119    bool found, quit;
120    BSOCK *fd = jcr->file_bsock;
121    BSOCK *dir = jcr->dir_bsock;
122    char ec1[30];
123
124
125    fd->jcr = jcr;
126    dir->jcr = jcr;
127    Dmsg1(120, "Start run Job=%s\n", jcr->Job);
128    bnet_fsend(dir, Job_start, jcr->Job);
129    jcr->start_time = time(NULL);
130    jcr->run_time = jcr->start_time;
131    set_jcr_job_status(jcr, JS_Running);
132    dir_send_job_status(jcr);          /* update director */
133    for (quit=false; !quit;) {
134       int stat;
135
136       /* Read command coming from the File daemon */
137       stat = bnet_recv(fd);
138       if (is_bnet_stop(fd)) {         /* hardeof or error */
139          break;                       /* connection terminated */
140       }
141       if (stat <= 0) {
142          continue;                    /* ignore signals and zero length msgs */
143       }
144       Dmsg1(110, "<filed: %s", fd->msg);
145       found = false;
146       for (i=0; fd_cmds[i].cmd; i++) {
147          if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
148             found = true;               /* indicate command found */
149             if (!fd_cmds[i].func(jcr) || job_canceled(jcr)) {    /* do command */
150                set_jcr_job_status(jcr, JS_ErrorTerminated);
151                quit = true;
152             }
153             break;
154          }
155       }
156       if (!found) {                   /* command not found */
157          Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
158          bnet_fsend(fd, ferrmsg);
159          break;
160       }
161    }
162    bnet_sig(fd, BNET_TERMINATE);      /* signal to FD job is done */
163    jcr->end_time = time(NULL);
164    dequeue_messages(jcr);             /* send any queued messages */
165    set_jcr_job_status(jcr, JS_Terminated);
166    generate_daemon_event(jcr, "JobEnd");
167    bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
168       edit_uint64(jcr->JobBytes, ec1));
169    bnet_sig(dir, BNET_EOD);           /* send EOD to Director daemon */
170    return;
171 }
172
173
174 /*
175  *   Append Data command
176  *     Open Data Channel and receive Data for archiving
177  *     Write the Data to the archive device
178  */
179 static bool append_data_cmd(JCR *jcr)
180 {
181    BSOCK *fd = jcr->file_bsock;
182
183    Dmsg1(120, "Append data: %s", fd->msg);
184    if (jcr->session_opened) {
185       Dmsg1(110, "<bfiled: %s", fd->msg);
186       jcr->JobType = JT_BACKUP;
187       if (do_append_data(jcr)) {
188          return bnet_fsend(fd, OK_append);
189       } else {
190          bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
191          bnet_fsend(fd, ERROR_append);
192       }
193    } else {
194       bnet_fsend(fd, NOT_opened);
195    }
196    return false;
197 }
198
199 static bool append_end_session(JCR *jcr)
200 {
201    BSOCK *fd = jcr->file_bsock;
202
203    Dmsg1(120, "store<file: %s", fd->msg);
204    if (!jcr->session_opened) {
205       bnet_fsend(fd, NOT_opened);
206       return false;
207    }
208    set_jcr_job_status(jcr, JS_Terminated);
209    return bnet_fsend(fd, OK_end);
210 }
211
212
213 /*
214  * Append Open session command
215  *
216  */
217 static bool append_open_session(JCR *jcr)
218 {
219    BSOCK *fd = jcr->file_bsock;
220
221    Dmsg1(120, "Append open session: %s", fd->msg);
222    if (jcr->session_opened) {
223       bnet_fsend(fd, NO_open);
224       return false;
225    }
226
227    jcr->session_opened = true;
228
229    /* Send "Ticket" to File Daemon */
230    bnet_fsend(fd, OK_open, jcr->VolSessionId);
231    Dmsg1(110, ">filed: %s", fd->msg);
232
233    return true;
234 }
235
236 /*
237  *   Append Close session command
238  *      Close the append session and send back Statistics
239  *         (need to fix statistics)
240  */
241 static bool append_close_session(JCR *jcr)
242 {
243    BSOCK *fd = jcr->file_bsock;
244
245    Dmsg1(120, "<filed: %s", fd->msg);
246    if (!jcr->session_opened) {
247       bnet_fsend(fd, NOT_opened);
248       return false;
249    }
250    /* Send final statistics to File daemon */
251    bnet_fsend(fd, OK_close, jcr->JobStatus);
252    Dmsg1(120, ">filed: %s", fd->msg);
253
254    bnet_sig(fd, BNET_EOD);            /* send EOD to File daemon */
255
256    jcr->session_opened = false;
257    return true;
258 }
259
260 /*
261  *   Read Data command
262  *     Open Data Channel, read the data from
263  *     the archive device and send to File
264  *     daemon.
265  */
266 static bool read_data_cmd(JCR *jcr)
267 {
268    BSOCK *fd = jcr->file_bsock;
269
270    Dmsg1(120, "Read data: %s", fd->msg);
271    if (jcr->session_opened) {
272       Dmsg1(120, "<bfiled: %s", fd->msg);
273       return do_read_data(jcr);
274    } else {
275       bnet_fsend(fd, NOT_opened);
276       return false;
277    }
278 }
279
280 /*
281  * Read Open session command
282  *
283  *  We need to scan for the parameters of the job
284  *    to be restored.
285  */
286 static bool read_open_session(JCR *jcr)
287 {
288    BSOCK *fd = jcr->file_bsock;
289
290    Dmsg1(120, "%s\n", fd->msg);
291    if (jcr->session_opened) {
292       bnet_fsend(fd, NO_open);
293       return false;
294    }
295
296    if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
297          &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
298          &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
299       if (jcr->session_opened) {
300          bnet_fsend(fd, NOT_opened);
301          return false;
302       }
303       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
304          jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
305          jcr->read_VolSessionTime);
306       Dmsg4(100, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
307          jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
308          jcr->read_EndBlock);
309    }
310
311    jcr->session_opened = true;
312    jcr->JobType = JT_RESTORE;
313
314    /* Send "Ticket" to File Daemon */
315    bnet_fsend(fd, OK_open, jcr->VolSessionId);
316    Dmsg1(110, ">filed: %s", fd->msg);
317
318    return true;
319 }
320
321 static bool bootstrap_cmd(JCR *jcr)
322 {
323    return get_bootstrap_file(jcr, jcr->file_bsock);
324 }
325
326 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
327 static uint32_t bsr_uniq = 0;
328
329 bool get_bootstrap_file(JCR *jcr, BSOCK *sock)
330 {
331    POOLMEM *fname = get_pool_memory(PM_FNAME);
332    FILE *bs;
333    bool ok = false;
334
335    if (jcr->RestoreBootstrap) {
336       unlink(jcr->RestoreBootstrap);
337       free_pool_memory(jcr->RestoreBootstrap);
338    }
339    P(bsr_mutex);
340    bsr_uniq++;
341    Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
342       jcr->Job, bsr_uniq);
343    V(bsr_mutex);
344    Dmsg1(400, "bootstrap=%s\n", fname);
345    jcr->RestoreBootstrap = fname;
346    bs = fopen(fname, "a+b");           /* create file */
347    if (!bs) {
348       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
349          jcr->RestoreBootstrap, strerror(errno));
350       goto bail_out;
351    }
352    Dmsg0(10, "=== Bootstrap file ===\n");
353    while (bnet_recv(sock) >= 0) {
354        Dmsg1(10, "%s", sock->msg);
355        fputs(sock->msg, bs);
356    }
357    fclose(bs);
358    Dmsg0(10, "=== end bootstrap file ===\n");
359    jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
360    if (!jcr->bsr) {
361       Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
362       goto bail_out;
363    }
364    if (debug_level >= 10) {
365       dump_bsr(jcr->bsr, true);
366    }
367    ok = true;
368
369 bail_out:
370    unlink(jcr->RestoreBootstrap);
371    free_pool_memory(jcr->RestoreBootstrap);
372    jcr->RestoreBootstrap = NULL;
373    if (!ok) {
374       bnet_fsend(sock, ERROR_bootstrap);
375       return false;
376    }
377    return bnet_fsend(sock, OK_bootstrap);
378 }
379
380
381 /*
382  *   Read Close session command
383  *      Close the read session
384  */
385 static bool read_close_session(JCR *jcr)
386 {
387    BSOCK *fd = jcr->file_bsock;
388
389    Dmsg1(120, "Read close session: %s\n", fd->msg);
390    if (!jcr->session_opened) {
391       bnet_fsend(fd, NOT_opened);
392       return false;
393    }
394    /* Send final statistics to File daemon */
395    bnet_fsend(fd, OK_close);
396    Dmsg1(160, ">filed: %s\n", fd->msg);
397
398    bnet_sig(fd, BNET_EOD);          /* send EOD to File daemon */
399
400    jcr->session_opened = false;
401    return true;
402 }