diff options
Diffstat (limited to 'contrib/bind/lib/isc/ctl_srvr.c')
-rw-r--r-- | contrib/bind/lib/isc/ctl_srvr.c | 752 |
1 files changed, 0 insertions, 752 deletions
diff --git a/contrib/bind/lib/isc/ctl_srvr.c b/contrib/bind/lib/isc/ctl_srvr.c deleted file mode 100644 index 9beea0d42355..000000000000 --- a/contrib/bind/lib/isc/ctl_srvr.c +++ /dev/null @@ -1,752 +0,0 @@ -#if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: ctl_srvr.c,v 8.24 2000/11/14 01:10:37 vixie Exp $"; -#endif /* not lint */ - -/* - * Copyright (c) 1998,1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* Extern. */ - -#include "port_before.h" - -#include <sys/param.h> -#include <sys/file.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <arpa/inet.h> - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <fcntl.h> - -#include <isc/assertions.h> -#include <isc/ctl.h> -#include <isc/eventlib.h> -#include <isc/list.h> -#include <isc/logging.h> -#include <isc/memcluster.h> - -#include "ctl_p.h" - -#include "port_after.h" - -#ifdef SPRINTF_CHAR -# define SPRINTF(x) strlen(sprintf/**/x) -#else -# define SPRINTF(x) ((size_t)sprintf x) -#endif - -/* Macros. */ - -#define lastverb_p(verb) (verb->name == NULL || verb->func == NULL) -#define address_expr ctl_sa_ntop((struct sockaddr *)&sess->sa, \ - tmp, sizeof tmp, ctx->logger) - -/* Types. */ - -enum state { - available = 0, initializing, writing, reading, reading_data, - processing, idling, quitting, closing -}; - -union sa_un { - struct sockaddr_in in; -#ifndef NO_SOCKADDR_UN - struct sockaddr_un un; -#endif -}; - -struct ctl_sess { - LINK(struct ctl_sess) link; - struct ctl_sctx * ctx; - enum state state; - int sock; - union sa_un sa; - evFileID rdID; - evStreamID wrID; - evTimerID rdtiID; - evTimerID wrtiID; - struct ctl_buf inbuf; - struct ctl_buf outbuf; - const struct ctl_verb * verb; - u_int helpcode; - void * respctx; - u_int respflags; - ctl_srvrdone donefunc; - void * uap; - void * csctx; -}; - -struct ctl_sctx { - evContext ev; - void * uctx; - u_int unkncode; - u_int timeoutcode; - const struct ctl_verb * verbs; - const struct ctl_verb * connverb; - int sock; - int max_sess; - int cur_sess; - struct timespec timeout; - ctl_logfunc logger; - evConnID acID; - LIST(struct ctl_sess) sess; -}; - -/* Forward. */ - -static void ctl_accept(evContext, void *, int, - const void *, int, - const void *, int); -static void ctl_close(struct ctl_sess *); -static void ctl_new_state(struct ctl_sess *, - enum state, - const char *); -static void ctl_start_read(struct ctl_sess *); -static void ctl_stop_read(struct ctl_sess *); -static void ctl_readable(evContext, void *, int, int); -static void ctl_rdtimeout(evContext, void *, - struct timespec, - struct timespec); -static void ctl_wrtimeout(evContext, void *, - struct timespec, - struct timespec); -static void ctl_docommand(struct ctl_sess *); -static void ctl_writedone(evContext, void *, int, int); -static void ctl_morehelp(struct ctl_sctx *, - struct ctl_sess *, - const struct ctl_verb *, - const char *, - u_int, void *, void *); -static void ctl_signal_done(struct ctl_sctx *, - struct ctl_sess *); - -/* Private data. */ - -static const char * state_names[] = { - "available", "initializing", "writing", "reading", - "reading_data", "processing", "idling", "quitting", "closing" -}; - -static const char space[] = " "; - -static const struct ctl_verb fakehelpverb = { "fakehelp", ctl_morehelp }; - -/* Public. */ - -/* - * void - * ctl_server() - * create, condition, and start a listener on the control port. - */ -struct ctl_sctx * -ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len, - const struct ctl_verb *verbs, - u_int unkncode, u_int timeoutcode, - u_int timeout, int backlog, int max_sess, - ctl_logfunc logger, void *uctx) -{ - static const char me[] = "ctl_server"; - static const int on = 1; - const struct ctl_verb *connverb; - struct ctl_sctx *ctx; - int save_errno; - - if (logger == NULL) - logger = ctl_logger; - for (connverb = verbs; - connverb->name != NULL && connverb->func != NULL; - connverb++) - if (connverb->name[0] == '\0') - break; - if (connverb->func == NULL) { - (*logger)(ctl_error, "%s: no connection verb found", me); - return (NULL); - } - ctx = memget(sizeof *ctx); - if (ctx == NULL) { - (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno)); - return (NULL); - } - ctx->ev = lev; - ctx->uctx = uctx; - ctx->unkncode = unkncode; - ctx->timeoutcode = timeoutcode; - ctx->verbs = verbs; - ctx->timeout = evConsTime(timeout, 0); - ctx->logger = logger; - ctx->connverb = connverb; - ctx->max_sess = max_sess; - ctx->cur_sess = 0; - INIT_LIST(ctx->sess); - ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC); - if (ctx->sock > evHighestFD(ctx->ev)) { - ctx->sock = -1; - errno = ENOTSOCK; - } - if (ctx->sock < 0) { - save_errno = errno; - (*ctx->logger)(ctl_error, "%s: socket: %s", - me, strerror(errno)); - memput(ctx, sizeof *ctx); - errno = save_errno; - return (NULL); - } - if (ctx->sock > evHighestFD(lev)) { - close(ctx->sock); - (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD"); - errno = ENFILE; - memput(ctx, sizeof *ctx); - return (NULL); - } -#ifdef NO_UNIX_REUSEADDR - if (sap->sa_family != AF_UNIX) -#endif - if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof on) != 0) { - (*ctx->logger)(ctl_warning, - "%s: setsockopt(REUSEADDR): %s", - me, strerror(errno)); - } - if (bind(ctx->sock, sap, sap_len) < 0) { - char tmp[MAX_NTOP]; - save_errno = errno; - (*ctx->logger)(ctl_error, "%s: bind: %s: %s", - me, ctl_sa_ntop((struct sockaddr *)sap, - tmp, sizeof tmp, ctx->logger), - strerror(save_errno)); - close(ctx->sock); - memput(ctx, sizeof *ctx); - errno = save_errno; - return (NULL); - } - if (fcntl(ctx->sock, F_SETFD, 1) < 0) { - (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me, - strerror(errno)); - } - if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx, - &ctx->acID) < 0) { - save_errno = errno; - (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s", - me, (void *)ctx->sock, strerror(errno)); - close(ctx->sock); - memput(ctx, sizeof *ctx); - errno = save_errno; - return (NULL); - } - (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d", - me, ctx, ctx->sock); - return (ctx); -} - -/* - * void - * ctl_endserver(ctx) - * if the control listener is open, close it. clean out all eventlib - * stuff. close all active sessions. - */ -void -ctl_endserver(struct ctl_sctx *ctx) { - static const char me[] = "ctl_endserver"; - struct ctl_sess *this, *next; - - (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p", - me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess); - if (ctx->acID.opaque != NULL) { - (void)evCancelConn(ctx->ev, ctx->acID); - ctx->acID.opaque = NULL; - } - if (ctx->sock != -1) { - (void) close(ctx->sock); - ctx->sock = -1; - } - for (this = HEAD(ctx->sess); this != NULL; this = next) { - next = NEXT(this, link); - ctl_close(this); - } - memput(ctx, sizeof *ctx); -} - -/* - * If body is non-NULL then it we add a "." line after it. - * Caller must have escaped lines with leading ".". - */ -void -ctl_response(struct ctl_sess *sess, u_int code, const char *text, - u_int flags, void *respctx, ctl_srvrdone donefunc, void *uap, - const char *body, size_t bodylen) -{ - static const char me[] = "ctl_response"; - struct iovec iov[3], *iovp = iov; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP], *pc; - int n; - - REQUIRE(sess->state == initializing || - sess->state == processing || - sess->state == reading_data || - sess->state == writing); - REQUIRE(sess->wrtiID.opaque == NULL); - REQUIRE(sess->wrID.opaque == NULL); - ctl_new_state(sess, writing, me); - sess->donefunc = donefunc; - sess->uap = uap; - if (!allocated_p(sess->outbuf) && - ctl_bufget(&sess->outbuf, ctx->logger) < 0) { - (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer", - me, address_expr); - goto untimely; - } - if (sizeof "000-\r\n" + strlen(text) > MAX_LINELEN) { - (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing", - me, address_expr); - goto untimely; - } - sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n", - code, (flags & CTL_MORE) != 0 ? '-' : ' ', - text)); - for (pc = sess->outbuf.text, n = 0; n < sess->outbuf.used-2; pc++, n++) - if (!isascii(*pc) || !isprint(*pc)) - *pc = '\040'; - *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used); - if (body != NULL) { - *iovp++ = evConsIovec((char *)body, bodylen); - *iovp++ = evConsIovec(".\r\n", 3); - } - (*ctx->logger)(ctl_debug, "%s: [%d] %s", me, - sess->outbuf.used, sess->outbuf.text); - if (evWrite(ctx->ev, sess->sock, iov, iovp - iov, - ctl_writedone, sess, &sess->wrID) < 0) { - (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me, - address_expr, strerror(errno)); - goto untimely; - } - if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout, - &sess->wrtiID) < 0) - { - (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me, - address_expr, strerror(errno)); - goto untimely; - } - if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) { - (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me, - address_expr, strerror(errno)); - untimely: - ctl_signal_done(ctx, sess); - ctl_close(sess); - return; - } - sess->respctx = respctx; - sess->respflags = flags; -} - -void -ctl_sendhelp(struct ctl_sess *sess, u_int code) { - static const char me[] = "ctl_sendhelp"; - struct ctl_sctx *ctx = sess->ctx; - - sess->helpcode = code; - sess->verb = &fakehelpverb; - ctl_morehelp(ctx, sess, NULL, me, CTL_MORE, (void *)ctx->verbs, NULL); -} - -void * -ctl_getcsctx(struct ctl_sess *sess) { - return (sess->csctx); -} - -void * -ctl_setcsctx(struct ctl_sess *sess, void *csctx) { - void *old = sess->csctx; - - sess->csctx = csctx; - return (old); -} - -/* Private functions. */ - -static void -ctl_accept(evContext lev, void *uap, int fd, - const void *lav, int lalen, - const void *rav, int ralen) -{ - static const char me[] = "ctl_accept"; - struct ctl_sctx *ctx = uap; - struct ctl_sess *sess = NULL; - char tmp[MAX_NTOP]; - - if (fd < 0) { - (*ctx->logger)(ctl_error, "%s: accept: %s", - me, strerror(errno)); - return; - } - if (ctx->cur_sess == ctx->max_sess) { - (*ctx->logger)(ctl_error, "%s: %s: too many control sessions", - me, ctl_sa_ntop((struct sockaddr *)rav, - tmp, sizeof tmp, - ctx->logger)); - (void) close(fd); - return; - } - sess = memget(sizeof *sess); - if (sess == NULL) { - (*ctx->logger)(ctl_error, "%s: memget: %s", me, - strerror(errno)); - (void) close(fd); - return; - } - if (fcntl(fd, F_SETFD, 1) < 0) { - (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me, - strerror(errno)); - } - ctx->cur_sess++; - INIT_LINK(sess, link); - APPEND(ctx->sess, sess, link); - sess->ctx = ctx; - sess->sock = fd; - sess->wrID.opaque = NULL; - sess->rdID.opaque = NULL; - sess->wrtiID.opaque = NULL; - sess->rdtiID.opaque = NULL; - sess->respctx = NULL; - sess->csctx = NULL; - if (((struct sockaddr *)rav)->sa_family == AF_UNIX) - ctl_sa_copy((struct sockaddr *)lav, - (struct sockaddr *)&sess->sa); - else - ctl_sa_copy((struct sockaddr *)rav, - (struct sockaddr *)&sess->sa); - sess->donefunc = NULL; - buffer_init(sess->inbuf); - buffer_init(sess->outbuf); - sess->state = available; - ctl_new_state(sess, initializing, me); - sess->verb = ctx->connverb; - (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)", - me, address_expr, sess->sock); - (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0, - (struct sockaddr *)rav, ctx->uctx); -} - -static void -ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason) -{ - static const char me[] = "ctl_new_state"; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - - (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)", - me, address_expr, - state_names[sess->state], - state_names[new_state], reason); - sess->state = new_state; -} - -static void -ctl_close(struct ctl_sess *sess) { - static const char me[] = "ctl_close"; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - - REQUIRE(sess->state == initializing || - sess->state == writing || - sess->state == reading || - sess->state == processing || - sess->state == reading_data || - sess->state == idling); - REQUIRE(sess->sock != -1); - if (sess->state == reading || sess->state == reading_data) - ctl_stop_read(sess); - else if (sess->state == writing) { - if (sess->wrID.opaque != NULL) { - (void) evCancelRW(ctx->ev, sess->wrID); - sess->wrID.opaque = NULL; - } - if (sess->wrtiID.opaque != NULL) { - (void) evClearIdleTimer(ctx->ev, sess->wrtiID); - sess->wrtiID.opaque = NULL; - } - } - ctl_new_state(sess, closing, me); - (void) close(sess->sock); - if (allocated_p(sess->inbuf)) - ctl_bufput(&sess->inbuf); - if (allocated_p(sess->outbuf)) - ctl_bufput(&sess->outbuf); - (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)", - me, address_expr, sess->sock); - UNLINK(ctx->sess, sess, link); - memput(sess, sizeof *sess); - ctx->cur_sess--; -} - -static void -ctl_start_read(struct ctl_sess *sess) { - static const char me[] = "ctl_start_read"; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - - REQUIRE(sess->state == initializing || - sess->state == writing || - sess->state == processing || - sess->state == idling); - REQUIRE(sess->rdtiID.opaque == NULL); - REQUIRE(sess->rdID.opaque == NULL); - sess->inbuf.used = 0; - if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout, - &sess->rdtiID) < 0) - { - (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me, - address_expr, strerror(errno)); - ctl_close(sess); - return; - } - if (evSelectFD(ctx->ev, sess->sock, EV_READ, - ctl_readable, sess, &sess->rdID) < 0) { - (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me, - address_expr, strerror(errno)); - return; - } - ctl_new_state(sess, reading, me); -} - -static void -ctl_stop_read(struct ctl_sess *sess) { - static const char me[] = "ctl_stop_read"; - struct ctl_sctx *ctx = sess->ctx; - - REQUIRE(sess->state == reading || sess->state == reading_data); - REQUIRE(sess->rdID.opaque != NULL); - (void) evDeselectFD(ctx->ev, sess->rdID); - sess->rdID.opaque = NULL; - if (sess->rdtiID.opaque != NULL) { - (void) evClearIdleTimer(ctx->ev, sess->rdtiID); - sess->rdtiID.opaque = NULL; - } - ctl_new_state(sess, idling, me); -} - -static void -ctl_readable(evContext lev, void *uap, int fd, int evmask) { - static const char me[] = "ctl_readable"; - struct ctl_sess *sess = uap; - struct ctl_sctx *ctx = sess->ctx; - char *eos, tmp[MAX_NTOP]; - ssize_t n; - - REQUIRE(sess != NULL); - REQUIRE(fd >= 0); - REQUIRE(evmask == EV_READ); - REQUIRE(sess->state == reading || sess->state == reading_data); - evTouchIdleTimer(lev, sess->rdtiID); - if (!allocated_p(sess->inbuf) && - ctl_bufget(&sess->inbuf, ctx->logger) < 0) { - (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer", - me, address_expr); - ctl_close(sess); - return; - } - n = read(sess->sock, sess->inbuf.text + sess->inbuf.used, - MAX_LINELEN - sess->inbuf.used); - if (n <= 0) { - (*ctx->logger)(ctl_debug, "%s: %s: read: %s", - me, address_expr, - (n == 0) ? "Unexpected EOF" : strerror(errno)); - ctl_close(sess); - return; - } - sess->inbuf.used += n; - eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used); - if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') { - eos[-1] = '\0'; - if ((sess->respflags & CTL_DATA) != 0) { - INSIST(sess->verb != NULL); - (*sess->verb->func)(sess->ctx, sess, sess->verb, - sess->inbuf.text, - CTL_DATA, sess->respctx, - sess->ctx->uctx); - } else { - ctl_stop_read(sess); - ctl_docommand(sess); - } - sess->inbuf.used -= ((eos - sess->inbuf.text) + 1); - if (sess->inbuf.used == 0) - ctl_bufput(&sess->inbuf); - else - memmove(sess->inbuf.text, eos + 1, sess->inbuf.used); - return; - } - if (sess->inbuf.used == MAX_LINELEN) { - (*ctx->logger)(ctl_error, "%s: %s: line too long, closing", - me, address_expr); - ctl_close(sess); - } -} - -static void -ctl_wrtimeout(evContext lev, void *uap, - struct timespec due, - struct timespec itv) -{ - static const char me[] = "ctl_wrtimeout"; - struct ctl_sess *sess = uap; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - - REQUIRE(sess->state == writing); - sess->wrtiID.opaque = NULL; - (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing", - me, address_expr); - if (sess->wrID.opaque != NULL) { - (void) evCancelRW(ctx->ev, sess->wrID); - sess->wrID.opaque = NULL; - } - ctl_signal_done(ctx, sess); - ctl_new_state(sess, processing, me); - ctl_close(sess); -} - -static void -ctl_rdtimeout(evContext lev, void *uap, - struct timespec due, - struct timespec itv) -{ - static const char me[] = "ctl_rdtimeout"; - struct ctl_sess *sess = uap; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - - REQUIRE(sess->state == reading); - sess->rdtiID.opaque = NULL; - (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing", - me, address_expr); - if (sess->state == reading || sess->state == reading_data) - ctl_stop_read(sess); - ctl_signal_done(ctx, sess); - ctl_new_state(sess, processing, me); - ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL, - NULL, NULL, NULL, 0); -} - -static void -ctl_docommand(struct ctl_sess *sess) { - static const char me[] = "ctl_docommand"; - char *name, *rest, tmp[MAX_NTOP]; - struct ctl_sctx *ctx = sess->ctx; - const struct ctl_verb *verb; - - REQUIRE(allocated_p(sess->inbuf)); - (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]", - me, address_expr, - sess->inbuf.text, (u_int)sess->inbuf.used); - ctl_new_state(sess, processing, me); - name = sess->inbuf.text + strspn(sess->inbuf.text, space); - rest = name + strcspn(name, space); - if (*rest != '\0') { - *rest++ = '\0'; - rest += strspn(rest, space); - } - for (verb = ctx->verbs; - verb != NULL && verb->name != NULL && verb->func != NULL; - verb++) - if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0) - break; - if (verb != NULL && verb->name != NULL && verb->func != NULL) { - sess->verb = verb; - (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx); - } else { - char buf[1100]; - - if (sizeof "Unrecognized command \"\" (args \"\")" + - strlen(name) + strlen(rest) > sizeof buf) - strcpy(buf, "Unrecognized command (buf ovf)"); - else - sprintf(buf, - "Unrecognized command \"%s\" (args \"%s\")", - name, rest); - ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL, - NULL, 0); - } -} - -static void -ctl_writedone(evContext lev, void *uap, int fd, int bytes) { - static const char me[] = "ctl_writedone"; - struct ctl_sess *sess = uap; - struct ctl_sctx *ctx = sess->ctx; - char tmp[MAX_NTOP]; - int save_errno = errno; - - REQUIRE(sess->state == writing); - REQUIRE(fd == sess->sock); - REQUIRE(sess->wrtiID.opaque != NULL); - sess->wrID.opaque = NULL; - (void) evClearIdleTimer(ctx->ev, sess->wrtiID); - sess->wrtiID.opaque = NULL; - if (bytes < 0) { - (*ctx->logger)(ctl_error, "%s: %s: %s", - me, address_expr, strerror(save_errno)); - ctl_close(sess); - return; - } - - INSIST(allocated_p(sess->outbuf)); - ctl_bufput(&sess->outbuf); - if ((sess->respflags & CTL_EXIT) != 0) { - ctl_signal_done(ctx, sess); - ctl_close(sess); - return; - } else if ((sess->respflags & CTL_MORE) != 0) { - INSIST(sess->verb != NULL); - (*sess->verb->func)(sess->ctx, sess, sess->verb, "", - CTL_MORE, sess->respctx, sess->ctx->uctx); - } else { - ctl_signal_done(ctx, sess); - ctl_start_read(sess); - } -} - -static void -ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess, - const struct ctl_verb *verb, const char *text, - u_int respflags, void *respctx, void *uctx) -{ - struct ctl_verb *this = respctx, *next = this + 1; - - REQUIRE(!lastverb_p(this)); - REQUIRE((respflags & CTL_MORE) != 0); - if (lastverb_p(next)) - respflags &= ~CTL_MORE; - ctl_response(sess, sess->helpcode, this->help, respflags, next, - NULL, NULL, NULL, 0); -} - -static void -ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) { - if (sess->donefunc != NULL) { - (*sess->donefunc)(ctx, sess, sess->uap); - sess->donefunc = NULL; - } -} |