mpm_common.c revision 8966f6c6e6ed032cd17d020140e0ac1329d382b6
97a9a944b5887e91042b019776c41d5dd74557aferikabele/* Licensed to the Apache Software Foundation (ASF) under one or more
97a9a944b5887e91042b019776c41d5dd74557aferikabele * contributor license agreements. See the NOTICE file distributed with
97a9a944b5887e91042b019776c41d5dd74557aferikabele * this work for additional information regarding copyright ownership.
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * The ASF licenses this file to You under the Apache License, Version 2.0
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * (the "License"); you may not use this file except in compliance with
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * the License. You may obtain a copy of the License at
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
5a58787efeb02a1c3f06569d019ad81fd2efa06end * http://www.apache.org/licenses/LICENSE-2.0
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
5a58787efeb02a1c3f06569d019ad81fd2efa06end */
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end/* The purpose of this file is to store the code that MOST mpm's will need
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen * this does not mean a function only goes into this file if every MPM needs
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * it. It means that if a function is needed by more than one MPM, and
5a58787efeb02a1c3f06569d019ad81fd2efa06end * future maintenance would be served by making the code common, then the
5a58787efeb02a1c3f06569d019ad81fd2efa06end * function belongs here.
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * This is going in src/main because it is not platform specific, it is
5a58787efeb02a1c3f06569d019ad81fd2efa06end * specific to multi-process servers, but NOT to Unix. Which is why it
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd * does not belong in src/os/unix
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd */
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd#include "apr.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "apr_thread_proc.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "apr_signal.h"
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd#include "apr_strings.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end#define APR_WANT_STRFUNC
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "apr_want.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "apr_getopt.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "apr_optional.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "apr_allocator.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "httpd.h"
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#include "http_config.h"
ced7ef1f8c0df1805da0e87dbc5a1b6282910573nd#include "http_core.h"
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive#include "http_log.h"
ced7ef1f8c0df1805da0e87dbc5a1b6282910573nd#include "http_main.h"
b21197dc8e6b8c764fdcc24d4bae8b0eebb6bc4end#include "mpm_common.h"
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive#include "mod_core.h"
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive#include "ap_mpm.h"
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive#include "ap_listen.h"
97a9a944b5887e91042b019776c41d5dd74557aferikabele#include "util_mutex.h"
f8396ed8364b56ec8adeaa49cac35a929758a29eslive
ffb01336be79c64046b636e59fa8ddca8ec029edsf#include "scoreboard.h"
f8396ed8364b56ec8adeaa49cac35a929758a29eslive
f8396ed8364b56ec8adeaa49cac35a929758a29eslive#ifdef HAVE_PWD_H
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include <pwd.h>
5a58787efeb02a1c3f06569d019ad81fd2efa06end#endif
5a58787efeb02a1c3f06569d019ad81fd2efa06end#ifdef HAVE_GRP_H
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include <grp.h>
deeee6bb6fd94c0ba5f3730b58abd9d299c89ccdnd#endif
4db28ee269aa06f7c6232e11cd01f58c3349af23noodl#if APR_HAVE_UNISTD_H
117c1f888a14e73cdd821dc6c23eb0411144a41cnd#include <unistd.h>
117c1f888a14e73cdd821dc6c23eb0411144a41cnd#endif
4a31db3c3a0202003c1b9f87affa7cc143e120e5sf
117c1f888a14e73cdd821dc6c23eb0411144a41cnd/* we know core's module_index is 0 */
ffb01336be79c64046b636e59fa8ddca8ec029edsf#undef APLOG_MODULE_INDEX
117c1f888a14e73cdd821dc6c23eb0411144a41cnd#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cnd#if AP_ENABLE_EXCEPTION_HOOK
2bc7f1cf720973a67f8ff7a8d523e40569ae5b6cndAPR_HOOK_STRUCT(
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(fatal_exception)
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(monitor)
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(drop_privileges)
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(mpm)
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(mpm_query)
117c1f888a14e73cdd821dc6c23eb0411144a41cnd APR_HOOK_LINK(mpm_register_timed_callback)
87ffb6e33f3cbef3b9bb406cc2d27039fa336eaatrawick APR_HOOK_LINK(mpm_register_socket_callback)
4db28ee269aa06f7c6232e11cd01f58c3349af23noodl APR_HOOK_LINK(mpm_unregister_socket_callback)
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(mpm_get_name)
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(end_generation)
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(child_status)
5a58787efeb02a1c3f06569d019ad81fd2efa06end)
5a58787efeb02a1c3f06569d019ad81fd2efa06endAP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
5a58787efeb02a1c3f06569d019ad81fd2efa06end (ap_exception_info_t *ei), (ei), OK, DECLINED)
654d8eb036bedc99e90e11910ee02d3421417697rbowen#else
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohAPR_HOOK_STRUCT(
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(monitor)
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(drop_privileges)
5a58787efeb02a1c3f06569d019ad81fd2efa06end APR_HOOK_LINK(mpm)
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf APR_HOOK_LINK(mpm_query)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick APR_HOOK_LINK(mpm_register_timed_callback)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick APR_HOOK_LINK(mpm_register_socket_callback)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick APR_HOOK_LINK(mpm_unregister_socket_callback)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick APR_HOOK_LINK(mpm_get_name)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive APR_HOOK_LINK(end_generation)
654d8eb036bedc99e90e11910ee02d3421417697rbowen APR_HOOK_LINK(child_status)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#endif
06ba4a61654b3763ad65f52283832ebf058fdf1csliveAP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
92510838f2eb125726e15c5eb4f7a23c7a0396e4slive (apr_pool_t *p, server_rec *s), (p, s), OK, DECLINED)
97a9a944b5887e91042b019776c41d5dd74557aferikabeleAP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
654d8eb036bedc99e90e11910ee02d3421417697rbowen (apr_pool_t * pchild, server_rec * s),
92510838f2eb125726e15c5eb4f7a23c7a0396e4slive (pchild, s), OK, DECLINED)
97a9a944b5887e91042b019776c41d5dd74557aferikabeleAP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive (pconf, plog, s), DECLINED)
92510838f2eb125726e15c5eb4f7a23c7a0396e4sliveAP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm_query,
92510838f2eb125726e15c5eb4f7a23c7a0396e4slive (int query_code, int *result, apr_status_t *_rv),
ffb01336be79c64046b636e59fa8ddca8ec029edsf (query_code, result, _rv), DECLINED)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawickAP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
ffb01336be79c64046b636e59fa8ddca8ec029edsf (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (t, cbfn, baton), APR_ENOTIMPL)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawickAP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_socket_callback,
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (apr_socket_t **s, apr_pool_t *p, int for_read, ap_mpm_callback_fn_t *cbfn, void *baton),
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (s, p, for_read, cbfn, baton), APR_ENOTIMPL)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawickAP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_unregister_socket_callback,
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf (apr_socket_t **s, apr_pool_t *p),
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (s, p), APR_ENOTIMPL)
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsfAP_IMPLEMENT_HOOK_VOID(end_generation,
ffb01336be79c64046b636e59fa8ddca8ec029edsf (server_rec *s, ap_generation_t gen),
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (s, gen))
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsfAP_IMPLEMENT_HOOK_VOID(child_status,
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status status),
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (s,pid,gen,slot,status))
77c77cf89621f21c8e2bbad63058b5eaa5f88d4ajim
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick/* hooks with no args are implemented last, after disabling APR hook probes */
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf#if defined(APR_HOOK_PROBES_ENABLED)
ced7ef1f8c0df1805da0e87dbc5a1b6282910573nd#undef APR_HOOK_PROBES_ENABLED
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick#undef APR_HOOK_PROBE_ENTRY
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf#undef APR_HOOK_PROBE_RETURN
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
ced7ef1f8c0df1805da0e87dbc5a1b6282910573nd#undef APR_HOOK_PROBE_INVOKE
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick#undef APR_HOOK_PROBE_COMPLETE
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
4a31db3c3a0202003c1b9f87affa7cc143e120e5sf#undef APR_HOOK_INT_DCL_UD
4a31db3c3a0202003c1b9f87affa7cc143e120e5sf#define APR_HOOK_INT_DCL_UD
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick#endif
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawickAP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick (void),
ffb01336be79c64046b636e59fa8ddca8ec029edsf (), NULL)
8a6d5edcb07aeccca7afba02a17dd6904d6b206ctrawick
92510838f2eb125726e15c5eb4f7a23c7a0396e4slivetypedef struct mpm_gen_info_t {
92510838f2eb125726e15c5eb4f7a23c7a0396e4slive APR_RING_ENTRY(mpm_gen_info_t) link;
97a9a944b5887e91042b019776c41d5dd74557aferikabele int gen; /* which gen? */
92510838f2eb125726e15c5eb4f7a23c7a0396e4slive int active; /* number of active processes */
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic int done; /* gen finished? (whether or not active processes) */
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic} mpm_gen_info_t;
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalicAPR_RING_HEAD(mpm_gen_info_head_t, mpm_gen_info_t);
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalicstatic struct mpm_gen_info_head_t *geninfo, *unused_geninfo;
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalicstatic int gen_head_init; /* yuck */
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic/* variables representing config directives implemented here */
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalicAP_DECLARE_DATA const char *ap_pid_fname;
06ba4a61654b3763ad65f52283832ebf058fdf1csliveAP_DECLARE_DATA int ap_max_requests_per_child;
e8d485701957d5c6de870111c112e168a894d49andAP_DECLARE_DATA char ap_coredump_dir[MAX_STRING_LEN];
e8d485701957d5c6de870111c112e168a894d49andAP_DECLARE_DATA int ap_coredumpdir_configured;
654d8eb036bedc99e90e11910ee02d3421417697rbowenAP_DECLARE_DATA int ap_graceful_shutdown_timeout;
654d8eb036bedc99e90e11910ee02d3421417697rbowenAP_DECLARE_DATA apr_uint32_t ap_max_mem_free;
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7sliveAP_DECLARE_DATA apr_size_t ap_thread_stacksize;
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive
9bcfc3697a91b5215893a7d0206865b13fc72148nd#define ALLOCATOR_MAX_FREE_DEFAULT (2048*1024)
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive/* Set defaults for config directives implemented here. This is
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * called from core's pre-config hook, so MPMs which need to override
4a31db3c3a0202003c1b9f87affa7cc143e120e5sf * one of these should run their pre-config hook after that of core.
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive */
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slivevoid mpm_common_pre_config(apr_pool_t *pconf)
709e3a21ba73b8433462959cd56c773454b34441trawick{
709e3a21ba73b8433462959cd56c773454b34441trawick ap_pid_fname = DEFAULT_PIDLOG;
709e3a21ba73b8433462959cd56c773454b34441trawick ap_max_requests_per_child = 0; /* unlimited */
709e3a21ba73b8433462959cd56c773454b34441trawick apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
709e3a21ba73b8433462959cd56c773454b34441trawick ap_coredumpdir_configured = 0;
709e3a21ba73b8433462959cd56c773454b34441trawick ap_graceful_shutdown_timeout = 0; /* unlimited */
709e3a21ba73b8433462959cd56c773454b34441trawick ap_max_mem_free = ALLOCATOR_MAX_FREE_DEFAULT;
5a58787efeb02a1c3f06569d019ad81fd2efa06end ap_thread_stacksize = 0; /* use system default */
5a58787efeb02a1c3f06569d019ad81fd2efa06end}
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd/* number of calls to wait_or_timeout between writable probes */
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd#ifndef INTERVAL_OF_WRITABLE_PROBES
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#define INTERVAL_OF_WRITABLE_PROBES 10
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#endif
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohstatic int wait_or_timeout_counter;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohAP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode,
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh apr_proc_t *ret, apr_pool_t *p,
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh server_rec *s)
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh{
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh apr_status_t rv;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh ++wait_or_timeout_counter;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh wait_or_timeout_counter = 0;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh ap_run_monitor(p, s);
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh if (APR_STATUS_IS_EINTR(rv)) {
5effc8b39fae5cd169d17f342bfc265705840014rbowen ret->pid = -1;
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen return;
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd }
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd if (APR_STATUS_IS_CHILD_DONE(rv)) {
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd return;
5a58787efeb02a1c3f06569d019ad81fd2efa06end }
apr_sleep(apr_time_from_sec(1));
ret->pid = -1;
return;
}
#if defined(TCP_NODELAY)
void ap_sock_disable_nagle(apr_socket_t *s)
{
/* The Nagle algorithm says that we should delay sending partial
* packets in hopes of getting more data. We don't want to do
* this; we are not telnet. There are bad interactions between
* persistent connections and Nagle's algorithm that have very severe
* performance penalties. (Failing to disable Nagle is not much of a
* problem with simple HTTP.)
*
* In spite of these problems, failure here is not a shooting offense.
*/
apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf, APLOGNO(00542)
"apr_socket_opt_set: (TCP_NODELAY)");
}
}
#endif
#ifdef HAVE_GETPWNAM
AP_DECLARE(uid_t) ap_uname2id(const char *name)
{
struct passwd *ent;
if (name[0] == '#')
return (atoi(&name[1]));
if (!(ent = getpwnam(name))) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00543)
"%s: bad user name %s", ap_server_argv0, name);
exit(1);
}
return (ent->pw_uid);
}
#endif
#ifdef HAVE_GETGRNAM
AP_DECLARE(gid_t) ap_gname2id(const char *name)
{
struct group *ent;
if (name[0] == '#')
return (atoi(&name[1]));
if (!(ent = getgrnam(name))) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00544)
"%s: bad group name %s", ap_server_argv0, name);
exit(1);
}
return (ent->gr_gid);
}
#endif
#ifndef HAVE_INITGROUPS
int initgroups(const char *name, gid_t basegid)
{
#if defined(_OSD_POSIX) || defined(OS2) || defined(WIN32) || defined(NETWARE)
return 0;
#else
gid_t groups[NGROUPS_MAX];
struct group *g;
int index = 0;
setgrent();
groups[index++] = basegid;
while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
if (g->gr_gid != basegid) {
char **names;
for (names = g->gr_mem; *names != NULL; ++names) {
if (!strcmp(*names, name))
groups[index++] = g->gr_gid;
}
}
}
endgrent();
return setgroups(index, groups);
#endif
}
#endif /* def HAVE_INITGROUPS */
/* standard mpm configuration handling */
const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (cmd->server->is_virtual) {
return "PidFile directive not allowed in <VirtualHost>";
}
ap_pid_fname = arg;
return NULL;
}
void ap_mpm_dump_pidfile(apr_pool_t *p, apr_file_t *out)
{
apr_file_printf(out, "PidFile: \"%s\"\n",
ap_runtime_dir_relative(p, ap_pid_fname));
}
const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (!strcasecmp(cmd->cmd->name, "MaxRequestsPerChild")) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00545)
"MaxRequestsPerChild is deprecated, use "
"MaxConnectionsPerChild instead.");
}
ap_max_requests_per_child = atoi(arg);
return NULL;
}
const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
const char *arg)
{
apr_finfo_t finfo;
const char *fname;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
fname = ap_server_root_relative(cmd->pool, arg);
if (!fname) {
return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
arg, NULL);
}
if (apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) {
return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
" does not exist", NULL);
}
if (finfo.filetype != APR_DIR) {
return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
" is not a directory", NULL);
}
apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
ap_coredumpdir_configured = 1;
return NULL;
}
AP_DECLARE(const char *)ap_mpm_set_graceful_shutdown(cmd_parms *cmd,
void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
ap_graceful_shutdown_timeout = atoi(arg);
return NULL;
}
const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
const char *arg)
{
long value;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
value = strtol(arg, NULL, 10);
if (value < 0 || errno == ERANGE)
return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
arg, NULL);
ap_max_mem_free = (apr_uint32_t)value * 1024;
return NULL;
}
const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
const char *arg)
{
long value;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
value = strtol(arg, NULL, 10);
if (value < 0 || errno == ERANGE)
return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
arg, NULL);
ap_thread_stacksize = (apr_size_t)value;
return NULL;
}
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
{
apr_status_t rv;
if (ap_run_mpm_query(query_code, result, &rv) == DECLINED) {
rv = APR_EGENERAL;
}
return rv;
}
static void end_gen(mpm_gen_info_t *gi)
{
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
"end of generation %d", gi->gen);
ap_run_end_generation(ap_server_conf, gi->gen);
APR_RING_REMOVE(gi, link);
APR_RING_INSERT_HEAD(unused_geninfo, gi, mpm_gen_info_t, link);
}
apr_status_t ap_mpm_end_gen_helper(void *unused) /* cleanup on pconf */
{
int gen = ap_config_generation - 1; /* differs from MPM generation */
mpm_gen_info_t *cur;
if (geninfo == NULL) {
/* initial pconf teardown, MPM hasn't run */
return APR_SUCCESS;
}
cur = APR_RING_FIRST(geninfo);
while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
cur->gen != gen) {
cur = APR_RING_NEXT(cur, link);
}
if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
/* last child of generation already exited */
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
"no record of generation %d", gen);
}
else {
cur->done = 1;
if (cur->active == 0) {
end_gen(cur);
}
}
return APR_SUCCESS;
}
/* core's child-status hook
* tracks number of remaining children per generation and
* runs the end-generation hook when the last child of
* a generation exits
*/
void ap_core_child_status(server_rec *s, pid_t pid,
ap_generation_t gen, int slot,
mpm_child_status status)
{
mpm_gen_info_t *cur;
const char *status_msg = "unknown status";
if (!gen_head_init) { /* where to run this? */
gen_head_init = 1;
geninfo = apr_pcalloc(s->process->pool, sizeof *geninfo);
unused_geninfo = apr_pcalloc(s->process->pool, sizeof *unused_geninfo);
APR_RING_INIT(geninfo, mpm_gen_info_t, link);
APR_RING_INIT(unused_geninfo, mpm_gen_info_t, link);
}
cur = APR_RING_FIRST(geninfo);
while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
cur->gen != gen) {
cur = APR_RING_NEXT(cur, link);
}
switch(status) {
case MPM_CHILD_STARTED:
status_msg = "started";
if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
/* first child for this generation */
if (!APR_RING_EMPTY(unused_geninfo, mpm_gen_info_t, link)) {
cur = APR_RING_FIRST(unused_geninfo);
APR_RING_REMOVE(cur, link);
cur->active = cur->done = 0;
}
else {
cur = apr_pcalloc(s->process->pool, sizeof *cur);
}
cur->gen = gen;
APR_RING_ELEM_INIT(cur, link);
APR_RING_INSERT_HEAD(geninfo, cur, mpm_gen_info_t, link);
}
ap_random_parent_after_fork();
++cur->active;
break;
case MPM_CHILD_EXITED:
status_msg = "exited";
if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00546)
"no record of generation %d of exiting child %" APR_PID_T_FMT,
gen, pid);
}
else {
--cur->active;
if (!cur->active && cur->done) { /* no children, server has stopped/restarted */
end_gen(cur);
}
}
break;
case MPM_CHILD_LOST_SLOT:
status_msg = "lost slot";
/* we don't track by slot, so it doesn't matter */
break;
}
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, s,
"mpm child %" APR_PID_T_FMT " (gen %d/slot %d) %s",
pid, gen, slot, status_msg);
}
AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
{
return ap_run_mpm_register_timed_callback(t, cbfn, baton);
}
AP_DECLARE(apr_status_t) ap_mpm_register_socket_callback(apr_socket_t **s, apr_pool_t *p, int for_read, ap_mpm_callback_fn_t *cbfn, void *baton)
{
return ap_run_mpm_register_socket_callback(s, p, for_read, cbfn, baton);
}
AP_DECLARE(apr_status_t) ap_mpm_unregister_socket_callback(apr_socket_t **s, apr_pool_t *p)
{
return ap_run_mpm_unregister_socket_callback(s, p);
}
AP_DECLARE(const char *)ap_show_mpm(void)
{
const char *name = ap_run_mpm_get_name();
if (!name) {
name = "";
}
return name;
}
AP_DECLARE(const char *)ap_check_mpm(void)
{
static const char *last_mpm_name = NULL;
if (!_hooks.link_mpm || _hooks.link_mpm->nelts == 0)
return "No MPM loaded.";
else if (_hooks.link_mpm->nelts > 1)
return "More than one MPM loaded.";
if (last_mpm_name) {
if (strcmp(last_mpm_name, ap_show_mpm())) {
return "The MPM cannot be changed during restart.";
}
}
else {
last_mpm_name = apr_pstrdup(ap_pglobal, ap_show_mpm());
}
return NULL;
}