From: phk Date: Fri, 21 Nov 2008 09:50:22 +0000 (+0000) Subject: Move the code for running stuff in a sub-process out to a library X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dbd2cfe6e657ddcfb800e3319d21a402fcad19b4;p=varnish Move the code for running stuff in a sub-process out to a library function, and give it the ability to limit how many lines of output we get back from the subprocess, in order to muzzle the C-compiler somewhat. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3413 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/mgt_vcc.c b/varnish-cache/bin/varnishd/mgt_vcc.c index 4c122f95..14f53d06 100644 --- a/varnish-cache/bin/varnishd/mgt_vcc.c +++ b/varnish-cache/bin/varnishd/mgt_vcc.c @@ -47,7 +47,6 @@ #include "compat/asprintf.h" #endif #include "vsb.h" -#include "vlu.h" #include "vqueue.h" @@ -124,16 +123,13 @@ mgt_make_cc_cmd(struct vsb *sb, const char *sf, const char *of) * Errors goes in sb; */ -static int -mgt_cc_vlu(void *priv, const char *str) +static void +run_cc(void *priv) { - struct vsb *vsb; - - vsb = priv; - vsb_printf(vsb, "C-compiler said: %s\n", str); - return (0); + (void)execl("/bin/sh", "/bin/sh", "-c", priv, NULL); } + static char * mgt_run_cc(const char *source, struct vsb *sb) { @@ -142,10 +138,8 @@ mgt_run_cc(const char *source, struct vsb *sb) char sf[] = "./vcl.########.c"; char of[sizeof sf + 1]; char *retval; - int rv, p[2], sfd, srclen, status; - pid_t pid; + int sfd, srclen; void *dlh; - struct vlu *vlu; /* Create temporary C source file */ sfd = vtmpfile(sf); @@ -178,57 +172,8 @@ mgt_run_cc(const char *source, struct vsb *sb) AZ(vsb_overflowed(&cmdsb)); /* XXX check vsb state */ - if (pipe(p) < 0) { - vsb_printf(sb, "%s(): pipe() failed: %s", - __func__, strerror(errno)); - (void)unlink(sf); - return (NULL); - } - assert(p[0] > STDERR_FILENO); - assert(p[1] > STDERR_FILENO); - if ((pid = fork()) < 0) { - vsb_printf(sb, "%s(): fork() failed: %s", - __func__, strerror(errno)); - AZ(close(p[0])); - AZ(close(p[1])); + if (SUB_run(sb, run_cc, cmdline, "C-compiler", 10)) { (void)unlink(sf); - return (NULL); - } - if (pid == 0) { - AZ(close(STDIN_FILENO)); - assert(open("/dev/null", O_RDONLY) == STDIN_FILENO); - assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO); - assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO); - /* Close all other fds */ - for (sfd = STDERR_FILENO + 1; sfd < 100; sfd++) - (void)close(sfd); - (void)execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); - _exit(1); - } - AZ(close(p[1])); - vlu = VLU_New(sb, mgt_cc_vlu, 0); - while (!VLU_Fd(p[0], vlu)) - continue; - AZ(close(p[0])); - VLU_Destroy(vlu); - (void)unlink(sf); - do { - rv = waitpid(pid, &status, 0); - if (rv < 0 && errno != EINTR) { - vsb_printf(sb, "%s(): waitpid() failed: %s", - __func__, strerror(errno)); - (void)unlink(of); - return (NULL); - } - } while (rv < 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - vsb_printf(sb, "%s(): Compiler failed", __func__); - if (WIFEXITED(status)) - vsb_printf(sb, ", exit %d", WEXITSTATUS(status)); - if (WIFSIGNALED(status)) - vsb_printf(sb, ", signal %d", WTERMSIG(status)); - if (WCOREDUMP(status)) - vsb_printf(sb, ", core dumped"); (void)unlink(of); return (NULL); } diff --git a/varnish-cache/include/libvarnish.h b/varnish-cache/include/libvarnish.h index 7ef22d1b..c023fbeb 100644 --- a/varnish-cache/include/libvarnish.h +++ b/varnish-cache/include/libvarnish.h @@ -37,6 +37,8 @@ #define NULL ((void*)0) #endif +struct vsb; + /* from libvarnish/argv.c */ void FreeArgv(char **argv); char **ParseArgv(const char *s, int flag); @@ -50,6 +52,10 @@ uint32_t crc32_l(const void *p1, unsigned l); /* from libvarnish/num.c */ const char *str2bytes(const char *p, uintmax_t *r, uintmax_t rel); +/* from libvarnish/subproc.c */ +typedef void sub_func_f(void*); +int SUB_run(struct vsb *sb, sub_func_f *func, void *priv, const char *name, int maxlines); + /* from libvarnish/tcp.c */ /* NI_MAXHOST and NI_MAXSERV are ridiculously long for numeric format */ #define TCP_ADDRBUFSIZE 64 diff --git a/varnish-cache/lib/libvarnish/Makefile.am b/varnish-cache/lib/libvarnish/Makefile.am index 4ac60d2f..a8d4b0c9 100644 --- a/varnish-cache/lib/libvarnish/Makefile.am +++ b/varnish-cache/lib/libvarnish/Makefile.am @@ -10,6 +10,7 @@ libvarnish_la_SOURCES = \ argv.c \ assert.c \ binary_heap.c \ + subproc.c \ cli.c \ cli_common.c \ crc32.c \ diff --git a/varnish-cache/lib/libvarnish/subproc.c b/varnish-cache/lib/libvarnish/subproc.c new file mode 100644 index 00000000..e5dd7581 --- /dev/null +++ b/varnish-cache/lib/libvarnish/subproc.c @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006-2008 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * 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. + * + * $Id$ + * + * Run stuff in a child process + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "vsb.h" +#include "vlu.h" +#include "libvarnish.h" + +struct sub_priv { + const char *name; + struct vsb *sb; + int lines; + int maxlines; +}; + +static int +sub_vlu(void *priv, const char *str) +{ + struct sub_priv *sp; + + sp = priv; + if (!sp->lines++) + vsb_printf(sp->sb, "Message from %s:\n", sp->name); + if (sp->maxlines > 0 && sp->lines <= sp->maxlines) + vsb_printf(sp->sb, "%s\n", str); + return (0); +} + +int +SUB_run(struct vsb *sb, sub_func_f *func, void *priv, const char *name, int maxlines) +{ + int rv, p[2], sfd, status; + pid_t pid; + struct vlu *vlu; + struct sub_priv sp; + + sp.sb = sb; + sp.name = name; + sp.lines = 0; + sp.maxlines = maxlines; + + if (pipe(p) < 0) { + vsb_printf(sb, "Starting %s: pipe() failed: %s", + name, strerror(errno)); + return (-1); + } + assert(p[0] > STDERR_FILENO); + assert(p[1] > STDERR_FILENO); + if ((pid = fork()) < 0) { + vsb_printf(sb, "Starting %s: fork() failed: %s", + name, strerror(errno)); + AZ(close(p[0])); + AZ(close(p[1])); + return (-1); + } + if (pid == 0) { + AZ(close(STDIN_FILENO)); + assert(open("/dev/null", O_RDONLY) == STDIN_FILENO); + assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO); + assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO); + /* Close all other fds */ + for (sfd = STDERR_FILENO + 1; sfd < 100; sfd++) + (void)close(sfd); + func(priv); + _exit(1); + } + AZ(close(p[1])); + vlu = VLU_New(&sp, sub_vlu, 0); + while (!VLU_Fd(p[0], vlu)) + continue; + AZ(close(p[0])); + VLU_Destroy(vlu); + if (sp.lines > sp.maxlines) + vsb_printf(sb, "[%d lines truncated]\n", + sp.lines - sp.maxlines); + do { + rv = waitpid(pid, &status, 0); + if (rv < 0 && errno != EINTR) { + vsb_printf(sb, "Running %s: waitpid() failed: %s", + name, strerror(errno)); + return (-1); + } + } while (rv < 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + vsb_printf(sb, "Running %s failed", name); + if (WIFEXITED(status)) + vsb_printf(sb, ", exit %d", WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + vsb_printf(sb, ", signal %d", WTERMSIG(status)); + if (WCOREDUMP(status)) + vsb_printf(sb, ", core dumped"); + return (-1); + } + return (0); +}