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