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