Index | Thread | Search

From:
Martijn van Duren <openbsd+tech@list.imperialat.at>
Subject:
smtpd: create startup.c
To:
tech@openbsd.org
Date:
Wed, 1 Jul 2026 15:23:46 +0200

Download raw body.

Thread
  • Martijn van Duren:

    smtpd: create startup.c

Hello tech@,

Here's a followup to the shuffling of the deckchairs diff. This diff is
basically more of the same, but creates a new startup.c for functions
and variables that would cause issues for smtpctl when added to util.c.

I realize that startup.c isn't an ideal name, but since it's needed give
each libexec binary their own main() function it's the best I could come
up with.

This diff moves the env, p_*, profiling, backend_*, smtpd_process
variables, and imsg_callback, and setup_peer(), setup_proc(),
imsg_wait(), load_pki_tree(), load_pki_keys(), fork_proc_backend(),
and imsg_dispatch() functions into startup.c.

The debug variable appears to be a dead store, so can be removed.

The next step is giving each binary their own main().

OK?

martijn@

diff d010102fe4efde3ee95164581695909c7c6b672a 7c135bf813cf25880851c83cbd4734bfe1ac67c3
commit - d010102fe4efde3ee95164581695909c7c6b672a
commit + 7c135bf813cf25880851c83cbd4734bfe1ac67c3
blob - a6337c2bb329e27300a21ffa517a5a84d0f773c5
blob + 37b6919a9da103b0f3ce6bccfcb98f6dd5a47d6e
--- usr.sbin/smtpd/smtpd/Makefile
+++ usr.sbin/smtpd/smtpd/Makefile
@@ -14,7 +14,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 206cd414a29ac4acbb22b6a540c5ca2751098e90
blob + a00f8c6d79b8fea6b9071776ced8a909654aefd4
--- usr.sbin/smtpd/smtpd-ca/Makefile
+++ usr.sbin/smtpd/smtpd-ca/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 22d7abdc025cccaec993ecec8f4ab7c4377fd8b3
blob + d289b421744c03b32a2296c421e9f3734cd44089
--- usr.sbin/smtpd/smtpd-control/Makefile
+++ usr.sbin/smtpd/smtpd-control/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 9aa8e1c7ceb3112f7aaba17352f5b5aa3b242bf7
blob + f4c47fd8387e2bf7ee7c22a395f5e74b099be30d
--- usr.sbin/smtpd/smtpd-dispatcher/Makefile
+++ usr.sbin/smtpd/smtpd-dispatcher/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 03476d16571fc4fb85105215a79543bfb9882166
blob + 0b82bec27876d79e60fa80a4a65436fe3633142e
--- usr.sbin/smtpd/smtpd-lka/Makefile
+++ usr.sbin/smtpd/smtpd-lka/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 6fce8a91f1035dffdd28a98bb546d0ed5c62b977
blob + 7b6651dbeda248bc110f0b655118e59e23dfd9b2
--- usr.sbin/smtpd/smtpd-queue/Makefile
+++ usr.sbin/smtpd/smtpd-queue/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 93076c8a5241d7202b0810b4d3d723377dbaba1d
blob + d26854ca8cd02f506b2c4ebaf93fc204f0130a2c
--- usr.sbin/smtpd/smtpd-scheduler/Makefile
+++ usr.sbin/smtpd/smtpd-scheduler/Makefile
@@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
 	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
 	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
 	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
-	stat_backend.c table.c to.c tree.c util.c waitq.c \
+	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
 	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
 	table_static.c queue_fs.c queue_null.c queue_proc.c \
 	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
blob - 7292b6810caaa49358b7b92ef3f26ade95d2ea42
blob + de95861f48bf015b5cc1cce1857a8318d266111b
--- usr.sbin/smtpd/smtpd.c
+++ usr.sbin/smtpd/smtpd.c
@@ -59,12 +59,8 @@ static void forkmda(struct mproc *, uint64_t, struct d
 static int parent_forward_open(char *, char *, uid_t, gid_t);
 static struct child *child_add(pid_t, int, const char *);
 static struct mproc *start_child(int, char **, char *);
-static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int);
 static void setup_peers(struct mproc *, struct mproc *);
 static void setup_done(struct mproc *);
