[master] a641a46 Move the manager process sources into a subdirectory, away from the gaze of prying VMODs.

Poul-Henning Kamp phk at varnish-cache.org
Thu Oct 13 11:56:56 CEST 2011


commit a641a46cfe0e00e7104db050f459faeaa324a046
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Oct 13 09:42:36 2011 +0000

    Move the manager process sources into a subdirectory, away from
    the gaze of prying VMODs.

diff --git a/bin/varnishd/Makefile.am b/bin/varnishd/Makefile.am
index 499cb6c..f2e9d04 100644
--- a/bin/varnishd/Makefile.am
+++ b/bin/varnishd/Makefile.am
@@ -55,14 +55,14 @@ varnishd_SOURCES = \
 	hash/hash_classic.c \
 	hash/hash_critbit.c \
 	hash/hash_simple_list.c \
-	mgt_child.c \
-	mgt_cli.c \
-	mgt_param.c \
-	mgt_pool.c \
-	mgt_sandbox.c \
-	mgt_sandbox_solaris.c \
-	mgt_shmem.c \
-	mgt_vcc.c \
+	mgt/mgt_child.c \
+	mgt/mgt_cli.c \
+	mgt/mgt_param.c \
+	mgt/mgt_pool.c \
+	mgt/mgt_sandbox.c \
+	mgt/mgt_sandbox_solaris.c \
+	mgt/mgt_shmem.c \
+	mgt/mgt_vcc.c \
 	rfc2616.c \
 	storage/stevedore.c \
 	storage/stevedore_utils.c \
@@ -86,8 +86,8 @@ noinst_HEADERS = \
 	default_vcl.h \
 	hash/hash_slinger.h \
 	heritage.h \
-	mgt.h \
-	mgt_cli.h \
+	mgt/mgt.h \
+	mgt/mgt_cli.h \
 	storage/storage.h \
 	storage/storage_persistent.h \
 	vparam.h
@@ -128,7 +128,7 @@ default_vcl.h:	default.vcl Makefile
 	    -e 's/^/ "/' $(srcdir)/default.vcl >> $@
 
 # Explicitly record dependency
-mgt_vcc.c:	default_vcl.h
+mgt/mgt_vcc.c:	default_vcl.h
 
 varnishd.1: $(top_srcdir)/doc/sphinx/reference/varnishd.rst
 if HAVE_RST2MAN
