From: phk Date: Mon, 20 Aug 2007 10:21:07 +0000 (+0000) Subject: Make the C-compiler command a paramter, and generally clean up the X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0c8d2e18ed3a36fe40efb2e2516da9fb433072a;p=varnish Make the C-compiler command a paramter, and generally clean up the code that invokes it. If fmtcheck(3) is available, we refuse pedal target practice. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1882 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/mgt.h b/varnish-cache/bin/varnishd/mgt.h index afd8fb4c..3224d7e4 100644 --- a/varnish-cache/bin/varnishd/mgt.h +++ b/varnish-cache/bin/varnishd/mgt.h @@ -60,6 +60,7 @@ void MCF_ParamSet(struct cli *, const char *param, const char *val); void mgt_vcc_init(void); int mgt_vcc_default(const char *bflag, const char *fflag, int f_fd, int Cflag); int mgt_push_vcls_and_start(unsigned *status, char **p); +extern char *mgt_cc_cmd; #include "hash_slinger.h" diff --git a/varnish-cache/bin/varnishd/mgt_param.c b/varnish-cache/bin/varnishd/mgt_param.c index d400d99c..5d8ba53c 100644 --- a/varnish-cache/bin/varnishd/mgt_param.c +++ b/varnish-cache/bin/varnishd/mgt_param.c @@ -527,6 +527,30 @@ tweak_ping_interval(struct cli *cli, struct parspec *par, const char *arg) /*--------------------------------------------------------------------*/ +static void +tweak_cc_command(struct cli *cli, struct parspec *par, const char *arg) +{ + + (void)par; + if (arg == NULL) { + cli_out(cli, "%s", mgt_cc_cmd); + } else { +#if defined(HAVE_FMTCHECK) + if (arg != fmtcheck(arg, "%s %s")) { + cli_out(cli, + "Parameter has dangerous %%-string expansions."); + cli_result(cli, CLIS_PARAM); + return; + } +#endif + free(mgt_cc_cmd); + mgt_cc_cmd = strdup(arg); + XXXAN(mgt_cc_cmd); + } +} + +/*--------------------------------------------------------------------*/ + /* * Make sure to end all lines with either a space or newline of the * formatting will go haywire. @@ -539,6 +563,10 @@ tweak_ping_interval(struct cli *cli, struct parspec *par, const char *arg) "\nNB: This parameter will not take any effect until the " \ "child process has been restarted.\n" +#define MUST_RELOAD \ + "\nNB: This parameter will not take any effect until the " \ + "VCL programs have been reloaded.\n" + #define EXPERIMENTAL \ "\nNB: We don't know yet if it is a good idea to change " \ "this parameter. Caution advised.\n" @@ -700,6 +728,20 @@ static struct parspec parspec[] = { "it possible to attach a debugger to the child.\n" MUST_RESTART, "3", "seconds" }, + { "cc_command", tweak_cc_command, + "Command used for compiling the C source code to a " + "dlopen(3) loadable object.\n" + "NB: The string must contain two %%s sequences which " + "will be replaced by the binary and source file names " + "respectively.\n" + MUST_RELOAD, +#ifdef __APPLE__ + "exec cc -dynamiclib -Wl,-undefined,dynamic_lookup -o %s -x c" + " - < %s" +#else + "exec cc -nostdinc -fpic -shared -Wl,-x -o %s -x c - < %s" +#endif + , NULL }, { NULL, NULL, NULL } }; diff --git a/varnish-cache/bin/varnishd/mgt_vcc.c b/varnish-cache/bin/varnishd/mgt_vcc.c index efe95949..2b34509b 100644 --- a/varnish-cache/bin/varnishd/mgt_vcc.c +++ b/varnish-cache/bin/varnishd/mgt_vcc.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef HAVE_ASPRINTF #include "compat/asprintf.h" @@ -65,6 +66,8 @@ struct vclprog { static TAILQ_HEAD(, vclprog) vclhead = TAILQ_HEAD_INITIALIZER(vclhead); +char *mgt_cc_cmd; + /*--------------------------------------------------------------------*/ /* keep this in synch with man/vcl.7 */ @@ -148,8 +151,9 @@ mgt_CallCc(const char *source, struct vsb *sb) FILE *fo, *fs; char sf[] = "./vcl.XXXXXXXX"; char *of; - char buf[BUFSIZ]; - int i, j, len, sfd; + struct vsb *cccmd; + char buf[128]; + int i, j, sfd; void *p; /* Create temporary C source file */ @@ -161,7 +165,7 @@ mgt_CallCc(const char *source, struct vsb *sb) return (NULL); } fs = fdopen(sfd, "r+"); - AN(fs); + XXXAN(fs); if (fputs(source, fs) < 0 || fflush(fs)) { vsb_printf(sb, @@ -173,55 +177,92 @@ mgt_CallCc(const char *source, struct vsb *sb) } rewind(fs); - /* Name the output shared library */ + /* Name the output shared library by brutally overwriting "./vcl." */ of = strdup(sf); - AN(of); + XXXAN(of); memcpy(of, "./bin", 5); - /* Attempt to open a pipe to the system C-compiler */ - len = snprintf(buf, sizeof buf, - "ln -f %s _.c ;" /* XXX: for debugging */ -#ifdef __APPLE__ - "exec cc -dynamiclib -Wl,-undefined,dynamic_lookup -o %s -x c - < %s 2>&1", -#else - "env -i cc -nostdinc -fpic -shared -Wl,-x -o %s -x c - < %s 2>&1", -#endif - sf, of, sf); - xxxassert(len < sizeof buf); - - fo = popen(buf, "r"); + cccmd = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); + XXXAN(cccmd); + + /* + * Attempt to open a pipe to the system C-compiler. + * ------------------------------------------------ + * + * The arguments to the C-compiler must be whatever it takes to + * create a dlopen(3) compatible object file named $of from a + * source file named $sf. + * + * The source code is entirely selfcontained, so options should be + * specified to prevent the C-compiler from doing any DWITYW + * processing. For GCC this amounts to at least "-nostdinc". + * + * We wrap the entire command in a 'sh -c "..." 2>&1' to get any + * errors from popen(3)'s shell redirected to our stderr as well. + * + */ + vsb_printf(cccmd, "exec /bin/sh -c \"" ); + vsb_printf(cccmd, mgt_cc_cmd, of, sf); + vsb_printf(cccmd, "\" 2>&1"); + vsb_finish(cccmd); + /* XXX: check that vsb is happy about cccmd */ + + fo = popen(vsb_data(cccmd), "r"); if (fo == NULL) { vsb_printf(sb, - "Internal error: Cannot execute cc(1): %s\n", - strerror(errno)); + "System error: Cannot execute C-compiler: %s\n" + "\tcommand attempted: %s\n", + strerror(errno), vsb_data(cccmd)); free(of); unlink(sf); fclose(fs); + vsb_delete(cccmd); return (NULL); } - /* If we get any output, it's bad */ + /* Any output is considered fatal */ j = 0; while (1) { - if (fgets(buf, sizeof buf, fo) == NULL) + i = fread(buf, 1, sizeof buf, fo); + if (i == 0) break; if (!j) { - vsb_printf(sb, "Internal error: cc(1) complained:\n"); + vsb_printf(sb, + "System error:\n" + "C-compiler command complained.\n" + "Command attempted: %s\nMessage:\n", + vsb_data(cccmd)); j++; } - vsb_cat(sb, buf); + vsb_bcat(sb, buf, i); } i = pclose(fo); - if (j == 0 && i != 0) + + unlink(sf); + fclose(fs); + + if (j == 0 && i != 0) { + vsb_printf(sb, + "System error:\n" + "C-compiler command failed"); + if (WIFEXITED(i)) + vsb_printf(sb, ", exit %d", WEXITSTATUS(i)); + if (WIFSIGNALED(i)) + vsb_printf(sb, ", signal %d", WTERMSIG(i)); + if (WCOREDUMP(i)) + vsb_printf(sb, ", core dumped"); vsb_printf(sb, - "Internal error: cc(1) exit status 0x%04x\n", i); + "\nCommand attempted: %s\n", vsb_data(cccmd)); + } + + vsb_delete(cccmd); /* If the compiler complained, or exited non-zero, fail */ if (i || j) { unlink(of); free(of); - of = NULL; + return (NULL); } /* Next, try to load the object into the management process */ @@ -231,13 +272,10 @@ mgt_CallCc(const char *source, struct vsb *sb) dlerror()); unlink(of); free(of); - of = NULL; - } else - (void)dlclose(p); + return (NULL); + } - /* clean up and return */ - unlink(sf); - fclose(fs); + (void)dlclose(p); return (of); }