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