| /* 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 "mod_perl.h" |
| |
| /* this module contains mod_perl small tweaks to the Perl runtime |
| * others (larger tweaks) are in their own modules, e.g. modperl_env.c |
| */ |
| |
| typedef struct { |
| const char *name; |
| const char *sub_name; |
| const char *core_name; |
| } modperl_perl_core_global_t; |
| |
| #define MP_PERL_CORE_GLOBAL_ENT(name) \ |
| { name, "ModPerl::Util::" name, "CORE::GLOBAL::" name } |
| |
| static modperl_perl_core_global_t MP_perl_core_global_entries[] = { |
| MP_PERL_CORE_GLOBAL_ENT("exit"), |
| { NULL }, |
| }; |
| |
| XS(XS_ModPerl__Util_exit); /* prototype to pass -Wmissing-prototypes */ |
| XS(XS_ModPerl__Util_exit) |
| { |
| dXSARGS; |
| int status; |
| if (items < 0 || items > 1) { |
| Perl_croak(aTHX_ "Usage: ModPerl::Util::exit(status=0)"); |
| } |
| /* default: 0 */ |
| status = items < 1 ? 0 : (int)SvIV(ST(0)); |
| modperl_perl_exit(aTHX_ status); |
| |
| XSRETURN_EMPTY; |
| } |
| |
| void modperl_perl_core_global_init(pTHX) |
| { |
| modperl_perl_core_global_t *cglobals = MP_perl_core_global_entries; |
| |
| while (cglobals->name) { |
| GV *gv = gv_fetchpv(cglobals->core_name, TRUE, SVt_PVCV); |
| #ifdef MUTABLE_CV |
| GvCV_set(gv, |
| MUTABLE_CV(SvREFCNT_inc(get_cv(cglobals->sub_name, TRUE)))); |
| #else |
| GvCV_set(gv, |
| (CV*)(SvREFCNT_inc(get_cv(cglobals->sub_name, TRUE)))); |
| #endif |
| GvIMPORTED_CV_on(gv); |
| cglobals++; |
| } |
| |
| newXS("ModPerl::Util::exit", XS_ModPerl__Util_exit, __FILE__); |
| } |
| |
| static void modperl_perl_ids_get(modperl_perl_ids_t *ids) |
| { |
| ids->pid = (I32)getpid(); |
| #ifdef MP_MAINTAIN_PPID |
| ids->ppid = (I32)getppid(); |
| #endif |
| #ifndef WIN32 |
| ids->uid = getuid(); |
| ids->euid = geteuid(); |
| ids->gid = getgid(); |
| ids->egid = getegid(); |
| |
| MP_TRACE_r(MP_FUNC, |
| "pid=%d, " |
| #ifdef MP_MAINTAIN_PPID |
| "ppid=%d, " |
| #endif |
| "uid=%" Uid_t_f ", euid=%" Uid_t_f ", " |
| "gid=%" Gid_t_f ", egid=%" Gid_t_f, |
| (int)ids->pid, |
| #ifdef MP_MAINTAIN_PPID |
| (int)ids->ppid, |
| #endif |
| ids->uid, ids->euid, |
| ids->gid, ids->egid); |
| #endif /* #ifndef WIN32 */ |
| } |
| |
| static void modperl_perl_init_ids(pTHX_ modperl_perl_ids_t *ids) |
| { |
| sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), ids->pid); |
| |
| #if !MP_PERL_VERSION_AT_LEAST(5, 16, 0) |
| #ifndef WIN32 |
| PL_uid = ids->uid; |
| PL_euid = ids->euid; |
| PL_gid = ids->gid; |
| PL_egid = ids->egid; |
| #endif |
| #ifdef MP_MAINTAIN_PPID |
| PL_ppid = ids->ppid; |
| #endif |
| #endif |
| } |
| |
| |
| #ifdef USE_ITHREADS |
| |
| static apr_status_t modperl_perl_init_ids_mip(pTHX_ modperl_interp_pool_t *mip, |
| void *data) |
| { |
| modperl_perl_init_ids(aTHX_ (modperl_perl_ids_t *)data); |
| return APR_SUCCESS; |
| } |
| |
| #endif /* USE_ITHREADS */ |
| |
| void modperl_perl_init_ids_server(server_rec *s) |
| { |
| modperl_perl_ids_t ids; |
| modperl_perl_ids_get(&ids); |
| #ifdef USE_ITHREADS |
| modperl_interp_mip_walk_servers(NULL, s, |
| modperl_perl_init_ids_mip, |
| (void*)&ids); |
| #else |
| modperl_perl_init_ids(aTHX_ &ids); |
| #endif |
| } |
| |
| void modperl_perl_destruct(PerlInterpreter *perl) |
| { |
| char **orig_environ = NULL; |
| PTR_TBL_t *module_commands; |
| dTHXa(perl); |
| |
| PERL_SET_CONTEXT(perl); |
| |
| modperl_perl_call_endav(aTHX); |
| |
| PL_perl_destruct_level = modperl_perl_destruct_level(); |
| |
| #ifdef USE_ENVIRON_ARRAY |
| /* XXX: otherwise Perl may try to free() environ multiple times |
| * but it wasn't Perl that modified environ |
| * at least, not if modperl is doing things right |
| * this is a bug in Perl. |
| */ |
| # ifdef WIN32 |
| /* |
| * PL_origenviron = environ; doesn't work under win32 service. |
| * we pull a different stunt here that has the same effect of |
| * tricking perl into _not_ freeing the real 'environ' array. |
| * instead temporarily swap with a dummy array we malloc |
| * here which is ok to let perl free. |
| */ |
| orig_environ = environ; |
| environ = safemalloc(2 * sizeof(char *)); |
| environ[0] = NULL; |
| # else |
| PL_origenviron = environ; |
| # endif |
| #endif |
| |
| { |
| dTHXa(perl); |
| |
| if ((module_commands = modperl_module_config_table_get(aTHX_ FALSE))) { |
| modperl_svptr_table_destroy(aTHX_ module_commands); |
| } |
| } |
| |
| modperl_env_unload(aTHX); |
| |
| perl_destruct(perl); |
| |
| /* XXX: big bug in 5.6.1 fixed in 5.7.2+ |
| * XXX: try to find a workaround for 5.6.1 |
| */ |
| #if defined(WIN32) && !defined(CLONEf_CLONE_HOST) |
| # define MP_NO_PERL_FREE |
| #endif |
| |
| #ifndef MP_NO_PERL_FREE |
| perl_free(perl); |
| #endif |
| |
| #ifdef USE_ENVIRON_ARRAY |
| if (orig_environ) { |
| environ = orig_environ; |
| } |
| #endif |
| } |
| |
| void modperl_perl_call_endav(pTHX) |
| { |
| if (PL_endav) { |
| modperl_perl_call_list(aTHX_ PL_endav, "END"); |
| } |
| } |
| |
| #if !(MP_PERL_VERSION_AT_MOST(5, 8, 0)) && \ |
| (defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT)) |
| #define MP_NEED_HASH_SEED_FIXUP |
| #endif |
| |
| #ifdef MP_NEED_HASH_SEED_FIXUP |
| static UV MP_init_hash_seed = 0; |
| static bool MP_init_hash_seed_set = FALSE; |
| #endif |
| |
| /* see modperl_hash_seed_set() */ |
| void modperl_hash_seed_init(apr_pool_t *p) |
| { |
| #ifdef MP_NEED_HASH_SEED_FIXUP |
| char *s; |
| /* check if there is a specific hash seed passed via the env var |
| * and if that's the case -- use it */ |
| apr_status_t rv = apr_env_get(&s, "PERL_HASH_SEED", p); |
| if (rv == APR_SUCCESS) { |
| if (s) { |
| while (isSPACE(*s)) s++; |
| } |
| if (s && isDIGIT(*s)) { |
| MP_init_hash_seed = (UV)Atol(s); /* XXX: Atoul()? */ |
| MP_init_hash_seed_set = TRUE; |
| } |
| } |
| |
| /* calculate our own random hash seed */ |
| if (!MP_init_hash_seed_set) { |
| apr_uuid_t *uuid = (apr_uuid_t *)apr_palloc(p, sizeof(apr_uuid_t)); |
| char buf[APR_UUID_FORMATTED_LENGTH + 1]; |
| int i; |
| |
| apr_initialize(); |
| apr_uuid_get(uuid); |
| apr_uuid_format(buf, uuid); |
| /* fprintf(stderr, "UUID: %s\n", buf); */ |
| |
| /* XXX: need a better alg to convert uuid string into a seed */ |
| for (i=0; buf[i]; i++){ |
| MP_init_hash_seed += (UV)(i+1)*(buf[i]+MP_init_hash_seed); |
| } |
| |
| MP_init_hash_seed_set = TRUE; |
| } |
| #endif |
| } |
| |
| /* before 5.8.1, perl was using HASH_SEED=0, starting from 5.8.1 |
| * it randomizes if perl was compiled with ccflags -DUSE_HASH_SEED |
| * or -DUSE_HASH_SEED_EXPLICIT, in which case we need to tell perl |
| * to use the same seed everywhere */ |
| void modperl_hash_seed_set(pTHX) |
| { |
| #ifdef MP_NEED_HASH_SEED_FIXUP |
| if (MP_init_hash_seed_set) { |
| #if MP_PERL_VERSION_AT_LEAST(5, 17, 6) |
| memcpy(PL_hash_seed, &MP_init_hash_seed, |
| sizeof(PL_hash_seed) > sizeof(MP_init_hash_seed) ? |
| sizeof(MP_init_hash_seed) : sizeof(PL_hash_seed)); |
| PL_hash_seed_set = MP_init_hash_seed_set; |
| #elif MP_PERL_VERSION_AT_LEAST(5, 8, 2) |
| PL_rehash_seed = MP_init_hash_seed; |
| PL_rehash_seed_set = MP_init_hash_seed_set; |
| #else |
| PL_hash_seed = MP_init_hash_seed; |
| PL_hash_seed_set = MP_init_hash_seed_set; |
| #endif |
| } |
| #endif |
| } |
| |
| /* |
| * Local Variables: |
| * c-basic-offset: 4 |
| * indent-tabs-mode: nil |
| * End: |
| */ |