-static void setup_proc(void);
-static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int);
-static int imsg_wait(struct imsgbuf *, struct imsg *, int);
 
 static void	offline_scan(int, short, void *);
 static int	offline_add(char *, uid_t, gid_t);
@@ -73,8 +69,6 @@ static int	offline_enqueue(char *, uid_t, gid_t);
 
 static void	purge_task(void);
 static int	parent_auth_user(const char *, const char *);
-static void	load_pki_tree(void);
-static void	load_pki_keys(void);
 
 static void	fork_filter_processes(void);
 static void	fork_filter_process(const char *, struct filter_proc *);
@@ -115,26 +109,11 @@ static struct timeval		offline_timeout;
 static pid_t			purge_pid = -1;
 
 extern char	**environ;
-void		(*imsg_callback)(struct mproc *, struct imsg *);
 
-enum smtp_proc_type	smtpd_process;
+extern const char	*backend_queue;
+extern const char	*backend_scheduler;
+extern const char	*backend_stat;
 
-struct smtpd	*env = NULL;
-
-struct mproc	*p_control = NULL;
-struct mproc	*p_lka = NULL;
-struct mproc	*p_parent = NULL;
-struct mproc	*p_queue = NULL;
-struct mproc	*p_scheduler = NULL;
-struct mproc	*p_dispatcher = NULL;
-struct mproc	*p_ca = NULL;
-
-const char	*backend_queue = "fs";
-const char	*backend_scheduler = "ramqueue";
-const char	*backend_stat = "ram";
-
-int	profiling = 0;
-int	debug = 0;
 int	foreground = 0;
 int	control_socket = -1;
 
@@ -483,7 +462,6 @@ main(int argc, char *argv[])
 
 	flags = 0;
 	opts = 0;
-	debug = 0;
 	tracing = 0;
 
 	log_init(1, LOG_MAIL);
@@ -523,7 +501,6 @@ main(int argc, char *argv[])
 			usage();
 			break;
 		case 'n':
-			debug = 2;
 			opts |= SMTPD_OPT_NOACTION;
 			break;
 		case 'f':
@@ -902,136 +879,6 @@ setup_done(struct mproc *p)
 	imsg_free(&imsg);
 }
 
