summaryrefslogtreecommitdiffstats
path: root/misc/unix
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:23:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:23:09 +0000
commit30d479c28c831a0d4f1fdb54a9e346b0fc176be1 (patch)
treeaa35d7414ce9f1326abf6f723f6dfa5b0aa08b1d /misc/unix
parentInitial commit. (diff)
downloadapr-upstream/1.7.2.tar.xz
apr-upstream/1.7.2.zip
Adding upstream version 1.7.2.upstream/1.7.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'misc/unix')
-rw-r--r--misc/unix/charset.c83
-rw-r--r--misc/unix/env.c88
-rw-r--r--misc/unix/errorcodes.c443
-rw-r--r--misc/unix/getopt.c309
-rw-r--r--misc/unix/otherchild.c221
-rw-r--r--misc/unix/rand.c302
-rw-r--r--misc/unix/randbyte_os2.inc123
-rw-r--r--misc/unix/start.c89
-rw-r--r--misc/unix/version.c35
9 files changed, 1693 insertions, 0 deletions
diff --git a/misc/unix/charset.c b/misc/unix/charset.c
new file mode 100644
index 0000000..a16310c
--- /dev/null
+++ b/misc/unix/charset.c
@@ -0,0 +1,83 @@
+/* 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 "apr.h"
+#include "apr_private.h"
+#include "apr_strings.h"
+#include "apr_portable.h"
+
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+/*
+ * simple heuristic to determine codepage of source code so that
+ * literal strings (e.g., "GET /\r\n") in source code can be translated
+ * properly
+ *
+ * If appropriate, a symbol can be set at configure time to determine
+ * this. On EBCDIC platforms, it will be important how the code was
+ * unpacked.
+ */
+
+APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool)
+{
+#ifdef __MVS__
+# ifdef __CODESET__
+ return __CODESET__;
+# else
+ return "IBM-1047";
+# endif
+#endif
+
+ if ('}' == 0xD0) {
+ return "IBM-1047";
+ }
+
+ if ('{' == 0xFB) {
+ return "EDF04";
+ }
+
+ if ('A' == 0xC1) {
+ return "EBCDIC"; /* not useful */
+ }
+
+ if ('A' == 0x41) {
+ return "ISO-8859-1"; /* not necessarily true */
+ }
+
+ return "unknown";
+}
+
+
+APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool)
+{
+#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
+ const char *charset;
+
+ charset = nl_langinfo(CODESET);
+ if (charset && *charset) {
+#ifdef _OSD_POSIX /* Bug workaround - delete as soon as fixed in OSD_POSIX */
+ /* Some versions of OSD_POSIX return nl_langinfo(CODESET)="^[nN]" */
+ /* Ignore the bogus information and use apr_os_default_encoding() */
+ if (charset[0] != '^')
+#endif
+ return apr_pstrdup(pool, charset);
+ }
+#endif
+
+ return apr_os_default_encoding(pool);
+}
diff --git a/misc/unix/env.c b/misc/unix/env.c
new file mode 100644
index 0000000..b41f8f1
--- /dev/null
+++ b/misc/unix/env.c
@@ -0,0 +1,88 @@
+/* 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.
+ */
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr.h"
+#include "apr_private.h"
+#include "apr_env.h"
+#include "apr_strings.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+APR_DECLARE(apr_status_t) apr_env_get(char **value,
+ const char *envvar,
+ apr_pool_t *pool)
+{
+#ifdef HAVE_GETENV
+
+ char *val = getenv(envvar);
+ if (!val)
+ return APR_ENOENT;
+ *value = val;
+ return APR_SUCCESS;
+
+#else
+ return APR_ENOTIMPL;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_set(const char *envvar,
+ const char *value,
+ apr_pool_t *pool)
+{
+#if defined(HAVE_SETENV)
+
+ if (0 > setenv(envvar, value, 1))
+ return APR_ENOMEM;
+ return APR_SUCCESS;
+
+#elif defined(HAVE_PUTENV)
+
+ if (0 > putenv(apr_pstrcat(pool, envvar, "=", value, NULL)))
+ return APR_ENOMEM;
+ return APR_SUCCESS;
+
+#else
+ return APR_ENOTIMPL;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool)
+{
+#ifdef HAVE_UNSETENV
+
+ unsetenv(envvar);
+ return APR_SUCCESS;
+
+#else
+ /* hint: some platforms allow envvars to be unset via
+ * putenv("varname")... that isn't Single Unix spec,
+ * but if your platform doesn't have unsetenv() it is
+ * worth investigating and potentially adding a
+ * configure check to decide when to use that form of
+ * putenv() here
+ */
+ return APR_ENOTIMPL;
+#endif
+}
diff --git a/misc/unix/errorcodes.c b/misc/unix/errorcodes.c
new file mode 100644
index 0000000..60ea2f7
--- /dev/null
+++ b/misc/unix/errorcodes.c
@@ -0,0 +1,443 @@
+/* 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 "apr_arch_misc.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_dso.h"
+
+#if APR_HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+/*
+ * stuffbuffer - like apr_cpystrn() but returns the address of the
+ * dest buffer instead of the address of the terminating '\0'
+ */
+static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s)
+{
+ apr_cpystrn(buf,s,bufsize);
+ return buf;
+}
+
+static char *apr_error_string(apr_status_t statcode)
+{
+ switch (statcode) {
+ case APR_ENOSTAT:
+ return "Could not perform a stat on the file.";
+ case APR_ENOPOOL:
+ return "A new pool could not be created.";
+ case APR_EBADDATE:
+ return "An invalid date has been provided";
+ case APR_EINVALSOCK:
+ return "An invalid socket was returned";
+ case APR_ENOPROC:
+ return "No process was provided and one was required.";
+ case APR_ENOTIME:
+ return "No time was provided and one was required.";
+ case APR_ENODIR:
+ return "No directory was provided and one was required.";
+ case APR_ENOLOCK:
+ return "No lock was provided and one was required.";
+ case APR_ENOPOLL:
+ return "No poll structure was provided and one was required.";
+ case APR_ENOSOCKET:
+ return "No socket was provided and one was required.";
+ case APR_ENOTHREAD:
+ return "No thread was provided and one was required.";
+ case APR_ENOTHDKEY:
+ return "No thread key structure was provided and one was required.";
+ case APR_ENOSHMAVAIL:
+ return "No shared memory is currently available";
+ case APR_EDSOOPEN:
+#if APR_HAS_DSO && defined(HAVE_LIBDL)
+ return dlerror();
+#else
+ return "DSO load failed";
+#endif /* HAVE_LIBDL */
+ case APR_EBADIP:
+ return "The specified IP address is invalid.";
+ case APR_EBADMASK:
+ return "The specified network mask is invalid.";
+ case APR_ESYMNOTFOUND:
+ return "Could not find the requested symbol.";
+ case APR_ENOTENOUGHENTROPY:
+ return "Not enough entropy to continue.";
+ case APR_INCHILD:
+ return
+ "Your code just forked, and you are currently executing in the "
+ "child process";
+ case APR_INPARENT:
+ return
+ "Your code just forked, and you are currently executing in the "
+ "parent process";
+ case APR_DETACH:
+ return "The specified thread is detached";
+ case APR_NOTDETACH:
+ return "The specified thread is not detached";
+ case APR_CHILD_DONE:
+ return "The specified child process is done executing";
+ case APR_CHILD_NOTDONE:
+ return "The specified child process is not done executing";
+ case APR_TIMEUP:
+ return "The timeout specified has expired";
+ case APR_INCOMPLETE:
+ return "Partial results are valid but processing is incomplete";
+ case APR_BADCH:
+ return "Bad character specified on command line";
+ case APR_BADARG:
+ return "Missing parameter for the specified command line option";
+ case APR_EOF:
+ return "End of file found";
+ case APR_NOTFOUND:
+ return "Could not find specified socket in poll list.";
+ case APR_ANONYMOUS:
+ return "Shared memory is implemented anonymously";
+ case APR_FILEBASED:
+ return "Shared memory is implemented using files";
+ case APR_KEYBASED:
+ return "Shared memory is implemented using a key system";
+ case APR_EINIT:
+ return
+ "There is no error, this value signifies an initialized "
+ "error code";
+ case APR_ENOTIMPL:
+ return "This function has not been implemented on this platform";
+ case APR_EMISMATCH:
+ return "passwords do not match";
+ case APR_EABSOLUTE:
+ return "The given path is absolute";
+ case APR_ERELATIVE:
+ return "The given path is relative";
+ case APR_EINCOMPLETE:
+ return "The given path is incomplete";
+ case APR_EABOVEROOT:
+ return "The given path was above the root path";
+ case APR_EBADPATH:
+ return "The given path is misformatted or contained invalid characters";
+ case APR_EPATHWILD:
+ return "The given path contained wildcard characters";
+ case APR_EBUSY:
+ return "The given lock was busy.";
+ case APR_EPROC_UNKNOWN:
+ return "The process is not recognized.";
+ case APR_EGENERAL:
+ return "Internal error (specific information not available)";
+ default:
+ return "Error string not specified yet";
+ }
+}
+
+
+#ifdef OS2
+#include <ctype.h>
+
+int apr_canonical_error(apr_status_t err);
+
+static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
+{
+ char result[200];
+ unsigned char message[HUGE_STRING_LEN];
+ ULONG len;
+ char *pos;
+ int c;
+
+ if (err >= 10000 && err < 12000) { /* socket error codes */
+ return stuffbuffer(buf, bufsize,
+ strerror(apr_canonical_error(err+APR_OS_START_SYSERR)));
+ }
+ else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err,
+ "OSO001.MSG", &len) == 0) {
+ len--;
+ message[len] = 0;
+ pos = result;
+
+ if (len >= sizeof(result))
+ len = sizeof(result) - 1;
+
+ for (c=0; c<len; c++) {
+ /* skip multiple whitespace */
+ while (apr_isspace(message[c]) && apr_isspace(message[c+1]))
+ c++;
+ *(pos++) = apr_isspace(message[c]) ? ' ' : message[c];
+ }
+
+ *pos = 0;
+ }
+ else {
+ sprintf(result, "OS/2 error %d", err);
+ }
+
+ /* Stuff the string into the caller supplied buffer, then return
+ * a pointer to it.
+ */
+ return stuffbuffer(buf, bufsize, result);
+}
+
+#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
+
+static const struct {
+ apr_status_t code;
+ const char *msg;
+} gaErrorList[] = {
+ {WSAEINTR, "Interrupted system call"},
+ {WSAEBADF, "Bad file number"},
+ {WSAEACCES, "Permission denied"},
+ {WSAEFAULT, "Bad address"},
+ {WSAEINVAL, "Invalid argument"},
+ {WSAEMFILE, "Too many open sockets"},
+ {WSAEWOULDBLOCK, "Operation would block"},
+ {WSAEINPROGRESS, "Operation now in progress"},
+ {WSAEALREADY, "Operation already in progress"},
+ {WSAENOTSOCK, "Socket operation on non-socket"},
+ {WSAEDESTADDRREQ, "Destination address required"},
+ {WSAEMSGSIZE, "Message too long"},
+ {WSAEPROTOTYPE, "Protocol wrong type for socket"},
+ {WSAENOPROTOOPT, "Bad protocol option"},
+ {WSAEPROTONOSUPPORT, "Protocol not supported"},
+ {WSAESOCKTNOSUPPORT, "Socket type not supported"},
+ {WSAEOPNOTSUPP, "Operation not supported on socket"},
+ {WSAEPFNOSUPPORT, "Protocol family not supported"},
+ {WSAEAFNOSUPPORT, "Address family not supported"},
+ {WSAEADDRINUSE, "Address already in use"},
+ {WSAEADDRNOTAVAIL, "Can't assign requested address"},
+ {WSAENETDOWN, "Network is down"},
+ {WSAENETUNREACH, "Network is unreachable"},
+ {WSAENETRESET, "Net connection reset"},
+ {WSAECONNABORTED, "Software caused connection abort"},
+ {WSAECONNRESET, "Connection reset by peer"},
+ {WSAENOBUFS, "No buffer space available"},
+ {WSAEISCONN, "Socket is already connected"},
+ {WSAENOTCONN, "Socket is not connected"},
+ {WSAESHUTDOWN, "Can't send after socket shutdown"},
+ {WSAETOOMANYREFS, "Too many references, can't splice"},
+ {WSAETIMEDOUT, "Connection timed out"},
+ {WSAECONNREFUSED, "Connection refused"},
+ {WSAELOOP, "Too many levels of symbolic links"},
+ {WSAENAMETOOLONG, "File name too long"},
+ {WSAEHOSTDOWN, "Host is down"},
+ {WSAEHOSTUNREACH, "No route to host"},
+ {WSAENOTEMPTY, "Directory not empty"},
+ {WSAEPROCLIM, "Too many processes"},
+ {WSAEUSERS, "Too many users"},
+ {WSAEDQUOT, "Disc quota exceeded"},
+ {WSAESTALE, "Stale NFS file handle"},
+ {WSAEREMOTE, "Too many levels of remote in path"},
+ {WSASYSNOTREADY, "Network system is unavailable"},
+ {WSAVERNOTSUPPORTED, "Winsock version out of range"},
+ {WSANOTINITIALISED, "WSAStartup not yet called"},
+ {WSAEDISCON, "Graceful shutdown in progress"},
+ {WSAHOST_NOT_FOUND, "Host not found"},
+ {WSANO_DATA, "No host data of that type was found"},
+ {0, NULL}
+};
+
+
+static char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode)
+{
+ apr_size_t len=0, i;
+
+#ifndef NETWARE
+#ifndef _WIN32_WCE
+ len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ errcode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ buf,
+ (DWORD)bufsize,
+ NULL);
+#else /* _WIN32_WCE speaks unicode */
+ LPTSTR msg = (LPTSTR) buf;
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ errcode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ msg,
+ (DWORD) (bufsize/sizeof(TCHAR)),
+ NULL);
+ /* in-place convert to US-ASCII, substituting '?' for non ASCII */
+ for(i = 0; i <= len; i++) {
+ if (msg[i] < 0x80 && msg[i] >= 0) {
+ buf[i] = (char) msg[i];
+ } else {
+ buf[i] = '?';
+ }
+ }
+#endif
+#endif
+
+ if (!len) {
+ for (i = 0; gaErrorList[i].msg; ++i) {
+ if (gaErrorList[i].code == errcode) {
+ apr_cpystrn(buf, gaErrorList[i].msg, bufsize);
+ len = strlen(buf);
+ break;
+ }
+ }
+ }
+
+ if (len) {
+ /* FormatMessage put the message in the buffer, but it may
+ * have embedded a newline (\r\n), and possible more than one.
+ * Remove the newlines replacing them with a space. This is not
+ * as visually perfect as moving all the remaining message over,
+ * but more efficient.
+ */
+ i = len;
+ while (i) {
+ i--;
+ if ((buf[i] == '\r') || (buf[i] == '\n'))
+ buf[i] = ' ';
+ }
+ }
+ else {
+ /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message.
+ */
+ apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode);
+ }
+
+ return buf;
+}
+
+#else
+/* On Unix, apr_os_strerror() handles error codes from the resolver
+ * (h_errno).
+ */
+static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
+{
+#ifdef HAVE_HSTRERROR
+ return stuffbuffer(buf, bufsize, hstrerror(err));
+#else /* HAVE_HSTRERROR */
+ const char *msg;
+
+ switch(err) {
+ case HOST_NOT_FOUND:
+ msg = "Unknown host";
+ break;
+#if defined(NO_DATA)
+ case NO_DATA:
+#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS)
+ case NO_ADDRESS:
+#endif
+ msg = "No address for host";
+ break;
+#elif defined(NO_ADDRESS)
+ case NO_ADDRESS:
+ msg = "No address for host";
+ break;
+#endif /* NO_DATA */
+ default:
+ msg = "Unrecognized resolver error";
+ }
+ return stuffbuffer(buf, bufsize, msg);
+#endif /* HAVE_STRERROR */
+}
+#endif
+
+#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS)
+/* AIX and Tru64 style */
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ if (strerror_r(statcode, buf, bufsize) < 0) {
+ return stuffbuffer(buf, bufsize,
+ "APR does not understand this error code");
+ }
+ else {
+ return buf;
+ }
+}
+#elif defined(HAVE_STRERROR_R)
+/* glibc style */
+
+/* BeOS has the function available, but it doesn't provide
+ * the prototype publicly (doh!), so to avoid a build warning
+ * we add a suitable prototype here.
+ */
+#if defined(BEOS)
+const char *strerror_r(apr_status_t, char *, apr_size_t);
+#endif
+
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ const char *msg;
+
+ buf[0] = '\0';
+ msg = strerror_r(statcode, buf, bufsize);
+ if (buf[0] == '\0') { /* libc didn't use our buffer */
+ return stuffbuffer(buf, bufsize, msg);
+ }
+ else {
+ return buf;
+ }
+}
+#else
+/* plain old strerror();
+ * thread-safe on some platforms (e.g., Solaris, OS/390)
+ */
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+#ifdef _WIN32_WCE
+ static char err[32];
+ sprintf(err, "Native Error #%d", statcode);
+ return stuffbuffer(buf, bufsize, err);
+#else
+ const char *err = strerror(statcode);
+ if (err) {
+ return stuffbuffer(buf, bufsize, err);
+ } else {
+ return stuffbuffer(buf, bufsize,
+ "APR does not understand this error code");
+ }
+#endif
+}
+#endif
+
+APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ if (statcode < APR_OS_START_ERROR) {
+ return native_strerror(statcode, buf, bufsize);
+ }
+ else if (statcode < APR_OS_START_USERERR) {
+ return stuffbuffer(buf, bufsize, apr_error_string(statcode));
+ }
+ else if (statcode < APR_OS_START_EAIERR) {
+ return stuffbuffer(buf, bufsize, "APR does not understand this error code");
+ }
+ else if (statcode < APR_OS_START_SYSERR) {
+#if defined(HAVE_GAI_STRERROR)
+ statcode -= APR_OS_START_EAIERR;
+#if defined(NEGATIVE_EAI)
+ statcode = -statcode;
+#endif
+ return stuffbuffer(buf, bufsize, gai_strerror(statcode));
+#else
+ return stuffbuffer(buf, bufsize, "APR does not understand this error code");
+#endif
+ }
+ else {
+ return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR);
+ }
+}
+
diff --git a/misc/unix/getopt.c b/misc/unix/getopt.c
new file mode 100644
index 0000000..24be3c8
--- /dev/null
+++ b/misc/unix/getopt.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "apr_arch_misc.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+
+#define EMSG ""
+
+APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont,
+ int argc, const char *const *argv)
+{
+ void *argv_buff;
+
+ *os = apr_palloc(cont, sizeof(apr_getopt_t));
+ (*os)->cont = cont;
+ (*os)->reset = 0;
+ (*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
+ (*os)->errarg = (void*)(stderr);
+
+ (*os)->place = EMSG;
+ (*os)->argc = argc;
+
+ /* The argv parameter must be compatible with main()'s argv, since
+ that's the primary purpose of this function. But people might
+ want to use this function with arrays other than the main argv,
+ and we shouldn't touch the caller's data. So we copy. */
+ argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *));
+ memcpy(argv_buff, argv, argc * sizeof(const char *));
+ (*os)->argv = argv_buff;
+ (*os)->argv[argc] = NULL;
+
+ (*os)->interleave = 0;
+ (*os)->ind = 1;
+ (*os)->skip_start = 1;
+ (*os)->skip_end = 1;
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts,
+ char *optch, const char **optarg)
+{
+ const char *oli; /* option letter list index */
+
+ if (os->reset || !*os->place) { /* update scanning pointer */
+ os->reset = 0;
+ if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
+ os->place = EMSG;
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ if (os->place[1] && *++os->place == '-') { /* found "--" */
+ ++os->ind;
+ os->place = EMSG;
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ } /* option letter okay? */
+ if ((os->opt = (int) *os->place++) == (int) ':' ||
+ !(oli = strchr(opts, os->opt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (os->opt == (int) '-') {
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ if (!*os->place)
+ ++os->ind;
+ if (os->errfn && *opts != ':') {
+ (os->errfn)(os->errarg, "%s: illegal option -- %c\n",
+ apr_filepath_name_get(*os->argv), os->opt);
+ }
+ *optch = os->opt;
+ return (APR_BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ *optarg = NULL;
+ if (!*os->place)
+ ++os->ind;
+ }
+ else { /* need an argument */
+ if (*os->place) /* no white space */
+ *optarg = os->place;
+ else if (os->argc <= ++os->ind) { /* no arg */
+ os->place = EMSG;
+ if (*opts == ':') {
+ *optch = os->opt;
+ return (APR_BADARG);
+ }
+ if (os->errfn) {
+ (os->errfn)(os->errarg,
+ "%s: option requires an argument -- %c\n",
+ apr_filepath_name_get(*os->argv), os->opt);
+ }
+ *optch = os->opt;
+ return (APR_BADCH);
+ }
+ else /* white space */
+ *optarg = os->argv[os->ind];
+ os->place = EMSG;
+ ++os->ind;
+ }
+ *optch = os->opt;
+ return APR_SUCCESS;
+}
+
+/* Reverse the sequence argv[start..start+len-1]. */
+static void reverse(const char **argv, int start, int len)
+{
+ const char *temp;
+
+ for (; len >= 2; start++, len -= 2) {
+ temp = argv[start];
+ argv[start] = argv[start + len - 1];
+ argv[start + len - 1] = temp;
+ }
+}
+
+/*
+ * Permute os->argv with the goal that non-option arguments will all
+ * appear at the end. os->skip_start is where we started skipping
+ * non-option arguments, os->skip_end is where we stopped, and os->ind
+ * is where we are now.
+ */
+static void permute(apr_getopt_t *os)
+{
+ int len1 = os->skip_end - os->skip_start;
+ int len2 = os->ind - os->skip_end;
+
+ if (os->interleave) {
+ /*
+ * Exchange the sequences argv[os->skip_start..os->skip_end-1] and
+ * argv[os->skip_end..os->ind-1]. The easiest way to do that is
+ * to reverse the entire range and then reverse the two
+ * sub-ranges.
+ */
+ reverse(os->argv, os->skip_start, len1 + len2);
+ reverse(os->argv, os->skip_start, len2);
+ reverse(os->argv, os->skip_start + len2, len1);
+ }
+
+ /* Reset skip range to the new location of the non-option sequence. */
+ os->skip_start += len2;
+ os->skip_end += len2;
+}
+
+/* Helper function to print out an error involving a long option */
+static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str,
+ apr_status_t status)
+{
+ if (os->errfn)
+ (os->errfn)(os->errarg, "%s: %s: %s\n",
+ apr_filepath_name_get(*os->argv), err, str);
+ return status;
+}
+
+/* Helper function to print out an error involving a short option */
+static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch,
+ apr_status_t status)
+{
+ if (os->errfn)
+ (os->errfn)(os->errarg, "%s: %s: %c\n",
+ apr_filepath_name_get(*os->argv), err, ch);
+ return status;
+}
+
+APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
+ const apr_getopt_option_t *opts,
+ int *optch, const char **optarg)
+{
+ const char *p;
+ int i;
+
+ /* Let the calling program reset option processing. */
+ if (os->reset) {
+ os->place = EMSG;
+ os->ind = 1;
+ os->reset = 0;
+ }
+
+ /*
+ * We can be in one of two states: in the middle of processing a
+ * run of short options, or about to process a new argument.
+ * Since the second case can lead to the first one, handle that
+ * one first. */
+ p = os->place;
+ if (*p == '\0') {
+ /* If we are interleaving, skip non-option arguments. */
+ if (os->interleave) {
+ while (os->ind < os->argc && *os->argv[os->ind] != '-')
+ os->ind++;
+ os->skip_end = os->ind;
+ }
+ if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
+ os->ind = os->skip_start;
+ return APR_EOF;
+ }
+
+ p = os->argv[os->ind++] + 1;
+ if (*p == '-' && p[1] != '\0') { /* Long option */
+ /* Search for the long option name in the caller's table. */
+ apr_size_t len = 0;
+
+ p++;
+ for (i = 0; ; i++) {
+ if (opts[i].optch == 0) /* No match */
+ return serr(os, "invalid option", p - 2, APR_BADCH);
+
+ if (opts[i].name) {
+ len = strlen(opts[i].name);
+ if (strncmp(p, opts[i].name, len) == 0
+ && (p[len] == '\0' || p[len] == '='))
+ break;
+ }
+ }
+ *optch = opts[i].optch;
+
+ if (opts[i].has_arg) {
+ if (p[len] == '=') /* Argument inline */
+ *optarg = p + len + 1;
+ else {
+ if (os->ind >= os->argc) /* Argument missing */
+ return serr(os, "missing argument", p - 2, APR_BADARG);
+ else /* Argument in next arg */
+ *optarg = os->argv[os->ind++];
+ }
+ } else {
+ *optarg = NULL;
+ if (p[len] == '=')
+ return serr(os, "erroneous argument", p - 2, APR_BADARG);
+ }
+ permute(os);
+ return APR_SUCCESS;
+ } else {
+ if (*p == '-') { /* Bare "--"; we're done */
+ permute(os);
+ os->ind = os->skip_start;
+ return APR_EOF;
+ }
+ else
+ if (*p == '\0') /* Bare "-" is illegal */
+ return serr(os, "invalid option", p, APR_BADCH);
+ }
+ }
+
+ /*
+ * Now we're in a run of short options, and *p is the next one.
+ * Look for it in the caller's table.
+ */
+ for (i = 0; ; i++) {
+ if (opts[i].optch == 0) /* No match */
+ return cerr(os, "invalid option character", *p, APR_BADCH);
+
+ if (*p == opts[i].optch)
+ break;
+ }
+ *optch = *p++;
+
+ if (opts[i].has_arg) {
+ if (*p != '\0') /* Argument inline */
+ *optarg = p;
+ else {
+ if (os->ind >= os->argc) /* Argument missing */
+ return cerr(os, "missing argument", *optch, APR_BADARG);
+ else /* Argument in next arg */
+ *optarg = os->argv[os->ind++];
+ }
+ os->place = EMSG;
+ } else {
+ *optarg = NULL;
+ os->place = p;
+ }
+
+ permute(os);
+ return APR_SUCCESS;
+}
diff --git a/misc/unix/otherchild.c b/misc/unix/otherchild.c
new file mode 100644
index 0000000..427a57e
--- /dev/null
+++ b/misc/unix/otherchild.c
@@ -0,0 +1,221 @@
+/* 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 "apr.h"
+#include "apr_arch_misc.h"
+#include "apr_arch_threadproc.h"
+#include "apr_arch_file_io.h"
+
+#if APR_HAS_OTHER_CHILD
+
+#ifdef HAVE_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if APR_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef BEOS
+#include <sys/socket.h> /* for fd_set definition! */
+#endif
+
+static apr_other_child_rec_t *other_children = NULL;
+
+static apr_status_t other_child_cleanup(void *data)
+{
+ apr_other_child_rec_t **pocr, *nocr;
+
+ for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
+ if ((*pocr)->data == data) {
+ nocr = (*pocr)->next;
+ (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1);
+ *pocr = nocr;
+ /* XXX: um, well we've just wasted some space in pconf ? */
+ return APR_SUCCESS;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
+ void (*maintenance) (int reason, void *, int status),
+ void *data, apr_file_t *write_fd, apr_pool_t *p)
+{
+ apr_other_child_rec_t *ocr;
+
+ ocr = apr_palloc(p, sizeof(*ocr));
+ ocr->p = p;
+ ocr->proc = proc;
+ ocr->maintenance = maintenance;
+ ocr->data = data;
+ if (write_fd == NULL) {
+ ocr->write_fd = (apr_os_file_t) -1;
+ }
+ else {
+#ifdef WIN32
+ /* This should either go away as part of eliminating apr_proc_probe_writable_fds
+ * or write_fd should point to an apr_file_t
+ */
+ ocr->write_fd = write_fd->filehand;
+#else
+ ocr->write_fd = write_fd->filedes;
+#endif
+
+ }
+ ocr->next = other_children;
+ other_children = ocr;
+ apr_pool_cleanup_register(p, ocr->data, other_child_cleanup,
+ apr_pool_cleanup_null);
+}
+
+APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
+{
+ apr_other_child_rec_t *cur;
+
+ cur = other_children;
+ while (cur) {
+ if (cur->data == data) {
+ break;
+ }
+ cur = cur->next;
+ }
+
+ /* segfault if this function called with invalid parm */
+ apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup);
+ other_child_cleanup(data);
+}
+
+APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
+ int reason,
+ int status)
+{
+ apr_other_child_rec_t *ocr, *nocr;
+
+ for (ocr = other_children; ocr; ocr = nocr) {
+ nocr = ocr->next;
+ if (ocr->proc->pid != proc->pid)
+ continue;
+
+ ocr->proc = NULL;
+ (*ocr->maintenance) (reason, ocr->data, status);
+ return APR_SUCCESS;
+ }
+ return APR_EPROC_UNKNOWN;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
+ int reason)
+{
+ /* Todo:
+ * Implement code to detect if pipes are still alive.
+ */
+#ifdef WIN32
+ DWORD status;
+
+ if (ocr->proc == NULL)
+ return;
+
+ if (!ocr->proc->hproc) {
+ /* Already mopped up, perhaps we apr_proc_kill'ed it,
+ * they should have already unregistered!
+ */
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+ else if (!GetExitCodeProcess(ocr->proc->hproc, &status)) {
+ CloseHandle(ocr->proc->hproc);
+ ocr->proc->hproc = NULL;
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+ else if (status == STILL_ACTIVE) {
+ (*ocr->maintenance) (reason, ocr->data, -1);
+ }
+ else {
+ CloseHandle(ocr->proc->hproc);
+ ocr->proc->hproc = NULL;
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
+ }
+
+#else /* ndef Win32 */
+ pid_t waitret;
+ int status;
+
+ if (ocr->proc == NULL)
+ return;
+
+ waitret = waitpid(ocr->proc->pid, &status, WNOHANG);
+ if (waitret == ocr->proc->pid) {
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
+ }
+ else if (waitret == 0) {
+ (*ocr->maintenance) (reason, ocr->data, -1);
+ }
+ else if (waitret == -1) {
+ /* uh what the heck? they didn't call unregister? */
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+#endif
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
+{
+ apr_other_child_rec_t *ocr, *next_ocr;
+
+ for (ocr = other_children; ocr; ocr = next_ocr) {
+ next_ocr = ocr->next;
+ apr_proc_other_child_refresh(ocr, reason);
+ }
+}
+
+#else /* !APR_HAS_OTHER_CHILD */
+
+APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
+ void (*maintenance) (int reason, void *, int status),
+ void *data, apr_file_t *write_fd, apr_pool_t *p)
+{
+ return;
+}
+
+APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
+{
+ return;
+}
+
+APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
+ int reason,
+ int status)
+{
+ return APR_ENOTIMPL;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
+ int reason)
+{
+ return;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
+{
+ return;
+}
+
+#endif /* APR_HAS_OTHER_CHILD */
diff --git a/misc/unix/rand.c b/misc/unix/rand.c
new file mode 100644
index 0000000..c0567a6
--- /dev/null
+++ b/misc/unix/rand.c
@@ -0,0 +1,302 @@
+/* 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.
+ */
+
+#define APR_WANT_MEMFUNC
+#include "apr_want.h"
+#include "apr_general.h"
+
+#include "apr_arch_misc.h"
+#include <sys/stat.h>
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if APR_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if defined(HAVE_UUID_H)
+#include <uuid.h>
+#elif defined(HAVE_UUID_UUID_H)
+#include <uuid/uuid.h>
+#elif defined(HAVE_SYS_UUID_H)
+#include <sys/uuid.h>
+#endif
+
+#if defined(SYS_RANDOM)
+#if defined(HAVE_SYS_RANDOM_H) && \
+ defined(HAVE_GETRANDOM)
+
+#include <sys/random.h>
+#define USE_GETRANDOM
+
+#elif defined(HAVE_SYS_SYSCALL_H) && \
+ defined(HAVE_LINUX_RANDOM_H) && \
+ defined(HAVE_DECL_SYS_GETRANDOM) && \
+ HAVE_DECL_SYS_GETRANDOM
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/random.h>
+#define getrandom(buf, buflen, flags) \
+ syscall(SYS_getrandom, (buf), (buflen), (flags))
+#define USE_GETRANDOM
+
+#endif /* HAVE_SYS_RANDOM_H */
+#endif /* SYS_RANDOM */
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#if APR_HAS_OS_UUID
+
+#if defined(HAVE_UUID_CREATE)
+
+APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
+{
+ uint32_t rv;
+ uuid_t g;
+
+ uuid_create(&g, &rv);
+
+ if (rv != uuid_s_ok)
+ return APR_EGENERAL;
+
+ memcpy(uuid_data, &g, sizeof(uuid_t));
+
+ return APR_SUCCESS;
+}
+
+#elif defined(HAVE_UUID_GENERATE)
+
+APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
+{
+ uuid_t g;
+
+ uuid_generate(g);
+
+ memcpy(uuid_data, g, sizeof(uuid_t));
+
+ return APR_SUCCESS;
+}
+#endif
+
+#endif /* APR_HAS_OS_UUID */
+
+#if APR_HAS_RANDOM
+
+APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
+ apr_size_t length)
+{
+#if defined(HAVE_EGD)
+ /* use EGD-compatible socket daemon (such as EGD or PRNGd).
+ * message format:
+ * 0x00 (get entropy level)
+ * 0xMM (msb) 0xmm 0xll 0xLL (lsb)
+ * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
+ * 0xMM (bytes granted) MM bytes
+ * 0x02 (read entropy blocking) 0xNN (bytes desired)
+ * [block] NN bytes
+ * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
+ * NN bytes
+ * (no response - write only)
+ * 0x04 (report PID)
+ * 0xMM (length of PID string, not null-terminated) MM chars
+ */
+ static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
+ const char **egdsockname = NULL;
+
+ int egd_socket, egd_path_len, rv, bad_errno;
+ struct sockaddr_un addr;
+ apr_socklen_t egd_addr_len;
+ apr_size_t resp_expected;
+ unsigned char req[2], resp[255];
+ unsigned char *curbuf = buf;
+
+ for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
+ egd_path_len = strlen(*egdsockname);
+
+ if (egd_path_len > sizeof(addr.sun_path)) {
+ return APR_EINVAL;
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ memcpy(addr.sun_path, *egdsockname, egd_path_len);
+ egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) +
+ egd_path_len;
+
+ egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
+
+ if (egd_socket == -1) {
+ return errno;
+ }
+
+ rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
+
+ if (rv == -1) {
+ bad_errno = errno;
+ continue;
+ }
+
+ /* EGD can only return 255 bytes of data at a time. Silly. */
+ while (length > 0) {
+ apr_ssize_t srv;
+ req[0] = 2; /* We'll block for now. */
+ req[1] = length > 255 ? 255: length;
+
+ srv = write(egd_socket, req, 2);
+ if (srv == -1) {
+ bad_errno = errno;
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ break;
+ }
+
+ if (srv != 2) {
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ return APR_EGENERAL;
+ }
+
+ resp_expected = req[1];
+ srv = read(egd_socket, resp, resp_expected);
+ if (srv == -1) {
+ bad_errno = errno;
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ return bad_errno;
+ }
+
+ memcpy(curbuf, resp, srv);
+ curbuf += srv;
+ length -= srv;
+ }
+
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ }
+
+ if (length > 0) {
+ /* We must have iterated through the list of sockets,
+ * and no go. Return the errno.
+ */
+ return bad_errno;
+ }
+
+#elif defined(SYS_RANDOM) && defined(USE_GETRANDOM)
+
+ do {
+ int rc;
+
+ rc = getrandom(buf, length, 0);
+ if (rc == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return errno;
+ }
+
+ buf += rc;
+ length -= rc;
+ } while (length > 0);
+
+#elif defined(SYS_RANDOM) && defined(HAVE_ARC4RANDOM_BUF)
+
+ arc4random_buf(buf, length);
+
+#elif defined(DEV_RANDOM)
+
+ int fd = -1;
+
+ /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
+ * gives EOF, so reading 'length' bytes may require opening the
+ * device several times. */
+ do {
+ apr_ssize_t rc;
+
+ if (fd == -1)
+ if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
+ return errno;
+
+ do {
+ rc = read(fd, buf, length);
+ } while (rc == -1 && errno == EINTR);
+
+ if (rc < 0) {
+ int errnum = errno;
+ close(fd);
+ return errnum;
+ }
+ else if (rc == 0) {
+ close(fd);
+ fd = -1; /* force open() again */
+ }
+ else {
+ buf += rc;
+ length -= rc;
+ }
+ } while (length > 0);
+
+ close(fd);
+
+#elif defined(OS2)
+
+ static UCHAR randbyte();
+ unsigned int idx;
+
+ for (idx=0; idx<length; idx++)
+ buf[idx] = randbyte();
+
+#elif defined(HAVE_TRUERAND) /* use truerand */
+
+ extern int randbyte(void); /* from the truerand library */
+ unsigned int idx;
+
+ /* this will increase the startup time of the server, unfortunately...
+ * (generating 20 bytes takes about 8 seconds)
+ */
+ for (idx=0; idx<length; idx++)
+ buf[idx] = (unsigned char) randbyte();
+
+#else
+
+#error APR_HAS_RANDOM defined with no implementation
+
+#endif /* DEV_RANDOM */
+
+ return APR_SUCCESS;
+}
+
+#undef STR
+#undef XSTR
+
+#ifdef OS2
+#include "randbyte_os2.inc"
+#endif
+
+#endif /* APR_HAS_RANDOM */
diff --git a/misc/unix/randbyte_os2.inc b/misc/unix/randbyte_os2.inc
new file mode 100644
index 0000000..4020e31
--- /dev/null
+++ b/misc/unix/randbyte_os2.inc
@@ -0,0 +1,123 @@
+/* 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.
+ */
+
+/* The high resolution timer API provides access to the hardware timer
+ * running at around 1.1MHz. The amount this changes in a time slice is
+ * varies randomly due to system events, hardware interrupts etc
+ */
+static UCHAR randbyte_hrtimer()
+{
+ QWORD t1, t2;
+ UCHAR byte;
+
+ DosTmrQueryTime(&t1);
+ DosSleep(5);
+ DosTmrQueryTime(&t2);
+
+ byte = (t2.ulLo - t1.ulLo) & 0xFF;
+ byte ^= (t2.ulLo - t1.ulLo) >> 8;
+ return byte;
+}
+
+
+
+/* A bunch of system information like memory & process stats.
+ * Not highly random but every bit helps....
+ */
+static UCHAR randbyte_sysinfo()
+{
+ UCHAR byte = 0;
+ UCHAR SysVars[100];
+ int b;
+
+ DosQuerySysInfo(1, QSV_FOREGROUND_PROCESS, SysVars, sizeof(SysVars));
+
+ for (b = 0; b < 100; b++) {
+ byte ^= SysVars[b];
+ }
+
+ return byte;
+}
+
+
+
+/* Similar in concept to randbyte_hrtimer() but accesses the CPU's internal
+ * counters which run at the CPU's MHz speed. We get separate
+ * idle / busy / interrupt cycle counts which should provide very good
+ * randomness due to interference of hardware events.
+ * This only works on newer CPUs (at least PPro or K6) and newer OS/2 versions
+ * which is why it's run-time linked.
+ */
+
+static APIRET APIENTRY(*DosPerfSysCall) (ULONG ulCommand, ULONG ulParm1,
+ ULONG ulParm2, ULONG ulParm3) = NULL;
+static HMODULE hDoscalls = 0;
+#define CMD_KI_RDCNT (0x63)
+
+typedef struct _CPUUTIL {
+ ULONG ulTimeLow; /* Low 32 bits of time stamp */
+ ULONG ulTimeHigh; /* High 32 bits of time stamp */
+ ULONG ulIdleLow; /* Low 32 bits of idle time */
+ ULONG ulIdleHigh; /* High 32 bits of idle time */
+ ULONG ulBusyLow; /* Low 32 bits of busy time */
+ ULONG ulBusyHigh; /* High 32 bits of busy time */
+ ULONG ulIntrLow; /* Low 32 bits of interrupt time */
+ ULONG ulIntrHigh; /* High 32 bits of interrupt time */
+} CPUUTIL;
+
+
+static UCHAR randbyte_perf()
+{
+ UCHAR byte = 0;
+ CPUUTIL util;
+ int c;
+
+ if (hDoscalls == 0) {
+ char failed_module[20];
+ ULONG rc;
+
+ rc = DosLoadModule(failed_module, sizeof(failed_module), "DOSCALLS",
+ &hDoscalls);
+
+ if (rc == 0) {
+ rc = DosQueryProcAddr(hDoscalls, 976, NULL, (PFN *)&DosPerfSysCall);
+
+ if (rc) {
+ DosPerfSysCall = NULL;
+ }
+ }
+ }
+
+ if (DosPerfSysCall) {
+ if (DosPerfSysCall(CMD_KI_RDCNT, (ULONG)&util, 0, 0) == 0) {
+ for (c = 0; c < sizeof(util); c++) {
+ byte ^= ((UCHAR *)&util)[c];
+ }
+ }
+ else {
+ DosPerfSysCall = NULL;
+ }
+ }
+
+ return byte;
+}
+
+
+
+static UCHAR randbyte()
+{
+ return randbyte_hrtimer() ^ randbyte_sysinfo() ^ randbyte_perf();
+}
diff --git a/misc/unix/start.c b/misc/unix/start.c
new file mode 100644
index 0000000..4b8ad99
--- /dev/null
+++ b/misc/unix/start.c
@@ -0,0 +1,89 @@
+/* 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 "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_signal.h"
+#include "apr_atomic.h"
+
+#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */
+#include "apr_arch_internal_time.h"
+
+
+APR_DECLARE(apr_status_t) apr_app_initialize(int *argc,
+ const char * const * *argv,
+ const char * const * *env)
+{
+ /* An absolute noop. At present, only Win32 requires this stub, but it's
+ * required in order to move command arguments passed through the service
+ * control manager into the process, and it's required to fix the char*
+ * data passed in from win32 unicode into utf-8, win32's apr internal fmt.
+ */
+ return apr_initialize();
+}
+
+static int initialized = 0;
+
+APR_DECLARE(apr_status_t) apr_initialize(void)
+{
+ apr_pool_t *pool;
+ apr_status_t status;
+
+ if (initialized++) {
+ return APR_SUCCESS;
+ }
+
+#if !defined(BEOS) && !defined(OS2)
+ apr_proc_mutex_unix_setup_lock();
+ apr_unix_setup_time();
+#endif
+
+ if ((status = apr_pool_initialize()) != APR_SUCCESS)
+ return status;
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return APR_ENOPOOL;
+ }
+
+ apr_pool_tag(pool, "apr_initialize");
+
+ /* apr_atomic_init() used to be called from here aswell.
+ * Pools rely on mutexes though, which can be backed by
+ * atomics. Due to this circular dependency
+ * apr_pool_initialize() is taking care of calling
+ * apr_atomic_init() at the correct time.
+ */
+
+ apr_signal_init(pool);
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE_NONSTD(void) apr_terminate(void)
+{
+ initialized--;
+ if (initialized) {
+ return;
+ }
+ apr_pool_terminate();
+
+}
+
+APR_DECLARE(void) apr_terminate2(void)
+{
+ apr_terminate();
+}
diff --git a/misc/unix/version.c b/misc/unix/version.c
new file mode 100644
index 0000000..2f111bf
--- /dev/null
+++ b/misc/unix/version.c
@@ -0,0 +1,35 @@
+/* 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 "apr_version.h"
+#include "apr_general.h" /* for APR_STRINGIFY */
+
+APR_DECLARE(void) apr_version(apr_version_t *pvsn)
+{
+ pvsn->major = APR_MAJOR_VERSION;
+ pvsn->minor = APR_MINOR_VERSION;
+ pvsn->patch = APR_PATCH_VERSION;
+#ifdef APR_IS_DEV_VERSION
+ pvsn->is_dev = 1;
+#else
+ pvsn->is_dev = 0;
+#endif
+}
+
+APR_DECLARE(const char *) apr_version_string(void)
+{
+ return APR_VERSION_STRING;
+}