X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fcallcgi.c;h=2b1c9e63a53c2f0977eee6413e42d3a90afbccdc;hb=595adb9922885c2a05bc6917ee8f8f02f496e618;hp=3add3edbd0c7f0721c58b5fb8f9cbaac2fafd7b6;hpb=056f947352274dd1f6ec51b03c423c12e3828623;p=ashd.git diff --git a/src/callcgi.c b/src/callcgi.c index 3add3ed..2b1c9e6 100644 --- a/src/callcgi.c +++ b/src/callcgi.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -61,7 +62,8 @@ static int passdata(FILE *in, FILE *out) return(1); } if(fwrite(buf, 1, ret, out) != ret) { - flog(LOG_ERR, "callcgi: could not write output: %s", strerror(errno)); + if(errno != EPIPE) + flog(LOG_ERR, "callcgi: could not write output: %s", strerror(errno)); return(1); } } @@ -83,13 +85,13 @@ static char *absolutify(char *file) return(sstrdup(file)); } -static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *url, char *rest, int *infd, int *outfd) +static pid_t forkchild(int inpath, char **prog, char *file, char *method, char *url, char *rest, int *infd, int *outfd) { - int i; char *qp, **env, *name; int inp[2], outp[2]; pid_t pid; char *pi; + int (*execfun)(const char *, char *const []); pipe(inp); pipe(outp); @@ -98,12 +100,12 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u exit(1); } if(pid == 0) { - close(inp[1]); - close(outp[0]); dup2(inp[0], 0); dup2(outp[1], 1); - for(i = 3; i < FD_SETSIZE; i++) - close(i); + close(inp[0]); + close(inp[1]); + close(outp[0]); + close(outp[1]); if((qp = strchr(url, '?')) != NULL) *(qp++) = 0; putenv(sprintf2("SERVER_SOFTWARE=ashd/%s", VERSION)); @@ -145,12 +147,16 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u putenv(sprintf2("QUERY_STRING=%s", qp?qp:"")); if(getenv("REQ_HOST")) putenv(sprintf2("SERVER_NAME=%s", getenv("REQ_HOST"))); + if(getenv("REQ_X_ASH_SERVER_ADDRESS")) + putenv(sprintf2("SERVER_ADDR=%s", getenv("REQ_X_ASH_SERVER_ADDRESS"))); if(getenv("REQ_X_ASH_SERVER_PORT")) putenv(sprintf2("SERVER_PORT=%s", getenv("REQ_X_ASH_SERVER_PORT"))); if(getenv("REQ_X_ASH_PROTOCOL") && !strcmp(getenv("REQ_X_ASH_PROTOCOL"), "https")) putenv("HTTPS=on"); if(getenv("REQ_X_ASH_ADDRESS")) putenv(sprintf2("REMOTE_ADDR=%s", getenv("REQ_X_ASH_ADDRESS"))); + if(getenv("REQ_X_ASH_PORT")) + putenv(sprintf2("REMOTE_PORT=%s", getenv("REQ_X_ASH_PORT"))); if(getenv("REQ_X_ASH_REMOTE_USER")) putenv(sprintf2("REMOTE_USER=%s", getenv("REQ_X_ASH_REMOTE_USER"))); if(getenv("REQ_CONTENT_TYPE")) @@ -165,11 +171,10 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u * This is (understandably) missing from the CGI * specification, but PHP seems to require it. */ - putenv(sprintf2("SCRIPT_FILENAME=%s", absolutify(file))); - if(inpath) - execlp(prog, prog, file, NULL); - else - execl(prog, prog, file, NULL); + execfun = inpath?execvp:execv; + if(file != NULL) + putenv(sprintf2("SCRIPT_FILENAME=%s", absolutify(file))); + execfun(prog[0], prog); exit(127); } close(inp[0]); @@ -331,33 +336,57 @@ static void sendheaders(char **headers, FILE *out) static void usage(void) { - flog(LOG_ERR, "usage: callcgi [-c] [-p PROGRAM] METHOD URL REST"); + flog(LOG_ERR, "usage: callcgi [-c] [-p PROGRAM] [-P PROGRAM ARGS... ;] METHOD URL REST"); } int main(int argc, char **argv, char **envp) { int c; - char *file, *prog, *sp; - int inpath, cd; + char *file, *sp; + struct charvbuf prog; + int inpath, addfile, cd; int infd, outfd; FILE *in, *out; char **headers; pid_t child; + int estat; environ = envp; signal(SIGPIPE, SIG_IGN); - prog = NULL; + bufinit(prog); inpath = 0; + addfile = 1; cd = 0; - while((c = getopt(argc, argv, "cp:")) >= 0) { + while((c = getopt(argc, argv, "cp:P:")) >= 0) { switch(c) { case 'c': cd = 1; break; case 'p': - prog = optarg; + bufadd(prog, optarg); + inpath = 1; + break; + case 'P': + prog.d = 0; + bufadd(prog, optarg); + while(1) { + if(optind >= argc) { + flog(LOG_ERR, "callcgi: unterminated argument list for -P"); + exit(1); + } + if(!strcmp(argv[optind], ";")) { + optind++; + break; + } + bufadd(prog, argv[optind++]); + } + if(prog.d == 0) { + flog(LOG_ERR, "callcgi: -P option needs at least a program name"); + exit(1); + } inpath = 1; + addfile = 0; break; default: usage(); @@ -369,7 +398,7 @@ int main(int argc, char **argv, char **envp) usage(); exit(1); } - if((file = getenv("REQ_X_ASH_FILE")) == NULL) { + if(((file = getenv("REQ_X_ASH_FILE")) == NULL) && (prog.d == 0)) { flog(LOG_ERR, "callcgi: needs to be called with the X-Ash-File header"); exit(1); } @@ -388,9 +417,12 @@ int main(int argc, char **argv, char **envp) } } - if(prog == NULL) - prog = file; - child = forkchild(inpath, prog, file, argv[optind], argv[optind + 1], argv[optind + 2], &infd, &outfd); + if(prog.d == 0) + bufadd(prog, file); + if(addfile && (file != NULL)) + bufadd(prog, file); + bufadd(prog, NULL); + child = forkchild(inpath, prog.b, file, argv[optind], argv[optind + 1], argv[optind + 2], &infd, &outfd); in = fdopen(infd, "w"); passdata(stdin, in); /* Ignore errors, perhaps? */ fclose(in); @@ -404,5 +436,15 @@ int main(int argc, char **argv, char **envp) printf("\n"); if(passdata(out, stdout)) kill(child, SIGINT); - return(0); + fclose(out); + if(waitpid(child, &estat, 0) == child) { + if(WCOREDUMP(estat)) + flog(LOG_WARNING, "CGI handler `%s' dumped core", prog.b[0]); + if(WIFEXITED(estat) && !WEXITSTATUS(estat)) + return(0); + else + return(1); + } + flog(LOG_WARNING, "could not wait for CGI handler: %s", strerror(errno)); + return(1); }