diff options
author | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-04-21 18:12:06 +0000 |
---|---|---|
committer | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-04-21 18:12:06 +0000 |
commit | 604abccd0e6aa1fe8eae11effee1b454e839bd87 (patch) | |
tree | 53033a043b6c2b4d4fed3af3785af86690215757 /usr.sbin/smtpd/runner.c | |
parent | 65fbea4c6c81c751d2f36dd30b53cb9beffeb9da (diff) |
Make /usr/sbin/sendmail not fail due to smtpd being down.
The approach is to save cmdline + stdin in a file under a newly
added directory /var/spool/smtpd/offline (uid 0 gid 0 mode 1777).
Next time daemon starts, it uses information in that directory
to replay sendmail on user's behalf.
ok gilles@
Diffstat (limited to 'usr.sbin/smtpd/runner.c')
-rw-r--r-- | usr.sbin/smtpd/runner.c | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/usr.sbin/smtpd/runner.c b/usr.sbin/smtpd/runner.c index a52abac2f74..986c90c8882 100644 --- a/usr.sbin/smtpd/runner.c +++ b/usr.sbin/smtpd/runner.c @@ -1,4 +1,4 @@ -/* $OpenBSD: runner.c,v 1.41 2009/04/21 14:37:32 eric Exp $ */ +/* $OpenBSD: runner.c,v 1.42 2009/04/21 18:12:05 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -48,6 +48,7 @@ __dead void runner_shutdown(void); void runner_sig_handler(int, short, void *); +void runner_dispatch_parent(int, short, void *); void runner_dispatch_control(int, short, void *); void runner_dispatch_queue(int, short, void *); void runner_dispatch_mda(int, short, void *); @@ -57,6 +58,7 @@ void runner_setup_events(struct smtpd *); void runner_disable_events(struct smtpd *); void runner_reset_flags(void); +void runner_process_offline(struct smtpd *); void runner_timeout(int, short, void *); @@ -95,6 +97,55 @@ runner_sig_handler(int sig, short event, void *p) } void +runner_dispatch_parent(int sig, short event, void *p) +{ + struct smtpd *env = p; + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + + ibuf = env->sc_ibufs[PROC_PARENT]; + switch (event) { + case EV_READ: + if ((n = imsg_read(ibuf)) == -1) + fatal("imsg_read_error"); + if (n == 0) { + /* this pipe is dead, so remove the event handler */ + event_del(&ibuf->ev); + event_loopexit(NULL); + return; + } + 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("runner_dispatch_parent: imsg_read error"); + if (n == 0) + break; + + switch (imsg.hdr.type) { + case IMSG_PARENT_ENQUEUE_OFFLINE: + runner_process_offline(env); + break; + default: + log_warnx("runner_dispatch_parent: got imsg %d", + imsg.hdr.type); + fatalx("runner_dispatch_parent: unexpected imsg"); + } + imsg_free(&imsg); + } + imsg_event_add(ibuf); +} + +void runner_dispatch_control(int sig, short event, void *p) { struct smtpd *env = p; @@ -398,6 +449,7 @@ runner(struct smtpd *env) struct event ev_sigterm; struct peer peers[] = { + { PROC_PARENT, runner_dispatch_parent }, { PROC_CONTROL, runner_dispatch_control }, { PROC_MDA, runner_dispatch_mda }, { PROC_MTA, runner_dispatch_mta }, @@ -448,11 +500,12 @@ runner(struct smtpd *env) signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); - config_pipes(env, peers, 5); - config_peers(env, peers, 5); + config_pipes(env, peers, 6); + config_peers(env, peers, 6); unlink(PATH_QUEUE "/envelope.tmp"); runner_reset_flags(); + runner_process_offline(env); runner_setup_events(env); event_dispatch(); @@ -462,6 +515,22 @@ runner(struct smtpd *env) } void +runner_process_offline(struct smtpd *env) +{ + char path[MAXPATHLEN]; + struct qwalk *q; + + q = qwalk_new(PATH_OFFLINE); + + if (qwalk(q, path)) + imsg_compose(env->sc_ibufs[PROC_PARENT], + IMSG_PARENT_ENQUEUE_OFFLINE, 0, 0, -1, path, + strlen(path) + 1); + + qwalk_close(q); +} + +void runner_reset_flags(void) { char path[MAXPATHLEN]; |