]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/fd_cmds.c
c8ad493f75d07a5414d2dff3b97be3bc525cf8f8
[bacula/bacula] / bacula / src / stored / fd_cmds.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * This file handles commands from the File daemon.
21  *
22  *   Written by Kern Sibbald, MM
23  *
24  * We get here because the Director has initiated a Job with
25  *  the Storage daemon, then done the same with the File daemon,
26  *  then when the Storage daemon receives a proper connection from
27  *  the File daemon, control is passed here to handle the
28  *  subsequent File daemon commands.
29  */
30
31 #include "bacula.h"
32 #include "stored.h"
33
34 /* Forward referenced functions */
35 static bool response(JCR *jcr, BSOCK *bs, const char *resp, const char *cmd);
36
37 /* Imported variables */
38 extern STORES *me;
39
40 /* Static variables */
41 static char ferrmsg[]      = "3900 Invalid command\n";
42 static char OK_data[]      = "3000 OK data\n";
43
44 /* Imported functions */
45 extern bool do_append_data(JCR *jcr);
46 extern bool do_read_data(JCR *jcr);
47 extern bool do_backup_job(JCR *jcr);
48
49 /* Forward referenced FD commands */
50 static bool append_open_session(JCR *jcr);
51 static bool append_close_session(JCR *jcr);
52 static bool append_data_cmd(JCR *jcr);
53 static bool append_end_session(JCR *jcr);
54 static bool read_open_session(JCR *jcr);
55 static bool read_data_cmd(JCR *jcr);
56 static bool read_close_session(JCR *jcr);
57 static bool read_control_cmd(JCR *jcr);
58 static bool sd_testnetwork_cmd(JCR *jcr);
59
60 /* Exported function */
61 bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
62
63 struct s_cmds {
64    const char *cmd;
65    bool (*func)(JCR *jcr);
66 };
67
68 /*
69  * The following are the recognized commands from the File daemon
70  */
71 static struct s_cmds fd_cmds[] = {
72    {"append open",  append_open_session},
73    {"append data",  append_data_cmd},
74    {"append end",   append_end_session},
75    {"append close", append_close_session},
76    {"read open",    read_open_session},
77    {"read data",    read_data_cmd},
78    {"read close",   read_close_session},
79    {"read control", read_control_cmd},
80    {"testnetwork",  sd_testnetwork_cmd},
81    {NULL,           NULL}                  /* list terminator */
82 };
83
84 /* Commands from the File daemon that require additional scanning */
85 static char read_open[]       = "read open session = %127s %ld %ld %ld %ld %ld %ld\n";
86
87 /* Responses sent to the File daemon */
88 static char NO_open[]         = "3901 Error session already open\n";
89 static char NOT_opened[]      = "3902 Error session not opened\n";
90 static char ERROR_open[]      = "3904 Error open session, bad parameters\n";
91 static char OK_end[]          = "3000 OK end\n";
92 static char OK_close[]        = "3000 OK close Status = %d\n";
93 static char OK_open[]         = "3000 OK open ticket = %d\n";
94 static char ERROR_append[]    = "3903 Error append data: %s\n";
95
96 /* Information sent to the Director */
97 static char Job_start[] = "3010 Job %s start\n";
98 char Job_end[] =
99    "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s JobErrors=%u ErrMsg=%s\n";
100
101 /*
102  * Run a Client Job -- Client already authorized
103  *  Note: this can be either a backup or restore or
104  *    migrate/copy job.
105  *
106  * Basic task here is:
107  * - Read a command from the Client -- FD or SD
108  * - Execute it
109  *
110  */
111 void run_job(JCR *jcr)
112 {
113    BSOCK *dir = jcr->dir_bsock;
114    char ec1[30];
115
116    dir->set_jcr(jcr);
117    Dmsg1(120, "Start run Job=%s\n", jcr->Job);
118    dir->fsend(Job_start, jcr->Job);
119    jcr->start_time = time(NULL);
120    jcr->run_time = jcr->start_time;
121    jcr->sendJobStatus(JS_Running);
122
123    /* TODO: Remove when the new match_all is well tested */
124    jcr->use_new_match_all = use_new_match_all;
125    /*
126     * A migrate or copy job does both a restore (read_data) and
127     *   a backup (append_data).
128     * Otherwise we do the commands that the client sends
129     *   which are for normal backup or restore jobs.
130     */
131    Dmsg3(050, "==== JobType=%c run_job=%d sd_client=%d\n", jcr->getJobType(), jcr->JobId, jcr->sd_client);
132    if (jcr->is_JobType(JT_BACKUP) && jcr->sd_client) {
133       jcr->session_opened = true;
134       Dmsg0(050, "Do: receive for 3000 OK data then append\n");
135       if (!response(jcr, jcr->file_bsock, "3000 OK data\n", "Append data")) {
136          Dmsg1(050, "Expect: 3000 OK data, got: %s", jcr->file_bsock->msg);
137          Jmsg0(jcr, M_FATAL, 0, "Append data not accepted\n");
138          goto bail_out;
139       }
140       append_data_cmd(jcr);
141       append_end_session(jcr);
142    } else if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY)) {
143       jcr->session_opened = true;
144       /* send "3000 OK data" now to avoid a dead lock, the other side is also
145        * waiting for one. The old peace of code was reading the "3000 OK" reply
146        * at the end of the backup (not really appropriate).
147        * dedup need duplex communication with the other side and need the
148        * "3000 OK" to be out of the socket, and be handle here by the right
149        * peace of code */
150       Dmsg0(215, "send OK_data\n");
151       jcr->file_bsock->fsend(OK_data);
152       jcr->is_ok_data_sent = true;
153       Dmsg1(050, "Do: read_data_cmd file_bsock=%p\n", jcr->file_bsock);
154       Dmsg0(050, "Do: receive for 3000 OK data then read\n");
155       if (!response(jcr, jcr->file_bsock, "3000 OK data\n", "Data received")) {
156          Dmsg1(050, "Expect 3000 OK data, got: %s", jcr->file_bsock->msg);
157          Jmsg0(jcr, M_FATAL, 0, "Read data not accepted\n");
158          jcr->file_bsock->signal(BNET_EOD);
159          goto bail_out;
160       }
161       read_data_cmd(jcr);
162       jcr->file_bsock->signal(BNET_EOD);
163    } else {
164       /* Either a Backup or Restore job */
165       Dmsg0(050, "Do: do_client_commands\n");
166       do_client_commands(jcr);
167    }
168 bail_out:
169    jcr->end_time = time(NULL);
170    flush_jobmedia_queue(jcr);
171    dequeue_messages(jcr);             /* send any queued messages */
172    jcr->setJobStatus(JS_Terminated);
173    generate_daemon_event(jcr, "JobEnd");
174    generate_plugin_event(jcr, bsdEventJobEnd);
175    bash_spaces(jcr->StatusErrMsg);
176    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
177               edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors, jcr->StatusErrMsg);
178    Dmsg1(100, "==== %s", dir->msg);
179    unbash_spaces(jcr->StatusErrMsg);
180    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
181    free_plugins(jcr);                 /* release instantiated plugins */
182    garbage_collect_memory_pool();
183    return;
184 }
185
186 /*
187  * Now talk to the Client (FD/SD) and do what he says
188  */
189 void do_client_commands(JCR *jcr)
190 {
191    int i;
192    bool found, quit;
193    BSOCK *fd = jcr->file_bsock;
194
195    fd->set_jcr(jcr);
196    for (quit=false; !quit;) {
197       int stat;
198
199       /* Read command coming from the File daemon */
200       stat = fd->recv();
201       if (fd->is_stop()) {            /* hard eof or error */
202          break;                       /* connection terminated */
203       }
204       if (stat <= 0) {
205          continue;                    /* ignore signals and zero length msgs */
206       }
207       Dmsg1(110, "<filed: %s", fd->msg);
208       found = false;
209       for (i=0; fd_cmds[i].cmd; i++) {
210          if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
211             found = true;               /* indicate command found */
212             jcr->errmsg[0] = 0;
213             if (!fd_cmds[i].func(jcr)) {    /* do command */
214                /* Note fd->msg command may be destroyed by comm activity */
215                if (!job_canceled(jcr)) {
216                   strip_trailing_junk(fd->msg);
217                   if (jcr->errmsg[0]) {
218                      strip_trailing_junk(jcr->errmsg);
219                      Jmsg2(jcr, M_FATAL, 0, _("Command error with FD msg=\"%s\", SD hanging up. ERR=%s\n"),
220                            fd->msg, jcr->errmsg);
221                   } else {
222                      Jmsg1(jcr, M_FATAL, 0, _("Command error with FD msg=\"%s\", SD hanging up.\n"),
223                         fd->msg);
224                   }
225                   jcr->setJobStatus(JS_ErrorTerminated);
226                }
227                quit = true;
228             }
229             break;
230          }
231       }
232       if (!found) {                   /* command not found */
233          if (!job_canceled(jcr)) {
234             Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg);
235             Dmsg1(110, "<filed: Command not found: %s\n", fd->msg);
236          }
237          fd->fsend(ferrmsg);
238          break;
239       }
240    }
241    fd->signal(BNET_TERMINATE);        /* signal to FD job is done */
242 }
243
244 /*
245  *   Append Data command
246  *     Open Data Channel and receive Data for archiving
247  *     Write the Data to the archive device
248  */
249 static bool append_data_cmd(JCR *jcr)
250 {
251    BSOCK *fd = jcr->file_bsock;
252
253    Dmsg1(120, "Append data: %s", fd->msg);
254    if (jcr->session_opened) {
255       Dmsg1(110, "<bfiled: %s", fd->msg);
256       jcr->setJobType(JT_BACKUP);
257       jcr->errmsg[0] = 0;
258       if (do_append_data(jcr)) {
259          return true;
260       } else {
261          fd->suppress_error_messages(true); /* ignore errors at this point */
262          fd->fsend(ERROR_append, jcr->errmsg);
263       }
264    } else {
265       pm_strcpy(jcr->errmsg, _("Attempt to append on non-open session.\n"));
266       fd->fsend(NOT_opened);
267    }
268    return false;
269 }
270
271 static bool append_end_session(JCR *jcr)
272 {
273    BSOCK *fd = jcr->file_bsock;
274
275    Dmsg1(120, "store<file: %s", fd->msg);
276    if (!jcr->session_opened) {
277       pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
278       fd->fsend(NOT_opened);
279       return false;
280    }
281    return fd->fsend(OK_end);
282 }
283
284 /*
285  * Test the FD/SD connectivity
286  */
287 static bool sd_testnetwork_cmd(JCR *jcr)
288 {
289    BSOCK *fd = jcr->file_bsock;
290    int64_t nb=0;
291    bool can_compress, ok=true;
292
293    if (sscanf(fd->msg, "testnetwork bytes=%lld", &nb) != 1) {
294       return false;
295    }
296    /* We disable the comline compression for this test */
297    can_compress = fd->can_compress();
298    fd->clear_compress();
299
300    /* First, get data from the FD */
301    while (fd->recv() > 0) { }
302
303    /* Then, send back data to the FD */
304    memset(fd->msg, 0xBB, sizeof_pool_memory(fd->msg));
305    fd->msglen = sizeof_pool_memory(fd->msg);
306
307    while(nb > 0 && ok) {
308       if (nb < fd->msglen) {
309          fd->msglen = nb;
310       }
311       ok = fd->send();
312       nb -= fd->msglen;
313    }
314    fd->signal(BNET_EOD);
315
316    if (can_compress) {
317       fd->set_compress();
318    }
319    return true;
320 }
321
322 /*
323  * Append Open session command
324  *
325  */
326 static bool append_open_session(JCR *jcr)
327 {
328    BSOCK *fd = jcr->file_bsock;
329
330    Dmsg1(120, "Append open session: %s", fd->msg);
331    if (jcr->session_opened) {
332       pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n"));
333       fd->fsend(NO_open);
334       return false;
335    }
336
337    jcr->session_opened = true;
338
339    /* Send "Ticket" to File Daemon */
340    fd->fsend(OK_open, jcr->VolSessionId);
341    Dmsg1(110, ">filed: %s", fd->msg);
342
343    return true;
344 }
345
346 /*
347  *   Append Close session command
348  *      Close the append session and send back Statistics
349  *         (need to fix statistics)
350  */
351 static bool append_close_session(JCR *jcr)
352 {
353    BSOCK *fd = jcr->file_bsock;
354
355    Dmsg1(120, "<filed: %s", fd->msg);
356    if (!jcr->session_opened) {
357       pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n"));
358       fd->fsend(NOT_opened);
359       return false;
360    }
361    /* Send final statistics to File daemon */
362    fd->fsend(OK_close, jcr->JobStatus);
363    Dmsg1(120, ">filed: %s", fd->msg);
364
365    fd->signal(BNET_EOD);              /* send EOD to File daemon */
366
367    jcr->session_opened = false;
368    return true;
369 }
370
371 /*
372  *   Read Data command
373  *     Open Data Channel, read the data from
374  *     the archive device and send to File
375  *     daemon.
376  */
377 static bool read_data_cmd(JCR *jcr)
378 {
379    BSOCK *fd = jcr->file_bsock;
380
381    Dmsg1(120, "Read data: %s", fd->msg);
382    if (jcr->session_opened) {
383       Dmsg1(120, "<bfiled: %s", fd->msg);
384       return do_read_data(jcr);
385    } else {
386       pm_strcpy(jcr->errmsg, _("Attempt to read on non-open session.\n"));
387       fd->fsend(NOT_opened);
388       return false;
389    }
390 }
391
392 /*
393  * Read Open session command
394  *
395  *  We need to scan for the parameters of the job
396  *    to be restored.
397  */
398 static bool read_open_session(JCR *jcr)
399 {
400    BSOCK *fd = jcr->file_bsock;
401
402    Dmsg1(120, "%s", fd->msg);
403    if (jcr->session_opened) {
404       pm_strcpy(jcr->errmsg, _("Attempt to open an already open session.\n"));
405       fd->fsend(NO_open);
406       return false;
407    }
408
409    if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
410          &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
411          &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
412       Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
413          jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
414          jcr->read_VolSessionTime);
415       Dmsg4(100, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
416          jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
417          jcr->read_EndBlock);
418
419    } else {
420       pm_strcpy(jcr->errmsg, _("Cannot open session, received bad parameters.\n"));
421       fd->fsend(ERROR_open);
422       return false;
423    }
424
425    jcr->session_opened = true;
426    jcr->setJobType(JT_RESTORE);
427
428    /* Send "Ticket" to File Daemon */
429    fd->fsend(OK_open, jcr->VolSessionId);
430    Dmsg1(110, ">filed: %s", fd->msg);
431
432    return true;
433 }
434
435 static bool read_control_cmd(JCR *jcr)
436 {
437    BSOCK *fd = jcr->file_bsock;
438
439    Dmsg1(120, "Read control: %s\n", fd->msg);
440    if (!jcr->session_opened) {
441       fd->fsend(NOT_opened);
442       return false;
443    }
444    jcr->interactive_session = true;
445    return true;
446 }
447
448 /*
449  *   Read Close session command
450  *      Close the read session
451  */
452 static bool read_close_session(JCR *jcr)
453 {
454    BSOCK *fd = jcr->file_bsock;
455
456    Dmsg1(120, "Read close session: %s\n", fd->msg);
457    if (!jcr->session_opened) {
458       fd->fsend(NOT_opened);
459       return false;
460    }
461    /* Send final close msg to File daemon */
462    fd->fsend(OK_close, jcr->JobStatus);
463    Dmsg1(160, ">filed: %s\n", fd->msg);
464
465    fd->signal(BNET_EOD);            /* send EOD to File daemon */
466
467    jcr->session_opened = false;
468    return true;
469 }
470
471 /*
472  * Get response from FD or SD
473  * sent. Check that the response agrees with what we expect.
474  *
475  *  Returns: false on failure
476  *           true  on success
477  */
478 static bool response(JCR *jcr, BSOCK *bs, const char *resp, const char *cmd)
479 {
480    int n;
481
482    if (bs->is_error()) {
483       return false;
484    }
485    if ((n = bs->recv()) >= 0) {
486       if (strcmp(bs->msg, resp) == 0) {
487          return true;
488       }
489       Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
490             cmd, resp, bs->msg);
491       return false;
492    }
493    Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
494          cmd, bs->bstrerror());
495    return false;
496 }