diff options
Diffstat (limited to 'APACHE_1_3_42/src/os/win32/registry.c')
-rw-r--r-- | APACHE_1_3_42/src/os/win32/registry.c | 568 |
1 files changed, 568 insertions, 0 deletions
diff --git a/APACHE_1_3_42/src/os/win32/registry.c b/APACHE_1_3_42/src/os/win32/registry.c new file mode 100644 index 0000000000..44620fed8c --- /dev/null +++ b/APACHE_1_3_42/src/os/win32/registry.c @@ -0,0 +1,568 @@ +/* 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. + */ + +#ifdef WIN32 +/* + * Functions to handle interacting with the Win32 registry + */ + +/* + * Apache registry key structure + * + * Apache's registry information is stored in the HKEY_LOCAL_MACHINE + * key, under + * + * HKLM\SOFTWARE\Apache Group\Apache\version + * + * These keys are defined in this file. The definition of the "version" part + * will need updating each time Apache moves from beta to non-beta or from a + * release to a development or beta version. + */ + +/* To allow for multiple services, store the configuration file's full path + * under each service entry: + * + * HKLM\System\CurrentControlSet\Services\[service name]\Parameters\ConfPath + * + * The default configuration path (for console apache) is still stored: + * + * HKLM\Software\[Vendor]\[Software]\[Version]\ServerRoot + */ + +#include <windows.h> +#include <stdio.h> + +#include "httpd.h" +#include "http_log.h" +#include "service.h" + +/* Define where the Apache values are stored in the registry. In general + * VERSION will be the same across all beta releases for a particular + * major release, but will change when the final release is made. + */ + +/* Define where the Apache values are stored in the registry. + * + * If you are looking here to roll the tarball, you didn't need to visit. + * registry.c now picks up the version from include/httpd.h + */ + +#define REGKEY "SOFTWARE\\" SERVER_BASEVENDOR "\\" SERVER_BASEPRODUCT "\\" SERVER_BASEREVISION + +#define SERVICEKEYPRE "System\\CurrentControlSet\\Services\\" +#define SERVICEKEYPOST "\\Parameters" + +/* + * The Windows API registry key functions don't set the last error + * value (the windows equivalent of errno). So we need to set it + * with SetLastError() before calling the aplog_error() function. + * Because this is common, let's have a macro. + */ +#define do_error(rv,fmt,arg) do { \ + SetLastError(rv); \ + ap_log_error(APLOG_MARK, APLOG_WIN32ERROR|APLOG_ERR, NULL, fmt,arg); \ + } while (0); + +/* + * Get the data for registry key value. This is a generic function that + * can either get a value into a caller-supplied buffer, or it can + * allocate space for the value from the pass-in pool. It will normally + * be used by other functions within this file to get specific key values + * (e.g. registry_get_server_root()). This function returns a number of + * different error statuses, allowing the caller to differentiate + * between a key or value not existing and other kinds of errors. Depending + * on the type of data being obtained the caller can then either ignore + * the key-not-existing error, or treat it as a real error. + * + * If ppValue is NULL, allocate space for the value and return it in + * *pValue. The return value is the number of bytes in the value. + * The first argument is the pool to use to allocate space for the value. + * + * If pValue is not NULL, assume it is a buffer of nSizeValue bytes, + * and write the value into the buffer. The return value is the number + * of bytes in the value (so if the return value is greater than + * the supplied nSizeValue, the caller knows that *pValue is truncated). + * The pool argument is ignored. + * + * The return value is the number of bytes in the successfully retreived + * key if everything worked, or: + * + * -1 the key does not exists + * -2 if out of memory during the function + * -3 if the buffer specified by *pValue/nSizeValue was not large enough + * for the value. + * -4 if an error occurred + * + * If the return value is negative a message will be logged to the error + * log (aplog_error) function. If the return value is -2, -3 or -4 the message + * will be logged at priority "error", while if the return value is -1 the + * message will be logged at priority "warning". + */ + +static int ap_registry_get_key_int(pool *p, char *key, char *name, char *pBuffer, int nSizeBuffer, char **ppValue) +{ + long rv; + HKEY hKey; + char *pValue; + int nSize; + int retval; + + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + key, + 0, + KEY_READ, + &hKey); + + if (rv == ERROR_FILE_NOT_FOUND) { + ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL, + "Registry does not contain key %s",key); + return -1; + } + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegOpenKeyEx HKLM\\%s",key); + return -4; + } + + if (pBuffer == NULL) { + /* Find the size required for the data by passing NULL as the buffer + * pointer. On return nSize will contain the size required for the + * buffer if the return value is ERROR_SUCCESS. + */ + rv = RegQueryValueEx(hKey, + name, /* key name */ + NULL, /* reserved */ + NULL, /* type */ + NULL, /* for value */ + &nSize); /* for size of "value" */ + + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegQueryValueEx(key %s)", key); + return -1; + } + + pValue = ap_palloc(p, nSize); + *ppValue = pValue; + if (!pValue) { + /* Eek, out of memory, probably not worth trying to carry on, + * but let's give it a go + */ + ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,NULL, + "Error getting registry key: out of memory"); + return -2; + } + } + else { + /* Get the value into the existing buffer of length nSizeBuffer */ + pValue = pBuffer; + nSize = nSizeBuffer; + } + + rv = RegQueryValueEx(hKey, + name, /* key name */ + NULL, /* reserved */ + NULL, /* type */ + pValue, /* for value */ + &nSize); /* for size of "value" */ + + retval = 0; /* Return value */ + + if (rv == ERROR_FILE_NOT_FOUND) { + ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL, + "Registry does not contain value %s\\%s", key, name); + retval = -1; + } + else if (rv == ERROR_MORE_DATA) { + /* This should only happen if we got passed a pre-existing buffer + * (pBuffer, nSizeBuffer). But I suppose it could also happen if we + * allocate a buffer if another process changed the length of the + * value since we found out its length above. Umm. + */ + ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,NULL, + "Error getting registry value %s: buffer not big enough", key); + retval = -3; + } + else if (rv != ERROR_SUCCESS) { + do_error(rv, "RegQueryValueEx(key %s)", key); + retval = -4; + } + + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegCloseKey HKLM\\%s", key); + if (retval == 0) { + /* Keep error status from RegQueryValueEx, if any */ + retval = -4; + } + } + + return retval < 0 ? retval : nSize; +} + +/* + * Get the server root from the registry into 'dir' which is + * size bytes long. Returns 0 if the server root was found + * or if the serverroot key does not exist (in which case + * dir will contain an empty string), or -1 if there was + * an error getting the key. + */ + +API_EXPORT(int) ap_registry_get_server_root(pool *p, char *dir, int size) +{ + int rv; + + rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL); + if (rv < 0) { + dir[0] = '\0'; + } + + return (rv < 0) ? -1 : 0; +} + +API_EXPORT(char *) ap_get_service_key(char *display_name) +{ + char *key, *service_name; + + if (display_name == NULL) + return strdup(""); + + service_name = get_service_name(display_name); + + key = malloc(strlen(SERVICEKEYPRE) + + strlen(service_name) + + strlen(SERVICEKEYPOST) + 1); + + sprintf(key,"%s%s%s", SERVICEKEYPRE, service_name, SERVICEKEYPOST); + + return(key); +} + +/********************************************************************** + * The rest of this file deals with storing keys or values in the registry + */ + +char *ap_registry_parse_key(int index, char *key) +{ + char *head = key, *skey; + int i; + + if(!key) + return(NULL); + + for(i = 0; i <= index; i++) + { + if(key && key[0] == '\\') + key++; + if (!key) + return(NULL); + head = key; + key = strchr(head, '\\'); + } + + if(!key) + return(strdup(head)); + *key = '\0'; + skey = strdup(head); + *key = '\\'; + return(skey); +} + +/* + * ap_registry_create_apache_key() creates the Apache registry key + * (HLKM\SOFTWARE\Apache Group\Apache\version, as defined at the start + * of this file), if it does not already exist. It will be called by + * ap_registry_store_key_int() if it cannot open this key. This + * function is intended to be called by ap_registry_store_key_int() if + * the Apache key does not exist when it comes to store a data item. + * + * Returns 0 on success or -1 on error. If -1 is returned, the error will + * already have been logged. + */ + +static int ap_registry_create_key(char *longkey) +{ + int index; + HKEY hKey; + HKEY hKeyNext; + int retval; + int rv; + char *key; + + hKey = HKEY_LOCAL_MACHINE; + index = 0; + retval = 0; + + /* Walk the tree, creating at each stage if necessary */ + while (key=ap_registry_parse_key(index,longkey)) { + int result; + + rv = RegCreateKeyEx(hKey, + key, /* subkey */ + 0, /* reserved */ + NULL, /* class */ + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + &hKeyNext, + &result); + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegCreateKeyEx(%s)", longkey); + retval = -4; + } + + /* Close the old key */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegCloseKey", NULL); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + + if (retval) { + break; + } + + free(key); + hKey = hKeyNext; + index++; + } + + if (!key) { + /* Close the final key we opened, if we walked the entire + * tree + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegCloseKey", NULL); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + } + else + free(key); + + return retval; +} + +/* + * ap_registry_store_key_int() stores a value name and value under the + * Apache registry key. If the Apache key does not exist it is created + * first. This function is intended to be called from a wrapper function + * in this file to set particular data values, such as + * ap_registry_set_server_root() below. + * + * Returns 0 if the value name and data was stored successfully, or + * returns -1 if the Apache key does not exist (since we try to create + * this key, this should never happen), or -4 if any other error occurred + * (these values are consistent with ap_registry_get_key_int()). + * If the return value is negative then the error will already have been + * logged via aplog_error(). + */ + +static int ap_registry_store_key_int(char *key, char *name, DWORD type, void *value, int value_size) +{ + long rv; + HKEY hKey; + int retval; + + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + key, + 0, + KEY_WRITE, + &hKey); + + if (rv == ERROR_FILE_NOT_FOUND) { + /* Key could not be opened -- try to create it + */ + if (ap_registry_create_key(key) < 0) { + /* Creation failed (error already reported) */ + return -4; + } + + /* Now it has been created we should be able to open it + */ + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + key, + 0, + KEY_WRITE, + &hKey); + + if (rv == ERROR_FILE_NOT_FOUND) { + ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL, + "Registry does not contain key %s after creation",key); + return -1; + } + } + + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegOpenKeyEx HKLM\\%s", key); + return -4; + } + + /* Now set the value and data */ + rv = RegSetValueEx(hKey, + name, /* value key name */ + 0, /* reserved */ + type, /* type */ + value, /* value data */ + (DWORD)value_size); /* for size of "value" */ + + retval = 0; /* Return value */ + + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegQueryValueEx(key %s)", key); + retval = -4; + } + else { + ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,NULL, + "Registry stored HKLM\\" REGKEY "\\%s value %s", key, + type == REG_SZ ? value : "(not displayable)"); + } + + /* Make sure we close the key even if there was an error storing + * the data + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + do_error(rv, "RegCloseKey HKLM\\%s", key); + if (retval == 0) { + /* Keep error status from RegQueryValueEx, if any */ + retval = -4; + } + } + + return retval; +} + +/* + * Sets the serverroot value within the registry. Returns 0 on success + * or -1 on error. If -1 is return the error will already have been + * logged via aplog_error(). + */ + +int ap_registry_set_server_root(char *dir) +{ + int rv; + + rv = ap_registry_store_key_int(REGKEY, "ServerRoot", REG_SZ, dir, strlen(dir)+1); + + return rv < 0 ? -1 : 0; +} + +/* Creates and fills array pointed to by parray with the requested registry string + * + * Returns 0 on success, machine specific error code on error + */ +int ap_registry_get_array(pool *p, char *key, char *name, + array_header **pparray) +{ + char *pValue; + char *tmp; + char **newelem; + int ret; + int nSize = 0; + + ret = ap_registry_get_key_int(p, key, name, NULL, 0, &pValue); + if (ret < 0) + return ret; + + tmp = pValue; + if ((ret > 2) && (tmp[0] || tmp[1])) + nSize = 1; /* Element Count */ + while ((tmp < pValue + ret) && (tmp[0] || tmp[1])) + { + if (!tmp[0]) + ++nSize; + ++tmp; + } + + *pparray = ap_make_array(p, nSize, sizeof(char *)); + tmp = pValue; + if (tmp[0] || tmp[1]) { + newelem = (char **) ap_push_array(*pparray); + *newelem = tmp; + } + while ((tmp < pValue + ret) && (tmp[0] || tmp[1])) + { + if (!tmp[0]) { + newelem = (char **) ap_push_array(*pparray); + *newelem = tmp + 1; + } + ++tmp; + } + + return nSize; +} + +int ap_registry_get_service_args(pool *p, int *argc, char ***argv, char *display_name) +{ + int ret; + array_header *parray; + char *key = ap_get_service_key(display_name); + ret = ap_registry_get_array(p, key, "ConfigArgs", &parray); + if (ret > 0) { + *argc = parray->nelts; + *argv = (char**) parray->elts; + } + else { + *argc = 0; + *argv = NULL; + } + free(key); + return ret; +} + +int ap_registry_store_array(pool *p, char *key, char *name, + int nelts, char **elts) +{ + int bufsize, i; + char *buf, *tmp; + + bufsize = 1; /* For trailing second null */ + for (i = 0; i < nelts; ++i) + { + bufsize += strlen(elts[i]) + 1; + } + if (!nelts) + ++bufsize; + + buf = ap_palloc(p, bufsize); + tmp = buf; + for (i = 0; i < nelts; ++i) + { + strcpy(tmp, elts[i]); + tmp += strlen(elts[i]) + 1; + } + if (!nelts) + *(tmp++) = '\0'; + *(tmp++) = '\0'; /* Trailing second null */ + + return ap_registry_store_key_int(key, name, REG_MULTI_SZ, buf, tmp - buf); +} + +int ap_registry_set_service_args(pool *p, int argc, char **argv, char *display_name) +{ + int ret; + char *key = ap_get_service_key(display_name); + ret = ap_registry_store_array(p, key, "ConfigArgs", argc, argv); + free(key); + return ret; +} + +#endif /* WIN32 */ |