3 * Bacula Director -- routines to receive network data and
4 * handle network signals. These routines handle the connections
5 * to the Storage daemon and the File daemon.
7 * Kern Sibbald, August MM
9 * This routine runs as a thread and must be thread reentrant.
11 * Basic tasks done here:
12 * Handle network signals (signals).
13 * Signals always have return status 0 from bnet_recv() and
14 * a zero or negative message length.
15 * Pass appropriate messages back to the caller (responses).
16 * Responses always have a digit as the first character.
17 * Handle requests for message and catalog services (requests).
18 * Requests are any message that does not begin with a digit.
19 * In affect, they are commands.
24 Bacula® - The Network Backup Solution
26 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
28 The main author of Bacula is Kern Sibbald, with contributions from
29 many others, a complete list can be found in the file AUTHORS.
30 This program is Free Software; you can redistribute it and/or
31 modify it under the terms of version two of the GNU General Public
32 License as published by the Free Software Foundation plus additions
33 that are listed in the file LICENSE.
35 This program is distributed in the hope that it will be useful, but
36 WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 General Public License for more details.
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
45 Bacula® is a registered trademark of John Walker.
46 The licensor of Bacula is the Free Software Foundation Europe
47 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
48 Switzerland, email:ftf@fsfeurope.org.
54 /* Forward referenced functions */
55 static char *find_msg_start(char *msg);
57 static char Job_status[] = "Status Job=%127s JobStatus=%d\n";
59 static char Device_update[] = "DevUpd Job=%127s "
61 "append=%d read=%d num_writers=%d "
62 "open=%d labeled=%d offline=%d "
63 "reserved=%d max_writers=%d "
64 "autoselect=%d autochanger=%d "
65 "changer_name=%127s media_type=%127s volume_name=%127s\n";
69 static char OK_msg[] = "1000 OK\n";
73 * Call appropriate processing routine
74 * If it is not a Jmsg or a ReqCat message,
75 * return it to the caller.
77 * This routine is called to get the next message from
78 * another daemon. If the message is in canonical message
79 * format and the type is known, it will be dispatched
80 * to the appropriate handler. If the message is
81 * in any other format, it will be returned.
83 * E.g. any message beginning with a digit will be passed
84 * through to the caller.
85 * All other messages are expected begin with some identifier
86 * -- for the moment only the first character is checked, but
87 * at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
88 * could be checked. This is followed by Job=Jobname <user-defined>
89 * info. The identifier is used to dispatch the message to the right
90 * place (Job message, catalog request, ...). The Job is used to lookup
91 * the JCR so that the action is performed on the correct jcr, and
92 * the rest of the message is up to the user. Note, DevUpd uses
93 * *System* for the Job name, and hence no JCR is obtained. This
94 * is a *rare* case where a jcr is not really needed.
97 int bget_dirmsg(BSOCK *bs)
100 char Job[MAX_NAME_LENGTH];
108 Dmsg2(900, "bget_dirmsg %d: %s", n, bs->msg);
110 if (is_bnet_stop(bs)) {
111 return n; /* error or terminate */
113 if (n == BNET_SIGNAL) { /* handle signal */
114 /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
115 switch (bs->msglen) {
116 case BNET_EOD: /* end of data */
119 bnet_fsend(bs, OK_msg);/* send response */
120 return n; /* end of data */
125 bnet_fsend(bs, OK_msg); /* send response */
128 // encode_time(time(NULL), Job);
129 // Dmsg1(100, "%s got heartbeat.\n", Job);
131 case BNET_HB_RESPONSE:
134 /* *****FIXME***** Implement more completely */
135 bnet_fsend(bs, "Status OK\n");
136 bnet_sig(bs, BNET_EOD);
138 case BNET_BTIME: /* send Bacula time */
140 bnet_fsend(bs, "btime %s\n", edit_uint64(get_current_btime(),ed1));
143 Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
149 /* Handle normal data */
151 if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */
152 return n; /* yes, return it */
156 * If we get here, it must be a request. Either
157 * a message to dispatch, or a catalog request.
160 if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
161 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
164 if (strcmp(Job, "*System*") == 0) {
165 jcr = NULL; /* No jcr */
166 } else if (!(jcr=get_jcr_by_full_name(Job))) {
167 Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
170 Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
172 /* Skip past "Jmsg Job=nnn" */
173 if (!(msg=find_msg_start(bs->msg))) {
174 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
180 * Here we are expecting a message of the following format:
181 * Jmsg Job=nnn type=nnn level=nnn Message-string
183 if (bs->msg[0] == 'J') { /* Job message */
184 if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
185 Job, &type, &level) != 3) {
186 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
190 Dmsg1(900, "Got msg: %s\n", bs->msg);
192 skip_nonspaces(&msg); /* skip type=nnn */
194 skip_nonspaces(&msg); /* skip level=nnn */
196 msg++; /* skip leading space */
198 Dmsg1(900, "Dispatch msg: %s", msg);
199 dispatch_message(jcr, type, level, msg);
204 * Here we expact a CatReq message
205 * CatReq Job=nn Catalog-Request-Message
207 if (bs->msg[0] == 'C') { /* Catalog request */
208 Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
209 catalog_request(jcr, bs);
210 Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
214 if (bs->msg[0] == 'U') { /* Catalog update */
215 Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
216 catalog_update(jcr, bs);
217 Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
221 if (bs->msg[0] == 'M') { /* Mount request */
222 Dmsg1(900, "Mount req: %s", bs->msg);
223 mount_request(jcr, bs, msg);
227 if (bs->msg[0] == 'S') { /* Status change */
229 char Job[MAX_NAME_LENGTH];
230 if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
231 jcr->SDJobStatus = JobStatus; /* current status */
233 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
239 /* No JCR for Device Updates! */
240 if (bs->msg[0] = 'D') { /* Device update */
242 POOL_MEM dev_name, changer_name, media_type, volume_name;
243 int dev_open, dev_append, dev_read, dev_labeled;
244 int dev_offline, dev_autochanger, dev_autoselect;
245 int dev_num_writers, dev_max_writers, dev_reserved;
247 Dmsg1(100, "<stored: %s", bs->msg);
248 if (sscanf(bs->msg, Device_update,
249 &Job, dev_name.c_str(),
250 &dev_append, &dev_read,
251 &dev_num_writers, &dev_open,
252 &dev_labeled, &dev_offline, &dev_reserved,
253 &dev_max_writers, &dev_autoselect,
255 changer_name.c_str(), media_type.c_str(),
256 volume_name.c_str()) != 15) {
257 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
259 unbash_spaces(dev_name);
260 dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
264 unbash_spaces(changer_name);
265 unbash_spaces(media_type);
266 unbash_spaces(volume_name);
267 bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
268 bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
269 bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
270 /* Note, these are copied because they are boolean rather than
273 dev->open = dev_open;
274 dev->append = dev_append;
275 dev->read = dev_read;
276 dev->labeled = dev_labeled;
277 dev->offline = dev_offline;
278 dev->autoselect = dev_autoselect;
279 dev->autochanger = dev_autochanger > 0;
280 dev->num_drives = dev_autochanger; /* does double duty */
281 dev->PoolId = dev_PoolId;
282 dev->num_writers = dev_num_writers;
283 dev->max_writers = dev_max_writers;
284 dev->reserved = dev_reserved;
294 static char *find_msg_start(char *msg)
298 skip_nonspaces(&p); /* skip message type */
300 skip_nonspaces(&p); /* skip Job */
301 skip_spaces(&p); /* after spaces come the message */
306 * Get response from FD or SD to a command we
307 * sent. Check that the response agrees with what we expect.
309 * Returns: false on failure
312 bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
316 if (is_bnet_error(bs)) {
319 if ((n = bget_dirmsg(bs)) >= 0) {
320 if (strcmp(bs->msg, resp) == 0) {
323 if (prtmsg == DISPLAY_ERROR) {
324 Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
329 Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
330 cmd, bnet_strerror(bs));