]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/getmsg.c
Update copyright
[bacula/bacula] / bacula / src / dird / getmsg.c
1 /*
2  *
3  *   Bacula Director -- routines to receive network data and
4  *    handle network signals. These routines handle the connections
5  *    to the Storage daemon and the File daemon.
6  *
7  *     Kern Sibbald, August MM
8  *
9  *    This routine runs as a thread and must be thread reentrant.
10  *
11  *  Basic tasks done here:
12  *    Handle  network signals (signals).
13  *       Signals always have return status 0 from bnet_recv() and
14  *       a zero or negative message length.
15  *    Pass appropriate messages back to the caller (responses).
16  *       Responses always have a digit as the first character.
17  *    Handle requests for message and catalog services (requests).
18  *       Requests are any message that does not begin with a digit.
19  *       In affect, they are commands.
20  *
21  *   Version $Id$
22  */
23 /*
24    Bacula® - The Network Backup Solution
25
26    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
27
28    The main author of Bacula is Kern Sibbald, with contributions from
29    many others, a complete list can be found in the file AUTHORS.
30    This program is Free Software; you can redistribute it and/or
31    modify it under the terms of version two of the GNU General Public
32    License as published by the Free Software Foundation plus additions
33    that are listed in the file LICENSE.
34
35    This program is distributed in the hope that it will be useful, but
36    WITHOUT ANY WARRANTY; without even the implied warranty of
37    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38    General Public License for more details.
39
40    You should have received a copy of the GNU General Public License
41    along with this program; if not, write to the Free Software
42    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
43    02110-1301, USA.
44
45    Bacula® is a registered trademark of John Walker.
46    The licensor of Bacula is the Free Software Foundation Europe
47    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
48    Switzerland, email:ftf@fsfeurope.org.
49 */
50
51 #include "bacula.h"
52 #include "dird.h"
53
54 /* Forward referenced functions */
55 static char *find_msg_start(char *msg);
56
57 static char Job_status[] = "Status Job=%127s JobStatus=%d\n";
58 #ifdef needed
59 static char Device_update[]   = "DevUpd Job=%127s "
60    "device=%127s "
61    "append=%d read=%d num_writers=%d "
62    "open=%d labeled=%d offline=%d "
63    "reserved=%d max_writers=%d "
64    "autoselect=%d autochanger=%d "
65    "changer_name=%127s media_type=%127s volume_name=%127s\n";
66 #endif
67
68
69 static char OK_msg[] = "1000 OK\n";
70
71 /*
72  * Get a message
73  *  Call appropriate processing routine
74  *  If it is not a Jmsg or a ReqCat message,
75  *   return it to the caller.
76  *
77  *  This routine is called to get the next message from
78  *  another daemon. If the message is in canonical message
79  *  format and the type is known, it will be dispatched
80  *  to the appropriate handler.  If the message is
81  *  in any other format, it will be returned.
82  *
83  *  E.g. any message beginning with a digit will be passed   
84  *       through to the caller.
85  *  All other messages are expected begin with some identifier
86  *    -- for the moment only the first character is checked, but
87  *    at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
88  *    could be checked. This is followed by Job=Jobname <user-defined>
89  *    info. The identifier is used to dispatch the message to the right
90  *    place (Job message, catalog request, ...). The Job is used to lookup
91  *    the JCR so that the action is performed on the correct jcr, and
92  *    the rest of the message is up to the user.  Note, DevUpd uses
93  *    *System* for the Job name, and hence no JCR is obtained. This   
94  *    is a *rare* case where a jcr is not really needed.
95  *
96  */
97 int bget_dirmsg(BSOCK *bs)
98 {
99    int32_t n;
100    char Job[MAX_NAME_LENGTH];
101    char MsgType[20];
102    int type, level;
103    JCR *jcr;
104    char *msg;
105
106    for (;;) {
107       n = bnet_recv(bs);
108       Dmsg2(900, "bget_dirmsg %d: %s", n, bs->msg);
109
110       if (is_bnet_stop(bs)) {
111          return n;                    /* error or terminate */
112       }
113       if (n == BNET_SIGNAL) {          /* handle signal */
114          /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
115          switch (bs->msglen) {
116          case BNET_EOD:            /* end of data */
117             return n;
118          case BNET_EOD_POLL:
119             bnet_fsend(bs, OK_msg);/* send response */
120             return n;              /* end of data */
121          case BNET_TERMINATE:
122             bs->terminated = 1;
123             return n;
124          case BNET_POLL:
125             bnet_fsend(bs, OK_msg); /* send response */
126             break;
127          case BNET_HEARTBEAT:
128 //          encode_time(time(NULL), Job);
129 //          Dmsg1(100, "%s got heartbeat.\n", Job);
130             break;
131          case BNET_HB_RESPONSE:
132             break;
133          case BNET_STATUS:
134             /* *****FIXME***** Implement more completely */
135             bnet_fsend(bs, "Status OK\n");
136             bnet_sig(bs, BNET_EOD);
137             break;
138          case BNET_BTIME:             /* send Bacula time */
139             char ed1[50];
140             bnet_fsend(bs, "btime %s\n", edit_uint64(get_current_btime(),ed1));
141             break;
142          default:
143             Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
144             return n;
145          }
146          continue;
147       }
148
149       /* Handle normal data */
150
151       if (n > 0 && B_ISDIGIT(bs->msg[0])) {      /* response? */
152          return n;                    /* yes, return it */
153       }
154
155       /*
156        * If we get here, it must be a request.  Either
157        *  a message to dispatch, or a catalog request.
158        *  Try to fulfill it.
159        */
160       if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
161          Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
162          continue;
163       }
164       if (strcmp(Job, "*System*") == 0) {
165          jcr = NULL;                  /* No jcr */
166       } else if (!(jcr=get_jcr_by_full_name(Job))) {
167          Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
168          continue;
169       }
170       Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
171
172       /* Skip past "Jmsg Job=nnn" */
173       if (!(msg=find_msg_start(bs->msg))) {
174          Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
175          free_jcr(jcr);
176          continue;
177       }
178
179       /*
180        * Here we are expecting a message of the following format:
181        *   Jmsg Job=nnn type=nnn level=nnn Message-string
182        */
183       if (bs->msg[0] == 'J') {           /* Job message */
184          if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
185                     Job, &type, &level) != 3) {
186             Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
187             free_jcr(jcr);
188             continue;
189          }
190          Dmsg1(900, "Got msg: %s\n", bs->msg);
191          skip_spaces(&msg);
192          skip_nonspaces(&msg);        /* skip type=nnn */
193          skip_spaces(&msg);
194          skip_nonspaces(&msg);        /* skip level=nnn */
195          if (*msg == ' ') {
196             msg++;                    /* skip leading space */
197          }
198          Dmsg1(900, "Dispatch msg: %s", msg);
199          dispatch_message(jcr, type, level, msg);
200          free_jcr(jcr);
201          continue;
202       }
203       /*
204        * Here we expact a CatReq message
205        *   CatReq Job=nn Catalog-Request-Message
206        */
207       if (bs->msg[0] == 'C') {        /* Catalog request */
208          Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
209          catalog_request(jcr, bs);
210          Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
211          free_jcr(jcr);
212          continue;
213       }
214       if (bs->msg[0] == 'U') {        /* Catalog update */
215          Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
216          catalog_update(jcr, bs);
217          Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
218          free_jcr(jcr);
219          continue;
220       }
221       if (bs->msg[0] == 'M') {        /* Mount request */
222          Dmsg1(900, "Mount req: %s", bs->msg);
223          mount_request(jcr, bs, msg);
224          free_jcr(jcr);
225          continue;
226       }
227       if (bs->msg[0] == 'S') {       /* Status change */
228          int JobStatus;
229          char Job[MAX_NAME_LENGTH];
230          if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
231             jcr->SDJobStatus = JobStatus; /* current status */
232          } else {
233             Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
234          }
235          free_jcr(jcr);
236          continue;
237       }
238 #ifdef needed
239       /* No JCR for Device Updates! */
240       if (bs->msg[0] = 'D') {         /* Device update */
241          DEVICE *dev;
242          POOL_MEM dev_name, changer_name, media_type, volume_name;
243          int dev_open, dev_append, dev_read, dev_labeled;
244          int dev_offline, dev_autochanger, dev_autoselect;
245          int dev_num_writers, dev_max_writers, dev_reserved;
246          uint64_t dev_PoolId;
247          Dmsg1(100, "<stored: %s", bs->msg);
248          if (sscanf(bs->msg, Device_update,
249              &Job, dev_name.c_str(),
250              &dev_append, &dev_read,
251              &dev_num_writers, &dev_open,
252              &dev_labeled, &dev_offline, &dev_reserved,
253              &dev_max_writers, &dev_autoselect, 
254              &dev_autochanger, 
255              changer_name.c_str(), media_type.c_str(),
256              volume_name.c_str()) != 15) {
257             Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
258          } else {
259             unbash_spaces(dev_name);
260             dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
261             if (!dev) {
262                continue;
263             }
264             unbash_spaces(changer_name);
265             unbash_spaces(media_type);
266             unbash_spaces(volume_name);
267             bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
268             bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
269             bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
270             /* Note, these are copied because they are boolean rather than
271              *  integer.
272              */
273             dev->open = dev_open;
274             dev->append = dev_append;
275             dev->read = dev_read;
276             dev->labeled = dev_labeled;
277             dev->offline = dev_offline;
278             dev->autoselect = dev_autoselect;
279             dev->autochanger = dev_autochanger > 0;
280             dev->num_drives = dev_autochanger;    /* does double duty */
281             dev->PoolId = dev_PoolId;
282             dev->num_writers = dev_num_writers;
283             dev->max_writers = dev_max_writers;
284             dev->reserved = dev_reserved;
285             dev->found = true;
286          }
287          continue;
288       }
289 #endif
290       return n;
291    }
292 }
293
294 static char *find_msg_start(char *msg)
295 {
296    char *p = msg;
297
298    skip_nonspaces(&p);                /* skip message type */
299    skip_spaces(&p);
300    skip_nonspaces(&p);                /* skip Job */
301    skip_spaces(&p);                   /* after spaces come the message */
302    return p;
303 }
304
305 /*
306  * Get response from FD or SD to a command we
307  * sent. Check that the response agrees with what we expect.
308  *
309  *  Returns: false on failure
310  *           true  on success
311  */
312 bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
313 {
314    int n;
315
316    if (is_bnet_error(bs)) {
317       return false;
318    }
319    if ((n = bget_dirmsg(bs)) >= 0) {
320       if (strcmp(bs->msg, resp) == 0) {
321          return true;
322       }
323       if (prtmsg == DISPLAY_ERROR) {
324          Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
325             cmd, resp, bs->msg);
326       }
327       return false;
328    }
329    Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
330          cmd, bnet_strerror(bs));
331    return false;
332 }