| /* 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 <ctype.h> |
| #include <stdio.h> |
| |
| #include "apu_config.h" |
| #include "apu.h" |
| |
| #include "apr_pools.h" |
| #include "apr_tables.h" |
| #include "apr_dso.h" |
| #include "apr_strings.h" |
| #include "apr_hash.h" |
| #include "apr_file_io.h" |
| #include "apr_env.h" |
| |
| #include "apu_internal.h" |
| #include "apu_version.h" |
| |
| #if APU_DSO_BUILD |
| |
| #if APR_HAS_THREADS |
| static apr_thread_mutex_t* mutex = NULL; |
| #endif |
| static apr_hash_t *dsos = NULL; |
| |
| #if APR_HAS_THREADS |
| apr_status_t apu_dso_mutex_lock() |
| { |
| return apr_thread_mutex_lock(mutex); |
| } |
| apr_status_t apu_dso_mutex_unlock() |
| { |
| return apr_thread_mutex_unlock(mutex); |
| } |
| #else |
| apr_status_t apu_dso_mutex_lock() { |
| return APR_SUCCESS; |
| } |
| apr_status_t apu_dso_mutex_unlock() { |
| return APR_SUCCESS; |
| } |
| #endif |
| |
| static apr_status_t apu_dso_term(void *ptr) |
| { |
| /* set statics to NULL so init can work again */ |
| dsos = NULL; |
| #if APR_HAS_THREADS |
| mutex = NULL; |
| #endif |
| |
| /* Everything else we need is handled by cleanups registered |
| * when we created mutexes and loaded DSOs |
| */ |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t apu_dso_init(apr_pool_t *pool) |
| { |
| apr_status_t ret = APR_SUCCESS; |
| apr_pool_t *global; |
| apr_pool_t *parent; |
| |
| if (dsos != NULL) { |
| return APR_SUCCESS; |
| } |
| |
| /* Top level pool scope, need process-scope lifetime */ |
| for (parent = global = pool; parent; parent = apr_pool_parent_get(global)) |
| global = parent; |
| |
| dsos = apr_hash_make(global); |
| |
| #if APR_HAS_THREADS |
| ret = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, global); |
| /* This already registers a pool cleanup */ |
| #endif |
| |
| apr_pool_cleanup_register(global, NULL, apu_dso_term, |
| apr_pool_cleanup_null); |
| |
| return ret; |
| } |
| |
| apr_status_t apu_dso_load(apr_dso_handle_t **dlhandleptr, |
| apr_dso_handle_sym_t *dsoptr, |
| const char *module, |
| const char *modsym, |
| apr_pool_t *pool) |
| { |
| apr_dso_handle_t *dlhandle = NULL; |
| char *pathlist; |
| char path[APR_PATH_MAX + 1]; |
| apr_array_header_t *paths; |
| apr_pool_t *global; |
| apr_status_t rv = APR_EDSOOPEN; |
| char *eos = NULL; |
| int i; |
| |
| *dsoptr = apr_hash_get(dsos, module, APR_HASH_KEY_STRING); |
| if (*dsoptr) { |
| return APR_EINIT; |
| } |
| |
| /* The driver DSO must have exactly the same lifetime as the |
| * drivers hash table; ignore the passed-in pool */ |
| global = apr_hash_pool_get(dsos); |
| |
| /* Retrieve our path search list or prepare for a single search */ |
| if ((apr_env_get(&pathlist, APR_DSOPATH, pool) != APR_SUCCESS) |
| || (apr_filepath_list_split(&paths, pathlist, pool) != APR_SUCCESS)) |
| paths = apr_array_make(pool, 1, sizeof(char*)); |
| |
| #if defined(APU_DSO_LIBDIR) |
| /* Always search our prefix path, but on some platforms such as |
| * win32 this may be left undefined |
| */ |
| (*((char **)apr_array_push(paths))) = APU_DSO_LIBDIR; |
| #endif |
| |
| for (i = 0; i < paths->nelts; ++i) |
| { |
| #if defined(WIN32) |
| /* Use win32 dso search semantics and attempt to |
| * load the relative lib on the first pass. |
| */ |
| if (!eos) { |
| eos = path; |
| --i; |
| } |
| else |
| #endif |
| { |
| eos = apr_cpystrn(path, ((char**)paths->elts)[i], sizeof(path)); |
| if ((eos > path) && (eos - path < sizeof(path) - 1)) |
| *(eos++) = '/'; |
| } |
| apr_cpystrn(eos, module, sizeof(path) - (eos - path)); |
| |
| rv = apr_dso_load(&dlhandle, path, global); |
| if (dlhandleptr) { |
| *dlhandleptr = dlhandle; |
| } |
| if (rv == APR_SUCCESS) { /* APR_EDSOOPEN */ |
| break; |
| } |
| #if defined(APU_DSO_LIBDIR) |
| else if (i < paths->nelts - 1) { |
| #else |
| else { /* No APU_DSO_LIBDIR to skip */ |
| #endif |
| /* try with apr-util-APU_MAJOR_VERSION appended */ |
| eos = apr_cpystrn(eos, |
| "apr-util-" APU_STRINGIFY(APU_MAJOR_VERSION) "/", |
| sizeof(path) - (eos - path)); |
| |
| apr_cpystrn(eos, module, sizeof(path) - (eos - path)); |
| |
| rv = apr_dso_load(&dlhandle, path, global); |
| if (dlhandleptr) { |
| *dlhandleptr = dlhandle; |
| } |
| if (rv == APR_SUCCESS) { /* APR_EDSOOPEN */ |
| break; |
| } |
| } |
| } |
| |
| if (rv != APR_SUCCESS) /* APR_ESYMNOTFOUND */ |
| return rv; |
| |
| rv = apr_dso_sym(dsoptr, dlhandle, modsym); |
| if (rv != APR_SUCCESS) { /* APR_ESYMNOTFOUND */ |
| apr_dso_unload(dlhandle); |
| } |
| else { |
| module = apr_pstrdup(global, module); |
| apr_hash_set(dsos, module, APR_HASH_KEY_STRING, *dsoptr); |
| } |
| return rv; |
| } |
| |
| #endif /* APU_DSO_BUILD */ |
| |