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