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