summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/runner.c
diff options
context:
space:
mode:
authorJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-04-21 18:12:06 +0000
committerJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-04-21 18:12:06 +0000
commit604abccd0e6aa1fe8eae11effee1b454e839bd87 (patch)
tree53033a043b6c2b4d4fed3af3785af86690215757 /usr.sbin/smtpd/runner.c
parent65fbea4c6c81c751d2f36dd30b53cb9beffeb9da (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.c75
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];