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