]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/getmsg.c
ae670d97af198c2c4bb6d9f22e25132dd07dc26e
[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    if (jcr->SDJobStatus == JS_Incomplete) {
98       jcr->setJobStatus(JS_Incomplete);
99    }
100       
101 }
102
103 /*
104  * Get a message
105  *  Call appropriate processing routine
106  *  If it is not a Jmsg or a ReqCat message,
107  *   return it to the caller.
108  *
109  *  This routine is called to get the next message from
110  *  another daemon. If the message is in canonical message
111  *  format and the type is known, it will be dispatched
112  *  to the appropriate handler.  If the message is
113  *  in any other format, it will be returned.
114  *
115  *  E.g. any message beginning with a digit will be passed   
116  *       through to the caller.
117  *  All other messages are expected begin with some identifier
118  *    -- for the moment only the first character is checked, but
119  *    at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
120  *    could be checked. This is followed by Job=Jobname <user-defined>
121  *    info. The identifier is used to dispatch the message to the right
122  *    place (Job message, catalog request, ...). The Job is used to lookup
123  *    the JCR so that the action is performed on the correct jcr, and
124  *    the rest of the message is up to the user.  Note, DevUpd uses
125  *    *System* for the Job name, and hence no JCR is obtained. This   
126  *    is a *rare* case where a jcr is not really needed.
127  *
128  */
129 int bget_dirmsg(BSOCK *bs)
130 {
131    int32_t n = BNET_TERMINATE;
132    char Job[MAX_NAME_LENGTH];
133    char MsgType[20];
134    int type;
135    utime_t mtime;                     /* message time */
136    JCR *jcr = bs->jcr();
137    char *msg;
138
139    for ( ; !bs->is_stop() && !bs->is_timed_out(); ) {
140       n = bs->recv();
141       Dmsg2(100, "bget_dirmsg %d: %s\n", n, bs->msg);
142
143       if (bs->is_stop() || bs->is_timed_out()) {
144          return n;                    /* error or terminate */
145       }
146       if (n == BNET_SIGNAL) {          /* handle signal */
147          /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
148          switch (bs->msglen) {
149          case BNET_EOD:            /* end of data */
150             return n;
151          case BNET_EOD_POLL:
152             bs->fsend(OK_msg);/* send response */
153             return n;              /* end of data */
154          case BNET_TERMINATE:
155             bs->set_terminated();
156             return n;
157          case BNET_POLL:
158             bs->fsend(OK_msg); /* send response */
159             break;
160          case BNET_HEARTBEAT:
161 //          encode_time(time(NULL), Job);
162 //          Dmsg1(100, "%s got heartbeat.\n", Job);
163             break;
164          case BNET_HB_RESPONSE:
165             break;
166          case BNET_STATUS:
167             /* *****FIXME***** Implement more completely */
168             bs->fsend("Status OK\n");
169             bs->signal(BNET_EOD);
170             break;
171          case BNET_BTIME:             /* send Bacula time */
172             char ed1[50];
173             bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
174             break;
175          default:
176             Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
177             return n;
178          }
179          continue;
180       }
181
182       /* Handle normal data */
183
184       if (n > 0 && B_ISDIGIT(bs->msg[0])) {      /* response? */
185          return n;                    /* yes, return it */
186       }
187
188       /*
189        * If we get here, it must be a request.  Either
190        *  a message to dispatch, or a catalog request.
191        *  Try to fulfill it.
192        */
193       if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
194          Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
195          continue;
196       }
197
198       /* Skip past "Jmsg Job=nnn" */
199       if (!(msg=find_msg_start(bs->msg))) {
200          Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
201          continue;
202       }
203
204       /*
205        * Here we are expecting a message of the following format:
206        *   Jmsg Job=nnn type=nnn level=nnn Message-string
207        * Note, level should really be mtime, but that changes
208        *   the protocol.
209        */
210       if (bs->msg[0] == 'J') {           /* Job message */
211          if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld",
212                     Job, &type, &mtime) != 3) {
213             Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
214             continue;
215          }
216          Dmsg1(900, "Got msg: %s\n", bs->msg);
217          skip_spaces(&msg);
218          skip_nonspaces(&msg);        /* skip type=nnn */
219          skip_spaces(&msg);
220          skip_nonspaces(&msg);        /* skip level=nnn */
221          if (*msg == ' ') {
222             msg++;                    /* skip leading space */
223          }
224          Dmsg1(900, "Dispatch msg: %s", msg);
225          dispatch_message(jcr, type, mtime, msg);
226          continue;
227       }
228       /*
229        * Here we expact a CatReq message
230        *   CatReq Job=nn Catalog-Request-Message
231        */
232       if (bs->msg[0] == 'C') {        /* Catalog request */
233          Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
234          catalog_request(jcr, bs);
235          continue;
236       }
237       if (bs->msg[0] == 'U') {        /* SD sending attributes */
238          Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
239          catalog_update(jcr, bs);
240          continue;
241       }
242       if (bs->msg[0] == 'B') {        /* SD sending file spool attributes */
243          Dmsg2(100, "Blast attributes jcr 0x%x: %s", jcr, bs->msg);
244          char filename[256];
245          if (sscanf(bs->msg, "BlastAttr Job=%127s File=%255s", 
246                     Job, filename) != 2) {
247             Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
248             continue;
249          }
250          unbash_spaces(filename);
251          if (despool_attributes_from_file(jcr, filename)) {
252             bs->fsend("1000 OK BlastAttr\n");
253          } else {
254             bs->fsend("1990 ERROR BlastAttr\n");
255          }
256          continue;
257       }
258       if (bs->msg[0] == 'M') {        /* Mount request */
259          Dmsg1(900, "Mount req: %s", bs->msg);
260          mount_request(jcr, bs, msg);
261          continue;
262       }
263       if (bs->msg[0] == 'S') {       /* Status change */
264          int JobStatus;
265          char Job[MAX_NAME_LENGTH];
266          if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
267             set_jcr_sd_job_status(jcr, JobStatus); /* current status */
268          } else {
269             Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
270          }
271          continue;
272       }
273 #ifdef needed
274       /* No JCR for Device Updates! */
275       if (bs->msg[0] = 'D') {         /* Device update */
276          DEVICE *dev;
277          POOL_MEM dev_name, changer_name, media_type, volume_name;
278          int dev_open, dev_append, dev_read, dev_labeled;
279          int dev_offline, dev_autochanger, dev_autoselect;
280          int dev_num_writers, dev_max_writers, dev_reserved;
281          uint64_t dev_read_time, dev_write_time, dev_write_bytes, dev_read_bytes;
282          uint64_t dev_PoolId;
283          Dmsg1(100, "<stored: %s", bs->msg);
284          if (sscanf(bs->msg, Device_update,
285              &Job, dev_name.c_str(),
286              &dev_append, &dev_read,
287              &dev_num_writers, &dev_open,
288              &dev_labeled, &dev_offline, &dev_reserved,
289              &dev_max_writers, &dev_autoselect, 
290              &dev_autochanger, 
291              changer_name.c_str(), media_type.c_str(),
292              volume_name.c_str(),
293              &dev_read_time, &dev_write_time, &dev_read_bytes,
294              &dev_write_bytes) != 19) {
295             Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
296          } else {
297             unbash_spaces(dev_name);
298             dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
299             if (!dev) {
300                continue;
301             }
302             unbash_spaces(changer_name);
303             unbash_spaces(media_type);
304             unbash_spaces(volume_name);
305             bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
306             bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
307             bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
308             /* Note, these are copied because they are boolean rather than
309              *  integer.
310              */
311             dev->open = dev_open;
312             dev->append = dev_append;
313             dev->read = dev_read;
314             dev->labeled = dev_labeled;
315             dev->offline = dev_offline;
316             dev->autoselect = dev_autoselect;
317             dev->autochanger = dev_autochanger > 0;
318             dev->num_drives = dev_autochanger;    /* does double duty */
319             dev->PoolId = dev_PoolId;
320             dev->num_writers = dev_num_writers;
321             dev->max_writers = dev_max_writers;
322             dev->reserved = dev_reserved;
323             dev->found = true;
324             dev->DevReadTime = dev_read_time; /* TODO : have to update database */
325             dev->DevWriteTime = dev_write_time;
326             dev->DevReadBytes = dev_read_bytes;
327             dev->DevWriteBytes = dev_write_bytes;
328          }
329          continue;
330       }
331 #endif
332       return n;
333    }
334    return n;
335 }
336
337 static char *find_msg_start(char *msg)
338 {
339    char *p = msg;
340
341    skip_nonspaces(&p);                /* skip message type */
342    skip_spaces(&p);
343    skip_nonspaces(&p);                /* skip Job */
344    skip_spaces(&p);                   /* after spaces come the message */
345    return p;
346 }
347
348 /*
349  * Get response from FD or SD to a command we
350  * sent. Check that the response agrees with what we expect.
351  *
352  *  Returns: false on failure
353  *           true  on success
354  */
355 bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
356 {
357    int n;
358
359    if (is_bnet_error(bs)) {
360       return false;
361    }
362    if ((n = bget_dirmsg(bs)) >= 0) {
363       if (strcmp(bs->msg, resp) == 0) {
364          return true;
365       }
366       if (prtmsg == DISPLAY_ERROR) {
367          Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
368             cmd, resp, bs->msg);
369       }
370       return false;
371    }
372    Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
373          cmd, bnet_strerror(bs));
374    return false;
375 }