-static void
-setup_proc(void)
-{
-	struct imsgbuf *ibuf;
-	struct imsg imsg;
-        int setup = 1;
-
-	log_procinit(proc_title(smtpd_process));
-
-	p_parent = calloc(1, sizeof(*p_parent));
-	if (p_parent == NULL)
-		fatal("calloc");
-	if((p_parent->name = strdup("parent")) == NULL)
-		fatal("strdup");
-	p_parent->proc = PROC_PARENT;
-	p_parent->handler = imsg_dispatch;
-	mproc_init(p_parent, 3);
-
-	ibuf = &p_parent->imsgbuf;
-
-	while (setup) {
-		if (imsg_wait(ibuf, &imsg, 10000) == -1)
-			fatal("imsg_wait");
-
-		switch (imsg.hdr.type) {
-		case IMSG_SETUP_KEY:
-			env->sc_queue_key = strdup(imsg.data);
-			break;
-		case IMSG_SETUP_PEER:
-			setup_peer(imsg.hdr.peerid, imsg.hdr.pid,
-			    imsg_get_fd(&imsg));
-			break;
-		case IMSG_SETUP_DONE:
-			setup = 0;
-			break;
-		default:
-			fatal("bad imsg %d", imsg.hdr.type);
-		}
-		imsg_free(&imsg);
-	}
-
-	if (imsg_compose(ibuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1)
-		fatal("imsg_compose");
-
-	if (imsgbuf_flush(ibuf) == -1)
-		fatal("imsgbuf_flush");
-
-	log_debug("setup_proc: %s done", proc_title(smtpd_process));
-}
-
-static struct mproc *
-setup_peer(enum smtp_proc_type proc, pid_t pid, int sock)
-{
-	struct mproc *p, **pp;
-
-	log_debug("setup_peer: %s -> %s[%u] fd=%d", proc_title(smtpd_process),
-	    proc_title(proc), pid, sock);
-
-	if (sock == -1)
-		fatalx("peer socket not received");
-
-	switch (proc) {
-	case PROC_LKA:
-		pp = &p_lka;
-		break;
-	case PROC_QUEUE:
-		pp = &p_queue;
-		break;
-	case PROC_CONTROL:
-		pp = &p_control;
-		break;
-	case PROC_SCHEDULER:
-		pp = &p_scheduler;
-		break;
-	case PROC_DISPATCHER:
-		pp = &p_dispatcher;
-		break;
-	case PROC_CA:
-		pp = &p_ca;
-		break;
-	default:
-		fatalx("unknown peer");
-	}
-
-	if (*pp)
-		fatalx("peer already set");
-
-	p = calloc(1, sizeof(*p));
-	if (p == NULL)
-		fatal("calloc");
-	if((p->name = strdup(proc_title(proc))) == NULL)
-		fatal("strdup");
-	mproc_init(p, sock);
-	p->pid = pid;
-	p->proc = proc;
-	p->handler = imsg_dispatch;
-
-	*pp = p;
-
-	return p;
-}
-
-static int
-imsg_wait(struct imsgbuf *ibuf, struct imsg *imsg, int timeout)
-{
-	struct pollfd pfd[1];
-	ssize_t n;
-
-	pfd[0].fd = ibuf->fd;
-	pfd[0].events = POLLIN;
-
-	while (1) {
-		if ((n = imsg_get(ibuf, imsg)) == -1)
-			return -1;
-		if (n)
-			return 1;
-
-		n = poll(pfd, 1, timeout);
-		if (n == -1)
-			return -1;
-		if (n == 0) {
-			errno = ETIMEDOUT;
-			return -1;
-		}
-
-		if (imsgbuf_read(ibuf) != 1)
-			return -1;
-	}
-}
-
 int
 smtpd(void) {
 	struct event	 ev_sigint;
@@ -1093,111 +940,6 @@ smtpd(void) {
 	return (0);
 }
 
-static void
-load_pki_tree(void)
-{
-	struct pki	*pki;
-	struct ca	*sca;
-	const char	*k;
-	void		*iter_dict;
-
-	log_debug("debug: init ssl-tree");
-	iter_dict = NULL;
-	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
-		log_debug("info: loading pki information for %s", k);
-		if (pki->pki_cert_file == NULL)
-			fatalx("load_pki_tree: missing certificate file");
-		if (pki->pki_key_file == NULL)
-			fatalx("load_pki_tree: missing key file");
-
-		if (!ssl_load_certificate(pki, pki->pki_cert_file))
-			fatalx("load_pki_tree: failed to load certificate file");
-	}
-
-	log_debug("debug: init ca-tree");
-	iter_dict = NULL;
-	while (dict_iter(env->sc_ca_dict, &iter_dict, &k, (void **)&sca)) {
-		log_debug("info: loading CA information for %s", k);
-		if (!ssl_load_cafile(sca, sca->ca_cert_file))
-			fatalx("load_pki_tree: failed to load CA file");
-	}
-}
-
-void
-load_pki_keys(void)
-{
-	struct pki	*pki;
-	const char	*k;
-	void		*iter_dict;
-
-	log_debug("debug: init ssl-tree");
-	iter_dict = NULL;
-	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
-		log_debug("info: loading pki keys for %s", k);
-
-		if (!ssl_load_keyfile(pki, pki->pki_key_file, k))
-			fatalx("load_pki_keys: failed to load key file");
-	}
-}
-
-int
-fork_proc_backend(const char *key, const char *conf, const char *procname,
-    int do_stdout)
-{
-	pid_t		pid;
-	int		sp[2];
-	char		path[PATH_MAX];
-	char		name[PATH_MAX];
-	char		*arg;
-
-	if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) {
-		log_warnx("warn: %s-proc: conf too long", key);
-		return (-1);
-	}
-
-	arg = strchr(name, ':');
-	if (arg)
-		*arg++ = '\0';
-
-	if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >=
-	    (ssize_t)sizeof(path)) {
-		log_warn("warn: %s-proc: exec path too long", key);
-		return (-1);
-	}
-
-	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
-		log_warn("warn: %s-proc: socketpair", key);
-		return (-1);
-	}
-
-	if ((pid = fork()) == -1) {
-		log_warn("warn: %s-proc: fork", key);
-		close(sp[0]);
-		close(sp[1]);
-		return (-1);
-	}
-
-	if (pid == 0) {
-		/* child process */
-		dup2(sp[0], STDIN_FILENO);
-		if (do_stdout)
-			dup2(sp[0], STDOUT_FILENO);
-		if (closefrom(STDERR_FILENO + 1) == -1)
-			exit(1);
-
-		if (procname == NULL)
-			procname = name;
-
-		execl(path, procname, arg, (char *)NULL);
-		fatal("execl: %s", path);
-	}
-
-	/* parent process */
-	close(sp[0]);
-
-	return (sp[1]);
-}
-
 struct child *
 child_add(pid_t pid, int type, const char *title)
 {
@@ -1835,54 +1577,6 @@ parent_forward_open(char *username, char *directory, u
 	return fd;
 }
 
-void
-imsg_dispatch(struct mproc *p, struct imsg *imsg)
-{
-	struct timespec	t0, t1, dt;
-	int		msg;
-
-	if (imsg == NULL) {
-		imsg_callback(p, imsg);
-		return;
-	}
-
-	log_imsg(smtpd_process, p->proc, imsg);
-
-	if (profiling & PROFILE_IMSG)
-		clock_gettime(CLOCK_MONOTONIC, &t0);
-
-	msg = imsg->hdr.type;
-	imsg_callback(p, imsg);
-
-	if (profiling & PROFILE_IMSG) {
-		clock_gettime(CLOCK_MONOTONIC, &t1);
-		timespecsub(&t1, &t0, &dt);
-
-		log_debug("profile-imsg: %s %s %s %d %lld.%09ld",
-		    proc_name(smtpd_process),
-		    proc_name(p->proc),
-		    imsg_to_str(msg),
-		    (int)imsg->hdr.len,
-		    (long long)dt.tv_sec,
-		    dt.tv_nsec);
-
-		if (profiling & PROFILE_TOSTAT) {
-			char	key[STAT_KEY_SIZE];
-			/* can't profstat control process yet */
-			if (smtpd_process == PROC_CONTROL)
-				return;
-
-			if (!bsnprintf(key, sizeof key,
-				"profiling.imsg.%s.%s.%s",
-				proc_name(smtpd_process),
-				proc_name(p->proc),
-				imsg_to_str(msg)))
-				return;
-			stat_set(key, stat_timespec(&dt));
-		}
-	}
-}
-
 int
 parent_auth_user(const char *username, const char *password)
 {
blob - b8268d69c6985d4d42234b550c8cfe6086d465b3
blob + fe8bcb8204fbf40110bcecfdf4ee634876b35013
--- usr.sbin/smtpd/smtpd.h
+++ usr.sbin/smtpd/smtpd.h
@@ -1614,6 +1614,12 @@ const char *srs_encode(const char *, const char *);
 const char *srs_decode(const char *);
 
 
+/* startup.c */
+void setup_proc(void);
+int imsg_wait(struct imsgbuf *, struct imsg *, int);
+void load_pki_tree(void);
+void load_pki_keys(void);
+
 /* stat_backend.c */
 struct stat_backend	*stat_backend_lookup(const char *);
 void	stat_increment(const char *, size_t);
blob - /dev/null
blob + 8195f93b98fd0b9a8bd5993d675cc69cc2ce4287 (mode 644)
--- /dev/null
+++ usr.sbin/smtpd/startup.c
@@ -0,0 +1,332 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
+ *
+ * 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 <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtpd.h"
+#include "log.h"
+#include "ssl.h"
+
+struct smtpd		*env = NULL;
+
+struct mproc		*p_control = NULL;
+struct mproc		*p_lka = NULL;
+struct mproc		*p_parent = NULL;
+struct mproc		*p_queue = NULL;
+struct mproc		*p_scheduler = NULL;
+struct mproc		*p_dispatcher = NULL;
+struct mproc		*p_ca = NULL;
+
+int			 profiling = 0;
+
+enum smtp_proc_type	 smtpd_process;
+
+const char		*backend_queue = "fs";
+const char		*backend_scheduler = "ramqueue";
+const char		*backend_stat = "ram";
+
+void (*imsg_callback)(struct mproc *, struct imsg *);
+
+static struct mproc *
+setup_peer(enum smtp_proc_type proc, pid_t pid, int sock)
+{
+	struct mproc *p, **pp;
+
+	log_debug("setup_peer: %s -> %s[%u] fd=%d", proc_title(smtpd_process),
+	    proc_title(proc), pid, sock);
+
+	if (sock == -1)
+		fatalx("peer socket not received");
+
+	switch (proc) {
+	case PROC_LKA:
+		pp = &p_lka;
+		break;
+	case PROC_QUEUE:
+		pp = &p_queue;
+		break;
+	case PROC_CONTROL:
+		pp = &p_control;
+		break;
+	case PROC_SCHEDULER:
+		pp = &p_scheduler;
+		break;
+	case PROC_DISPATCHER:
+		pp = &p_dispatcher;
+		break;
+	case PROC_CA:
+		pp = &p_ca;
+		break;
+	default:
+		fatalx("unknown peer");
+	}
+
+	if (*pp)
+		fatalx("peer already set");
+
+	p = calloc(1, sizeof(*p));
+	if (p == NULL)
+		fatal("calloc");
+	if((p->name = strdup(proc_title(proc))) == NULL)
+		fatal("strdup");
+	mproc_init(p, sock);
+	p->pid = pid;
+	p->proc = proc;
+	p->handler = imsg_dispatch;
+
+	*pp = p;
+
+	return p;
+}
+
+void
+setup_proc(void)
+{
+	struct imsgbuf *ibuf;
+	struct imsg imsg;
+        int setup = 1;
+
+	log_procinit(proc_title(smtpd_process));
+
+	p_parent = calloc(1, sizeof(*p_parent));
+	if (p_parent == NULL)
+		fatal("calloc");
+	if((p_parent->name = strdup("parent")) == NULL)
+		fatal("strdup");
+	p_parent->proc = PROC_PARENT;
+	p_parent->handler = imsg_dispatch;
+	mproc_init(p_parent, 3);
+
+	ibuf = &p_parent->imsgbuf;
+
+	while (setup) {
+		if (imsg_wait(ibuf, &imsg, 10000) == -1)
+			fatal("imsg_wait");
+
+		switch (imsg.hdr.type) {
+		case IMSG_SETUP_KEY:
+			env->sc_queue_key = strdup(imsg.data);
+			break;
+		case IMSG_SETUP_PEER:
+			setup_peer(imsg.hdr.peerid, imsg.hdr.pid,
+			    imsg_get_fd(&imsg));
+			break;
+		case IMSG_SETUP_DONE:
+			setup = 0;
+			break;
+		default:
+			fatal("bad imsg %d", imsg.hdr.type);
+		}
+		imsg_free(&imsg);
+	}
+
+	if (imsg_compose(ibuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1)
+		fatal("imsg_compose");
+
+	if (imsgbuf_flush(ibuf) == -1)
+		fatal("imsgbuf_flush");
+
+	log_debug("setup_proc: %s done", proc_title(smtpd_process));
+}
+
+int
+imsg_wait(struct imsgbuf *ibuf, struct imsg *imsg, int timeout)
+{
+	struct pollfd pfd[1];
+	ssize_t n;
+
+	pfd[0].fd = ibuf->fd;
+	pfd[0].events = POLLIN;
+
+	while (1) {
+		if ((n = imsg_get(ibuf, imsg)) == -1)
+			return -1;
+		if (n)
+			return 1;
+
+		n = poll(pfd, 1, timeout);
+		if (n == -1)
+			return -1;
+		if (n == 0) {
+			errno = ETIMEDOUT;
+			return -1;
+		}
+
+		if (imsgbuf_read(ibuf) != 1)
+			return -1;
+	}
+}
+
+void
+load_pki_tree(void)
+{
+	struct pki	*pki;
+	struct ca	*sca;
+	const char	*k;
+	void		*iter_dict;
+
+	log_debug("debug: init ssl-tree");
+	iter_dict = NULL;
+	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
+		log_debug("info: loading pki information for %s", k);
+		if (pki->pki_cert_file == NULL)
+			fatalx("load_pki_tree: missing certificate file");
+		if (pki->pki_key_file == NULL)
+			fatalx("load_pki_tree: missing key file");
+
+		if (!ssl_load_certificate(pki, pki->pki_cert_file))
+			fatalx("load_pki_tree: failed to load certificate file");
+	}
+
+	log_debug("debug: init ca-tree");
+	iter_dict = NULL;
+	while (dict_iter(env->sc_ca_dict, &iter_dict, &k, (void **)&sca)) {
+		log_debug("info: loading CA information for %s", k);
+		if (!ssl_load_cafile(sca, sca->ca_cert_file))
+			fatalx("load_pki_tree: failed to load CA file");
+	}
+}
+
+void
+load_pki_keys(void)
+{
+	struct pki	*pki;
+	const char	*k;
+	void		*iter_dict;
+
+	log_debug("debug: init ssl-tree");
+	iter_dict = NULL;
+	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
+		log_debug("info: loading pki keys for %s", k);
+
+		if (!ssl_load_keyfile(pki, pki->pki_key_file, k))
+			fatalx("load_pki_keys: failed to load key file");
+	}
+}
+
+int
+fork_proc_backend(const char *key, const char *conf, const char *procname,
+    int do_stdout)
+{
+	pid_t		pid;
+	int		sp[2];
+	char		path[PATH_MAX];
+	char		name[PATH_MAX];
+	char		*arg;
+
+	if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) {
+		log_warnx("warn: %s-proc: conf too long", key);
+		return (-1);
+	}
+
+	arg = strchr(name, ':');
+	if (arg)
+		*arg++ = '\0';
+
+	if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >=
+	    (ssize_t)sizeof(path)) {
+		log_warn("warn: %s-proc: exec path too long", key);
+		return (-1);
+	}
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
+		log_warn("warn: %s-proc: socketpair", key);
+		return (-1);
+	}
+
+	if ((pid = fork()) == -1) {
+		log_warn("warn: %s-proc: fork", key);
+		close(sp[0]);
+		close(sp[1]);
+		return (-1);
+	}
+
+	if (pid == 0) {
+		/* child process */
+		dup2(sp[0], STDIN_FILENO);
+		if (do_stdout)
+			dup2(sp[0], STDOUT_FILENO);
+		if (closefrom(STDERR_FILENO + 1) == -1)
+			exit(1);
+
+		if (procname == NULL)
+			procname = name;
+
+		execl(path, procname, arg, (char *)NULL);
+		fatal("execl: %s", path);
+	}
+
+	/* parent process */
+	close(sp[0]);
+
+	return (sp[1]);
+}
+
+void
+imsg_dispatch(struct mproc *p, struct imsg *imsg)
+{
+	struct timespec	t0, t1, dt;
+	int		msg;
+
+	if (imsg == NULL) {
+		imsg_callback(p, imsg);
+		return;
+	}
+
+	log_imsg(smtpd_process, p->proc, imsg);
+
+	if (profiling & PROFILE_IMSG)
+		clock_gettime(CLOCK_MONOTONIC, &t0);
+
+	msg = imsg->hdr.type;
+	imsg_callback(p, imsg);
+
+	if (profiling & PROFILE_IMSG) {
+		clock_gettime(CLOCK_MONOTONIC, &t1);
+		timespecsub(&t1, &t0, &dt);
+
+		log_debug("profile-imsg: %s %s %s %d %lld.%09ld",
+		    proc_name(smtpd_process),
+		    proc_name(p->proc),
+		    imsg_to_str(msg),
+		    (int)imsg->hdr.len,
+		    (long long)dt.tv_sec,
+		    dt.tv_nsec);
+
+		if (profiling & PROFILE_TOSTAT) {
+			char	key[STAT_KEY_SIZE];
+			/* can't profstat control process yet */
+			if (smtpd_process == PROC_CONTROL)
+				return;
+
+			if (!bsnprintf(key, sizeof key,
+				"profiling.imsg.%s.%s.%s",
+				proc_name(smtpd_process),
+				proc_name(p->proc),
+				imsg_to_str(msg)))
+				return;
+			stat_set(key, stat_timespec(&dt));
+		}
+	}
+}