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