2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- routines to receive network data and
31 * handle network signals. These routines handle the connections
32 * to the Storage daemon and the File daemon.
34 * Kern Sibbald, August MM
36 * This routine runs as a thread and must be thread reentrant.
38 * Basic tasks done here:
39 * Handle network signals (signals).
40 * Signals always have return status 0 from bnet_recv() and
41 * a zero or negative message length.
42 * Pass appropriate messages back to the caller (responses).
43 * Responses always have a digit as the first character.
44 * Handle requests for message and catalog services (requests).
45 * Requests are any message that does not begin with a digit.
46 * In affect, they are commands.
53 /* Forward referenced functions */
54 static char *find_msg_start(char *msg);
56 static char Job_status[] = "Status Job=%127s JobStatus=%d\n";
58 static char Device_update[] = "DevUpd Job=%127s "
60 "append=%d read=%d num_writers=%d "
61 "open=%d labeled=%d offline=%d "
62 "reserved=%d max_writers=%d "
63 "autoselect=%d autochanger=%d "
64 "changer_name=%127s media_type=%127s volume_name=%127s "
65 "DevReadTime=%d DevWriteTime=%d DevReadBytes=%d "
70 static char OK_msg[] = "1000 OK\n";
73 static void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus)
75 bool set_waittime=false;
76 Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus);
77 /* if wait state is new, we keep current time for watchdog MaxWaitTime */
78 switch (SDJobStatus) {
87 if (job_waiting(jcr)) {
92 /* set it before JobStatus */
93 Dmsg0(800, "Setting wait_time\n");
94 jcr->wait_time = time(NULL);
96 jcr->SDJobStatus = SDJobStatus;
97 if (jcr->SDJobStatus == JS_Incomplete) {
98 jcr->setJobStatus(JS_Incomplete);
105 * Call appropriate processing routine
106 * If it is not a Jmsg or a ReqCat message,
107 * return it to the caller.
109 * This routine is called to get the next message from
110 * another daemon. If the message is in canonical message
111 * format and the type is known, it will be dispatched
112 * to the appropriate handler. If the message is
113 * in any other format, it will be returned.
115 * E.g. any message beginning with a digit will be passed
116 * through to the caller.
117 * All other messages are expected begin with some identifier
118 * -- for the moment only the first character is checked, but
119 * at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
120 * could be checked. This is followed by Job=Jobname <user-defined>
121 * info. The identifier is used to dispatch the message to the right
122 * place (Job message, catalog request, ...). The Job is used to lookup
123 * the JCR so that the action is performed on the correct jcr, and
124 * the rest of the message is up to the user. Note, DevUpd uses
125 * *System* for the Job name, and hence no JCR is obtained. This
126 * is a *rare* case where a jcr is not really needed.
129 int bget_dirmsg(BSOCK *bs)
131 int32_t n = BNET_TERMINATE;
132 char Job[MAX_NAME_LENGTH];
135 utime_t mtime; /* message time */
136 JCR *jcr = bs->jcr();
139 for ( ; !bs->is_stop() && !bs->is_timed_out(); ) {
141 Dmsg2(100, "bget_dirmsg %d: %s\n", n, bs->msg);
143 if (bs->is_stop() || bs->is_timed_out()) {
144 return n; /* error or terminate */
146 if (n == BNET_SIGNAL) { /* handle signal */
147 /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
148 switch (bs->msglen) {
149 case BNET_EOD: /* end of data */
152 bs->fsend(OK_msg);/* send response */
153 return n; /* end of data */
155 bs->set_terminated();
158 bs->fsend(OK_msg); /* send response */
161 // encode_time(time(NULL), Job);
162 // Dmsg1(100, "%s got heartbeat.\n", Job);
164 case BNET_HB_RESPONSE:
167 /* *****FIXME***** Implement more completely */
168 bs->fsend("Status OK\n");
169 bs->signal(BNET_EOD);
171 case BNET_BTIME: /* send Bacula time */
173 bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
176 Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
182 /* Handle normal data */
184 if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */
185 return n; /* yes, return it */
189 * If we get here, it must be a request. Either
190 * a message to dispatch, or a catalog request.
193 if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
194 Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
198 /* Skip past "Jmsg Job=nnn" */
199 if (!(msg=find_msg_start(bs->msg))) {
200 Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
205 * Here we are expecting a message of the following format:
206 * Jmsg Job=nnn type=nnn level=nnn Message-string
207 * Note, level should really be mtime, but that changes
210 if (bs->msg[0] == 'J') { /* Job message */
211 if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld",
212 Job, &type, &mtime) != 3) {
213 Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
216 Dmsg1(900, "Got msg: %s\n", bs->msg);
218 skip_nonspaces(&msg); /* skip type=nnn */
220 skip_nonspaces(&msg); /* skip level=nnn */
222 msg++; /* skip leading space */
224 Dmsg1(900, "Dispatch msg: %s", msg);
225 dispatch_message(jcr, type, mtime, msg);
229 * Here we expact a CatReq message
230 * CatReq Job=nn Catalog-Request-Message
232 if (bs->msg[0] == 'C') { /* Catalog request */
233 Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
234 catalog_request(jcr, bs);
237 if (bs->msg[0] == 'U') { /* SD sending attributes */
238 Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
239 catalog_update(jcr, bs);
242 if (bs->msg[0] == 'B') { /* SD sending file spool attributes */
243 Dmsg2(100, "Blast attributes jcr 0x%x: %s", jcr, bs->msg);
245 if (sscanf(bs->msg, "BlastAttr Job=%127s File=%255s",
246 Job, filename) != 2) {
247 Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
250 unbash_spaces(filename);
251 if (despool_attributes_from_file(jcr, filename)) {
252 bs->fsend("1000 OK BlastAttr\n");
254 bs->fsend("1990 ERROR BlastAttr\n");
258 if (bs->msg[0] == 'M') { /* Mount request */
259 Dmsg1(900, "Mount req: %s", bs->msg);
260 mount_request(jcr, bs, msg);
263 if (bs->msg[0] == 'S') { /* Status change */
265 char Job[MAX_NAME_LENGTH];
266 if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
267 set_jcr_sd_job_status(jcr, JobStatus); /* current status */
269 Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
274 /* No JCR for Device Updates! */
275 if (bs->msg[0] = 'D') { /* Device update */
277 POOL_MEM dev_name, changer_name, media_type, volume_name;
278 int dev_open, dev_append, dev_read, dev_labeled;
279 int dev_offline, dev_autochanger, dev_autoselect;
280 int dev_num_writers, dev_max_writers, dev_reserved;
281 uint64_t dev_read_time, dev_write_time, dev_write_bytes, dev_read_bytes;
283 Dmsg1(100, "<stored: %s", bs->msg);
284 if (sscanf(bs->msg, Device_update,
285 &Job, dev_name.c_str(),
286 &dev_append, &dev_read,
287 &dev_num_writers, &dev_open,
288 &dev_labeled, &dev_offline, &dev_reserved,
289 &dev_max_writers, &dev_autoselect,
291 changer_name.c_str(), media_type.c_str(),
293 &dev_read_time, &dev_write_time, &dev_read_bytes,
294 &dev_write_bytes) != 19) {
295 Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
297 unbash_spaces(dev_name);
298 dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
302 unbash_spaces(changer_name);
303 unbash_spaces(media_type);
304 unbash_spaces(volume_name);
305 bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
306 bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
307 bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
308 /* Note, these are copied because they are boolean rather than
311 dev->open = dev_open;
312 dev->append = dev_append;
313 dev->read = dev_read;
314 dev->labeled = dev_labeled;
315 dev->offline = dev_offline;
316 dev->autoselect = dev_autoselect;
317 dev->autochanger = dev_autochanger > 0;
318 dev->num_drives = dev_autochanger; /* does double duty */
319 dev->PoolId = dev_PoolId;
320 dev->num_writers = dev_num_writers;
321 dev->max_writers = dev_max_writers;
322 dev->reserved = dev_reserved;
324 dev->DevReadTime = dev_read_time; /* TODO : have to update database */
325 dev->DevWriteTime = dev_write_time;
326 dev->DevReadBytes = dev_read_bytes;
327 dev->DevWriteBytes = dev_write_bytes;
337 static char *find_msg_start(char *msg)
341 skip_nonspaces(&p); /* skip message type */
343 skip_nonspaces(&p); /* skip Job */
344 skip_spaces(&p); /* after spaces come the message */
349 * Get response from FD or SD to a command we
350 * sent. Check that the response agrees with what we expect.
352 * Returns: false on failure
355 bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
359 if (is_bnet_error(bs)) {
362 if ((n = bget_dirmsg(bs)) >= 0) {
363 if (strcmp(bs->msg, resp) == 0) {
366 if (prtmsg == DISPLAY_ERROR) {
367 Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
372 Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
373 cmd, bnet_strerror(bs));