diff --git a/modules/fcgid/Makefile.apxs b/modules/fcgid/Makefile.apxs index 771adda..500449b 100644 --- a/modules/fcgid/Makefile.apxs +++ b/modules/fcgid/Makefile.apxs @@ -16,7 +16,6 @@ fcgid_srcdir=../.. builddir=. srcdir=. -MOD_FCGID_LDADD = -export-symbols-regex fcgid_module CLEAN_TARGETS = *.loT include $(exp_installbuilddir)/special.mk diff --git a/modules/fcgid/Makefile.apxs.r1848311 b/modules/fcgid/Makefile.apxs.r1848311 deleted file mode 100644 index 500449b..0000000 --- a/modules/fcgid/Makefile.apxs.r1848311 +++ /dev/null @@ -1,28 +0,0 @@ -## -## Makefile.apxs -- Build procedure for mod_fcgid Apache module -## -## Do not use this target; build from the mod_fcgid dir root -## - -# top_builddir and top_srcdir are misnomers, because build/*.mk -# scripts expect it them be the parent of the build directory, -# and fail to trust the installbuilddir. -exp_installbuilddir=$(shell $(APXS) -q exp_installbuilddir) -top_srcdir=$(installbuilddir)/.. -top_builddir=$(installbuilddir)/.. - -fcgid_builddir=../.. -fcgid_srcdir=../.. -builddir=. -srcdir=. - -CLEAN_TARGETS = *.loT -include $(exp_installbuilddir)/special.mk - -all: local-shared-build all-recursive - -# additional defines, includes and libraries -DEFS=-DFCGID_APXS_BUILD -INCLUDES=-I$(builddir) -I$(srcdir) -I$(fcgid_srcdir)/include -#LIBS=-Lmy/lib/dir -lmylib - diff --git a/modules/fcgid/config.m4 b/modules/fcgid/config.m4 index cc488b4..eb8f67f 100644 --- a/modules/fcgid/config.m4 +++ b/modules/fcgid/config.m4 @@ -43,11 +43,6 @@ APACHE_MODULE(fcgid, [FastCGI support (mod_fcgid)], $fcigd_objs, , no, [ AC_CHECK_HEADERS(sys/mman.h) AC_CHECK_HEADERS(sys/mutex.h) AC_CHECK_HEADERS(sys/shm.h) - if test "x$enable_fcgid" = "xshared"; then - # The only symbol which needs to be exported is the module - # structure, so ask libtool to hide everything else: - APR_ADDTO(MOD_FCGID_LDADD, [-export-symbols-regex fcgid_module]) - fi ]) dnl # end of module specific part diff --git a/modules/fcgid/config.m4.r1848311 b/modules/fcgid/config.m4.r1848311 deleted file mode 100644 index eb8f67f..0000000 --- a/modules/fcgid/config.m4.r1848311 +++ /dev/null @@ -1,49 +0,0 @@ -dnl Licensed to the Apache Software Foundation (ASF) under one or more -dnl contributor license agreements. See the NOTICE file distributed with -dnl this work for additional information regarding copyright ownership. -dnl The ASF licenses this file to You under the Apache License, Version 2.0 -dnl (the "License"); you may not use this file except in compliance with -dnl the License. You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. - -dnl # start of module specific part -APACHE_MODPATH_INIT(fcgid) - -case $host in - *mingw*) - fcgid_platform_objs="fcgid_pm_win.lo fcgid_proc_win.lo fcgid_proctbl_win.lo" - ;; - *) - fcgid_platform_objs="fcgid_pm_unix.lo fcgid_proc_unix.lo fcgid_proctbl_unix.lo fcgid_mutex_unix.lo" - ;; -esac - -dnl # list of module object files -fcigd_objs="dnl -mod_fcgid.lo dnl -fcgid_bridge.lo dnl -fcgid_conf.lo dnl -fcgid_pm_main.lo dnl -fcgid_protocol.lo dnl -fcgid_spawn_ctl.lo dnl -fcgid_bucket.lo dnl -fcgid_filter.lo dnl -$fcgid_platform_objs dnl -" - -APACHE_MODULE(fcgid, [FastCGI support (mod_fcgid)], $fcigd_objs, , no, [ - AC_CHECK_HEADERS(sys/file.h) - AC_CHECK_HEADERS(sys/mman.h) - AC_CHECK_HEADERS(sys/mutex.h) - AC_CHECK_HEADERS(sys/shm.h) -]) - -dnl # end of module specific part -APACHE_MODPATH_FINISH diff --git a/modules/fcgid/fcgid_bridge.c b/modules/fcgid/fcgid_bridge.c index 3e1d7d1..c8b45c2 100644 --- a/modules/fcgid/fcgid_bridge.c +++ b/modules/fcgid/fcgid_bridge.c @@ -522,8 +522,7 @@ handle_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf, } static int add_request_body(request_rec *r, apr_pool_t *request_pool, - apr_bucket_brigade *output_brigade, - apr_off_t *body_length) + apr_bucket_brigade *output_brigade) { apr_bucket *bucket_input, *bucket_header; apr_file_t *fd = NULL; @@ -726,49 +725,22 @@ static int add_request_body(request_rec *r, apr_pool_t *request_pool, } APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header); - *body_length = request_size; - return 0; } int bridge_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf) { - apr_bucket_brigade *output_brigade, *body_brigade; + apr_bucket_brigade *output_brigade; apr_bucket *bucket_eos; - char **envp; + char **envp = ap_create_environment(r->pool, + r->subprocess_env); int rc; /* Create brigade for the request to fastcgi server */ - body_brigade - = apr_brigade_create(r->pool, r->connection->bucket_alloc); output_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); - /* In responder mode, handle the request body up front to ensure - * the content-length is known (even if the request body is - * chunked) and sent in the header. */ - if (role == FCGI_RESPONDER) { - apr_off_t body_length; - - rc = add_request_body(r, r->pool, body_brigade, &body_length); - if (rc) { - return rc; - } - - if (body_length && !apr_table_get(r->headers_in, "Content-Length")) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "mod_fcgid: dechunked request body length %" APR_OFF_T_FMT, - body_length); - - apr_table_set(r->subprocess_env, "CONTENT_LENGTH", - apr_off_t_toa(r->pool, body_length)); - apr_table_unset(r->subprocess_env, "HTTP_TRANSFER_ENCODING"); - } - } - - envp = ap_create_environment(r->pool, r->subprocess_env); - - /* Build the begin request and environ request, add them to output_brigade */ + /* Build the begin request and environ request, append them to output_brigade */ if (!build_begin_block (role, r, r->connection->bucket_alloc, output_brigade) || !build_env_block(r, envp, r->connection->bucket_alloc, @@ -778,8 +750,12 @@ int bridge_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf) return HTTP_INTERNAL_SERVER_ERROR; } - /* Append the body output. */ - APR_BRIGADE_CONCAT(output_brigade, body_brigade); + if (role == FCGI_RESPONDER) { + rc = add_request_body(r, r->pool, output_brigade); + if (rc) { + return rc; + } + } /* The eos bucket now */ bucket_eos = apr_bucket_eos_create(r->connection->bucket_alloc); diff --git a/modules/fcgid/fcgid_bridge.c.r1848298 b/modules/fcgid/fcgid_bridge.c.r1848298 deleted file mode 100644 index c8b45c2..0000000 --- a/modules/fcgid/fcgid_bridge.c.r1848298 +++ /dev/null @@ -1,766 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "httpd.h" -#include "http_request.h" -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_pools.h" -#include "apr_file_io.h" -#include "util_script.h" -#include "fcgid_bridge.h" -#include "fcgid_pm.h" -#include "fcgid_proctbl.h" -#include "fcgid_proc.h" -#include "fcgid_conf.h" -#include "fcgid_spawn_ctl.h" -#include "fcgid_protocol.h" -#include "fcgid_bucket.h" -#define FCGID_APPLY_TRY_COUNT 2 -#define FCGID_REQUEST_COUNT 32 -#define FCGID_BRIGADE_CLEAN_STEP 32 - -static fcgid_procnode *apply_free_procnode(request_rec *r, - fcgid_command * command) -{ - /* Scan idle list, find a node match inode, deviceid and groupid - If there is no one there, return NULL */ - fcgid_procnode *previous_node, *current_node, *next_node; - fcgid_procnode *busy_list_header, *proc_table; - apr_ino_t inode = command->inode; - apr_dev_t deviceid = command->deviceid; - uid_t uid = command->uid; - gid_t gid = command->gid; - const char *cmdline = command->cmdline; - - proc_table = proctable_get_table_array(); - previous_node = proctable_get_idle_list(); - busy_list_header = proctable_get_busy_list(); - - proctable_lock(r); - current_node = &proc_table[previous_node->next_index]; - while (current_node != proc_table) { - next_node = &proc_table[current_node->next_index]; - - if (current_node->inode == inode - && current_node->deviceid == deviceid - && !strcmp(current_node->cmdline, cmdline) - && current_node->vhost_id == command->vhost_id - && current_node->uid == uid && current_node->gid == gid) { - /* Unlink from idle list */ - previous_node->next_index = current_node->next_index; - - /* Link to busy list */ - current_node->next_index = busy_list_header->next_index; - busy_list_header->next_index = current_node - proc_table; - - proctable_unlock(r); - return current_node; - } - else - previous_node = current_node; - - current_node = next_node; - } - proctable_unlock(r); - - /* Found nothing */ - return NULL; -} - -static void -return_procnode(request_rec *r, - fcgid_procnode *procnode, int communicate_error) -{ - fcgid_procnode *previous_node, *current_node, *next_node; - fcgid_procnode *proc_table = proctable_get_table_array(); - fcgid_procnode *error_list_header = proctable_get_error_list(); - fcgid_procnode *idle_list_header = proctable_get_idle_list(); - fcgid_procnode *busy_list_header = proctable_get_busy_list(); - - proctable_lock(r); - - /* Unlink the node from busy list first */ - previous_node = busy_list_header; - current_node = &proc_table[previous_node->next_index]; - while (current_node != proc_table) { - next_node = &proc_table[current_node->next_index]; - if (current_node == procnode) { - /* Unlink from busy list */ - previous_node->next_index = current_node->next_index; - break; - } - else - previous_node = current_node; - current_node = next_node; - } - - /* Return to error list or idle list */ - if (communicate_error) { - /* Link to error list */ - procnode->next_index = error_list_header->next_index; - error_list_header->next_index = procnode - proc_table; - } - else { - /* Link to idle list */ - procnode->next_index = idle_list_header->next_index; - idle_list_header->next_index = procnode - proc_table; - } - - proctable_unlock(r); -} - -static int count_busy_processes(request_rec *r, fcgid_command *command) -{ - int result = 0; - fcgid_procnode *previous_node, *current_node, *next_node; - fcgid_procnode *proc_table = proctable_get_table_array(); - fcgid_procnode *busy_list_header = proctable_get_busy_list(); - - proctable_lock(r); - - previous_node = busy_list_header; - current_node = &proc_table[previous_node->next_index]; - while (current_node != proc_table) { - if (current_node->inode == command->inode - && current_node->deviceid == command->deviceid - && !strcmp(current_node->cmdline, command->cmdline) - && current_node->vhost_id == command->vhost_id - && current_node->uid == command->uid - && current_node->gid == command->gid) { - result++; - } - next_node = &proc_table[current_node->next_index]; - current_node = next_node; - } - - proctable_unlock(r); - - return result; -} - -apr_status_t bucket_ctx_cleanup(void *thectx) -{ - /* Cleanup jobs: - 1. Free bucket buffer - 2. Return procnode - NOTE: ipc will be clean when request pool cleanup, so I don't need to close it here - */ - fcgid_bucket_ctx *ctx = (fcgid_bucket_ctx *) thectx; - request_rec *r = ctx->ipc.request; - - /* Free bucket buffer */ - if (ctx->buffer) { - apr_bucket_destroy(ctx->buffer); - ctx->buffer = NULL; - } - - /* proc_close_ipc() and ipc_handle_cleanup() do their own sanity - * checks, but we'll do our own anyway - */ - if (ctx->ipc.ipc_handle_info) { - proc_close_ipc(&ctx->ipc); - ctx->ipc.ipc_handle_info = NULL; - } - - if (ctx->procnode) { - ++ctx->procnode->requests_handled; - - /* Return procnode - I will return this slot to idle(or error) list - */ - if (ctx->procnode->diewhy == FCGID_DIE_BUSY_TIMEOUT) { - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, - "mod_fcgid: %s took longer than busy timeout " - "(%d secs)", - r->uri, - ctx->procnode->cmdopts.busy_timeout); - return_procnode(r, ctx->procnode, 1 /* busy timeout */ ); - } - else if (ctx->has_error) { - ctx->procnode->diewhy = FCGID_DIE_COMM_ERROR; - return_procnode(r, ctx->procnode, 1 /* communication error */ ); - } - else if (ctx->procnode->cmdopts.max_requests_per_process - && ctx->procnode->requests_handled >= - ctx->procnode->cmdopts.max_requests_per_process) { - ctx->procnode->diewhy = FCGID_DIE_LIFETIME_EXPIRED; - return_procnode(r, ctx->procnode, 1 /* handled all requests */ ); - } - else - return_procnode(r, ctx->procnode, 0 /* communication ok */ ); - - ctx->procnode = NULL; - } - - return APR_SUCCESS; -} - -static int getsfunc_fcgid_BRIGADE(char *buf, int len, void *arg) -{ - apr_bucket_brigade *bb = (apr_bucket_brigade *) arg; - const char *dst_end = buf + len - 1; /* leave room for terminating null */ - char *dst = buf; - apr_bucket *e = APR_BRIGADE_FIRST(bb); - apr_status_t rv; - int done = 0; - int getLF = 0; - int getColon = 0; - - while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)) { - const char *bucket_data; - apr_size_t bucket_data_len; - const char *src; - const char *src_end; - apr_bucket *next; - - rv = apr_bucket_read(e, &bucket_data, &bucket_data_len, - APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - return 0; - } - - /* Move on to next bucket if it's fastcgi header bucket */ - if (e->type == &ap_bucket_type_fcgid_header - || e->type == &apr_bucket_type_immortal) { - next = APR_BUCKET_NEXT(e); - apr_bucket_delete(e); - e = next; - if (getLF) { - done = 1; - } - continue; - } - - if (bucket_data_len == 0) - return 0; - - /* Base on RFC2616 section 4.2 */ - src = bucket_data; - src_end = bucket_data + bucket_data_len; - while ((src < src_end) && (dst < dst_end) && !done) { - if (*src == ':') - getColon = 1; - - if (getLF && ((*src != ' ' && *src != '\t') || !getColon)) { - done = 1; - getColon = 0; - break; - } - else if (getLF && (*src == ' ' || *src == '\t')) { - *dst++ = '\r'; - *dst++ = '\n'; - getLF = 0; - } - - if (*src == '\n') { - getLF = 1; - } - else if (*src != '\r') { - *dst++ = *src; - } - src++; - } - - if (src < src_end) { - apr_bucket_split(e, src - bucket_data); - } - next = APR_BUCKET_NEXT(e); - apr_bucket_delete(e); - e = next; - } - *dst = 0; - return done; -} - -static int -handle_request_ipc(request_rec *r, int role, - apr_bucket_brigade *output_brigade, - fcgid_bucket_ctx *bucket_ctx, const char **location_ptr) -{ - int cond_status; - apr_status_t rv; - apr_bucket_brigade *brigade_stdout; - char sbuf[MAX_STRING_LEN]; - const char *location; - - /* Write output_brigade to fastcgi server */ - if ((rv = proc_write_ipc(&bucket_ctx->ipc, - output_brigade)) != APR_SUCCESS) { - bucket_ctx->has_error = 1; - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Create brigade */ - brigade_stdout = - apr_brigade_create(r->pool, r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(brigade_stdout, - ap_bucket_fcgid_header_create(r->connection-> - bucket_alloc, - bucket_ctx)); - - /* Check the script header first; return immediately on error. */ - if ((cond_status = - ap_scan_script_header_err_core(r, sbuf, getsfunc_fcgid_BRIGADE, - brigade_stdout))) { - /* - * cond_status could be HTTP_NOT_MODIFIED in the case that the FCGI - * script does not set an explicit status and ap_meets_conditions, - * which is called by ap_scan_script_header_err_brigade, detects that - * the conditions of the requests are met and the response is - * not modified. - * In this case set r->status and return OK in order to prevent - * running through the error processing stack as this would - * break with mod_cache, if the conditions had been set by - * mod_cache itself to validate a stale entity. - * BTW: We circumvent the error processing stack anyway if the - * FCGI script set an explicit status code (whatever it is) and - * the only possible values for cond_status here are: - * - * HTTP_NOT_MODIFIED (set by ap_meets_conditions) - * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) - * HTTP_GATEWAY_TIME_OUT (script timed out, returned no headers) - * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the - * processing of the response of the FCGI script, e.g broken headers - * or a crashed FCGI process). - */ - if (cond_status == HTTP_NOT_MODIFIED) { - /* We need to remove our fcgid_filter before returning this - * status and code; otherwise, when ap_process_async_request() - * invokes ap_finalize_request_protocol() and that calls - * ap_pass_brigade(), fcgid_filter notices it has an empty - * brigade and returns without calling ap_pass_brigade() itself, - * which incorrectly circumvents the standard output filters. - */ - ap_remove_output_filter(r->output_filters); - - r->status = cond_status; - return OK; - } - - return cond_status; - } - - if (role == FCGI_AUTHORIZER) { - return cond_status; - } - - /* Check redirect */ - location = apr_table_get(r->headers_out, "Location"); - - if (location && location[0] == '/' && r->status == 200) { - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = apr_pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* We already read the message body (if any), so don't allow - * the redirected request to think it has one. We can ignore - * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. - */ - apr_table_unset(r->headers_in, "Content-Length"); - - /* Setting this Location header value causes handle_request() to - * invoke ap_internal_redirect_handler(); that calls - * internal_internal_redirect() which sets the new sub-request's - * r->output_filters back to r->proto_output_filters before - * running the sub-request's handler. Because we return here - * without invoking ap_pass_brigade(), our fcgid_filter is ignored. - */ - *location_ptr = location; - return OK; - } - else if (location && r->status == 200) { - /* XX Note that if a script wants to produce its own Redirect - * body, it now has to explicitly *say* "Status: 302" - */ - - /* This return code causes ap_process_async_request() to invoke - * ap_die(); that calls ap_send_error_response(), which resets - * r->output_filters back to r->proto_output_filters, thus removing - * our fcgid_filter from the output chain before making a final call - * to ap_finalize_request_protocol(), which passes the brigade to - * the standard output filters. - */ - return HTTP_MOVED_TEMPORARILY; - } - - /* Now pass any remaining response body data to output filters */ - if ((rv = ap_pass_brigade(r->output_filters, - brigade_stdout)) != APR_SUCCESS) { - if (!APR_STATUS_IS_ECONNABORTED(rv)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: ap_pass_brigade failed in " - "handle_request_ipc function"); - } - - return HTTP_INTERNAL_SERVER_ERROR; - } - - return cond_status; -} - -static int -handle_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf, - apr_bucket_brigade * output_brigade) -{ - fcgid_command fcgi_request; - fcgid_bucket_ctx *bucket_ctx; - int i, j, cond_status; - const char *location = NULL; - - bucket_ctx = apr_pcalloc(r->pool, sizeof(*bucket_ctx)); - - bucket_ctx->ipc.request = r; - apr_pool_cleanup_register(r->pool, bucket_ctx, - bucket_ctx_cleanup, apr_pool_cleanup_null); - procmgr_init_spawn_cmd(&fcgi_request, r, cmd_conf); - - /* Try to get a connected ipc handle */ - for (i = 0; i < FCGID_REQUEST_COUNT; i++) { - /* Apply a free process slot, send a spawn request if I can't get one */ - for (j = 0; j < FCGID_APPLY_TRY_COUNT; j++) { - bucket_ctx->ipc.connect_timeout = - fcgi_request.cmdopts.ipc_connect_timeout; - bucket_ctx->ipc.communation_timeout = - fcgi_request.cmdopts.ipc_comm_timeout; - - /* Apply a process slot */ - bucket_ctx->procnode = apply_free_procnode(r, &fcgi_request); - if (bucket_ctx->procnode) - break; - - /* Avoid sleeping the very first time through if there are no - busy processes; the problem is just that we haven't spawned - anything yet, so waiting is pointless */ - if (i > 0 || j > 0 || count_busy_processes(r, &fcgi_request)) { - apr_sleep(apr_time_from_sec(1)); - - bucket_ctx->procnode = apply_free_procnode(r, &fcgi_request); - if (bucket_ctx->procnode) - break; - } - - /* Send a spawn request if I can't get a process slot */ - procmgr_send_spawn_cmd(&fcgi_request, r); - } - - /* Connect to the fastcgi server */ - if (bucket_ctx->procnode) { - if (proc_connect_ipc(bucket_ctx->procnode, - &bucket_ctx->ipc) != APR_SUCCESS) { - proc_close_ipc(&bucket_ctx->ipc); - bucket_ctx->procnode->diewhy = FCGID_DIE_CONNECT_ERROR; - return_procnode(r, bucket_ctx->procnode, 1 /* has error */ ); - bucket_ctx->procnode = NULL; - } - else - break; - } - } - - /* Now I get a connected ipc handle */ - if (!bucket_ctx->procnode) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "mod_fcgid: can't apply process slot for %s", - cmd_conf->cmdline); - return HTTP_SERVICE_UNAVAILABLE; - } - bucket_ctx->active_time = bucket_ctx->procnode->last_active_time = - apr_time_now(); - bucket_ctx->procnode->diewhy = FCGID_DIE_KILLSELF; - - cond_status = handle_request_ipc(r, role, output_brigade, - bucket_ctx, &location); - - /* Release the process ASAP. This may already have been done in - * ap_pass_brigade() by fcgid_header_bucket_read(), but not in the - * case where handle_request_ipc() returned early without reading - * the body of the HTTP response. This could be because of an error, - * or because of a role or a status code which permits us to ignore - * the message body. - * - * As an example, when handling a request in the FCGI_AUTHORIZER role, - * we don't read through to the end of the response from the process, - * we just read the HTTP headers. That means each phase of the - * request handling sequence (e.g., authentication, authorization, etc.) - * will require its own process unless we make sure to always release - * any process we acquired regardless of whether we're reading the - * response body. - * - * As another example, if we perform or cause an internal redirection - * (for instance, by returning an error code that invokes a script - * handler in ap_die() because of an ErrorDocument configuration), then - * we must also release the process we acquired here so that it is - * potentially available during the next handling phase. - */ - - apr_pool_cleanup_run(r->pool, bucket_ctx, bucket_ctx_cleanup); - - /* Perform internal redirection if necessary */ - if (location) { - ap_internal_redirect_handler(location, r); - } - - /* Return condition status */ - return cond_status; -} - -static int add_request_body(request_rec *r, apr_pool_t *request_pool, - apr_bucket_brigade *output_brigade) -{ - apr_bucket *bucket_input, *bucket_header; - apr_file_t *fd = NULL; - apr_off_t cur_pos = 0, request_size = 0; - apr_status_t rv; - FCGI_Header *stdin_request_header; - fcgid_server_conf *sconf = ap_get_module_config(r->server->module_config, - &fcgid_module); - int seen_eos = 0; - - /* Stdin header and body */ - /* I have to read all the request into memory before sending it - to fastcgi application server, this prevents slow clients from - keeping the server in processing too long. - But sometimes it's not acceptable (think about uploading a large attachment) - Request will be stored in tmp file if the size larger than max_mem_request_len - */ - - apr_bucket_brigade *input_brigade = apr_brigade_create(request_pool, - r->connection-> - bucket_alloc); - apr_bucket_brigade *tmp_brigade = apr_brigade_create(request_pool, - r->connection-> - bucket_alloc); - - do { - int loop_counter = 0; - - if ((rv = ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, - APR_BLOCK_READ, - HUGE_STRING_LEN)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: can't get data from http client"); - apr_brigade_destroy(output_brigade); - apr_brigade_destroy(tmp_brigade); - apr_brigade_destroy(input_brigade); - return HTTP_INTERNAL_SERVER_ERROR; - } - - - - while ((bucket_input = APR_BRIGADE_FIRST(input_brigade)) != APR_BRIGADE_SENTINEL(input_brigade)) { - const char *data; - apr_size_t len; - apr_bucket *bucket_stdin; - - ++loop_counter; - if ((loop_counter % FCGID_BRIGADE_CLEAN_STEP) == 0) { - apr_brigade_cleanup(tmp_brigade); - } - APR_BUCKET_REMOVE(bucket_input); - APR_BRIGADE_INSERT_TAIL(tmp_brigade, bucket_input); - - if (APR_BUCKET_IS_EOS(bucket_input)) { - seen_eos = 1; - break; - } - - if (APR_BUCKET_IS_METADATA(bucket_input)) - continue; - - if ((rv = apr_bucket_read(bucket_input, &data, &len, - APR_BLOCK_READ)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: can't read request from HTTP client"); - apr_brigade_destroy(input_brigade); - apr_brigade_destroy(tmp_brigade); - apr_brigade_destroy(output_brigade); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Append a header, and the the bucket */ - stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header), - r->connection-> - bucket_alloc); - bucket_header = - apr_bucket_heap_create((const char *) stdin_request_header, - sizeof(*stdin_request_header), - apr_bucket_free, - r->connection->bucket_alloc); - - request_size += len; - if (request_size > sconf->max_request_len) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "mod_fcgid: HTTP request length %" APR_OFF_T_FMT - " (so far) exceeds MaxRequestLen (%" - APR_OFF_T_FMT ")", request_size, - sconf->max_request_len); - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (request_size > sconf->max_mem_request_len) { - apr_size_t wrote_len; - static const char *fd_key = "fcgid_fd"; - - if (fd == NULL) { - void *tmp; - apr_pool_userdata_get(&tmp, fd_key, r->connection->pool); - fd = tmp; - - if (fd != NULL) { - if ((rv = apr_file_trunc(fd, 0)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: can't truncate existing " - "temporary file"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - } - - if (fd == NULL) { - const char *tempdir = NULL; - char *template; - - rv = apr_temp_dir_get(&tempdir, r->pool); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: can't get tmp dir"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - apr_filepath_merge(&template, tempdir, - "fcgid.tmp.XXXXXX", - APR_FILEPATH_NATIVE, r->pool); - rv = apr_file_mktemp(&fd, template, 0, - r->connection->pool); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, - "mod_fcgid: can't open tmp file fot stdin request"); - return HTTP_INTERNAL_SERVER_ERROR; - } - apr_pool_userdata_set((const void *) fd, fd_key, - apr_pool_cleanup_null, - r->connection->pool); - } - - /* Write request to tmp file */ - if ((rv = - apr_file_write_full(fd, (const void *) data, len, - &wrote_len)) != APR_SUCCESS - || len != wrote_len) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, - rv, r, - "mod_fcgid: can't write tmp file for stdin request"); - return HTTP_INTERNAL_SERVER_ERROR; - } - /* Create file bucket */ - bucket_stdin = - apr_bucket_file_create(fd, cur_pos, len, r->pool, - r->connection->bucket_alloc); - cur_pos += len; - } - else { - if (APR_BUCKET_IS_HEAP(bucket_input)) - apr_bucket_copy(bucket_input, &bucket_stdin); - else { - /* mod_ssl have a bug? */ - char *pcopydata = - apr_bucket_alloc(len, r->connection->bucket_alloc); - memcpy(pcopydata, data, len); - bucket_stdin = - apr_bucket_heap_create(pcopydata, len, - apr_bucket_free, - r->connection->bucket_alloc); - } - } - - if (!init_header(FCGI_STDIN, 1, len, 0, stdin_request_header)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "mod_fcgid: header overflow"); - apr_brigade_destroy(input_brigade); - apr_brigade_destroy(tmp_brigade); - apr_brigade_destroy(output_brigade); - return HTTP_INTERNAL_SERVER_ERROR; - } - APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header); - APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_stdin); - } - - apr_brigade_cleanup(input_brigade); - apr_brigade_cleanup(tmp_brigade); - } - while (!seen_eos); - - apr_brigade_destroy(input_brigade); - apr_brigade_destroy(tmp_brigade); - - /* Append an empty body stdin header */ - stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header), - r->connection->bucket_alloc); - bucket_header = - apr_bucket_heap_create((const char *) stdin_request_header, - sizeof(*stdin_request_header), - apr_bucket_free, r->connection->bucket_alloc); - if (!init_header(FCGI_STDIN, 1, 0, 0, stdin_request_header)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "mod_fcgid: header overflow"); - return HTTP_INTERNAL_SERVER_ERROR; - } - APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header); - - return 0; -} - -int bridge_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf) -{ - apr_bucket_brigade *output_brigade; - apr_bucket *bucket_eos; - char **envp = ap_create_environment(r->pool, - r->subprocess_env); - int rc; - - /* Create brigade for the request to fastcgi server */ - output_brigade = - apr_brigade_create(r->pool, r->connection->bucket_alloc); - - /* Build the begin request and environ request, append them to output_brigade */ - if (!build_begin_block - (role, r, r->connection->bucket_alloc, output_brigade) - || !build_env_block(r, envp, r->connection->bucket_alloc, - output_brigade)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "mod_fcgid: can't build begin or env request"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (role == FCGI_RESPONDER) { - rc = add_request_body(r, r->pool, output_brigade); - if (rc) { - return rc; - } - } - - /* The eos bucket now */ - bucket_eos = apr_bucket_eos_create(r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_eos); - - /* Bridge the request */ - return handle_request(r, role, cmd_conf, output_brigade); -} diff --git a/modules/fcgid/fcgid_conf.h b/modules/fcgid/fcgid_conf.h index 47d68bb..60aeee8 100644 --- a/modules/fcgid/fcgid_conf.h +++ b/modules/fcgid/fcgid_conf.h @@ -138,7 +138,7 @@ typedef struct { * to limit shared memory use */ #define INITENV_KEY_LEN 64 -#define INITENV_VAL_LEN 256 +#define INITENV_VAL_LEN 128 #define INITENV_CNT 64 typedef struct { char initenv_key[INITENV_CNT][INITENV_KEY_LEN]; diff --git a/modules/fcgid/fcgid_conf.h.r1847623 b/modules/fcgid/fcgid_conf.h.r1847623 deleted file mode 100644 index 60aeee8..0000000 --- a/modules/fcgid/fcgid_conf.h.r1847623 +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FCGID_CONF_H -#define FCGID_CONF_H - -#define MODFCGID_COPYRIGHT \ - "Copyright 2013 The Apache Software Foundation." - -#define MODFCGID_VERSION_MAJOR 2 -#define MODFCGID_VERSION_MINOR 3 -#define MODFCGID_VERSION_SUBVER 9 -#define MODFCGID_VERSION_DEV 0 - -#if MODFCGID_VERSION_DEV -#define MODFCGID_VERSION_DEVSTR "-dev" -#else -#define MODFCGID_VERSION_DEVSTR "" -#endif - -/* APR_STRINGIFY is defined here, and also in apr_general.h, so wrap it */ -#ifndef APR_STRINGIFY -/** Properly quote a value as a string in the C preprocessor */ -#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) -/** Helper macro for APR_STRINGIFY */ -#define APR_STRINGIFY_HELPER(n) #n -#endif - -#define MODFCGID_REVISION APR_STRINGIFY(MODFCGID_VERSION_MAJOR) \ - "." APR_STRINGIFY(MODFCGID_VERSION_MINOR) \ - "." APR_STRINGIFY(MODFCGID_VERSION_SUBVER) -#define MODFCGID_VERSION MODFCGID_REVISION MODFCGID_VERSION_DEVSTR - -#define MODFCGID_PRODUCT "mod_fcgid/" MODFCGID_VERSION - -#ifndef VERSION_ONLY - -#include "apr_user.h" -#include "fcgid_global.h" - -typedef struct { - const char *cgipath; /* executable file path */ - const char *cmdline; /* entire command line */ - apr_ino_t inode; - apr_dev_t deviceid; - int virtual; -} fcgid_cmd_conf; - -typedef struct { - /* not based on config */ - int vhost_id; - /* global only */ - apr_hash_t *cmdopts_hash; - int busy_scan_interval; - int error_scan_interval; - int idle_scan_interval; - int max_process_count; - int php_fix_pathinfo_enable; - char *shmname_path; - char *sockname_prefix; - int spawn_score; - int spawnscore_uplimit; - int termination_score; - int time_score; - int zombie_scan_interval; -#ifdef WIN32 - /* FcgidWin32PreventOrphans - Win32 CGI processes automatic cleanup */ - HANDLE hJobObjectForAutoCleanup; -#endif - /* global or vhost - * scalar values have corresponding _set field to aid merging - */ - apr_table_t *default_init_env; - int ipc_comm_timeout; - int ipc_comm_timeout_set; - int ipc_connect_timeout; - int ipc_connect_timeout_set; - int max_mem_request_len; - int max_mem_request_len_set; - apr_off_t max_request_len; - int max_request_len_set; - int max_requests_per_process; - int max_requests_per_process_set; - int output_buffersize; - int output_buffersize_set; - apr_array_header_t *pass_headers; - int max_class_process_count; - int max_class_process_count_set; - int min_class_process_count; - int min_class_process_count_set; - int busy_timeout; - int busy_timeout_set; - int idle_timeout; - int idle_timeout_set; - int proc_lifetime; - int proc_lifetime_set; -} fcgid_server_conf; - -typedef struct { - /* scalar values have corresponding _set field to aid merging */ - - /* wrapper */ - apr_hash_t *wrapper_info_hash; - - /* authenticator */ - fcgid_cmd_conf *authenticator_info; - int authenticator_authoritative; - int authenticator_authoritative_set; - - /* authorizer */ - fcgid_cmd_conf *authorizer_info; - int authorizer_authoritative; - int authorizer_authoritative_set; - - /* access check */ - fcgid_cmd_conf *access_info; - int access_authoritative; - int access_authoritative_set; -} fcgid_dir_conf; - -/* processing options which are sent to the PM with a spawn request - * and/or configurable via FCGIDCmdOptions; envvars are kept in a - * separate structure to keep them out of the process table in order - * to limit shared memory use - */ -#define INITENV_KEY_LEN 64 -#define INITENV_VAL_LEN 128 -#define INITENV_CNT 64 -typedef struct { - char initenv_key[INITENV_CNT][INITENV_KEY_LEN]; - char initenv_val[INITENV_CNT][INITENV_VAL_LEN]; -} fcgid_cmd_env; - -typedef struct { - int busy_timeout; - int idle_timeout; - int ipc_comm_timeout; - int ipc_connect_timeout; - int max_class_process_count; - int max_requests_per_process; - int min_class_process_count; - int proc_lifetime; - fcgid_cmd_env *cmdenv; -} fcgid_cmd_options; - -void *create_fcgid_server_config(apr_pool_t * p, server_rec * s); -void *merge_fcgid_server_config(apr_pool_t * p, void *basev, - void *overridesv); - -void *create_fcgid_dir_config(apr_pool_t * p, char *dummy); -void *merge_fcgid_dir_config(apr_pool_t * p, void *basev, - void *overridesv); - -const char *set_idle_timeout(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_idle_scan_interval(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_busy_timeout(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_busy_scan_interval(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_proc_lifetime(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_error_scan_interval(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_zombie_scan_interval(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_socketpath(cmd_parms * cmd, void *dummy, const char *arg); - -const char *set_shmpath(cmd_parms * cmd, void *dummy, const char *arg); - -const char *set_time_score(cmd_parms * cmd, void *dummy, const char *arg); - -const char *set_max_request_len(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_max_mem_request_len(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_termination_score(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_spawn_score(cmd_parms * cmd, void *dummy, const char *arg); - -const char *set_spawnscore_uplimit(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_max_process(cmd_parms * cmd, void *dummy, const char *arg); - -const char *set_max_class_process(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_min_class_process(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_ipc_connect_timeout(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_ipc_comm_timeout(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_output_buffersize(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *add_default_env_vars(cmd_parms * cmd, void *sconf, - const char *name, const char *value); - -const char *add_pass_headers(cmd_parms * cmd, void *sconf, - const char *name); - -apr_array_header_t *get_pass_headers(request_rec * r); - -const char *set_wrapper_config(cmd_parms * cmd, void *dummy, - const char *wrapper, const char *extension, const char* virtual); -fcgid_cmd_conf *get_wrapper_info(const char *cgipath, request_rec * r); - -const char *set_authenticator_info(cmd_parms * cmd, void *config, - const char *arg); -const char *set_authenticator_authoritative(cmd_parms * cmd, - void *config, int arg); -fcgid_cmd_conf *get_authenticator_info(request_rec * r, int *authoritative); - -const char *set_authorizer_info(cmd_parms * cmd, void *config, - const char *arg); -const char *set_authorizer_authoritative(cmd_parms * cmd, - void *config, int arg); -fcgid_cmd_conf *get_authorizer_info(request_rec * r, int *authoritative); - -const char *set_access_info(cmd_parms * cmd, void *config, - const char *arg); -const char *set_access_authoritative(cmd_parms * cmd, - void *config, int arg); -fcgid_cmd_conf *get_access_info(request_rec * r, int *authoritative); - -const char *set_php_fix_pathinfo_enable(cmd_parms * cmd, void *dummy, - const char *arg); - -const char *set_max_requests_per_process(cmd_parms * cmd, void *dummy, - const char *arg); - -#ifdef WIN32 -const char *set_win32_prevent_process_orphans(cmd_parms *cmd, void *dummy, - int arg); -#endif - -const char *set_cmd_options(cmd_parms *cmd, void *dummy, - const char *arg); - -void get_cmd_options(request_rec *r, const char *cmdpath, - fcgid_cmd_options *cmdopts, fcgid_cmd_env *cmdenv); - - -AP_MODULE_DECLARE_DATA extern module fcgid_module; - -#endif - -#endif diff --git a/modules/fcgid/fcgid_proc_unix.c b/modules/fcgid/fcgid_proc_unix.c index 7f37495..218f3f7 100644 --- a/modules/fcgid/fcgid_proc_unix.c +++ b/modules/fcgid/fcgid_proc_unix.c @@ -762,18 +762,14 @@ apr_status_t proc_write_ipc(fcgid_ipc *ipc_handle, struct iovec vec[FCGID_VEC_COUNT]; int nvec = 0; apr_bucket *e; - apr_bucket_brigade *tmpbb = apr_brigade_create(output_brigade->p, - output_brigade->bucket_alloc); - - while (!APR_BRIGADE_EMPTY(output_brigade)) - { - e = APR_BRIGADE_FIRST(output_brigade); + for (e = APR_BRIGADE_FIRST(output_brigade); + e != APR_BRIGADE_SENTINEL(output_brigade); + e = APR_BUCKET_NEXT(e)) { apr_size_t len; const char* base; if (APR_BUCKET_IS_METADATA(e)) { - apr_bucket_delete(e); continue; } @@ -784,9 +780,6 @@ apr_status_t proc_write_ipc(fcgid_ipc *ipc_handle, return rv; } - APR_BUCKET_REMOVE(e); - APR_BRIGADE_INSERT_TAIL(tmpbb, e); - vec[nvec].iov_len = len; vec[nvec].iov_base = (char*) base; if (nvec == (FCGID_VEC_COUNT - 1)) { @@ -796,7 +789,6 @@ apr_status_t proc_write_ipc(fcgid_ipc *ipc_handle, FCGID_VEC_COUNT)) != APR_SUCCESS) return rv; nvec = 0; - apr_brigade_cleanup(tmpbb); } else nvec++; @@ -808,7 +800,6 @@ apr_status_t proc_write_ipc(fcgid_ipc *ipc_handle, return rv; } - apr_brigade_destroy(tmpbb); return APR_SUCCESS; } diff --git a/modules/fcgid/fcgid_proc_unix.c.r1847624 b/modules/fcgid/fcgid_proc_unix.c.r1847624 deleted file mode 100644 index 218f3f7..0000000 --- a/modules/fcgid/fcgid_proc_unix.c.r1847624 +++ /dev/null @@ -1,879 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include /* For TCP_NODELAY */ -#include -#include -#define CORE_PRIVATE -#include "httpd.h" -#include "apr_version.h" -#include "apr_thread_proc.h" -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_pools.h" -#include "apr_network_io.h" -#include "ap_mpm.h" -#include "http_config.h" -#include "mpm_common.h" -#include "util_script.h" -#include "unixd.h" -#include "mod_core.h" -#include "mod_cgi.h" -#include "apr_tables.h" -#include "fcgid_proc.h" -#include "fcgid_proctbl.h" -#include "fcgid_protocol.h" -#include "fcgid_conf.h" -#include "fcgid_pm.h" -#include "fcgid_spawn_ctl.h" - -#if MODULE_MAGIC_NUMBER_MAJOR < 20081201 -#define ap_unixd_config unixd_config -#endif - -#if APR_MAJOR_VERSION < 1 -#define APR_FPROT_UWRITE APR_UWRITE -#define APR_FPROT_UREAD APR_UREAD -#define APR_FPROT_UEXECUTE APR_UEXECUTE -#endif - -#define DEFAULT_FCGID_LISTENBACKLOG 5 - -typedef struct { - int handle_socket; -} fcgid_namedpipe_handle; - -static int g_process_counter = 0; - -static apr_status_t ap_unix_create_privileged_process(apr_proc_t *newproc, - const char *progname, - const char *const *args, - const char *const *env, - apr_procattr_t *attr, - ap_unix_identity_t *ugid, - apr_pool_t *p) -{ - int i = 0; - const char **newargs; - const char *newprogname; - const char *execuser, *execgroup; - const char *argv0; - - if (!ap_unixd_config.suexec_enabled) { - return apr_proc_create(newproc, progname, args, env, attr, p); - } - - argv0 = ap_strrchr_c(progname, '/'); - /* Allow suexec's "/" check to succeed */ - if (argv0 != NULL) { - argv0++; - } else { - argv0 = progname; - } - - - if (ugid->userdir) { - execuser = apr_psprintf(p, "~%ld", (long) ugid->uid); - } - else { - execuser = apr_psprintf(p, "%ld", (long) ugid->uid); - } - execgroup = apr_psprintf(p, "%ld", (long) ugid->gid); - - if (!execuser || !execgroup) { - return APR_ENOMEM; - } - - i = 0; - while (args[i]) { - i++; - } - /* allocate space for 4 new args, the input args, and a null terminator */ - newargs = apr_palloc(p, sizeof(char *) * (i + 4)); - newprogname = SUEXEC_BIN; - newargs[0] = SUEXEC_BIN; - newargs[1] = execuser; - newargs[2] = execgroup; - newargs[3] = apr_pstrdup(p, argv0); - - /* - ** using a shell to execute suexec makes no sense thus - ** we force everything to be APR_PROGRAM, and never - ** APR_SHELLCMD - */ - if (apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) { - return APR_EGENERAL; - } - - i = 1; - do { - newargs[i + 3] = args[i]; - } while (args[i++]); - - return apr_proc_create(newproc, newprogname, newargs, env, attr, p); -} - -static apr_status_t fcgid_create_privileged_process(apr_proc_t *newproc, - const char *progname, - const char *const *args, - const char *const *env, - apr_procattr_t *attr, - fcgid_proc_info *procinfo, - apr_pool_t *p) -{ - ap_unix_identity_t ugid; - - if (!ap_unixd_config.suexec_enabled - || (procinfo->uid == (uid_t) - 1 - && procinfo->gid == (gid_t) - 1)) { - return apr_proc_create(newproc, progname, args, env, attr, p); - } - - ugid.gid = procinfo->gid; - ugid.uid = procinfo->uid; - ugid.userdir = procinfo->userdir; - return ap_unix_create_privileged_process(newproc, progname, args, env, - attr, &ugid, p); -} - -static apr_status_t socket_file_cleanup(void *theprocnode) -{ - fcgid_procnode *procnode = (fcgid_procnode *) theprocnode; - - unlink(procnode->socket_path); - return APR_SUCCESS; -} - -static void log_setid_failure(const char *proc_type, - const char *id_type, - uid_t user_id) -{ - char errno_desc[120]; - char errmsg[240]; - - apr_strerror(errno, errno_desc, sizeof errno_desc); - apr_snprintf(errmsg, sizeof errmsg, - "(%d)%s: %s unable to set %s to %ld\n", - errno, errno_desc, proc_type, id_type, (long)user_id); - write(STDERR_FILENO, errmsg, strlen(errmsg)); -} - -/* When suexec is enabled, this runs in the forked child - * process prior to exec(). - */ -static apr_status_t exec_setuid_cleanup(void *dummy) -{ - if (seteuid(0) == -1) { - log_setid_failure("mod_fcgid child", "effective uid", 0); - _exit(1); - } - if (setuid(ap_unixd_config.user_id) == -1) { - log_setid_failure("mod_fcgid child", "uid", ap_unixd_config.user_id); - _exit(1); - } - return APR_SUCCESS; -} - -apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, - fcgid_procnode *procnode) -{ - server_rec *main_server = procinfo->main_server; - fcgid_server_conf *sconf = ap_get_module_config(main_server->module_config, - &fcgid_module); - apr_status_t rv = APR_SUCCESS; - apr_file_t *file; - apr_proc_t tmpproc; - int omask, retcode, unix_socket; - char **proc_environ; - struct sockaddr_un unix_addr; - apr_procattr_t *procattr = NULL; - int len; - const char **wargv; - - /* Build wrapper args */ - apr_tokenize_to_argv(cmdline, (char ***)&wargv, procnode->proc_pool); - - /* - Create UNIX domain socket before spawn - */ - - /* Generate a UNIX domain socket file path */ - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - len = apr_snprintf(unix_addr.sun_path, sizeof(unix_addr.sun_path), - "%s/%" APR_PID_T_FMT ".%d", sconf->sockname_prefix, - getpid(), g_process_counter++); - - /* check for truncation of the socket path - * - * cheap but overly zealous check for sun_path overflow: if length of - * prepared string is at the limit, assume truncation - */ - if (len + 1 == sizeof(unix_addr.sun_path) - || len >= sizeof procnode->socket_path) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server, - "mod_fcgid: socket path length exceeds compiled-in limits"); - return APR_EGENERAL; - } - - apr_cpystrn(procnode->socket_path, unix_addr.sun_path, - sizeof(procnode->socket_path)); - - /* truncation already checked for in handler or FcgidWrapper parser */ - AP_DEBUG_ASSERT(wargv[0] != NULL); - AP_DEBUG_ASSERT(strlen(wargv[0]) < sizeof(procnode->executable_path)); - apr_cpystrn(procnode->executable_path, wargv[0], - sizeof(procnode->executable_path)); - - /* Unlink the file just in case */ - unlink(unix_addr.sun_path); - - /* Create the socket */ - if ((unix_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "mod_fcgid: couldn't create unix domain socket"); - return errno; - } - - /* Register cleanups to - * 1. Unlink the socket when the process exits - * 2. (suexec mode only, in the child cleanup) Switch to the configured uid - */ - if (ap_unixd_config.suexec_enabled) { - apr_pool_cleanup_register(procnode->proc_pool, - procnode, socket_file_cleanup, - exec_setuid_cleanup); - } - else { - apr_pool_cleanup_register(procnode->proc_pool, - procnode, socket_file_cleanup, - apr_pool_cleanup_null); - } - - /* Bind the socket */ - omask = umask(0077); - retcode = bind(unix_socket, (struct sockaddr *) &unix_addr, - sizeof(unix_addr)); - umask(omask); - if (retcode < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "mod_fcgid: couldn't bind unix domain socket %s", - unix_addr.sun_path); - close(unix_socket); - return errno; - } - - /* IPC directory permissions are safe, but avoid confusion */ - /* Not all flavors of unix use the current umask for AF_UNIX perms */ - - rv = apr_file_perms_set(unix_addr.sun_path, - APR_FPROT_UREAD|APR_FPROT_UWRITE|APR_FPROT_UEXECUTE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, main_server, - "mod_fcgid: Couldn't set permissions on unix domain socket %s", - unix_addr.sun_path); - return rv; - } - - /* Listen the socket */ - if (listen(unix_socket, DEFAULT_FCGID_LISTENBACKLOG) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "mod_fcgid: couldn't listen on unix domain socket"); - close(unix_socket); - return errno; - } - - /* Correct the file owner */ - if (!geteuid()) { - if (chown(unix_addr.sun_path, ap_unixd_config.user_id, -1) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, - "mod_fcgid: couldn't change owner of unix domain socket %s", - unix_addr.sun_path); - close(unix_socket); - return errno; - } - } - - { - int oldflags = fcntl(unix_socket, F_GETFD, 0); - - if (oldflags < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: fcntl F_GETFD failed"); - close(unix_socket); - return errno; - } - - oldflags |= FD_CLOEXEC; - if (fcntl(unix_socket, F_SETFD, oldflags) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: fcntl F_SETFD failed"); - close(unix_socket); - return errno; - } - } - - /* Build environment variables */ - proc_environ = ap_create_environment(procnode->proc_pool, - procinfo->proc_environ); - if (!proc_environ) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: can't build environment variables"); - close(unix_socket); - return APR_ENOMEM; - } - - /* Prepare the fork */ - if ((rv = apr_procattr_create(&procattr, procnode->proc_pool)) != APR_SUCCESS - || (rv = apr_procattr_child_err_set(procattr, - procinfo->main_server->error_log, - NULL)) != APR_SUCCESS - || (rv = apr_procattr_child_out_set(procattr, - procinfo->main_server->error_log, - NULL)) != APR_SUCCESS - || (rv = apr_procattr_dir_set(procattr, - ap_make_dirstr_parent(procnode->proc_pool, - wargv[0]))) != APR_SUCCESS - || (rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS - || (rv = apr_os_file_put(&file, &unix_socket, 0, - procnode->proc_pool)) != APR_SUCCESS - || (rv = apr_procattr_child_in_set(procattr, file, NULL)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, - "mod_fcgid: couldn't set child process attributes: %s", - unix_addr.sun_path); - close(unix_socket); - return rv; - } - - /* fork and exec now */ - /* Note, don't pass &(procnode->proc_id) to fcgid_create_privileged_process(), - * for it's a share memory address, both parent and child process may modify - * procnode->proc_id->pid, so sometimes it's 0 and sometimes it's >0 - */ - rv = fcgid_create_privileged_process(&tmpproc, wargv[0], wargv, - (const char *const *)proc_environ, - procattr, procinfo, - procnode->proc_pool); - - if (ap_unixd_config.suexec_enabled) { - /* Prior to creating the child process, a child cleanup was registered - * to switch the uid in the child. No-op the child cleanup for this - * pool so that it won't run again as other child processes are created. - * (The cleanup will be registered for the pool associated with those - * processes too.) - */ - apr_pool_child_cleanup_set(procnode->proc_pool, procnode, - socket_file_cleanup, apr_pool_cleanup_null); - } - - /* Close socket before try to connect to it */ - close(unix_socket); - procnode->proc_id = tmpproc; - - if (rv != APR_SUCCESS) { - memset(&procnode->proc_id, 0, sizeof(procnode->proc_id)); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, - "mod_fcgid: can't run %s", wargv[0]); - } - - return rv; -} - -static apr_status_t proc_kill_internal(fcgid_procnode *procnode, int sig) -{ - /* su as root before sending signal, for suEXEC */ - apr_status_t rv; - - if (procnode->proc_id.pid == 0) { - /* procnode->proc_id.pid be 0 while fcgid_create_privileged_process() fail */ - return APR_SUCCESS; - } - - if (ap_unixd_config.suexec_enabled && seteuid(0) != 0) { - - /* can't gain privileges to send signal (should not occur); do NOT - * proceed, as something is broken with current identity - */ - log_setid_failure("mod_fcgid PM", "effective uid", 0); - _exit(1); - } - rv = apr_proc_kill(&(procnode->proc_id), sig); - if (ap_unixd_config.suexec_enabled && seteuid(ap_unixd_config.user_id) != 0) { - /* can't drop privileges after signalling (should not occur); do NOT - * proceed any further as euid(0)! - */ - log_setid_failure("mod_fcgid PM", "effective uid", ap_unixd_config.user_id); - _exit(1); - } - return rv; -} - -apr_status_t proc_kill_gracefully(fcgid_procnode *procnode, server_rec *main_server) -{ - return proc_kill_internal(procnode, SIGTERM); -} - -apr_status_t proc_kill_force(fcgid_procnode * procnode, - server_rec * main_server) -{ - return proc_kill_internal(procnode, SIGKILL); -} - -apr_status_t proc_wait_process(server_rec *main_server, fcgid_procnode *procnode) -{ - apr_status_t rv; - int exitcode; - apr_exit_why_e exitwhy; - - rv = apr_proc_wait(&(procnode->proc_id), &exitcode, &exitwhy, APR_NOWAIT); - if (rv == APR_CHILD_DONE || rv == APR_EGENERAL) { - /* Log why and how it die */ - proc_print_exit_info(procnode, exitcode, exitwhy, main_server); - - /* Register the death */ - register_termination(main_server, procnode); - - /* Destroy pool */ - apr_pool_destroy(procnode->proc_pool); - procnode->proc_pool = NULL; - memset(&procnode->proc_id, 0, sizeof(procnode->proc_id)); - - return APR_CHILD_DONE; - } - - return rv; -} - -static apr_status_t ipc_handle_cleanup(void *thesocket) -{ - fcgid_namedpipe_handle *handle_info = - (fcgid_namedpipe_handle *) thesocket; - - if (handle_info) { - if (handle_info->handle_socket != -1) { - close(handle_info->handle_socket); - handle_info->handle_socket = -1; - } - } - - return APR_SUCCESS; -} - -static apr_status_t set_socket_nonblock(int sd) -{ -#ifndef BEOS - int fd_flags; - - fd_flags = fcntl(sd, F_GETFL, 0); -#if defined(O_NONBLOCK) - fd_flags |= O_NONBLOCK; -#elif defined(O_NDELAY) - fd_flags |= O_NDELAY; -#elif defined(FNDELAY) - fd_flags |= FNDELAY; -#else -#error Please teach APR how to make sockets non-blocking on your platform. -#endif - if (fcntl(sd, F_SETFL, fd_flags) == -1) { - return errno; - } -#else - int on = 1; - if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) - return errno; -#endif /* BEOS */ - return APR_SUCCESS; -} - -apr_status_t proc_connect_ipc(fcgid_procnode *procnode, fcgid_ipc *ipc_handle) -{ - fcgid_namedpipe_handle *handle_info; - struct sockaddr_un unix_addr; - apr_status_t rv; - - /* Alloc memory for unix domain socket */ - ipc_handle->ipc_handle_info - = (fcgid_namedpipe_handle *) apr_pcalloc(ipc_handle->request->pool, - sizeof - (fcgid_namedpipe_handle)); - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - handle_info->handle_socket = socket(AF_UNIX, SOCK_STREAM, 0); - apr_pool_cleanup_register(ipc_handle->request->pool, - handle_info, ipc_handle_cleanup, - apr_pool_cleanup_null); - - /* Connect to fastcgi server */ - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - - /* PM already made this check for truncation */ - AP_DEBUG_ASSERT(sizeof unix_addr.sun_path > strlen(procnode->socket_path)); - apr_cpystrn(unix_addr.sun_path, procnode->socket_path, - sizeof(unix_addr.sun_path)); - - /* I am the only one who connecting the server - So I don't have to worry about ECONNREFUSED(listen queue overflow) problem, - and I will never retry on error */ - if (connect(handle_info->handle_socket, (struct sockaddr *) &unix_addr, - sizeof(unix_addr)) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, apr_get_os_error(), - ipc_handle->request, - "mod_fcgid: can't connect unix domain socket: %s", - procnode->socket_path); - return APR_ECONNREFUSED; - } - - /* Set nonblock option */ - if ((rv = set_socket_nonblock(handle_info->handle_socket)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, ipc_handle->request, - "mod_fcgid: can't make unix domain socket nonblocking"); - return rv; - } - - return APR_SUCCESS; -} - -apr_status_t proc_close_ipc(fcgid_ipc * ipc_handle) -{ - apr_status_t rv; - - rv = apr_pool_cleanup_run(ipc_handle->request->pool, - ipc_handle->ipc_handle_info, - ipc_handle_cleanup); - ipc_handle->ipc_handle_info = NULL; - return rv; -} - -apr_status_t proc_read_ipc(fcgid_ipc *ipc_handle, const char *buffer, - apr_size_t *size) -{ - int retcode, unix_socket; - fcgid_namedpipe_handle *handle_info; - struct pollfd pollfds[1]; - - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - unix_socket = handle_info->handle_socket; - - do { - if ((retcode = read(unix_socket, (void *) buffer, *size)) > 0) { - *size = retcode; - return APR_SUCCESS; - } - } while (retcode == -1 && APR_STATUS_IS_EINTR(errno)); - if (retcode == -1 && !APR_STATUS_IS_EAGAIN(errno)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, - ipc_handle->request, - "mod_fcgid: error reading data from FastCGI server"); - return errno; - } - - /* I have to wait a while */ - - pollfds[0].fd = unix_socket; - pollfds[0].events = POLLIN; - do { - retcode = poll(pollfds, 1, ipc_handle->communation_timeout * 1000); - } while (retcode <= 0 && APR_STATUS_IS_EINTR(errno)); - if (retcode == -1) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, - ipc_handle->request, - "mod_fcgid: error polling unix domain socket"); - return errno; - } - else if (retcode == 0) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, - ipc_handle->request, - "mod_fcgid: read data timeout in %d seconds", - ipc_handle->communation_timeout); - return APR_ETIMEDOUT; - } - - do { - if ((retcode = read(unix_socket, (void *) buffer, *size)) > 0) { - *size = retcode; - return APR_SUCCESS; - } - } while (retcode == -1 && APR_STATUS_IS_EINTR(errno)); - - if (retcode == 0) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, - ipc_handle->request, - "mod_fcgid: error reading data, FastCGI server closed connection"); - return APR_EPIPE; - } - - ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, - ipc_handle->request, - "mod_fcgid: error reading data from FastCGI server"); - return errno; -} - -static apr_status_t socket_writev(fcgid_ipc *ipc_handle, - struct iovec *vec, int nvec, - int *writecnt) -{ - apr_status_t rv; - int retcode, unix_socket; - fcgid_namedpipe_handle *handle_info; - struct pollfd pollfds[1]; - - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - unix_socket = handle_info->handle_socket; - - /* Try nonblock write */ - do { - if ((retcode = writev(unix_socket, vec, nvec)) > 0) { - *writecnt = retcode; - return APR_SUCCESS; - } - } while (retcode == -1 && APR_STATUS_IS_EINTR(errno)); - rv = errno; - - if (APR_STATUS_IS_EAGAIN(rv)) { - /* poll() */ - pollfds[0].fd = unix_socket; - pollfds[0].events = POLLOUT; - do { - retcode = poll(pollfds, 1, ipc_handle->communation_timeout * 1000); - } while (retcode < 0 && APR_STATUS_IS_EINTR(errno)); - - if (retcode < 0) { - rv = errno; - } - else if (retcode == 0) { - rv = APR_TIMEUP; - } - else { - /* Write again */ - do { - if ((retcode = writev(unix_socket, vec, nvec)) > 0) { - *writecnt = retcode; - return APR_SUCCESS; - } - } while (retcode == -1 && APR_STATUS_IS_EINTR(errno)); - rv = errno; - } - } - - if (APR_STATUS_IS_EAGAIN(rv)) { - /* socket is writable, but we can't write the entire buffer; try to write a - * smaller amount, and if even that fails then sleep - */ - size_t to_write = vec[0].iov_len; - int slept = 0; - const apr_interval_time_t sleep_time = APR_USEC_PER_SEC / 4; - const int max_sleeps = 8; - - do { - if ((retcode = write(unix_socket, vec[0].iov_base, to_write)) > 0) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ipc_handle->request, - "wrote %d byte(s) and slept %d time(s) after EAGAIN", - retcode, slept); - *writecnt = retcode; - return APR_SUCCESS; - } - if (APR_STATUS_IS_EAGAIN(errno)) { - if (to_write == 1) { - apr_sleep(sleep_time); - ++slept; - } - else { - to_write /= 2; - } - } - } while ((APR_STATUS_IS_EINTR(errno) || APR_STATUS_IS_EAGAIN(errno)) - && slept < max_sleeps); - rv = errno; - } - - ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, - ipc_handle->request, - "mod_fcgid: error writing data to FastCGI server"); - return rv; -} - -static apr_status_t writev_it_all(fcgid_ipc *ipc_handle, - struct iovec *vec, int nvec) -{ - apr_size_t bytes_written = 0; - apr_status_t rv; - apr_size_t len = 0; - int i = 0; - int writecnt = 0; - - /* Calculate the total size */ - for (i = 0; i < nvec; i++) { - len += vec[i].iov_len; - } - - i = 0; - while (bytes_written != len) { - rv = socket_writev(ipc_handle, vec + i, nvec - i, &writecnt); - if (rv != APR_SUCCESS) - return rv; - bytes_written += writecnt; - - if (bytes_written < len) { - /* Skip over the vectors that have already been written */ - apr_size_t cnt = vec[i].iov_len; - - while (writecnt >= cnt && i + 1 < nvec) { - i++; - cnt += vec[i].iov_len; - } - - if (writecnt < cnt) { - /* Handle partial write of vec i */ - vec[i].iov_base = (char *) vec[i].iov_base + - (vec[i].iov_len - (cnt - writecnt)); - vec[i].iov_len = cnt - writecnt; - } - } - } - - return APR_SUCCESS; -} - -#define FCGID_VEC_COUNT 8 -apr_status_t proc_write_ipc(fcgid_ipc *ipc_handle, - apr_bucket_brigade *output_brigade) -{ - apr_status_t rv; - struct iovec vec[FCGID_VEC_COUNT]; - int nvec = 0; - apr_bucket *e; - - for (e = APR_BRIGADE_FIRST(output_brigade); - e != APR_BRIGADE_SENTINEL(output_brigade); - e = APR_BUCKET_NEXT(e)) { - apr_size_t len; - const char* base; - - if (APR_BUCKET_IS_METADATA(e)) { - continue; - } - - if ((rv = apr_bucket_read(e, &base, &len, - APR_BLOCK_READ)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, ipc_handle->request, - "mod_fcgid: can't read request from bucket"); - return rv; - } - - vec[nvec].iov_len = len; - vec[nvec].iov_base = (char*) base; - if (nvec == (FCGID_VEC_COUNT - 1)) { - /* It's time to write now */ - if ((rv = - writev_it_all(ipc_handle, vec, - FCGID_VEC_COUNT)) != APR_SUCCESS) - return rv; - nvec = 0; - } - else - nvec++; - } - - /* There are something left */ - if (nvec != 0) { - if ((rv = writev_it_all(ipc_handle, vec, nvec)) != APR_SUCCESS) - return rv; - } - - return APR_SUCCESS; -} - -void proc_print_exit_info(fcgid_procnode *procnode, int exitcode, - apr_exit_why_e exitwhy, server_rec *main_server) -{ - const char *diewhy = NULL; - char signal_info[HUGE_STRING_LEN]; - int signum = exitcode; - int loglevel = APLOG_INFO; - - memset(signal_info, 0, HUGE_STRING_LEN); - - /* Reasons to exit */ - switch (procnode->diewhy) { - case FCGID_DIE_KILLSELF: - diewhy = "normal exit"; - break; - case FCGID_DIE_IDLE_TIMEOUT: - diewhy = "idle timeout"; - break; - case FCGID_DIE_LIFETIME_EXPIRED: - diewhy = "lifetime expired"; - break; - case FCGID_DIE_BUSY_TIMEOUT: - diewhy = "busy timeout"; - break; - case FCGID_DIE_CONNECT_ERROR: - diewhy = "connect error"; - break; - case FCGID_DIE_COMM_ERROR: - diewhy = "communication error"; - break; - case FCGID_DIE_SHUTDOWN: - diewhy = "shutting down"; - break; - default: - loglevel = APLOG_ERR; - diewhy = "unknown"; - } - - /* Get signal info */ - if (APR_PROC_CHECK_SIGNALED(exitwhy)) { - switch (signum) { - case SIGTERM: - case SIGHUP: - case AP_SIG_GRACEFUL: - case SIGKILL: - apr_snprintf(signal_info, HUGE_STRING_LEN - 1, - "get stop signal %d", signum); - break; - - default: - loglevel = APLOG_ERR; - if (APR_PROC_CHECK_CORE_DUMP(exitwhy)) { - apr_snprintf(signal_info, HUGE_STRING_LEN - 1, - "get signal %d, possible coredump generated", - signum); - } else { - apr_snprintf(signal_info, HUGE_STRING_LEN - 1, - "get unexpected signal %d", signum); - } - } - } - else if (APR_PROC_CHECK_EXIT(exitwhy)) { - apr_snprintf(signal_info, HUGE_STRING_LEN - 1, - "terminated by calling exit(), return code: %d", - exitcode); - if (procnode->diewhy == FCGID_DIE_CONNECT_ERROR) - diewhy = "server exited"; - } - - /* Print log now */ - ap_log_error(APLOG_MARK, loglevel, 0, main_server, - "mod_fcgid: process %s(%" APR_PID_T_FMT ") exit(%s), %s", - procnode->executable_path, procnode->proc_id.pid, diewhy, signal_info); -} diff --git a/modules/fcgid/fcgid_proc_win.c b/modules/fcgid/fcgid_proc_win.c index 5b3b33a..60b26a6 100644 --- a/modules/fcgid/fcgid_proc_win.c +++ b/modules/fcgid/fcgid_proc_win.c @@ -380,22 +380,19 @@ apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, apr_bucket *bucket_request; apr_status_t rv; DWORD transferred; - apr_bucket_brigade *tmpbb = apr_brigade_create(birgade_send->p, - birgade_send->bucket_alloc); handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - while (!APR_BRIGADE_EMPTY(birgade_send)) { + for (bucket_request = APR_BRIGADE_FIRST(birgade_send); + bucket_request != APR_BRIGADE_SENTINEL(birgade_send); + bucket_request = APR_BUCKET_NEXT(bucket_request)) + { const char *write_buf; apr_size_t write_buf_len; apr_size_t has_write; - bucket_request = APR_BRIGADE_FIRST(birgade_send); - - if (APR_BUCKET_IS_METADATA(bucket_request)) { - apr_bucket_delete(bucket_request); + if (APR_BUCKET_IS_METADATA(bucket_request)) continue; - } if ((rv = apr_bucket_read(bucket_request, &write_buf, &write_buf_len, APR_BLOCK_READ)) != APR_SUCCESS) { @@ -404,9 +401,6 @@ apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, return rv; } - APR_BUCKET_REMOVE(bucket_request); - APR_BRIGADE_INSERT_TAIL(tmpbb, bucket_request); - /* Write the buffer to fastcgi server */ has_write = 0; while (has_write < write_buf_len) { @@ -417,7 +411,6 @@ apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, write_buf_len - has_write, &byteswrite, &handle_info->overlap_write)) { has_write += byteswrite; - apr_brigade_cleanup(tmpbb); continue; } else if ((rv = GetLastError()) != ERROR_IO_PENDING) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, @@ -444,7 +437,6 @@ apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, return APR_ESPIPE; } has_write += transferred; - apr_brigade_cleanup(tmpbb); continue; } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, @@ -456,7 +448,6 @@ apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, } } - apr_brigade_destroy(tmpbb); return APR_SUCCESS; } diff --git a/modules/fcgid/fcgid_proc_win.c.r1847624 b/modules/fcgid/fcgid_proc_win.c.r1847624 deleted file mode 100644 index 60b26a6..0000000 --- a/modules/fcgid/fcgid_proc_win.c.r1847624 +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "httpd.h" -#include "apr_thread_proc.h" -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_pools.h" -#include "util_script.h" -#include "mod_core.h" -#include "mod_cgi.h" -#include "apr_tables.h" -#include "fcgid_proc.h" -#include "fcgid_proctbl.h" -#include "fcgid_protocol.h" -#include "fcgid_conf.h" -#include "fcgid_pm.h" -#include "fcgid_spawn_ctl.h" -#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_" -#define FINISH_EVENT_DATA_NAME "finish_event" -#ifndef SIGKILL -#define SIGKILL 9 -#endif - -/* It's tested on WinNT ONLY, if it work on the other MS platform, let me know */ -#if WINVER < 0x0400 -#error It is tested on WinNT only -#endif - -typedef struct { - HANDLE handle_pipe; - OVERLAPPED overlap_read; - OVERLAPPED overlap_write; -} fcgid_namedpipe_handle; - -static int g_process_counter = 0; - -static apr_status_t close_finish_event(void *finishevent) -{ - HANDLE *finish_event = finishevent; - - CloseHandle(*finish_event); - return APR_SUCCESS; -} - -apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, - fcgid_procnode *procnode) -{ - HANDLE *finish_event, listen_handle; - SECURITY_ATTRIBUTES SecurityAttributes; - fcgid_server_conf *sconf; - apr_procattr_t *proc_attr; - apr_status_t rv; - apr_file_t *file; - const char * const *proc_environ; - char sock_path[FCGID_PATH_MAX]; - const char **wargv; - - /* Build wrapper args */ - apr_tokenize_to_argv(cmdline, (char ***)&wargv, procnode->proc_pool); - - memset(&SecurityAttributes, 0, sizeof(SecurityAttributes)); - - /* Prepare finish event */ - finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE)); - *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (*finish_event == NULL - || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE)) - { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: can't create mutex for subprocess"); - return APR_ENOLOCK; - } - apr_pool_cleanup_register(procnode->proc_pool, finish_event, - close_finish_event, apr_pool_cleanup_null); - - /* For proc_kill_gracefully() */ - apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME, - NULL, procnode->proc_pool); - - /* Pass the finish event id to subprocess */ - apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME, - apr_ltoa(procnode->proc_pool, (long) *finish_event)); - - /* Prepare the listen namedpipe file name (no check for truncation) */ - apr_snprintf(sock_path, sizeof sock_path, - "\\\\.\\pipe\\fcgidpipe-%lu.%d", - GetCurrentProcessId(), g_process_counter++); - - /* Prepare the listen namedpipe handle */ - SecurityAttributes.bInheritHandle = TRUE; - SecurityAttributes.nLength = sizeof(SecurityAttributes); - SecurityAttributes.lpSecurityDescriptor = NULL; - listen_handle = CreateNamedPipe(sock_path, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | - PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 8192, 8192, 0, &SecurityAttributes); - if (listen_handle == INVALID_HANDLE_VALUE) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: can't create namedpipe for subprocess"); - return APR_ENOSOCKET; - } - apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path)); - apr_cpystrn(procnode->executable_path, wargv[0], - sizeof(procnode->executable_path)); - - /* Build environment variables */ - proc_environ = (const char * const *) - ap_create_environment(procnode->proc_pool, - procinfo->proc_environ); - if (!proc_environ) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: can't build environment variables"); - return APR_ENOMEM; - } - - /* Create process now */ - if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool)) - != APR_SUCCESS - || (rv = apr_procattr_dir_set(proc_attr, - ap_make_dirstr_parent(procnode->proc_pool, - wargv[0]))) != APR_SUCCESS - || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM)) - != APR_SUCCESS - || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS - || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE, - APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS - || (rv = apr_os_file_put(&file, &listen_handle, 0, - procnode->proc_pool)) != APR_SUCCESS - || (rv = apr_procattr_child_in_set(proc_attr, file, NULL)) - != APR_SUCCESS) - { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, - "mod_fcgid: can't create FastCGI process attribute"); - CloseHandle(listen_handle); - return APR_ENOPROC; - } - - /* fork and exec now */ - rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, - proc_environ, - proc_attr, procnode->proc_pool); - - /* OK, I created the process, now put it back to idle list */ - CloseHandle(listen_handle); - - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, - "mod_fcgid: can't run %s", wargv[0]); - return rv; - } - - /* FcgidWin32PreventOrphans feature */ - sconf = ap_get_module_config(procinfo->main_server->module_config, - &fcgid_module); - - if (sconf->hJobObjectForAutoCleanup != NULL) { - /* Associate cgi process to current process */ - if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup, - procnode->proc_id.hproc) == 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), - procinfo->main_server, - "mod_fcgid: unable to assign child process to " - "job object"); - } - } - - return APR_SUCCESS; -} - -apr_status_t proc_kill_gracefully(fcgid_procnode *procnode, - server_rec *main_server) -{ - HANDLE *finish_event = NULL; - - apr_pool_userdata_get((void **) &finish_event, - FINISH_EVENT_DATA_NAME, procnode->proc_pool); - - if (finish_event != NULL) - SetEvent(*finish_event); - return APR_SUCCESS; -} - -apr_status_t proc_kill_force(fcgid_procnode *procnode, - server_rec *main_server) -{ - return apr_proc_kill(&(procnode->proc_id), SIGKILL); -} - -apr_status_t proc_wait_process(server_rec *main_server, - fcgid_procnode *procnode) -{ - apr_status_t rv; - int exitcode; - apr_exit_why_e exitwhy; - - if ((rv = apr_proc_wait(&(procnode->proc_id), &exitcode, &exitwhy, - APR_NOWAIT)) == APR_CHILD_DONE) { - /* Log why and how it die */ - proc_print_exit_info(procnode, exitcode, exitwhy, main_server); - - /* Register the death */ - register_termination(main_server, procnode); - - /* Destroy pool */ - apr_pool_destroy(procnode->proc_pool); - procnode->proc_pool = NULL; - } - - return rv; -} - -static apr_status_t ipc_handle_cleanup(void *thehandle) -{ - fcgid_namedpipe_handle *handle = thehandle; - - /* Sanity check */ - if (handle) { - if (handle->handle_pipe != INVALID_HANDLE_VALUE) - CloseHandle(handle->handle_pipe); - if (handle->overlap_read.hEvent != NULL) - CloseHandle(handle->overlap_read.hEvent); - if (handle->overlap_write.hEvent != NULL) - CloseHandle(handle->overlap_write.hEvent); - handle->handle_pipe = INVALID_HANDLE_VALUE; - handle->overlap_read.hEvent = NULL; - handle->overlap_write.hEvent = NULL; - } - - return APR_SUCCESS; -} - -apr_status_t proc_connect_ipc(fcgid_procnode *procnode, fcgid_ipc *ipc_handle) -{ - /* Prepare the ipc struct */ - fcgid_namedpipe_handle *handle_info; - - ipc_handle->ipc_handle_info = - (fcgid_namedpipe_handle *) apr_pcalloc(ipc_handle->request->pool, - sizeof - (fcgid_namedpipe_handle)); - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - - /* Prepare OVERLAPPED struct for non-block I/O */ - handle_info->overlap_read.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - handle_info->overlap_write.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - handle_info->handle_pipe = INVALID_HANDLE_VALUE; - - apr_pool_cleanup_register(ipc_handle->request->pool, - handle_info, - ipc_handle_cleanup, apr_pool_cleanup_null); - - if (handle_info->overlap_read.hEvent == NULL - || handle_info->overlap_write.hEvent == NULL) - return APR_ENOMEM; - - /* Connect to name pipe */ - handle_info->handle_pipe = CreateFile(procnode->socket_path, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - - if (handle_info->handle_pipe == INVALID_HANDLE_VALUE - && ipc_handle->connect_timeout != 0 - && GetLastError() == ERROR_PIPE_BUSY) - { - /* XXX - there appears to be a race, here - * Wait for pipe to be ready for connect, and try again - */ - if (WaitNamedPipe(procnode->socket_path, ipc_handle->connect_timeout)) - { - handle_info->handle_pipe = CreateFile(procnode->socket_path, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - } - } - - if (handle_info->handle_pipe == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) /* The process has exited */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ipc_handle->request, - "mod_fcgid: can't connect to named pipe, FastCGI" - " server %" APR_PID_T_FMT " has been terminated", - procnode->proc_id.pid); - else - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, apr_get_os_error(), - ipc_handle->request, - "mod_fcgid: can't connect to named pipe, FastCGI" - " server pid %" APR_PID_T_FMT, - procnode->proc_id.pid); - return APR_ESPIPE; - } - - /* Now named pipe connected */ - return APR_SUCCESS; -} - -apr_status_t proc_close_ipc(fcgid_ipc * ipc_handle) -{ - apr_status_t rv; - - rv = apr_pool_cleanup_run(ipc_handle->request->pool, - ipc_handle->ipc_handle_info, - ipc_handle_cleanup); - ipc_handle->ipc_handle_info = NULL; - return rv; -} - -apr_status_t proc_read_ipc(fcgid_ipc * ipc_handle, const char *buffer, - apr_size_t * size) -{ - apr_status_t rv; - fcgid_namedpipe_handle *handle_info; - DWORD bytesread; - - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - - if (ReadFile(handle_info->handle_pipe, (LPVOID) buffer, - *size, &bytesread, &handle_info->overlap_read)) { - *size = bytesread; - return APR_SUCCESS; - } else if ((rv = GetLastError()) != ERROR_IO_PENDING) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_FROM_OS_ERROR(rv), - ipc_handle->request, - "mod_fcgid: can't read from pipe"); - return rv; - } else { - /* it's ERROR_IO_PENDING */ - DWORD transferred; - DWORD dwWaitResult - = WaitForSingleObject(handle_info->overlap_read.hEvent, - ipc_handle->communation_timeout * 1000); - - if (dwWaitResult == WAIT_OBJECT_0) { - if (!GetOverlappedResult(handle_info->handle_pipe, - &handle_info->overlap_read, - &transferred, FALSE /* don't wait */ ) - || transferred == 0) { - rv = apr_get_os_error(); - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, - ipc_handle->request, - "mod_fcgid: get overlap result error"); - return rv; - } - - *size = transferred; - return APR_SUCCESS; - } else { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ipc_handle->request, - "mod_fcgid: read timeout from pipe"); - return APR_ETIMEDOUT; - } - } -} - -apr_status_t proc_write_ipc(fcgid_ipc * ipc_handle, - apr_bucket_brigade * birgade_send) -{ - fcgid_namedpipe_handle *handle_info; - apr_bucket *bucket_request; - apr_status_t rv; - DWORD transferred; - - handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; - - for (bucket_request = APR_BRIGADE_FIRST(birgade_send); - bucket_request != APR_BRIGADE_SENTINEL(birgade_send); - bucket_request = APR_BUCKET_NEXT(bucket_request)) - { - const char *write_buf; - apr_size_t write_buf_len; - apr_size_t has_write; - - if (APR_BUCKET_IS_METADATA(bucket_request)) - continue; - - if ((rv = apr_bucket_read(bucket_request, &write_buf, &write_buf_len, - APR_BLOCK_READ)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, ipc_handle->request, - "mod_fcgid: can't read request from bucket"); - return rv; - } - - /* Write the buffer to fastcgi server */ - has_write = 0; - while (has_write < write_buf_len) { - DWORD byteswrite; - - if (WriteFile(handle_info->handle_pipe, - write_buf + has_write, - write_buf_len - has_write, - &byteswrite, &handle_info->overlap_write)) { - has_write += byteswrite; - continue; - } else if ((rv = GetLastError()) != ERROR_IO_PENDING) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, - APR_FROM_OS_ERROR(rv), ipc_handle->request, - "mod_fcgid: can't write to pipe"); - return rv; - } else { - /* - it's ERROR_IO_PENDING on write - */ - DWORD dwWaitResult = - WaitForSingleObject(handle_info->overlap_write.hEvent, - ipc_handle->communation_timeout * 1000); - if (dwWaitResult == WAIT_OBJECT_0) { - if (!GetOverlappedResult(handle_info->handle_pipe, - &handle_info->overlap_write, - &transferred, - FALSE /* don't wait */ ) - || transferred == 0) - { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, - apr_get_os_error(), ipc_handle->request, - "mod_fcgid: get overlap result error"); - return APR_ESPIPE; - } - has_write += transferred; - continue; - } else { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, - ipc_handle->request, - "mod_fcgid: write timeout to pipe"); - return APR_ESPIPE; - } - } - } - } - - return APR_SUCCESS; -} - -void proc_print_exit_info(fcgid_procnode * procnode, int exitcode, - apr_exit_why_e exitwhy, server_rec * main_server) -{ - char *diewhy = NULL; - - /* Reasons to exit */ - switch (procnode->diewhy) { - case FCGID_DIE_KILLSELF: - if (exitwhy == APR_PROC_EXIT) - diewhy = "normal exit"; - else - diewhy = "access violation"; - break; - case FCGID_DIE_IDLE_TIMEOUT: - diewhy = "idle timeout"; - break; - case FCGID_DIE_LIFETIME_EXPIRED: - diewhy = "lifetime expired"; - break; - case FCGID_DIE_BUSY_TIMEOUT: - diewhy = "busy timeout"; - break; - case FCGID_DIE_CONNECT_ERROR: - diewhy = "connect error, server may has exited"; - break; - case FCGID_DIE_COMM_ERROR: - diewhy = "communication error"; - break; - case FCGID_DIE_SHUTDOWN: - diewhy = "shutting down"; - break; - default: - diewhy = "unknown"; - } - - /* Print log now */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, - "mod_fcgid: process %s(%" APR_PID_T_FMT ") exit(%s), return code %d", - procnode->executable_path, procnode->proc_id.pid, diewhy, exitcode); -} diff --git a/modules/fcgid/modules.mk.apxs b/modules/fcgid/modules.mk.apxs index b6c032b..51ad05d 100644 --- a/modules/fcgid/modules.mk.apxs +++ b/modules/fcgid/modules.mk.apxs @@ -17,7 +17,7 @@ # this is used/needed by the APACHE2 build system # mod_fcgid.la: mod_fcgid.slo fcgid_bridge.slo fcgid_conf.slo fcgid_pm_main.slo fcgid_protocol.slo fcgid_spawn_ctl.slo fcgid_proctbl_unix.slo fcgid_pm_unix.slo fcgid_proc_unix.slo fcgid_bucket.slo fcgid_filter.slo fcgid_mutex_unix.slo - $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_fcgid.lo fcgid_bridge.lo fcgid_conf.lo fcgid_pm_main.lo fcgid_protocol.lo fcgid_spawn_ctl.lo fcgid_proctbl_unix.lo fcgid_pm_unix.lo fcgid_proc_unix.lo fcgid_bucket.lo fcgid_filter.lo fcgid_mutex_unix.lo $(MOD_FCGID_LDADD) + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_fcgid.lo fcgid_bridge.lo fcgid_conf.lo fcgid_pm_main.lo fcgid_protocol.lo fcgid_spawn_ctl.lo fcgid_proctbl_unix.lo fcgid_pm_unix.lo fcgid_proc_unix.lo fcgid_bucket.lo fcgid_filter.lo fcgid_mutex_unix.lo DISTCLEAN_TARGETS = modules.mk static = shared = mod_fcgid.la diff --git a/modules/fcgid/modules.mk.apxs.r1848311 b/modules/fcgid/modules.mk.apxs.r1848311 deleted file mode 100644 index 51ad05d..0000000 --- a/modules/fcgid/modules.mk.apxs.r1848311 +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -# this is used/needed by the APACHE2 build system -# -mod_fcgid.la: mod_fcgid.slo fcgid_bridge.slo fcgid_conf.slo fcgid_pm_main.slo fcgid_protocol.slo fcgid_spawn_ctl.slo fcgid_proctbl_unix.slo fcgid_pm_unix.slo fcgid_proc_unix.slo fcgid_bucket.slo fcgid_filter.slo fcgid_mutex_unix.slo - $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_fcgid.lo fcgid_bridge.lo fcgid_conf.lo fcgid_pm_main.lo fcgid_protocol.lo fcgid_spawn_ctl.lo fcgid_proctbl_unix.lo fcgid_pm_unix.lo fcgid_proc_unix.lo fcgid_bucket.lo fcgid_filter.lo fcgid_mutex_unix.lo -DISTCLEAN_TARGETS = modules.mk -static = -shared = mod_fcgid.la -