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