diff options
Diffstat (limited to 'usr.sbin/hostated/hostated.c')
-rw-r--r-- | usr.sbin/hostated/hostated.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/usr.sbin/hostated/hostated.c b/usr.sbin/hostated/hostated.c new file mode 100644 index 00000000000..32c0989c4cc --- /dev/null +++ b/usr.sbin/hostated/hostated.c @@ -0,0 +1,377 @@ +/* $OpenBSD: hostated.c,v 1.1 2006/12/16 11:45:07 reyk Exp $ */ + +/* + * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> + * + * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <net/if.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <err.h> +#include <errno.h> +#include <event.h> +#include <signal.h> +#include <unistd.h> +#include <pwd.h> + +#include "hostated.h" + +__dead void usage(void); + +void main_sig_handler(int, short, void *); +void main_shutdown(void); +void main_dispatch_pfe(int, short, void *); +void main_dispatch_hce(int, short, void *); +int check_child(pid_t, const char *); + +int pipe_parent2pfe[2]; +int pipe_parent2hce[2]; +int pipe_pfe2hce[2]; + +struct imsgbuf *ibuf_pfe; +struct imsgbuf *ibuf_hce; + +pid_t pfe_pid = 0; +pid_t hce_pid = 0; + +void +main_sig_handler(int sig, short event, void *arg) +{ + int die = 0; + + switch (sig) { + case SIGTERM: + case SIGINT: + die = 1; + case SIGCHLD: + if (check_child(pfe_pid, "pf udpate engine")) { + pfe_pid = 0; + die = 1; + } + if (check_child(hce_pid, "host check engine")) { + hce_pid = 0; + die = 1; + } + if (die) + main_shutdown(); + break; + case SIGHUP: + /* reconfigure */ + break; + default: + fatalx("unexpected signal"); + } +} + +/* __dead is for lint */ +__dead void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "%s [-dnv] [-f file]\n", __progname); + exit (1); +} + +int main(int argc, char *argv[]) +{ + int c; + int debug; + u_int32_t opts; + struct hostated env; + const char *conffile; + struct event ev_sigint; + struct event ev_sigterm; + struct event ev_sigchld; + struct event ev_sighup; + + opts = 0; + debug = 0; + conffile = CONF_FILE; + bzero(&env, sizeof (env)); + + for (;(c = getopt(argc, argv, "dnf:v")) != -1;) { + switch (c) { + case 'd': + debug = 1; + break; + case 'n': + opts |= HOSTATED_OPT_NOACTION; + break; + case 'f': + conffile = optarg; + break; + case 'v': + opts |= HOSTATED_OPT_VERBOSE; + break; + default: + usage(); + } + + } + + log_init(debug); + + if (parse_config(&env, conffile, opts)) + exit(1); + + if (env.opts & HOSTATED_OPT_NOACTION) { + fprintf(stderr, "configuration OK\n"); + exit(0); + } + + if (geteuid()) + errx(1, "need root privileges"); + + if (getpwnam(HOSTATED_USER) == NULL) + errx(1, "unknown user %s", HOSTATED_USER); + + if (!debug) + daemon(1, 0); + + log_info("startup"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2pfe) == -1) + fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2hce) == -1) + fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_pfe2hce) == -1) + fatal("socketpair"); + + session_socket_blockmode(pipe_parent2pfe[0], BM_NONBLOCK); + session_socket_blockmode(pipe_parent2pfe[1], BM_NONBLOCK); + session_socket_blockmode(pipe_parent2hce[0], BM_NONBLOCK); + session_socket_blockmode(pipe_parent2hce[1], BM_NONBLOCK); + session_socket_blockmode(pipe_pfe2hce[0], BM_NONBLOCK); + session_socket_blockmode(pipe_pfe2hce[1], BM_NONBLOCK); + + pfe_pid = pfe(&env, pipe_parent2pfe, pipe_parent2hce, pipe_pfe2hce); + hce_pid = hce(&env, pipe_parent2pfe, pipe_parent2hce, pipe_pfe2hce); + + setproctitle("parent"); + + event_init(); + + signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + signal_add(&ev_sighup, NULL); + + close(pipe_parent2pfe[1]); + close(pipe_parent2hce[1]); + close(pipe_pfe2hce[0]); + close(pipe_pfe2hce[1]); + + if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL || + (ibuf_hce = calloc(1, sizeof(struct imsgbuf))) == NULL) + fatal(NULL); + + imsg_init(ibuf_pfe, pipe_parent2pfe[0], main_dispatch_pfe); + imsg_init(ibuf_hce, pipe_parent2hce[0], main_dispatch_hce); + + ibuf_pfe->events = EV_READ; + event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events, + ibuf_pfe->handler, ibuf_pfe); + event_add(&ibuf_pfe->ev, NULL); + + ibuf_hce->events = EV_READ; + event_set(&ibuf_hce->ev, ibuf_hce->fd, ibuf_hce->events, + ibuf_hce->handler, ibuf_hce); + event_add(&ibuf_hce->ev, NULL); + + event_dispatch(); + + return (0); +} + +void +main_shutdown(void) +{ + pid_t pid; + + if (pfe_pid) + kill(pfe_pid, SIGTERM); + if (hce_pid) + kill(hce_pid, SIGTERM); + + do { + if ((pid = wait(NULL)) == -1 && + errno != EINTR && errno != ECHILD) + fatal("wait"); + } while (pid != -1 || (pid == -1 && errno == EINTR)); + + control_cleanup(); + log_info("terminating"); + exit(0); +} + +int +check_child(pid_t pid, const char *pname) +{ + int status; + + if (waitpid(pid, &status, WNOHANG) > 0) { + if (WIFEXITED(status)) { + log_warnx("check_child: lost child: %s exited", pname); + return (1); + } + if (WIFSIGNALED(status)) { + log_warnx("check_child: lost child: %s terminated; signal %d", + pname, WTERMSIG(status)); + return (1); + } + } + + return (0); +} + +void +imsg_event_add(struct imsgbuf *ibuf) +{ + ibuf->events = EV_READ; + if (ibuf->w.queued) + ibuf->events |= EV_WRITE; + + event_del(&ibuf->ev); + event_set(&ibuf->ev, ibuf->fd, ibuf->events, ibuf->handler, ibuf); + event_add(&ibuf->ev, NULL); +} + +void +main_dispatch_pfe(int fd, short event, void *ptr) +{ + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + + ibuf = ptr; + switch (event) { + case EV_READ: + if ((n = imsg_read(ibuf)) == -1) + fatal("imsg_read_error"); + if (n == 0) + fatalx("parent: pipe closed"); + break; + case EV_WRITE: + if (msgbuf_write(&ibuf->w) == -1) + fatal("msgbuf_write"); + imsg_event_add(ibuf); + return; + default: + fatalx("unknown event"); + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("main_dispatch_pfe: imsg_read error"); + if (n == 0) + break; + + switch (imsg.hdr.type) { + default: + log_debug("main_dispatch_pfe: unexpected imsg %d", + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + imsg_event_add(ibuf); +} + +void +main_dispatch_hce(int fd, short event, void * ptr) +{ + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + + ibuf = ptr; + switch (event) { + case EV_READ: + if ((n = imsg_read(ibuf)) == -1) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + fatalx("parent: pipe closed"); + break; + case EV_WRITE: + if (msgbuf_write(&ibuf->w) == -1) + fatal("msgbuf_write"); + imsg_event_add(ibuf); + return; + default: + fatalx("unknown event"); + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("main_dispatch_hce: imsg_read error"); + if (n == 0) + break; + + switch (imsg.hdr.type) { + default: + log_debug("main_dispatch_hce: unexpected imsg %d", + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } +} + +struct host * +host_find(struct hostated *env, objid_t id) +{ + struct table *table; + struct host *host; + + TAILQ_FOREACH(table, &env->tables, entry) + TAILQ_FOREACH(host, &table->hosts, entry) + if (host->id == id) + return (host); + return (NULL); +} + +struct table * +table_find(struct hostated *env, objid_t id) +{ + struct table *table; + + TAILQ_FOREACH(table, &env->tables, entry) + if (table->id == id) + return (table); + return (NULL); +} + +struct service * +service_find(struct hostated *env, objid_t id) +{ + struct service *service; + + TAILQ_FOREACH(service, &env->services, entry) + if (service->id == id) + return (service); + return (NULL); +} |