From 2199c99d1360a185abc2588e8597f9a85a6ef827 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 9 Jul 2022 10:54:59 +0100 Subject: [PATCH] Break much of cgi-fcgi-interp.c out into prefork.[ch] We are going to want to reuse most of this for prefork-interp. Signed-off-by: Ian Jackson --- cprogs/Makefile | 3 +- cprogs/cgi-fcgi-interp.c | 431 +-------------------------------------- cprogs/prefork.c | 336 ++++++++++++++++++++++++++++++ cprogs/prefork.h | 93 +++++++++ cprogs/timespeccmp.h | 39 ++++ 5 files changed, 477 insertions(+), 425 deletions(-) create mode 100644 cprogs/prefork.c create mode 100644 cprogs/prefork.h create mode 100644 cprogs/timespeccmp.h diff --git a/cprogs/Makefile b/cprogs/Makefile index 0e60a4f..2eacf1f 100644 --- a/cprogs/Makefile +++ b/cprogs/Makefile @@ -62,6 +62,7 @@ really: really.o myopt.o acctdump: acctdump.o myopt.o acctdump.o really.o myopt.o rcopy-repeatedly.o: myopt.h +cgi-cfgi-interp.o prefork.o: myopt.h prefork.h timespeccmp.h readbuffer.o writebuffer.o rwbuffer.o wrbufcore.o trivsoundd.o: rwbuffer.h xbatmon-simple: LDLIBS += -lX11 -lm @@ -79,7 +80,7 @@ rcopy-repeatedly: LDLIBS += -lm -lrt watershed: watershed.o common.o watershed: LDLIBS += -lnettle -lgmp -cgi-fcgi-interp: cgi-fcgi-interp.o myopt.o common.o +cgi-fcgi-interp: cgi-fcgi-interp.o prefork.o myopt.o common.o cgi-fcgi-interp: LDLIBS += -lnettle $(SEDDERYDOCS): %.txt: %.c diff --git a/cprogs/cgi-fcgi-interp.c b/cprogs/cgi-fcgi-interp.c index 6b15294..96a78ce 100644 --- a/cprogs/cgi-fcgi-interp.c +++ b/cprogs/cgi-fcgi-interp.c @@ -122,133 +122,11 @@ * kill process group (at second iteration) */ -#include "common.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "myopt.h" - -#define MINHEXHASH 33 -#define STAGE2_VAR "CHIARKUTILS_CGIFCGIINTERP_STAGE2" - -static const char *interp, *ident; -static int numservers=4, debugmode; -static int check_interval=300; - -static struct sha256_ctx identsc; - -static bool logging; -static const char *stage2; - -static void vmsgcore(int estatus, int errnoval, const char *fmt, va_list al) { - int r; - - if (logging) { - const char *fmt_use = fmt; - char *fmt_free = 0; - if (errnoval) { - r = asprintf(&fmt_free, "%s: %%m", fmt); - if (r) { - fmt_free = 0; - } else { - fmt_use = fmt_free; - } - } - vsyslog(LOG_ERR, fmt_use, al); - free(fmt_free); - } else { - fputs("cgi-fcgi-interp: ",stderr); - vfprintf(stderr,fmt,al); - if (errnoval!=-1) fprintf(stderr,": %s",strerror(errnoval)); - fputc('\n',stderr); - } - if (estatus) exit(estatus); -} - -#define DEF_MSG(func, attrs, estatus, errnoval, after) \ - static void func(const char *fmt, ...) \ - __attribute__((format(printf,1,2))) attrs; \ - static void func(const char *fmt, ...) { \ - va_list al; \ - va_start(al,fmt); \ - vmsgcore(estatus,errnoval,fmt,al); \ - after \ - } - -DEF_MSG(warninge, /*empty*/, 0, errno, { }); -DEF_MSG(warning , /*empty*/, 0, 0, { }); - -#define DEF_DIE(func, errnoval) \ - DEF_MSG(func, __attribute__((noreturn)), 127, errnoval, { abort(); }) - -DEF_DIE(diee, errno) -DEF_DIE(die, 0) - -void common_diee(const char *m) { diee("%s", m); } -void common_die (const char *m) { die ("%s", m); } +#include "prefork.h" -static void fusagemessage(FILE *f) { - fprintf(f, "usage: #!/usr/bin/cgi-fcgi-interp []\n"); -} - -void usagemessage(void) { fusagemessage(stderr); } - -static void of_help(const struct cmdinfo *ci, const char *val) { - fusagemessage(stdout); - if (ferror(stdout)) diee("write usage message to stdout"); - exit(0); -} - -static void of_iassign(const struct cmdinfo *ci, const char *val) { - long v; - char *ep; - errno= 0; v= strtol(val,&ep,10); - if (!*val || *ep || errno || vINT_MAX) - badusage("bad integer argument `%s' for --%s",val,ci->olong); - *ci->iassignto = v; -} - -static void ident_addstring(const struct cmdinfo *ci, const char *string) { - /* ci may be 0 and is provided so this can be .call */ - sha256_update(&identsc,strlen(string)+1,string); -} - -static void off_ident_addenv(const struct cmdinfo *ci, const char *name) { - const char *val = getenv(name); - if (val) { - sha256_update(&identsc,strlen(name),name); /* no nul */ - sha256_update(&identsc,1,"="); - ident_addstring(0,val); - } else { - ident_addstring(0,name); - } -} - -#define MAX_OPTS 5 +static const char *stage2; -static const struct cmdinfo cmdinfos[]= { +const struct cmdinfo cmdinfos[]= { { "help", 0, .call=of_help }, { 0, 'g', 1, .sassignto= &ident }, { 0, 'G', 1, .call= ident_addstring }, @@ -259,262 +137,11 @@ static const struct cmdinfo cmdinfos[]= { { 0 } }; -static uid_t us; -static const char *run_base, *script, *socket_path; -static const char *run_base_mkdir_p; -static int stderr_copy; - -static bool find_run_base_var_run(void) { - struct stat stab; - char *try; - int r; - - try = m_asprintf("%s/%lu", "/var/run/user", us); - r = lstat(try, &stab); - if (r<0) { - if (errno == ENOENT || - errno == ENOTDIR || - errno == EACCES || - errno == EPERM) - return 0; /* oh well */ - diee("stat /var/run/user/UID"); - } - if (!S_ISDIR(stab.st_mode)) { - warning("%s not a directory, falling back to ~\n", try); - return 0; - } - if (stab.st_uid != us) { - warning("%s not owned by uid %lu, falling back to ~\n", try, - (unsigned long)us); - return 0; - } - if (stab.st_mode & 0077) { - warning("%s writeable by group or other, falling back to ~\n", try); - return 0; - } - run_base = m_asprintf("%s/%s", try, "cgi-fcgi-interp"); - return 1; -} - -static bool find_run_base_home(void) { - struct passwd *pw; - struct utsname ut; - char *dot, *try; - int r; - - pw = getpwuid(us); if (!pw) diee("getpwent(uid)"); - - r = uname(&ut); if (r) diee("uname(2)"); - dot = strchr(ut.nodename, '.'); - if (dot) *dot = 0; - if (sizeof(ut.nodename) > 32) - ut.nodename[32] = 0; - - run_base_mkdir_p = m_asprintf("%s/%s", pw->pw_dir, ".cgi-fcgi-interp"); - try = m_asprintf("%s/%s", run_base_mkdir_p, ut.nodename); - run_base = try; - return 1; -} - -static void find_socket_path(void) { - struct sockaddr_un sun; - int r; - - us = getuid(); if (us==(uid_t)-1) diee("getuid"); - - find_run_base_var_run() || - find_run_base_home() || - (abort(),0); - - int maxidentlen = sizeof(sun.sun_path) - strlen(run_base) - 10 - 2; - - if (!ident) { - if (maxidentlen < MINHEXHASH) - die("base directory `%s'" - " leaves only %d characters for id hash" - " which is too little (<%d)", - run_base, maxidentlen, MINHEXHASH); - - int identlen = maxidentlen > 64 ? 64 : maxidentlen; - char *hexident = xmalloc(identlen + 2); - unsigned char bbuf[32]; - int i; - - ident_addstring(0,interp); - ident_addstring(0,script); - sha256_digest(&identsc,sizeof(bbuf),bbuf); - - for (i=0; i maxidentlen) - die("base directory `%s' plus ident `%s' too long" - " (with spare) for socket (max ident %d)\n", - run_base, ident, maxidentlen); - - r = mkdir(run_base, 0700); - if (r && errno==ENOENT && run_base_mkdir_p) { - r = mkdir(run_base_mkdir_p, 0700); - if (r) diee("mkdir %s (since %s was ENOENT)",run_base_mkdir_p,run_base); - r = mkdir(run_base, 0700); - } - if (r) { - if (!(errno == EEXIST)) - diee("mkdir %s",run_base); - } - - socket_path = m_asprintf("%s/s%s",run_base,ident); -} - -/* - * Regarding the macro timespeccmp: - * - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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. - * - * @(#)time.h 8.5 (Berkeley) 5/4/95 - * $FreeBSD: head/sys/sys/time.h 275985 2014-12-21 05:07:11Z imp $ - */ -#ifndef timespeccmp -#define timespeccmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#endif /*timespeccmp*/ - - - -#ifdef st_mtime - -static bool stab_isnewer(const struct stat *a, const struct stat *b) { - if (debugmode) - fprintf(stderr,"stab_isnewer mtim %lu.%06lu %lu.06%lu\n", - (unsigned long)a->st_mtim.tv_sec, - (unsigned long)a->st_mtim.tv_nsec, - (unsigned long)b->st_mtim.tv_sec, - (unsigned long)b->st_mtim.tv_nsec); - return timespeccmp(&a->st_mtim, &b->st_mtim, >); -} - -static void stab_mtimenow(struct stat *out) { - int r = clock_gettime(CLOCK_REALTIME, &out->st_mtim); - if (r) diee("(stage2) clock_gettime"); - if (debugmode) - fprintf(stderr,"stab_mtimenow mtim %lu.%06lu\n", - (unsigned long)out->st_mtim.tv_sec, - (unsigned long)out->st_mtim.tv_nsec); -} - -#else /* !defined(st_mtime) */ - -static bool stab_isnewer(const struct stat *a, const struct stat *b) { - if (debugmode) - fprintf(stderr,"stab_isnewer mtime %lu %lu\n", - (unsigned long)a->st_mtime, - (unsigned long)b->st_mtime); - return a->st_mtime > b->st_mtime; -} - -static void stab_mtimenow(struct stat *out) { - out->st_mtime = time(NULL); - if (out->st_mtime == (time_t)-1) diee("(stage2) time()"); - if (debugmode) - fprintf(stderr,"stab_mtimenow mtime %lu\n", - (unsigned long)out->st_mtime); -} - -#endif /* !defined(st_mtime) */ - -static bool check_garbage_vs(const struct stat *started) { - struct stat script_stab; - int r; - - r = lstat(script, &script_stab); - if (r) diee("lstat script (%s)",script); - - if (stab_isnewer(&script_stab, started)) - return 1; - - if (S_ISLNK(script_stab.st_mode)) { - r = stat(script, &script_stab); - if (r) diee("stat script (%s0",script); - - if (stab_isnewer(&script_stab, started)) - return 1; - } - - return 0; -} - -static bool check_garbage(void) { - struct stat sock_stab; - int r; - - r = lstat(socket_path, &sock_stab); - if (r) { - if ((errno == ENOENT)) - return 0; /* well, no garbage then */ - diee("stat socket (%s)",socket_path); - } - - return check_garbage_vs(&sock_stab); +void fusagemessage(FILE *f) { + fprintf(f, "usage: #!/usr/bin/cgi-fcgi-interp []\n"); } -static void tidy_garbage(void) { - /* We lock l and re-check. The effect of this is that each - * stale socket is removed only once. So unless multiple updates to - * the script happen rapidly, we can't be racing with the cgi-fcgi - * (which is recreating the socket */ - int lockfd = -1; - int r; - - const char *lock_path = m_asprintf("%s/l%s",run_base,ident); - - lockfd = open(lock_path, O_CREAT|O_RDWR, 0600); - if (lockfd<0) diee("create lock (%s)", lock_path); - - r = flock(lockfd, LOCK_EX); - if (r) diee("lock lock (%s)", lock_path); - - if (check_garbage()) { - r = unlink(socket_path); - if (r) { - if (!(errno == ENOENT)) - diee("remove out-of-date socket (%s)", socket_path); - } - } - - r = close(lockfd); - if (r) diee("close lock (%s)", lock_path); -} +static int stderr_copy; static void make_stderr_copy(void) { stderr_copy = dup(2); @@ -529,14 +156,6 @@ static void prep_stage2(void) { if (r) diee("set %s (to announce to stage2)", STAGE2_VAR); } -static void shbang_opts(const char *const **argv_io, - const struct cmdinfo *cmdinfos) { - myopt(argv_io, cmdinfos); - - interp = *(*argv_io)++; - if (!interp) badusage("need interpreter argument"); -} - /* stage2 predeclarations */ static void record_baseline_time(void); static void become_pgrp(void); @@ -547,7 +166,6 @@ static void start_logging(void); static void await_something(void); int main(int argc, const char *const *argv) { - const char *smashedopt; int r; stage2 = getenv(STAGE2_VAR); @@ -567,42 +185,7 @@ int main(int argc, const char *const *argv) { if (r) diee("close saved stderr fd"); } - sha256_init(&identsc); - - if (argc>=2 && - (smashedopt = argv[1]) && - smashedopt[0]=='-' && - (strchr(smashedopt,' ') || strchr(smashedopt,','))) { - /* single argument containg all the options and */ - argv += 2; /* eat argv[0] and smashedopt */ - const char *split_args[MAX_OPTS+1]; - int split_argc = 0; - split_args[split_argc++] = argv[0]; - for (;;) { - if (split_argc >= MAX_OPTS) die("too many options in combined arg"); - split_args[split_argc++] = smashedopt; - if (smashedopt[0] != '-') /* never true on first iteration */ - break; - char *delim = strchr(smashedopt,' '); - if (!delim) delim = strchr(smashedopt,','); - if (!delim) badusage("combined arg lacks "); - *delim = 0; - smashedopt = delim+1; - } - assert(split_argc <= MAX_OPTS); - split_args[split_argc++] = 0; - - const char *const *split_argv = split_args; - - shbang_opts(&split_argv, cmdinfos); - /* sets interp */ - if (!split_argv) badusage("combined arg too many non-option arguments"); - } else { - shbang_opts(&argv, cmdinfos); - } - - script = *argv++; - if (!script) badusage("need script argument"); + script = process_opts(argc, argv); if (!stage2) { diff --git a/cprogs/prefork.c b/cprogs/prefork.c new file mode 100644 index 0000000..004b5d3 --- /dev/null +++ b/cprogs/prefork.c @@ -0,0 +1,336 @@ +/* common stuff for cgi-fcgi-interp and prefork-interp */ + +#include "prefork.h" + +const char *interp, *ident; +int numservers=4, debugmode; +int check_interval=300; + +struct sha256_ctx identsc; + +uid_t us; +const char *run_base, *script, *socket_path; +const char *run_base_mkdir_p; +bool logging; + +void common_diee(const char *m) { diee("%s", m); } +void common_die (const char *m) { die ("%s", m); } + +void vmsgcore(int estatus, int errnoval, const char *fmt, va_list al) { + int r; + + if (logging) { + const char *fmt_use = fmt; + char *fmt_free = 0; + if (errnoval) { + r = asprintf(&fmt_free, "%s: %%m", fmt); + if (r) { + fmt_free = 0; + } else { + fmt_use = fmt_free; + } + } + vsyslog(LOG_ERR, fmt_use, al); + free(fmt_free); + } else { + fputs("cgi-fcgi-interp: ",stderr); + vfprintf(stderr,fmt,al); + if (errnoval!=-1) fprintf(stderr,": %s",strerror(errnoval)); + fputc('\n',stderr); + } + if (estatus) exit(estatus); +} + +void usagemessage(void) { fusagemessage(stderr); } + +void of_help(const struct cmdinfo *ci, const char *val) { + fusagemessage(stdout); + if (ferror(stdout)) diee("write usage message to stdout"); + exit(0); +} + +void of_iassign(const struct cmdinfo *ci, const char *val) { + long v; + char *ep; + errno= 0; v= strtol(val,&ep,10); + if (!*val || *ep || errno || vINT_MAX) + badusage("bad integer argument `%s' for --%s",val,ci->olong); + *ci->iassignto = v; +} + +void ident_addstring(const struct cmdinfo *ci, const char *string) { + /* ci may be 0 and is provided so this can be .call */ + sha256_update(&identsc,strlen(string)+1,string); +} + +void off_ident_addenv(const struct cmdinfo *ci, const char *name) { + const char *val = getenv(name); + if (val) { + sha256_update(&identsc,strlen(name),name); /* no nul */ + sha256_update(&identsc,1,"="); + ident_addstring(0,val); + } else { + ident_addstring(0,name); + } +} + +bool find_run_base_var_run(void) { + struct stat stab; + char *try; + int r; + + try = m_asprintf("%s/%lu", "/var/run/user", us); + r = lstat(try, &stab); + if (r<0) { + if (errno == ENOENT || + errno == ENOTDIR || + errno == EACCES || + errno == EPERM) + return 0; /* oh well */ + diee("stat /var/run/user/UID"); + } + if (!S_ISDIR(stab.st_mode)) { + warning("%s not a directory, falling back to ~\n", try); + return 0; + } + if (stab.st_uid != us) { + warning("%s not owned by uid %lu, falling back to ~\n", try, + (unsigned long)us); + return 0; + } + if (stab.st_mode & 0077) { + warning("%s writeable by group or other, falling back to ~\n", try); + return 0; + } + run_base = m_asprintf("%s/%s", try, "cgi-fcgi-interp"); + return 1; +} + +static bool find_run_base_home(void) { + struct passwd *pw; + struct utsname ut; + char *dot, *try; + int r; + + pw = getpwuid(us); if (!pw) diee("getpwent(uid)"); + + r = uname(&ut); if (r) diee("uname(2)"); + dot = strchr(ut.nodename, '.'); + if (dot) *dot = 0; + if (sizeof(ut.nodename) > 32) + ut.nodename[32] = 0; + + run_base_mkdir_p = m_asprintf("%s/%s", pw->pw_dir, ".cgi-fcgi-interp"); + try = m_asprintf("%s/%s", run_base_mkdir_p, ut.nodename); + run_base = try; + return 1; +} + +void find_socket_path(void) { + struct sockaddr_un sun; + int r; + + us = getuid(); if (us==(uid_t)-1) diee("getuid"); + + find_run_base_var_run() || + find_run_base_home() || + (abort(),0); + + int maxidentlen = sizeof(sun.sun_path) - strlen(run_base) - 10 - 2; + + if (!ident) { + if (maxidentlen < MINHEXHASH) + die("base directory `%s'" + " leaves only %d characters for id hash" + " which is too little (<%d)", + run_base, maxidentlen, MINHEXHASH); + + int identlen = maxidentlen > 64 ? 64 : maxidentlen; + char *hexident = xmalloc(identlen + 2); + unsigned char bbuf[32]; + int i; + + ident_addstring(0,interp); + ident_addstring(0,script); + sha256_digest(&identsc,sizeof(bbuf),bbuf); + + for (i=0; i maxidentlen) + die("base directory `%s' plus ident `%s' too long" + " (with spare) for socket (max ident %d)\n", + run_base, ident, maxidentlen); + + r = mkdir(run_base, 0700); + if (r && errno==ENOENT && run_base_mkdir_p) { + r = mkdir(run_base_mkdir_p, 0700); + if (r) diee("mkdir %s (since %s was ENOENT)",run_base_mkdir_p,run_base); + r = mkdir(run_base, 0700); + } + if (r) { + if (!(errno == EEXIST)) + diee("mkdir %s",run_base); + } + + socket_path = m_asprintf("%s/s%s",run_base,ident); +} + +#ifdef st_mtime + +bool stab_isnewer(const struct stat *a, const struct stat *b) { + if (debugmode) + fprintf(stderr,"stab_isnewer mtim %lu.%06lu %lu.06%lu\n", + (unsigned long)a->st_mtim.tv_sec, + (unsigned long)a->st_mtim.tv_nsec, + (unsigned long)b->st_mtim.tv_sec, + (unsigned long)b->st_mtim.tv_nsec); + return timespeccmp(&a->st_mtim, &b->st_mtim, >); +} + +void stab_mtimenow(struct stat *out) { + int r = clock_gettime(CLOCK_REALTIME, &out->st_mtim); + if (r) diee("(stage2) clock_gettime"); + if (debugmode) + fprintf(stderr,"stab_mtimenow mtim %lu.%06lu\n", + (unsigned long)out->st_mtim.tv_sec, + (unsigned long)out->st_mtim.tv_nsec); +} + +#else /* !defined(st_mtime) */ + +bool stab_isnewer(const struct stat *a, const struct stat *b) { + if (debugmode) + fprintf(stderr,"stab_isnewer mtime %lu %lu\n", + (unsigned long)a->st_mtime, + (unsigned long)b->st_mtime); + return a->st_mtime > b->st_mtime; +} + +void stab_mtimenow(struct stat *out) { + out->st_mtime = time(NULL); + if (out->st_mtime == (time_t)-1) diee("(stage2) time()"); + if (debugmode) + fprintf(stderr,"stab_mtimenow mtime %lu\n", + (unsigned long)out->st_mtime); +} + +#endif /* !defined(st_mtime) */ + +bool check_garbage_vs(const struct stat *started) { + struct stat script_stab; + int r; + + r = lstat(script, &script_stab); + if (r) diee("lstat script (%s)",script); + + if (stab_isnewer(&script_stab, started)) + return 1; + + if (S_ISLNK(script_stab.st_mode)) { + r = stat(script, &script_stab); + if (r) diee("stat script (%s0",script); + + if (stab_isnewer(&script_stab, started)) + return 1; + } + + return 0; +} + +bool check_garbage(void) { + struct stat sock_stab; + int r; + + r = lstat(socket_path, &sock_stab); + if (r) { + if ((errno == ENOENT)) + return 0; /* well, no garbage then */ + diee("stat socket (%s)",socket_path); + } + + return check_garbage_vs(&sock_stab); +} + +void tidy_garbage(void) { + /* We lock l and re-check. The effect of this is that each + * stale socket is removed only once. So unless multiple updates to + * the script happen rapidly, we can't be racing with the cgi-fcgi + * (which is recreating the socket */ + int lockfd = -1; + int r; + + const char *lock_path = m_asprintf("%s/l%s",run_base,ident); + + lockfd = open(lock_path, O_CREAT|O_RDWR, 0600); + if (lockfd<0) diee("create lock (%s)", lock_path); + + r = flock(lockfd, LOCK_EX); + if (r) diee("lock lock (%s)", lock_path); + + if (check_garbage()) { + r = unlink(socket_path); + if (r) { + if (!(errno == ENOENT)) + diee("remove out-of-date socket (%s)", socket_path); + } + } + + r = close(lockfd); + if (r) diee("close lock (%s)", lock_path); +} + +static void shbang_opts(const char *const **argv_io, + const struct cmdinfo *cmdinfos) { + myopt(argv_io, cmdinfos); + + interp = *(*argv_io)++; + if (!interp) badusage("need interpreter argument"); +} + +const char *process_opts(int argc, const char *const *argv) { + const char *smashedopt; + + sha256_init(&identsc); + + if (argc>=2 && + (smashedopt = argv[1]) && + smashedopt[0]=='-' && + (strchr(smashedopt,' ') || strchr(smashedopt,','))) { + /* single argument containg all the options and */ + argv += 2; /* eat argv[0] and smashedopt */ + const char *split_args[MAX_OPTS+1]; + int split_argc = 0; + split_args[split_argc++] = argv[0]; + for (;;) { + if (split_argc >= MAX_OPTS) die("too many options in combined arg"); + split_args[split_argc++] = smashedopt; + if (smashedopt[0] != '-') /* never true on first iteration */ + break; + char *delim = strchr(smashedopt,' '); + if (!delim) delim = strchr(smashedopt,','); + if (!delim) badusage("combined arg lacks "); + *delim = 0; + smashedopt = delim+1; + } + assert(split_argc <= MAX_OPTS); + split_args[split_argc++] = 0; + + const char *const *split_argv = split_args; + + shbang_opts(&split_argv, cmdinfos); + /* sets interp */ + if (!split_argv) badusage("combined arg too many non-option arguments"); + } else { + shbang_opts(&argv, cmdinfos); + } + + script = *argv++; + if (!script) badusage("need script argument"); + + return script; +} diff --git a/cprogs/prefork.h b/cprogs/prefork.h new file mode 100644 index 0000000..4cde777 --- /dev/null +++ b/cprogs/prefork.h @@ -0,0 +1,93 @@ +/* common stuff for cgi-fcgi-interp and prefork-interp */ + +#ifndef PREFORK_H +#define PREFORK_H + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "myopt.h" +#include "timespeccmp.h" + +#define MINHEXHASH 33 +#define STAGE2_VAR "CHIARKUTILS_CGIFCGIINTERP_STAGE2" + +extern const char *interp, *ident; +extern int numservers, debugmode; +extern int check_interval; + +extern struct sha256_ctx identsc; + +extern uid_t us; +extern const char *run_base, *script, *socket_path; +extern const char *run_base_mkdir_p; +extern bool logging; + +bool find_run_base_var_run(void); +void find_socket_path(void); + +bool stab_isnewer(const struct stat *a, const struct stat *b); +void stab_mtimenow(struct stat *out); +bool check_garbage_vs(const struct stat *started); +bool check_garbage(void); +void tidy_garbage(void); + +extern const struct cmdinfo cmdinfos[]; + +// returns script pathname +const char *process_opts(int argc, const char *const *argv); + +void vmsgcore(int estatus, int errnoval, const char *fmt, va_list al); + +#define DEF_MSG(func, attrs, estatus, errnoval, after) \ + static void func(const char *fmt, ...) \ + __attribute__((unused, format(printf,1,2))) attrs; \ + static void func(const char *fmt, ...) { \ + va_list al; \ + va_start(al,fmt); \ + vmsgcore(estatus,errnoval,fmt,al); \ + after \ + } + +DEF_MSG(warninge, /*empty*/, 0, errno, { }); +DEF_MSG(warning , /*empty*/, 0, 0, { }); + +#define DEF_DIE(func, errnoval) \ + DEF_MSG(func, __attribute__((noreturn)), 127, errnoval, { abort(); }) + +DEF_DIE(diee, errno) +DEF_DIE(die, 0) + +#define MAX_OPTS 5 + +void fusagemessage(FILE *f); +void usagemessage(void); +void of_help(const struct cmdinfo *ci, const char *val); +void of_iassign(const struct cmdinfo *ci, const char *val); +void ident_addstring(const struct cmdinfo *ci, const char *string); +void off_ident_addenv(const struct cmdinfo *ci, const char *name); + +#endif /*PREFORK_H*/ diff --git a/cprogs/timespeccmp.h b/cprogs/timespeccmp.h new file mode 100644 index 0000000..e0a4f07 --- /dev/null +++ b/cprogs/timespeccmp.h @@ -0,0 +1,39 @@ +/* + * Regarding the macro timespeccmp: + * + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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. + * + * @(#)time.h 8.5 (Berkeley) 5/4/95 + * $FreeBSD: head/sys/sys/time.h 275985 2014-12-21 05:07:11Z imp $ + */ +#ifndef timespeccmp +#define timespeccmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#endif /*timespeccmp*/ -- 2.30.2