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