]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
Add mac.c file
[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-2006 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 static bool bootstrap_cmd(JCR *jcr);
57
58 /* Exported function */
59 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
60
61 struct s_cmds {
62    const char *cmd;
63    bool (*func)(JCR *jcr);
64 };
65
66 /*
67  * The following are the recognized commands from the File daemon
68  */
69 static struct s_cmds fd_cmds[] = {
70    {"append open",  append_open_session},
71    {"append data",  append_data_cmd},
72    {"append end",   append_end_session},
73    {"append close", append_close_session},
74    {"read open",    read_open_session},
75    {"read data",    read_data_cmd},
76    {"read close",   read_close_session},
77    {"bootstrap",    bootstrap_cmd},
78    {NULL,           NULL}                  /* list terminator */
79 };
80
81 /* Commands from the File daemon that require additional scanning */
82 static char read_open[]       = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
83
84 /* Responses sent to the File daemon */
85 static char NO_open[]         = "3901 Error session already open\n";
86 static char NOT_opened[]      = "3902 Error session not opened\n";
87 static char OK_end[]          = "3000 OK end\n";
88 static char OK_close[]        = "3000 OK close Status = %d\n";
89 static char OK_open[]         = "3000 OK open ticket = %d\n";
90 static char OK_append[]       = "3000 OK append data\n";
91 static char ERROR_append[]    = "3903 Error append data\n";
92 static char OK_bootstrap[]    = "3000 OK bootstrap\n";
93 static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
94
95 /* Information sent to the Director */
96 static char Job_start[] = "3010 Job %s start\n";
97 char Job_end[]   =
98    "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n";
99
100 /*
101  * Run a File daemon Job -- File daemon already authorized
102  *
103  * Basic task here is:
104  * - Read a command from the File daemon
105  * - Execute it
106  *
107  */
108 void run_job(JCR *jcr)
109 {
110    int i;
111    bool found, quit;
112    BSOCK *fd = jcr->file_bsock;
113    BSOCK *dir = jcr->dir_bsock;
114    char ec1[30];
115
116
117    fd->jcr = jcr;
118    dir->jcr = jcr;
119    Dmsg1(120, "Start run Job=%s\n", jcr->Job);
120    bnet_fsend(dir, Job_start, jcr->Job);
121    jcr->start_time = time(NULL);
122    jcr->run_time = jcr->start_time;
123    set_jcr_job_status(jcr, JS_Running);
124    dir_send_job_status(jcr);          /* update director */
125    for (quit=false; !quit;) {
126       int stat;
127
128       /* Read command coming from the File daemon */
129       stat = bnet_recv(fd);
130       if (is_bnet_stop(fd)) {         /* hardeof or error */
131          break;                       /* connection terminated */
132       }
133       if (stat <= 0) {
134          continue;                    /* ignore signals and zero length msgs */
135       }
136       Dmsg1(110, "<filed: %s", fd->msg);
137       found = false;
138       for (i=0; fd_cmds[i].cmd; i++) {
139          if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
140             found = true;               /* indicate command found */
141             if (!fd_cmds[i].func(jcr)) {    /* do command */
142                set_jcr_job_status(jcr, JS_ErrorTerminated);
143                quit = true;
144             }
145             break;
146          }
147       }
148       if (!found) {                   /* command not found */
149          Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
150          bnet_fsend(fd, ferrmsg);
151          break;
152       }
153    }
154    bnet_sig(fd, BNET_TERMINATE);      /* signal to FD job is done */
155    jcr->end_time = time(NULL);
156    dequeue_messages(jcr);             /* send any queued messages */
157    set_jcr_job_status(jcr, JS_Terminated);
158    generate_daemon_event(jcr, "JobEnd");
159    bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
160       edit_uint64(jcr->JobBytes, ec1));
161    bnet_sig(dir, BNET_EOD);           /* send EOD to Director daemon */
162    return;
163 }
164
165
166 /*
167  *   Append Data command
168  *     Open Data Channel and receive Data for archiving
169  *     Write the Data to the archive device
170  */
171 static bool append_data_cmd(JCR *jcr)
172 {
173    BSOCK *fd = jcr->file_bsock;
174
175    Dmsg1(120, "Append data: %s", fd->msg);
176    if (jcr->session_opened) {
177       Dmsg1(110, "<bfiled: %s", fd->msg);
178       jcr->JobType = JT_BACKUP;
179       if (do_append_data(jcr)) {
180          return bnet_fsend(fd, OK_append);
181       } else {
182          bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */
183          bnet_fsend(fd, ERROR_append);
184       }
185    } else {
186       bnet_fsend(fd, NOT_opened);
187    }
188    return false;
189 }
190
191 static bool append_end_session(JCR *jcr)
192 {
193    BSOCK *fd = jcr->file_bsock;
194
195    Dmsg1(120, "store<file: %s", fd->msg);
196    if (!jcr->session_opened) {
197       bnet_fsend(fd, NOT_opened);
198       return false;
199    }
200    set_jcr_job_status(jcr, JS_Terminated);
201    return bnet_fsend(fd, OK_end);
202 }
203
204
205 /*
206  * Append Open session command
207  *
208  */
209 static bool append_open_session(JCR *jcr)
210 {
211    BSOCK *fd = jcr->file_bsock;
212
213    Dmsg1(120, "Append open session: %s", fd->msg);
214    if (jcr->session_opened) {
215       bnet_fsend(fd, NO_open);
216       return false;
217    }
218
219    jcr->session_opened = true;
220
221    /* Send "Ticket" to File Daemon */
222    bnet_fsend(fd, OK_open, jcr->VolSessionId);
223    Dmsg1(110, ">filed: %s", fd->msg);
224
225    return true;
226 }
227
228 /*
229  *   Append Close session command
230  *      Close the append session and send back Statistics
231  *         (need to fix statistics)
232  */
233 static bool append_close_session(JCR *jcr)
234 {
235    BSOCK *fd = jcr->file_bsock;
236
237    Dmsg1(120, "<filed: %s", fd->msg);
238    if (!jcr->session_opened) {
239       bnet_fsend(fd, NOT_opened);
240       return false;
241    }
242    /* Send final statistics to File daemon */
243    bnet_fsend(fd, OK_close, jcr->JobStatus);
244    Dmsg1(120, ">filed: %s", fd->msg);
245
246    bnet_sig(fd, BNET_EOD);            /* send EOD to File daemon */
247
248    jcr->session_opened = false;
249    return true;
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 bool read_data_cmd(JCR *jcr)
259 {
260    BSOCK *fd = jcr->file_bsock;
261
262    Dmsg1(120, "Read data: %s", 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 false;
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 bool 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 false;
286    }
287
288    if (sscanf(fd->msg, read_open, jcr->read_dcr->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 false;
294       }
295       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
296          jcr->JobId, jcr->read_dcr->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    jcr->session_opened = true;
304    jcr->JobType = JT_RESTORE;
305
306    /* Send "Ticket" to File Daemon */
307    bnet_fsend(fd, OK_open, jcr->VolSessionId);
308    Dmsg1(110, ">filed: %s", fd->msg);
309
310    return true;
311 }
312
313 static bool bootstrap_cmd(JCR *jcr)
314 {
315    return get_bootstrap_file(jcr, jcr->file_bsock);
316 }
317
318 bool get_bootstrap_file(JCR *jcr, BSOCK *sock)
319 {
320    POOLMEM *fname = get_pool_memory(PM_FNAME);
321    FILE *bs;
322    bool ok = false;
323
324    if (jcr->RestoreBootstrap) {
325       unlink(jcr->RestoreBootstrap);
326       free_pool_memory(jcr->RestoreBootstrap);
327    }
328    Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
329       jcr->Job);
330    Dmsg1(400, "bootstrap=%s\n", fname);
331    jcr->RestoreBootstrap = fname;
332    bs = fopen(fname, "a+");           /* create file */
333    if (!bs) {
334       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
335          jcr->RestoreBootstrap, strerror(errno));
336       goto bail_out;
337    }
338    while (bnet_recv(sock) >= 0) {
339        Dmsg1(400, "stored<filed: bootstrap file %s", sock->msg);
340        fputs(sock->msg, bs);
341    }
342    fclose(bs);
343    jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
344    if (!jcr->bsr) {
345       Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
346       goto bail_out;
347    }
348    if (debug_level > 20) {
349       dump_bsr(jcr->bsr, true);
350    }
351    ok = true;
352
353 bail_out:
354    unlink(jcr->RestoreBootstrap);
355    free_pool_memory(jcr->RestoreBootstrap);
356    jcr->RestoreBootstrap = NULL;
357    if (!ok) {
358       bnet_fsend(sock, ERROR_bootstrap);
359       return false;
360    }
361    return bnet_fsend(sock, OK_bootstrap);
362 }
363
364
365 /*
366  *   Read Close session command
367  *      Close the read session
368  */
369 static bool read_close_session(JCR *jcr)
370 {
371    BSOCK *fd = jcr->file_bsock;
372
373    Dmsg1(120, "Read close session: %s\n", fd->msg);
374    if (!jcr->session_opened) {
375       bnet_fsend(fd, NOT_opened);
376       return false;
377    }
378    /* Send final statistics to File daemon */
379    bnet_fsend(fd, OK_close);
380    Dmsg1(160, ">filed: %s\n", fd->msg);
381
382    bnet_sig(fd, BNET_EOD);          /* send EOD to File daemon */
383
384    jcr->session_opened = false;
385    return true;
386 }