| /* -- mod_rivet_common.c - functions likely to be shared among different |
| * components of mod_rivet.c |
| */ |
| |
| /* |
| 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_strings.h> |
| #include <apr_env.h> |
| #include <apr_file_io.h> |
| #include <apr_file_info.h> |
| #include <ap_mpm.h> |
| |
| #include "mod_rivet.h" |
| #include "rivetChannel.h" |
| #include "TclWeb.h" |
| #include "rivetParser.h" |
| #include "rivet.h" |
| #include "apache_config.h" |
| |
| /* as long as we need to emulate ap_chdir_file we need to include unistd.h */ |
| #ifdef RIVET_HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif /* RIVET_HAVE_UNISTD_H */ |
| #ifdef WIN32 |
| #include <direct.h> // provides POSIX _chdir |
| #endif /* WIN32 */ |
| |
| /* Function prototypes are defined with EXTERN. Since we are in the same DLL, |
| * no need to keep this extern... */ |
| #ifdef EXTERN |
| # undef EXTERN |
| # define EXTERN DLLEXPORT |
| #endif /* EXTERN */ |
| #include "rivetCore.h" |
| #include "mod_rivet_common.h" |
| #include "mod_rivet_cache.h" |
| |
| extern apr_threadkey_t* rivet_thread_key; |
| extern mod_rivet_globals* module_globals; |
| extern module rivet_module; |
| |
| /* |
| * -- Rivet_ReadFile |
| * |
| */ |
| |
| int |
| Rivet_ReadFile (apr_pool_t* pool,char* filename, |
| char** buffer,int* nbytes) |
| { |
| apr_finfo_t* file_info; |
| apr_file_t* apr_fp; |
| apr_size_t buffer_size; |
| |
| *nbytes = 0; |
| |
| file_info = (apr_finfo_t*) apr_palloc(pool,sizeof(apr_finfo_t)); |
| if (apr_stat(file_info,filename,APR_FINFO_SIZE,pool) != APR_SUCCESS) |
| { |
| return 1; |
| } |
| |
| if (apr_file_open(&apr_fp,filename,APR_FOPEN_READ, |
| APR_FPROT_OS_DEFAULT, |
| pool) != APR_SUCCESS) |
| { |
| return 1; |
| } |
| |
| buffer_size = file_info->size; |
| *buffer = (char*) apr_palloc(pool,buffer_size); |
| |
| if (apr_file_read(apr_fp,*buffer,&buffer_size) != APR_SUCCESS) |
| { |
| return 2; |
| } |
| |
| apr_file_close(apr_fp); |
| |
| *nbytes = (int)buffer_size; |
| return 0; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| * Rivet_CreateTclInterp -- |
| * |
| * Arguments: |
| * server_rec* s: pointer to a server_rec structure |
| * |
| * Results: |
| * pointer to a Tcl_Interp structure |
| * |
| * Side Effects: |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| static Tcl_Interp* |
| Rivet_CreateTclInterp (apr_pool_t* pool) |
| { |
| Tcl_Interp* interp; |
| |
| /* Initialize TCL stuff */ |
| Tcl_FindExecutable(RIVET_NAMEOFEXECUTABLE); |
| interp = Tcl_CreateInterp(); |
| |
| if (interp == NULL) |
| { |
| ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, pool, |
| MODNAME ": Error in Tcl_CreateInterp, aborting\n"); |
| exit(1); |
| } |
| |
| if (Tcl_Init(interp) == TCL_ERROR) |
| { |
| ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, pool, |
| MODNAME ": Error in Tcl_Init: %s, aborting\n", |
| Tcl_GetStringResult(interp)); |
| exit(1); |
| } |
| |
| return interp; |
| } |
| |
| /*--------------------------------------------------------------------- |
| * -- Rivet_RunningScripts |
| * |
| * |
| * |
| *--------------------------------------------------------------------- |
| */ |
| |
| running_scripts* Rivet_RunningScripts ( apr_pool_t* pool, |
| running_scripts* scripts, |
| rivet_server_conf* rivet_conf ) |
| { |
| RIVET_SCRIPT_INIT (pool,scripts,rivet_conf,rivet_before_script); |
| RIVET_SCRIPT_INIT (pool,scripts,rivet_conf,rivet_after_script); |
| RIVET_SCRIPT_INIT (pool,scripts,rivet_conf,rivet_error_script); |
| RIVET_SCRIPT_INIT (pool,scripts,rivet_conf,rivet_abort_script); |
| RIVET_SCRIPT_INIT (pool,scripts,rivet_conf,after_every_script); |
| |
| if (rivet_conf->request_handler != NULL) |
| { |
| char* request_handler; |
| int handler_size; |
| |
| ap_assert(Rivet_ReadFile(pool,rivet_conf->request_handler, |
| &request_handler,&handler_size) == 0); |
| |
| scripts->request_processing = |
| Tcl_NewStringObj(request_handler,handler_size); |
| |
| } else { |
| scripts->request_processing = |
| Tcl_NewStringObj(module_globals->default_handler, |
| module_globals->default_handler_size); |
| } |
| Tcl_IncrRefCount(scripts->request_processing); |
| |
| return scripts; |
| } |
| |
| /* |
| * -- Rivet_ReleaseRunningScripts |
| * |
| */ |
| |
| void Rivet_ReleaseRunningScripts (running_scripts* scripts) |
| { |
| RIVET_SCRIPT_DISPOSE(scripts,rivet_before_script); |
| RIVET_SCRIPT_DISPOSE(scripts,rivet_after_script); |
| RIVET_SCRIPT_DISPOSE(scripts,rivet_error_script); |
| RIVET_SCRIPT_DISPOSE(scripts,rivet_abort_script); |
| RIVET_SCRIPT_DISPOSE(scripts,after_every_script); |
| RIVET_SCRIPT_DISPOSE(scripts,request_processing); |
| } |
| |
| /* |
| * -- Rivet_ReleasePerDirScripts |
| * |
| */ |
| |
| void Rivet_ReleasePerDirScripts(rivet_thread_interp* rivet_interp) |
| { |
| apr_hash_t* ht = rivet_interp->per_dir_scripts; |
| apr_hash_index_t* hi; |
| Tcl_Obj* script; |
| apr_pool_t* p = rivet_interp->pool; |
| |
| for (hi = apr_hash_first(p,ht); hi; hi = apr_hash_next(hi)) |
| { |
| apr_hash_this(hi, NULL, NULL, (void*)(&script)); |
| Tcl_DecrRefCount(script); |
| } |
| |
| apr_hash_clear(ht); |
| } |
| |
| |
| /* |
| *--------------------------------------------------------------------- |
| * |
| * Rivet_PerInterpInit -- |
| * |
| * Do the initialization that needs to happen to every interpreter. |
| * |
| * Results: |
| * None. |
| * |
| * Side Effects: |
| * None. |
| * |
| *--------------------------------------------------------------------- |
| */ |
| void Rivet_PerInterpInit(rivet_thread_interp* interp_obj, |
| rivet_thread_private* private, |
| server_rec *s, |
| apr_pool_t *p) |
| { |
| rivet_interp_globals* globals = NULL; |
| Tcl_Obj* auto_path = NULL; |
| Tcl_Obj* rivet_tcl = NULL; |
| Tcl_Interp* interp = interp_obj->interp; |
| |
| ap_assert (interp != (Tcl_Interp *)NULL); |
| Tcl_Preserve (interp); |
| |
| /* Set up interpreter associated data */ |
| |
| globals = ckalloc(sizeof(rivet_interp_globals)); |
| Tcl_SetAssocData (interp,"rivet",NULL,globals); |
| |
| /* |
| * the ::rivet namespace is the only information still stored |
| * in the interpreter global data |
| */ |
| |
| /* Rivet commands namespace is created */ |
| |
| globals->rivet_ns = Tcl_CreateNamespace (interp,RIVET_NS,NULL, |
| (Tcl_NamespaceDeleteProc *)NULL); |
| |
| /* We put in front the auto_path list the path to the directory where |
| * init.tcl is located (provides package Rivet, previously RivetTcl) |
| */ |
| |
| auto_path = Tcl_GetVar2Ex(interp,"auto_path",NULL,TCL_GLOBAL_ONLY); |
| |
| rivet_tcl = Tcl_NewStringObj(RIVET_DIR,-1); |
| Tcl_IncrRefCount(rivet_tcl); |
| |
| if (Tcl_IsShared(auto_path)) { |
| auto_path = Tcl_DuplicateObj(auto_path); |
| } |
| |
| if (Tcl_ListObjReplace(interp,auto_path,0,0,1,&rivet_tcl) == TCL_ERROR) |
| { |
| ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, |
| MODNAME ": error setting auto_path: %s", |
| Tcl_GetStringFromObj(auto_path,NULL)); |
| } else { |
| Tcl_SetVar2Ex(interp,"auto_path",NULL,auto_path,TCL_GLOBAL_ONLY); |
| } |
| |
| Tcl_DecrRefCount(rivet_tcl); |
| |
| /* If the thread has private data we stuff the server conf |
| * pointer in the 'running_conf' field. |
| * Commands running ouside a request processing must figure out |
| * themselves how get a pointer to the configuration from the |
| * context (e.g. ::rivet::inspect) |
| */ |
| |
| if (private != NULL) private->running_conf = RIVET_SERVER_CONF (s->module_config); |
| |
| /* Initialize the interpreter with Rivet's Tcl commands. */ |
| Rivet_InitCore(interp,private); |
| |
| /* Create a global array with information about the server. */ |
| Rivet_InitServerVariables(interp,p); |
| |
| /* Eval Rivet's init.tcl file to load in the Tcl-level commands. */ |
| |
| /* Watch out! Calling Tcl_PkgRequire with a version number binds this module to |
| * the Rivet package revision number in rivet/init.tcl |
| * |
| * RIVET_TCL_PACKAGE_VERSION is defined by configure.ac as the combination |
| * "MAJOR_VERSION.MINOR_VERSION". We don't expect to change rivet/init.tcl |
| * across patchlevel releases |
| */ |
| |
| if (Tcl_PkgRequire(interp, "Rivet", RIVET_INIT_VERSION, 1) == NULL) |
| { |
| ap_log_error (APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, |
| MODNAME ": init.tcl must be installed correctly for Apache Rivet to function: %s (%s)", |
| Tcl_GetStringResult(interp), RIVET_DIR ); |
| exit(1); |
| } |
| |
| Tcl_Release(interp); |
| interp_obj->flags |= RIVET_INTERP_INITIALIZED; |
| } |
| |
| /* -- Rivet_NewVHostInterp |
| * |
| * Returns a new rivet_thread_interp object with a new Tcl interpreter |
| * configuration scripts and cache. The pool passed to Rivet_NewVHostInterp |
| * |
| * Arguments: |
| * apr_pool_t* pool: a memory pool, it must be the private pool of a |
| * rivet_thread_private object (thread private) |
| * |
| * Returned value: |
| * a rivet_thread_interp* record object |
| * |
| */ |
| |
| rivet_thread_interp* Rivet_NewVHostInterp(apr_pool_t *pool,int default_cache_size) |
| { |
| rivet_thread_interp* interp_obj = apr_pcalloc(pool,sizeof(rivet_thread_interp)); |
| |
| /* This calls needs the root server_rec just for logging purposes */ |
| |
| interp_obj->interp = Rivet_CreateTclInterp(pool); |
| |
| /* we now create memory from the cache pool as subpool of the thread private pool */ |
| |
| if (apr_pool_create(&interp_obj->pool, pool) != APR_SUCCESS) |
| { |
| ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, pool, |
| MODNAME ": could not initialize cache private pool"); |
| return NULL; |
| } |
| |
| /* We now read from the pointers to the cache_size and cache_free conf parameters |
| * for compatibility with mod_rivet current version, but these values must become |
| * integers not pointers |
| */ |
| |
| if (default_cache_size < 0) { |
| interp_obj->cache_size = RivetCache_DefaultSize(); |
| } else if (default_cache_size > 0) { |
| interp_obj->cache_size = default_cache_size; |
| } |
| |
| interp_obj->cache_free = interp_obj->cache_size; |
| |
| // Initialize cache structures |
| |
| if (interp_obj->cache_size) { |
| RivetCache_Create(pool,interp_obj); |
| } |
| |
| interp_obj->flags = 0; |
| interp_obj->scripts = (running_scripts *) apr_pcalloc(pool,sizeof(running_scripts)); |
| interp_obj->per_dir_scripts = apr_hash_make(pool); |
| |
| return interp_obj; |
| } |
| |
| |
| /* |
| *----------------------------------------------------------------------------- |
| * |
| * -- Rivet_CreateRivetChannel |
| * |
| * Creates a channel and registers with to the interpreter |
| * |
| * Arguments: |
| * |
| * - apr_pool_t* pPool: a pointer to an APR memory pool |
| * |
| * Returned value: |
| * |
| * the pointer to the Tcl_Channel object |
| * |
| * Side Effects: |
| * |
| * a Tcl channel is created allocating memory from the pool |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| Tcl_Channel* |
| Rivet_CreateRivetChannel(apr_pool_t* pPool, apr_threadkey_t* rivet_thread_key) |
| { |
| Tcl_Channel* outchannel; |
| |
| outchannel = apr_pcalloc (pPool, sizeof(Tcl_Channel)); |
| *outchannel = Tcl_CreateChannel(&RivetChan, "apacheout", rivet_thread_key, TCL_WRITABLE); |
| |
| /* The channel we have just created replaces Tcl's stdout */ |
| |
| Tcl_SetStdChannel (*(outchannel), TCL_STDOUT); |
| |
| /* Set the output buffer size to the largest allowed value, so that we |
| * won't send any result packets to the browser unless the Rivet |
| * programmer does a "flush stdout" or the page is completed. |
| */ |
| |
| Tcl_SetChannelBufferSize (*outchannel, TCL_MAX_CHANNEL_BUFFER_SIZE); |
| |
| return outchannel; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| * |
| * -- Rivet_ReleaseRivetChannel |
| * |
| * Tcl_UnregisterChannel wrapper with the purpose of introducing a control |
| * variables that might help debugging |
| * |
| * Arguments: |
| * |
| * - Tcl_Interp* interp |
| * - Tcl_Channel* channel |
| * |
| * Returned value |
| * |
| * none |
| * |
| * Side Effects: |
| * |
| * channel debug counter decremented (TODO) |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| void |
| Rivet_ReleaseRivetChannel (Tcl_Interp* interp, Tcl_Channel* channel) |
| { |
| Tcl_UnregisterChannel(interp,*channel); |
| } |
| |
| |
| /*----------------------------------------------------------------------------- |
| * |
| * -- Rivet_CreatePrivateData |
| * |
| * Creates a thread private data object |
| * |
| * Arguments: |
| * |
| * - apr_threadkey_t* rivet_thread_key |
| * |
| * Returned value: |
| * |
| * - rivet_thread_private* private data object |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| rivet_thread_private* Rivet_CreatePrivateData (void) |
| { |
| rivet_thread_private* private; |
| |
| ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS); |
| |
| apr_thread_mutex_lock(module_globals->pool_mutex); |
| private = apr_pcalloc (module_globals->pool,sizeof(*private)); |
| apr_thread_mutex_unlock(module_globals->pool_mutex); |
| |
| if (apr_pool_create (&private->pool, NULL) != APR_SUCCESS) |
| { |
| ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, module_globals->server, |
| MODNAME ": could not create thread private pool"); |
| return NULL; |
| } |
| private->req_cnt = 0; |
| private->r = NULL; |
| private->req = TclWeb_NewRequestObject(private->pool); |
| private->page_aborting = 0; |
| private->thread_exit = 0; |
| private->exit_status = 0; |
| private->abort_code = NULL; |
| |
| apr_threadkey_private_set (private,rivet_thread_key); |
| return private; |
| } |
| |
| /* |
| * -- Rivet_ExecutionThreadInit |
| * |
| * We keep here the basic initilization each execution thread should undergo |
| * |
| * - create the thread private data |
| * - create a Tcl channel |
| * - set up the Panic procedure |
| */ |
| |
| rivet_thread_private* Rivet_ExecutionThreadInit (void) |
| { |
| rivet_thread_private* private = Rivet_CreatePrivateData(); |
| ap_assert(private != NULL); |
| private->channel = Rivet_CreateRivetChannel(private->pool,rivet_thread_key); |
| Rivet_SetupTclPanicProc(); |
| |
| return private; |
| } |
| |
| /* |
| *----------------------------------------------------------------------------- |
| * |
| * -- Rivet_SetupTclPanicProc |
| * |
| * initialize Tcl panic procedure data in a rivet_thread_private object |
| * |
| * Arguments: |
| * |
| * - none |
| * |
| * Returned value: |
| * |
| * - initialized rivet_thread_private* data record |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| rivet_thread_private* |
| Rivet_SetupTclPanicProc (void) |
| { |
| rivet_thread_private* private; |
| |
| ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS); |
| |
| private->rivet_panic_pool = private->pool; |
| private->rivet_panic_server_rec = module_globals->server; |
| private->rivet_panic_request_rec = NULL; |
| |
| return private; |
| } |
| |
| /* |
| *----------------------------------------------------------------------------- |
| * |
| * Rivet_PanicProc -- |
| * |
| * Called when Tcl panics, usually because of memory problems. |
| * We log the request, in order to be able to determine what went |
| * wrong later. |
| * |
| * Results: |
| * None. |
| * |
| * Side Effects: |
| * Calls abort(), which does not return - the child exits. |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| void Rivet_Panic TCL_VARARGS_DEF(CONST char *, arg1) |
| { |
| va_list argList; |
| char* buf; |
| char* format; |
| rivet_thread_private* private; |
| |
| ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS); |
| |
| format = (char *) TCL_VARARGS_START(char *,arg1,argList); |
| buf = (char *) apr_pvsprintf(private->rivet_panic_pool, format, argList); |
| |
| if (private->rivet_panic_request_rec != NULL) { |
| ap_log_error(APLOG_MARK, APLOG_CRIT, APR_EGENERAL, |
| private->rivet_panic_server_rec, |
| MODNAME ": Critical error in request: %s", |
| private->rivet_panic_request_rec->unparsed_uri); |
| } |
| |
| ap_log_error(APLOG_MARK, APLOG_CRIT, APR_EGENERAL, |
| private->rivet_panic_server_rec, "%s", buf); |
| |
| abort(); |
| } |
| |
| /* |
| * -- Rivet_CleanupRequest |
| * |
| * This function is meant to release memory and resorces |
| * owned by a thread. |
| * The handler in general is not guaranteed to be called |
| * within the same thread that created the resources to |
| + release. As such it's useless to release any Tcl |
| * related resorces (e.g. a Tcl_Interp* object) as |
| * any threaded build of Tcl uses its own thread private |
| * data. We leave the function as a placeholder |
| * in case we want to stuff into it something else to do. |
| * |
| * Arguments: |
| * |
| * request_rec* request object pointer |
| * |
| * Returned value: |
| * |
| * None |
| */ |
| |
| void Rivet_CleanupRequest( request_rec *r ) |
| { |
| } |
| |
| /* |
| * -- Rivet_InitServerVariables |
| * |
| * Setup an array in each interpreter to tell us things about Apache. |
| * This saves us from having to do any real call to load an entire |
| * environment. This routine only gets called once, when the child process |
| * is created. |
| * |
| * Arguments: |
| * |
| * Tcl_Interp* interp: pointer to the Tcl interpreter |
| * apr_pool_t* pool: pool used for calling Apache framework functions |
| * |
| * Returned value: |
| * none |
| * |
| * Side effects: |
| * |
| * within the global scope of the interpreter passed as first |
| * argument a 'server' array is created and the variable associated |
| * to the following keys are defined |
| * |
| * SERVER_ROOT - Apache's root location |
| * SERVER_CONF - Apache's configuration file |
| * RIVET_DIR - Rivet's Tcl source directory |
| * RIVET_INIT - Rivet's init.tcl file |
| * RIVET_VERSION - Rivet version (only when RIVET_DISPLAY_VERSION is 1) |
| * MPM_THREADED - It should contain the string 'unsupported' for a prefork MPM |
| * MPM_FORKED - String describing the forking model of the MPM |
| * RIVET_MPM_BRIDGE - Filename of the running MPM bridge |
| * |
| */ |
| |
| void Rivet_InitServerVariables( Tcl_Interp *interp, apr_pool_t *pool ) |
| { |
| int ap_mpm_result; |
| Tcl_Obj *obj; |
| |
| obj = Tcl_NewStringObj(ap_server_root, -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "SERVER_ROOT", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| obj = Tcl_NewStringObj(ap_server_root_relative(pool,SERVER_CONFIG_FILE), -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "SERVER_CONF", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| obj = Tcl_NewStringObj(ap_server_root_relative(pool, RIVET_DIR), -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "RIVET_DIR", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| obj = Tcl_NewStringObj(ap_server_root_relative(pool, RIVET_INIT), -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "RIVET_INIT", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| #if RIVET_DISPLAY_VERSION |
| obj = Tcl_NewStringObj(RIVET_VERSION, -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "RIVET_VERSION", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| #endif |
| |
| if (ap_mpm_query(AP_MPMQ_IS_THREADED,&ap_mpm_result) == APR_SUCCESS) |
| { |
| switch (ap_mpm_result) |
| { |
| case AP_MPMQ_STATIC: |
| obj = Tcl_NewStringObj("static", -1); |
| break; |
| case AP_MPMQ_NOT_SUPPORTED: |
| obj = Tcl_NewStringObj("unsupported", -1); |
| break; |
| default: |
| obj = Tcl_NewStringObj("undefined", -1); |
| break; |
| } |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp,"server","MPM_THREADED",obj,TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| } |
| |
| if (ap_mpm_query(AP_MPMQ_IS_FORKED,&ap_mpm_result) == APR_SUCCESS) |
| { |
| switch (ap_mpm_result) |
| { |
| case AP_MPMQ_STATIC: |
| obj = Tcl_NewStringObj("static", -1); |
| break; |
| case AP_MPMQ_DYNAMIC: |
| obj = Tcl_NewStringObj("dynamic", -1); |
| break; |
| default: |
| obj = Tcl_NewStringObj("undefined", -1); |
| break; |
| } |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp,"server","MPM_FORKED",obj,TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| } |
| |
| obj = Tcl_NewStringObj(module_globals->rivet_mpm_bridge, -1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "RIVET_MPM_BRIDGE", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| obj = Tcl_NewStringObj(RIVET_CONFIGURE_CMD,-1); |
| Tcl_IncrRefCount(obj); |
| Tcl_SetVar2Ex(interp, |
| "server", |
| "RIVET_CONFIGURE_CMD", |
| obj, |
| TCL_GLOBAL_ONLY); |
| Tcl_DecrRefCount(obj); |
| |
| } |
| |
| /* |
| * -- Rivet_chdir_file (const char* filename) |
| * |
| * Determines the directory name from the filename argument |
| * and sets it as current working directory |
| * |
| * Argument: |
| * |
| * const char* filename: file name to be used for determining |
| * the current directory (URI style path) |
| * the directory name is everything comes |
| * before the last '/' (slash) character |
| * |
| * This snippet of code came from the mod_ruby project, |
| * which is under a BSD license. |
| */ |
| |
| int Rivet_chdir_file (const char *file) |
| { |
| const char *x; |
| int chdir_retval = 0; |
| char chdir_buf[HUGE_STRING_LEN]; |
| |
| x = strrchr(file, '/'); |
| if (x == NULL) { |
| #ifdef WIN32 |
| chdir_retval = _chdir(file); |
| #else |
| chdir_retval = chdir(file); |
| #endif |
| } else if (x - file < sizeof(chdir_buf) - 1) { |
| memcpy(chdir_buf, file, x - file); |
| chdir_buf[x - file] = '\0'; |
| #ifdef WIN32 |
| chdir_retval = _chdir(chdir_buf); |
| #else |
| chdir_retval = chdir(chdir_buf); |
| #endif |
| } |
| |
| return chdir_retval; |
| } |
| |