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 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 int tweak_generic_timeout_double(struct cli *cli, volatile double *dest, const char *arg, double min, double max) { double u; char *p; if (arg != NULL) { p = NULL; u = strtod(arg, &p); if (*arg == '\0' || *p != '\0') { VCLI_Out(cli, "Not a number(%s)\n", arg); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } if (u < min) { VCLI_Out(cli, "Timeout must be greater or equal to %.g\n", min); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } if (u > max) { VCLI_Out(cli, "Timeout must be less than or equal to %.g\n", max); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } *dest = u; } else VCLI_Out(cli, "%.6f", *dest); return (0); }
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); } }
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")) { if (av[2] == NULL || strcmp(av[2], "-j")) 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_destroy(&vsb); VCLI_SetResult(cli, CLIS_COMMS); VCLI_Out(cli, "CLI communication error"); MGT_Child_Cli_Fail(); return; } VSB_destroy(&vsb); if (VCLI_ReadResult(cli_i, &u, &q, mgt_param.cli_timeout)) MGT_Child_Cli_Fail(); VCLI_SetResult(cli, u); VCLI_Out(cli, "%s", q); free(q); }
void tweak_group(struct cli *cli, const struct parspec *par, const char *arg) { struct group *gr; (void)par; if (arg != NULL) { if (*arg != '\0') { gr = getgrnam(arg); if (gr == NULL) { VCLI_Out(cli, "Unknown group"); VCLI_SetResult(cli, CLIS_PARAM); return; } REPLACE(mgt_param.group, gr->gr_name); mgt_param.gid = gr->gr_gid; } else { mgt_param.gid = getgid(); } } else if (mgt_param.group) { VCLI_Out(cli, "%s (%d)", mgt_param.group, (int)mgt_param.gid); } else { VCLI_Out(cli, "GID %d", (int)mgt_param.gid); } }
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_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); } }
void tweak_user(struct cli *cli, const struct parspec *par, const char *arg) { struct passwd *pw; (void)par; if (arg != NULL) { if (*arg != '\0') { pw = getpwnam(arg); if (pw == NULL) { VCLI_Out(cli, "Unknown user"); VCLI_SetResult(cli, CLIS_PARAM); return; } REPLACE(mgt_param.user, pw->pw_name); mgt_param.uid = pw->pw_uid; } else { mgt_param.uid = getuid(); } } else if (mgt_param.user) { VCLI_Out(cli, "%s (%d)", mgt_param.user, (int)mgt_param.uid); } else { VCLI_Out(cli, "UID %d", (int)mgt_param.uid); } }
void WAIT_tweak_waiter(struct cli *cli, const char *arg) { int i; ASSERT_MGT(); if (arg == NULL) { if (waiter == NULL) VCLI_Out(cli, "default"); else VCLI_Out(cli, "%s", waiter->name); VCLI_Out(cli, " ("); for (i = 0; vca_waiters[i] != NULL; i++) VCLI_Out(cli, "%s%s", i == 0 ? "" : ", ", vca_waiters[i]->name); VCLI_Out(cli, ")"); return; } if (!strcmp(arg, "default")) { waiter = NULL; return; } for (i = 0; vca_waiters[i]; i++) { if (!strcmp(arg, vca_waiters[i]->name)) { waiter = vca_waiters[i]; return; } } VCLI_Out(cli, "Unknown waiter"); VCLI_SetResult(cli, CLIS_PARAM); }
mcf_server_start(struct cli *cli, const char * const *av, void *priv) { (void)av; (void)priv; if (child_state == CH_STOPPED) { if (mgt_has_vcl()) { mgt_launch_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]); } }
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()) { mgt_launch_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]); } }
static void tweak_generic_bytes(struct cli *cli, volatile ssize_t *dest, const char *arg, double min, double max) { uintmax_t r; const char *p; if (arg != NULL) { p = VNUM_2bytes(arg, &r, 0); if (p != NULL) { VCLI_Out(cli, "Could not convert to bytes.\n"); VCLI_Out(cli, "%s\n", p); VCLI_Out(cli, " Try something like '80k' or '120M'\n"); VCLI_SetResult(cli, CLIS_PARAM); return; } if ((uintmax_t)((ssize_t)r) != r) { fmt_bytes(cli, r); VCLI_Out(cli, " is too large for this architecture.\n"); VCLI_SetResult(cli, CLIS_PARAM); return; } if (max != 0. && r > max) { VCLI_Out(cli, "Must be no more than "); fmt_bytes(cli, (uintmax_t)max); VCLI_Out(cli, "\n"); VCLI_SetResult(cli, CLIS_PARAM); return; } if (r < min) { VCLI_Out(cli, "Must be at least "); fmt_bytes(cli, (uintmax_t)min); VCLI_Out(cli, "\n"); VCLI_SetResult(cli, CLIS_PARAM); return; } *dest = r; } else { fmt_bytes(cli, *dest); } }
mcf_panic_clear(struct cli *cli, const char * const *av, void *priv) { (void)priv; if (av[2] != NULL && strcmp(av[2], "-z")) { VCLI_SetResult(cli, CLIS_PARAM); VCLI_Out(cli, "Unknown parameter \"%s\".", av[2]); return; } else if (av[2] != NULL) { VSC_C_mgt->child_panic = static_VSC_C_mgt.child_panic = 0; if (child_panic == NULL) return; } if (child_panic == NULL) { VCLI_SetResult(cli, CLIS_CANT); VCLI_Out(cli, "No panic to clear"); return; } mgt_panic_clear(); }
mcf_server_stop(struct cli *cli, const char * const *av, void *priv) { (void)av; (void)priv; if (child_state == CH_RUNNING) { mgt_stop_child(); } else { VCLI_SetResult(cli, CLIS_CANT); VCLI_Out(cli, "Child in state %s", ch_state[child_state]); } }
char * mgt_VccCompile(struct cli *cli, const char *vclname, const char *vclsrc, int C_flag) { struct vcc_priv vp; struct vsb *sb; unsigned status; AN(cli); sb = VSB_new_auto(); XXXAN(sb); INIT_OBJ(&vp, VCC_PRIV_MAGIC); vp.src = vclsrc; VSB_printf(sb, "./vcl_%s.c", vclname); AZ(VSB_finish(sb)); vp.srcfile = strdup(VSB_data(sb)); AN(vp.srcfile); VSB_clear(sb); VSB_printf(sb, "./vcl_%s.so", vclname); AZ(VSB_finish(sb)); vp.libfile = strdup(VSB_data(sb)); AN(vp.srcfile); VSB_clear(sb); status = mgt_vcc_compile(&vp, sb, C_flag); AZ(VSB_finish(sb)); if (VSB_len(sb) > 0) VCLI_Out(cli, "%s", VSB_data(sb)); VSB_delete(sb); (void)unlink(vp.srcfile); free(vp.srcfile); if (status || C_flag) { (void)unlink(vp.libfile); free(vp.libfile); if (!C_flag) { VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); } return(NULL); } VCLI_Out(cli, "VCL compiled.\n"); return (vp.libfile); }
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); }
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)); }
int tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg, unsigned min, unsigned max) { unsigned u; char *p; if (arg != NULL) { p = NULL; if (!strcasecmp(arg, "unlimited")) u = UINT_MAX; else { u = strtoul(arg, &p, 0); if (*arg == '\0' || *p != '\0') { VCLI_Out(cli, "Not a number (%s)\n", arg); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } } if (u < min) { VCLI_Out(cli, "Must be at least %u\n", min); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } if (u > max) { VCLI_Out(cli, "Must be no more than %u\n", max); VCLI_SetResult(cli, CLIS_PARAM); return (-1); } *dest = u; } else if (*dest == UINT_MAX) { VCLI_Out(cli, "unlimited"); } else { VCLI_Out(cli, "%u", *dest); } return (0); }
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; } VJ_master(JAIL_MASTER_FILE); 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); VJ_master(JAIL_MASTER_LOW); return; } VJ_master(JAIL_MASTER_LOW); mgt_got_fd(fd); VCLI_AuthResponse(fd, cli->challenge, buf); AZ(close(fd)); if (strcasecmp(buf, av[2])) { MGT_complain(C_SECURITY, "CLI Authentication failure from %s", cli->ident); VCLI_SetResult(cli, CLIS_CLOSE); return; } cli->auth = MCF_AUTH; memset(cli->challenge, 0, sizeof cli->challenge); VCLI_SetResult(cli, CLIS_OK); mcf_banner(cli, av, priv); }
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); }
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); }
static void mgt_cli_challenge(struct cli *cli) { int i; uint8_t u; AZ(VRND_RandomCrypto(cli->challenge, sizeof cli->challenge - 2)); for (i = 0; i < (sizeof cli->challenge) - 2; i++) { AZ(VRND_RandomCrypto(&u, sizeof u)); cli->challenge[i] = (u % 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); }
void tweak_bool(struct cli *cli, const struct parspec *par, const char *arg) { volatile unsigned *dest; int mode = 0; if (!strcmp(par->def, "off") || !strcmp(par->def, "on")) mode = 1; dest = par->priv; 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, mode ? "use \"on\" or \"off\"\n" : "use \"true\" or \"false\"\n"); VCLI_SetResult(cli, CLIS_PARAM); return; } } else if (mode) { VCLI_Out(cli, *dest ? "on" : "off"); } else { VCLI_Out(cli, *dest ? "true" : "false"); } }
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); } }
static void mgt_launch_child(struct cli *cli) { pid_t pid; unsigned u; char *p; struct vev *e; int i, j, k, cp[2]; struct sigaction sa; if (child_state != CH_STOPPED && child_state != CH_DIED) return; if (!MAC_sockets_ready(cli)) { child_state = CH_STOPPED; if (cli != NULL) { VCLI_SetResult(cli, CLIS_CANT); return; } MGT_complain(C_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_cli_out = cp[1]; /* Open pipe for child->mgr CLI */ AZ(pipe(cp)); heritage.cli_out = cp[1]; mgt_child_inherit(heritage.cli_out, "cli_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]; AN(heritage.vsm); mgt_SHM_Size_Adjust(); AN(heritage.vsm); AN(heritage.param); if ((pid = fork()) < 0) { /* XXX */ 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 all FDs the child shouldn't know about * * We cannot just close these filedescriptors, some random * library routine might miss it later on and wantonly close * a FD we use at that point in time. (See bug #1841). * We close the FD and replace it with /dev/null instead, * That prevents security leakage, and gives the library * code a valid FD to close when it discovers the changed * circumstances. */ closelog(); for (i = STDERR_FILENO + 1; i < CLOSE_FD_UP_TO; i++) { if (vbit_test(fd_map, i)) continue; if (close(i) == 0) { k = open("/dev/null", O_RDONLY); assert(k >= 0); j = dup2(k, i); assert(j == i); AZ(close(k)); } } #ifdef HAVE_SETPROCTITLE setproctitle("Varnish-Chld %s", heritage.name); #endif if (mgt_param.sigsegv_handler) { memset(&sa, 0, sizeof sa); sa.sa_sigaction = child_sigsegv_handler; sa.sa_flags = SA_SIGINFO; (void)sigaction(SIGSEGV, &sa, NULL); (void)sigaction(SIGBUS, &sa, NULL); (void)sigaction(SIGABRT, &sa, NULL); } (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); VJ_subproc(JAIL_SUBPROC_WORKER); child_main(); exit(0); } assert(pid > 1); MGT_complain(C_DEBUG, "Child (%jd) Started", (intmax_t)pid); VSC_C_mgt->child_start = ++static_VSC_C_mgt.child_start; /* Close stuff the child got */ closex(&heritage.std_fd); mgt_child_inherit(heritage.cli_in, NULL); closex(&heritage.cli_in); mgt_child_inherit(heritage.cli_out, NULL); closex(&heritage.cli_out); child_std_vlu = VLU_New(NULL, child_line, 0); AN(child_std_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 (mgt_param.ping_interval > 0) { e = vev_new(); XXXAN(e); e->timeout = mgt_param.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_cli_out); child_pid = pid; if (mgt_push_vcls_and_start(cli, &u, &p)) { VCLI_SetResult(cli, u); MGT_complain(C_ERR, "Child (%jd) Pushing vcls failed:\n%s", (intmax_t)child_pid, p); free(p); child_state = CH_RUNNING; mgt_stop_child(); } else child_state = CH_RUNNING; }
char * mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname, const char *vclsrc, const char *vclsrcfile, int C_flag) { struct vcc_priv vp; struct vsb *sb; unsigned status; char buf[1024]; FILE *fcs; char **av; int ac; AN(cli); sb = VSB_new_auto(); XXXAN(sb); INIT_OBJ(&vp, VCC_PRIV_MAGIC); vp.vclsrc = vclsrc; vp.vclsrcfile = vclsrcfile; /* * The subdirectory must have a unique name to 100% certain evade * the refcounting semantics of dlopen(3). * * Bad implementations of dlopen(3) think the shlib you are opening * is the same, if the filename is the same as one already opened. * * Sensible implementations do a stat(2) and requires st_ino and * st_dev to also match. * * A correct implementation would run on filesystems which tickle * st_gen, and also insist that be the identical, before declaring * a match. * * Since no correct implementations are known to exist, we are subject * to really interesting races if you do something like: * * (running on 'boot' vcl) * vcl.load foo /foo.vcl * vcl.use foo * few/slow requests * vcl.use boot * vcl.discard foo * vcl.load foo /foo.vcl // dlopen(3) says "same-same" * vcl.use foo * * Because discard of the first 'foo' lingers on non-zero reference * count, and when it finally runs, it trashes the second 'foo' because * dlopen(3) decided they were really the same thing. * * The Best way to reproduce this is to have regexps in the VCL. */ VSB_printf(sb, "vcl_%s.%.9f", vclname, VTIM_real()); AZ(VSB_finish(sb)); vp.dir = strdup(VSB_data(sb)); AN(vp.dir); if (VJ_make_subdir(vp.dir, "VCL", cli->sb)) { free(vp.dir); VSB_destroy(&sb); VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); return (NULL); } VSB_clear(sb); VSB_printf(sb, "%s/%s", vp.dir, VGC_SRC); AZ(VSB_finish(sb)); vp.csrcfile = strdup(VSB_data(sb)); AN(vp.csrcfile); VSB_clear(sb); VSB_printf(sb, "%s/%s", vp.dir, VGC_LIB); AZ(VSB_finish(sb)); vp.libfile = strdup(VSB_data(sb)); AN(vp.csrcfile); VSB_clear(sb); status = mgt_vcc_compile(&vp, sb, C_flag); AZ(VSB_finish(sb)); if (VSB_len(sb) > 0) VCLI_Out(cli, "%s", VSB_data(sb)); VSB_destroy(&sb); if (status || C_flag) { (void)unlink(vp.csrcfile); free(vp.csrcfile); (void)unlink(vp.libfile); free(vp.libfile); (void)rmdir(vp.dir); free(vp.dir); if (status) { VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); } return (NULL); } fcs = fopen(vp.csrcfile, "r"); AN(fcs); while (1) { AN(fgets(buf, sizeof buf, fcs)); if (memcmp(buf, VCC_INFO_PREFIX, strlen(VCC_INFO_PREFIX))) break; av = VAV_Parse(buf, &ac, 0); AN(av); AZ(av[0]); AZ(strcmp(av[1], "/*")); AZ(strcmp(av[ac-1], "*/")); if (!strcmp(av[3], "VCL")) mgt_vcl_depends(vcl, av[4]); else if (!strcmp(av[3], "VMOD")) mgt_vcl_vmod(vcl, av[4], av[5]); else WRONG("Wrong VCCINFO"); VAV_Free(av); } AZ(fclose(fcs)); (void)unlink(vp.csrcfile); free(vp.csrcfile); free(vp.dir); VCLI_Out(cli, "VCL compiled.\n"); return (vp.libfile); }