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 Copyright (C) 2000-2005 Kern Sibbald
26 This program is free software; you can redistribute it and/or
27 modify it under the terms of the GNU General Public License as
28 published by the Free Software Foundation; either version 2 of
29 the License, or (at your option) any later version.
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 General Public License for more details.
36 You should have received a copy of the GNU General Public
37 License along with this program; if not, write to the Free
38 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
46 /* Forward referenced functions */
47 static char *find_msg_start(char *msg);
49 static char Job_status[] = "Status Job=%127s JobStatus=%d\n";
50 static char Device_update[] = "DevUpd Job=%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 "
57 "changer_name=%127s media_type=%127s volume_name=%127s\n";
60 static char OK_msg[] = "1000 OK\n";
64 * Call appropriate processing routine
65 * If it is not a Jmsg or a ReqCat message,
66 * return it to the caller.
68 * This routine is called to get the next message from
69 * another daemon. If the message is in canonical message
70 * format and the type is known, it will be dispatched
71 * to the appropriate handler. If the message is
72 * in any other format, it will be returned.
74 * E.g. any message beginning with a digit will be passed
75 * through to the caller.
76 * All other messages are expected begin with some identifier
77 * -- for the moment only the first character is checked, but
78 * at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
79 * could be checked. This is followed by Job=Jobname <user-defined>
80 * info. The identifier is used to dispatch the message to the right
81 * place (Job message, catalog request, ...). The Job is used to lookup
82 * the JCR so that the action is performed on the correct jcr, and
83 * the rest of the message is up to the user. Note, DevUpd uses
84 * *System* for the Job name, and hence no JCR is obtained. This
85 * is a *rare* case where a jcr is not really needed.
88 int bget_dirmsg(BSOCK *bs)
91 char Job[MAX_NAME_LENGTH];
99 Dmsg2(900, "bget_dirmsg %d: %s", n, bs->msg);
101 if (is_bnet_stop(bs)) {
102 return n; /* error or terminate */
104 if (n == BNET_SIGNAL) { /* handle signal */
105 /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
106 switch (bs->msglen) {
107 case BNET_EOD: /* end of data */
110 bnet_fsend(bs, OK_msg);/* send response */
111 return n; /* end of data */
116 bnet_fsend(bs, OK_msg); /* send response */
119 // encode_time(time(NULL), Job);
120 // Dmsg1(100, "%s got heartbeat.\n", Job);
122 case BNET_HB_RESPONSE:
125 /* *****FIXME***** Implement more completely */
126 bnet_fsend(bs, "Status OK\n");
127 bnet_sig(bs, BNET_EOD);
129 case BNET_BTIME: /* send Bacula time */
131 bnet_fsend(bs, "btime %s\n", edit_uint64(get_current_btime(),ed1));
134 Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
140 /* Handle normal data */
142 if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */
143 return n; /* yes, return it */
147 * If we get here, it must be a request. Either
148 * a message to dispatch, or a catalog request.
151 if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
152 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
155 if (strcmp(Job, "*System*") == 0) {
156 jcr = NULL; /* No jcr */
157 } else if (!(jcr=get_jcr_by_full_name(Job))) {
158 Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
161 Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
163 /* Skip past "Jmsg Job=nnn" */
164 if (!(msg=find_msg_start(bs->msg))) {
165 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
171 * Here we are expecting a message of the following format:
172 * Jmsg Job=nnn type=nnn level=nnn Message-string
174 if (bs->msg[0] == 'J') { /* Job message */
175 if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
176 Job, &type, &level) != 3) {
177 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
181 Dmsg1(900, "Got msg: %s\n", bs->msg);
183 skip_nonspaces(&msg); /* skip type=nnn */
185 skip_nonspaces(&msg); /* skip level=nnn */
187 msg++; /* skip leading space */
189 Dmsg1(900, "Dispatch msg: %s", msg);
190 dispatch_message(jcr, type, level, msg);
195 * Here we expact a CatReq message
196 * CatReq Job=nn Catalog-Request-Message
198 if (bs->msg[0] == 'C') { /* Catalog request */
199 Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
200 catalog_request(jcr, bs, msg);
201 Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
205 if (bs->msg[0] == 'U') { /* Catalog update */
206 Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
207 catalog_update(jcr, bs, msg);
208 Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
212 if (bs->msg[0] == 'M') { /* Mount request */
213 Dmsg1(900, "Mount req: %s", bs->msg);
214 mount_request(jcr, bs, msg);
218 if (bs->msg[0] == 'S') { /* Status change */
220 char Job[MAX_NAME_LENGTH];
221 if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
222 jcr->SDJobStatus = JobStatus; /* current status */
224 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
229 /* No JCR for Device Updates! */
230 if (bs->msg[0] = 'D') { /* Device update */
232 POOL_MEM dev_name, changer_name, media_type, volume_name;
233 int dev_open, dev_append, dev_read, dev_labeled;
234 int dev_offline, dev_autochanger, dev_autoselect;
235 int dev_num_writers, dev_max_writers, dev_reserved;
237 Dmsg1(100, "<stored: %s", bs->msg);
238 if (sscanf(bs->msg, Device_update,
239 &Job, dev_name.c_str(),
240 &dev_append, &dev_read,
241 &dev_num_writers, &dev_open,
242 &dev_labeled, &dev_offline, &dev_reserved,
243 &dev_max_writers, &dev_autoselect,
244 &dev_autochanger, &dev_PoolId,
245 changer_name.c_str(), media_type.c_str(),
246 volume_name.c_str()) != 16) {
247 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
249 unbash_spaces(dev_name);
250 dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
254 unbash_spaces(changer_name);
255 unbash_spaces(media_type);
256 unbash_spaces(volume_name);
257 bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
258 bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
259 bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
260 /* Note, these are copied because they are boolean rather than
263 dev->open = dev_open;
264 dev->append = dev_append;
265 dev->read = dev_read;
266 dev->labeled = dev_labeled;
267 dev->offline = dev_offline;
268 dev->autoselect = dev_autoselect;
269 dev->autochanger = dev_autochanger > 0;
270 dev->num_drives = dev_autochanger; /* does double duty */
271 dev->PoolId = dev_PoolId;
272 dev->num_writers = dev_num_writers;
273 dev->max_writers = dev_max_writers;
274 dev->reserved = dev_reserved;
283 static char *find_msg_start(char *msg)
287 skip_nonspaces(&p); /* skip message type */
289 skip_nonspaces(&p); /* skip Job */
290 skip_spaces(&p); /* after spaces come the message */
295 * Get response from FD or SD to a command we
296 * sent. Check that the response agrees with what we expect.
298 * Returns: false on failure
301 bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
305 if (is_bnet_error(bs)) {
308 if ((n = bget_dirmsg(bs)) >= 0) {
310 if (strcmp(bs->msg, resp) == 0) {
313 Dmsg1(900, "Bad response: ERR=%s", bs->msg);
314 if (prtmsg == DISPLAY_ERROR) {
315 Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s got: %s\n"),
320 Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
321 cmd, bnet_strerror(bs));