rbb 99/10/11 07:20:48
Modified: src Configure src/include http_log.h src/lib/apr/file_io/unix open.c src/lib/apr/include apr_file_io.h apr_lib.h apr_thread_proc.h src/lib/apr/lib apr_cpystrn.c apr_pools.c src/lib/apr/threadproc/unix proc.c src/main http_log.c src/os/beos os-inline.c os.c src/os/unix os-inline.c src/os/win32 util_win32.c Log: Make Apache use the new ap_create_process call. This is the first of a group of patches. This patch, allows the core server to compile and serve pages. There is a set of patches which will follow to allow the standard modules to use ap_create_process. This change should make writing code which spawns new processes easy to read and understand. Submitted by: Paul Reder Revision Changes Path 1.12 +1 -1 apache-2.0/src/Configure Index: Configure =================================================================== RCS file: /home/cvs/apache-2.0/src/Configure,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- Configure 1999/10/10 17:07:53 1.11 +++ Configure 1999/10/11 14:20:36 1.12 @@ -1748,7 +1748,7 @@ fi cd ../.. APRLIB="" - for lib in apr file network lock misc sig threadproc time; do + for lib in network threadproc file misc apr time lock sig; do APRLIB="$APRLIB \$(SRCDIR)/lib/apr/libs/lib${lib}.a" done CFLAGS="$CFLAGS -I\$(SRCDIR)/lib/apr/include" 1.5 +1 -1 apache-2.0/src/include/http_log.h Index: http_log.h =================================================================== RCS file: /home/cvs/apache-2.0/src/include/http_log.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- http_log.h 1999/09/08 14:15:40 1.4 +++ http_log.h 1999/10/11 14:20:37 1.5 @@ -138,7 +138,7 @@ ap_context_t *p; #ifndef NO_RELIABLE_PIPED_LOGS char *program; - int pid; + ap_proc_t *pid; ap_file_t fds[2]; #else ap_file_t *write_f; 1.14 +14 -0 apache-2.0/src/lib/apr/file_io/unix/open.c Index: open.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/unix/open.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- open.c 1999/10/06 23:03:46 1.13 +++ open.c 1999/10/11 14:20:38 1.14 @@ -278,3 +278,17 @@ return APR_SUCCESS; } +/* ***APRDOC******************************************************** + * ap_status_t ap_ferror(ap_file_t *) + * Is there an error on the stream? + * arg 1) The apr file we are testing. + * NOTE: Returns -1 if the error indicator is set, APR_SUCCESS otherwise. + */ +ap_status_t ap_ferror(ap_file_t *fptr) +{ + if (ferror(fptr->filehand)) { + return (-1); + } + + return APR_SUCCESS; +} 1.11 +1 -0 apache-2.0/src/lib/apr/include/apr_file_io.h Index: apr_file_io.h =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_file_io.h,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- apr_file_io.h 1999/10/08 13:47:03 1.10 +++ apr_file_io.h 1999/10/11 14:20:38 1.11 @@ -111,6 +111,7 @@ ap_status_t ap_close(ap_file_t *); ap_status_t ap_remove_file(char *, ap_context_t *); ap_status_t ap_eof(ap_file_t *); +ap_status_t ap_ferror(ap_file_t *); ap_status_t ap_read(ap_file_t *, void *, ap_ssize_t *); ap_status_t ap_write(ap_file_t *, void *, ap_ssize_t *); 1.12 +3 -2 apache-2.0/src/lib/apr/include/apr_lib.h Index: apr_lib.h =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_lib.h,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- apr_lib.h 1999/10/08 13:47:04 1.11 +++ apr_lib.h 1999/10/11 14:20:38 1.12 @@ -164,6 +164,8 @@ * Define the prototypes for the various APR GP routines. */ API_EXPORT(char *) ap_cpystrn(char *d, const char *s, size_t l); +API_EXPORT(int) ap_tokenize_to_argv(ap_context_t *token_context, + char *arg_str, char ***argv_out); /*API_EXPORT(ap_mutex_t *) ap_create_mutex(void *m);*/ API_EXPORT(int) ap_slack(int l, int h); API_EXPORT_NONSTD(int) ap_execle(const char *c, const char *a, ...); @@ -371,9 +373,8 @@ API_EXPORT(ap_status_t) ap_getpass(const char *prompt, char *pwbuf, size_t *bufsize); API_EXPORT_NONSTD(ap_status_t) ap_null_cleanup(void *data); -/*API_EXPORT(void) ap_note_subprocess(ap_pool_t *a, pid_t pid, +API_EXPORT(void) ap_note_subprocess(struct context_t *a, pid_t pid, enum kill_conditions how); -*/ API_EXPORT(int) ap_spawn_child(ap_context_t *p, int (*func) (void *a, ap_child_info_t *c), 1.7 +9 -3 apache-2.0/src/lib/apr/include/apr_thread_proc.h Index: apr_thread_proc.h =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_thread_proc.h,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- apr_thread_proc.h 1999/10/08 14:45:00 1.6 +++ apr_thread_proc.h 1999/10/11 14:20:39 1.7 @@ -112,7 +112,13 @@ ap_status_t ap_createprocattr_init(ap_procattr_t **, ap_context_t *); ap_status_t ap_setprocattr_io(ap_procattr_t *, ap_int32_t, ap_int32_t, ap_int32_t); -ap_status_t ap_setprocattr_dir(ap_procattr_t *, char *); +ap_status_t ap_setprocattr_childin(struct procattr_t *, ap_file_t *, + ap_file_t *); +ap_status_t ap_setprocattr_childout(struct procattr_t *, ap_file_t *, + ap_file_t *); +ap_status_t ap_setprocattr_childerr(struct procattr_t *, ap_file_t *, + ap_file_t *); +ap_status_t ap_setprocattr_dir(ap_procattr_t *, const char *); ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *, ap_cmdtype_e); ap_status_t ap_setprocattr_detach(ap_procattr_t *, ap_int32_t); ap_status_t ap_get_procdata(ap_proc_t *, char *, void *); @@ -124,8 +130,8 @@ ap_status_t ap_get_childerr(ap_file_t **, ap_proc_t *); ap_status_t ap_fork(ap_proc_t **, ap_context_t *); -ap_status_t ap_create_process(ap_context_t *, char *, char *const [], char **, - ap_procattr_t *, ap_proc_t **); +ap_status_t ap_create_process(ap_proc_t **, ap_context_t *, const char *, + char *const [], char **, ap_procattr_t *); ap_status_t ap_wait_proc(ap_proc_t *, ap_wait_how_e); ap_status_t ap_kill(ap_proc_t *, ap_int32_t); 1.4 +84 -0 apache-2.0/src/lib/apr/lib/apr_cpystrn.c Index: apr_cpystrn.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/lib/apr_cpystrn.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- apr_cpystrn.c 1999/10/01 16:18:32 1.3 +++ apr_cpystrn.c 1999/10/11 14:20:40 1.4 @@ -100,3 +100,87 @@ return (d); } + + +/* + * This function provides a way to parse a generic argument string + * into a standard argv[] form of argument list. It respects the + * usual "whitespace" and quoteing rules. In the future this could + * be expanded to include support for the ap_call_exec command line + * string processing (including converting '+' to ' ' and doing the + * url processing. It does not currently support this function. + * + * token_context: Context from which pool allocations will occur. + * arg_str: Input argument string for conversion to argv[]. + * argv_out: Output location. This is a pointer to an array + * of pointers to strings (ie. &(char *argv[]). + * This value will be allocated from the contexts + * pool and filled in with copies of the tokens + * found during parsing of the arg_str. + */ +API_EXPORT(int) ap_tokenize_to_argv(ap_context_t *token_context, + char *arg_str, char ***argv_out) +{ + char *cp, *tmpCnt; + int isquoted, numargs = 0, rc = APR_SUCCESS; + +#define SKIP_WHITESPACE(cp) \ + for ( ; *cp == ' ' || *cp == '\t'; ) { \ + cp++; \ + }; + +#define CHECK_QUOTATION(cp,isquoted) \ + isquoted = 0; \ + if (*cp == '"') { \ + isquoted = 1; \ + cp++; \ + } + +#define DETERMINE_NEXTSTRING(cp,isquoted) \ + for ( ; *cp != '\0'; cp++) { \ + if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ + || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \ + cp++; \ + continue; \ + } \ + if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ + || (isquoted && *cp == '"') ) { \ + break; \ + } \ + } + + cp = arg_str; + SKIP_WHITESPACE(cp); + tmpCnt = cp; + + /* This is ugly and expensive, but if anyone wants to figure a + * way to support any number of args without counting and + * allocating, please go ahead and change the code. + */ + while (*tmpCnt != '\0') { + CHECK_QUOTATION(tmpCnt, isquoted); + DETERMINE_NEXTSTRING(tmpCnt, isquoted); + numargs++; + SKIP_WHITESPACE(tmpCnt); + } + + *argv_out = ap_palloc(token_context, numargs*sizeof(char*)); + if (*argv_out == NULL) { + return (APR_ENOMEM); + } + + /* determine first argument */ + numargs = 0; + while (*cp != '\0') { + CHECK_QUOTATION(cp, isquoted); + tmpCnt = cp; + DETERMINE_NEXTSTRING(cp, isquoted); + *cp++ = '\0'; + (*argv_out)[numargs] = ap_pstrdup(token_context, tmpCnt); + + SKIP_WHITESPACE(cp); + } + *cp++ = '\0'; + + return(rc); +} 1.14 +0 -555 apache-2.0/src/lib/apr/lib/apr_pools.c Index: apr_pools.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/lib/apr_pools.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- apr_pools.c 1999/10/08 14:26:12 1.13 +++ apr_pools.c 1999/10/11 14:20:41 1.14 @@ -1213,561 +1213,6 @@ #endif -static pid_t spawn_child_core(ap_context_t *p, - int (*func) (void *, ap_child_info_t *), - void *data,enum kill_conditions kill_how, - int *pipe_in, int *pipe_out, int *pipe_err) -{ - pid_t pid; - int in_fds[2]; - int out_fds[2]; - int err_fds[2]; - int save_errno; - - if (pipe_in && os_pipe(in_fds) < 0) { - return 0; - } - - if (pipe_out && os_pipe(out_fds) < 0) { - save_errno = errno; - if (pipe_in) { - close(in_fds[0]); - close(in_fds[1]); - } - errno = save_errno; - return 0; - } - - if (pipe_err && os_pipe(err_fds) < 0) { - save_errno = errno; - if (pipe_in) { - close(in_fds[0]); - close(in_fds[1]); - } - if (pipe_out) { - close(out_fds[0]); - close(out_fds[1]); - } - errno = save_errno; - return 0; - } - -#ifdef WIN32 - - { - HANDLE thread_handle; - int hStdIn, hStdOut, hStdErr; - int old_priority; - ap_child_info_t info; - - (void) ap_acquire_mutex(spawn_mutex); - thread_handle = GetCurrentThread(); /* doesn't need to be closed */ - old_priority = GetThreadPriority(thread_handle); - SetThreadPriority(thread_handle, THREAD_PRIORITY_HIGHEST); - /* Now do the right thing with your pipes */ - if (pipe_in) { - hStdIn = dup(fileno(stdin)); - if (dup2(in_fds[0], fileno(stdin))) { - ap_log_error(APLOG_MARK, APLOG_ERR, NULL, - "dup2(stdin) failed"); - } - close(in_fds[0]); - } - if (pipe_out) { - hStdOut = dup(fileno(stdout)); - close(fileno(stdout)); - if (dup2(out_fds[1], fileno(stdout))) { - ap_log_error(APLOG_MARK, APLOG_ERR, NULL, - "dup2(stdout) failed"); - } - close(out_fds[1]); - } - if (pipe_err) { - hStdErr = dup(fileno(stderr)); - if (dup2(err_fds[1], fileno(stderr))) { - ap_log_error(APLOG_MARK, APLOG_ERR, NULL, - "dup2(stderr) failed"); - } - close(err_fds[1]); - } - - info.hPipeInputRead = GetStdHandle(STD_INPUT_HANDLE); - info.hPipeOutputWrite = GetStdHandle(STD_OUTPUT_HANDLE); - info.hPipeErrorWrite = GetStdHandle(STD_ERROR_HANDLE); - - pid = (*func) (data, &info); - if (pid == -1) { - pid = 0; /* map Win32 error code onto Unix default */ - } - - if (!pid) { - save_errno = errno; - close(in_fds[1]); - close(out_fds[0]); - close(err_fds[0]); - } - - /* restore the original stdin, stdout and stderr */ - if (pipe_in) { - dup2(hStdIn, fileno(stdin)); - close(hStdIn); - } - if (pipe_out) { - dup2(hStdOut, fileno(stdout)); - close(hStdOut); - } - if (pipe_err) { - dup2(hStdErr, fileno(stderr)); - close(hStdErr); - } - - if (pid) { - ap_note_subprocess(p, pid, kill_how); - if (pipe_in) { - *pipe_in = in_fds[1]; - } - if (pipe_out) { - *pipe_out = out_fds[0]; - } - if (pipe_err) { - *pipe_err = err_fds[0]; - } - } - SetThreadPriority(thread_handle, old_priority); - (void) ap_release_mutex(spawn_mutex); - /* - * go on to the end of the function, where you can - * unblock alarms and return the pid - */ - - } -#elif defined(OS2) - { - int save_in=-1, save_out=-1, save_err=-1; - - if (pipe_out) { - save_out = dup(STDOUT_FILENO); - dup2(out_fds[1], STDOUT_FILENO); - close(out_fds[1]); - } - - if (pipe_in) { - save_in = dup(STDIN_FILENO); - dup2(in_fds[0], STDIN_FILENO); - close(in_fds[0]); - } - - if (pipe_err) { - save_err = dup(STDERR_FILENO); - dup2(err_fds[1], STDERR_FILENO); - close(err_fds[1]); - } - - pid = func(data, NULL); - - if (pid) { - ap_note_subprocess(p, pid, kill_how); - } - - if (pipe_out) { - close(STDOUT_FILENO); - dup2(save_out, STDOUT_FILENO); - close(save_out); - *pipe_out = out_fds[0]; - } - - if (pipe_in) { - close(STDIN_FILENO); - dup2(save_in, STDIN_FILENO); - close(save_in); - *pipe_in = in_fds[1]; - } - - if (pipe_err) { - close(STDERR_FILENO); - dup2(save_err, STDERR_FILENO); - close(save_err); - *pipe_err = err_fds[0]; - } - } -#elif defined(TPF) - return (pid = ap_tpf_spawn_child(p, func, data, kill_how, - pipe_in, pipe_out, pipe_err, out_fds, - in_fds, err_fds)); -#else - - if ((pid = fork()) < 0) { - save_errno = errno; - if (pipe_in) { - close(in_fds[0]); - close(in_fds[1]); - } - if (pipe_out) { - close(out_fds[0]); - close(out_fds[1]); - } - if (pipe_err) { - close(err_fds[0]); - close(err_fds[1]); - } - errno = save_errno; - return 0; - } - - if (!pid) { - /* Child process */ - RAISE_SIGSTOP(SPAWN_CHILD); - - if (pipe_out) { - close(out_fds[0]); - dup2(out_fds[1], STDOUT_FILENO); - close(out_fds[1]); - } - - if (pipe_in) { - close(in_fds[1]); - dup2(in_fds[0], STDIN_FILENO); - close(in_fds[0]); - } - - if (pipe_err) { - close(err_fds[0]); - dup2(err_fds[1], STDERR_FILENO); - close(err_fds[1]); - } - - /* - * HP-UX SIGCHLD fix goes here, if someone will remind me - * what it is... - */ - signal(SIGCHLD, SIG_DFL); /* Was that it? */ - - func(data, NULL); - exit(1); /* Should only get here if the exec in func() failed */ - } - - /* Parent process */ - - ap_note_subprocess(p, pid, kill_how); - - if (pipe_out) { - close(out_fds[1]); - *pipe_out = out_fds[0]; - } - - if (pipe_in) { - close(in_fds[0]); - *pipe_in = in_fds[1]; - } - - if (pipe_err) { - close(err_fds[1]); - *pipe_err = err_fds[0]; - } -#endif /* WIN32 */ - - return pid; -} - - -API_EXPORT(int) ap_spawn_child(ap_context_t *p, - int (*func) (void *v, ap_child_info_t *c), - void *data, enum kill_conditions kill_how, - FILE **pipe_in, FILE **pipe_out, - FILE **pipe_err) -{ - int fd_in, fd_out, fd_err; - pid_t pid; - int save_errno; - - ap_block_alarms(); - - pid = spawn_child_core(p, func, data, kill_how, - pipe_in ? &fd_in : NULL, - pipe_out ? &fd_out : NULL, - pipe_err ? &fd_err : NULL); - - if (pid == 0) { - save_errno = errno; - ap_unblock_alarms(); - errno = save_errno; - return 0; - } - - if (pipe_out) { - *pipe_out = ap_fdopen(fd_out, "r" BINMODE); - if (*pipe_out) { - /* remove for now. These go away with the APR abstraction - * for process spawning. - * ap_note_cleanups_for_file(p, *pipe_out); - */ - } - else { - close(fd_out); - } - } - - if (pipe_in) { - *pipe_in = ap_fdopen(fd_in, "w" BINMODE); - if (*pipe_in) { - /* remove for now. These go away with the APR abstraction - * for process spawning. - * ap_note_cleanups_for_file(p, *pipe_in); - */ - } - else { - close(fd_in); - } - } - - if (pipe_err) { - *pipe_err = ap_fdopen(fd_err, "r" BINMODE); - if (*pipe_err) { - /* remove for now. These go away with the APR abstraction - * for process spawning. - * ap_note_cleanups_for_file(p, *pipe_err); - */ - } - else { - close(fd_err); - } - } - - ap_unblock_alarms(); - return pid; -} -#if 0 -API_EXPORT(int) ap_bspawn_child(ap_pool_t *p, - int (*func) (void *v, ap_child_info_t *c), - void *data, enum kill_conditions kill_how, - BUFF **pipe_in, BUFF **pipe_out, - BUFF **pipe_err) -{ -#ifdef WIN32 - SECURITY_ATTRIBUTES sa = {0}; - HANDLE hPipeOutputRead = NULL; - HANDLE hPipeOutputWrite = NULL; - HANDLE hPipeInputRead = NULL; - HANDLE hPipeInputWrite = NULL; - HANDLE hPipeErrorRead = NULL; - HANDLE hPipeErrorWrite = NULL; - HANDLE hPipeInputWriteDup = NULL; - HANDLE hPipeOutputReadDup = NULL; - HANDLE hPipeErrorReadDup = NULL; - HANDLE hCurrentProcess; - pid_t pid = 0; - ap_child_info_t info; - - ap_block_alarms(); - - /* - * First thing to do is to create the pipes that we will use - * for stdin, stdout, and stderr in the child process. - */ - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - - /* Create pipes for standard input/output/error redirection. */ - if (pipe_in && !CreatePipe(&hPipeInputRead, &hPipeInputWrite, &sa, 0)) { - return 0; - } - - if (pipe_out && !CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &sa, 0)) { - if (pipe_in) { - CloseHandle(hPipeInputRead); - CloseHandle(hPipeInputWrite); - } - return 0; - } - - if (pipe_err && !CreatePipe(&hPipeErrorRead, &hPipeErrorWrite, &sa, 0)) { - if (pipe_in) { - CloseHandle(hPipeInputRead); - CloseHandle(hPipeInputWrite); - } - if (pipe_out) { - CloseHandle(hPipeOutputRead); - CloseHandle(hPipeOutputWrite); - } - return 0; - } - /* - * When the pipe handles are created, the security descriptor - * indicates that the handle can be inherited. However, we do not - * want the server side handles to the pipe to be inherited by the - * child CGI process. If the child CGI does inherit the server - * side handles, then the child may be left around if the server - * closes its handles (e.g. if the http connection is aborted), - * because the child will have a valid copy of handles to both - * sides of the pipes, and no I/O error will occur. Microsoft - * recommends using DuplicateHandle to turn off the inherit bit - * under NT and Win95. - */ - hCurrentProcess = GetCurrentProcess(); - if ((pipe_in && !DuplicateHandle(hCurrentProcess, hPipeInputWrite, - hCurrentProcess, - &hPipeInputWriteDup, 0, FALSE, - DUPLICATE_SAME_ACCESS)) - || (pipe_out && !DuplicateHandle(hCurrentProcess, hPipeOutputRead, - hCurrentProcess, &hPipeOutputReadDup, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - || (pipe_err && !DuplicateHandle(hCurrentProcess, hPipeErrorRead, - hCurrentProcess, &hPipeErrorReadDup, - 0, FALSE, DUPLICATE_SAME_ACCESS))) { - if (pipe_in) { - CloseHandle(hPipeInputRead); - CloseHandle(hPipeInputWrite); - } - if (pipe_out) { - CloseHandle(hPipeOutputRead); - CloseHandle(hPipeOutputWrite); - } - if (pipe_err) { - CloseHandle(hPipeErrorRead); - CloseHandle(hPipeErrorWrite); - } - return 0; - } - else { - if (pipe_in) { - CloseHandle(hPipeInputWrite); - hPipeInputWrite = hPipeInputWriteDup; - } - if (pipe_out) { - CloseHandle(hPipeOutputRead); - hPipeOutputRead = hPipeOutputReadDup; - } - if (pipe_err) { - CloseHandle(hPipeErrorRead); - hPipeErrorRead = hPipeErrorReadDup; - } - } - - /* The script writes stdout to this pipe handle */ - info.hPipeOutputWrite = hPipeOutputWrite; - - /* The script reads stdin from this pipe handle */ - info.hPipeInputRead = hPipeInputRead; - - /* The script writes stderr to this pipe handle */ - info.hPipeErrorWrite = hPipeErrorWrite; - - /* - * Try to launch the CGI. Under the covers, this call - * will try to pick up the appropriate interpreter if - * one is needed. - */ - pid = func(data, &info); - if (pid == -1) { - /* Things didn't work, so cleanup */ - pid = 0; /* map Win32 error code onto Unix default */ - CloseHandle(hPipeOutputRead); - CloseHandle(hPipeInputWrite); - CloseHandle(hPipeErrorRead); - } - else { - if (pipe_out) { - /* - * This pipe represents stdout for the script, - * so we read from this pipe. - */ - /* Create a read buffer */ - *pipe_out = ap_bcreate(p, B_RD); - - /* Setup the cleanup routine for the handle */ - ap_note_cleanups_for_h(p, hPipeOutputRead); - - /* Associate the handle with the new buffer */ - ap_bpushh(*pipe_out, hPipeOutputRead); - } - - if (pipe_in) { - /* - * This pipe represents stdin for the script, so we - * write to this pipe. - */ - /* Create a write buffer */ - *pipe_in = ap_bcreate(p, B_WR); - - /* Setup the cleanup routine for the handle */ - ap_note_cleanups_for_h(p, hPipeInputWrite); - - /* Associate the handle with the new buffer */ - ap_bpushh(*pipe_in, hPipeInputWrite); - - } - - if (pipe_err) { - /* - * This pipe represents stderr for the script, so - * we read from this pipe. - */ - /* Create a read buffer */ - *pipe_err = ap_bcreate(p, B_RD); - - /* Setup the cleanup routine for the handle */ - ap_note_cleanups_for_h(p, hPipeErrorRead); - - /* Associate the handle with the new buffer */ - ap_bpushh(*pipe_err, hPipeErrorRead); - } - } - - - /* - * Now that handles have been inherited, close them to be safe. - * You don't want to read or write to them accidentally, and we - * sure don't want to have a handle leak. - */ - CloseHandle(hPipeOutputWrite); - CloseHandle(hPipeInputRead); - CloseHandle(hPipeErrorWrite); - -#else - int fd_in, fd_out, fd_err; - pid_t pid; - int save_errno; - - ap_block_alarms(); - - pid = spawn_child_core(p, func, data, kill_how, - pipe_in ? &fd_in : NULL, - pipe_out ? &fd_out : NULL, - pipe_err ? &fd_err : NULL); - - if (pid == 0) { - save_errno = errno; - ap_unblock_alarms(); - errno = save_errno; - return 0; - } - - if (pipe_out) { - *pipe_out = ap_bcreate(p, B_RD); - ap_note_cleanups_for_fd(p, fd_out); - ap_bpushfd(*pipe_out, fd_out, fd_out); - } - - if (pipe_in) { - *pipe_in = ap_bcreate(p, B_WR); - ap_note_cleanups_for_fd(p, fd_in); - ap_bpushfd(*pipe_in, fd_in, fd_in); - } - - if (pipe_err) { - *pipe_err = ap_bcreate(p, B_RD); - ap_note_cleanups_for_fd(p, fd_err); - ap_bpushfd(*pipe_err, fd_err, fd_err); - } -#endif - - ap_unblock_alarms(); - return pid; -} -#endif - static void free_proc_chain(struct process_chain *procs) { /* Dispose of the subprocesses we've spawned off in the course of 1.5 +92 -5 apache-2.0/src/lib/apr/threadproc/unix/proc.c Index: proc.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/threadproc/unix/proc.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- proc.c 1999/10/04 16:37:39 1.4 +++ proc.c 1999/10/11 14:20:43 1.5 @@ -127,6 +127,93 @@ return APR_SUCCESS; } + +/* ***APRDOC******************************************************** + * ap_status_t ap_setprocattr_childin(ap_procattr_t *, ap_file_t *, + * ap_file_t *) + * Set the child_in and/or parent_in values to existing ap_file_t + * values. This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across mutiple + * process invocations - such as a log file. You can save some + * extra function calls by not creating your own pipe since this + * creates one in the process space for you. + * arg 1) The procattr we care about. + * arg 2) ap_file_t value to use as child_in. Must be a valid file. + * arg 3) ap_file_t value to use as parent_in. Must be a valid file. + */ +ap_status_t ap_setprocattr_childin(struct procattr_t *attr, ap_file_t *child_in, + ap_file_t *parent_in) +{ + if (attr->child_in == NULL && attr->parent_in == NULL) + ap_create_pipe(&attr->child_in, &attr->parent_in, attr->cntxt); + + if (child_in != NULL) + ap_dupfile(&attr->child_in, child_in); + + if (parent_in != NULL) + ap_dupfile(&attr->parent_in, parent_in); + + return APR_SUCCESS; +} + + +/* ***APRDOC******************************************************** + * ap_status_t ap_setprocattr_childout(ap_procattr_t *, ap_file_t *, + * ap_file_t *) + * Set the child_out and parent_out values to existing ap_file_t + * values. This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across mutiple + * process invocations - such as a log file. + * arg 1) The procattr we care about. + * arg 2) ap_file_t value to use as child_out. Must be a valid file. + * arg 3) ap_file_t value to use as parent_out. Must be a valid file. + */ +ap_status_t ap_setprocattr_childout(struct procattr_t *attr, ap_file_t *child_out, + ap_file_t *parent_out) +{ + if (attr->child_out == NULL && attr->parent_out == NULL) + ap_create_pipe(&attr->child_out, &attr->parent_out, attr->cntxt); + + if (child_out != NULL) + ap_dupfile(&attr->child_out, child_out); + + if (parent_out != NULL) + ap_dupfile(&attr->parent_out, parent_out); + + return APR_SUCCESS; +} + + +/* ***APRDOC******************************************************** + * ap_status_t ap_setprocattr_childerr(ap_procattr_t *, ap_file_t *, + * ap_file_t *) + * Set the child_err and parent_err values to existing ap_file_t + * values. This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across mutiple + * process invocations - such as a log file. + * arg 1) The procattr we care about. + * arg 2) ap_file_t value to use as child_err. Must be a valid file. + * arg 3) ap_file_t value to use as parent_err. Must be a valid file. + */ +ap_status_t ap_setprocattr_childerr(struct procattr_t *attr, ap_file_t *child_err, + ap_file_t *parent_err) +{ + if (attr->child_err == NULL && attr->parent_err == NULL) + ap_create_pipe(&attr->child_err, &attr->parent_err, attr->cntxt); + + if (child_err != NULL) + ap_dupfile(&attr->child_err, child_err); + + if (parent_err != NULL) + ap_dupfile(&attr->parent_err, parent_err); + + return APR_SUCCESS; +} + + /* ***APRDOC******************************************************** * ap_status_t ap_setprocattr_dir(ap_procattr_t *, char *) * Set which directory the child process should start executing in. @@ -136,7 +223,7 @@ * is made. */ ap_status_t ap_setprocattr_dir(struct procattr_t *attr, - char *dir) + const char *dir) { attr->currdir = ap_pstrdup(attr->cntxt, dir); if (attr->currdir) { @@ -199,7 +286,7 @@ } /* ***APRDOC******************************************************** - * ap_status_t ap_create_process(ap_context_t *, char *, char *const [], + * ap_status_t ap_create_process(ap_context_t *, const char *, char *const [], char **, ap_procattr_t *, ap_proc_t **) * Create a new process and execute a new program within that process. * arg 1) The context to use. @@ -212,9 +299,9 @@ * process * arg 6) The resulting process handle. */ -ap_status_t ap_create_process(ap_context_t *cont, char *progname, - char *const args[], char **env, - struct procattr_t *attr, struct proc_t **new) +ap_status_t ap_create_process(struct proc_t **new, ap_context_t *cont, + const char *progname, char *const args[], + char **env, struct procattr_t *attr) { int i; char **newargs; 1.9 +105 -113 apache-2.0/src/main/http_log.c Index: http_log.c =================================================================== RCS file: /home/cvs/apache-2.0/src/main/http_log.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- http_log.c 1999/10/06 23:04:08 1.8 +++ http_log.c 1999/10/11 14:20:45 1.9 @@ -156,60 +156,84 @@ {NULL, -1}, }; -static int error_log_child(void *cmd, ap_child_info_t *pinfo) +static int log_child(ap_context_t *p, const char *progname, + ap_file_t **fpout, ap_file_t **fpin, + ap_file_t **fperr) { /* Child process code for 'ErrorLog "|..."'; * may want a common framework for this, since I expect it will * be common for other foo-loggers to want this sort of thing... */ - int child_pid = 0; + int rc = -1; + ap_procattr_t *procattr; + ap_proc_t *procnew; + ap_os_proc_t fred; + ap_block_alarms(); ap_cleanup_for_exec(); + #ifdef SIGHUP /* No concept of a child process on Win32 */ signal(SIGHUP, SIG_IGN); #endif /* ndef SIGHUP */ -#if defined(WIN32) - child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); - return(child_pid); -#elif defined(OS2) - /* For OS/2 we need to use a '/' and spawn the child rather than exec as - * we haven't forked */ - child_pid = spawnl(P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); - return(child_pid); -#else - execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - exit(1); - /* NOT REACHED */ - return(child_pid); + + if ((ap_createprocattr_init(&procattr, p) != APR_SUCCESS) || + (ap_setprocattr_io(procattr, + fpin ? 1 : 0, + fpout ? 1 : 0, + fperr ? 1 : 0) != APR_SUCCESS) || + (ap_setprocattr_dir(procattr, progname) != APR_SUCCESS)) { + /* Something bad happened, give up and go away. */ + rc = -1; + } + else { + rc = ap_create_process(&procnew, p, progname, NULL, NULL, procattr); + + if (rc == APR_SUCCESS) { +#ifndef WIN32 + /* pjr - this is a cheap hack for now to get the basics working in + * stages. ap_note_subprocess and free_proc need to be redone + * to make use of ap_proc_t instead of pid. + */ + ap_get_os_proc(procnew, &fred); + ap_note_subprocess(p, fred, kill_after_timeout); +#endif + if (fpin) { + ap_get_childin(fpin, procnew); + } + + if (fpout) { + ap_get_childout(fpout, procnew); + } + + if (fperr) { + ap_get_childerr(fperr, procnew); + } + } + } + + ap_unblock_alarms(); + + return(rc); } static void open_error_log(server_rec *s, ap_context_t *p) { const char *fname; + int rc; if (*s->error_fname == '|') { - FILE *dummy; - int dummyno; -#ifdef TPF - TPF_FORK_CHILD cld; - cld.filename = s->error_fname+1; - cld.subprocess_env = NULL; - cld.prog_type = FORK_NAME; - if (!ap_spawn_child(p, NULL, &cld, - kill_after_timeout, &dummy, NULL, NULL)) { -#else - if (!ap_spawn_child(p, error_log_child, (void *)(s->error_fname+1), - kill_after_timeout, &dummy, NULL, NULL)) { -#endif /* TPF */ + ap_file_t *dummy; + + /* This starts a new process... */ + rc = log_child (p, s->error_fname+1, NULL, &dummy, NULL); + if (rc != APR_SUCCESS) { perror("ap_spawn_child"); fprintf(stderr, "Couldn't fork child for ErrorLog process\n"); exit(1); } - dummyno = fileno(dummy); - ap_put_os_file(&s->error_log, &dummyno, p); + s->error_log = dummy; } #ifdef HAVE_SYSLOG @@ -276,8 +300,7 @@ } for (virt = s_main->next; virt; virt = virt->next) { - if (virt->error_fname) - { + if (virt->error_fname) { for (q=s_main; q != virt; q = q->next) if (q->error_fname != NULL && strcmp(q->error_fname, virt->error_fname) == 0) @@ -506,7 +529,7 @@ void ap_log_pid(ap_context_t *p, const char *fname) { - FILE *pid_file; + ap_file_t *pid_file; struct stat finfo; static pid_t saved_pid = -1; pid_t mypid; @@ -531,14 +554,14 @@ ); } - if(!(pid_file = fopen(fname, "w"))) { + if(ap_open(&pid_file, p, fname, APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT) != APR_SUCCESS) { perror("fopen"); fprintf(stderr, "%s: could not log pid to file %s\n", ap_server_argv0, fname); exit(1); } - fprintf(pid_file, "%ld\n", (long)mypid); - fclose(pid_file); + ap_fprintf(pid_file, "%ld\n", (long)mypid); + ap_close(pid_file); saved_pid = mypid; } @@ -592,35 +615,42 @@ static int piped_log_spawn(piped_log *pl) { - int pid; + int rc; + ap_procattr_t *procattr; + ap_os_proc_t pid; + ap_proc_t *procnew; + + /* pjr - calls to block and unblock alarms weren't here before, was this */ + /* an oversight or intentional? */ +/* ap_block_alarms(); */ - pid = fork(); - if (pid == 0) { - /* XXX: this needs porting to OS2 and WIN32 */ - /* XXX: need to check what open fds the logger is actually passed, - * XXX: and CGIs for that matter ... cleanup_for_exec *should* - * XXX: close all the relevant stuff, but hey, it could be broken. */ - RAISE_SIGSTOP(PIPED_LOG_SPAWN); - /* we're now in the child */ - close(STDIN_FILENO); - dup2(pl->fds[0], STDIN_FILENO); - - ap_cleanup_for_exec(); - signal(SIGCHLD, SIG_DFL); /* for HPUX */ - signal(SIGHUP, SIG_IGN); - execl(SHELL_PATH, SHELL_PATH, "-c", pl->program, NULL); + ap_cleanup_for_exec(); +#ifdef SIGHUP + signal(SIGHUP, SIG_IGN); +#endif + if ((ap_createprocattr_init(pl->p, &procattr) != APR_SUCCESS) || + (ap_setprocattr_dir(procattr, pl->program) != APR_SUCCESS) || + (ap_set_childin(procattr, pl->fds[0], pl->fds[1]) != APR_SUCCESS)) { + /* Something bad happened, give up and go away. */ fprintf(stderr, "piped_log_spawn: unable to exec %s -c '%s': %s\n", SHELL_PATH, pl->program, strerror (errno)); - exit(1); + rc = -1; } - if (pid == -1) { - fprintf(stderr, - "piped_log_spawn: unable to fork(): %s\n", strerror (errno)); - return -1; + else { + rc = ap_create_process(pl->p, pl->program, NULL, NULL, procattr, &procnew); + + if (rc == APR_SUCCESS) { /* pjr - This no longer happens inside the child, */ + RAISE_SIGSTOP(PIPED_LOG_SPAWN); /* I am assuming that if ap_create_process was */ + /* successful that the child is running. */ + pl->pid = procnew; + ap_get_os_proc(&procnew, &pid); + ap_register_other_child(pid, piped_log_maintenance, pl, pl->fds[1]); + } } - pl->pid = pid; - ap_register_other_child(pid, piped_log_maintenance, pl, pl->fds[1]); + +/* ap_unblock_alarms(); */ + return 0; } @@ -632,13 +662,13 @@ switch (reason) { case OC_REASON_DEATH: case OC_REASON_LOST: - pl->pid = -1; + pl->pid = NULL; ap_unregister_other_child(pl); if (pl->program == NULL) { /* during a restart */ break; } - if (piped_log_spawn(pl) == -1) { + if (piped_log_spawn(pl) != APR_SUCCESS) { /* what can we do? This could be the error log we're having * problems opening up... */ fprintf(stderr, @@ -648,15 +678,15 @@ break; case OC_REASON_UNWRITABLE: - if (pl->pid != -1) { - kill(pl->pid, SIGTERM); + if (pl->pid != NULL) { + ap_kill(pl->pid, SIGTERM); } break; case OC_REASON_RESTART: pl->program = NULL; - if (pl->pid != -1) { - kill(pl->pid, SIGTERM); + if (pl->pid != NULL) { + ap_kill(pl->pid, SIGTERM); } break; @@ -670,8 +700,8 @@ { piped_log *pl = data; - if (pl->pid != -1) { - kill(pl->pid, SIGTERM); + if (pl->pid != NULL) { + ap_kill(pl->pid, SIGTERM); } ap_unregister_other_child(pl); ap_close(pl->fds[0]); @@ -695,7 +725,7 @@ pl = ap_palloc(p, sizeof (*pl)); pl->p = p; pl->program = ap_pstrdup(p, program); - pl->pid = -1; + pl->pid = NULL; if (ap_create_pipe(p, &pl->fds[0], &pl->fds[1]) != APR_SUCCESS) { int save_errno = errno; errno = save_errno; @@ -720,60 +750,22 @@ } #else -static int piped_log_child(void *cmd, ap_child_info_t *pinfo) -{ - /* Child process code for 'TransferLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - int child_pid = 1; - - ap_cleanup_for_exec(); -#ifdef SIGHUP - signal(SIGHUP, SIG_IGN); -#endif -#if defined(WIN32) - child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); - return(child_pid); -#elif defined(OS2) - /* For OS/2 we need to use a '/' and spawn the child rather than exec as - * we haven't forked */ - child_pid = spawnl(P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); - return(child_pid); -#else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - perror("exec"); - fprintf(stderr, "Exec of shell for logging failed!!!\n"); - return(child_pid); -} - - API_EXPORT(piped_log *) ap_open_piped_log(ap_context_t *p, const char *program) { piped_log *pl; - FILE *dummy; - int dummyno; -#ifdef TPF - TPF_FORK_CHILD cld; - cld.filename = (char *)program; - cld.subprocess_env = NULL; - cld.prog_type = FORK_NAME; + ap_file_t *dummy; + int rc; - if (!ap_spawn_child (p, NULL, &cld, - kill_after_timeout, &dummy, NULL, NULL)){ -#else - if (!ap_spawn_child(p, piped_log_child, (void *)program, - kill_after_timeout, &dummy, NULL, NULL)) { -#endif /* TPF */ + rc = log_child(p, program, NULL, &dummy, NULL); + if (rc != APR_SUCCESS) { perror("ap_spawn_child"); fprintf(stderr, "Couldn't fork child for piped log process\n"); exit (1); } + pl = ap_palloc(p, sizeof (*pl)); pl->p = p; - dummyno = fileno(dummy); - ap_put_os_file(&pl->write_f, &dummyno, p); + pl->write_f = dummy; return pl; } 1.2 +0 -17 apache-2.0/src/os/beos/os-inline.c Index: os-inline.c =================================================================== RCS file: /home/cvs/apache-2.0/src/os/beos/os-inline.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- os-inline.c 1999/07/12 22:51:14 1.1 +++ os-inline.c 1999/10/11 14:20:46 1.2 @@ -30,20 +30,3 @@ { return file[0] == '/'; } - -INLINE int ap_spawnvp(const char *file, char *const argv[]) -{ - int pid; - - if ((pid = fork()) == -1) { - return pid; - } else if (pid == 0) { - if (execvp(file, argv) == -1) - return -1; - else - return -1; /* If we get, we have a real error, but this keeps - us from getting a warning during compile time. */ - } else - return pid; -} - 1.4 +0 -16 apache-2.0/src/os/beos/os.c Index: os.c =================================================================== RCS file: /home/cvs/apache-2.0/src/os/beos/os.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- os.c 1999/08/31 12:33:04 1.3 +++ os.c 1999/10/11 14:20:46 1.4 @@ -11,22 +11,6 @@ return file[0] == '/'; } -int ap_spawnvp(const char *file, char *const argv[]) -{ - int pid; - - if ((pid = fork()) == -1) { - return pid; - } else if (pid == 0) { - if (execvp(file, argv) == -1) - return -1; - else - return -1; /* If we get, we have a real error, but this keeps - us from getting a warning during compile time. */ - } else - return pid; -} - /* some linkers complain unless there's at least one function in each * .o file... and extra prototype is for gcc -Wmissing-prototypes 1.3 +0 -17 apache-2.0/src/os/unix/os-inline.c Index: os-inline.c =================================================================== RCS file: /home/cvs/apache-2.0/src/os/unix/os-inline.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- os-inline.c 1999/08/26 18:06:12 1.2 +++ os-inline.c 1999/10/11 14:20:47 1.3 @@ -30,20 +30,3 @@ { return file[0] == '/'; } - -INLINE int ap_spawnvp(const char *file, char *const argv[]) -{ - int pid; - - if ((pid = fork()) == -1) { - return pid; - } else if (pid == 0) { - if (execvp(file, argv) == -1) - return -1; - else - return -1; /* If we get, we have a real error, but this keeps - us from getting a warning during compile time. */ - } else - return pid; -} - 1.3 +0 -140 apache-2.0/src/os/win32/util_win32.c Index: util_win32.c =================================================================== RCS file: /home/cvs/apache-2.0/src/os/win32/util_win32.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- util_win32.c 1999/08/31 05:35:13 1.2 +++ util_win32.c 1999/10/11 14:20:48 1.3 @@ -332,146 +332,6 @@ return stat(szPath, pStat); } -/* Fix two really crap problems with Win32 spawn[lv]e*: - * - * 1. Win32 doesn't deal with spaces in argv. - * 2. Win95 doesn't like / in cmdname. - */ - -#undef _spawnv -API_EXPORT(int) os_spawnv(int mode, const char *cmdname, - const char *const *argv) -{ - int n; - char **aszArgs; - const char *szArg; - char *szCmd; - char *s; - - szCmd = _alloca(strlen(cmdname)+1); - strcpy(szCmd, cmdname); - for (s = szCmd; *s; ++s) { - if (*s == '/') { - *s = '\\'; - } - } - - for (n = 0; argv[n]; ++n) - ; - - aszArgs = _alloca((n + 1) * sizeof(const char *)); - - for (n = 0; szArg = argv[n]; ++n) { - if (strchr(szArg, ' ')) { - int l = strlen(szArg); - - aszArgs[n] = _alloca(l + 2 + 1); - aszArgs[n][0] = '"'; - strcpy(&aszArgs[n][1], szArg); - aszArgs[n][l + 1] = '"'; - aszArgs[n][l + 2] = '\0'; - } - else { - aszArgs[n] = (char *)szArg; - } - } - - aszArgs[n] = NULL; - - return _spawnv(mode, szCmd, aszArgs); -} - -#undef _spawnve -API_EXPORT(int) os_spawnve(int mode, const char *cmdname, - const char *const *argv, const char *const *envp) -{ - int n; - char **aszArgs; - const char *szArg; - char *szCmd; - char *s; - - szCmd = _alloca(strlen(cmdname)+1); - strcpy(szCmd, cmdname); - for (s = szCmd; *s; ++s) { - if (*s == '/') { - *s = '\\'; - } - } - - for (n = 0; argv[n]; ++n) - ; - - aszArgs = _alloca((n + 1)*sizeof(const char *)); - - for (n = 0; szArg = argv[n]; ++n){ - if (strchr(szArg, ' ')) { - int l = strlen(szArg); - - aszArgs[n] = _alloca(l + 2 + 1); - aszArgs[n][0] = '"'; - strcpy(&aszArgs[n][1], szArg); - aszArgs[n][l + 1] = '"'; - aszArgs[n][l + 2] = '\0'; - } - else { - aszArgs[n] = (char *)szArg; - } - } - - aszArgs[n] = NULL; - - return _spawnve(mode, szCmd, aszArgs, envp); -} - -API_EXPORT(int) os_spawnle(int mode, const char *cmdname, ...) -{ - int n; - va_list vlist; - char **aszArgs; - const char *szArg; - const char *const *aszEnv; - char *szCmd; - char *s; - - szCmd = _alloca(strlen(cmdname)+1); - strcpy(szCmd, cmdname); - for (s = szCmd; *s; ++s) { - if (*s == '/') { - *s = '\\'; - } - } - - va_start(vlist, cmdname); - for (n = 0; va_arg(vlist, const char *); ++n) - ; - va_end(vlist); - - aszArgs = _alloca((n + 1) * sizeof(const char *)); - - va_start(vlist, cmdname); - for (n = 0; szArg = va_arg(vlist, const char *); ++n) { - if (strchr(szArg, ' ')) { - int l = strlen(szArg); - - aszArgs[n] = _alloca(l + 2 + 1); - aszArgs[n][0] = '"'; - strcpy(&aszArgs[n][1], szArg); - aszArgs[n][l + 1] = '"'; - aszArgs[n][l + 2] = '\0'; - } - else { - aszArgs[n] = (char *)szArg; - } - } - - aszArgs[n] = NULL; - - aszEnv = va_arg(vlist, const char *const *); - va_end(vlist); - - return _spawnve(mode, szCmd, aszArgs, aszEnv); -} #undef strftime