[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