X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fgetmsg.c;h=18b54e961d8159153b462e9fa401a041ac9a7538;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=ae961f30118935a47d931b502bd14d53325f606c;hpb=37b22f498aa148b3782288fa858c40a81ca0bfba;p=bacula%2Fbacula diff --git a/bacula/src/dird/getmsg.c b/bacula/src/dird/getmsg.c index ae961f3011..18b54e961d 100644 --- a/bacula/src/dird/getmsg.c +++ b/bacula/src/dird/getmsg.c @@ -1,3 +1,21 @@ +/* + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2018 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. +*/ /* * * Bacula Director -- routines to receive network data and @@ -10,34 +28,14 @@ * * Basic tasks done here: * Handle network signals (signals). - * Signals always have return status 0 from bnet_recv() and - * a zero or negative message length. + * Signals always have return status 0 from bnet_recv() and + * a zero or negative message length. * Pass appropriate messages back to the caller (responses). - * Responses always have a digit as the first character. + * Responses always have a digit as the first character. * Handle requests for message and catalog services (requests). - * Requests are any message that does not begin with a digit. - * In affect, they are commands. + * Requests are any message that does not begin with a digit. + * In affect, they are commands. * - * Version $Id$ - */ -/* - Copyright (C) 2000-2005 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - */ #include "bacula.h" @@ -46,19 +44,70 @@ /* Forward referenced functions */ static char *find_msg_start(char *msg); -static char Job_status[] = "Status Job=%127s JobStatus=%d\n"; -static char Device_update[] = "DevUpd Job=%127s " +static char Job_status[] = "Status JobId=%ld JobStatus=%d\n"; +#ifdef needed +static char Device_update[] = "DevUpd JobId=%127s " "device=%127s " "append=%d read=%d num_writers=%d " "open=%d labeled=%d offline=%d " "reserved=%d max_writers=%d " "autoselect=%d autochanger=%d " - "poolid=%lld " - "changer_name=%127s media_type=%127s volume_name=%127s\n"; + "changer_name=%127s media_type=%127s volume_name=%127s " + "DevReadTime=%d DevWriteTime=%d DevReadBytes=%d " + "DevWriteBytes=%d\n"; +#endif static char OK_msg[] = "1000 OK\n"; + +static void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus) +{ + bool set_waittime=false; + Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus); + /* if wait state is new, we keep current time for watchdog MaxWaitTime */ + switch (SDJobStatus) { + case JS_WaitMedia: + case JS_WaitMount: + case JS_WaitMaxJobs: + set_waittime = true; + default: + break; + } + + if (job_waiting(jcr)) { + set_waittime = false; + } + + if (set_waittime) { + /* set it before JobStatus */ + Dmsg0(800, "Setting wait_time\n"); + jcr->wait_time = time(NULL); + } + jcr->SDJobStatus = SDJobStatus; + if (jcr->SDJobStatus == JS_Incomplete) { + jcr->setJobStatus(JS_Incomplete); + } + +} + +/* + * See if we are pointing to a message id + * Look for: [XYnnnn] + */ +static bool is_msgid(char *msg) +{ + if (!msg) return false; + char *end = strchr(msg, ']'); + if (!end) return false; + if ((end - msg) != 7) return false; + if (!B_ISUPPER(msg[1]) || !B_ISUPPER(msg[2])) return false; + for (int i=3; i<7; i++) { + if (!B_ISDIGIT(msg[i])) return false; + } + return true; +} + /* * Get a message * Call appropriate processing routine @@ -71,223 +120,264 @@ static char OK_msg[] = "1000 OK\n"; * to the appropriate handler. If the message is * in any other format, it will be returned. * - * E.g. any message beginning with a digit will be passed - * through to the caller. + * E.g. any message beginning with a digit will be passed + * through to the caller. * All other messages are expected begin with some identifier * -- for the moment only the first character is checked, but * at a later time, the whole identifier (e.g. Jmsg, CatReq, ...) - * could be checked. This is followed by Job=Jobname + * could be checked. + * This is followed by JobId=nnn * info. The identifier is used to dispatch the message to the right * place (Job message, catalog request, ...). The Job is used to lookup * the JCR so that the action is performed on the correct jcr, and * the rest of the message is up to the user. Note, DevUpd uses - * *System* for the Job name, and hence no JCR is obtained. This + * *System* for the Job name, and hence no JCR is obtained. This * is a *rare* case where a jcr is not really needed. * */ int bget_dirmsg(BSOCK *bs) { - int32_t n; + int32_t n = BNET_TERMINATE; char Job[MAX_NAME_LENGTH]; + JobId_t JobId = 0; char MsgType[20]; - int type, level; - JCR *jcr; + int type; + utime_t mtime; /* message time */ + JCR *jcr = bs->jcr(); char *msg; - for (;;) { - n = bnet_recv(bs); - Dmsg2(900, "bget_dirmsg %d: %s\n", n, bs->msg); + for ( ; !bs->is_stop() && !bs->is_timed_out(); ) { + n = bs->recv(); + Dmsg4(200, "bget_dirmsg n=%d msglen=%ld is_stop=%d: %s\n", n, bs->msglen, bs->is_stop(), bs->msg); - if (is_bnet_stop(bs)) { - return n; /* error or terminate */ + if (bs->is_stop() || bs->is_timed_out()) { + return n; /* error or terminate */ } - if (n == BNET_SIGNAL) { /* handle signal */ - /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */ - switch (bs->msglen) { - case BNET_EOD: /* end of data */ - return n; - case BNET_EOD_POLL: - bnet_fsend(bs, OK_msg);/* send response */ - return n; /* end of data */ - case BNET_TERMINATE: - bs->terminated = 1; - return n; - case BNET_POLL: - bnet_fsend(bs, OK_msg); /* send response */ - break; - case BNET_HEARTBEAT: -// encode_time(time(NULL), Job); + if (n == BNET_SIGNAL) { /* handle signal */ + /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */ + switch (bs->msglen) { + case BNET_EOD: /* end of data */ + return n; + case BNET_EOD_POLL: + bs->fsend(OK_msg);/* send response */ + return n; /* end of data */ + case BNET_TERMINATE: + bs->set_terminated(); + return n; + case BNET_POLL: + bs->fsend(OK_msg); /* send response */ + break; + case BNET_HEARTBEAT: +// encode_time(time(NULL), Job); // Dmsg1(100, "%s got heartbeat.\n", Job); - break; - case BNET_HB_RESPONSE: - break; - case BNET_STATUS: - /* *****FIXME***** Implement more completely */ - bnet_fsend(bs, "Status OK\n"); - bnet_sig(bs, BNET_EOD); - break; - case BNET_BTIME: /* send Bacula time */ - char ed1[50]; - bnet_fsend(bs, "btime %s\n", edit_uint64(get_current_btime(),ed1)); - break; - default: - Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen); - return n; - } - continue; + break; + case BNET_HB_RESPONSE: + break; + case BNET_STATUS: + /* *****FIXME***** Implement more completely */ + bs->fsend("Status OK\n"); + bs->signal(BNET_EOD); + break; + case BNET_BTIME: /* send Bacula time */ + char ed1[50]; + bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1)); + break; + default: + Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen); + return n; + } + continue; } /* Handle normal data */ - if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */ - return n; /* yes, return it */ + if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */ + return n; /* yes, return it */ } /* - * If we get here, it must be a request. Either + * If we get here, it must be a request. Either * a message to dispatch, or a catalog request. * Try to fulfill it. */ - if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) { - Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); - continue; - } - if (strcmp(Job, "*System*") == 0) { - jcr = NULL; /* No jcr */ - } else if (!(jcr=get_jcr_by_full_name(Job))) { - Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg); - continue; + if ((sscanf(bs->msg, "%020s JobId=%ld ", MsgType, &JobId) != 2) && + (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) && + (sscanf(bs->msg, "%020s Job=x", MsgType) != 1)) { + if (is_msgid(strchr(bs->msg, '['))) { + return n; + } + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + continue; } - Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr); - /* Skip past "Jmsg Job=nnn" */ + /* Skip past first two fields: "Jmsg JobId=nnn" */ if (!(msg=find_msg_start(bs->msg))) { - Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); - free_jcr(jcr); - continue; + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + continue; } /* * Here we are expecting a message of the following format: - * Jmsg Job=nnn type=nnn level=nnn Message-string + * Jmsg JobId=nnn type=nnn level=nnn Message-string + * Note, level should really be mtime, but that changes + * the protocol. */ if (bs->msg[0] == 'J') { /* Job message */ - if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d", - Job, &type, &level) != 3) { - Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); - free_jcr(jcr); - continue; - } + if ((sscanf(bs->msg, "Jmsg JobId=%ld type=%d level=%lld", + &JobId, &type, &mtime) != 3) && + (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld", + Job, &type, &mtime) != 3)) { + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + continue; + } Dmsg1(900, "Got msg: %s\n", bs->msg); - skip_spaces(&msg); - skip_nonspaces(&msg); /* skip type=nnn */ - skip_spaces(&msg); - skip_nonspaces(&msg); /* skip level=nnn */ + skip_spaces(&msg); + skip_nonspaces(&msg); /* skip type=nnn */ + skip_spaces(&msg); + skip_nonspaces(&msg); /* skip level=nnn */ if (*msg == ' ') { - msg++; /* skip leading space */ - } + msg++; /* skip leading space */ + } Dmsg1(900, "Dispatch msg: %s", msg); - dispatch_message(jcr, type, level, msg); - free_jcr(jcr); - continue; + dispatch_message(jcr, type, mtime, msg); + continue; } /* * Here we expact a CatReq message - * CatReq Job=nn Catalog-Request-Message + * CatReq JobId=nn Catalog-Request-Message */ if (bs->msg[0] == 'C') { /* Catalog request */ - Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg); - catalog_request(jcr, bs, msg); - Dmsg1(900, "Calling freejcr 0x%x\n", jcr); - free_jcr(jcr); - continue; + Dmsg2(900, "Catalog req jcr=%p: %s", jcr, bs->msg); + catalog_request(jcr, bs); + continue; + } + if (bs->msg[0] == 'U') { /* SD sending attributes */ + Dmsg2(900, "Catalog upd jcr=%p: %s", jcr, bs->msg); + catalog_update(jcr, bs); + continue; } - if (bs->msg[0] == 'U') { /* Catalog update */ - Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg); - catalog_update(jcr, bs, msg); - Dmsg1(900, "Calling freejcr 0x%x\n", jcr); - free_jcr(jcr); - continue; + if (bs->msg[0] == 'B') { /* SD sending file spool attributes */ + Dmsg2(100, "Blast attributes jcr=%p: %s", jcr, bs->msg); + char filename[256]; + if (sscanf(bs->msg, "BlastAttr JobId=%ld File=%255s", + &JobId, filename) != 2) { + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + continue; + } + unbash_spaces(filename); + if (despool_attributes_from_file(jcr, filename)) { + bs->fsend("1000 OK BlastAttr\n"); + } else { + bs->fsend("1990 ERROR BlastAttr\n"); + } + continue; } if (bs->msg[0] == 'M') { /* Mount request */ Dmsg1(900, "Mount req: %s", bs->msg); - mount_request(jcr, bs, msg); - free_jcr(jcr); - continue; + mount_request(jcr, bs, msg); + continue; + } + /* Get Progress: files, bytes, bytes/sec */ + if (bs->msg[0] == 'P') { /* Progress report */ + uint32_t files, bps; + uint64_t bytes; + if ((sscanf(bs->msg, "Progress JobId=%ld files=%ld bytes=%lld bps=%ld\n", + &JobId, &files, &bytes, &bps) == 4) || + (sscanf(bs->msg, "Progress JobId=x files=%ld bytes=%lld bps=%ld\n", + &files, &bytes, &bps) == 3) || + (sscanf(bs->msg, "Progress Job=x files=%ld bytes=%lld bps=%ld\n", + &files, &bytes, &bps) == 3)) { + Dmsg2(900, "JobId=%d %s", jcr->JobId, bs->msg); + /* Save progress data */ + jcr->JobFiles = files; + jcr->JobBytes = bytes; + jcr->LastRate = bps; + } else { + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + } + continue; } if (bs->msg[0] == 'S') { /* Status change */ - int JobStatus; - char Job[MAX_NAME_LENGTH]; - if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) { - jcr->SDJobStatus = JobStatus; /* current status */ - } else { - Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); - } - free_jcr(jcr); - continue; + int JobStatus; + if (sscanf(bs->msg, Job_status, &JobId, &JobStatus) == 2) { + set_jcr_sd_job_status(jcr, JobStatus); /* current status */ + } else { + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + } + continue; } +#ifdef needed /* No JCR for Device Updates! */ if (bs->msg[0] = 'D') { /* Device update */ - DEVICE *dev; - POOL_MEM dev_name, changer_name, media_type, volume_name; - int dev_open, dev_append, dev_read, dev_labeled; - int dev_offline, dev_autochanger, dev_autoselect; - int dev_num_writers, dev_max_writers, dev_reserved; - uint64_t dev_PoolId; + DEVICE *dev; + POOL_MEM dev_name, changer_name, media_type, volume_name; + int dev_open, dev_append, dev_read, dev_labeled; + int dev_offline, dev_autochanger, dev_autoselect; + int dev_num_writers, dev_max_writers, dev_reserved; + uint64_t dev_read_time, dev_write_time, dev_write_bytes, dev_read_bytes; + uint64_t dev_PoolId; Dmsg1(100, "msg); - if (sscanf(bs->msg, Device_update, - &Job, dev_name.c_str(), - &dev_append, &dev_read, - &dev_num_writers, &dev_open, - &dev_labeled, &dev_offline, &dev_reserved, - &dev_max_writers, &dev_autoselect, - &dev_autochanger, &dev_PoolId, - changer_name.c_str(), media_type.c_str(), - volume_name.c_str()) != 16) { + if (sscanf(bs->msg, Device_update, + &Job, dev_name.c_str(), + &dev_append, &dev_read, + &dev_num_writers, &dev_open, + &dev_labeled, &dev_offline, &dev_reserved, + &dev_max_writers, &dev_autoselect, + &dev_autochanger, + changer_name.c_str(), media_type.c_str(), + volume_name.c_str(), + &dev_read_time, &dev_write_time, &dev_read_bytes, + &dev_write_bytes) != 19) { Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); - } else { - unbash_spaces(dev_name); - dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str()); - if (!dev) { - continue; - } - unbash_spaces(changer_name); - unbash_spaces(media_type); - unbash_spaces(volume_name); - bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName)); - bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType)); - bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName)); - /* Note, these are copied because they are boolean rather than - * integer. - */ - dev->open = dev_open; - dev->append = dev_append; - dev->read = dev_read; - dev->labeled = dev_labeled; - dev->offline = dev_offline; - dev->autoselect = dev_autoselect; - dev->autochanger = dev_autochanger > 0; - dev->num_drives = dev_autochanger; /* does double duty */ - dev->PoolId = dev_PoolId; - dev->num_writers = dev_num_writers; - dev->max_writers = dev_max_writers; - dev->reserved = dev_reserved; - dev->found = true; - } - continue; + } else { + unbash_spaces(dev_name); + dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str()); + if (!dev) { + continue; + } + unbash_spaces(changer_name); + unbash_spaces(media_type); + unbash_spaces(volume_name); + bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName)); + bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType)); + bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName)); + /* Note, these are copied because they are boolean rather than + * integer. + */ + dev->open = dev_open; + dev->append = dev_append; + dev->read = dev_read; + dev->labeled = dev_labeled; + dev->offline = dev_offline; + dev->autoselect = dev_autoselect; + dev->autochanger = dev_autochanger > 0; + dev->num_drives = dev_autochanger; /* does double duty */ + dev->PoolId = dev_PoolId; + dev->num_writers = dev_num_writers; + dev->max_writers = dev_max_writers; + dev->reserved = dev_reserved; + dev->found = true; + dev->DevReadTime = dev_read_time; /* TODO : have to update database */ + dev->DevWriteTime = dev_write_time; + dev->DevReadBytes = dev_read_bytes; + dev->DevWriteBytes = dev_write_bytes; + } + continue; } +#endif return n; } + return n; } static char *find_msg_start(char *msg) { char *p = msg; - skip_nonspaces(&p); /* skip message type */ + skip_nonspaces(&p); /* skip message type */ skip_spaces(&p); - skip_nonspaces(&p); /* skip Job */ - skip_spaces(&p); /* after spaces come the message */ + skip_nonspaces(&p); /* skip Job */ + skip_spaces(&p); /* after spaces come the message */ return p; } @@ -296,28 +386,26 @@ static char *find_msg_start(char *msg) * sent. Check that the response agrees with what we expect. * * Returns: false on failure - * true on success + * true on success */ bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg) { int n; - if (is_bnet_error(bs)) { + if (bs->is_error()) { return false; } if ((n = bget_dirmsg(bs)) >= 0) { - Dmsg0(900, bs->msg); if (strcmp(bs->msg, resp) == 0) { - return true; + return true; } - Dmsg1(900, "Bad response: ERR=%s", bs->msg); if (prtmsg == DISPLAY_ERROR) { - Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s got: %s\n"), - cmd, resp, bs->msg); + Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"), + cmd, resp, bs->msg); } return false; } Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"), - cmd, bnet_strerror(bs)); + cmd, bs->bstrerror()); return false; }