diff --git a/bin/varnishd/flint.sh b/bin/varnishd/flint.sh
index 357d280..4beb9d5 100755
--- a/bin/varnishd/flint.sh
+++ b/bin/varnishd/flint.sh
@@ -18,6 +18,8 @@ flexelint \
 	*.c \
 	storage/*.c \
 	waiter/*.c \
+	hash/*.c \
+	mgt/*.c \
 	../../lib/libvarnish/*.c \
 	../../lib/libvarnishcompat/execinfo.c \
 	../../lib/libvcl/*.c \
diff --git a/bin/varnishd/mgt.h b/bin/varnishd/mgt.h
deleted file mode 100644
index 1656af8..0000000
--- a/bin/varnishd/mgt.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include <stdint.h>
-
-#include "common.h"
-
-struct cli;
-
-extern struct vev_base	*mgt_evb;
-extern unsigned		d_flag;
-extern int		exit_status;
-
-/* mgt_child.c */
-extern pid_t child_pid;
-void MGT_Run(void);
-void mgt_stop_child(void);
-void mgt_got_fd(int fd);
-void MGT_Child_Cli_Fail(void);
-
-/* mgt_cli.c */
-
-typedef void mgt_cli_close_f(void *priv);
-void mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident, mgt_cli_close_f *close_func, void *priv);
-int mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...);
-void mgt_cli_start_child(int fdi, int fdo);
-void mgt_cli_stop_child(void);
-void mgt_cli_telnet(const char *T_arg);
-void mgt_cli_master(const char *M_arg);
-void mgt_cli_secret(const char *S_arg);
-void mgt_cli_close_all(void);
-
-/* mgt_param.c */
-void MCF_ParamSync(void);
-void MCF_ParamInit(struct cli *);
-void MCF_ParamSet(struct cli *, const char *param, const char *val);
-void MCF_DumpRst(void);
-
-/* mgt_sandbox.c */
-void mgt_sandbox(void);
-
-/* mgt_sandbox_solaris.c */
-#ifdef HAVE_SETPPRIV
-void mgt_sandbox_solaris_init(void);
-void mgt_sandbox_solaris_fini(void);
-void mgt_sandbox_solaris_privsep(void);
-#endif
-
-/* mgt_shmem.c */
-void mgt_SHM_Init(const char *arg);
-void mgt_SHM_Pid(void);
-
-/* mgt_vcc.c */
-void mgt_vcc_init(void);
-int mgt_vcc_default(const char *bflag, const char *f_arg, char *vcl, int Cflag);
-int mgt_push_vcls_and_start(unsigned *status, char **p);
-int mgt_has_vcl(void);
-extern char *mgt_cc_cmd;
-extern const char *mgt_vcl_dir;
-extern const char *mgt_vmod_dir;
-extern unsigned mgt_vcc_err_unref;
-
-
-#define REPORT0(pri, fmt)				\
-	do {						\
-		fprintf(stderr, fmt "\n");		\
-		syslog(pri, fmt);			\
-	} while (0)
-
-#define REPORT(pri, fmt, ...)				\
-	do {						\
-		fprintf(stderr, fmt "\n", __VA_ARGS__);	\
-		syslog(pri, fmt, __VA_ARGS__);		\
-	} while (0)
-
-#define VSM_Alloc(a, b, c, d)	VSM__Alloc(a,b,c,d)
-#define VSM_Free(a)		VSM__Free(a)
-#define VSM_Clean()		VSM__Clean()
-
-
-#if defined(PTHREAD_CANCELED) || defined(PTHREAD_MUTEX_DEFAULT)
-#error "Keep pthreads out of in manager process"
-#endif
diff --git a/bin/varnishd/mgt/mgt.h b/bin/varnishd/mgt/mgt.h
new file mode 100644
index 0000000..1656af8
--- /dev/null
+++ b/bin/varnishd/mgt/mgt.h
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+
+#include "common.h"
+
+struct cli;
+
+extern struct vev_base	*mgt_evb;
+extern unsigned		d_flag;
+extern int		exit_status;
+
+/* mgt_child.c */
+extern pid_t child_pid;
+void MGT_Run(void);
+void mgt_stop_child(void);
+void mgt_got_fd(int fd);
+void MGT_Child_Cli_Fail(void);
+
+/* mgt_cli.c */
+
+typedef void mgt_cli_close_f(void *priv);
+void mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident, mgt_cli_close_f *close_func, void *priv);
+int mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...);
+void mgt_cli_start_child(int fdi, int fdo);
+void mgt_cli_stop_child(void);
+void mgt_cli_telnet(const char *T_arg);
+void mgt_cli_master(const char *M_arg);
+void mgt_cli_secret(const char *S_arg);
+void mgt_cli_close_all(void);
+
+/* mgt_param.c */
+void MCF_ParamSync(void);
+void MCF_ParamInit(struct cli *);
+void MCF_ParamSet(struct cli *, const char *param, const char *val);
+void MCF_DumpRst(void);
+
+/* mgt_sandbox.c */
+void mgt_sandbox(void);
+
+/* mgt_sandbox_solaris.c */
+#ifdef HAVE_SETPPRIV
+void mgt_sandbox_solaris_init(void);
+void mgt_sandbox_solaris_fini(void);
+void mgt_sandbox_solaris_privsep(void);
+#endif
+
+/* mgt_shmem.c */
+void mgt_SHM_Init(const char *arg);
+void mgt_SHM_Pid(void);
+
+/* mgt_vcc.c */
+void mgt_vcc_init(void);
+int mgt_vcc_default(const char *bflag, const char *f_arg, char *vcl, int Cflag);
+int mgt_push_vcls_and_start(unsigned *status, char **p);
+int mgt_has_vcl(void);
+extern char *mgt_cc_cmd;
+extern const char *mgt_vcl_dir;
+extern const char *mgt_vmod_dir;
+extern unsigned mgt_vcc_err_unref;
+
+
+#define REPORT0(pri, fmt)				\
+	do {						\
+		fprintf(stderr, fmt "\n");		\
+		syslog(pri, fmt);			\
+	} while (0)
+
+#define REPORT(pri, fmt, ...)				\
+	do {						\
+		fprintf(stderr, fmt "\n", __VA_ARGS__);	\
+		syslog(pri, fmt, __VA_ARGS__);		\
+	} while (0)
+
+#define VSM_Alloc(a, b, c, d)	VSM__Alloc(a,b,c,d)
+#define VSM_Free(a)		VSM__Free(a)
+#define VSM_Clean()		VSM__Clean()
+
+
+#if defined(PTHREAD_CANCELED) || defined(PTHREAD_MUTEX_DEFAULT)
+#error "Keep pthreads out of in manager process"
+#endif
diff --git a/bin/varnishd/mgt/mgt_child.c b/bin/varnishd/mgt/mgt_child.c
new file mode 100644
index 0000000..ff8a776
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_child.c
@@ -0,0 +1,673 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The mechanics of handling the child process
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "heritage.h"
+#include "vapi/vsm_int.h"
+#include "vbm.h"
+#include "vcli.h"
+#include "vcli_priv.h"
+#include "vev.h"
+#include "vlu.h"
+#include "vss.h"
+#include "vtcp.h"
+#include "vtim.h"
+
+#include "mgt_cli.h"
+
+pid_t		child_pid = -1;
+
+
+static struct vbitmap	*fd_map;
+
+static int		child_cli_in = -1;
+static int		child_VCLI_Out = -1;
+static int		child_output = -1;
+
+static enum {
+	CH_STOPPED = 0,
+	CH_STARTING = 1,
+	CH_RUNNING = 2,
+	CH_STOPPING = 3,
+	CH_DIED = 4
+}			child_state = CH_STOPPED;
+
+static const char * const ch_state[] = {
+	[CH_STOPPED] =	"stopped",
+	[CH_STARTING] =	"starting",
+	[CH_RUNNING] =	"running",
+	[CH_STOPPING] =	"stopping",
+	[CH_DIED] =	"died, (restarting)",
+};
+
+static struct vev	*ev_poker;
+static struct vev	*ev_listen;
+static struct vlu	*vlu;
+
+static struct vsb *child_panic = NULL;
+
+/*--------------------------------------------------------------------
+ * Track the highest file descriptor the parent knows is being used.
+ *
+ * This allows the child process to clean/close only a small fraction
+ * of the possible file descriptors after exec(2).
+ *
+ * This is likely to a bit on the low side, as libc and other libraries
+ * has a tendency to cache file descriptors (syslog, resolver, etc.)
+ * so we add a margin of 100 fds.
+ */
+
+static int		mgt_max_fd;
+
+#define CLOSE_FD_UP_TO	(mgt_max_fd + 100)
+
+void
+mgt_got_fd(int fd)
+{
+	/*
+	 * Assert > 0, to catch bogus opens, we know where stdin goes
+	 * in the master process.
+	 */
+	assert(fd > 0);
+	if (fd > mgt_max_fd)
+		mgt_max_fd = fd;
+}
+
+/*--------------------------------------------------------------------
+ * A handy little function
+ */
+
+static inline void
+closex(int *fd)
+{
+
+	assert(*fd >= 0);
+	AZ(close(*fd));
+	*fd = -1;
+}
+
+/*--------------------------------------------------------------------
+ * Keep track of which filedescriptors the child should inherit and
+ * which should be closed after fork()
+ */
+
+void
+mgt_child_inherit(int fd, const char *what)
+{
+
+	assert(fd >= 0);
+	if (fd_map == NULL)
+		fd_map = vbit_init(128);
+	AN(fd_map);
+	if (what != NULL)
+		vbit_set(fd_map, fd);
+	else
+		vbit_clr(fd_map, fd);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+child_line(void *priv, const char *p)
+{
+	(void)priv;
+
+	REPORT(LOG_NOTICE, "Child (%jd) said %s", (intmax_t)child_pid, p);
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+child_listener(const struct vev *e, int what)
+{
+
+	(void)e;
+	if ((what & ~EV_RD)) {
+		ev_listen = NULL;
+		return (1);
+	}
+	if (VLU_Fd(child_output, vlu)) {
+		ev_listen = NULL;
+		return (1);
+	}
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+child_poker(const struct vev *e, int what)
+{
+
+	(void)e;
+	(void)what;
+	if (child_state != CH_RUNNING)
+		return (1);
+	if (child_pid < 0)
+		return (0);
+	if (!mgt_cli_askchild(NULL, NULL, "ping\n"))
+		return (0);
+	return (0);
+}
+
+/*--------------------------------------------------------------------
+ * If CLI communications with the child process fails, there is nothing
+ * for us to do but to drag it behind the barn and get it over with.
+ *
+ * The typical case is where the child process fails to return a reply
+ * before the cli_timeout expires.  This invalidates the CLI pipes for
+ * all future use, as we don't know if the child was just slow and the
+ * result gets piped later on, or if the child is catatonic.
+ */
+
+void
+MGT_Child_Cli_Fail(void)
+{
+
+	if (child_state != CH_RUNNING)
+		return;
+	if (child_pid < 0)
+		return;
+	REPORT(LOG_ERR, "Child (%jd) not responding to CLI, killing it.",
+	    (intmax_t)child_pid);
+	if (params->diag_bitmap & 0x1000)
+		(void)kill(child_pid, SIGKILL);
+	else
+		(void)kill(child_pid, SIGQUIT);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+open_sockets(void)
+{
+	struct listen_sock *ls, *ls2;
+	int good = 0;
+
+	VTAILQ_FOREACH_SAFE(ls, &heritage.socks, list, ls2) {
+		if (ls->sock >= 0) {
+			good++;
+			continue;
+		}
+		ls->sock = VSS_bind(ls->addr);
+		if (ls->sock < 0)
+			continue;
+
+		mgt_child_inherit(ls->sock, "sock");
+
+		/*
+		 * Set nonblocking mode to avoid a race where a client
+		 * closes before we call accept(2) and nobody else are in
+		 * the listen queue to release us.
+		 */
+		(void)VTCP_filter_http(ls->sock);
+		good++;
+	}
+	if (!good)
+		return (1);
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+close_sockets(void)
+{
+	struct listen_sock *ls;
+
+	VTAILQ_FOREACH(ls, &heritage.socks, list) {
+		if (ls->sock < 0)
+			continue;
+		mgt_child_inherit(ls->sock, NULL);
+		closex(&ls->sock);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+start_child(struct cli *cli)
+{
+	pid_t pid;
+	unsigned u;
+	char *p;
+	struct vev *e;
+	int i, cp[2];
+
+	if (child_state != CH_STOPPED && child_state != CH_DIED)
+		return;
+
+	if (open_sockets() != 0) {
+		child_state = CH_STOPPED;
+		if (cli != NULL) {
+			VCLI_SetResult(cli, CLIS_CANT);
+			VCLI_Out(cli, "Could not open sockets");
+			return;
+		}
+		REPORT0(LOG_ERR,
+		    "Child start failed: could not open sockets");
+		return;
+	}
+
+	child_state = CH_STARTING;
+
+	/* Open pipe for mgr->child CLI */
+	AZ(pipe(cp));
+	heritage.cli_in = cp[0];
+	mgt_child_inherit(heritage.cli_in, "cli_in");
+	child_VCLI_Out = cp[1];
+
+	/* Open pipe for child->mgr CLI */
+	AZ(pipe(cp));
+	heritage.VCLI_Out = cp[1];
+	mgt_child_inherit(heritage.VCLI_Out, "VCLI_Out");
+	child_cli_in = cp[0];
+
+	/*
+	 * Open pipe for child stdout/err
+	 * NB: not inherited, because we dup2() it to stdout/stderr in child
+	 */
+	AZ(pipe(cp));
+	heritage.std_fd = cp[1];
+	child_output = cp[0];
+
+	MCF_ParamSync();
+	if ((pid = fork()) < 0) {
+		perror("Could not fork child");
+		exit(1);
+	}
+	if (pid == 0) {
+
+		/* Redirect stdin/out/err */
+		AZ(close(STDIN_FILENO));
+		assert(open("/dev/null", O_RDONLY) == STDIN_FILENO);
+		assert(dup2(heritage.std_fd, STDOUT_FILENO) == STDOUT_FILENO);
+		assert(dup2(heritage.std_fd, STDERR_FILENO) == STDERR_FILENO);
+
+		/* Close anything we shouldn't know about */
+		closelog();
+		for (i = STDERR_FILENO + 1; i < CLOSE_FD_UP_TO; i++) {
+			if (vbit_test(fd_map, i))
+				continue;
+			(void)(close(i) == 0);
+		}
+#ifdef HAVE_SETPROCTITLE
+		setproctitle("Varnish-Chld %s", heritage.name);
+#endif
+
+		(void)signal(SIGINT, SIG_DFL);
+		(void)signal(SIGTERM, SIG_DFL);
+
+		mgt_sandbox();
+
+		child_main();
+
+		exit(1);
+	}
+	REPORT(LOG_NOTICE, "child (%jd) Started", (intmax_t)pid);
+
+	/* Close stuff the child got */
+	closex(&heritage.std_fd);
+
+	mgt_child_inherit(heritage.cli_in, NULL);
+	closex(&heritage.cli_in);
+
+	mgt_child_inherit(heritage.VCLI_Out, NULL);
+	closex(&heritage.VCLI_Out);
+
+	close_sockets();
+
+	vlu = VLU_New(NULL, child_line, 0);
+	AN(vlu);
+
+	AZ(ev_listen);
+	e = vev_new();
+	XXXAN(e);
+	e->fd = child_output;
+	e->fd_flags = EV_RD;
+	e->name = "Child listener";
+	e->callback = child_listener;
+	AZ(vev_add(mgt_evb, e));
+	ev_listen = e;
+	AZ(ev_poker);
+	if (params->ping_interval > 0) {
+		e = vev_new();
+		XXXAN(e);
+		e->timeout = params->ping_interval;
+		e->callback = child_poker;
+		e->name = "child poker";
+		AZ(vev_add(mgt_evb, e));
+		ev_poker = e;
+	}
+
+	mgt_cli_start_child(child_cli_in, child_VCLI_Out);
+	child_pid = pid;
+	if (mgt_push_vcls_and_start(&u, &p)) {
+		REPORT(LOG_ERR, "Pushing vcls failed:\n%s", p);
+		free(p);
+		child_state = CH_RUNNING;
+		mgt_stop_child();
+	} else
+		child_state = CH_RUNNING;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_stop_child(void)
+{
+
+	if (child_state != CH_RUNNING)
+		return;
+
+	child_state = CH_STOPPING;
+
+	REPORT0(LOG_DEBUG, "Stopping Child");
+	if (ev_poker != NULL) {
+		vev_del(mgt_evb, ev_poker);
+		free(ev_poker);
+	}
+	ev_poker = NULL;
+
+	mgt_cli_stop_child();
+
+	/* We tell the child to die gracefully by closing the CLI */
+	closex(&child_VCLI_Out);
+	closex(&child_cli_in);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+mgt_report_panic(pid_t r)
+{
+
+	if (VSM_head->panicstr[0] == '\0')
+		return;
+	REPORT(LOG_ERR, "Child (%jd) Panic message: %s",
+	    (intmax_t)r, VSM_head->panicstr);
+}
+
+static void
+mgt_save_panic(void)
+{
+	char time_str[30];
+	if (VSM_head->panicstr[0] == '\0')
+		return;
+
+	if (child_panic)
+		VSB_delete(child_panic);
+	child_panic = VSB_new_auto();
+	XXXAN(child_panic);
+	VTIM_format(VTIM_real(), time_str);
+	VSB_printf(child_panic, "Last panic at: %s\n", time_str);
+	VSB_cat(child_panic, VSM_head->panicstr);
+	AZ(VSB_finish(child_panic));
+}
+
+static void
+mgt_clear_panic(void)
+{
+	VSB_delete(child_panic);
+	child_panic = NULL;
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+mgt_sigchld(const struct vev *e, int what)
+{
+	int status;
+	struct vsb *vsb;
+	pid_t r;
+
+	(void)e;
+	(void)what;
+
+	if (ev_poker != NULL) {
+		vev_del(mgt_evb, ev_poker);
+		free(ev_poker);
+	}
+	ev_poker = NULL;
+
+	r = waitpid(child_pid, &status, WNOHANG);
+	if (r == 0 || (r == -1 && errno == ECHILD))
+		return (0);
+	assert(r == child_pid);
+	vsb = VSB_new_auto();
+	XXXAN(vsb);
+	VSB_printf(vsb, "Child (%d) %s", r, status ? "died" : "ended");
+	if (WIFEXITED(status) && WEXITSTATUS(status)) {
+		VSB_printf(vsb, " status=%d", WEXITSTATUS(status));
+		exit_status |= 0x20;
+	}
+	if (WIFSIGNALED(status)) {
+		VSB_printf(vsb, " signal=%d", WTERMSIG(status));
+		exit_status |= 0x40;
+	}
+#ifdef WCOREDUMP
+	if (WCOREDUMP(status)) {
+		VSB_printf(vsb, " (core dumped)");
+		exit_status |= 0x80;
+	}
+#endif
+	AZ(VSB_finish(vsb));
+	REPORT(LOG_INFO, "%s", VSB_data(vsb));
+	VSB_delete(vsb);
+
+	mgt_report_panic(r);
+	mgt_save_panic();
+
+	child_pid = -1;
+
+	if (child_state == CH_RUNNING) {
+		child_state = CH_DIED;
+		mgt_cli_stop_child();
+		closex(&child_VCLI_Out);
+		closex(&child_cli_in);
+	}
+
+	if (ev_listen != NULL) {
+		vev_del(mgt_evb, ev_listen);
+		free(ev_listen);
+		ev_listen = NULL;
+	}
+	/* Pick up any stuff lingering on stdout/stderr */
+	(void)child_listener(NULL, EV_RD);
+	closex(&child_output);
+
+	REPORT0(LOG_DEBUG, "Child cleanup complete");
+
+	if (child_state == CH_DIED && params->auto_restart)
+		start_child(NULL);
+	else if (child_state == CH_DIED) {
+		child_state = CH_STOPPED;
+	} else if (child_state == CH_STOPPING)
+		child_state = CH_STOPPED;
+
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+mgt_sigint(const struct vev *e, int what)
+{
+
+	(void)e;
+	(void)what;
+	REPORT0(LOG_ERR, "Manager got SIGINT");
+	(void)fflush(stdout);
+	if (child_pid >= 0)
+		mgt_stop_child();
+	exit (2);
+}
+
+/*--------------------------------------------------------------------
+ * This thread is the master thread in the management process.
+ * The relatively simple task is to start and stop the child process
+ * and to reincarnate it in case of trouble.
+ */
+
+void
+MGT_Run(void)
+{
+	struct sigaction sac;
+	struct vev *e;
+	int i;
+
+	e = vev_new();
+	XXXAN(e);
+	e->sig = SIGTERM;
+	e->callback = mgt_sigint;
+	e->name = "mgt_sigterm";
+	AZ(vev_add(mgt_evb, e));
+
+	e = vev_new();
+	XXXAN(e);
+	e->sig = SIGINT;
+	e->callback = mgt_sigint;
+	e->name = "mgt_sigint";
+	AZ(vev_add(mgt_evb, e));
+
+	e = vev_new();
+	XXXAN(e);
+	e->sig = SIGCHLD;
+	e->sig_flags = SA_NOCLDSTOP;
+	e->callback = mgt_sigchld;
+	e->name = "mgt_sigchild";
+	AZ(vev_add(mgt_evb, e));
+
+#ifdef HAVE_SETPROCTITLE
+	setproctitle("Varnish-Mgr %s", heritage.name);
+#endif
+
+	memset(&sac, 0, sizeof sac);
+	sac.sa_handler = SIG_IGN;
+	sac.sa_flags = SA_RESTART;
+
+	AZ(sigaction(SIGPIPE, &sac, NULL));
+	AZ(sigaction(SIGHUP, &sac, NULL));
+
+	if (!d_flag && !mgt_has_vcl())
+		REPORT0(LOG_ERR, "No VCL loaded yet");
+	else if (!d_flag) {
+		start_child(NULL);
+		if (child_state == CH_STOPPED) {
+			exit_status = 2;
+			return;
+		}
+	}
+
+	i = vev_schedule(mgt_evb);
+	if (i != 0)
+		REPORT(LOG_ERR, "vev_schedule() = %d", i);
+
+	REPORT0(LOG_ERR, "manager dies");
+}
+
+/*--------------------------------------------------------------------*/
+
+void __match_proto__(cli_func_t)
+mcf_server_startstop(struct cli *cli, const char * const *av, void *priv)
+{
+
+	(void)av;
+	if (priv != NULL && child_state == CH_RUNNING)
+		mgt_stop_child();
+	else if (priv == NULL && child_state == CH_STOPPED) {
+		if (mgt_has_vcl()) {
+			start_child(cli);
+		} else {
+			VCLI_SetResult(cli, CLIS_CANT);
+			VCLI_Out(cli, "No VCL available");
+		}
+	} else {
+		VCLI_SetResult(cli, CLIS_CANT);
+		VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mcf_server_status(struct cli *cli, const char * const *av, void *priv)
+{
+	(void)av;
+	(void)priv;
+	VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
+}
+
+void
+mcf_panic_show(struct cli *cli, const char * const *av, void *priv)
+{
+	(void)av;
+	(void)priv;
+
+	if (!child_panic) {
+	  VCLI_SetResult(cli, CLIS_CANT);
+	  VCLI_Out(cli, "Child has not panicked or panic has been cleared");
+	  return;
+	}
+
+	VCLI_Out(cli, "%s\n", VSB_data(child_panic));
+}
+
+void
+mcf_panic_clear(struct cli *cli, const char * const *av, void *priv)
+{
+	(void)av;
+	(void)priv;
+
+	if (!child_panic) {
+	  VCLI_SetResult(cli, CLIS_CANT);
+	  VCLI_Out(cli, "No panic to clear");
+	  return;
+	}
+
+	mgt_clear_panic();
+}
diff --git a/bin/varnishd/mgt/mgt_cli.c b/bin/varnishd/mgt/mgt_cli.c
new file mode 100644
index 0000000..c8f22c3
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_cli.c
@@ -0,0 +1,663 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The management process' CLI handling
+ */
+
+#include "config.h"
+
+#include <sys/socket.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "heritage.h"
+#include "vcli.h"
+#include "vcli_common.h"
+#include "vcli_priv.h"
+#include "vcli_serve.h"
+#include "vev.h"
+#include "vlu.h"
+#include "vss.h"
+#include "vtcp.h"
+
+#include "mgt_cli.h"
+
+#ifndef HAVE_SRANDOMDEV
+#include "compat/srandomdev.h"
+#endif
+
+static int		cli_i = -1, cli_o = -1;
+static struct VCLS	*cls;
+static const char	*secret_file;
+
+#define	MCF_NOAUTH	0	/* NB: zero disables here-documents */
+#define MCF_AUTH	16
+
+/*--------------------------------------------------------------------*/
+
+static void
+mcf_banner(struct cli *cli, const char *const *av, void *priv)
+{
+
+	(void)av;
+	(void)priv;
+	VCLI_Out(cli, "-----------------------------\n");
+	VCLI_Out(cli, "Varnish Cache CLI 1.0\n");
+	VCLI_Out(cli, "-----------------------------\n");
+	VCLI_Out(cli, "%s\n", VSB_data(vident) + 1);
+	VCLI_Out(cli, "\n");
+	VCLI_Out(cli, "Type 'help' for command list.\n");
+	VCLI_Out(cli, "Type 'quit' to close CLI session.\n");
+	if (child_pid < 0)
+		VCLI_Out(cli, "Type 'start' to launch worker process.\n");
+	VCLI_SetResult(cli, CLIS_OK);
+}
+
+/*--------------------------------------------------------------------*/
+
+/* XXX: what order should this list be in ? */
+static struct cli_proto cli_proto[] = {
+	{ CLI_BANNER,		"", mcf_banner, NULL },
+	{ CLI_SERVER_STATUS,	"", mcf_server_status, NULL },
+	{ CLI_SERVER_START,	"", mcf_server_startstop, NULL },
+	{ CLI_SERVER_STOP,	"", mcf_server_startstop, cli_proto },
+	{ CLI_VCL_LOAD,		"", mcf_config_load, NULL },
+	{ CLI_VCL_INLINE,	"", mcf_config_inline, NULL },
+	{ CLI_VCL_USE,		"", mcf_config_use, NULL },
+	{ CLI_VCL_DISCARD,	"", mcf_config_discard, NULL },
+	{ CLI_VCL_LIST,		"", mcf_config_list, NULL },
+	{ CLI_VCL_SHOW,		"", mcf_config_show, NULL },
+	{ CLI_PARAM_SHOW,	"", mcf_param_show, NULL },
+	{ CLI_PARAM_SET,	"", mcf_param_set, NULL },
+	{ CLI_PANIC_SHOW,	"", mcf_panic_show, NULL },
+	{ CLI_PANIC_CLEAR,	"", mcf_panic_clear, NULL },
+	{ NULL }
+};
+
+/*--------------------------------------------------------------------*/
+
+static void
+mcf_panic(struct cli *cli, const char * const *av, void *priv)
+{
+
+	(void)cli;
+	(void)av;
+	(void)priv;
+	assert(!strcmp("", "You asked for it"));
+}
+
+static struct cli_proto cli_debug[] = {
+	{ "debug.panic.master", "debug.panic.master",
+		"\tPanic the master process.\n",
+		0, 0, "d", mcf_panic, NULL},
+	{ NULL }
+};
+
+/*--------------------------------------------------------------------*/
+
+static void
+mcf_askchild(struct cli *cli, const char * const *av, void *priv)
+{
+	int i;
+	char *q;
+	unsigned u;
+	struct vsb *vsb;
+
+	(void)priv;
+	/*
+	 * Command not recognized in master, try cacher if it is
+	 * running.
+	 */
+	if (cli_o <= 0) {
+		if (!strcmp(av[1], "help")) {
+			VCLI_Out(cli, "No help from child, (not running).\n");
+			return;
+		}
+		VCLI_SetResult(cli, CLIS_UNKNOWN);
+		VCLI_Out(cli,
+		    "Unknown request in manager process "
+		    "(child not running).\n"
+		    "Type 'help' for more info.");
+		return;
+	}
+	vsb = VSB_new_auto();
+	for (i = 1; av[i] != NULL; i++) {
+		VSB_quote(vsb, av[i], strlen(av[i]), 0);
+		VSB_putc(vsb, ' ');
+	}
+	VSB_putc(vsb, '\n');
+	AZ(VSB_finish(vsb));
+	i = write(cli_o, VSB_data(vsb), VSB_len(vsb));
+	if (i != VSB_len(vsb)) {
+		VSB_delete(vsb);
+		VCLI_SetResult(cli, CLIS_COMMS);
+		VCLI_Out(cli, "CLI communication error");
+		MGT_Child_Cli_Fail();
+		return;
+	}
+	VSB_delete(vsb);
+	(void)VCLI_ReadResult(cli_i, &u, &q, params->cli_timeout);
+	VCLI_SetResult(cli, u);
+	VCLI_Out(cli, "%s", q);
+	free(q);
+}
+
+static struct cli_proto cli_askchild[] = {
+	{ "*", "<wild-card-entry>", "\t<fall through to cacher>\n",
+		0, 9999, "h*", mcf_askchild, NULL},
+	{ NULL }
+};
+
+/*--------------------------------------------------------------------
+ * Ask the child something over CLI, return zero only if everything is
+ * happy happy.
+ */
+
+int
+mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...) {
+	int i, j;
+	va_list ap;
+	unsigned u;
+	char buf[params->cli_buffer], *p;
+
+	if (resp != NULL)
+		*resp = NULL;
+	if (status != NULL)
+		*status = 0;
+	if (cli_i < 0|| cli_o < 0) {
+		if (status != NULL)
+			*status = CLIS_CANT;
+		return (CLIS_CANT);
+	}
+	va_start(ap, fmt);
+	vbprintf(buf, fmt, ap);
+	va_end(ap);
+	p = strchr(buf, '\0');
+	assert(p != NULL && p > buf && p[-1] == '\n');
+	i = p - buf;
+	j = write(cli_o, buf, i);
+	if (j != i) {
+		if (status != NULL)
+			*status = CLIS_COMMS;
+		if (resp != NULL)
+			*resp = strdup("CLI communication error");
+		MGT_Child_Cli_Fail();
+		return (CLIS_COMMS);
+	}
+
+	(void)VCLI_ReadResult(cli_i, &u, resp, params->cli_timeout);
+	if (status != NULL)
+		*status = u;
+	if (u == CLIS_COMMS)
+		MGT_Child_Cli_Fail();
+	return (u == CLIS_OK ? 0 : u);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_start_child(int fdi, int fdo)
+{
+
+	cli_i = fdi;
+	cli_o = fdo;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_stop_child(void)
+{
+
+	cli_i = -1;
+	cli_o = -1;
+	/* XXX: kick any users */
+}
+
+/*--------------------------------------------------------------------
+ * Generate a random challenge
+ */
+
+static void
+mgt_cli_challenge(struct cli *cli)
+{
+	int i;
+
+	for (i = 0; i + 2L < sizeof cli->challenge; i++)
+		cli->challenge[i] = (random() % 26) + 'a';
+	cli->challenge[i++] = '\n';
+	cli->challenge[i] = '\0';
+	VCLI_Out(cli, "%s", cli->challenge);
+	VCLI_Out(cli, "\nAuthentication required.\n");
+	VCLI_SetResult(cli, CLIS_AUTH);
+}
+
+/*--------------------------------------------------------------------
+ * Validate the authentication
+ */
+
+static void
+mcf_auth(struct cli *cli, const char *const *av, void *priv)
+{
+	int fd;
+	char buf[CLI_AUTH_RESPONSE_LEN + 1];
+
+	AN(av[2]);
+	(void)priv;
+	if (secret_file == NULL) {
+		VCLI_Out(cli, "Secret file not configured\n");
+		VCLI_SetResult(cli, CLIS_CANT);
+		return;
+	}
+	fd = open(secret_file, O_RDONLY);
+	if (fd < 0) {
+		VCLI_Out(cli, "Cannot open secret file (%s)\n",
+		    strerror(errno));
+		VCLI_SetResult(cli, CLIS_CANT);
+		return;
+	}
+	mgt_got_fd(fd);
+	VCLI_AuthResponse(fd, cli->challenge, buf);
+	AZ(close(fd));
+	if (strcasecmp(buf, av[2])) {
+		mgt_cli_challenge(cli);
+		return;
+	}
+	cli->auth = MCF_AUTH;
+	memset(cli->challenge, 0, sizeof cli->challenge);
+	VCLI_SetResult(cli, CLIS_OK);
+	mcf_banner(cli, av, priv);
+}
+
+static struct cli_proto cli_auth[] = {
+	{ CLI_HELP,		"", VCLS_func_help, NULL },
+	{ CLI_PING,		"", VCLS_func_ping },
+	{ CLI_AUTH,		"", mcf_auth, NULL },
+	{ CLI_QUIT,		"", VCLS_func_close, NULL},
+	{ NULL }
+};
+
+/*--------------------------------------------------------------------*/
+static void
+mgt_cli_cb_before(const struct cli *cli)
+{
+
+	if (params->syslog_cli_traffic)
+		syslog(LOG_NOTICE, "CLI %s Rd %s", cli->ident, cli->cmd);
+}
+
+static void
+mgt_cli_cb_after(const struct cli *cli)
+{
+
+	if (params->syslog_cli_traffic)
+		syslog(LOG_NOTICE, "CLI %s Wr %03u %s",
+		    cli->ident, cli->result, VSB_data(cli->sb));
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+mgt_cli_init_cls(void)
+{
+
+	cls = VCLS_New(mgt_cli_cb_before, mgt_cli_cb_after, params->cli_buffer);
+	AN(cls);
+	AZ(VCLS_AddFunc(cls, MCF_NOAUTH, cli_auth));
+	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_proto));
+	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_debug));
+	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_stv));
+	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_askchild));
+}
+
+/*--------------------------------------------------------------------
+ * Get rid of all CLI sessions
+ */
+
+void
+mgt_cli_close_all(void)
+{
+
+	VCLS_Destroy(&cls);
+}
+
+/*--------------------------------------------------------------------
+ * Callback whenever something happens to the input fd of the session.
+ */
+
+static int
+mgt_cli_callback2(const struct vev *e, int what)
+{
+	int i;
+
+	(void)e;
+	(void)what;
+	i = VCLS_PollFd(cls, e->fd, 0);
+	return (i);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident, mgt_cli_close_f *closefunc, void *priv)
+{
+	struct cli *cli;
+	struct vev *ev;
+
+	(void)ident;
+	(void)verbose;
+	if (cls == NULL)
+		mgt_cli_init_cls();
+
+	cli = VCLS_AddFd(cls, fdi, fdo, closefunc, priv);
+
+	cli->ident = strdup(ident);
+
+	/* Deal with TELNET options */
+	if (fdi != 0)
+		VLU_SetTelnet(cli->vlu, fdo);
+
+	if (fdi != 0 && secret_file != NULL) {
+		cli->auth = MCF_NOAUTH;
+		mgt_cli_challenge(cli);
+	} else {
+		cli->auth = MCF_AUTH;
+		mcf_banner(cli, NULL, NULL);
+	}
+	AZ(VSB_finish(cli->sb));
+	(void)VCLI_WriteResult(fdo, cli->result, VSB_data(cli->sb));
+
+
+	ev = vev_new();
+	AN(ev);
+	ev->name = cli->ident;
+	ev->fd = fdi;
+	ev->fd_flags = EV_RD;
+	ev->callback = mgt_cli_callback2;
+	ev->priv = cli;
+	AZ(vev_add(mgt_evb, ev));
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct vsb *
+sock_id(const char *pfx, int fd)
+{
+	struct vsb *vsb;
+
+	char abuf1[VTCP_ADDRBUFSIZE], abuf2[VTCP_ADDRBUFSIZE];
+	char pbuf1[VTCP_PORTBUFSIZE], pbuf2[VTCP_PORTBUFSIZE];
+
+	vsb = VSB_new_auto();
+	AN(vsb);
+	VTCP_myname(fd, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1);
+	VTCP_hisname(fd, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2);
+	VSB_printf(vsb, "%s %s %s %s %s", pfx, abuf2, pbuf2, abuf1, pbuf1);
+	AZ(VSB_finish(vsb));
+	return (vsb);
+}
+
+/*--------------------------------------------------------------------*/
+
+struct telnet {
+	unsigned		magic;
+#define TELNET_MAGIC		0x53ec3ac0
+	int			fd;
+	struct vev		*ev;
+};
+
+static void
+telnet_close(void *priv)
+{
+	struct telnet *tn;
+
+	CAST_OBJ_NOTNULL(tn, priv, TELNET_MAGIC);
+	(void)close(tn->fd);
+	FREE_OBJ(tn);
+}
+
+static struct telnet *
+telnet_new(int fd)
+{
+	struct telnet *tn;
+
+	ALLOC_OBJ(tn, TELNET_MAGIC);
+	AN(tn);
+	tn->fd = fd;
+	return (tn);
+}
+
+static int
+telnet_accept(const struct vev *ev, int what)
+{
+	struct vsb *vsb;
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	struct telnet *tn;
+	int i;
+
+	(void)what;
+	addrlen = sizeof addr;
+	i = accept(ev->fd, (void *)&addr, &addrlen);
+	if (i < 0 && errno == EBADF)
+		return (1);
+	if (i < 0)
+		return (0);
+
+	mgt_got_fd(i);
+	tn = telnet_new(i);
+	vsb = sock_id("telnet", i);
+	mgt_cli_setup(i, i, 0, VSB_data(vsb), telnet_close, tn);
+	VSB_delete(vsb);
+	return (0);
+}
+
+void
+mgt_cli_secret(const char *S_arg)
+{
+	int i, fd;
+	char buf[BUFSIZ];
+	char *p;
+
+	/* Save in shmem */
+	i = strlen(S_arg);
+	p = VSM_Alloc(i + 1, "Arg", "-S", "");
+	AN(p);
+	strcpy(p, S_arg);
+
+	srandomdev();
+	fd = open(S_arg, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can not open secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	mgt_got_fd(fd);
+	i = read(fd, buf, sizeof buf);
+	if (i == 0) {
+		fprintf(stderr, "Empty secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	if (i < 0) {
+		fprintf(stderr, "Can not read secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	AZ(close(fd));
+	secret_file = S_arg;
+}
+
+void
+mgt_cli_telnet(const char *T_arg)
+{
+	struct vss_addr **ta;
+	int i, n, sock, good;
+	struct telnet *tn;
+	char *p;
+	struct vsb *vsb;
+	char abuf[VTCP_ADDRBUFSIZE];
+	char pbuf[VTCP_PORTBUFSIZE];
+
+	n = VSS_resolve(T_arg, NULL, &ta);
+	if (n == 0) {
+		REPORT(LOG_ERR, "-T %s Could not be resolved\n", T_arg);
+		exit(2);
+	}
+	good = 0;
+	vsb = VSB_new_auto();
+	XXXAN(vsb);
+	for (i = 0; i < n; ++i) {
+		sock = VSS_listen(ta[i], 10);
+		if (sock < 0)
+			continue;
+		VTCP_myname(sock, abuf, sizeof abuf, pbuf, sizeof pbuf);
+		VSB_printf(vsb, "%s %s\n", abuf, pbuf);
+		good++;
+		tn = telnet_new(sock);
+		tn->ev = vev_new();
+		XXXAN(tn->ev);
+		tn->ev->fd = sock;
+		tn->ev->fd_flags = POLLIN;
+		tn->ev->callback = telnet_accept;
+		AZ(vev_add(mgt_evb, tn->ev));
+		free(ta[i]);
+		ta[i] = NULL;
+	}
+	free(ta);
+	if (good == 0) {
+		REPORT(LOG_ERR, "-T %s could not be listened on.", T_arg);
+		exit(2);
+	}
+	AZ(VSB_finish(vsb));
+	/* Save in shmem */
+	p = VSM_Alloc(VSB_len(vsb) + 1, "Arg", "-T", "");
+	AN(p);
+	strcpy(p, VSB_data(vsb));
+	VSB_delete(vsb);
+}
+
+/* Reverse CLI ("Master") connections --------------------------------*/
+
+static int M_fd = -1;
+static struct vev *M_poker, *M_conn;
+static struct vss_addr **M_ta;
+static int M_nta, M_nxt;
+static double M_poll = 0.1;
+
+static void
+Marg_closer(void *priv)
+{
+
+	(void)priv;
+	(void)close(M_fd);
+	M_fd = -1;
+}
+
+static int
+Marg_poker(const struct vev *e, int what)
+{
+	struct vsb *vsb;
+	int s, k;
+	socklen_t l;
+
+	(void)what;	/* XXX: ??? */
+
+	if (e == M_conn) {
+		/* Our connect(2) returned, check result */
+		l = sizeof k;
+		AZ(getsockopt(M_fd, SOL_SOCKET, SO_ERROR, &k, &l));
+		if (k) {
+			errno = k;
+			syslog(LOG_INFO, "Could not connect to CLI-master: %m");
+			(void)close(M_fd);
+			M_fd = -1;
+			/* Try next address */
+			if (++M_nxt >= M_nta) {
+				M_nxt = 0;
+				if (M_poll < 10)
+					M_poll *= 2;
+			}
+			return (1);
+		}
+		vsb = sock_id("master", M_fd);
+		mgt_cli_setup(M_fd, M_fd, 0, VSB_data(vsb), Marg_closer, NULL);
+		VSB_delete(vsb);
+		M_poll = 1;
+		return (1);
+	}
+
+	assert(e == M_poker);
+
+	M_poker->timeout = M_poll;	/* XXX nasty ? */
+	if (M_fd >= 0)
+		return (0);
+
+	/* Try to connect asynchronously */
+	s = VSS_connect(M_ta[M_nxt], 1);
+	if (s < 0)
+		return (0);
+
+	mgt_got_fd(s);
+
+	M_conn = vev_new();
+	AN(M_conn);
+	M_conn->callback = Marg_poker;
+	M_conn->name = "-M connector";
+	M_conn->fd_flags = EV_WR;
+	M_conn->fd = s;
+	M_fd = s;
+	AZ(vev_add(mgt_evb, M_conn));
+	return (0);
+}
+
+void
+mgt_cli_master(const char *M_arg)
+{
+	(void)M_arg;
+
+	M_nta = VSS_resolve(M_arg, NULL, &M_ta);
+	if (M_nta <= 0) {
+		fprintf(stderr, "Could resolve -M argument to address\n");
+		exit (1);
+	}
+	M_nxt = 0;
+	AZ(M_poker);
+	M_poker = vev_new();
+	AN(M_poker);
+	M_poker->timeout = M_poll;
+	M_poker->callback = Marg_poker;
+	M_poker->name = "-M poker";
+	AZ(vev_add(mgt_evb, M_poker));
+}
diff --git a/bin/varnishd/mgt/mgt_cli.h b/bin/varnishd/mgt/mgt_cli.h
new file mode 100644
index 0000000..8c49abb
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_cli.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2009 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* mgt_child.c */
+cli_func_t mcf_server_startstop;
+cli_func_t mcf_server_status;
+cli_func_t mcf_panic_show;
+cli_func_t mcf_panic_clear;
+
+/* mgt_param.c */
+cli_func_t mcf_param_show;
+cli_func_t mcf_param_set;
+
+/* mgt_vcc.c */
+cli_func_t mcf_config_load;
+cli_func_t mcf_config_inline;
+cli_func_t mcf_config_use;
+cli_func_t mcf_config_discard;
+cli_func_t mcf_config_list;
+cli_func_t mcf_config_show;
+
+/* stevedore.c */
+extern struct cli_proto cli_stv[];
diff --git a/bin/varnishd/mgt/mgt_param.c b/bin/varnishd/mgt/mgt_param.c
new file mode 100644
index 0000000..1ca6a74
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_param.c
@@ -0,0 +1,1237 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "waiter/cache_waiter.h"
+#include "heritage.h"
+#include "vav.h"
+#include "vcli.h"
+#include "vcli_common.h"
+#include "vcli_priv.h"
+#include "vparam.h"
+#include "vss.h"
+
+#include "mgt_cli.h"
+
+#define MAGIC_INIT_STRING	"\001"
+struct params master;
+static int nparspec;
+static struct parspec const ** parspec;
+static int margin;
+
+/*--------------------------------------------------------------------*/
+
+static const struct parspec *
+mcf_findpar(const char *name)
+{
+	int i;
+
+	for (i = 0; i < nparspec; i++)
+		if (!strcmp(parspec[i]->name, name))
+			return (parspec[i]);
+	return (NULL);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_generic_timeout(struct cli *cli, volatile unsigned *dst, const char *arg)
+{
+	unsigned u;
+
+	if (arg != NULL) {
+		u = strtoul(arg, NULL, 0);
+		if (u == 0) {
+			VCLI_Out(cli, "Timeout must be greater than zero\n");
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		*dst = u;
+	} else
+		VCLI_Out(cli, "%u", *dst);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+tweak_timeout(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	volatile unsigned *dest;
+
+	dest = par->priv;
+	tweak_generic_timeout(cli, dest, arg);
+}
+
+static void
+tweak_timeout_double(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+	volatile double *dest;
+	double u;
+
+	dest = par->priv;
+	if (arg != NULL) {
+		u = strtod(arg, NULL);
+		if (u < par->min) {
+			VCLI_Out(cli,
+			    "Timeout must be greater or equal to %.g\n",
+				 par->min);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		if (u > par->max) {
+			VCLI_Out(cli,
+			    "Timeout must be less than or equal to %.g\n",
+				 par->max);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		*dest = u;
+	} else
+		VCLI_Out(cli, "%.6f", *dest);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_generic_double(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+	volatile double *dest;
+	double u;
+
+	dest = par->priv;
+	if (arg != NULL) {
+		u = strtod(arg, NULL);
+		if (u < par->min) {
+			VCLI_Out(cli,
+			    "Must be greater or equal to %.g\n",
+				 par->min);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		if (u > par->max) {
+			VCLI_Out(cli,
+			    "Must be less than or equal to %.g\n",
+				 par->max);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		*dest = u;
+	} else
+		VCLI_Out(cli, "%f", *dest);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_generic_bool(struct cli *cli, volatile unsigned *dest, const char *arg)
+{
+	if (arg != NULL) {
+		if (!strcasecmp(arg, "off"))
+			*dest = 0;
+		else if (!strcasecmp(arg, "disable"))
+			*dest = 0;
+		else if (!strcasecmp(arg, "no"))
+			*dest = 0;
+		else if (!strcasecmp(arg, "false"))
+			*dest = 0;
+		else if (!strcasecmp(arg, "on"))
+			*dest = 1;
+		else if (!strcasecmp(arg, "enable"))
+			*dest = 1;
+		else if (!strcasecmp(arg, "yes"))
+			*dest = 1;
+		else if (!strcasecmp(arg, "true"))
+			*dest = 1;
+		else {
+			VCLI_Out(cli, "use \"on\" or \"off\"\n");
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+	} else
+		VCLI_Out(cli, *dest ? "on" : "off");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_bool(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	volatile unsigned *dest;
+
+	dest = par->priv;
+	tweak_generic_bool(cli, dest, arg);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
+    unsigned min, unsigned max)
+{
+	unsigned u;
+
+	if (arg != NULL) {
+		if (!strcasecmp(arg, "unlimited"))
+			u = UINT_MAX;
+		else
+			u = strtoul(arg, NULL, 0);
+		if (u < min) {
+			VCLI_Out(cli, "Must be at least %u\n", min);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		if (u > max) {
+			VCLI_Out(cli, "Must be no more than %u\n", max);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		*dest = u;
+	} else if (*dest == UINT_MAX) {
+		VCLI_Out(cli, "unlimited", *dest);
+	} else {
+		VCLI_Out(cli, "%u", *dest);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+tweak_uint(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	volatile unsigned *dest;
+
+	dest = par->priv;
+	tweak_generic_uint(cli, dest, arg, (uint)par->min, (uint)par->max);
+}
+
+/*--------------------------------------------------------------------
+ * XXX: slightly magic.  We want to initialize to "nobody" (XXX: shouldn't
+ * XXX: that be something autocrap found for us ?) but we don't want to
+ * XXX: fail initialization if that user doesn't exists, even though we
+ * XXX: do want to fail it, in subsequent sets.
+ * XXX: The magic init string is a hack for this.
+ */
+
+static void
+tweak_user(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	struct passwd *pw;
+	struct group *gr;
+
+	(void)par;
+	if (arg != NULL) {
+		if (!strcmp(arg, MAGIC_INIT_STRING)) {
+			pw = getpwnam("nobody");
+			if (pw == NULL) {
+				master.uid = getuid();
+				return;
+			}
+		} else
+			pw = getpwnam(arg);
+		if (pw == NULL) {
+			VCLI_Out(cli, "Unknown user");
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		REPLACE(master.user, pw->pw_name);
+		master.uid = pw->pw_uid;
+		master.gid = pw->pw_gid;
+
+		/* set group to user's primary group */
+		if ((gr = getgrgid(pw->pw_gid)) != NULL &&
+		    (gr = getgrnam(gr->gr_name)) != NULL &&
+		    gr->gr_gid == pw->pw_gid)
+			REPLACE(master.group, gr->gr_name);
+	} else if (master.user) {
+		VCLI_Out(cli, "%s (%d)", master.user, (int)master.uid);
+	} else {
+		VCLI_Out(cli, "%d", (int)master.uid);
+	}
+}
+
+/*--------------------------------------------------------------------
+ * XXX: see comment for tweak_user, same thing here.
+ */
+
+static void
+tweak_group(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	struct group *gr;
+
+	(void)par;
+	if (arg != NULL) {
+		if (!strcmp(arg, MAGIC_INIT_STRING)) {
+			gr = getgrnam("nogroup");
+			if (gr == NULL) {
+				/* Only replace if tweak_user didn't */
+				if (master.gid == 0)
+					master.gid = getgid();
+				return;
+			}
+		} else
+			gr = getgrnam(arg);
+		if (gr == NULL) {
+			VCLI_Out(cli, "Unknown group");
+			VCLI_SetResult(cli, CLIS_PARAM);
+			return;
+		}
+		REPLACE(master.group, gr->gr_name);
+		master.gid = gr->gr_gid;
+	} else if (master.group) {
+		VCLI_Out(cli, "%s (%d)", master.group, (int)master.gid);
+	} else {
+		VCLI_Out(cli, "%d", (int)master.gid);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+clean_listen_sock_head(struct listen_sock_head *lsh)
+{
+	struct listen_sock *ls, *ls2;
+
+	VTAILQ_FOREACH_SAFE(ls, lsh, list, ls2) {
+		CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
+		VTAILQ_REMOVE(lsh, ls, list);
+		free(ls->name);
+		free(ls->addr);
+		FREE_OBJ(ls);
+	}
+}
+
+static void
+tweak_listen_address(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+	char **av;
+	int i;
+	struct listen_sock		*ls;
+	struct listen_sock_head		lsh;
+
+	(void)par;
+	if (arg == NULL) {
+		VCLI_Quote(cli, master.listen_address);
+		return;
+	}
+
+	av = VAV_Parse(arg, NULL, ARGV_COMMA);
+	if (av == NULL) {
+		VCLI_Out(cli, "Parse error: out of memory");
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+	if (av[0] != NULL) {
+		VCLI_Out(cli, "Parse error: %s", av[0]);
+		VCLI_SetResult(cli, CLIS_PARAM);
+		VAV_Free(av);
+		return;
+	}
+	if (av[1] == NULL) {
+		VCLI_Out(cli, "Empty listen address");
+		VCLI_SetResult(cli, CLIS_PARAM);
+		VAV_Free(av);
+		return;
+	}
+	VTAILQ_INIT(&lsh);
+	for (i = 1; av[i] != NULL; i++) {
+		struct vss_addr **ta;
+		int j, n;
+
+		n = VSS_resolve(av[i], "http", &ta);
+		if (n == 0) {
+			VCLI_Out(cli, "Invalid listen address ");
+			VCLI_Quote(cli, av[i]);
+			VCLI_SetResult(cli, CLIS_PARAM);
+			break;
+		}
+		for (j = 0; j < n; ++j) {
+			ALLOC_OBJ(ls, LISTEN_SOCK_MAGIC);
+			AN(ls);
+			ls->sock = -1;
+			ls->addr = ta[j];
+			ls->name = strdup(av[i]);
+			AN(ls->name);
+			VTAILQ_INSERT_TAIL(&lsh, ls, list);
+		}
+		free(ta);
+	}
+	VAV_Free(av);
+	if (cli != NULL && cli->result != CLIS_OK) {
+		clean_listen_sock_head(&lsh);
+		return;
+	}
+
+	REPLACE(master.listen_address, arg);
+
+	clean_listen_sock_head(&heritage.socks);
+	heritage.nsocks = 0;
+
+	while (!VTAILQ_EMPTY(&lsh)) {
+		ls = VTAILQ_FIRST(&lsh);
+		VTAILQ_REMOVE(&lsh, ls, list);
+		CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
+		VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
+		heritage.nsocks++;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_string(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	char **p = TRUST_ME(par->priv);
+
+	AN(p);
+	/* XXX should have tweak_generic_string */
+	if (arg == NULL) {
+		VCLI_Quote(cli, *p);
+	} else {
+		REPLACE(*p, arg);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_waiter(struct cli *cli, const struct parspec *par, const char *arg)
+{
+
+	/* XXX should have tweak_generic_string */
+	(void)par;
+	WAIT_tweak_waiter(cli, arg);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_diag_bitmap(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	unsigned u;
+
+	(void)par;
+	if (arg != NULL) {
+		u = strtoul(arg, NULL, 0);
+		master.diag_bitmap = u;
+	} else {
+		VCLI_Out(cli, "0x%x", master.diag_bitmap);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+/*
+ * Make sure to end all lines with either a space or newline of the
+ * formatting will go haywire.
+ */
+
+#define DELAYED_EFFECT_TEXT \
+	"\nNB: This parameter may take quite some time to take (full) effect."
+
+#define MUST_RESTART_TEXT \
+	"\nNB: This parameter will not take any effect until the " \
+	"child process has been restarted."
+
+#define MUST_RELOAD_TEXT \
+	"\nNB: This parameter will not take any effect until the " \
+	"VCL programs have been reloaded."
+
+#define EXPERIMENTAL_TEXT \
+	"\nNB: We do not know yet if it is a good idea to change " \
+	"this parameter, or if the default value is even sensible.  " \
+	"Caution is advised, and feedback is most welcome."
+
+#define WIZARD_TEXT \
+	"\nNB: Do not change this parameter, unless a developer tell " \
+	"you to do so."
+
+/*
+ * Remember to update varnishd.1 whenever you add / remove a parameter or
+ * change its default value.
+ * XXX: we should generate the relevant section of varnishd.1 from here.
+ */
+static const struct parspec input_parspec[] = {
+	{ "user", tweak_user, NULL, 0, 0,
+		"The unprivileged user to run as.  Setting this will "
+		"also set \"group\" to the specified user's primary group.",
+		MUST_RESTART,
+		MAGIC_INIT_STRING },
+	{ "group", tweak_group, NULL, 0, 0,
+		"The unprivileged group to run as.",
+		MUST_RESTART,
+		MAGIC_INIT_STRING },
+	{ "default_ttl", tweak_timeout_double, &master.default_ttl,
+		0, UINT_MAX,
+		"The TTL assigned to objects if neither the backend nor "
+		"the VCL code assigns one.\n"
+		"Objects already cached will not be affected by changes "
+		"made until they are fetched from the backend again.\n"
+		"To force an immediate effect at the expense of a total "
+		"flush of the cache use \"ban.url .\"",
+		0,
+		"120", "seconds" },
+	{ "sess_workspace", tweak_uint, &master.sess_workspace, 1024, UINT_MAX,
+		"Bytes of HTTP protocol workspace allocated for sessions. "
+		"This space must be big enough for the entire HTTP protocol "
+		"header and any edits done to it in the VCL code.\n"
+		"Minimum is 1024 bytes.",
+		DELAYED_EFFECT,
+		"65536",
+		"bytes" },
+	{ "http_req_hdr_len", tweak_uint, &master.http_req_hdr_len,
+		40, UINT_MAX,
+		"Maximum length of any HTTP client request header we will "
+		"allow.  The limit is inclusive its continuation lines.\n",
+		0,
+		"8192", "bytes" },
+	{ "http_req_size", tweak_uint, &master.http_req_size,
+		256, UINT_MAX,
+		"Maximum number of bytes of HTTP client request we will deal "
+		"with.  This is a limit on all bytes up to the double blank "
+		"line which ends the HTTP request.\n"
+		"The memory for the request is allocated from the session "
+		"workspace (param: sess_workspace) and this parameter limits "
+		"how much of that the request is allowed to take up.",
+		0,
+		"32768", "bytes" },
+	{ "http_resp_hdr_len", tweak_uint, &master.http_resp_hdr_len,
+		40, UINT_MAX,
+		"Maximum length of any HTTP backend response header we will "
+		"allow.  The limit is inclusive its continuation lines.\n",
+		0,
+		"8192", "bytes" },
+	{ "http_resp_size", tweak_uint, &master.http_resp_size,
+		256, UINT_MAX,
+		"Maximum number of bytes of HTTP backend resonse we will deal "
+		"with.  This is a limit on all bytes up to the double blank "
+		"line which ends the HTTP request.\n"
+		"The memory for the request is allocated from the worker "
+		"workspace (param: sess_workspace) and this parameter limits "
+		"how much of that the request is allowed to take up.",
+		0,
+		"32768", "bytes" },
+	{ "http_max_hdr", tweak_uint, &master.http_max_hdr, 32, 65535,
+		"Maximum number of HTTP headers we will deal with in "
+		"client request or backend reponses.  "
+		"Note that the first line occupies five header fields.\n"
+		"This paramter does not influence storage consumption, "
+		"objects allocate exact space for the headers they store.\n",
+		0,
+		"64", "header lines" },
+	{ "shm_workspace", tweak_uint, &master.shm_workspace, 4096, UINT_MAX,
+		"Bytes of shmlog workspace allocated for worker threads. "
+		"If too big, it wastes some ram, if too small it causes "
+		"needless flushes of the SHM workspace.\n"
+		"These flushes show up in stats as "
+		"\"SHM flushes due to overflow\".\n"
+		"Minimum is 4096 bytes.",
+		DELAYED_EFFECT,
+		"8192", "bytes" },
+	{ "shm_reclen", tweak_uint, &master.shm_reclen, 16, 65535,
+		"Maximum number of bytes in SHM log record.\n"
+		"Maximum is 65535 bytes.",
+		0,
+		"255", "bytes" },
+	{ "default_grace", tweak_timeout_double, &master.default_grace,
+		0, UINT_MAX,
+		"Default grace period.  We will deliver an object "
+		"this long after it has expired, provided another thread "
+		"is attempting to get a new copy.\n"
+		"Objects already cached will not be affected by changes "
+		"made until they are fetched from the backend again.\n",
+		DELAYED_EFFECT,
+		"10", "seconds" },
+	{ "default_keep", tweak_timeout_double, &master.default_keep,
+		0, UINT_MAX,
+		"Default keep period.  We will keep a useless object "
+		"around this long, making it available for conditional "
+		"backend fetches.  "
+		"That means that the object will be removed from the "
+		"cache at the end of ttl+grace+keep.",
+		DELAYED_EFFECT,
+		"0", "seconds" },
+	{ "sess_timeout", tweak_timeout, &master.sess_timeout, 0, 0,
+		"Idle timeout for persistent sessions. "
+		"If a HTTP request has not been received in this many "
+		"seconds, the session is closed.",
+		0,
+		"5", "seconds" },
+	{ "expiry_sleep", tweak_timeout_double, &master.expiry_sleep, 0, 60,
+		"How long the expiry thread sleeps when there is nothing "
+		"for it to do.\n",
+		0,
+		"1", "seconds" },
+	{ "pipe_timeout", tweak_timeout, &master.pipe_timeout, 0, 0,
+		"Idle timeout for PIPE sessions. "
+		"If nothing have been received in either direction for "
+		"this many seconds, the session is closed.\n",
+		0,
+		"60", "seconds" },
+	{ "send_timeout", tweak_timeout, &master.send_timeout, 0, 0,
+		"Send timeout for client connections. "
+		"If the HTTP response hasn't been transmitted in this many\n"
+                "seconds the session is closed. \n"
+		"See setsockopt(2) under SO_SNDTIMEO for more information.",
+		DELAYED_EFFECT,
+		"60", "seconds" },
+	{ "auto_restart", tweak_bool, &master.auto_restart, 0, 0,
+		"Restart child process automatically if it dies.\n",
+		0,
+		"on", "bool" },
+	{ "nuke_limit",
+		tweak_uint, &master.nuke_limit, 0, UINT_MAX,
+		"Maximum number of objects we attempt to nuke in order"
+		"to make space for a object body.",
+		EXPERIMENTAL,
+		"50", "allocations" },
+	{ "fetch_chunksize",
+		tweak_uint, &master.fetch_chunksize, 4, UINT_MAX / 1024.,
+		"The default chunksize used by fetcher. "
+		"This should be bigger than the majority of objects with "
+		"short TTLs.\n"
+		"Internal limits in the storage_file module makes increases "
+		"above 128kb a dubious idea.",
+		EXPERIMENTAL,
+		"128", "kilobytes" },
+	{ "fetch_maxchunksize",
+		tweak_uint, &master.fetch_maxchunksize, 64, UINT_MAX / 1024.,
+		"The maximum chunksize we attempt to allocate from storage. "
+		"Making this too large may cause delays and storage "
+		"fragmentation.\n",
+		EXPERIMENTAL,
+		"262144", "kilobytes" },
+#ifdef SENDFILE_WORKS
+	{ "sendfile_threshold",
+		tweak_uint, &master.sendfile_threshold, 0, UINT_MAX,
+		"The minimum size of objects transmitted with sendfile.",
+		EXPERIMENTAL,
+		"-1", "bytes" },
+#endif /* SENDFILE_WORKS */
+	{ "vcl_trace", tweak_bool,  &master.vcl_trace, 0, 0,
+		"Trace VCL execution in the shmlog.\n"
+		"Enabling this will allow you to see the path each "
+		"request has taken through the VCL program.\n"
+		"This generates a lot of logrecords so it is off by "
+		"default.",
+		0,
+		"off", "bool" },
+	{ "listen_address", tweak_listen_address, NULL, 0, 0,
+		"Whitespace separated list of network endpoints where "
+		"Varnish will accept requests.\n"
+		"Possible formats: host, host:port, :port",
+		MUST_RESTART,
+		":80" },
+	{ "listen_depth", tweak_uint, &master.listen_depth, 0, UINT_MAX,
+		"Listen queue depth.",
+		MUST_RESTART,
+		"1024", "connections" },
+	{ "cli_timeout", tweak_timeout, &master.cli_timeout, 0, 0,
+		"Timeout for the childs replies to CLI requests from "
+		"the master.",
+		0,
+		"10", "seconds" },
+	{ "ping_interval", tweak_uint, &master.ping_interval, 0, UINT_MAX,
+		"Interval between pings from parent to child.\n"
+		"Zero will disable pinging entirely, which makes "
+		"it possible to attach a debugger to the child.",
+		MUST_RESTART,
+		"3", "seconds" },
+	{ "lru_interval", tweak_timeout, &master.lru_timeout, 0, 0,
+		"Grace period before object moves on LRU list.\n"
+		"Objects are only moved to the front of the LRU "
+		"list if they have not been moved there already inside "
+		"this timeout period.  This reduces the amount of lock "
+		"operations necessary for LRU list access.",
+		EXPERIMENTAL,
+		"2", "seconds" },
+	{ "cc_command", tweak_string, &mgt_cc_cmd, 0, 0,
+		"Command used for compiling the C source code to a "
+		"dlopen(3) loadable object.  Any occurrence of %s in "
+		"the string will be replaced with the source file name, "
+		"and %o will be replaced with the output file name.",
+		MUST_RELOAD,
+		VCC_CC , NULL },
+	{ "max_restarts", tweak_uint, &master.max_restarts, 0, UINT_MAX,
+		"Upper limit on how many times a request can restart."
+		"\nBe aware that restarts are likely to cause a hit against "
+		"the backend, so don't increase thoughtlessly.\n",
+		0,
+		"4", "restarts" },
+	{ "esi_syntax",
+		tweak_uint, &master.esi_syntax, 0, UINT_MAX,
+		"Bitmap controlling ESI parsing code:\n"
+		"  0x00000001 - Don't check if it looks like XML\n"
+		"  0x00000002 - Ignore non-esi elements\n"
+		"  0x00000004 - Emit parsing debug records\n"
+		"  0x00000008 - Force-split parser input (debugging)\n"
+		"Use 0x notation and do the bitor in your head :-)\n",
+		0,
+		"0", "bitmap" },
+	{ "max_esi_depth",
+		tweak_uint, &master.max_esi_depth, 0, UINT_MAX,
+		"Maximum depth of esi:include processing.\n",
+		0,
+		"5", "levels" },
+	{ "connect_timeout", tweak_timeout_double,
+		&master.connect_timeout,0, UINT_MAX,
+		"Default connection timeout for backend connections. "
+		"We only try to connect to the backend for this many "
+		"seconds before giving up. "
+		"VCL can override this default value for each backend and "
+		"backend request.",
+		0,
+		"0.7", "s" },
+	{ "first_byte_timeout", tweak_timeout_double,
+		&master.first_byte_timeout,0, UINT_MAX,
+		"Default timeout for receiving first byte from backend. "
+		"We only wait for this many seconds for the first "
+		"byte before giving up. A value of 0 means it will never time "
+		"out. "
+		"VCL can override this default value for each backend and "
+		"backend request. This parameter does not apply to pipe.",
+		0,
+		"60", "s" },
+	{ "between_bytes_timeout", tweak_timeout_double,
+		&master.between_bytes_timeout,0, UINT_MAX,
+		"Default timeout between bytes when receiving data from "
+		"backend. "
+		"We only wait for this many seconds between bytes "
+		"before giving up. A value of 0 means it will never time out. "
+		"VCL can override this default value for each backend request "
+		"and backend request. This parameter does not apply to pipe.",
+		0,
+		"60", "s" },
+	{ "acceptor_sleep_max", tweak_timeout_double,
+		&master.acceptor_sleep_max, 0,  10,
+		"If we run out of resources, such as file descriptors or "
+		"worker threads, the acceptor will sleep between accepts.\n"
+		"This parameter limits how long it can sleep between "
+		"attempts to accept new connections.",
+		EXPERIMENTAL,
+		"0.050", "s" },
+	{ "acceptor_sleep_incr", tweak_timeout_double,
+		&master.acceptor_sleep_incr, 0,  1,
+		"If we run out of resources, such as file descriptors or "
+		"worker threads, the acceptor will sleep between accepts.\n"
+		"This parameter control how much longer we sleep, each time "
+		"we fail to accept a new connection.",
+		EXPERIMENTAL,
+		"0.001", "s" },
+	{ "acceptor_sleep_decay", tweak_generic_double,
+		&master.acceptor_sleep_decay, 0,  1,
+		"If we run out of resources, such as file descriptors or "
+		"worker threads, the acceptor will sleep between accepts.\n"
+		"This parameter (multiplicatively) reduce the sleep duration "
+		"for each succesfull accept. (ie: 0.9 = reduce by 10%)",
+		EXPERIMENTAL,
+		"0.900", "" },
+	{ "clock_skew", tweak_uint, &master.clock_skew, 0, UINT_MAX,
+		"How much clockskew we are willing to accept between the "
+		"backend and our own clock.",
+		0,
+		"10", "s" },
+	{ "prefer_ipv6", tweak_bool, &master.prefer_ipv6, 0, 0,
+		"Prefer IPv6 address when connecting to backends which "
+		"have both IPv4 and IPv6 addresses.",
+		0,
+		"off", "bool" },
+	{ "session_max", tweak_uint,
+		&master.max_sess, 1000, UINT_MAX,
+		"Maximum number of sessions we will allocate from one pool "
+		"before just dropping connections.\n"
+		"This is mostly an anti-DoS measure, and setting it plenty "
+		"high should not hurt, as long as you have the memory for "
+		"it.\n",
+		0,
+		"100000", "sessions" },
+	{ "session_linger", tweak_uint,
+		&master.session_linger,0, UINT_MAX,
+		"How long time the workerthread lingers on the session "
+		"to see if a new request appears right away.\n"
+		"If sessions are reused, as much as half of all reuses "
+		"happen within the first 100 msec of the previous request "
+		"completing.\n"
+		"Setting this too high results in worker threads not doing "
+		"anything for their keep, setting it too low just means that "
+		"more sessions take a detour around the waiter.",
+		EXPERIMENTAL,
+		"50", "ms" },
+	{ "cli_buffer", tweak_uint, &master.cli_buffer, 4096, UINT_MAX,
+		"Size of buffer for CLI input."
+		"\nYou may need to increase this if you have big VCL files "
+		"and use the vcl.inline CLI command.\n"
+		"NB: Must be specified with -p to have effect.\n",
+		0,
+		"8192", "bytes" },
+	{ "log_hashstring", tweak_bool, &master.log_hash, 0, 0,
+		"Log the hash string components to shared memory log.\n",
+		0,
+		"on", "bool" },
+	{ "log_local_address", tweak_bool, &master.log_local_addr, 0, 0,
+		"Log the local address on the TCP connection in the "
+		"SessionOpen shared memory record.\n",
+		0,
+		"off", "bool" },
+	{ "waiter", tweak_waiter, NULL, 0, 0,
+		"Select the waiter kernel interface.\n",
+		EXPERIMENTAL | MUST_RESTART,
+		"default", NULL },
+	{ "diag_bitmap", tweak_diag_bitmap, 0, 0, 0,
+		"Bitmap controlling diagnostics code:\n"
+		"  0x00000001 - CNT_Session states.\n"
+		"  0x00000002 - workspace debugging.\n"
+		"  0x00000004 - kqueue debugging.\n"
+		"  0x00000008 - mutex logging.\n"
+		"  0x00000010 - mutex contests.\n"
+		"  0x00000020 - waiting list.\n"
+		"  0x00000040 - object workspace.\n"
+		"  0x00001000 - do not core-dump child process.\n"
+		"  0x00002000 - only short panic message.\n"
+		"  0x00004000 - panic to stderr.\n"
+#ifdef HAVE_ABORT2
+		"  0x00008000 - panic to abort2().\n"
+#endif
+		"  0x00010000 - synchronize shmlog.\n"
+		"  0x00020000 - synchronous start of persistence.\n"
+		"  0x00040000 - release VCL early.\n"
+		"  0x80000000 - do edge-detection on digest.\n"
+		"Use 0x notation and do the bitor in your head :-)\n",
+		0,
+		"0", "bitmap" },
+	{ "ban_dups", tweak_bool, &master.ban_dups, 0, 0,
+		"Detect and eliminate duplicate bans.\n",
+		0,
+		"on", "bool" },
+	{ "syslog_cli_traffic", tweak_bool, &master.syslog_cli_traffic, 0, 0,
+		"Log all CLI traffic to syslog(LOG_INFO).\n",
+		0,
+		"on", "bool" },
+	{ "ban_lurker_sleep", tweak_timeout_double,
+		&master.ban_lurker_sleep, 0, UINT_MAX,
+		"How long time does the ban lurker thread sleeps between "
+		"successful attempts to push the last item up the ban "
+		" list.  It always sleeps a second when nothing can be done.\n"
+		"A value of zero disables the ban lurker.",
+		0,
+		"0.01", "s" },
+	{ "saintmode_threshold", tweak_uint,
+		&master.saintmode_threshold, 0, UINT_MAX,
+		"The maximum number of objects held off by saint mode before "
+		"no further will be made to the backend until one times out.  "
+		"A value of 0 disables saintmode.",
+		EXPERIMENTAL,
+		"10", "objects" },
+	{ "http_range_support", tweak_bool, &master.http_range_support, 0, 0,
+		"Enable support for HTTP Range headers.\n",
+		EXPERIMENTAL,
+		"on", "bool" },
+	{ "http_gzip_support", tweak_bool, &master.http_gzip_support, 0, 0,
+		"Enable gzip support. When enabled Varnish will compress "
+		"uncompressed objects before they are stored in the cache. "
+		"If a client does not support gzip encoding Varnish will "
+		"uncompress compressed objects on demand. Varnish will also "
+		"rewrite the Accept-Encoding header of clients indicating "
+		"support for gzip to:\n"
+		"Accept-Encoding: gzip\n\n"
+		"Clients that do not support gzip will have their "
+		"Accept-Encoding header removed. For more information on how "
+		"gzip is implemented please see the chapter on gzip in the "
+		"Varnish reference.",
+		EXPERIMENTAL,
+		"on", "bool" },
+	{ "gzip_tmp_space", tweak_uint, &master.gzip_tmp_space, 0, 2,
+		"Where temporary space for gzip/gunzip is allocated:\n"
+		"  0 - malloc\n"
+		"  1 - session workspace\n"
+		"  2 - thread workspace\n"
+		"If you have much gzip/gunzip activity, it may be an"
+		" advantage to use workspace for these allocations to reduce"
+		" malloc activity.  Be aware that gzip needs 256+KB and gunzip"
+		" needs 32+KB of workspace (64+KB if ESI processing).",
+		EXPERIMENTAL,
+		"0", "" },
+	{ "gzip_level", tweak_uint, &master.gzip_level, 0, 9,
+		"Gzip compression level: 0=debug, 1=fast, 9=best",
+		0,
+		"6", ""},
+	{ "gzip_window", tweak_uint, &master.gzip_window, 8, 15,
+		"Gzip window size 8=least, 15=most compression.\n"
+		"Memory impact is 8=1k, 9=2k, ... 15=128k.",
+		0,
+		"15", ""},
+	{ "gzip_memlevel", tweak_uint, &master.gzip_memlevel, 1, 9,
+		"Gzip memory level 1=slow/least, 9=fast/most compression.\n"
+		"Memory impact is 1=1k, 2=2k, ... 9=256k.",
+		0,
+		"8", ""},
+	{ "gzip_stack_buffer", tweak_uint, &master.gzip_stack_buffer,
+	        2048, UINT_MAX,
+		"Size of stack buffer used for gzip processing.\n"
+		"The stack buffers are used for in-transit data,"
+		" for instance gunzip'ed data being sent to a client."
+		"Making this space to small results in more overhead,"
+		" writes to sockets etc, making it too big is probably"
+		" just a waste of memory.",
+		EXPERIMENTAL,
+		"32768", "Bytes" },
+	{ "shortlived", tweak_timeout_double,
+		&master.shortlived, 0, UINT_MAX,
+		"Objects created with TTL shorter than this are always "
+		"put in transient storage.\n",
+		0,
+		"10.0", "s" },
+	{ "critbit_cooloff", tweak_timeout_double,
+		&master.critbit_cooloff, 60, 254,
+		"How long time the critbit hasher keeps deleted objheads "
+		"on the cooloff list.\n",
+		WIZARD,
+		"180.0", "s" },
+	{ "vcl_dir", tweak_string, &mgt_vcl_dir, 0, 0,
+		"Directory from which relative VCL filenames (vcl.load and "
+		"include) are opened.",
+		0,
+#ifdef VARNISH_VCL_DIR
+		VARNISH_VCL_DIR,
+#else
+		".",
+#endif
+		NULL },
+	{ "vmod_dir", tweak_string, &mgt_vmod_dir, 0, 0,
+		"Directory where VCL modules are to be found.",
+		0,
+#ifdef VARNISH_VMOD_DIR
+		VARNISH_VMOD_DIR,
+#else
+		".",
+#endif
+		NULL },
+	{ "vcc_err_unref", tweak_bool, &mgt_vcc_err_unref, 0, 0,
+		"Unreferenced VCL objects result in error.\n",
+		0,
+		"on", "bool" },
+
+
+	{ "pcre_match_limit", tweak_uint,
+		&master.vre_limits.match,
+		1, UINT_MAX,
+		"The limit for the  number of internal matching function"
+		" calls in a pcre_exec() execution.",
+		0,
+		"10000", ""},
+
+	{ "pcre_match_limit_recursion", tweak_uint,
+		&master.vre_limits.match_recursion,
+		1, UINT_MAX,
+		"The limit for the  number of internal matching function"
+		" recursions in a pcre_exec() execution.",
+		0,
+		"10000", ""},
+
+	{ NULL, NULL, NULL }
+};
+
+/*--------------------------------------------------------------------*/
+
+#define WIDTH 76
+
+static void
+mcf_wrap(struct cli *cli, const char *text)
+{
+	const char *p, *q;
+
+	/* Format text to COLUMNS width */
+	for (p = text; *p != '\0'; ) {
+		q = strchr(p, '\n');
+		if (q == NULL)
+			q = strchr(p, '\0');
+		if (q > p + WIDTH - margin) {
+			q = p + WIDTH - margin;
+			while (q > p && *q != ' ')
+				q--;
+			AN(q);
+		}
+		VCLI_Out(cli, "%*s %.*s\n", margin, "", (int)(q - p), p);
+		p = q;
+		if (*p == ' ' || *p == '\n')
+			p++;
+	}
+}
+
+void
+mcf_param_show(struct cli *cli, const char * const *av, void *priv)
+{
+	int i;
+	const struct parspec *pp;
+	int lfmt;
+
+	(void)priv;
+	if (av[2] == NULL || strcmp(av[2], "-l"))
+		lfmt = 0;
+	else
+		lfmt = 1;
+	for (i = 0; i < nparspec; i++) {
+		pp = parspec[i];
+		if (av[2] != NULL && !lfmt && strcmp(pp->name, av[2]))
+			continue;
+		VCLI_Out(cli, "%-*s ", margin, pp->name);
+		if (pp->func == NULL) {
+			VCLI_Out(cli, "Not implemented.\n");
+			if (av[2] != NULL && !lfmt)
+				return;
+			else
+				continue;
+		}
+		pp->func(cli, pp, NULL);
+		if (pp->units != NULL)
+			VCLI_Out(cli, " [%s]\n", pp->units);
+		else
+			VCLI_Out(cli, "\n");
+		if (av[2] != NULL) {
+			VCLI_Out(cli, "%-*s Default is %s\n",
+			    margin, "", pp->def);
+			mcf_wrap(cli, pp->descr);
+			if (pp->flags & DELAYED_EFFECT)
+				mcf_wrap(cli, DELAYED_EFFECT_TEXT);
+			if (pp->flags & EXPERIMENTAL)
+				mcf_wrap(cli, EXPERIMENTAL_TEXT);
+			if (pp->flags & MUST_RELOAD)
+				mcf_wrap(cli, MUST_RELOAD_TEXT);
+			if (pp->flags & MUST_RESTART)
+				mcf_wrap(cli, MUST_RESTART_TEXT);
+			if (pp->flags & WIZARD)
+				mcf_wrap(cli, WIZARD_TEXT);
+			if (!lfmt)
+				return;
+			else
+				VCLI_Out(cli, "\n");
+		}
+	}
+	if (av[2] != NULL && !lfmt) {
+		VCLI_SetResult(cli, CLIS_PARAM);
+		VCLI_Out(cli, "Unknown parameter \"%s\".", av[2]);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+MCF_ParamSync(void)
+{
+	if (params != &master)
+		*params = master;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+MCF_ParamSet(struct cli *cli, const char *param, const char *val)
+{
+	const struct parspec *pp;
+
+	pp = mcf_findpar(param);
+	if (pp != NULL) {
+		pp->func(cli, pp, val);
+		if (cli->result != CLIS_OK) {
+			VCLI_Out(cli, "(attempting to set param %s to %s)\n",
+			    pp->name, val);
+		} else if (child_pid >= 0 && pp->flags & MUST_RESTART) {
+			VCLI_Out(cli, "Change will take effect"
+			    " when child is restarted");
+		} else if (pp->flags & MUST_RELOAD) {
+			VCLI_Out(cli, "Change will take effect"
+			    " when VCL script is reloaded");
+		}
+		MCF_ParamSync();
+		return;
+	}
+	VCLI_SetResult(cli, CLIS_PARAM);
+	VCLI_Out(cli, "Unknown parameter \"%s\".", param);
+}
+
+
+/*--------------------------------------------------------------------*/
+
+void
+mcf_param_set(struct cli *cli, const char * const *av, void *priv)
+{
+
+	(void)priv;
+	MCF_ParamSet(cli, av[2], av[3]);
+}
+
+/*--------------------------------------------------------------------
+ * Add a group of parameters to the global set and sort by name.
+ */
+
+static int
+parspec_cmp(const void *a, const void *b)
+{
+	struct parspec * const * pa = a;
+	struct parspec * const * pb = b;
+	return (strcmp((*pa)->name, (*pb)->name));
+}
+
+static void
+MCF_AddParams(const struct parspec *ps)
+{
+	const struct parspec *pp;
+	int n;
+
+	n = 0;
+	for (pp = ps; pp->name != NULL; pp++) {
+		if (mcf_findpar(pp->name) != NULL)
+			fprintf(stderr, "Duplicate param: %s\n", pp->name);
+		if (strlen(pp->name) + 1 > margin)
+			margin = strlen(pp->name) + 1;
+		n++;
+	}
+	parspec = realloc(parspec, (1L + nparspec + n) * sizeof *parspec);
+	XXXAN(parspec);
+	for (pp = ps; pp->name != NULL; pp++)
+		parspec[nparspec++] = pp;
+	parspec[nparspec] = NULL;
+	qsort (parspec, nparspec, sizeof parspec[0], parspec_cmp);
+}
+
+/*--------------------------------------------------------------------
+ * Set defaults for all parameters
+ */
+
+static void
+MCF_SetDefaults(struct cli *cli)
+{
+	const struct parspec *pp;
+	int i;
+
+	for (i = 0; i < nparspec; i++) {
+		pp = parspec[i];
+		if (cli != NULL)
+			VCLI_Out(cli,
+			    "Set Default for %s = %s\n", pp->name, pp->def);
+		pp->func(cli, pp, pp->def);
+		if (cli != NULL && cli->result != CLIS_OK)
+			return;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+MCF_ParamInit(struct cli *cli)
+{
+
+	MCF_AddParams(input_parspec);
+	MCF_AddParams(WRK_parspec);
+
+	/* XXX: We do this twice, to get past any interdependencies */
+	MCF_SetDefaults(NULL);
+	MCF_SetDefaults(cli);
+
+	params = &master;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+MCF_DumpRst(void)
+{
+	const struct parspec *pp;
+	const char *p, *q;
+	int i;
+
+	for (i = 0; i < nparspec; i++) {
+		pp = parspec[i];
+		printf("%s\n", pp->name);
+		if (pp->units != NULL && *pp->units != '\0')
+			printf("\t- Units: %s\n", pp->units);
+		printf("\t- Default: %s\n",
+		    strcmp(pp->def,MAGIC_INIT_STRING) == 0 ? "magic" : pp->def);
+		/*
+		 * XXX: we should mark the params with one/two flags
+		 * XXX: that say if ->min/->max are valid, so we
+		 * XXX: can emit those also in help texts.
+		 */
+		if (pp->flags) {
+			printf("\t- Flags: ");
+			q = "";
+			if (pp->flags & DELAYED_EFFECT) {
+				printf("%sdelayed", q);
+				q = ", ";
+			}
+			if (pp->flags & MUST_RESTART) {
+				printf("%smust_restart", q);
+				q = ", ";
+			}
+			if (pp->flags & MUST_RELOAD) {
+				printf("%smust_reload", q);
+				q = ", ";
+			}
+			if (pp->flags & EXPERIMENTAL) {
+				printf("%sexperimental", q);
+				q = ", ";
+			}
+			printf("\n");
+		}
+		printf("\n\t");
+		for (p = pp->descr; *p; p++) {
+			if (*p == '\n' && p[1] =='\0')
+				break;
+			if (*p == '\n' && p[1] =='\n') {
+				printf("\n\n\t");
+				p++;
+			} else if (*p == '\n') {
+				printf("\n\t");
+			} else if (*p == ':' && p[1] == '\n') {
+				/*
+				 * Start of definition list,
+				 * use RSTs code mode for this
+				 */
+				printf("::\n");
+			} else {
+				printf("%c", *p);
+			}
+		}
+		printf("\n\n");
+	}
+	printf("\n");
+}
diff --git a/bin/varnishd/mgt/mgt_pool.c b/bin/varnishd/mgt/mgt_pool.c
new file mode 100644
index 0000000..978e60a
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_pool.c
@@ -0,0 +1,238 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * We maintain a number of worker thread pools, to spread lock contention.
+ *
+ * Pools can be added on the fly, as a means to mitigate lock contention,
+ * but can only be removed again by a restart. (XXX: we could fix that)
+ *
+ * Two threads herd the pools, one eliminates idle threads and aggregates
+ * statistics for all the pools, the other thread creates new threads
+ * on demand, subject to various numerical constraints.
+ *
+ * The algorithm for when to create threads needs to be reactive enough
+ * to handle startup spikes, but sufficiently attenuated to not cause
+ * thread pileups.  This remains subject for improvement.
+ */
+
+#include "config.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "heritage.h"
+#include "vparam.h"
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_thread_pool_min(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+
+	tweak_generic_uint(cli, &master.wthread_min, arg,
+	    (unsigned)par->min, master.wthread_max);
+}
+
+/*--------------------------------------------------------------------
+ * This is utterly ridiculous:  POSIX does not guarantee that the
+ * minimum thread stack size is a compile time constant.
+ * XXX: "32" is a magic marker for 32bit systems.
+ */
+
+static void
+tweak_stack_size(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+	unsigned low, u;
+	char buf[12];
+
+	low = sysconf(_SC_THREAD_STACK_MIN);
+
+	if (arg != NULL && !strcmp(arg, "32bit")) {
+		u = 65536;
+		if (u < low)
+			u = low;
+		sprintf(buf, "%u", u);
+		arg = buf;
+	}
+
+	tweak_generic_uint(cli, &master.wthread_stacksize, arg,
+	    low, (uint)par->max);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_thread_pool_max(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+
+	(void)par;
+	tweak_generic_uint(cli, &master.wthread_max, arg,
+	    master.wthread_min, UINT_MAX);
+}
+
+/*--------------------------------------------------------------------*/
+
+const struct parspec WRK_parspec[] = {
+	{ "thread_pools", tweak_uint, &master.wthread_pools, 1, UINT_MAX,
+		"Number of worker thread pools.\n"
+		"\n"
+		"Increasing number of worker pools decreases lock "
+		"contention.\n"
+		"\n"
+		"Too many pools waste CPU and RAM resources, and more than "
+		"one pool for each CPU is probably detrimal to performance.\n"
+		"\n"
+		"Can be increased on the fly, but decreases require a "
+		"restart to take effect.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"2", "pools" },
+	{ "thread_pool_max", tweak_thread_pool_max, NULL, 1, 0,
+		"The maximum number of worker threads in each pool.\n"
+		"\n"
+		"Do not set this higher than you have to, since excess "
+		"worker threads soak up RAM and CPU and generally just get "
+		"in the way of getting work done.\n",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"500", "threads" },
+	{ "thread_pool_min", tweak_thread_pool_min, NULL, 2, 0,
+		"The minimum number of worker threads in each pool.\n"
+		"\n"
+		"Increasing this may help ramp up faster from low load "
+		"situations where threads have expired.\n"
+		"\n"
+		"Minimum is 2 threads.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"5", "threads" },
+	{ "thread_pool_timeout", tweak_timeout, &master.wthread_timeout, 1, 0,
+		"Thread idle threshold.\n"
+		"\n"
+		"Threads in excess of thread_pool_min, which have been idle "
+		"for at least this long are candidates for purging.\n"
+		"\n"
+		"Minimum is 1 second.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"300", "seconds" },
+	{ "thread_pool_purge_delay",
+		tweak_timeout, &master.wthread_purge_delay, 100, 0,
+		"Wait this long between purging threads.\n"
+		"\n"
+		"This controls the decay of thread pools when idle(-ish).\n"
+		"\n"
+		"Minimum is 100 milliseconds.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"1000", "milliseconds" },
+	{ "thread_pool_add_threshold",
+		tweak_uint, &master.wthread_add_threshold, 0, UINT_MAX,
+		"Overflow threshold for worker thread creation.\n"
+		"\n"
+		"Setting this too low, will result in excess worker threads, "
+		"which is generally a bad idea.\n"
+		"\n"
+		"Setting it too high results in insuffient worker threads.\n",
+		EXPERIMENTAL,
+		"2", "requests" },
+	{ "thread_pool_add_delay",
+		tweak_timeout, &master.wthread_add_delay, 0, UINT_MAX,
+		"Wait at least this long between creating threads.\n"
+		"\n"
+		"Setting this too long results in insuffient worker threads.\n"
+		"\n"
+		"Setting this too short increases the risk of worker "
+		"thread pile-up.\n",
+		0,
+		"2", "milliseconds" },
+	{ "thread_pool_fail_delay",
+		tweak_timeout, &master.wthread_fail_delay, 100, UINT_MAX,
+		"Wait at least this long after a failed thread creation "
+		"before trying to create another thread.\n"
+		"\n"
+		"Failure to create a worker thread is often a sign that "
+		" the end is near, because the process is running out of "
+		"RAM resources for thread stacks.\n"
+		"This delay tries to not rush it on needlessly.\n"
+		"\n"
+		"If thread creation failures are a problem, check that "
+		"thread_pool_max is not too high.\n"
+		"\n"
+		"It may also help to increase thread_pool_timeout and "
+		"thread_pool_min, to reduce the rate at which treads are "
+		"destroyed and later recreated.\n",
+		EXPERIMENTAL,
+		"200", "milliseconds" },
+	{ "thread_stats_rate",
+		tweak_uint, &master.wthread_stats_rate, 0, UINT_MAX,
+		"Worker threads accumulate statistics, and dump these into "
+		"the global stats counters if the lock is free when they "
+		"finish a request.\n"
+		"This parameters defines the maximum number of requests "
+		"a worker thread may handle, before it is forced to dump "
+		"its accumulated stats into the global counters.\n",
+		EXPERIMENTAL,
+		"10", "requests" },
+	{ "queue_max", tweak_uint, &master.queue_max, 0, UINT_MAX,
+		"Percentage permitted queue length.\n"
+		"\n"
+		"This sets the ratio of queued requests to worker threads, "
+		"above which sessions will be dropped instead of queued.\n",
+		EXPERIMENTAL,
+		"100", "%" },
+	{ "rush_exponent", tweak_uint, &master.rush_exponent, 2, UINT_MAX,
+		"How many parked request we start for each completed "
+		"request on the object.\n"
+		"NB: Even with the implict delay of delivery, "
+		"this parameter controls an exponential increase in "
+		"number of worker threads.",
+		EXPERIMENTAL,
+		"3", "requests per request" },
+	{ "thread_pool_stack",
+		tweak_stack_size, &master.wthread_stacksize, 0, UINT_MAX,
+		"Worker thread stack size.\n"
+		"On 32bit systems you may need to tweak this down to fit "
+		"many threads into the limited address space.\n",
+		EXPERIMENTAL,
+		"-1", "bytes" },
+	{ "thread_pool_workspace", tweak_uint, &master.wthread_workspace,
+		1024, UINT_MAX,
+		"Bytes of HTTP protocol workspace allocated for worker "
+		"threads. "
+		"This space must be big enough for the backend request "
+		"and responses, and response to the client plus any other "
+		"memory needs in the VCL code."
+		"Minimum is 1024 bytes.",
+		DELAYED_EFFECT,
+		"65536",
+		"bytes" },
+	{ NULL, NULL, NULL }
+};
diff --git a/bin/varnishd/mgt/mgt_sandbox.c b/bin/varnishd/mgt/mgt_sandbox.c
new file mode 100644
index 0000000..b01d243
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_sandbox.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Sandboxing child processes
+ *
+ * The worker/manager process border is one of the major security barriers
+ * in Varnish, and therefore subject to whatever restrictions we have access
+ * to under the given operating system.
+ *
+ * Unfortunately there is no consensus on APIs for this purpose, so each
+ * operating system will require its own methods.
+ *
+ * This sourcefile tries to encapsulate the resulting mess on place.
+ *
+ * TODO:
+ *	Unix:	chroot
+ *	FreeBSD: jail
+ *	FreeBSD: capsicum
+ */
+
+#include "config.h"
+
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "heritage.h"
+
+/*--------------------------------------------------------------------*/
+
+/* Waive all privileges in the child, it does not need any */
+
+void
+mgt_sandbox(void)
+{
+#ifdef HAVE_SETPPRIV
+	mgt_sandbox_solaris_init();
+	mgt_sandbox_solaris_privsep();
+#else
+	if (geteuid() == 0) {
+		XXXAZ(setgid(params->gid));
+		XXXAZ(setuid(params->uid));
+	} else {
+		REPORT0(LOG_INFO, "Not running as root, no priv-sep");
+	}
+#endif
+
+	/* On Linux >= 2.4, you need to set the dumpable flag
+	   to get core dumps after you have done a setuid. */
+
+#ifdef __linux__
+	if (prctl(PR_SET_DUMPABLE, 1) != 0)
+		REPORT0(LOG_INFO,
+		    "Could not set dumpable bit.  Core dumps turned off\n");
+#endif
+
+#ifdef HAVE_SETPPRIV
+	mgt_sandbox_solaris_fini();
+#endif
+
+}
diff --git a/bin/varnishd/mgt/mgt_sandbox_solaris.c b/bin/varnishd/mgt/mgt_sandbox_solaris.c
new file mode 100644
index 0000000..715408e
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_sandbox_solaris.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *	   Nils Goroll <nils.goroll at uplex.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Sandboxing child processes on Solaris
+ *
+ */
+
+#include "config.h"
+
+#ifdef HAVE_SETPPRIV
+
+#ifdef HAVE_PRIV_H
+#include <priv.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "heritage.h"
+
+/*--------------------------------------------------------------------
+ * SOLARIS PRIVILEGES: Note on use of symbolic PRIV_* constants
+ * 
+ * For privileges which existed in Solaris 10 FCS, we may use the constants from
+ * sys/priv_names.h
+ *
+ * For privileges which have been added later, we need to use strings in order
+ * not to break builds of varnish on these platforms. To remain binary
+ * compatible, we need to silently ignore errors from priv_addset when using
+ * these strings.
+ *
+ * For optimal build and binary forward comatibility, we could use subtractive
+ * set specs like
+ *
+ *       basic,!file_link_any,!proc_exec,!proc_fork,!proc_info,!proc_session
+ *
+ * but I (Nils) have a preference for making an informed decision about which
+ * privileges the varnish child should have and which it shouldn't.
+ *
+ * Newly introduced privileges should be annotated with their PSARC / commit ID
+ * (as long as Oracle reveils these :/ )
+ *
+ * SOLARIS PRIVILEGES: Note on accidentally setting the SNOCD flag
+ *
+ * When setting privileges, we need to take care not to accidentally set the
+ * SNOCD flag which will disable core dumps unnecessarily. (see
+ * https://www.varnish-cache.org/trac/ticket/671 )
+ *
+ * When changing the logic herein, always check with mdb -k. Replace _PID_ with
+ * the pid of your varnish child, the result should be 0, otherwise a regression
+ * has been introduced.
+ *
+ * > 0t_PID_::pid2proc | ::print proc_t p_flag | >a
+ * > (<a & 0x10000000)=X
+ *                 0
+ *
+ * (a value of 0x10000000 indicates that SNOCD is set)
+ *
+ * NOTE that on Solaris changing the uid will _always_ set SNOCD, so make sure
+ * you run this test with appropriate privileges, but without proc_setid, so
+ * varnish won't setuid(), e.g.
+ *
+ * pfexec ppriv -e -s A=basic,net_privaddr,sys_resource varnish ...
+ *
+ * SOLARIS COREDUMPS with setuid(): See coreadm(1M) - global-setid / proc-setid
+ *
+ */
+
+/* effective during runtime of the child */
+static inline void
+mgt_sandbox_solaris_add_effective(priv_set_t *pset)
+{
+	/* PSARC/2009/685 - 8eca52188202 - onnv_132 */
+	priv_addset(pset, "net_access");
+
+	/* PSARC/2009/378 - 63678502e95e - onnv_140 */
+	priv_addset(pset, "file_read");
+	priv_addset(pset, "file_write");
+}
+
+/* permitted during runtime of the child - for privilege bracketing */
+static inline void
+mgt_sandbox_solaris_add_permitted(priv_set_t *pset)
+{
+	/* for raising limits in cache_waiter_ports.c */
+	priv_addset(pset, PRIV_SYS_RESOURCE);
+}
+
+/* effective during mgt_sandbox */
+static inline void
+mgt_sandbox_solaris_add_initial(priv_set_t *pset)
+{
+	/* for setgid/setuid */
+	priv_addset(pset, PRIV_PROC_SETID);
+}
+
+/*
+ * if we are not yet privilege-aware already (ie we have been started
+ * not-privilege aware wird euid 0), we need to grab any additional privileges
+ * needed during mgt_standbox, until we reduce to least privileges in
+ * mgt_sandbox_waive, otherwise we would loose them with setuid()
+ */
+
+void
+mgt_sandbox_solaris_init(void)
+{
+	priv_set_t *priv_all;
+
+	if (! (priv_all = priv_allocset())) {
+		REPORT(LOG_ERR,
+		    "Child start warning: mgt_sandbox_init - priv_allocset failed: errno=%d (%s)",
+		    errno, strerror(errno));
+		return;
+	}
+	
+	priv_emptyset(priv_all);
+
+	mgt_sandbox_solaris_add_effective(priv_all);
+	mgt_sandbox_solaris_add_permitted(priv_all);
+	mgt_sandbox_solaris_add_initial(priv_all);
+
+	setppriv(PRIV_ON, PRIV_PERMITTED, priv_all);
+	setppriv(PRIV_ON, PRIV_EFFECTIVE, priv_all);
+	setppriv(PRIV_ON, PRIV_INHERITABLE, priv_all);
+
+	priv_freeset(priv_all);
+}
+
+void
+mgt_sandbox_solaris_privsep(void)
+{
+	if (priv_ineffect(PRIV_PROC_SETID)) {
+                if (getgid() != params->gid)
+                        XXXAZ(setgid(params->gid));
+                if (getuid() != params->uid)
+                        XXXAZ(setuid(params->uid));
+        } else {
+                REPORT(LOG_INFO, "Privilege %s missing, will not change uid/gid",
+		    PRIV_PROC_SETID);
+        }
+}
+
+/* 
+ * Waive most privileges in the child
+ *
+ * as of onnv_151a, we should end up with:
+ *
+ * > ppriv -v #pid of varnish child
+ * PID:  .../varnishd ...
+ * flags = PRIV_AWARE
+ *      E: file_read,file_write,net_access
+ *      I: none
+ *      P: file_read,file_write,net_access,sys_resource
+ *      L: file_read,file_write,net_access,sys_resource
+ *
+ * We should keep sys_resource in P in order to adjust our limits if we need to
+ */
+
+void
+mgt_sandbox_solaris_fini(void)
+{
+	priv_set_t *effective, *inheritable, *permitted;
+
+	if (!(effective = priv_allocset()) ||
+	    !(inheritable = priv_allocset()) ||
+	    !(permitted = priv_allocset())) {
+		REPORT(LOG_ERR,
+		    "Child start warning: mgt_sandbox_waive - priv_allocset failed: errno=%d (%s)",
+		    errno, strerror(errno));
+		return;
+	}
+
+	priv_emptyset(inheritable);
+
+	priv_emptyset(effective);
+	mgt_sandbox_solaris_add_effective(effective);
+
+	priv_copyset(effective, permitted);
+	mgt_sandbox_solaris_add_permitted(permitted);
+
+	/* 
+	 * invert the sets and clear privileges such that setppriv will always
+	 * succeed
+	 */
+	priv_inverse(inheritable);
+	priv_inverse(effective);
+	priv_inverse(permitted);
+
+#define SETPPRIV(which, set)						\
+	if (setppriv(PRIV_OFF, which, set))				\
+		REPORT(LOG_ERR,						\
+		    "Child start warning: Waiving privileges failed on %s: errno=%d (%s)", \
+		    #which, errno, strerror(errno));
+
+	SETPPRIV(PRIV_INHERITABLE, inheritable);
+	SETPPRIV(PRIV_EFFECTIVE, effective);
+	SETPPRIV(PRIV_PERMITTED, permitted);
+	SETPPRIV(PRIV_LIMIT, permitted);
+#undef SETPPRIV
+
+	priv_freeset(inheritable);
+	priv_freeset(effective);
+}
+
+#endif /* HAVE_SETPPRIV */
diff --git a/bin/varnishd/mgt/mgt_shmem.c b/bin/varnishd/mgt/mgt_shmem.c
new file mode 100644
index 0000000..630865d
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_shmem.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * TODO:
+ *
+ * There is a risk that the child process might corrupt the VSM segment
+ * and we should capture that event and recover gracefully.
+ *
+ * A possible state diagram could be:
+ *
+ *	[manager start]
+ *		|
+ *		v
+ *      Open old VSM,
+ *	check pid	--------> exit/fail (-n message)
+ *		|
+ *		+<----------------------+
+ *		|			^
+ *		v			|
+ *	Create new VSM			|
+ *		|			|
+ *		v			|
+ *	Init header			|
+ *	Alloc VSL			|
+ *	Alloc VSC:Main			|
+ *	Alloc Args etc.			|
+ *		|			|
+ *		+<--------------+	|
+ *		|		^	|
+ *		v		|	|
+ *	start worker		|	|
+ *		|		|	|
+ *		|		|	+<---- worker crash
+ *		v		|	^
+ *	Reset VSL ptr.		|	|
+ *	Reset VSC counters	|	|
+ *		|		|	|
+ *		+<------+	|	|
+ *		|	^	|	|
+ *		v	|	|	|
+ *	alloc dynamics	|	|	|
+ *	free dynamics	|	|	|
+ *		|	|	|	|
+ *		v	|	|	|
+ *		+------>+	|	|
+ *		|		|	|
+ *		v		|	|
+ *	stop worker		|	|
+ *		|		|	|
+ *		v		|	|
+ *	Check consist---------- | ----->+
+ *		|		|
+ *		v		|
+ *	Free dynamics		|
+ *		|		|
+ *		v		|
+ *		+-------------->+
+ *
+ */
+
+#include "config.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "flopen.h"
+#include "heritage.h"
+#include "vapi/vsc_int.h"
+#include "vapi/vsl_int.h"
+#include "vapi/vsm_int.h"
+#include "vav.h"
+#include "vmb.h"
+#include "vnum.h"
+
+#ifndef MAP_HASSEMAPHORE
+#define MAP_HASSEMAPHORE 0 /* XXX Linux */
+#endif
+
+#ifndef MAP_NOSYNC
+#define MAP_NOSYNC 0 /* XXX Linux */
+#endif
+
+struct VSC_C_main	*VSC_C_main;
+
+static int vsl_fd = -1;
+
+/*--------------------------------------------------------------------
+ * Check that we are not started with the same -n argument as an already
+ * running varnishd
+ */
+
+static void
+vsl_n_check(int fd)
+{
+	struct VSM_head slh;
+	int i;
+	struct stat st;
+	pid_t pid;
+
+	AZ(fstat(fd, &st));
+	if (!S_ISREG(st.st_mode))
+		ARGV_ERR("\tshmlog: Not a file\n");
+
+	/* Test if the SHMFILE is locked by other Varnish */
+	if (fltest(fd, &pid) > 0) {
+		fprintf(stderr,
+			"SHMFILE locked by running varnishd master (pid=%jd)\n",
+			(intmax_t)pid);
+		fprintf(stderr,
+			"(Use unique -n arguments if you want multiple "
+			"instances)\n");
+		exit(2);
+	}
+
+	/* Read owning pid from SHMFILE */
+	memset(&slh, 0, sizeof slh);	/* XXX: for flexelint */
+	i = read(fd, &slh, sizeof slh);
+	if (i != sizeof slh)
+		return;
+	if (slh.magic != VSM_HEAD_MAGIC)
+		return;
+	if (slh.hdrsize != sizeof slh)
+		return;
+	if (slh.master_pid != 0 && !kill(slh.master_pid, 0)) {
+		fprintf(stderr,
+			"WARNING: Taking over SHMFILE marked as owned by "
+			"running process (pid=%jd)\n",
+			(intmax_t)slh.master_pid);
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Build a new shmlog file
+ */
+
+static void
+vsl_buildnew(const char *fn, unsigned size, int fill)
+{
+	struct VSM_head slh;
+	int i;
+	unsigned u;
+	char buf[64*1024];
+	int flags;
+
+	(void)unlink(fn);
+	vsl_fd = flopen(fn, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0644);
+	if (vsl_fd < 0) {
+		fprintf(stderr, "Could not create %s: %s\n",
+		    fn, strerror(errno));
+		exit (1);
+	}
+	flags = fcntl(vsl_fd, F_GETFL);
+	assert(flags != -1);
+	flags &= ~O_NONBLOCK;
+	AZ(fcntl(vsl_fd, F_SETFL, flags));
+
+	memset(&slh, 0, sizeof slh);
+	slh.magic = VSM_HEAD_MAGIC;
+	slh.hdrsize = sizeof slh;
+	slh.shm_size = size;
+	i = write(vsl_fd, &slh, sizeof slh);
+	xxxassert(i == sizeof slh);
+
+	if (fill) {
+		memset(buf, 0, sizeof buf);
+		for (u = sizeof slh; u < size; ) {
+			i = write(vsl_fd, buf, sizeof buf);
+			if (i <= 0) {
+				fprintf(stderr, "Write error %s: %s\n",
+				    fn, strerror(errno));
+				exit (1);
+			}
+			u += i;
+		}
+	}
+
+	AZ(ftruncate(vsl_fd, (off_t)size));
+}
+
+/*--------------------------------------------------------------------
+ * Exit handler that clears the owning pid from the SHMLOG
+ */
+
+static
+void
+mgt_shm_atexit(void)
+{
+	if (getpid() == VSM_head->master_pid)
+		VSM_head->master_pid = 0;
+}
+
+void
+mgt_SHM_Init(const char *l_arg)
+{
+	int i, fill;
+	struct params *pp;
+	const char *q;
+	uintmax_t size, s1, s2, ps;
+	char **av, **ap;
+	uint32_t *vsl_log_start;
+
+	if (l_arg == NULL)
+		l_arg = "";
+
+	av = VAV_Parse(l_arg, NULL, ARGV_COMMA);
+	AN(av);
+	if (av[0] != NULL)
+		ARGV_ERR("\t-l ...: %s", av[0]);
+
+	ap = av + 1;
+
+	/* Size of SHMLOG */
+	if (*ap != NULL && **ap != '\0') {
+		q = VNUM_2bytes(*ap, &s1, 0);
+		if (q != NULL)
+			ARGV_ERR("\t-l[1] ...:  %s\n", q);
+	} else {
+		s1 = 80 * 1024 * 1024;
+	}
+	if (*ap != NULL)
+		ap++;
+
+	/* Size of space for other stuff */
+	if (*ap != NULL && **ap != '\0') {
+		q = VNUM_2bytes(*ap, &s2, 0);
+		if (q != NULL)
+			ARGV_ERR("\t-l[2] ...:  %s\n", q);
+	} else {
+		s2 = 1024 * 1024;
+	}
+	if (*ap != NULL)
+		ap++;
+
+	/* Fill or not ? */
+	if (*ap != NULL) {
+		if (**ap == '\0')
+			fill = 1;
+		else if (!strcmp(*ap, "-"))
+			fill = 0;
+		else if (!strcmp(*ap, "+"))
+			fill = 1;
+		else
+			ARGV_ERR("\t-l[3] ...:  Must be \"-\" or \"+\"\n");
+		ap++;
+	} else {
+		fill = 1;
+	}
+
+	if (*ap != NULL)
+		ARGV_ERR("\t-l ...:  Too many sub-args\n");
+
+	VAV_Free(av);
+
+	size = s1 + s2;
+	ps = getpagesize();
+	size += ps - 1;
+	size &= ~(ps - 1);
+
+	i = open(VSM_FILENAME, O_RDWR, 0644);
+	if (i >= 0) {
+		vsl_n_check(i);
+		(void)close(i);
+	}
+	vsl_buildnew(VSM_FILENAME, size, fill);
+
+	VSM_head = (void *)mmap(NULL, size,
+	    PROT_READ|PROT_WRITE,
+	    MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
+	    vsl_fd, 0);
+	VSM_head->master_pid = getpid();
+	AZ(atexit(mgt_shm_atexit));
+	xxxassert(VSM_head != MAP_FAILED);
+	(void)mlock((void*)VSM_head, size);
+
+	memset(&VSM_head->head, 0, sizeof VSM_head->head);
+	VSM_head->head.magic = VSM_CHUNK_MAGIC;
+	VSM_head->head.len =
+	    (uint8_t*)(VSM_head) + size - (uint8_t*)&VSM_head->head;
+	bprintf(VSM_head->head.class, "%s", VSM_CLASS_FREE);
+	VWMB();
+
+	vsm_end = (void*)((uint8_t*)VSM_head + size);
+
+	VSC_C_main = VSM_Alloc(sizeof *VSC_C_main,
+	    VSC_CLASS, VSC_TYPE_MAIN, "");
+	AN(VSC_C_main);
+
+	pp = VSM_Alloc(sizeof *pp, VSM_CLASS_PARAM, "", "");
+	AN(pp);
+	*pp = *params;
+	params = pp;
+
+	vsl_log_start = VSM_Alloc(s1, VSL_CLASS, "", "");
+	AN(vsl_log_start);
+	vsl_log_start[1] = VSL_ENDMARKER;
+	VWMB();
+
+	do
+		*vsl_log_start = random() & 0xffff;
+	while (*vsl_log_start == 0);
+
+	VWMB();
+
+	do
+		VSM_head->alloc_seq = random();
+	while (VSM_head->alloc_seq == 0);
+
+}
+
+void
+mgt_SHM_Pid(void)
+{
+
+	VSM_head->master_pid = getpid();
+}
diff --git a/bin/varnishd/mgt/mgt_vcc.c b/bin/varnishd/mgt/mgt_vcc.c
new file mode 100644
index 0000000..ec117db
--- /dev/null
+++ b/bin/varnishd/mgt/mgt_vcc.c
@@ -0,0 +1,676 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * VCL compiler stuff
+ */
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mgt/mgt.h"
+
+#include "libvcl.h"
+#include "vcl.h"
+#include "vcli.h"
+#include "vcli_priv.h"
+#include "vfil.h"
+#include "vsub.h"
+
+#include "mgt_cli.h"
+
+struct vclprog {
+	VTAILQ_ENTRY(vclprog)	list;
+	char			*name;
+	char			*fname;
+	int			active;
+};
+
+static VTAILQ_HEAD(, vclprog) vclhead = VTAILQ_HEAD_INITIALIZER(vclhead);
+
+char *mgt_cc_cmd;
+const char *mgt_vcl_dir;
+const char *mgt_vmod_dir;
+unsigned mgt_vcc_err_unref;
+
+static struct vcc *vcc;
+
+/*--------------------------------------------------------------------*/
+
+static const char * const default_vcl =
+#include "default_vcl.h"
+    ""	;
+
+/*--------------------------------------------------------------------
+ * Prepare the compiler command line
+ */
+static struct vsb *
+mgt_make_cc_cmd(const char *sf, const char *of)
+{
+	struct vsb *sb;
+	int pct;
+	char *p;
+
+	sb = VSB_new_auto();
+	XXXAN(sb);
+	for (p = mgt_cc_cmd, pct = 0; *p; ++p) {
+		if (pct) {
+			switch (*p) {
+			case 's':
+				VSB_cat(sb, sf);
+				break;
+			case 'o':
+				VSB_cat(sb, of);
+				break;
+			case '%':
+				VSB_putc(sb, '%');
+				break;
+			default:
+				VSB_putc(sb, '%');
+				VSB_putc(sb, *p);
+				break;
+			}
+			pct = 0;
+		} else if (*p == '%') {
+			pct = 1;
+		} else {
+			VSB_putc(sb, *p);
+		}
+	}
+	if (pct)
+		VSB_putc(sb, '%');
+	AZ(VSB_finish(sb));
+	return (sb);
+}
+
+/*--------------------------------------------------------------------
+ * Invoke system VCC compiler in a sub-process
+ */
+
+struct vcc_priv {
+	unsigned	magic;
+#define VCC_PRIV_MAGIC	0x70080cb8
+	char		*sf;
+	const char	*vcl;
+};
+
+static void
+run_vcc(void *priv)
+{
+	char *csrc;
+	struct vsb *sb;
+	struct vcc_priv *vp;
+	int fd, i, l;
+
+	CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
+	sb = VSB_new_auto();
+	XXXAN(sb);
+	VCC_VCL_dir(vcc, mgt_vcl_dir);
+	VCC_VMOD_dir(vcc, mgt_vmod_dir);
+	VCC_Err_Unref(vcc, mgt_vcc_err_unref);
+	csrc = VCC_Compile(vcc, sb, vp->vcl);
+	AZ(VSB_finish(sb));
+	if (VSB_len(sb))
+		printf("%s", VSB_data(sb));
+	VSB_delete(sb);
+	if (csrc == NULL)
+		exit (1);
+
+	fd = open(vp->sf, O_WRONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open %s", vp->sf);
+		exit (1);
+	}
+	l = strlen(csrc);
+	i = write(fd, csrc, l);
+	if (i != l) {
+		fprintf(stderr, "Cannot write %s", vp->sf);
+		exit (1);
+	}
+	AZ(close(fd));
+	free(csrc);
+	exit (0);
+}
+
+/*--------------------------------------------------------------------
+ * Invoke system C compiler in a sub-process
+ */
+
+static void
+run_cc(void *priv)
+{
+	(void)execl("/bin/sh", "/bin/sh", "-c", priv, NULL);
+}
+
+/*--------------------------------------------------------------------
+ * Attempt to open compiled VCL in a sub-process
+ */
+
+static void __match_proto__(sub_func_f)
+run_dlopen(void *priv)
+{
+	const char *of;
+	void *dlh;
+	struct VCL_conf const *cnf;
+
+	of = priv;
+
+	/* Try to load the object into the management process */
+	if ((dlh = dlopen(of, RTLD_NOW | RTLD_LOCAL)) == NULL) {
+		fprintf(stderr,
+		    "Compiled VCL program failed to load:\n  %s\n",
+		    dlerror());
+		exit(1);
+	}
+
+	cnf = dlsym(dlh, "VCL_conf");
+	if (cnf == NULL) {
+		fprintf(stderr, "Compiled VCL program, metadata not found\n");
+		exit(1);
+	}
+
+	if (cnf->magic != VCL_CONF_MAGIC) {
+		fprintf(stderr, "Compiled VCL program, mangled metadata\n");
+		exit(1);
+	}
+
+	if (dlclose(dlh)) {
+		fprintf(stderr,
+		    "Compiled VCL program failed to unload:\n  %s\n",
+		    dlerror());
+		exit(1);
+	}
+	exit(0);
+}
+
+/*--------------------------------------------------------------------
+ * Compile a VCL program, return shared object, errors in sb.
+ */
+
+static char *
+mgt_run_cc(const char *vcl, struct vsb *sb, int C_flag)
+{
+	char *csrc;
+	struct vsb *cmdsb;
+	char sf[] = "./vcl.########.c";
+	char of[sizeof sf + 1];
+	char *retval;
+	int sfd, i;
+	struct vcc_priv vp;
+
+	/* Create temporary C source file */
+	sfd = VFIL_tmpfile(sf);
+	if (sfd < 0) {
+		VSB_printf(sb, "Failed to create %s: %s", sf, strerror(errno));
+		return (NULL);
+	}
+	AZ(close(sfd));
+
+	/* Run the VCC compiler in a sub-process */
+	memset(&vp, 0, sizeof vp);
+	vp.magic = VCC_PRIV_MAGIC;
+	vp.sf = sf;
+	vp.vcl = vcl;
+	if (VSUB_run(sb, run_vcc, &vp, "VCC-compiler", -1)) {
+		(void)unlink(sf);
+		return (NULL);
+	}
+
+	if (C_flag) {
+		csrc = VFIL_readfile(NULL, sf, NULL);
+		XXXAN(csrc);
+		(void)fputs(csrc, stdout);
+		free(csrc);
+	}
+
+	/* Name the output shared library by "s/[.]c$/[.]so/" */
+	memcpy(of, sf, sizeof sf);
+	assert(sf[sizeof sf - 2] == 'c');
+	of[sizeof sf - 2] = 's';
+	of[sizeof sf - 1] = 'o';
+	of[sizeof sf] = '\0';
+
+	/* Build the C-compiler command line */
+	cmdsb = mgt_make_cc_cmd(sf, of);
+
+	/* Run the C-compiler in a sub-shell */
+	i = VSUB_run(sb, run_cc, VSB_data(cmdsb), "C-compiler", 10);
+
+	(void)unlink(sf);
+	VSB_delete(cmdsb);
+
+	if (!i)
+		i = VSUB_run(sb, run_dlopen, of, "dlopen", 10);
+
+	if (i) {
+		(void)unlink(of);
+		return (NULL);
+	}
+
+	retval = strdup(of);
+	XXXAN(retval);
+	return (retval);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+mgt_VccCompile(struct vsb **sb, const char *b, int C_flag)
+{
+	char *vf;
+
+	*sb = VSB_new_auto();
+	XXXAN(*sb);
+	vf = mgt_run_cc(b, *sb, C_flag);
+	AZ(VSB_finish(*sb));
+	return (vf);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct vclprog *
+mgt_vcc_add(const char *name, char *file)
+{
+	struct vclprog *vp;
+
+	vp = calloc(sizeof *vp, 1);
+	XXXAN(vp);
+	vp->name = strdup(name);
+	XXXAN(vp->name);
+	vp->fname = file;
+	VTAILQ_INSERT_TAIL(&vclhead, vp, list);
+	return (vp);
+}
+
+static void
+mgt_vcc_del(struct vclprog *vp)
+{
+	VTAILQ_REMOVE(&vclhead, vp, list);
+	printf("unlink %s\n", vp->fname);
+	XXXAZ(unlink(vp->fname));
+	free(vp->fname);
+	free(vp->name);
+	free(vp);
+}
+
+static struct vclprog *
+mgt_vcc_byname(const char *name)
+{
+	struct vclprog *vp;
+
+	VTAILQ_FOREACH(vp, &vclhead, list)
+		if (!strcmp(name, vp->name))
+			return (vp);
+	return (NULL);
+}
+
+
+static int
+mgt_vcc_delbyname(const char *name)
+{
+	struct vclprog *vp;
+
+	vp = mgt_vcc_byname(name);
+	if (vp != NULL) {
+		mgt_vcc_del(vp);
+		return (0);
+	}
+	return (1);
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+mgt_vcc_default(const char *b_arg, const char *f_arg, char *vcl, int C_flag)
+{
+	char *vf;
+	struct vsb *sb;
+	struct vclprog *vp;
+	char buf[BUFSIZ];
+
+	/* XXX: annotate vcl with -b/-f arg so people know where it came from */
+	(void)f_arg;
+
+	if (b_arg != NULL) {
+		AZ(vcl);
+		/*
+		 * XXX: should do a "HEAD /" on the -b argument to see that
+		 * XXX: it even works.  On the other hand, we should do that
+		 * XXX: for all backends in the cache process whenever we
+		 * XXX: change config, but for a complex VCL, it might not be
+		 * XXX: a bug for a backend to not reply at that time, so then
+		 * XXX: again: we should check it here in the "trivial" case.
+		 */
+		bprintf(buf,
+		    "backend default {\n"
+		    "    .host = \"%s\";\n"
+		    "}\n", b_arg);
+		vcl = strdup(buf);
+		AN(vcl);
+	}
+	strcpy(buf, "boot");
+
+	vf = mgt_VccCompile(&sb, vcl, C_flag);
+	free(vcl);
+	if (VSB_len(sb) > 0)
+		fprintf(stderr, "%s", VSB_data(sb));
+	VSB_delete(sb);
+	if (C_flag) {
+		if (vf != NULL)
+			AZ(unlink(vf));
+		return (0);
+	}
+	if (vf == NULL) {
+		fprintf(stderr, "\nVCL compilation failed\n");
+		return (1);
+	}
+	vp = mgt_vcc_add(buf, vf);
+	vp->active = 1;
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+mgt_has_vcl()
+{
+
+	return (!VTAILQ_EMPTY(&vclhead));
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+mgt_push_vcls_and_start(unsigned *status, char **p)
+{
+	struct vclprog *vp;
+
+	VTAILQ_FOREACH(vp, &vclhead, list) {
+		if (mgt_cli_askchild(status, p,
+		    "vcl.load \"%s\" %s\n", vp->name, vp->fname))
+			return (1);
+		free(*p);
+		if (!vp->active)
+			continue;
+		if (mgt_cli_askchild(status, p,
+		    "vcl.use \"%s\"\n", vp->name))
+			return (1);
+		free(*p);
+	}
+	if (mgt_cli_askchild(status, p, "start\n"))
+		return (1);
+	free(*p);
+	*p = NULL;
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static
+void
+mgt_vcc_atexit(void)
+{
+	struct vclprog *vp;
+
+	if (getpid() != mgt_pid)
+		return;
+	while (1) {
+		vp = VTAILQ_FIRST(&vclhead);
+		if (vp == NULL)
+			break;
+		(void)unlink(vp->fname);
+		VTAILQ_REMOVE(&vclhead, vp, list);
+	}
+}
+
+void
+mgt_vcc_init(void)
+{
+
+	vcc = VCC_New();
+	AN(vcc);
+	VCC_Default_VCL(vcc, default_vcl);
+	AZ(atexit(mgt_vcc_atexit));
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mcf_config_inline(struct cli *cli, const char * const *av, void *priv)
+{
+	char *vf, *p = NULL;
+	struct vsb *sb;
+	unsigned status;
+	struct vclprog *vp;
+
+	(void)priv;
+
+	vp = mgt_vcc_byname(av[2]);
+	if (vp != NULL) {
+		VCLI_Out(cli, "Already a VCL program named %s", av[2]);
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+
+	vf = mgt_VccCompile(&sb, av[3], 0);
+	if (VSB_len(sb) > 0)
+		VCLI_Out(cli, "%s\n", VSB_data(sb));
+	VSB_delete(sb);
+	if (vf == NULL) {
+		VCLI_Out(cli, "VCL compilation failed");
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+	VCLI_Out(cli, "VCL compiled.");
+	if (child_pid >= 0 &&
+	    mgt_cli_askchild(&status, &p, "vcl.load %s %s\n", av[2], vf)) {
+		VCLI_SetResult(cli, status);
+		VCLI_Out(cli, "%s", p);
+	} else {
+		(void)mgt_vcc_add(av[2], vf);
+	}
+	free(p);
+}
+
+void
+mcf_config_load(struct cli *cli, const char * const *av, void *priv)
+{
+	char *vf, *vcl;
+	struct vsb *sb;
+	unsigned status;
+	char *p = NULL;
+	struct vclprog *vp;
+
+	(void)priv;
+	vp = mgt_vcc_byname(av[2]);
+	if (vp != NULL) {
+		VCLI_Out(cli, "Already a VCL program named %s", av[2]);
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+
+	vcl = VFIL_readfile(mgt_vcl_dir, av[3], NULL);
+	if (vcl == NULL) {
+		VCLI_Out(cli, "Cannot open '%s'", av[3]);
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+
+	vf = mgt_VccCompile(&sb, vcl, 0);
+	free(vcl);
+
+	if (VSB_len(sb) > 0)
+		VCLI_Out(cli, "%s", VSB_data(sb));
+	VSB_delete(sb);
+	if (vf == NULL) {
+		VCLI_Out(cli, "VCL compilation failed");
+		VCLI_SetResult(cli, CLIS_PARAM);
+		return;
+	}
+	VCLI_Out(cli, "VCL compiled.");
+	if (child_pid >= 0 &&
+	    mgt_cli_askchild(&status, &p, "vcl.load %s %s\n", av[2], vf)) {
+		VCLI_SetResult(cli, status);
+		VCLI_Out(cli, "%s", p);
+	} else {
+		(void)mgt_vcc_add(av[2], vf);
+	}
+	free(p);
+}
+
+static struct vclprog *
+mcf_find_vcl(struct cli *cli, const char *name)
+{
+	struct vclprog *vp;
+
+	vp = mgt_vcc_byname(name);
+	if (vp != NULL)
+		return (vp);
+	VCLI_SetResult(cli, CLIS_PARAM);
+	VCLI_Out(cli, "No configuration named %s known.", name);
+	return (NULL);
+}
+
+void
+mcf_config_use(struct cli *cli, const char * const *av, void *priv)
+{
+	unsigned status;
+	char *p = NULL;
+	struct vclprog *vp;
+
+	(void)priv;
+	vp = mcf_find_vcl(cli, av[2]);
+	if (vp == NULL)
+		return;
+	if (vp->active != 0)
+		return;
+	if (child_pid >= 0 &&
+	    mgt_cli_askchild(&status, &p, "vcl.use %s\n", av[2])) {
+		VCLI_SetResult(cli, status);
+		VCLI_Out(cli, "%s", p);
+	} else {
+		vp->active = 2;
+		VTAILQ_FOREACH(vp, &vclhead, list) {
+			if (vp->active == 1)
+				vp->active = 0;
+			else if (vp->active == 2)
+				vp->active = 1;
+		}
+	}
+	free(p);
+}
+
+void
+mcf_config_discard(struct cli *cli, const char * const *av, void *priv)
+{
+	unsigned status;
+	char *p = NULL;
+	struct vclprog *vp;
+
+	(void)priv;
+	vp = mcf_find_vcl(cli, av[2]);
+	if (vp != NULL && vp->active) {
+		VCLI_SetResult(cli, CLIS_PARAM);
+		VCLI_Out(cli, "Cannot discard active VCL program\n");
+	} else if (vp != NULL) {
+		if (child_pid >= 0 &&
+		    mgt_cli_askchild(&status, &p,
+		    "vcl.discard %s\n", av[2])) {
+			VCLI_SetResult(cli, status);
+			VCLI_Out(cli, "%s", p);
+		} else {
+			AZ(mgt_vcc_delbyname(av[2]));
+		}
+	}
+	free(p);
+}
+
+void
+mcf_config_list(struct cli *cli, const char * const *av, void *priv)
+{
+	unsigned status;
+	char *p;
+	const char *flg;
+	struct vclprog *vp;
+
+	(void)av;
+	(void)priv;
+	if (child_pid >= 0) {
+		if (!mgt_cli_askchild(&status, &p, "vcl.list\n")) {
+			VCLI_SetResult(cli, status);
+			VCLI_Out(cli, "%s", p);
+		}
+		free(p);
+	} else {
+		VTAILQ_FOREACH(vp, &vclhead, list) {
+			if (vp->active) {
+				flg = "active";
+			} else
+				flg = "available";
+			VCLI_Out(cli, "%-10s %6s %s\n",
+			    flg, "N/A", vp->name);
+		}
+	}
+}
+
+/*
+ * XXX: This should take an option argument to show all (include) files
+ * XXX: This violates the principle of not loading VCL's in the master
+ * XXX: process.
+ */
+void
+mcf_config_show(struct cli *cli, const char * const *av, void *priv)
+{
+	struct vclprog *vp;
+	void *dlh, *sym;
+	const char **src;
+
+	(void)priv;
+	if ((vp = mcf_find_vcl(cli, av[2])) != NULL) {
+		if ((dlh = dlopen(vp->fname, RTLD_NOW | RTLD_LOCAL)) == NULL) {
+			VCLI_Out(cli, "failed to load %s: %s\n",
+			    vp->name, dlerror());
+			VCLI_SetResult(cli, CLIS_CANT);
+		} else if ((sym = dlsym(dlh, "srcbody")) == NULL) {
+			VCLI_Out(cli, "failed to locate source for %s: %s\n",
+			    vp->name, dlerror());
+			VCLI_SetResult(cli, CLIS_CANT);
+			AZ(dlclose(dlh));
+		} else {
+			src = sym;
+			VCLI_Out(cli, "%s", src[0]);
+			/* VCLI_Out(cli, src[1]); */
+			AZ(dlclose(dlh));
+		}
+	}
+}
diff --git a/bin/varnishd/mgt_child.c b/bin/varnishd/mgt_child.c
deleted file mode 100644
index 2108230..0000000
--- a/bin/varnishd/mgt_child.c
+++ /dev/null
@@ -1,673 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The mechanics of handling the child process
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "heritage.h"
-#include "vapi/vsm_int.h"
-#include "vbm.h"
-#include "vcli.h"
-#include "vcli_priv.h"
-#include "vev.h"
-#include "vlu.h"
-#include "vss.h"
-#include "vtcp.h"
-#include "vtim.h"
-
-#include "mgt_cli.h"
-
-pid_t		child_pid = -1;
-
-
-static struct vbitmap	*fd_map;
-
-static int		child_cli_in = -1;
-static int		child_VCLI_Out = -1;
-static int		child_output = -1;
-
-static enum {
-	CH_STOPPED = 0,
-	CH_STARTING = 1,
-	CH_RUNNING = 2,
-	CH_STOPPING = 3,
-	CH_DIED = 4
-}			child_state = CH_STOPPED;
-
-static const char * const ch_state[] = {
-	[CH_STOPPED] =	"stopped",
-	[CH_STARTING] =	"starting",
-	[CH_RUNNING] =	"running",
-	[CH_STOPPING] =	"stopping",
-	[CH_DIED] =	"died, (restarting)",
-};
-
-static struct vev	*ev_poker;
-static struct vev	*ev_listen;
-static struct vlu	*vlu;
-
-static struct vsb *child_panic = NULL;
-
-/*--------------------------------------------------------------------
- * Track the highest file descriptor the parent knows is being used.
- *
- * This allows the child process to clean/close only a small fraction
- * of the possible file descriptors after exec(2).
- *
- * This is likely to a bit on the low side, as libc and other libraries
- * has a tendency to cache file descriptors (syslog, resolver, etc.)
- * so we add a margin of 100 fds.
- */
-
-static int		mgt_max_fd;
-
-#define CLOSE_FD_UP_TO	(mgt_max_fd + 100)
-
-void
-mgt_got_fd(int fd)
-{
-	/*
-	 * Assert > 0, to catch bogus opens, we know where stdin goes
-	 * in the master process.
-	 */
-	assert(fd > 0);
-	if (fd > mgt_max_fd)
-		mgt_max_fd = fd;
-}
-
-/*--------------------------------------------------------------------
- * A handy little function
- */
-
-static inline void
-closex(int *fd)
-{
-
-	assert(*fd >= 0);
-	AZ(close(*fd));
-	*fd = -1;
-}
-
-/*--------------------------------------------------------------------
- * Keep track of which filedescriptors the child should inherit and
- * which should be closed after fork()
- */
-
-void
-mgt_child_inherit(int fd, const char *what)
-{
-
-	assert(fd >= 0);
-	if (fd_map == NULL)
-		fd_map = vbit_init(128);
-	AN(fd_map);
-	if (what != NULL)
-		vbit_set(fd_map, fd);
-	else
-		vbit_clr(fd_map, fd);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-child_line(void *priv, const char *p)
-{
-	(void)priv;
-
-	REPORT(LOG_NOTICE, "Child (%jd) said %s", (intmax_t)child_pid, p);
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-child_listener(const struct vev *e, int what)
-{
-
-	(void)e;
-	if ((what & ~EV_RD)) {
-		ev_listen = NULL;
-		return (1);
-	}
-	if (VLU_Fd(child_output, vlu)) {
-		ev_listen = NULL;
-		return (1);
-	}
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-child_poker(const struct vev *e, int what)
-{
-
-	(void)e;
-	(void)what;
-	if (child_state != CH_RUNNING)
-		return (1);
-	if (child_pid < 0)
-		return (0);
-	if (!mgt_cli_askchild(NULL, NULL, "ping\n"))
-		return (0);
-	return (0);
-}
-
-/*--------------------------------------------------------------------
- * If CLI communications with the child process fails, there is nothing
- * for us to do but to drag it behind the barn and get it over with.
- *
- * The typical case is where the child process fails to return a reply
- * before the cli_timeout expires.  This invalidates the CLI pipes for
- * all future use, as we don't know if the child was just slow and the
- * result gets piped later on, or if the child is catatonic.
- */
-
-void
-MGT_Child_Cli_Fail(void)
-{
-
-	if (child_state != CH_RUNNING)
-		return;
-	if (child_pid < 0)
-		return;
-	REPORT(LOG_ERR, "Child (%jd) not responding to CLI, killing it.",
-	    (intmax_t)child_pid);
-	if (params->diag_bitmap & 0x1000)
-		(void)kill(child_pid, SIGKILL);
-	else
-		(void)kill(child_pid, SIGQUIT);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-open_sockets(void)
-{
-	struct listen_sock *ls, *ls2;
-	int good = 0;
-
-	VTAILQ_FOREACH_SAFE(ls, &heritage.socks, list, ls2) {
-		if (ls->sock >= 0) {
-			good++;
-			continue;
-		}
-		ls->sock = VSS_bind(ls->addr);
-		if (ls->sock < 0)
-			continue;
-
-		mgt_child_inherit(ls->sock, "sock");
-
-		/*
-		 * Set nonblocking mode to avoid a race where a client
-		 * closes before we call accept(2) and nobody else are in
-		 * the listen queue to release us.
-		 */
-		(void)VTCP_filter_http(ls->sock);
-		good++;
-	}
-	if (!good)
-		return (1);
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-close_sockets(void)
-{
-	struct listen_sock *ls;
-
-	VTAILQ_FOREACH(ls, &heritage.socks, list) {
-		if (ls->sock < 0)
-			continue;
-		mgt_child_inherit(ls->sock, NULL);
-		closex(&ls->sock);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-start_child(struct cli *cli)
-{
-	pid_t pid;
-	unsigned u;
-	char *p;
-	struct vev *e;
-	int i, cp[2];
-
-	if (child_state != CH_STOPPED && child_state != CH_DIED)
-		return;
-
-	if (open_sockets() != 0) {
-		child_state = CH_STOPPED;
-		if (cli != NULL) {
-			VCLI_SetResult(cli, CLIS_CANT);
-			VCLI_Out(cli, "Could not open sockets");
-			return;
-		}
-		REPORT0(LOG_ERR,
-		    "Child start failed: could not open sockets");
-		return;
-	}
-
-	child_state = CH_STARTING;
-
-	/* Open pipe for mgr->child CLI */
-	AZ(pipe(cp));
-	heritage.cli_in = cp[0];
-	mgt_child_inherit(heritage.cli_in, "cli_in");
-	child_VCLI_Out = cp[1];
-
-	/* Open pipe for child->mgr CLI */
-	AZ(pipe(cp));
-	heritage.VCLI_Out = cp[1];
-	mgt_child_inherit(heritage.VCLI_Out, "VCLI_Out");
-	child_cli_in = cp[0];
-
-	/*
-	 * Open pipe for child stdout/err
-	 * NB: not inherited, because we dup2() it to stdout/stderr in child
-	 */
-	AZ(pipe(cp));
-	heritage.std_fd = cp[1];
-	child_output = cp[0];
-
-	MCF_ParamSync();
-	if ((pid = fork()) < 0) {
-		perror("Could not fork child");
-		exit(1);
-	}
-	if (pid == 0) {
-
-		/* Redirect stdin/out/err */
-		AZ(close(STDIN_FILENO));
-		assert(open("/dev/null", O_RDONLY) == STDIN_FILENO);
-		assert(dup2(heritage.std_fd, STDOUT_FILENO) == STDOUT_FILENO);
-		assert(dup2(heritage.std_fd, STDERR_FILENO) == STDERR_FILENO);
-
-		/* Close anything we shouldn't know about */
-		closelog();
-		for (i = STDERR_FILENO + 1; i < CLOSE_FD_UP_TO; i++) {
-			if (vbit_test(fd_map, i))
-				continue;
-			(void)(close(i) == 0);
-		}
-#ifdef HAVE_SETPROCTITLE
-		setproctitle("Varnish-Chld %s", heritage.name);
-#endif
-
-		(void)signal(SIGINT, SIG_DFL);
-		(void)signal(SIGTERM, SIG_DFL);
-
-		mgt_sandbox();
-
-		child_main();
-
-		exit(1);
-	}
-	REPORT(LOG_NOTICE, "child (%jd) Started", (intmax_t)pid);
-
-	/* Close stuff the child got */
-	closex(&heritage.std_fd);
-
-	mgt_child_inherit(heritage.cli_in, NULL);
-	closex(&heritage.cli_in);
-
-	mgt_child_inherit(heritage.VCLI_Out, NULL);
-	closex(&heritage.VCLI_Out);
-
-	close_sockets();
-
-	vlu = VLU_New(NULL, child_line, 0);
-	AN(vlu);
-
-	AZ(ev_listen);
-	e = vev_new();
-	XXXAN(e);
-	e->fd = child_output;
-	e->fd_flags = EV_RD;
-	e->name = "Child listener";
-	e->callback = child_listener;
-	AZ(vev_add(mgt_evb, e));
-	ev_listen = e;
-	AZ(ev_poker);
-	if (params->ping_interval > 0) {
-		e = vev_new();
-		XXXAN(e);
-		e->timeout = params->ping_interval;
-		e->callback = child_poker;
-		e->name = "child poker";
-		AZ(vev_add(mgt_evb, e));
-		ev_poker = e;
-	}
-
-	mgt_cli_start_child(child_cli_in, child_VCLI_Out);
-	child_pid = pid;
-	if (mgt_push_vcls_and_start(&u, &p)) {
-		REPORT(LOG_ERR, "Pushing vcls failed:\n%s", p);
-		free(p);
-		child_state = CH_RUNNING;
-		mgt_stop_child();
-	} else
-		child_state = CH_RUNNING;
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mgt_stop_child(void)
-{
-
-	if (child_state != CH_RUNNING)
-		return;
-
-	child_state = CH_STOPPING;
-
-	REPORT0(LOG_DEBUG, "Stopping Child");
-	if (ev_poker != NULL) {
-		vev_del(mgt_evb, ev_poker);
-		free(ev_poker);
-	}
-	ev_poker = NULL;
-
-	mgt_cli_stop_child();
-
-	/* We tell the child to die gracefully by closing the CLI */
-	closex(&child_VCLI_Out);
-	closex(&child_cli_in);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-mgt_report_panic(pid_t r)
-{
-
-	if (VSM_head->panicstr[0] == '\0')
-		return;
-	REPORT(LOG_ERR, "Child (%jd) Panic message: %s",
-	    (intmax_t)r, VSM_head->panicstr);
-}
-
-static void
-mgt_save_panic(void)
-{
-	char time_str[30];
-	if (VSM_head->panicstr[0] == '\0')
-		return;
-
-	if (child_panic)
-		VSB_delete(child_panic);
-	child_panic = VSB_new_auto();
-	XXXAN(child_panic);
-	VTIM_format(VTIM_real(), time_str);
-	VSB_printf(child_panic, "Last panic at: %s\n", time_str);
-	VSB_cat(child_panic, VSM_head->panicstr);
-	AZ(VSB_finish(child_panic));
-}
-
-static void
-mgt_clear_panic(void)
-{
-	VSB_delete(child_panic);
-	child_panic = NULL;
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-mgt_sigchld(const struct vev *e, int what)
-{
-	int status;
-	struct vsb *vsb;
-	pid_t r;
-
-	(void)e;
-	(void)what;
-
-	if (ev_poker != NULL) {
-		vev_del(mgt_evb, ev_poker);
-		free(ev_poker);
-	}
-	ev_poker = NULL;
-
-	r = waitpid(child_pid, &status, WNOHANG);
-	if (r == 0 || (r == -1 && errno == ECHILD))
-		return (0);
-	assert(r == child_pid);
-	vsb = VSB_new_auto();
-	XXXAN(vsb);
-	VSB_printf(vsb, "Child (%d) %s", r, status ? "died" : "ended");
-	if (WIFEXITED(status) && WEXITSTATUS(status)) {
-		VSB_printf(vsb, " status=%d", WEXITSTATUS(status));
-		exit_status |= 0x20;
-	}
-	if (WIFSIGNALED(status)) {
-		VSB_printf(vsb, " signal=%d", WTERMSIG(status));
-		exit_status |= 0x40;
-	}
-#ifdef WCOREDUMP
-	if (WCOREDUMP(status)) {
-		VSB_printf(vsb, " (core dumped)");
-		exit_status |= 0x80;
-	}
-#endif
-	AZ(VSB_finish(vsb));
-	REPORT(LOG_INFO, "%s", VSB_data(vsb));
-	VSB_delete(vsb);
-
-	mgt_report_panic(r);
-	mgt_save_panic();
-
-	child_pid = -1;
-
-	if (child_state == CH_RUNNING) {
-		child_state = CH_DIED;
-		mgt_cli_stop_child();
-		closex(&child_VCLI_Out);
-		closex(&child_cli_in);
-	}
-
-	if (ev_listen != NULL) {
-		vev_del(mgt_evb, ev_listen);
-		free(ev_listen);
-		ev_listen = NULL;
-	}
-	/* Pick up any stuff lingering on stdout/stderr */
-	(void)child_listener(NULL, EV_RD);
-	closex(&child_output);
-
-	REPORT0(LOG_DEBUG, "Child cleanup complete");
-
-	if (child_state == CH_DIED && params->auto_restart)
-		start_child(NULL);
-	else if (child_state == CH_DIED) {
-		child_state = CH_STOPPED;
-	} else if (child_state == CH_STOPPING)
-		child_state = CH_STOPPED;
-
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-mgt_sigint(const struct vev *e, int what)
-{
-
-	(void)e;
-	(void)what;
-	REPORT0(LOG_ERR, "Manager got SIGINT");
-	(void)fflush(stdout);
-	if (child_pid >= 0)
-		mgt_stop_child();
-	exit (2);
-}
-
-/*--------------------------------------------------------------------
- * This thread is the master thread in the management process.
- * The relatively simple task is to start and stop the child process
- * and to reincarnate it in case of trouble.
- */
-
-void
-MGT_Run(void)
-{
-	struct sigaction sac;
-	struct vev *e;
-	int i;
-
-	e = vev_new();
-	XXXAN(e);
-	e->sig = SIGTERM;
-	e->callback = mgt_sigint;
-	e->name = "mgt_sigterm";
-	AZ(vev_add(mgt_evb, e));
-
-	e = vev_new();
-	XXXAN(e);
-	e->sig = SIGINT;
-	e->callback = mgt_sigint;
-	e->name = "mgt_sigint";
-	AZ(vev_add(mgt_evb, e));
-
-	e = vev_new();
-	XXXAN(e);
-	e->sig = SIGCHLD;
-	e->sig_flags = SA_NOCLDSTOP;
-	e->callback = mgt_sigchld;
-	e->name = "mgt_sigchild";
-	AZ(vev_add(mgt_evb, e));
-
-#ifdef HAVE_SETPROCTITLE
-	setproctitle("Varnish-Mgr %s", heritage.name);
-#endif
-
-	memset(&sac, 0, sizeof sac);
-	sac.sa_handler = SIG_IGN;
-	sac.sa_flags = SA_RESTART;
-
-	AZ(sigaction(SIGPIPE, &sac, NULL));
-	AZ(sigaction(SIGHUP, &sac, NULL));
-
-	if (!d_flag && !mgt_has_vcl())
-		REPORT0(LOG_ERR, "No VCL loaded yet");
-	else if (!d_flag) {
-		start_child(NULL);
-		if (child_state == CH_STOPPED) {
-			exit_status = 2;
-			return;
-		}
-	}
-
-	i = vev_schedule(mgt_evb);
-	if (i != 0)
-		REPORT(LOG_ERR, "vev_schedule() = %d", i);
-
-	REPORT0(LOG_ERR, "manager dies");
-}
-
-/*--------------------------------------------------------------------*/
-
-void __match_proto__(cli_func_t)
-mcf_server_startstop(struct cli *cli, const char * const *av, void *priv)
-{
-
-	(void)av;
-	if (priv != NULL && child_state == CH_RUNNING)
-		mgt_stop_child();
-	else if (priv == NULL && child_state == CH_STOPPED) {
-		if (mgt_has_vcl()) {
-			start_child(cli);
-		} else {
-			VCLI_SetResult(cli, CLIS_CANT);
-			VCLI_Out(cli, "No VCL available");
-		}
-	} else {
-		VCLI_SetResult(cli, CLIS_CANT);
-		VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mcf_server_status(struct cli *cli, const char * const *av, void *priv)
-{
-	(void)av;
-	(void)priv;
-	VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
-}
-
-void
-mcf_panic_show(struct cli *cli, const char * const *av, void *priv)
-{
-	(void)av;
-	(void)priv;
-
-	if (!child_panic) {
-	  VCLI_SetResult(cli, CLIS_CANT);
-	  VCLI_Out(cli, "Child has not panicked or panic has been cleared");
-	  return;
-	}
-
-	VCLI_Out(cli, "%s\n", VSB_data(child_panic));
-}
-
-void
-mcf_panic_clear(struct cli *cli, const char * const *av, void *priv)
-{
-	(void)av;
-	(void)priv;
-
-	if (!child_panic) {
-	  VCLI_SetResult(cli, CLIS_CANT);
-	  VCLI_Out(cli, "No panic to clear");
-	  return;
-	}
-
-	mgt_clear_panic();
-}
diff --git a/bin/varnishd/mgt_cli.c b/bin/varnishd/mgt_cli.c
deleted file mode 100644
index dea5e7f..0000000
--- a/bin/varnishd/mgt_cli.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The management process' CLI handling
- */
-
-#include "config.h"
-
-#include <sys/socket.h>
-
-#include <fcntl.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "heritage.h"
-#include "vcli.h"
-#include "vcli_common.h"
-#include "vcli_priv.h"
-#include "vcli_serve.h"
-#include "vev.h"
-#include "vlu.h"
-#include "vss.h"
-#include "vtcp.h"
-
-#include "mgt_cli.h"
-
-#ifndef HAVE_SRANDOMDEV
-#include "compat/srandomdev.h"
-#endif
-
-static int		cli_i = -1, cli_o = -1;
-static struct VCLS	*cls;
-static const char	*secret_file;
-
-#define	MCF_NOAUTH	0	/* NB: zero disables here-documents */
-#define MCF_AUTH	16
-
-/*--------------------------------------------------------------------*/
-
-static void
-mcf_banner(struct cli *cli, const char *const *av, void *priv)
-{
-
-	(void)av;
-	(void)priv;
-	VCLI_Out(cli, "-----------------------------\n");
-	VCLI_Out(cli, "Varnish Cache CLI 1.0\n");
-	VCLI_Out(cli, "-----------------------------\n");
-	VCLI_Out(cli, "%s\n", VSB_data(vident) + 1);
-	VCLI_Out(cli, "\n");
-	VCLI_Out(cli, "Type 'help' for command list.\n");
-	VCLI_Out(cli, "Type 'quit' to close CLI session.\n");
-	if (child_pid < 0)
-		VCLI_Out(cli, "Type 'start' to launch worker process.\n");
-	VCLI_SetResult(cli, CLIS_OK);
-}
-
-/*--------------------------------------------------------------------*/
-
-/* XXX: what order should this list be in ? */
-static struct cli_proto cli_proto[] = {
-	{ CLI_BANNER,		"", mcf_banner, NULL },
-	{ CLI_SERVER_STATUS,	"", mcf_server_status, NULL },
-	{ CLI_SERVER_START,	"", mcf_server_startstop, NULL },
-	{ CLI_SERVER_STOP,	"", mcf_server_startstop, cli_proto },
-	{ CLI_VCL_LOAD,		"", mcf_config_load, NULL },
-	{ CLI_VCL_INLINE,	"", mcf_config_inline, NULL },
-	{ CLI_VCL_USE,		"", mcf_config_use, NULL },
-	{ CLI_VCL_DISCARD,	"", mcf_config_discard, NULL },
-	{ CLI_VCL_LIST,		"", mcf_config_list, NULL },
-	{ CLI_VCL_SHOW,		"", mcf_config_show, NULL },
-	{ CLI_PARAM_SHOW,	"", mcf_param_show, NULL },
-	{ CLI_PARAM_SET,	"", mcf_param_set, NULL },
-	{ CLI_PANIC_SHOW,	"", mcf_panic_show, NULL },
-	{ CLI_PANIC_CLEAR,	"", mcf_panic_clear, NULL },
-	{ NULL }
-};
-
-/*--------------------------------------------------------------------*/
-
-static void
-mcf_panic(struct cli *cli, const char * const *av, void *priv)
-{
-
-	(void)cli;
-	(void)av;
-	(void)priv;
-	assert(!strcmp("", "You asked for it"));
-}
-
-static struct cli_proto cli_debug[] = {
-	{ "debug.panic.master", "debug.panic.master",
-		"\tPanic the master process.\n",
-		0, 0, "d", mcf_panic, NULL},
-	{ NULL }
-};
-
-/*--------------------------------------------------------------------*/
-
-static void
-mcf_askchild(struct cli *cli, const char * const *av, void *priv)
-{
-	int i;
-	char *q;
-	unsigned u;
-	struct vsb *vsb;
-
-	(void)priv;
-	/*
-	 * Command not recognized in master, try cacher if it is
-	 * running.
-	 */
-	if (cli_o <= 0) {
-		if (!strcmp(av[1], "help")) {
-			VCLI_Out(cli, "No help from child, (not running).\n");
-			return;
-		}
-		VCLI_SetResult(cli, CLIS_UNKNOWN);
-		VCLI_Out(cli,
-		    "Unknown request in manager process "
-		    "(child not running).\n"
-		    "Type 'help' for more info.");
-		return;
-	}
-	vsb = VSB_new_auto();
-	for (i = 1; av[i] != NULL; i++) {
-		VSB_quote(vsb, av[i], strlen(av[i]), 0);
-		VSB_putc(vsb, ' ');
-	}
-	VSB_putc(vsb, '\n');
-	AZ(VSB_finish(vsb));
-	i = write(cli_o, VSB_data(vsb), VSB_len(vsb));
-	if (i != VSB_len(vsb)) {
-		VSB_delete(vsb);
-		VCLI_SetResult(cli, CLIS_COMMS);
-		VCLI_Out(cli, "CLI communication error");
-		MGT_Child_Cli_Fail();
-		return;
-	}
-	VSB_delete(vsb);
-	(void)VCLI_ReadResult(cli_i, &u, &q, params->cli_timeout);
-	VCLI_SetResult(cli, u);
-	VCLI_Out(cli, "%s", q);
-	free(q);
-}
-
-static struct cli_proto cli_askchild[] = {
-	{ "*", "<wild-card-entry>", "\t<fall through to cacher>\n",
-		0, 9999, "h*", mcf_askchild, NULL},
-	{ NULL }
-};
-
-/*--------------------------------------------------------------------
- * Ask the child something over CLI, return zero only if everything is
- * happy happy.
- */
-
-int
-mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...) {
-	int i, j;
-	va_list ap;
-	unsigned u;
-	char buf[params->cli_buffer], *p;
-
-	if (resp != NULL)
-		*resp = NULL;
-	if (status != NULL)
-		*status = 0;
-	if (cli_i < 0|| cli_o < 0) {
-		if (status != NULL)
-			*status = CLIS_CANT;
-		return (CLIS_CANT);
-	}
-	va_start(ap, fmt);
-	vbprintf(buf, fmt, ap);
-	va_end(ap);
-	p = strchr(buf, '\0');
-	assert(p != NULL && p > buf && p[-1] == '\n');
-	i = p - buf;
-	j = write(cli_o, buf, i);
-	if (j != i) {
-		if (status != NULL)
-			*status = CLIS_COMMS;
-		if (resp != NULL)
-			*resp = strdup("CLI communication error");
-		MGT_Child_Cli_Fail();
-		return (CLIS_COMMS);
-	}
-
-	(void)VCLI_ReadResult(cli_i, &u, resp, params->cli_timeout);
-	if (status != NULL)
-		*status = u;
-	if (u == CLIS_COMMS)
-		MGT_Child_Cli_Fail();
-	return (u == CLIS_OK ? 0 : u);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mgt_cli_start_child(int fdi, int fdo)
-{
-
-	cli_i = fdi;
-	cli_o = fdo;
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mgt_cli_stop_child(void)
-{
-
-	cli_i = -1;
-	cli_o = -1;
-	/* XXX: kick any users */
-}
-
-/*--------------------------------------------------------------------
- * Generate a random challenge
- */
-
-static void
-mgt_cli_challenge(struct cli *cli)
-{
-	int i;
-
-	for (i = 0; i + 2L < sizeof cli->challenge; i++)
-		cli->challenge[i] = (random() % 26) + 'a';
-	cli->challenge[i++] = '\n';
-	cli->challenge[i] = '\0';
-	VCLI_Out(cli, "%s", cli->challenge);
-	VCLI_Out(cli, "\nAuthentication required.\n");
-	VCLI_SetResult(cli, CLIS_AUTH);
-}
-
-/*--------------------------------------------------------------------
- * Validate the authentication
- */
-
-static void
-mcf_auth(struct cli *cli, const char *const *av, void *priv)
-{
-	int fd;
-	char buf[CLI_AUTH_RESPONSE_LEN + 1];
-
-	AN(av[2]);
-	(void)priv;
-	if (secret_file == NULL) {
-		VCLI_Out(cli, "Secret file not configured\n");
-		VCLI_SetResult(cli, CLIS_CANT);
-		return;
-	}
-	fd = open(secret_file, O_RDONLY);
-	if (fd < 0) {
-		VCLI_Out(cli, "Cannot open secret file (%s)\n",
-		    strerror(errno));
-		VCLI_SetResult(cli, CLIS_CANT);
-		return;
-	}
-	mgt_got_fd(fd);
-	VCLI_AuthResponse(fd, cli->challenge, buf);
-	AZ(close(fd));
-	if (strcasecmp(buf, av[2])) {
-		mgt_cli_challenge(cli);
-		return;
-	}
-	cli->auth = MCF_AUTH;
-	memset(cli->challenge, 0, sizeof cli->challenge);
-	VCLI_SetResult(cli, CLIS_OK);
-	mcf_banner(cli, av, priv);
-}
-
-static struct cli_proto cli_auth[] = {
-	{ CLI_HELP,		"", VCLS_func_help, NULL },
-	{ CLI_PING,		"", VCLS_func_ping },
-	{ CLI_AUTH,		"", mcf_auth, NULL },
-	{ CLI_QUIT,		"", VCLS_func_close, NULL},
-	{ NULL }
-};
-
-/*--------------------------------------------------------------------*/
-static void
-mgt_cli_cb_before(const struct cli *cli)
-{
-
-	if (params->syslog_cli_traffic)
-		syslog(LOG_NOTICE, "CLI %s Rd %s", cli->ident, cli->cmd);
-}
-
-static void
-mgt_cli_cb_after(const struct cli *cli)
-{
-
-	if (params->syslog_cli_traffic)
-		syslog(LOG_NOTICE, "CLI %s Wr %03u %s",
-		    cli->ident, cli->result, VSB_data(cli->sb));
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-mgt_cli_init_cls(void)
-{
-
-	cls = VCLS_New(mgt_cli_cb_before, mgt_cli_cb_after, params->cli_buffer);
-	AN(cls);
-	AZ(VCLS_AddFunc(cls, MCF_NOAUTH, cli_auth));
-	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_proto));
-	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_debug));
-	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_stv));
-	AZ(VCLS_AddFunc(cls, MCF_AUTH, cli_askchild));
-}
-
-/*--------------------------------------------------------------------
- * Get rid of all CLI sessions
- */
-
-void
-mgt_cli_close_all(void)
-{
-
-	VCLS_Destroy(&cls);
-}
-
-/*--------------------------------------------------------------------
- * Callback whenever something happens to the input fd of the session.
- */
-
-static int
-mgt_cli_callback2(const struct vev *e, int what)
-{
-	int i;
-
-	(void)e;
-	(void)what;
-	i = VCLS_PollFd(cls, e->fd, 0);
-	return (i);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident, mgt_cli_close_f *closefunc, void *priv)
-{
-	struct cli *cli;
-	struct vev *ev;
-
-	(void)ident;
-	(void)verbose;
-	if (cls == NULL)
-		mgt_cli_init_cls();
-
-	cli = VCLS_AddFd(cls, fdi, fdo, closefunc, priv);
-
-	cli->ident = strdup(ident);
-
-	/* Deal with TELNET options */
-	if (fdi != 0)
-		VLU_SetTelnet(cli->vlu, fdo);
-
-	if (fdi != 0 && secret_file != NULL) {
-		cli->auth = MCF_NOAUTH;
-		mgt_cli_challenge(cli);
-	} else {
-		cli->auth = MCF_AUTH;
-		mcf_banner(cli, NULL, NULL);
-	}
-	AZ(VSB_finish(cli->sb));
-	(void)VCLI_WriteResult(fdo, cli->result, VSB_data(cli->sb));
-
-
-	ev = vev_new();
-	AN(ev);
-	ev->name = cli->ident;
-	ev->fd = fdi;
-	ev->fd_flags = EV_RD;
-	ev->callback = mgt_cli_callback2;
-	ev->priv = cli;
-	AZ(vev_add(mgt_evb, ev));
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct vsb *
-sock_id(const char *pfx, int fd)
-{
-	struct vsb *vsb;
-
-	char abuf1[VTCP_ADDRBUFSIZE], abuf2[VTCP_ADDRBUFSIZE];
-	char pbuf1[VTCP_PORTBUFSIZE], pbuf2[VTCP_PORTBUFSIZE];
-
-	vsb = VSB_new_auto();
-	AN(vsb);
-	VTCP_myname(fd, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1);
-	VTCP_hisname(fd, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2);
-	VSB_printf(vsb, "%s %s %s %s %s", pfx, abuf2, pbuf2, abuf1, pbuf1);
-	AZ(VSB_finish(vsb));
-	return (vsb);
-}
-
-/*--------------------------------------------------------------------*/
-
-struct telnet {
-	unsigned		magic;
-#define TELNET_MAGIC		0x53ec3ac0
-	int			fd;
-	struct vev		*ev;
-};
-
-static void
-telnet_close(void *priv)
-{
-	struct telnet *tn;
-
-	CAST_OBJ_NOTNULL(tn, priv, TELNET_MAGIC);
-	(void)close(tn->fd);
-	FREE_OBJ(tn);
-}
-
-static struct telnet *
-telnet_new(int fd)
-{
-	struct telnet *tn;
-
-	ALLOC_OBJ(tn, TELNET_MAGIC);
-	AN(tn);
-	tn->fd = fd;
-	return (tn);
-}
-
-static int
-telnet_accept(const struct vev *ev, int what)
-{
-	struct vsb *vsb;
-	struct sockaddr_storage addr;
-	socklen_t addrlen;
-	struct telnet *tn;
-	int i;
-
-	(void)what;
-	addrlen = sizeof addr;
-	i = accept(ev->fd, (void *)&addr, &addrlen);
-	if (i < 0 && errno == EBADF)
-		return (1);
-	if (i < 0)
-		return (0);
-
-	mgt_got_fd(i);
-	tn = telnet_new(i);
-	vsb = sock_id("telnet", i);
-	mgt_cli_setup(i, i, 0, VSB_data(vsb), telnet_close, tn);
-	VSB_delete(vsb);
-	return (0);
-}
-
-void
-mgt_cli_secret(const char *S_arg)
-{
-	int i, fd;
-	char buf[BUFSIZ];
-	char *p;
-
-	/* Save in shmem */
-	i = strlen(S_arg);
-	p = VSM_Alloc(i + 1, "Arg", "-S", "");
-	AN(p);
-	strcpy(p, S_arg);
-
-	srandomdev();
-	fd = open(S_arg, O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "Can not open secret-file \"%s\"\n", S_arg);
-		exit (2);
-	}
-	mgt_got_fd(fd);
-	i = read(fd, buf, sizeof buf);
-	if (i == 0) {
-		fprintf(stderr, "Empty secret-file \"%s\"\n", S_arg);
-		exit (2);
-	}
-	if (i < 0) {
-		fprintf(stderr, "Can not read secret-file \"%s\"\n", S_arg);
-		exit (2);
-	}
-	AZ(close(fd));
-	secret_file = S_arg;
-}
-
-void
-mgt_cli_telnet(const char *T_arg)
-{
-	struct vss_addr **ta;
-	int i, n, sock, good;
-	struct telnet *tn;
-	char *p;
-	struct vsb *vsb;
-	char abuf[VTCP_ADDRBUFSIZE];
-	char pbuf[VTCP_PORTBUFSIZE];
-
-	n = VSS_resolve(T_arg, NULL, &ta);
-	if (n == 0) {
-		REPORT(LOG_ERR, "-T %s Could not be resolved\n", T_arg);
-		exit(2);
-	}
-	good = 0;
-	vsb = VSB_new_auto();
-	XXXAN(vsb);
-	for (i = 0; i < n; ++i) {
-		sock = VSS_listen(ta[i], 10);
-		if (sock < 0)
-			continue;
-		VTCP_myname(sock, abuf, sizeof abuf, pbuf, sizeof pbuf);
-		VSB_printf(vsb, "%s %s\n", abuf, pbuf);
-		good++;
-		tn = telnet_new(sock);
-		tn->ev = vev_new();
-		XXXAN(tn->ev);
-		tn->ev->fd = sock;
-		tn->ev->fd_flags = POLLIN;
-		tn->ev->callback = telnet_accept;
-		AZ(vev_add(mgt_evb, tn->ev));
-		free(ta[i]);
-		ta[i] = NULL;
-	}
-	free(ta);
-	if (good == 0) {
-		REPORT(LOG_ERR, "-T %s could not be listened on.", T_arg);
-		exit(2);
-	}
-	AZ(VSB_finish(vsb));
-	/* Save in shmem */
-	p = VSM_Alloc(VSB_len(vsb) + 1, "Arg", "-T", "");
-	AN(p);
-	strcpy(p, VSB_data(vsb));
-	VSB_delete(vsb);
-}
-
-/* Reverse CLI ("Master") connections --------------------------------*/
-
-static int M_fd = -1;
-static struct vev *M_poker, *M_conn;
-static struct vss_addr **M_ta;
-static int M_nta, M_nxt;
-static double M_poll = 0.1;
-
-static void
-Marg_closer(void *priv)
-{
-
-	(void)priv;
-	(void)close(M_fd);
-	M_fd = -1;
-}
-
-static int
-Marg_poker(const struct vev *e, int what)
-{
-	struct vsb *vsb;
-	int s, k;
-	socklen_t l;
-
-	(void)what;	/* XXX: ??? */
-
-	if (e == M_conn) {
-		/* Our connect(2) returned, check result */
-		l = sizeof k;
-		AZ(getsockopt(M_fd, SOL_SOCKET, SO_ERROR, &k, &l));
-		if (k) {
-			errno = k;
-			syslog(LOG_INFO, "Could not connect to CLI-master: %m");
-			(void)close(M_fd);
-			M_fd = -1;
-			/* Try next address */
-			if (++M_nxt >= M_nta) {
-				M_nxt = 0;
-				if (M_poll < 10)
-					M_poll *= 2;
-			}
-			return (1);
-		}
-		vsb = sock_id("master", M_fd);
-		mgt_cli_setup(M_fd, M_fd, 0, VSB_data(vsb), Marg_closer, NULL);
-		VSB_delete(vsb);
-		M_poll = 1;
-		return (1);
-	}
-
-	assert(e == M_poker);
-
-	M_poker->timeout = M_poll;	/* XXX nasty ? */
-	if (M_fd >= 0)
-		return (0);
-
-	/* Try to connect asynchronously */
-	s = VSS_connect(M_ta[M_nxt], 1);
-	if (s < 0)
-		return (0);
-
-	mgt_got_fd(s);
-
-	M_conn = vev_new();
-	AN(M_conn);
-	M_conn->callback = Marg_poker;
-	M_conn->name = "-M connector";
-	M_conn->fd_flags = EV_WR;
-	M_conn->fd = s;
-	M_fd = s;
-	AZ(vev_add(mgt_evb, M_conn));
-	return (0);
-}
-
-void
-mgt_cli_master(const char *M_arg)
-{
-	(void)M_arg;
-
-	M_nta = VSS_resolve(M_arg, NULL, &M_ta);
-	if (M_nta <= 0) {
-		fprintf(stderr, "Could resolve -M argument to address\n");
-		exit (1);
-	}
-	M_nxt = 0;
-	AZ(M_poker);
-	M_poker = vev_new();
-	AN(M_poker);
-	M_poker->timeout = M_poll;
-	M_poker->callback = Marg_poker;
-	M_poker->name = "-M poker";
-	AZ(vev_add(mgt_evb, M_poker));
-}
diff --git a/bin/varnishd/mgt_cli.h b/bin/varnishd/mgt_cli.h
deleted file mode 100644
index 8c49abb..0000000
--- a/bin/varnishd/mgt_cli.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2009 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/* mgt_child.c */
-cli_func_t mcf_server_startstop;
-cli_func_t mcf_server_status;
-cli_func_t mcf_panic_show;
-cli_func_t mcf_panic_clear;
-
-/* mgt_param.c */
-cli_func_t mcf_param_show;
-cli_func_t mcf_param_set;
-
-/* mgt_vcc.c */
-cli_func_t mcf_config_load;
-cli_func_t mcf_config_inline;
-cli_func_t mcf_config_use;
-cli_func_t mcf_config_discard;
-cli_func_t mcf_config_list;
-cli_func_t mcf_config_show;
-
-/* stevedore.c */
-extern struct cli_proto cli_stv[];
diff --git a/bin/varnishd/mgt_param.c b/bin/varnishd/mgt_param.c
deleted file mode 100644
index 43749b6..0000000
--- a/bin/varnishd/mgt_param.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <grp.h>
-#include <limits.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "waiter/cache_waiter.h"
-#include "heritage.h"
-#include "vav.h"
-#include "vcli.h"
-#include "vcli_common.h"
-#include "vcli_priv.h"
-#include "vparam.h"
-#include "vss.h"
-
-#include "mgt_cli.h"
-
-#define MAGIC_INIT_STRING	"\001"
-struct params master;
-static int nparspec;
-static struct parspec const ** parspec;
-static int margin;
-
-/*--------------------------------------------------------------------*/
-
-static const struct parspec *
-mcf_findpar(const char *name)
-{
-	int i;
-
-	for (i = 0; i < nparspec; i++)
-		if (!strcmp(parspec[i]->name, name))
-			return (parspec[i]);
-	return (NULL);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_generic_timeout(struct cli *cli, volatile unsigned *dst, const char *arg)
-{
-	unsigned u;
-
-	if (arg != NULL) {
-		u = strtoul(arg, NULL, 0);
-		if (u == 0) {
-			VCLI_Out(cli, "Timeout must be greater than zero\n");
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		*dst = u;
-	} else
-		VCLI_Out(cli, "%u", *dst);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-tweak_timeout(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	volatile unsigned *dest;
-
-	dest = par->priv;
-	tweak_generic_timeout(cli, dest, arg);
-}
-
-static void
-tweak_timeout_double(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-	volatile double *dest;
-	double u;
-
-	dest = par->priv;
-	if (arg != NULL) {
-		u = strtod(arg, NULL);
-		if (u < par->min) {
-			VCLI_Out(cli,
-			    "Timeout must be greater or equal to %.g\n",
-				 par->min);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		if (u > par->max) {
-			VCLI_Out(cli,
-			    "Timeout must be less than or equal to %.g\n",
-				 par->max);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		*dest = u;
-	} else
-		VCLI_Out(cli, "%.6f", *dest);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_generic_double(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-	volatile double *dest;
-	double u;
-
-	dest = par->priv;
-	if (arg != NULL) {
-		u = strtod(arg, NULL);
-		if (u < par->min) {
-			VCLI_Out(cli,
-			    "Must be greater or equal to %.g\n",
-				 par->min);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		if (u > par->max) {
-			VCLI_Out(cli,
-			    "Must be less than or equal to %.g\n",
-				 par->max);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		*dest = u;
-	} else
-		VCLI_Out(cli, "%f", *dest);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_generic_bool(struct cli *cli, volatile unsigned *dest, const char *arg)
-{
-	if (arg != NULL) {
-		if (!strcasecmp(arg, "off"))
-			*dest = 0;
-		else if (!strcasecmp(arg, "disable"))
-			*dest = 0;
-		else if (!strcasecmp(arg, "no"))
-			*dest = 0;
-		else if (!strcasecmp(arg, "false"))
-			*dest = 0;
-		else if (!strcasecmp(arg, "on"))
-			*dest = 1;
-		else if (!strcasecmp(arg, "enable"))
-			*dest = 1;
-		else if (!strcasecmp(arg, "yes"))
-			*dest = 1;
-		else if (!strcasecmp(arg, "true"))
-			*dest = 1;
-		else {
-			VCLI_Out(cli, "use \"on\" or \"off\"\n");
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-	} else
-		VCLI_Out(cli, *dest ? "on" : "off");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_bool(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	volatile unsigned *dest;
-
-	dest = par->priv;
-	tweak_generic_bool(cli, dest, arg);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
-    unsigned min, unsigned max)
-{
-	unsigned u;
-
-	if (arg != NULL) {
-		if (!strcasecmp(arg, "unlimited"))
-			u = UINT_MAX;
-		else
-			u = strtoul(arg, NULL, 0);
-		if (u < min) {
-			VCLI_Out(cli, "Must be at least %u\n", min);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		if (u > max) {
-			VCLI_Out(cli, "Must be no more than %u\n", max);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		*dest = u;
-	} else if (*dest == UINT_MAX) {
-		VCLI_Out(cli, "unlimited", *dest);
-	} else {
-		VCLI_Out(cli, "%u", *dest);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-tweak_uint(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	volatile unsigned *dest;
-
-	dest = par->priv;
-	tweak_generic_uint(cli, dest, arg, (uint)par->min, (uint)par->max);
-}
-
-/*--------------------------------------------------------------------
- * XXX: slightly magic.  We want to initialize to "nobody" (XXX: shouldn't
- * XXX: that be something autocrap found for us ?) but we don't want to
- * XXX: fail initialization if that user doesn't exists, even though we
- * XXX: do want to fail it, in subsequent sets.
- * XXX: The magic init string is a hack for this.
- */
-
-static void
-tweak_user(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	struct passwd *pw;
-	struct group *gr;
-
-	(void)par;
-	if (arg != NULL) {
-		if (!strcmp(arg, MAGIC_INIT_STRING)) {
-			pw = getpwnam("nobody");
-			if (pw == NULL) {
-				master.uid = getuid();
-				return;
-			}
-		} else
-			pw = getpwnam(arg);
-		if (pw == NULL) {
-			VCLI_Out(cli, "Unknown user");
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		REPLACE(master.user, pw->pw_name);
-		master.uid = pw->pw_uid;
-		master.gid = pw->pw_gid;
-
-		/* set group to user's primary group */
-		if ((gr = getgrgid(pw->pw_gid)) != NULL &&
-		    (gr = getgrnam(gr->gr_name)) != NULL &&
-		    gr->gr_gid == pw->pw_gid)
-			REPLACE(master.group, gr->gr_name);
-	} else if (master.user) {
-		VCLI_Out(cli, "%s (%d)", master.user, (int)master.uid);
-	} else {
-		VCLI_Out(cli, "%d", (int)master.uid);
-	}
-}
-
-/*--------------------------------------------------------------------
- * XXX: see comment for tweak_user, same thing here.
- */
-
-static void
-tweak_group(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	struct group *gr;
-
-	(void)par;
-	if (arg != NULL) {
-		if (!strcmp(arg, MAGIC_INIT_STRING)) {
-			gr = getgrnam("nogroup");
-			if (gr == NULL) {
-				/* Only replace if tweak_user didn't */
-				if (master.gid == 0)
-					master.gid = getgid();
-				return;
-			}
-		} else
-			gr = getgrnam(arg);
-		if (gr == NULL) {
-			VCLI_Out(cli, "Unknown group");
-			VCLI_SetResult(cli, CLIS_PARAM);
-			return;
-		}
-		REPLACE(master.group, gr->gr_name);
-		master.gid = gr->gr_gid;
-	} else if (master.group) {
-		VCLI_Out(cli, "%s (%d)", master.group, (int)master.gid);
-	} else {
-		VCLI_Out(cli, "%d", (int)master.gid);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-clean_listen_sock_head(struct listen_sock_head *lsh)
-{
-	struct listen_sock *ls, *ls2;
-
-	VTAILQ_FOREACH_SAFE(ls, lsh, list, ls2) {
-		CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
-		VTAILQ_REMOVE(lsh, ls, list);
-		free(ls->name);
-		free(ls->addr);
-		FREE_OBJ(ls);
-	}
-}
-
-static void
-tweak_listen_address(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-	char **av;
-	int i;
-	struct listen_sock		*ls;
-	struct listen_sock_head		lsh;
-
-	(void)par;
-	if (arg == NULL) {
-		VCLI_Quote(cli, master.listen_address);
-		return;
-	}
-
-	av = VAV_Parse(arg, NULL, ARGV_COMMA);
-	if (av == NULL) {
-		VCLI_Out(cli, "Parse error: out of memory");
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-	if (av[0] != NULL) {
-		VCLI_Out(cli, "Parse error: %s", av[0]);
-		VCLI_SetResult(cli, CLIS_PARAM);
-		VAV_Free(av);
-		return;
-	}
-	if (av[1] == NULL) {
-		VCLI_Out(cli, "Empty listen address");
-		VCLI_SetResult(cli, CLIS_PARAM);
-		VAV_Free(av);
-		return;
-	}
-	VTAILQ_INIT(&lsh);
-	for (i = 1; av[i] != NULL; i++) {
-		struct vss_addr **ta;
-		int j, n;
-
-		n = VSS_resolve(av[i], "http", &ta);
-		if (n == 0) {
-			VCLI_Out(cli, "Invalid listen address ");
-			VCLI_Quote(cli, av[i]);
-			VCLI_SetResult(cli, CLIS_PARAM);
-			break;
-		}
-		for (j = 0; j < n; ++j) {
-			ALLOC_OBJ(ls, LISTEN_SOCK_MAGIC);
-			AN(ls);
-			ls->sock = -1;
-			ls->addr = ta[j];
-			ls->name = strdup(av[i]);
-			AN(ls->name);
-			VTAILQ_INSERT_TAIL(&lsh, ls, list);
-		}
-		free(ta);
-	}
-	VAV_Free(av);
-	if (cli != NULL && cli->result != CLIS_OK) {
-		clean_listen_sock_head(&lsh);
-		return;
-	}
-
-	REPLACE(master.listen_address, arg);
-
-	clean_listen_sock_head(&heritage.socks);
-	heritage.nsocks = 0;
-
-	while (!VTAILQ_EMPTY(&lsh)) {
-		ls = VTAILQ_FIRST(&lsh);
-		VTAILQ_REMOVE(&lsh, ls, list);
-		CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
-		VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
-		heritage.nsocks++;
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_string(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	char **p = TRUST_ME(par->priv);
-
-	AN(p);
-	/* XXX should have tweak_generic_string */
-	if (arg == NULL) {
-		VCLI_Quote(cli, *p);
-	} else {
-		REPLACE(*p, arg);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_waiter(struct cli *cli, const struct parspec *par, const char *arg)
-{
-
-	/* XXX should have tweak_generic_string */
-	(void)par;
-	WAIT_tweak_waiter(cli, arg);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_diag_bitmap(struct cli *cli, const struct parspec *par, const char *arg)
-{
-	unsigned u;
-
-	(void)par;
-	if (arg != NULL) {
-		u = strtoul(arg, NULL, 0);
-		master.diag_bitmap = u;
-	} else {
-		VCLI_Out(cli, "0x%x", master.diag_bitmap);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-/*
- * Make sure to end all lines with either a space or newline of the
- * formatting will go haywire.
- */
-
-#define DELAYED_EFFECT_TEXT \
-	"\nNB: This parameter may take quite some time to take (full) effect."
-
-#define MUST_RESTART_TEXT \
-	"\nNB: This parameter will not take any effect until the " \
-	"child process has been restarted."
-
-#define MUST_RELOAD_TEXT \
-	"\nNB: This parameter will not take any effect until the " \
-	"VCL programs have been reloaded."
-
-#define EXPERIMENTAL_TEXT \
-	"\nNB: We do not know yet if it is a good idea to change " \
-	"this parameter, or if the default value is even sensible.  " \
-	"Caution is advised, and feedback is most welcome."
-
-#define WIZARD_TEXT \
-	"\nNB: Do not change this parameter, unless a developer tell " \
-	"you to do so."
-
-/*
- * Remember to update varnishd.1 whenever you add / remove a parameter or
- * change its default value.
- * XXX: we should generate the relevant section of varnishd.1 from here.
- */
-static const struct parspec input_parspec[] = {
-	{ "user", tweak_user, NULL, 0, 0,
-		"The unprivileged user to run as.  Setting this will "
-		"also set \"group\" to the specified user's primary group.",
-		MUST_RESTART,
-		MAGIC_INIT_STRING },
-	{ "group", tweak_group, NULL, 0, 0,
-		"The unprivileged group to run as.",
-		MUST_RESTART,
-		MAGIC_INIT_STRING },
-	{ "default_ttl", tweak_timeout_double, &master.default_ttl,
-		0, UINT_MAX,
-		"The TTL assigned to objects if neither the backend nor "
-		"the VCL code assigns one.\n"
-		"Objects already cached will not be affected by changes "
-		"made until they are fetched from the backend again.\n"
-		"To force an immediate effect at the expense of a total "
-		"flush of the cache use \"ban.url .\"",
-		0,
-		"120", "seconds" },
-	{ "sess_workspace", tweak_uint, &master.sess_workspace, 1024, UINT_MAX,
-		"Bytes of HTTP protocol workspace allocated for sessions. "
-		"This space must be big enough for the entire HTTP protocol "
-		"header and any edits done to it in the VCL code.\n"
-		"Minimum is 1024 bytes.",
-		DELAYED_EFFECT,
-		"65536",
-		"bytes" },
-	{ "http_req_hdr_len", tweak_uint, &master.http_req_hdr_len,
-		40, UINT_MAX,
-		"Maximum length of any HTTP client request header we will "
-		"allow.  The limit is inclusive its continuation lines.\n",
-		0,
-		"8192", "bytes" },
-	{ "http_req_size", tweak_uint, &master.http_req_size,
-		256, UINT_MAX,
-		"Maximum number of bytes of HTTP client request we will deal "
-		"with.  This is a limit on all bytes up to the double blank "
-		"line which ends the HTTP request.\n"
-		"The memory for the request is allocated from the session "
-		"workspace (param: sess_workspace) and this parameter limits "
-		"how much of that the request is allowed to take up.",
-		0,
-		"32768", "bytes" },
-	{ "http_resp_hdr_len", tweak_uint, &master.http_resp_hdr_len,
-		40, UINT_MAX,
-		"Maximum length of any HTTP backend response header we will "
-		"allow.  The limit is inclusive its continuation lines.\n",
-		0,
-		"8192", "bytes" },
-	{ "http_resp_size", tweak_uint, &master.http_resp_size,
-		256, UINT_MAX,
-		"Maximum number of bytes of HTTP backend resonse we will deal "
-		"with.  This is a limit on all bytes up to the double blank "
-		"line which ends the HTTP request.\n"
-		"The memory for the request is allocated from the worker "
-		"workspace (param: sess_workspace) and this parameter limits "
-		"how much of that the request is allowed to take up.",
-		0,
-		"32768", "bytes" },
-	{ "http_max_hdr", tweak_uint, &master.http_max_hdr, 32, 65535,
-		"Maximum number of HTTP headers we will deal with in "
-		"client request or backend reponses.  "
-		"Note that the first line occupies five header fields.\n"
-		"This paramter does not influence storage consumption, "
-		"objects allocate exact space for the headers they store.\n",
-		0,
-		"64", "header lines" },
-	{ "shm_workspace", tweak_uint, &master.shm_workspace, 4096, UINT_MAX,
-		"Bytes of shmlog workspace allocated for worker threads. "
-		"If too big, it wastes some ram, if too small it causes "
-		"needless flushes of the SHM workspace.\n"
-		"These flushes show up in stats as "
-		"\"SHM flushes due to overflow\".\n"
-		"Minimum is 4096 bytes.",
-		DELAYED_EFFECT,
-		"8192", "bytes" },
-	{ "shm_reclen", tweak_uint, &master.shm_reclen, 16, 65535,
-		"Maximum number of bytes in SHM log record.\n"
-		"Maximum is 65535 bytes.",
-		0,
-		"255", "bytes" },
-	{ "default_grace", tweak_timeout_double, &master.default_grace,
-		0, UINT_MAX,
-		"Default grace period.  We will deliver an object "
-		"this long after it has expired, provided another thread "
-		"is attempting to get a new copy.\n"
-		"Objects already cached will not be affected by changes "
-		"made until they are fetched from the backend again.\n",
-		DELAYED_EFFECT,
-		"10", "seconds" },
-	{ "default_keep", tweak_timeout_double, &master.default_keep,
-		0, UINT_MAX,
-		"Default keep period.  We will keep a useless object "
-		"around this long, making it available for conditional "
-		"backend fetches.  "
-		"That means that the object will be removed from the "
-		"cache at the end of ttl+grace+keep.",
-		DELAYED_EFFECT,
-		"0", "seconds" },
-	{ "sess_timeout", tweak_timeout, &master.sess_timeout, 0, 0,
-		"Idle timeout for persistent sessions. "
-		"If a HTTP request has not been received in this many "
-		"seconds, the session is closed.",
-		0,
-		"5", "seconds" },
-	{ "expiry_sleep", tweak_timeout_double, &master.expiry_sleep, 0, 60,
-		"How long the expiry thread sleeps when there is nothing "
-		"for it to do.\n",
-		0,
-		"1", "seconds" },
-	{ "pipe_timeout", tweak_timeout, &master.pipe_timeout, 0, 0,
-		"Idle timeout for PIPE sessions. "
-		"If nothing have been received in either direction for "
-		"this many seconds, the session is closed.\n",
-		0,
-		"60", "seconds" },
-	{ "send_timeout", tweak_timeout, &master.send_timeout, 0, 0,
-		"Send timeout for client connections. "
-		"If the HTTP response hasn't been transmitted in this many\n"
-                "seconds the session is closed. \n"
-		"See setsockopt(2) under SO_SNDTIMEO for more information.",
-		DELAYED_EFFECT,
-		"60", "seconds" },
-	{ "auto_restart", tweak_bool, &master.auto_restart, 0, 0,
-		"Restart child process automatically if it dies.\n",
-		0,
-		"on", "bool" },
-	{ "nuke_limit",
-		tweak_uint, &master.nuke_limit, 0, UINT_MAX,
-		"Maximum number of objects we attempt to nuke in order"
-		"to make space for a object body.",
-		EXPERIMENTAL,
-		"50", "allocations" },
-	{ "fetch_chunksize",
-		tweak_uint, &master.fetch_chunksize, 4, UINT_MAX / 1024.,
-		"The default chunksize used by fetcher. "
-		"This should be bigger than the majority of objects with "
-		"short TTLs.\n"
-		"Internal limits in the storage_file module makes increases "
-		"above 128kb a dubious idea.",
-		EXPERIMENTAL,
-		"128", "kilobytes" },
-	{ "fetch_maxchunksize",
-		tweak_uint, &master.fetch_maxchunksize, 64, UINT_MAX / 1024.,
-		"The maximum chunksize we attempt to allocate from storage. "
-		"Making this too large may cause delays and storage "
-		"fragmentation.\n",
-		EXPERIMENTAL,
-		"262144", "kilobytes" },
-#ifdef SENDFILE_WORKS
-	{ "sendfile_threshold",
-		tweak_uint, &master.sendfile_threshold, 0, UINT_MAX,
-		"The minimum size of objects transmitted with sendfile.",
-		EXPERIMENTAL,
-		"-1", "bytes" },
-#endif /* SENDFILE_WORKS */
-	{ "vcl_trace", tweak_bool,  &master.vcl_trace, 0, 0,
-		"Trace VCL execution in the shmlog.\n"
-		"Enabling this will allow you to see the path each "
-		"request has taken through the VCL program.\n"
-		"This generates a lot of logrecords so it is off by "
-		"default.",
-		0,
-		"off", "bool" },
-	{ "listen_address", tweak_listen_address, NULL, 0, 0,
-		"Whitespace separated list of network endpoints where "
-		"Varnish will accept requests.\n"
-		"Possible formats: host, host:port, :port",
-		MUST_RESTART,
-		":80" },
-	{ "listen_depth", tweak_uint, &master.listen_depth, 0, UINT_MAX,
-		"Listen queue depth.",
-		MUST_RESTART,
-		"1024", "connections" },
-	{ "cli_timeout", tweak_timeout, &master.cli_timeout, 0, 0,
-		"Timeout for the childs replies to CLI requests from "
-		"the master.",
-		0,
-		"10", "seconds" },
-	{ "ping_interval", tweak_uint, &master.ping_interval, 0, UINT_MAX,
-		"Interval between pings from parent to child.\n"
-		"Zero will disable pinging entirely, which makes "
-		"it possible to attach a debugger to the child.",
-		MUST_RESTART,
-		"3", "seconds" },
-	{ "lru_interval", tweak_timeout, &master.lru_timeout, 0, 0,
-		"Grace period before object moves on LRU list.\n"
-		"Objects are only moved to the front of the LRU "
-		"list if they have not been moved there already inside "
-		"this timeout period.  This reduces the amount of lock "
-		"operations necessary for LRU list access.",
-		EXPERIMENTAL,
-		"2", "seconds" },
-	{ "cc_command", tweak_string, &mgt_cc_cmd, 0, 0,
-		"Command used for compiling the C source code to a "
-		"dlopen(3) loadable object.  Any occurrence of %s in "
-		"the string will be replaced with the source file name, "
-		"and %o will be replaced with the output file name.",
-		MUST_RELOAD,
-		VCC_CC , NULL },
-	{ "max_restarts", tweak_uint, &master.max_restarts, 0, UINT_MAX,
-		"Upper limit on how many times a request can restart."
-		"\nBe aware that restarts are likely to cause a hit against "
-		"the backend, so don't increase thoughtlessly.\n",
-		0,
-		"4", "restarts" },
-	{ "esi_syntax",
-		tweak_uint, &master.esi_syntax, 0, UINT_MAX,
-		"Bitmap controlling ESI parsing code:\n"
-		"  0x00000001 - Don't check if it looks like XML\n"
-		"  0x00000002 - Ignore non-esi elements\n"
-		"  0x00000004 - Emit parsing debug records\n"
-		"  0x00000008 - Force-split parser input (debugging)\n"
-		"Use 0x notation and do the bitor in your head :-)\n",
-		0,
-		"0", "bitmap" },
-	{ "max_esi_depth",
-		tweak_uint, &master.max_esi_depth, 0, UINT_MAX,
-		"Maximum depth of esi:include processing.\n",
-		0,
-		"5", "levels" },
-	{ "connect_timeout", tweak_timeout_double,
-		&master.connect_timeout,0, UINT_MAX,
-		"Default connection timeout for backend connections. "
-		"We only try to connect to the backend for this many "
-		"seconds before giving up. "
-		"VCL can override this default value for each backend and "
-		"backend request.",
-		0,
-		"0.7", "s" },
-	{ "first_byte_timeout", tweak_timeout_double,
-		&master.first_byte_timeout,0, UINT_MAX,
-		"Default timeout for receiving first byte from backend. "
-		"We only wait for this many seconds for the first "
-		"byte before giving up. A value of 0 means it will never time "
-		"out. "
-		"VCL can override this default value for each backend and "
-		"backend request. This parameter does not apply to pipe.",
-		0,
-		"60", "s" },
-	{ "between_bytes_timeout", tweak_timeout_double,
-		&master.between_bytes_timeout,0, UINT_MAX,
-		"Default timeout between bytes when receiving data from "
-		"backend. "
-		"We only wait for this many seconds between bytes "
-		"before giving up. A value of 0 means it will never time out. "
-		"VCL can override this default value for each backend request "
-		"and backend request. This parameter does not apply to pipe.",
-		0,
-		"60", "s" },
-	{ "acceptor_sleep_max", tweak_timeout_double,
-		&master.acceptor_sleep_max, 0,  10,
-		"If we run out of resources, such as file descriptors or "
-		"worker threads, the acceptor will sleep between accepts.\n"
-		"This parameter limits how long it can sleep between "
-		"attempts to accept new connections.",
-		EXPERIMENTAL,
-		"0.050", "s" },
-	{ "acceptor_sleep_incr", tweak_timeout_double,
-		&master.acceptor_sleep_incr, 0,  1,
-		"If we run out of resources, such as file descriptors or "
-		"worker threads, the acceptor will sleep between accepts.\n"
-		"This parameter control how much longer we sleep, each time "
-		"we fail to accept a new connection.",
-		EXPERIMENTAL,
-		"0.001", "s" },
-	{ "acceptor_sleep_decay", tweak_generic_double,
-		&master.acceptor_sleep_decay, 0,  1,
-		"If we run out of resources, such as file descriptors or "
-		"worker threads, the acceptor will sleep between accepts.\n"
-		"This parameter (multiplicatively) reduce the sleep duration "
-		"for each succesfull accept. (ie: 0.9 = reduce by 10%)",
-		EXPERIMENTAL,
-		"0.900", "" },
-	{ "clock_skew", tweak_uint, &master.clock_skew, 0, UINT_MAX,
-		"How much clockskew we are willing to accept between the "
-		"backend and our own clock.",
-		0,
-		"10", "s" },
-	{ "prefer_ipv6", tweak_bool, &master.prefer_ipv6, 0, 0,
-		"Prefer IPv6 address when connecting to backends which "
-		"have both IPv4 and IPv6 addresses.",
-		0,
-		"off", "bool" },
-	{ "session_max", tweak_uint,
-		&master.max_sess, 1000, UINT_MAX,
-		"Maximum number of sessions we will allocate from one pool "
-		"before just dropping connections.\n"
-		"This is mostly an anti-DoS measure, and setting it plenty "
-		"high should not hurt, as long as you have the memory for "
-		"it.\n",
-		0,
-		"100000", "sessions" },
-	{ "session_linger", tweak_uint,
-		&master.session_linger,0, UINT_MAX,
-		"How long time the workerthread lingers on the session "
-		"to see if a new request appears right away.\n"
-		"If sessions are reused, as much as half of all reuses "
-		"happen within the first 100 msec of the previous request "
-		"completing.\n"
-		"Setting this too high results in worker threads not doing "
-		"anything for their keep, setting it too low just means that "
-		"more sessions take a detour around the waiter.",
-		EXPERIMENTAL,
-		"50", "ms" },
-	{ "cli_buffer", tweak_uint, &master.cli_buffer, 4096, UINT_MAX,
-		"Size of buffer for CLI input."
-		"\nYou may need to increase this if you have big VCL files "
-		"and use the vcl.inline CLI command.\n"
-		"NB: Must be specified with -p to have effect.\n",
-		0,
-		"8192", "bytes" },
-	{ "log_hashstring", tweak_bool, &master.log_hash, 0, 0,
-		"Log the hash string components to shared memory log.\n",
-		0,
-		"on", "bool" },
-	{ "log_local_address", tweak_bool, &master.log_local_addr, 0, 0,
-		"Log the local address on the TCP connection in the "
-		"SessionOpen shared memory record.\n",
-		0,
-		"off", "bool" },
-	{ "waiter", tweak_waiter, NULL, 0, 0,
-		"Select the waiter kernel interface.\n",
-		EXPERIMENTAL | MUST_RESTART,
-		"default", NULL },
-	{ "diag_bitmap", tweak_diag_bitmap, 0, 0, 0,
-		"Bitmap controlling diagnostics code:\n"
-		"  0x00000001 - CNT_Session states.\n"
-		"  0x00000002 - workspace debugging.\n"
-		"  0x00000004 - kqueue debugging.\n"
-		"  0x00000008 - mutex logging.\n"
-		"  0x00000010 - mutex contests.\n"
-		"  0x00000020 - waiting list.\n"
-		"  0x00000040 - object workspace.\n"
-		"  0x00001000 - do not core-dump child process.\n"
-		"  0x00002000 - only short panic message.\n"
-		"  0x00004000 - panic to stderr.\n"
-#ifdef HAVE_ABORT2
-		"  0x00008000 - panic to abort2().\n"
-#endif
-		"  0x00010000 - synchronize shmlog.\n"
-		"  0x00020000 - synchronous start of persistence.\n"
-		"  0x00040000 - release VCL early.\n"
-		"  0x80000000 - do edge-detection on digest.\n"
-		"Use 0x notation and do the bitor in your head :-)\n",
-		0,
-		"0", "bitmap" },
-	{ "ban_dups", tweak_bool, &master.ban_dups, 0, 0,
-		"Detect and eliminate duplicate bans.\n",
-		0,
-		"on", "bool" },
-	{ "syslog_cli_traffic", tweak_bool, &master.syslog_cli_traffic, 0, 0,
-		"Log all CLI traffic to syslog(LOG_INFO).\n",
-		0,
-		"on", "bool" },
-	{ "ban_lurker_sleep", tweak_timeout_double,
-		&master.ban_lurker_sleep, 0, UINT_MAX,
-		"How long time does the ban lurker thread sleeps between "
-		"successful attempts to push the last item up the ban "
-		" list.  It always sleeps a second when nothing can be done.\n"
-		"A value of zero disables the ban lurker.",
-		0,
-		"0.01", "s" },
-	{ "saintmode_threshold", tweak_uint,
-		&master.saintmode_threshold, 0, UINT_MAX,
-		"The maximum number of objects held off by saint mode before "
-		"no further will be made to the backend until one times out.  "
-		"A value of 0 disables saintmode.",
-		EXPERIMENTAL,
-		"10", "objects" },
-	{ "http_range_support", tweak_bool, &master.http_range_support, 0, 0,
-		"Enable support for HTTP Range headers.\n",
-		EXPERIMENTAL,
-		"on", "bool" },
-	{ "http_gzip_support", tweak_bool, &master.http_gzip_support, 0, 0,
-		"Enable gzip support. When enabled Varnish will compress "
-		"uncompressed objects before they are stored in the cache. "
-		"If a client does not support gzip encoding Varnish will "
-		"uncompress compressed objects on demand. Varnish will also "
-		"rewrite the Accept-Encoding header of clients indicating "
-		"support for gzip to:\n"
-		"Accept-Encoding: gzip\n\n"
-		"Clients that do not support gzip will have their "
-		"Accept-Encoding header removed. For more information on how "
-		"gzip is implemented please see the chapter on gzip in the "
-		"Varnish reference.",
-		EXPERIMENTAL,
-		"on", "bool" },
-	{ "gzip_tmp_space", tweak_uint, &master.gzip_tmp_space, 0, 2,
-		"Where temporary space for gzip/gunzip is allocated:\n"
-		"  0 - malloc\n"
-		"  1 - session workspace\n"
-		"  2 - thread workspace\n"
-		"If you have much gzip/gunzip activity, it may be an"
-		" advantage to use workspace for these allocations to reduce"
-		" malloc activity.  Be aware that gzip needs 256+KB and gunzip"
-		" needs 32+KB of workspace (64+KB if ESI processing).",
-		EXPERIMENTAL,
-		"0", "" },
-	{ "gzip_level", tweak_uint, &master.gzip_level, 0, 9,
-		"Gzip compression level: 0=debug, 1=fast, 9=best",
-		0,
-		"6", ""},
-	{ "gzip_window", tweak_uint, &master.gzip_window, 8, 15,
-		"Gzip window size 8=least, 15=most compression.\n"
-		"Memory impact is 8=1k, 9=2k, ... 15=128k.",
-		0,
-		"15", ""},
-	{ "gzip_memlevel", tweak_uint, &master.gzip_memlevel, 1, 9,
-		"Gzip memory level 1=slow/least, 9=fast/most compression.\n"
-		"Memory impact is 1=1k, 2=2k, ... 9=256k.",
-		0,
-		"8", ""},
-	{ "gzip_stack_buffer", tweak_uint, &master.gzip_stack_buffer,
-	        2048, UINT_MAX,
-		"Size of stack buffer used for gzip processing.\n"
-		"The stack buffers are used for in-transit data,"
-		" for instance gunzip'ed data being sent to a client."
-		"Making this space to small results in more overhead,"
-		" writes to sockets etc, making it too big is probably"
-		" just a waste of memory.",
-		EXPERIMENTAL,
-		"32768", "Bytes" },
-	{ "shortlived", tweak_timeout_double,
-		&master.shortlived, 0, UINT_MAX,
-		"Objects created with TTL shorter than this are always "
-		"put in transient storage.\n",
-		0,
-		"10.0", "s" },
-	{ "critbit_cooloff", tweak_timeout_double,
-		&master.critbit_cooloff, 60, 254,
-		"How long time the critbit hasher keeps deleted objheads "
-		"on the cooloff list.\n",
-		WIZARD,
-		"180.0", "s" },
-	{ "vcl_dir", tweak_string, &mgt_vcl_dir, 0, 0,
-		"Directory from which relative VCL filenames (vcl.load and "
-		"include) are opened.",
-		0,
-#ifdef VARNISH_VCL_DIR
-		VARNISH_VCL_DIR,
-#else
-		".",
-#endif
-		NULL },
-	{ "vmod_dir", tweak_string, &mgt_vmod_dir, 0, 0,
-		"Directory where VCL modules are to be found.",
-		0,
-#ifdef VARNISH_VMOD_DIR
-		VARNISH_VMOD_DIR,
-#else
-		".",
-#endif
-		NULL },
-	{ "vcc_err_unref", tweak_bool, &mgt_vcc_err_unref, 0, 0,
-		"Unreferenced VCL objects result in error.\n",
-		0,
-		"on", "bool" },
-
-
-	{ "pcre_match_limit", tweak_uint,
-		&master.vre_limits.match,
-		1, UINT_MAX,
-		"The limit for the  number of internal matching function"
-		" calls in a pcre_exec() execution.",
-		0,
-		"10000", ""},
-
-	{ "pcre_match_limit_recursion", tweak_uint,
-		&master.vre_limits.match_recursion,
-		1, UINT_MAX,
-		"The limit for the  number of internal matching function"
-		" recursions in a pcre_exec() execution.",
-		0,
-		"10000", ""},
-
-	{ NULL, NULL, NULL }
-};
-
-/*--------------------------------------------------------------------*/
-
-#define WIDTH 76
-
-static void
-mcf_wrap(struct cli *cli, const char *text)
-{
-	const char *p, *q;
-
-	/* Format text to COLUMNS width */
-	for (p = text; *p != '\0'; ) {
-		q = strchr(p, '\n');
-		if (q == NULL)
-			q = strchr(p, '\0');
-		if (q > p + WIDTH - margin) {
-			q = p + WIDTH - margin;
-			while (q > p && *q != ' ')
-				q--;
-			AN(q);
-		}
-		VCLI_Out(cli, "%*s %.*s\n", margin, "", (int)(q - p), p);
-		p = q;
-		if (*p == ' ' || *p == '\n')
-			p++;
-	}
-}
-
-void
-mcf_param_show(struct cli *cli, const char * const *av, void *priv)
-{
-	int i;
-	const struct parspec *pp;
-	int lfmt;
-
-	(void)priv;
-	if (av[2] == NULL || strcmp(av[2], "-l"))
-		lfmt = 0;
-	else
-		lfmt = 1;
-	for (i = 0; i < nparspec; i++) {
-		pp = parspec[i];
-		if (av[2] != NULL && !lfmt && strcmp(pp->name, av[2]))
-			continue;
-		VCLI_Out(cli, "%-*s ", margin, pp->name);
-		if (pp->func == NULL) {
-			VCLI_Out(cli, "Not implemented.\n");
-			if (av[2] != NULL && !lfmt)
-				return;
-			else
-				continue;
-		}
-		pp->func(cli, pp, NULL);
-		if (pp->units != NULL)
-			VCLI_Out(cli, " [%s]\n", pp->units);
-		else
-			VCLI_Out(cli, "\n");
-		if (av[2] != NULL) {
-			VCLI_Out(cli, "%-*s Default is %s\n",
-			    margin, "", pp->def);
-			mcf_wrap(cli, pp->descr);
-			if (pp->flags & DELAYED_EFFECT)
-				mcf_wrap(cli, DELAYED_EFFECT_TEXT);
-			if (pp->flags & EXPERIMENTAL)
-				mcf_wrap(cli, EXPERIMENTAL_TEXT);
-			if (pp->flags & MUST_RELOAD)
-				mcf_wrap(cli, MUST_RELOAD_TEXT);
-			if (pp->flags & MUST_RESTART)
-				mcf_wrap(cli, MUST_RESTART_TEXT);
-			if (pp->flags & WIZARD)
-				mcf_wrap(cli, WIZARD_TEXT);
-			if (!lfmt)
-				return;
-			else
-				VCLI_Out(cli, "\n");
-		}
-	}
-	if (av[2] != NULL && !lfmt) {
-		VCLI_SetResult(cli, CLIS_PARAM);
-		VCLI_Out(cli, "Unknown parameter \"%s\".", av[2]);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-MCF_ParamSync(void)
-{
-	if (params != &master)
-		*params = master;
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-MCF_ParamSet(struct cli *cli, const char *param, const char *val)
-{
-	const struct parspec *pp;
-
-	pp = mcf_findpar(param);
-	if (pp != NULL) {
-		pp->func(cli, pp, val);
-		if (cli->result != CLIS_OK) {
-			VCLI_Out(cli, "(attempting to set param %s to %s)\n",
-			    pp->name, val);
-		} else if (child_pid >= 0 && pp->flags & MUST_RESTART) {
-			VCLI_Out(cli, "Change will take effect"
-			    " when child is restarted");
-		} else if (pp->flags & MUST_RELOAD) {
-			VCLI_Out(cli, "Change will take effect"
-			    " when VCL script is reloaded");
-		}
-		MCF_ParamSync();
-		return;
-	}
-	VCLI_SetResult(cli, CLIS_PARAM);
-	VCLI_Out(cli, "Unknown parameter \"%s\".", param);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-void
-mcf_param_set(struct cli *cli, const char * const *av, void *priv)
-{
-
-	(void)priv;
-	MCF_ParamSet(cli, av[2], av[3]);
-}
-
-/*--------------------------------------------------------------------
- * Add a group of parameters to the global set and sort by name.
- */
-
-static int
-parspec_cmp(const void *a, const void *b)
-{
-	struct parspec * const * pa = a;
-	struct parspec * const * pb = b;
-	return (strcmp((*pa)->name, (*pb)->name));
-}
-
-static void
-MCF_AddParams(const struct parspec *ps)
-{
-	const struct parspec *pp;
-	int n;
-
-	n = 0;
-	for (pp = ps; pp->name != NULL; pp++) {
-		if (mcf_findpar(pp->name) != NULL)
-			fprintf(stderr, "Duplicate param: %s\n", pp->name);
-		if (strlen(pp->name) + 1 > margin)
-			margin = strlen(pp->name) + 1;
-		n++;
-	}
-	parspec = realloc(parspec, (1L + nparspec + n) * sizeof *parspec);
-	XXXAN(parspec);
-	for (pp = ps; pp->name != NULL; pp++)
-		parspec[nparspec++] = pp;
-	parspec[nparspec] = NULL;
-	qsort (parspec, nparspec, sizeof parspec[0], parspec_cmp);
-}
-
-/*--------------------------------------------------------------------
- * Set defaults for all parameters
- */
-
-static void
-MCF_SetDefaults(struct cli *cli)
-{
-	const struct parspec *pp;
-	int i;
-
-	for (i = 0; i < nparspec; i++) {
-		pp = parspec[i];
-		if (cli != NULL)
-			VCLI_Out(cli,
-			    "Set Default for %s = %s\n", pp->name, pp->def);
-		pp->func(cli, pp, pp->def);
-		if (cli != NULL && cli->result != CLIS_OK)
-			return;
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-MCF_ParamInit(struct cli *cli)
-{
-
-	MCF_AddParams(input_parspec);
-	MCF_AddParams(WRK_parspec);
-
-	/* XXX: We do this twice, to get past any interdependencies */
-	MCF_SetDefaults(NULL);
-	MCF_SetDefaults(cli);
-
-	params = &master;
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-MCF_DumpRst(void)
-{
-	const struct parspec *pp;
-	const char *p, *q;
-	int i;
-
-	for (i = 0; i < nparspec; i++) {
-		pp = parspec[i];
-		printf("%s\n", pp->name);
-		if (pp->units != NULL && *pp->units != '\0')
-			printf("\t- Units: %s\n", pp->units);
-		printf("\t- Default: %s\n",
-		    strcmp(pp->def,MAGIC_INIT_STRING) == 0 ? "magic" : pp->def);
-		/*
-		 * XXX: we should mark the params with one/two flags
-		 * XXX: that say if ->min/->max are valid, so we
-		 * XXX: can emit those also in help texts.
-		 */
-		if (pp->flags) {
-			printf("\t- Flags: ");
-			q = "";
-			if (pp->flags & DELAYED_EFFECT) {
-				printf("%sdelayed", q);
-				q = ", ";
-			}
-			if (pp->flags & MUST_RESTART) {
-				printf("%smust_restart", q);
-				q = ", ";
-			}
-			if (pp->flags & MUST_RELOAD) {
-				printf("%smust_reload", q);
-				q = ", ";
-			}
-			if (pp->flags & EXPERIMENTAL) {
-				printf("%sexperimental", q);
-				q = ", ";
-			}
-			printf("\n");
-		}
-		printf("\n\t");
-		for (p = pp->descr; *p; p++) {
-			if (*p == '\n' && p[1] =='\0')
-				break;
-			if (*p == '\n' && p[1] =='\n') {
-				printf("\n\n\t");
-				p++;
-			} else if (*p == '\n') {
-				printf("\n\t");
-			} else if (*p == ':' && p[1] == '\n') {
-				/*
-				 * Start of definition list,
-				 * use RSTs code mode for this
-				 */
-				printf("::\n");
-			} else {
-				printf("%c", *p);
-			}
-		}
-		printf("\n\n");
-	}
-	printf("\n");
-}
diff --git a/bin/varnishd/mgt_pool.c b/bin/varnishd/mgt_pool.c
deleted file mode 100644
index 489fab8..0000000
--- a/bin/varnishd/mgt_pool.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * We maintain a number of worker thread pools, to spread lock contention.
- *
- * Pools can be added on the fly, as a means to mitigate lock contention,
- * but can only be removed again by a restart. (XXX: we could fix that)
- *
- * Two threads herd the pools, one eliminates idle threads and aggregates
- * statistics for all the pools, the other thread creates new threads
- * on demand, subject to various numerical constraints.
- *
- * The algorithm for when to create threads needs to be reactive enough
- * to handle startup spikes, but sufficiently attenuated to not cause
- * thread pileups.  This remains subject for improvement.
- */
-
-#include "config.h"
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "heritage.h"
-#include "vparam.h"
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_thread_pool_min(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-
-	tweak_generic_uint(cli, &master.wthread_min, arg,
-	    (unsigned)par->min, master.wthread_max);
-}
-
-/*--------------------------------------------------------------------
- * This is utterly ridiculous:  POSIX does not guarantee that the
- * minimum thread stack size is a compile time constant.
- * XXX: "32" is a magic marker for 32bit systems.
- */
-
-static void
-tweak_stack_size(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-	unsigned low, u;
-	char buf[12];
-
-	low = sysconf(_SC_THREAD_STACK_MIN);
-
-	if (arg != NULL && !strcmp(arg, "32bit")) {
-		u = 65536;
-		if (u < low)
-			u = low;
-		sprintf(buf, "%u", u);
-		arg = buf;
-	}
-
-	tweak_generic_uint(cli, &master.wthread_stacksize, arg,
-	    low, (uint)par->max);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_thread_pool_max(struct cli *cli, const struct parspec *par,
-    const char *arg)
-{
-
-	(void)par;
-	tweak_generic_uint(cli, &master.wthread_max, arg,
-	    master.wthread_min, UINT_MAX);
-}
-
-/*--------------------------------------------------------------------*/
-
-const struct parspec WRK_parspec[] = {
-	{ "thread_pools", tweak_uint, &master.wthread_pools, 1, UINT_MAX,
-		"Number of worker thread pools.\n"
-		"\n"
-		"Increasing number of worker pools decreases lock "
-		"contention.\n"
-		"\n"
-		"Too many pools waste CPU and RAM resources, and more than "
-		"one pool for each CPU is probably detrimal to performance.\n"
-		"\n"
-		"Can be increased on the fly, but decreases require a "
-		"restart to take effect.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"2", "pools" },
-	{ "thread_pool_max", tweak_thread_pool_max, NULL, 1, 0,
-		"The maximum number of worker threads in each pool.\n"
-		"\n"
-		"Do not set this higher than you have to, since excess "
-		"worker threads soak up RAM and CPU and generally just get "
-		"in the way of getting work done.\n",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"500", "threads" },
-	{ "thread_pool_min", tweak_thread_pool_min, NULL, 2, 0,
-		"The minimum number of worker threads in each pool.\n"
-		"\n"
-		"Increasing this may help ramp up faster from low load "
-		"situations where threads have expired.\n"
-		"\n"
-		"Minimum is 2 threads.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"5", "threads" },
-	{ "thread_pool_timeout", tweak_timeout, &master.wthread_timeout, 1, 0,
-		"Thread idle threshold.\n"
-		"\n"
-		"Threads in excess of thread_pool_min, which have been idle "
-		"for at least this long are candidates for purging.\n"
-		"\n"
-		"Minimum is 1 second.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"300", "seconds" },
-	{ "thread_pool_purge_delay",
-		tweak_timeout, &master.wthread_purge_delay, 100, 0,
-		"Wait this long between purging threads.\n"
-		"\n"
-		"This controls the decay of thread pools when idle(-ish).\n"
-		"\n"
-		"Minimum is 100 milliseconds.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"1000", "milliseconds" },
-	{ "thread_pool_add_threshold",
-		tweak_uint, &master.wthread_add_threshold, 0, UINT_MAX,
-		"Overflow threshold for worker thread creation.\n"
-		"\n"
-		"Setting this too low, will result in excess worker threads, "
-		"which is generally a bad idea.\n"
-		"\n"
-		"Setting it too high results in insuffient worker threads.\n",
-		EXPERIMENTAL,
-		"2", "requests" },
-	{ "thread_pool_add_delay",
-		tweak_timeout, &master.wthread_add_delay, 0, UINT_MAX,
-		"Wait at least this long between creating threads.\n"
-		"\n"
-		"Setting this too long results in insuffient worker threads.\n"
-		"\n"
-		"Setting this too short increases the risk of worker "
-		"thread pile-up.\n",
-		0,
-		"2", "milliseconds" },
-	{ "thread_pool_fail_delay",
-		tweak_timeout, &master.wthread_fail_delay, 100, UINT_MAX,
-		"Wait at least this long after a failed thread creation "
-		"before trying to create another thread.\n"
-		"\n"
-		"Failure to create a worker thread is often a sign that "
-		" the end is near, because the process is running out of "
-		"RAM resources for thread stacks.\n"
-		"This delay tries to not rush it on needlessly.\n"
-		"\n"
-		"If thread creation failures are a problem, check that "
-		"thread_pool_max is not too high.\n"
-		"\n"
-		"It may also help to increase thread_pool_timeout and "
-		"thread_pool_min, to reduce the rate at which treads are "
-		"destroyed and later recreated.\n",
-		EXPERIMENTAL,
-		"200", "milliseconds" },
-	{ "thread_stats_rate",
-		tweak_uint, &master.wthread_stats_rate, 0, UINT_MAX,
-		"Worker threads accumulate statistics, and dump these into "
-		"the global stats counters if the lock is free when they "
-		"finish a request.\n"
-		"This parameters defines the maximum number of requests "
-		"a worker thread may handle, before it is forced to dump "
-		"its accumulated stats into the global counters.\n",
-		EXPERIMENTAL,
-		"10", "requests" },
-	{ "queue_max", tweak_uint, &master.queue_max, 0, UINT_MAX,
-		"Percentage permitted queue length.\n"
-		"\n"
-		"This sets the ratio of queued requests to worker threads, "
-		"above which sessions will be dropped instead of queued.\n",
-		EXPERIMENTAL,
-		"100", "%" },
-	{ "rush_exponent", tweak_uint, &master.rush_exponent, 2, UINT_MAX,
-		"How many parked request we start for each completed "
-		"request on the object.\n"
-		"NB: Even with the implict delay of delivery, "
-		"this parameter controls an exponential increase in "
-		"number of worker threads.",
-		EXPERIMENTAL,
-		"3", "requests per request" },
-	{ "thread_pool_stack",
-		tweak_stack_size, &master.wthread_stacksize, 0, UINT_MAX,
-		"Worker thread stack size.\n"
-		"On 32bit systems you may need to tweak this down to fit "
-		"many threads into the limited address space.\n",
-		EXPERIMENTAL,
-		"-1", "bytes" },
-	{ "thread_pool_workspace", tweak_uint, &master.wthread_workspace,
-		1024, UINT_MAX,
-		"Bytes of HTTP protocol workspace allocated for worker "
-		"threads. "
-		"This space must be big enough for the backend request "
-		"and responses, and response to the client plus any other "
-		"memory needs in the VCL code."
-		"Minimum is 1024 bytes.",
-		DELAYED_EFFECT,
-		"65536",
-		"bytes" },
-	{ NULL, NULL, NULL }
-};
diff --git a/bin/varnishd/mgt_sandbox.c b/bin/varnishd/mgt_sandbox.c
deleted file mode 100644
index 8ac827d..0000000
--- a/bin/varnishd/mgt_sandbox.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Sandboxing child processes
- *
- * The worker/manager process border is one of the major security barriers
- * in Varnish, and therefore subject to whatever restrictions we have access
- * to under the given operating system.
- *
- * Unfortunately there is no consensus on APIs for this purpose, so each
- * operating system will require its own methods.
- *
- * This sourcefile tries to encapsulate the resulting mess on place.
- *
- * TODO:
- *	Unix:	chroot
- *	FreeBSD: jail
- *	FreeBSD: capsicum
- */
-
-#include "config.h"
-
-#ifdef __linux__
-#include <sys/prctl.h>
-#endif
-
-#include <stdio.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "heritage.h"
-
-/*--------------------------------------------------------------------*/
-
-/* Waive all privileges in the child, it does not need any */
-
-void
-mgt_sandbox(void)
-{
-#ifdef HAVE_SETPPRIV
-	mgt_sandbox_solaris_init();
-	mgt_sandbox_solaris_privsep();
-#else
-	if (geteuid() == 0) {
-		XXXAZ(setgid(params->gid));
-		XXXAZ(setuid(params->uid));
-	} else {
-		REPORT0(LOG_INFO, "Not running as root, no priv-sep");
-	}
-#endif
-
-	/* On Linux >= 2.4, you need to set the dumpable flag
-	   to get core dumps after you have done a setuid. */
-
-#ifdef __linux__
-	if (prctl(PR_SET_DUMPABLE, 1) != 0)
-		REPORT0(LOG_INFO,
-		    "Could not set dumpable bit.  Core dumps turned off\n");
-#endif
-
-#ifdef HAVE_SETPPRIV
-	mgt_sandbox_solaris_fini();
-#endif
-
-}
diff --git a/bin/varnishd/mgt_sandbox_solaris.c b/bin/varnishd/mgt_sandbox_solaris.c
deleted file mode 100644
index 534f609..0000000
--- a/bin/varnishd/mgt_sandbox_solaris.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*-
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *	   Nils Goroll <nils.goroll at uplex.de>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Sandboxing child processes on Solaris
- *
- */
-
-#include "config.h"
-
-#ifdef HAVE_SETPPRIV
-
-#ifdef HAVE_PRIV_H
-#include <priv.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "heritage.h"
-
-/*--------------------------------------------------------------------
- * SOLARIS PRIVILEGES: Note on use of symbolic PRIV_* constants
- * 
- * For privileges which existed in Solaris 10 FCS, we may use the constants from
- * sys/priv_names.h
- *
- * For privileges which have been added later, we need to use strings in order
- * not to break builds of varnish on these platforms. To remain binary
- * compatible, we need to silently ignore errors from priv_addset when using
- * these strings.
- *
- * For optimal build and binary forward comatibility, we could use subtractive
- * set specs like
- *
- *       basic,!file_link_any,!proc_exec,!proc_fork,!proc_info,!proc_session
- *
- * but I (Nils) have a preference for making an informed decision about which
- * privileges the varnish child should have and which it shouldn't.
- *
- * Newly introduced privileges should be annotated with their PSARC / commit ID
- * (as long as Oracle reveils these :/ )
- *
- * SOLARIS PRIVILEGES: Note on accidentally setting the SNOCD flag
- *
- * When setting privileges, we need to take care not to accidentally set the
- * SNOCD flag which will disable core dumps unnecessarily. (see
- * https://www.varnish-cache.org/trac/ticket/671 )
- *
- * When changing the logic herein, always check with mdb -k. Replace _PID_ with
- * the pid of your varnish child, the result should be 0, otherwise a regression
- * has been introduced.
- *
- * > 0t_PID_::pid2proc | ::print proc_t p_flag | >a
- * > (<a & 0x10000000)=X
- *                 0
- *
- * (a value of 0x10000000 indicates that SNOCD is set)
- *
- * NOTE that on Solaris changing the uid will _always_ set SNOCD, so make sure
- * you run this test with appropriate privileges, but without proc_setid, so
- * varnish won't setuid(), e.g.
- *
- * pfexec ppriv -e -s A=basic,net_privaddr,sys_resource varnish ...
- *
- * SOLARIS COREDUMPS with setuid(): See coreadm(1M) - global-setid / proc-setid
- *
- */
-
-/* effective during runtime of the child */
-static inline void
-mgt_sandbox_solaris_add_effective(priv_set_t *pset)
-{
-	/* PSARC/2009/685 - 8eca52188202 - onnv_132 */
-	priv_addset(pset, "net_access");
-
-	/* PSARC/2009/378 - 63678502e95e - onnv_140 */
-	priv_addset(pset, "file_read");
-	priv_addset(pset, "file_write");
-}
-
-/* permitted during runtime of the child - for privilege bracketing */
-static inline void
-mgt_sandbox_solaris_add_permitted(priv_set_t *pset)
-{
-	/* for raising limits in cache_waiter_ports.c */
-	priv_addset(pset, PRIV_SYS_RESOURCE);
-}
-
-/* effective during mgt_sandbox */
-static inline void
-mgt_sandbox_solaris_add_initial(priv_set_t *pset)
-{
-	/* for setgid/setuid */
-	priv_addset(pset, PRIV_PROC_SETID);
-}
-
-/*
- * if we are not yet privilege-aware already (ie we have been started
- * not-privilege aware wird euid 0), we need to grab any additional privileges
- * needed during mgt_standbox, until we reduce to least privileges in
- * mgt_sandbox_waive, otherwise we would loose them with setuid()
- */
-
-void
-mgt_sandbox_solaris_init(void)
-{
-	priv_set_t *priv_all;
-
-	if (! (priv_all = priv_allocset())) {
-		REPORT(LOG_ERR,
-		    "Child start warning: mgt_sandbox_init - priv_allocset failed: errno=%d (%s)",
-		    errno, strerror(errno));
-		return;
-	}
-	
-	priv_emptyset(priv_all);
-
-	mgt_sandbox_solaris_add_effective(priv_all);
-	mgt_sandbox_solaris_add_permitted(priv_all);
-	mgt_sandbox_solaris_add_initial(priv_all);
-
-	setppriv(PRIV_ON, PRIV_PERMITTED, priv_all);
-	setppriv(PRIV_ON, PRIV_EFFECTIVE, priv_all);
-	setppriv(PRIV_ON, PRIV_INHERITABLE, priv_all);
-
-	priv_freeset(priv_all);
-}
-
-void
-mgt_sandbox_solaris_privsep(void)
-{
-	if (priv_ineffect(PRIV_PROC_SETID)) {
-                if (getgid() != params->gid)
-                        XXXAZ(setgid(params->gid));
-                if (getuid() != params->uid)
-                        XXXAZ(setuid(params->uid));
-        } else {
-                REPORT(LOG_INFO, "Privilege %s missing, will not change uid/gid",
-		    PRIV_PROC_SETID);
-        }
-}
-
-/* 
- * Waive most privileges in the child
- *
- * as of onnv_151a, we should end up with:
- *
- * > ppriv -v #pid of varnish child
- * PID:  .../varnishd ...
- * flags = PRIV_AWARE
- *      E: file_read,file_write,net_access
- *      I: none
- *      P: file_read,file_write,net_access,sys_resource
- *      L: file_read,file_write,net_access,sys_resource
- *
- * We should keep sys_resource in P in order to adjust our limits if we need to
- */
-
-void
-mgt_sandbox_solaris_fini(void)
-{
-	priv_set_t *effective, *inheritable, *permitted;
-
-	if (!(effective = priv_allocset()) ||
-	    !(inheritable = priv_allocset()) ||
-	    !(permitted = priv_allocset())) {
-		REPORT(LOG_ERR,
-		    "Child start warning: mgt_sandbox_waive - priv_allocset failed: errno=%d (%s)",
-		    errno, strerror(errno));
-		return;
-	}
-
-	priv_emptyset(inheritable);
-
-	priv_emptyset(effective);
-	mgt_sandbox_solaris_add_effective(effective);
-
-	priv_copyset(effective, permitted);
-	mgt_sandbox_solaris_add_permitted(permitted);
-
-	/* 
-	 * invert the sets and clear privileges such that setppriv will always
-	 * succeed
-	 */
-	priv_inverse(inheritable);
-	priv_inverse(effective);
-	priv_inverse(permitted);
-
-#define SETPPRIV(which, set)						\
-	if (setppriv(PRIV_OFF, which, set))				\
-		REPORT(LOG_ERR,						\
-		    "Child start warning: Waiving privileges failed on %s: errno=%d (%s)", \
-		    #which, errno, strerror(errno));
-
-	SETPPRIV(PRIV_INHERITABLE, inheritable);
-	SETPPRIV(PRIV_EFFECTIVE, effective);
-	SETPPRIV(PRIV_PERMITTED, permitted);
-	SETPPRIV(PRIV_LIMIT, permitted);
-#undef SETPPRIV
-
-	priv_freeset(inheritable);
-	priv_freeset(effective);
-}
-
-#endif /* HAVE_SETPPRIV */
diff --git a/bin/varnishd/mgt_shmem.c b/bin/varnishd/mgt_shmem.c
deleted file mode 100644
index ae0a50d..0000000
--- a/bin/varnishd/mgt_shmem.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *
- * TODO:
- *
- * There is a risk that the child process might corrupt the VSM segment
- * and we should capture that event and recover gracefully.
- *
- * A possible state diagram could be:
- *
- *	[manager start]
- *		|
- *		v
- *      Open old VSM,
- *	check pid	--------> exit/fail (-n message)
- *		|
- *		+<----------------------+
- *		|			^
- *		v			|
- *	Create new VSM			|
- *		|			|
- *		v			|
- *	Init header			|
- *	Alloc VSL			|
- *	Alloc VSC:Main			|
- *	Alloc Args etc.			|
- *		|			|
- *		+<--------------+	|
- *		|		^	|
- *		v		|	|
- *	start worker		|	|
- *		|		|	|
- *		|		|	+<---- worker crash
- *		v		|	^
- *	Reset VSL ptr.		|	|
- *	Reset VSC counters	|	|
- *		|		|	|
- *		+<------+	|	|
- *		|	^	|	|
- *		v	|	|	|
- *	alloc dynamics	|	|	|
- *	free dynamics	|	|	|
- *		|	|	|	|
- *		v	|	|	|
- *		+------>+	|	|
- *		|		|	|
- *		v		|	|
- *	stop worker		|	|
- *		|		|	|
- *		v		|	|
- *	Check consist---------- | ----->+
- *		|		|
- *		v		|
- *	Free dynamics		|
- *		|		|
- *		v		|
- *		+-------------->+
- *
- */
-
-#include "config.h"
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "flopen.h"
-#include "heritage.h"
-#include "vapi/vsc_int.h"
-#include "vapi/vsl_int.h"
-#include "vapi/vsm_int.h"
-#include "vav.h"
-#include "vmb.h"
-#include "vnum.h"
-
-#ifndef MAP_HASSEMAPHORE
-#define MAP_HASSEMAPHORE 0 /* XXX Linux */
-#endif
-
-#ifndef MAP_NOSYNC
-#define MAP_NOSYNC 0 /* XXX Linux */
-#endif
-
-struct VSC_C_main	*VSC_C_main;
-
-static int vsl_fd = -1;
-
-/*--------------------------------------------------------------------
- * Check that we are not started with the same -n argument as an already
- * running varnishd
- */
-
-static void
-vsl_n_check(int fd)
-{
-	struct VSM_head slh;
-	int i;
-	struct stat st;
-	pid_t pid;
-
-	AZ(fstat(fd, &st));
-	if (!S_ISREG(st.st_mode))
-		ARGV_ERR("\tshmlog: Not a file\n");
-
-	/* Test if the SHMFILE is locked by other Varnish */
-	if (fltest(fd, &pid) > 0) {
-		fprintf(stderr,
-			"SHMFILE locked by running varnishd master (pid=%jd)\n",
-			(intmax_t)pid);
-		fprintf(stderr,
-			"(Use unique -n arguments if you want multiple "
-			"instances)\n");
-		exit(2);
-	}
-
-	/* Read owning pid from SHMFILE */
-	memset(&slh, 0, sizeof slh);	/* XXX: for flexelint */
-	i = read(fd, &slh, sizeof slh);
-	if (i != sizeof slh)
-		return;
-	if (slh.magic != VSM_HEAD_MAGIC)
-		return;
-	if (slh.hdrsize != sizeof slh)
-		return;
-	if (slh.master_pid != 0 && !kill(slh.master_pid, 0)) {
-		fprintf(stderr,
-			"WARNING: Taking over SHMFILE marked as owned by "
-			"running process (pid=%jd)\n",
-			(intmax_t)slh.master_pid);
-	}
-}
-
-/*--------------------------------------------------------------------
- * Build a new shmlog file
- */
-
-static void
-vsl_buildnew(const char *fn, unsigned size, int fill)
-{
-	struct VSM_head slh;
-	int i;
-	unsigned u;
-	char buf[64*1024];
-	int flags;
-
-	(void)unlink(fn);
-	vsl_fd = flopen(fn, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0644);
-	if (vsl_fd < 0) {
-		fprintf(stderr, "Could not create %s: %s\n",
-		    fn, strerror(errno));
-		exit (1);
-	}
-	flags = fcntl(vsl_fd, F_GETFL);
-	assert(flags != -1);
-	flags &= ~O_NONBLOCK;
-	AZ(fcntl(vsl_fd, F_SETFL, flags));
-
-	memset(&slh, 0, sizeof slh);
-	slh.magic = VSM_HEAD_MAGIC;
-	slh.hdrsize = sizeof slh;
-	slh.shm_size = size;
-	i = write(vsl_fd, &slh, sizeof slh);
-	xxxassert(i == sizeof slh);
-
-	if (fill) {
-		memset(buf, 0, sizeof buf);
-		for (u = sizeof slh; u < size; ) {
-			i = write(vsl_fd, buf, sizeof buf);
-			if (i <= 0) {
-				fprintf(stderr, "Write error %s: %s\n",
-				    fn, strerror(errno));
-				exit (1);
-			}
-			u += i;
-		}
-	}
-
-	AZ(ftruncate(vsl_fd, (off_t)size));
-}
-
-/*--------------------------------------------------------------------
- * Exit handler that clears the owning pid from the SHMLOG
- */
-
-static
-void
-mgt_shm_atexit(void)
-{
-	if (getpid() == VSM_head->master_pid)
-		VSM_head->master_pid = 0;
-}
-
-void
-mgt_SHM_Init(const char *l_arg)
-{
-	int i, fill;
-	struct params *pp;
-	const char *q;
-	uintmax_t size, s1, s2, ps;
-	char **av, **ap;
-	uint32_t *vsl_log_start;
-
-	if (l_arg == NULL)
-		l_arg = "";
-
-	av = VAV_Parse(l_arg, NULL, ARGV_COMMA);
-	AN(av);
-	if (av[0] != NULL)
-		ARGV_ERR("\t-l ...: %s", av[0]);
-
-	ap = av + 1;
-
-	/* Size of SHMLOG */
-	if (*ap != NULL && **ap != '\0') {
-		q = VNUM_2bytes(*ap, &s1, 0);
-		if (q != NULL)
-			ARGV_ERR("\t-l[1] ...:  %s\n", q);
-	} else {
-		s1 = 80 * 1024 * 1024;
-	}
-	if (*ap != NULL)
-		ap++;
-
-	/* Size of space for other stuff */
-	if (*ap != NULL && **ap != '\0') {
-		q = VNUM_2bytes(*ap, &s2, 0);
-		if (q != NULL)
-			ARGV_ERR("\t-l[2] ...:  %s\n", q);
-	} else {
-		s2 = 1024 * 1024;
-	}
-	if (*ap != NULL)
-		ap++;
-
-	/* Fill or not ? */
-	if (*ap != NULL) {
-		if (**ap == '\0')
-			fill = 1;
-		else if (!strcmp(*ap, "-"))
-			fill = 0;
-		else if (!strcmp(*ap, "+"))
-			fill = 1;
-		else
-			ARGV_ERR("\t-l[3] ...:  Must be \"-\" or \"+\"\n");
-		ap++;
-	} else {
-		fill = 1;
-	}
-
-	if (*ap != NULL)
-		ARGV_ERR("\t-l ...:  Too many sub-args\n");
-
-	VAV_Free(av);
-
-	size = s1 + s2;
-	ps = getpagesize();
-	size += ps - 1;
-	size &= ~(ps - 1);
-
-	i = open(VSM_FILENAME, O_RDWR, 0644);
-	if (i >= 0) {
-		vsl_n_check(i);
-		(void)close(i);
-	}
-	vsl_buildnew(VSM_FILENAME, size, fill);
-
-	VSM_head = (void *)mmap(NULL, size,
-	    PROT_READ|PROT_WRITE,
-	    MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
-	    vsl_fd, 0);
-	VSM_head->master_pid = getpid();
-	AZ(atexit(mgt_shm_atexit));
-	xxxassert(VSM_head != MAP_FAILED);
-	(void)mlock((void*)VSM_head, size);
-
-	memset(&VSM_head->head, 0, sizeof VSM_head->head);
-	VSM_head->head.magic = VSM_CHUNK_MAGIC;
-	VSM_head->head.len =
-	    (uint8_t*)(VSM_head) + size - (uint8_t*)&VSM_head->head;
-	bprintf(VSM_head->head.class, "%s", VSM_CLASS_FREE);
-	VWMB();
-
-	vsm_end = (void*)((uint8_t*)VSM_head + size);
-
-	VSC_C_main = VSM_Alloc(sizeof *VSC_C_main,
-	    VSC_CLASS, VSC_TYPE_MAIN, "");
-	AN(VSC_C_main);
-
-	pp = VSM_Alloc(sizeof *pp, VSM_CLASS_PARAM, "", "");
-	AN(pp);
-	*pp = *params;
-	params = pp;
-
-	vsl_log_start = VSM_Alloc(s1, VSL_CLASS, "", "");
-	AN(vsl_log_start);
-	vsl_log_start[1] = VSL_ENDMARKER;
-	VWMB();
-
-	do
-		*vsl_log_start = random() & 0xffff;
-	while (*vsl_log_start == 0);
-
-	VWMB();
-
-	do
-		VSM_head->alloc_seq = random();
-	while (VSM_head->alloc_seq == 0);
-
-}
-
-void
-mgt_SHM_Pid(void)
-{
-
-	VSM_head->master_pid = getpid();
-}
diff --git a/bin/varnishd/mgt_vcc.c b/bin/varnishd/mgt_vcc.c
deleted file mode 100644
index 5901408..0000000
--- a/bin/varnishd/mgt_vcc.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * VCL compiler stuff
- */
-
-#include "config.h"
-
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mgt.h"
-
-#include "libvcl.h"
-#include "vcl.h"
-#include "vcli.h"
-#include "vcli_priv.h"
-#include "vfil.h"
-#include "vsub.h"
-
-#include "mgt_cli.h"
-
-struct vclprog {
-	VTAILQ_ENTRY(vclprog)	list;
-	char			*name;
-	char			*fname;
-	int			active;
-};
-
-static VTAILQ_HEAD(, vclprog) vclhead = VTAILQ_HEAD_INITIALIZER(vclhead);
-
-char *mgt_cc_cmd;
-const char *mgt_vcl_dir;
-const char *mgt_vmod_dir;
-unsigned mgt_vcc_err_unref;
-
-static struct vcc *vcc;
-
-/*--------------------------------------------------------------------*/
-
-static const char * const default_vcl =
-#include "default_vcl.h"
-    ""	;
-
-/*--------------------------------------------------------------------
- * Prepare the compiler command line
- */
-static struct vsb *
-mgt_make_cc_cmd(const char *sf, const char *of)
-{
-	struct vsb *sb;
-	int pct;
-	char *p;
-
-	sb = VSB_new_auto();
-	XXXAN(sb);
-	for (p = mgt_cc_cmd, pct = 0; *p; ++p) {
-		if (pct) {
-			switch (*p) {
-			case 's':
-				VSB_cat(sb, sf);
-				break;
-			case 'o':
-				VSB_cat(sb, of);
-				break;
-			case '%':
-				VSB_putc(sb, '%');
-				break;
-			default:
-				VSB_putc(sb, '%');
-				VSB_putc(sb, *p);
-				break;
-			}
-			pct = 0;
-		} else if (*p == '%') {
-			pct = 1;
-		} else {
-			VSB_putc(sb, *p);
-		}
-	}
-	if (pct)
-		VSB_putc(sb, '%');
-	AZ(VSB_finish(sb));
-	return (sb);
-}
-
-/*--------------------------------------------------------------------
- * Invoke system VCC compiler in a sub-process
- */
-
-struct vcc_priv {
-	unsigned	magic;
-#define VCC_PRIV_MAGIC	0x70080cb8
-	char		*sf;
-	const char	*vcl;
-};
-
-static void
-run_vcc(void *priv)
-{
-	char *csrc;
-	struct vsb *sb;
-	struct vcc_priv *vp;
-	int fd, i, l;
-
-	CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
-	sb = VSB_new_auto();
-	XXXAN(sb);
-	VCC_VCL_dir(vcc, mgt_vcl_dir);
-	VCC_VMOD_dir(vcc, mgt_vmod_dir);
-	VCC_Err_Unref(vcc, mgt_vcc_err_unref);
-	csrc = VCC_Compile(vcc, sb, vp->vcl);
-	AZ(VSB_finish(sb));
-	if (VSB_len(sb))
-		printf("%s", VSB_data(sb));
-	VSB_delete(sb);
-	if (csrc == NULL)
-		exit (1);
-
-	fd = open(vp->sf, O_WRONLY);
-	if (fd < 0) {
-		fprintf(stderr, "Cannot open %s", vp->sf);
-		exit (1);
-	}
-	l = strlen(csrc);
-	i = write(fd, csrc, l);
-	if (i != l) {
-		fprintf(stderr, "Cannot write %s", vp->sf);
-		exit (1);
-	}
-	AZ(close(fd));
-	free(csrc);
-	exit (0);
-}
-
-/*--------------------------------------------------------------------
- * Invoke system C compiler in a sub-process
- */
-
-static void
-run_cc(void *priv)
-{
-	(void)execl("/bin/sh", "/bin/sh", "-c", priv, NULL);
-}
-
-/*--------------------------------------------------------------------
- * Attempt to open compiled VCL in a sub-process
- */
-
-static void __match_proto__(sub_func_f)
-run_dlopen(void *priv)
-{
-	const char *of;
-	void *dlh;
-	struct VCL_conf const *cnf;
-
-	of = priv;
-
-	/* Try to load the object into the management process */
-	if ((dlh = dlopen(of, RTLD_NOW | RTLD_LOCAL)) == NULL) {
-		fprintf(stderr,
-		    "Compiled VCL program failed to load:\n  %s\n",
-		    dlerror());
-		exit(1);
-	}
-
-	cnf = dlsym(dlh, "VCL_conf");
-	if (cnf == NULL) {
-		fprintf(stderr, "Compiled VCL program, metadata not found\n");
-		exit(1);
-	}
-
-	if (cnf->magic != VCL_CONF_MAGIC) {
-		fprintf(stderr, "Compiled VCL program, mangled metadata\n");
-		exit(1);
-	}
-
-	if (dlclose(dlh)) {
-		fprintf(stderr,
-		    "Compiled VCL program failed to unload:\n  %s\n",
-		    dlerror());
-		exit(1);
-	}
-	exit(0);
-}
-
-/*--------------------------------------------------------------------
- * Compile a VCL program, return shared object, errors in sb.
- */
-
-static char *
-mgt_run_cc(const char *vcl, struct vsb *sb, int C_flag)
-{
-	char *csrc;
-	struct vsb *cmdsb;
-	char sf[] = "./vcl.########.c";
-	char of[sizeof sf + 1];
-	char *retval;
-	int sfd, i;
-	struct vcc_priv vp;
-
-	/* Create temporary C source file */
-	sfd = VFIL_tmpfile(sf);
-	if (sfd < 0) {
-		VSB_printf(sb, "Failed to create %s: %s", sf, strerror(errno));
-		return (NULL);
-	}
-	AZ(close(sfd));
-
-	/* Run the VCC compiler in a sub-process */
-	memset(&vp, 0, sizeof vp);
-	vp.magic = VCC_PRIV_MAGIC;
-	vp.sf = sf;
-	vp.vcl = vcl;
-	if (VSUB_run(sb, run_vcc, &vp, "VCC-compiler", -1)) {
-		(void)unlink(sf);
-		return (NULL);
-	}
-
-	if (C_flag) {
-		csrc = VFIL_readfile(NULL, sf, NULL);
-		XXXAN(csrc);
-		(void)fputs(csrc, stdout);
-		free(csrc);
-	}
-
-	/* Name the output shared library by "s/[.]c$/[.]so/" */
-	memcpy(of, sf, sizeof sf);
-	assert(sf[sizeof sf - 2] == 'c');
-	of[sizeof sf - 2] = 's';
-	of[sizeof sf - 1] = 'o';
-	of[sizeof sf] = '\0';
-
-	/* Build the C-compiler command line */
-	cmdsb = mgt_make_cc_cmd(sf, of);
-
-	/* Run the C-compiler in a sub-shell */
-	i = VSUB_run(sb, run_cc, VSB_data(cmdsb), "C-compiler", 10);
-
-	(void)unlink(sf);
-	VSB_delete(cmdsb);
-
-	if (!i)
-		i = VSUB_run(sb, run_dlopen, of, "dlopen", 10);
-
-	if (i) {
-		(void)unlink(of);
-		return (NULL);
-	}
-
-	retval = strdup(of);
-	XXXAN(retval);
-	return (retval);
-}
-
-/*--------------------------------------------------------------------*/
-
-static char *
-mgt_VccCompile(struct vsb **sb, const char *b, int C_flag)
-{
-	char *vf;
-
-	*sb = VSB_new_auto();
-	XXXAN(*sb);
-	vf = mgt_run_cc(b, *sb, C_flag);
-	AZ(VSB_finish(*sb));
-	return (vf);
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct vclprog *
-mgt_vcc_add(const char *name, char *file)
-{
-	struct vclprog *vp;
-
-	vp = calloc(sizeof *vp, 1);
-	XXXAN(vp);
-	vp->name = strdup(name);
-	XXXAN(vp->name);
-	vp->fname = file;
-	VTAILQ_INSERT_TAIL(&vclhead, vp, list);
-	return (vp);
-}
-
-static void
-mgt_vcc_del(struct vclprog *vp)
-{
-	VTAILQ_REMOVE(&vclhead, vp, list);
-	printf("unlink %s\n", vp->fname);
-	XXXAZ(unlink(vp->fname));
-	free(vp->fname);
-	free(vp->name);
-	free(vp);
-}
-
-static struct vclprog *
-mgt_vcc_byname(const char *name)
-{
-	struct vclprog *vp;
-
-	VTAILQ_FOREACH(vp, &vclhead, list)
-		if (!strcmp(name, vp->name))
-			return (vp);
-	return (NULL);
-}
-
-
-static int
-mgt_vcc_delbyname(const char *name)
-{
-	struct vclprog *vp;
-
-	vp = mgt_vcc_byname(name);
-	if (vp != NULL) {
-		mgt_vcc_del(vp);
-		return (0);
-	}
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-mgt_vcc_default(const char *b_arg, const char *f_arg, char *vcl, int C_flag)
-{
-	char *vf;
-	struct vsb *sb;
-	struct vclprog *vp;
-	char buf[BUFSIZ];
-
-	/* XXX: annotate vcl with -b/-f arg so people know where it came from */
-	(void)f_arg;
-
-	if (b_arg != NULL) {
-		AZ(vcl);
-		/*
-		 * XXX: should do a "HEAD /" on the -b argument to see that
-		 * XXX: it even works.  On the other hand, we should do that
-		 * XXX: for all backends in the cache process whenever we
-		 * XXX: change config, but for a complex VCL, it might not be
-		 * XXX: a bug for a backend to not reply at that time, so then
-		 * XXX: again: we should check it here in the "trivial" case.
-		 */
-		bprintf(buf,
-		    "backend default {\n"
-		    "    .host = \"%s\";\n"
-		    "}\n", b_arg);
-		vcl = strdup(buf);
-		AN(vcl);
-	}
-	strcpy(buf, "boot");
-
-	vf = mgt_VccCompile(&sb, vcl, C_flag);
-	free(vcl);
-	if (VSB_len(sb) > 0)
-		fprintf(stderr, "%s", VSB_data(sb));
-	VSB_delete(sb);
-	if (C_flag) {
-		if (vf != NULL)
-			AZ(unlink(vf));
-		return (0);
-	}
-	if (vf == NULL) {
-		fprintf(stderr, "\nVCL compilation failed\n");
-		return (1);
-	}
-	vp = mgt_vcc_add(buf, vf);
-	vp->active = 1;
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-mgt_has_vcl()
-{
-
-	return (!VTAILQ_EMPTY(&vclhead));
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-mgt_push_vcls_and_start(unsigned *status, char **p)
-{
-	struct vclprog *vp;
-
-	VTAILQ_FOREACH(vp, &vclhead, list) {
-		if (mgt_cli_askchild(status, p,
-		    "vcl.load \"%s\" %s\n", vp->name, vp->fname))
-			return (1);
-		free(*p);
-		if (!vp->active)
-			continue;
-		if (mgt_cli_askchild(status, p,
-		    "vcl.use \"%s\"\n", vp->name))
-			return (1);
-		free(*p);
-	}
-	if (mgt_cli_askchild(status, p, "start\n"))
-		return (1);
-	free(*p);
-	*p = NULL;
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static
-void
-mgt_vcc_atexit(void)
-{
-	struct vclprog *vp;
-
-	if (getpid() != mgt_pid)
-		return;
-	while (1) {
-		vp = VTAILQ_FIRST(&vclhead);
-		if (vp == NULL)
-			break;
-		(void)unlink(vp->fname);
-		VTAILQ_REMOVE(&vclhead, vp, list);
-	}
-}
-
-void
-mgt_vcc_init(void)
-{
-
-	vcc = VCC_New();
-	AN(vcc);
-	VCC_Default_VCL(vcc, default_vcl);
-	AZ(atexit(mgt_vcc_atexit));
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-mcf_config_inline(struct cli *cli, const char * const *av, void *priv)
-{
-	char *vf, *p = NULL;
-	struct vsb *sb;
-	unsigned status;
-	struct vclprog *vp;
-
-	(void)priv;
-
-	vp = mgt_vcc_byname(av[2]);
-	if (vp != NULL) {
-		VCLI_Out(cli, "Already a VCL program named %s", av[2]);
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-
-	vf = mgt_VccCompile(&sb, av[3], 0);
-	if (VSB_len(sb) > 0)
-		VCLI_Out(cli, "%s\n", VSB_data(sb));
-	VSB_delete(sb);
-	if (vf == NULL) {
-		VCLI_Out(cli, "VCL compilation failed");
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-	VCLI_Out(cli, "VCL compiled.");
-	if (child_pid >= 0 &&
-	    mgt_cli_askchild(&status, &p, "vcl.load %s %s\n", av[2], vf)) {
-		VCLI_SetResult(cli, status);
-		VCLI_Out(cli, "%s", p);
-	} else {
-		(void)mgt_vcc_add(av[2], vf);
-	}
-	free(p);
-}
-
-void
-mcf_config_load(struct cli *cli, const char * const *av, void *priv)
-{
-	char *vf, *vcl;
-	struct vsb *sb;
-	unsigned status;
-	char *p = NULL;
-	struct vclprog *vp;
-
-	(void)priv;
-	vp = mgt_vcc_byname(av[2]);
-	if (vp != NULL) {
-		VCLI_Out(cli, "Already a VCL program named %s", av[2]);
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-
-	vcl = VFIL_readfile(mgt_vcl_dir, av[3], NULL);
-	if (vcl == NULL) {
-		VCLI_Out(cli, "Cannot open '%s'", av[3]);
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-
-	vf = mgt_VccCompile(&sb, vcl, 0);
-	free(vcl);
-
-	if (VSB_len(sb) > 0)
-		VCLI_Out(cli, "%s", VSB_data(sb));
-	VSB_delete(sb);
-	if (vf == NULL) {
-		VCLI_Out(cli, "VCL compilation failed");
-		VCLI_SetResult(cli, CLIS_PARAM);
-		return;
-	}
-	VCLI_Out(cli, "VCL compiled.");
-	if (child_pid >= 0 &&
-	    mgt_cli_askchild(&status, &p, "vcl.load %s %s\n", av[2], vf)) {
-		VCLI_SetResult(cli, status);
-		VCLI_Out(cli, "%s", p);
-	} else {
-		(void)mgt_vcc_add(av[2], vf);
-	}
-	free(p);
-}
-
-static struct vclprog *
-mcf_find_vcl(struct cli *cli, const char *name)
-{
-	struct vclprog *vp;
-
-	vp = mgt_vcc_byname(name);
-	if (vp != NULL)
-		return (vp);
-	VCLI_SetResult(cli, CLIS_PARAM);
-	VCLI_Out(cli, "No configuration named %s known.", name);
-	return (NULL);
-}
-
-void
-mcf_config_use(struct cli *cli, const char * const *av, void *priv)
-{
-	unsigned status;
-	char *p = NULL;
-	struct vclprog *vp;
-
-	(void)priv;
-	vp = mcf_find_vcl(cli, av[2]);
-	if (vp == NULL)
-		return;
-	if (vp->active != 0)
-		return;
-	if (child_pid >= 0 &&
-	    mgt_cli_askchild(&status, &p, "vcl.use %s\n", av[2])) {
-		VCLI_SetResult(cli, status);
-		VCLI_Out(cli, "%s", p);
-	} else {
-		vp->active = 2;
-		VTAILQ_FOREACH(vp, &vclhead, list) {
-			if (vp->active == 1)
-				vp->active = 0;
-			else if (vp->active == 2)
-				vp->active = 1;
-		}
-	}
-	free(p);
-}
-
-void
-mcf_config_discard(struct cli *cli, const char * const *av, void *priv)
-{
-	unsigned status;
-	char *p = NULL;
-	struct vclprog *vp;
-
-	(void)priv;
-	vp = mcf_find_vcl(cli, av[2]);
-	if (vp != NULL && vp->active) {
-		VCLI_SetResult(cli, CLIS_PARAM);
-		VCLI_Out(cli, "Cannot discard active VCL program\n");
-	} else if (vp != NULL) {
-		if (child_pid >= 0 &&
-		    mgt_cli_askchild(&status, &p,
-		    "vcl.discard %s\n", av[2])) {
-			VCLI_SetResult(cli, status);
-			VCLI_Out(cli, "%s", p);
-		} else {
-			AZ(mgt_vcc_delbyname(av[2]));
-		}
-	}
-	free(p);
-}
-
-void
-mcf_config_list(struct cli *cli, const char * const *av, void *priv)
-{
-	unsigned status;
-	char *p;
-	const char *flg;
-	struct vclprog *vp;
-
-	(void)av;
-	(void)priv;
-	if (child_pid >= 0) {
-		if (!mgt_cli_askchild(&status, &p, "vcl.list\n")) {
-			VCLI_SetResult(cli, status);
-			VCLI_Out(cli, "%s", p);
-		}
-		free(p);
-	} else {
-		VTAILQ_FOREACH(vp, &vclhead, list) {
-			if (vp->active) {
-				flg = "active";
-			} else
-				flg = "available";
-			VCLI_Out(cli, "%-10s %6s %s\n",
-			    flg, "N/A", vp->name);
-		}
-	}
-}
-
-/*
- * XXX: This should take an option argument to show all (include) files
- * XXX: This violates the principle of not loading VCL's in the master
- * XXX: process.
- */
-void
-mcf_config_show(struct cli *cli, const char * const *av, void *priv)
-{
-	struct vclprog *vp;
-	void *dlh, *sym;
-	const char **src;
-
-	(void)priv;
-	if ((vp = mcf_find_vcl(cli, av[2])) != NULL) {
-		if ((dlh = dlopen(vp->fname, RTLD_NOW | RTLD_LOCAL)) == NULL) {
-			VCLI_Out(cli, "failed to load %s: %s\n",
-			    vp->name, dlerror());
-			VCLI_SetResult(cli, CLIS_CANT);
-		} else if ((sym = dlsym(dlh, "srcbody")) == NULL) {
-			VCLI_Out(cli, "failed to locate source for %s: %s\n",
-			    vp->name, dlerror());
-			VCLI_SetResult(cli, CLIS_CANT);
-			AZ(dlclose(dlh));
-		} else {
-			src = sym;
-			VCLI_Out(cli, "%s", src[0]);
-			/* VCLI_Out(cli, src[1]); */
-			AZ(dlclose(dlh));
-		}
-	}
-}
diff --git a/bin/varnishd/storage/stevedore_utils.c b/bin/varnishd/storage/stevedore_utils.c
index 3daebf8..7e9c7d5 100644
--- a/bin/varnishd/storage/stevedore_utils.c
+++ b/bin/varnishd/storage/stevedore_utils.c
@@ -49,7 +49,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "mgt.h"
+#include "mgt/mgt.h"
 
 #include "storage/storage.h"
 #include "vnum.h"
diff --git a/bin/varnishd/varnishd.c b/bin/varnishd/varnishd.c
index e0654a3..e0ba759 100644
--- a/bin/varnishd/varnishd.c
+++ b/bin/varnishd/varnishd.c
@@ -43,7 +43,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#include "mgt.h"
+#include "mgt/mgt.h"
 
 #include "hash/hash_slinger.h"
 #include "heritage.h"



More information about the varnish-commit mailing list