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