X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fgetmsg.c;h=c0237489b46547dd164df760b67b97770829c7ed;hb=fa93071721d8546d6e8599f906fbc3717516be45;hp=d99b24bb4a3f6f44224fe09615863112faaa06bb;hpb=8be85f9427a4f59f4f8f7d116d4803335bba1cdb;p=bacula%2Fbacula diff --git a/bacula/src/dird/getmsg.c b/bacula/src/dird/getmsg.c index d99b24bb4a..c0237489b4 100644 --- a/bacula/src/dird/getmsg.c +++ b/bacula/src/dird/getmsg.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * * Bacula Director -- routines to receive network data and @@ -9,36 +36,17 @@ * This routine runs as a thread and must be thread reentrant. * * Basic tasks done here: - * Handle network signals (signals). - * 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. - * Handle requests for message and catalog services (requests). - * Requests are any message that does not begin with a digit. - * In affect, they are commands. + * Handle network signals (signals). + * 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. + * Handle requests for message and catalog services (requests). + * Requests are any message that does not begin with a digit. + * In affect, they are commands. * * Version $Id$ */ -/* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker - - 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" #include "dird.h" @@ -46,8 +54,49 @@ /* Forward referenced functions */ static char *find_msg_start(char *msg); +static char Job_status[] = "Status Job=%127s JobStatus=%d\n"; +#ifdef needed +static char Device_update[] = "DevUpd Job=%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 " + "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"; + +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; +} + /* * Get a message * Call appropriate processing routine @@ -58,127 +107,209 @@ static char OK_msg[] = "1000 OK\n"; * another daemon. If the message is in canonical message * format and the type is known, it will be dispatched * to the appropriate handler. If the message is - * in any other format, it will be returned. + * in any other format, it will be returned. + * + * 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 + * 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 + * is a *rare* case where a jcr is not really needed. * */ -int32_t bget_msg(BSOCK *bs, int rtn) +int bget_dirmsg(BSOCK *bs) { int32_t n; char Job[MAX_NAME_LENGTH]; 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(120, "bget_msg %d: %s\n", n, bs->msg); + n = bs->recv(); + Dmsg2(300, "bget_dirmsg %d: %s\n", n, bs->msg); - if (n < 0) { - return n; /* error return */ + if (is_bnet_stop(bs)) { + return n; /* error or terminate */ } - if (n == 0) { /* handle signal */ - /* 0 return from bnet_recv() => network signal */ - switch (bs->msglen) { - case BNET_NONO: /* for compatibility */ - case BNET_EOD: /* end of data */ - return 0; - case BNET_EOD_POLL: - bnet_fsend(bs, OK_msg);/* send response */ - return 0; /* end of data */ - case BNET_TERMINATE: - bs->terminated = 1; - return 0; - case BNET_POLL: - bnet_fsend(bs, OK_msg); /* send response */ - break; - case BNET_HEARTBEAT: - bnet_sig(bs, BNET_HB_RESPONSE); - break; - case BNET_STATUS: - /* *****FIXME***** Implement */ - bnet_fsend(bs, "Status OK\n"); - bnet_sig(bs, BNET_EOD); - break; - default: - Emsg1(M_WARNING, 0, _("bget_msg: unknown signal %d\n"), bs->msglen); - return 0; - } - continue; + 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 */ + 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 (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 (!(jcr=get_jcr_by_full_name(Job))) { - Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg); - continue; + Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); + continue; } /* Skip past "Jmsg Job=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 + * 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; - } - Dmsg1(120, "Got msg: %s\n", bs->msg); - skip_spaces(&msg); - skip_nonspaces(&msg); /* skip type=nnn */ - skip_spaces(&msg); - skip_nonspaces(&msg); /* skip level=nnn */ + if (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 */ if (*msg == ' ') { - msg++; /* skip leading space */ - } - Dmsg1(120, "Dispatch msg: %s", msg); - dispatch_message(jcr, type, level, msg); - free_jcr(jcr); - continue; + msg++; /* skip leading space */ + } + Dmsg1(900, "Dispatch msg: %s", msg); + dispatch_message(jcr, type, mtime, msg); + continue; } - /* + /* * Here we expact a CatReq message * CatReq Job=nn Catalog-Request-Message */ if (bs->msg[0] == 'C') { /* Catalog request */ - Dmsg1(120, "Catalog req: %s", bs->msg); - catalog_request(jcr, bs, msg); - free_jcr(jcr); - continue; + Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg); + catalog_request(jcr, bs); + continue; } - if (bs->msg[0] == 'U') { /* Catalog update */ - catalog_update(jcr, bs, msg); - free_jcr(jcr); - continue; + if (bs->msg[0] == 'U') { /* SD sending attributes */ + Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg); + catalog_update(jcr, bs); + continue; } if (bs->msg[0] == 'M') { /* Mount request */ - Dmsg1(120, "Mount req: %s", bs->msg); - mount_request(jcr, bs, msg); - free_jcr(jcr); - continue; + Dmsg1(900, "Mount req: %s", bs->msg); + mount_request(jcr, 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) { + 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_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, + 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; + 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; } } @@ -187,37 +318,38 @@ 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; } /* - * Get response from File daemon to a command we + * Get response from FD or SD to a command we * sent. Check that the response agrees with what we expect. * - * Returns: 0 on failure - * 1 on success + * Returns: false on failure + * true on success */ -int response(BSOCK *fd, char *resp, char *cmd) +bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg) { int n; - if (fd->errors) { - return 0; + if (is_bnet_error(bs)) { + return false; } - if ((n = bget_msg(fd, 0)) > 0) { - Dmsg0(10, fd->msg); - if (strcmp(fd->msg, resp) == 0) { - return 1; + if ((n = bget_dirmsg(bs)) >= 0) { + if (strcmp(bs->msg, resp) == 0) { + return true; } - Emsg3(M_FATAL, 0, _("msg); - return 0; - } - Emsg2(M_FATAL, 0, _("msg); + } + return false; + } + Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"), + cmd, bnet_strerror(bs)); + return false; }