From: Jeff Trawick Date: Wed, 12 Feb 2003 18:27:37 +0000 (+0000) Subject: mod_cgi, mod_cgid, mod_ext_filter: Log errors when scripts cannot X-Git-Tag: pre_ajp_proxy~2157 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b535985b9b0f3e6b35403c5edc70d93c2a46813e;p=apache mod_cgi, mod_cgid, mod_ext_filter: Log errors when scripts cannot be started on Unix because of such problems as bad permissions, bad shebang line, etc. Some minor points: If mod_ext_filter debug is enabled, we go ahead and burn cycles in the parent to try to discover when we won't be able to exec the script. The mod_cgid handler wasn't communicating the right log level to the daemon; that was required to get the child errfn to spit out the right message, and it may fix an existing problem. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98630 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index ef6117e7b2..7219687a17 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ Changes with Apache 2.1.0-dev [Remove entries to the current 2.0 section below, when backported] + *) mod_cgi, mod_cgid, mod_ext_filter: Log errors when scripts cannot + be started on Unix because of such problems as bad permissions, + bad shebang line, etc. [Jeff Trawick] + *) Fix suexec compile error under SUNOS4, where strerror() doesn't exist. PR 5913, 9977. [Jonathan W Miner ] diff --git a/modules/filters/mod_ext_filter.c b/modules/filters/mod_ext_filter.c index 4a1ecc9f35..6031cd45a8 100644 --- a/modules/filters/mod_ext_filter.c +++ b/modules/filters/mod_ext_filter.c @@ -119,8 +119,11 @@ static const server_rec *main_server; static apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *); #define DBGLVL_SHOWOPTIONS 1 +#define DBGLVL_ERRORCHECK 2 #define DBGLVL_GORY 9 +#define ERRFN_USERDATA_KEY "EXTFILTCHILDERRFN" + static void *create_ef_dir_conf(apr_pool_t *p, char *dummy) { ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t)); @@ -420,6 +423,17 @@ static apr_status_t ef_close_file(void *vfile) return apr_file_close(vfile); } +static void child_errfn(apr_pool_t *p, apr_status_t err, const char *desc) +{ + request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, p); + r = vr; + + ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, "%s", desc); +} + /* init_ext_filter_process: get the external filter process going * This is per-filter-instance (i.e., per-request) initialization. */ @@ -451,6 +465,15 @@ static apr_status_t init_ext_filter_process(ap_filter_t *f) ap_assert(rc == APR_SUCCESS); } + rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn); + ap_assert(rc == APR_SUCCESS); + apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p); + + if (dc->debug >= DBGLVL_ERRORCHECK) { + rc = apr_procattr_error_check_set(ctx->procattr, 1); + ap_assert(rc == APR_SUCCESS); + } + /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO, * and QUERY_STRING_UNESCAPED */ diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c index 6effc7f777..3d9e1284b5 100644 --- a/modules/generators/mod_cgi.c +++ b/modules/generators/mod_cgi.c @@ -122,6 +122,8 @@ static int is_scriptaliased(request_rec *r) #define DEFAULT_LOGBYTES 10385760 #define DEFAULT_BUFBYTES 1024 +#define ERRFN_USERDATA_KEY "CGICHILDERRFN" + typedef struct { const char *logname; long logbytes; @@ -380,6 +382,18 @@ static void add_ssi_vars(request_rec *r) } } +static void cgi_child_errfn(apr_pool_t *pool, apr_status_t err, + const char *description) +{ + request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); + r = vr; + + ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, "%s", description); +} + static apr_status_t run_cgi_child(apr_file_t **script_out, apr_file_t **script_in, apr_file_t **script_err, @@ -452,12 +466,15 @@ static apr_status_t run_cgi_child(apr_file_t **script_out, e_info->cmd_type)) != APR_SUCCESS) || ((rc = apr_procattr_detach_set(procattr, - e_info->detached)) != APR_SUCCESS)) { + e_info->detached)) != APR_SUCCESS) || + ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) { /* Something bad happened, tell the world. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "couldn't set child process attributes: %s", r->filename); } else { + apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, p); + procnew = apr_pcalloc(p, sizeof(*procnew)); if (e_info->prog_type == RUN_AS_SSI) { SPLIT_AND_PASS_PRETAG_BUCKETS(*(e_info->bb), e_info->ctx, diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c index a147d6019e..4ce4ec7019 100644 --- a/modules/generators/mod_cgid.c +++ b/modules/generators/mod_cgid.c @@ -155,6 +155,8 @@ static int is_scriptaliased(request_rec *r) #define SSI_REQ 2 #define GETPID_REQ 3 /* get the pid of script created for prior request */ +#define ERRFN_USERDATA_KEY "CGIDCHILDERRFN" + /* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's * pending connection queue. If a bunch of cgi requests arrive at about * the same time, connections from httpd threads/processes will back up @@ -202,6 +204,7 @@ typedef struct { apr_size_t uri_len; apr_size_t args_len; apr_size_t mod_userdir_user_len; + int loglevel; /* to stuff in server_rec */ } cgid_req_t; /* This routine is called to create the argument list to be passed @@ -349,6 +352,7 @@ static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, if (stat != APR_SUCCESS) { return stat; } + r->server->loglevel = req->loglevel; if (req->req_type == GETPID_REQ) { /* no more data sent for this request */ return APR_SUCCESS; @@ -480,6 +484,7 @@ static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, if (user != NULL) { req.mod_userdir_user_len = strlen(user); } + req.loglevel = r->server->loglevel; /* Write the request header */ if ((stat = sock_write(fd, &req, sizeof(req))) != APR_SUCCESS) { @@ -565,6 +570,22 @@ static void daemon_signal_handler(int sig) } } +static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, + const char *description) +{ + request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); + r = vr; + + /* sure we got r, but don't call ap_log_rerror() because we don't + * have r->headers_in and possibly other storage referenced by + * ap_log_rerror() + */ + ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, "%s", description); +} + static int cgid_server(void *data) { struct sockaddr_un unix_addr; @@ -711,12 +732,15 @@ static int cgid_server(void *data) ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) || ((rc = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || - ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS)) { + ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS) || + ((rc = apr_procattr_child_errfn_set(procattr, cgid_child_errfn)) != APR_SUCCESS)) { /* Something bad happened, tell the world. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "couldn't set child process attributes: %s", r->filename); } else { + apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); + argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); /* We want to close sd2 for the new CGI process too.