6c648dd642
This is actually a fully functional build except: * All internal shared libraries are static linked to make sure there is no interference with ports (and to reduce build time). * It does not have the python/perl/etc plugin or API support. * By default, it installs as "svnlite" rather than "svn". * If WITH_SVN added in make.conf, you get "svn". * If WITHOUT_SVNLITE is in make.conf, this is completely disabled. To be absolutely clear, this is not intended for any use other than checking out freebsd source and committing, like we once did with cvs. It should be usable for small scale local repositories that don't need the python/perl plugin architecture.
488 lines
12 KiB
C
488 lines
12 KiB
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.
|
|
*/
|
|
|
|
#define INCL_DOSEXCEPTIONS /* for OS2 */
|
|
#include "apr_arch_threadproc.h"
|
|
#include "apr_private.h"
|
|
#include "apr_pools.h"
|
|
#include "apr_signal.h"
|
|
#include "apr_strings.h"
|
|
|
|
#include <assert.h>
|
|
#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#ifdef SIGWAIT_TAKES_ONE_ARG
|
|
#define apr_sigwait(a,b) ((*(b)=sigwait((a)))<0?-1:0)
|
|
#else
|
|
#define apr_sigwait(a,b) sigwait((a),(b))
|
|
#endif
|
|
|
|
APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum)
|
|
{
|
|
#ifdef OS2
|
|
/* SIGTERM's don't work too well in OS/2 (only affects other EMX
|
|
* programs). CGIs may not be, esp. REXX scripts, so use a native
|
|
* call instead
|
|
*/
|
|
if (signum == SIGTERM) {
|
|
return APR_OS2_STATUS(DosSendSignalException(proc->pid,
|
|
XCPT_SIGNAL_BREAK));
|
|
}
|
|
#endif /* OS2 */
|
|
|
|
if (kill(proc->pid, signum) == -1) {
|
|
return errno;
|
|
}
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
|
|
#if APR_HAVE_SIGACTION
|
|
|
|
#if defined(__NetBSD__) || defined(DARWIN)
|
|
static void avoid_zombies(int signo)
|
|
{
|
|
int exit_status;
|
|
|
|
while (waitpid(-1, &exit_status, WNOHANG) > 0) {
|
|
/* do nothing */
|
|
}
|
|
}
|
|
#endif /* DARWIN */
|
|
|
|
/*
|
|
* Replace standard signal() with the more reliable sigaction equivalent
|
|
* from W. Richard Stevens' "Advanced Programming in the UNIX Environment"
|
|
* (the version that does not automatically restart system calls).
|
|
*/
|
|
APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func)
|
|
{
|
|
struct sigaction act, oact;
|
|
|
|
act.sa_handler = func;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = 0;
|
|
#ifdef SA_INTERRUPT /* SunOS */
|
|
act.sa_flags |= SA_INTERRUPT;
|
|
#endif
|
|
#if defined(__osf__) && defined(__alpha)
|
|
/* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */
|
|
|
|
/* this is required on Tru64 to cause child processes to
|
|
* disappear gracefully - XPG4 compatible
|
|
*/
|
|
if ((signo == SIGCHLD) && (func == SIG_IGN)) {
|
|
act.sa_flags |= SA_NOCLDWAIT;
|
|
}
|
|
#endif
|
|
#if defined(__NetBSD__) || defined(DARWIN)
|
|
/* ignoring SIGCHLD or leaving the default disposition doesn't avoid zombies,
|
|
* and there is no SA_NOCLDWAIT flag, so catch the signal and reap status in
|
|
* the handler to avoid zombies
|
|
*/
|
|
if ((signo == SIGCHLD) && (func == SIG_IGN)) {
|
|
act.sa_handler = avoid_zombies;
|
|
}
|
|
#endif
|
|
if (sigaction(signo, &act, &oact) < 0)
|
|
return SIG_ERR;
|
|
return oact.sa_handler;
|
|
}
|
|
|
|
#endif /* HAVE_SIGACTION */
|
|
|
|
/* AC_DECL_SYS_SIGLIST defines either of these symbols depending
|
|
* on the version of autoconf used. */
|
|
#if defined(SYS_SIGLIST_DECLARED) || HAVE_DECL_SYS_SIGLIST
|
|
|
|
void apr_signal_init(apr_pool_t *pglobal)
|
|
{
|
|
}
|
|
const char *apr_signal_description_get(int signum)
|
|
{
|
|
return (signum >= 0) ? sys_siglist[signum] : "unknown signal (number)";
|
|
}
|
|
|
|
#else /* !(SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST) */
|
|
|
|
/* we need to roll our own signal description stuff */
|
|
|
|
#if defined(NSIG)
|
|
#define APR_NUMSIG NSIG
|
|
#elif defined(_NSIG)
|
|
#define APR_NUMSIG _NSIG
|
|
#elif defined(__NSIG)
|
|
#define APR_NUMSIG __NSIG
|
|
#else
|
|
#define APR_NUMSIG 33 /* breaks on OS/390 with < 33; 32 is o.k. for most */
|
|
#endif
|
|
|
|
static const char *signal_description[APR_NUMSIG];
|
|
|
|
#define store_desc(index, string) \
|
|
do { \
|
|
if (index >= APR_NUMSIG) { \
|
|
assert(index < APR_NUMSIG); \
|
|
} \
|
|
else { \
|
|
signal_description[index] = string; \
|
|
} \
|
|
} while (0)
|
|
|
|
void apr_signal_init(apr_pool_t *pglobal)
|
|
{
|
|
int sig;
|
|
|
|
store_desc(0, "Signal 0");
|
|
|
|
#ifdef SIGHUP
|
|
store_desc(SIGHUP, "Hangup");
|
|
#endif
|
|
#ifdef SIGINT
|
|
store_desc(SIGINT, "Interrupt");
|
|
#endif
|
|
#ifdef SIGQUIT
|
|
store_desc(SIGQUIT, "Quit");
|
|
#endif
|
|
#ifdef SIGILL
|
|
store_desc(SIGILL, "Illegal instruction");
|
|
#endif
|
|
#ifdef SIGTRAP
|
|
store_desc(SIGTRAP, "Trace/BPT trap");
|
|
#endif
|
|
#ifdef SIGIOT
|
|
store_desc(SIGIOT, "IOT instruction");
|
|
#endif
|
|
#ifdef SIGABRT
|
|
store_desc(SIGABRT, "Abort");
|
|
#endif
|
|
#ifdef SIGEMT
|
|
store_desc(SIGEMT, "Emulator trap");
|
|
#endif
|
|
#ifdef SIGFPE
|
|
store_desc(SIGFPE, "Arithmetic exception");
|
|
#endif
|
|
#ifdef SIGKILL
|
|
store_desc(SIGKILL, "Killed");
|
|
#endif
|
|
#ifdef SIGBUS
|
|
store_desc(SIGBUS, "Bus error");
|
|
#endif
|
|
#ifdef SIGSEGV
|
|
store_desc(SIGSEGV, "Segmentation fault");
|
|
#endif
|
|
#ifdef SIGSYS
|
|
store_desc(SIGSYS, "Bad system call");
|
|
#endif
|
|
#ifdef SIGPIPE
|
|
store_desc(SIGPIPE, "Broken pipe");
|
|
#endif
|
|
#ifdef SIGALRM
|
|
store_desc(SIGALRM, "Alarm clock");
|
|
#endif
|
|
#ifdef SIGTERM
|
|
store_desc(SIGTERM, "Terminated");
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
store_desc(SIGUSR1, "User defined signal 1");
|
|
#endif
|
|
#ifdef SIGUSR2
|
|
store_desc(SIGUSR2, "User defined signal 2");
|
|
#endif
|
|
#ifdef SIGCLD
|
|
store_desc(SIGCLD, "Child status change");
|
|
#endif
|
|
#ifdef SIGCHLD
|
|
store_desc(SIGCHLD, "Child status change");
|
|
#endif
|
|
#ifdef SIGPWR
|
|
store_desc(SIGPWR, "Power-fail restart");
|
|
#endif
|
|
#ifdef SIGWINCH
|
|
store_desc(SIGWINCH, "Window changed");
|
|
#endif
|
|
#ifdef SIGURG
|
|
store_desc(SIGURG, "urgent socket condition");
|
|
#endif
|
|
#ifdef SIGPOLL
|
|
store_desc(SIGPOLL, "Pollable event occurred");
|
|
#endif
|
|
#ifdef SIGIO
|
|
store_desc(SIGIO, "socket I/O possible");
|
|
#endif
|
|
#ifdef SIGSTOP
|
|
store_desc(SIGSTOP, "Stopped (signal)");
|
|
#endif
|
|
#ifdef SIGTSTP
|
|
store_desc(SIGTSTP, "Stopped");
|
|
#endif
|
|
#ifdef SIGCONT
|
|
store_desc(SIGCONT, "Continued");
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
store_desc(SIGTTIN, "Stopped (tty input)");
|
|
#endif
|
|
#ifdef SIGTTOU
|
|
store_desc(SIGTTOU, "Stopped (tty output)");
|
|
#endif
|
|
#ifdef SIGVTALRM
|
|
store_desc(SIGVTALRM, "virtual timer expired");
|
|
#endif
|
|
#ifdef SIGPROF
|
|
store_desc(SIGPROF, "profiling timer expired");
|
|
#endif
|
|
#ifdef SIGXCPU
|
|
store_desc(SIGXCPU, "exceeded cpu limit");
|
|
#endif
|
|
#ifdef SIGXFSZ
|
|
store_desc(SIGXFSZ, "exceeded file size limit");
|
|
#endif
|
|
|
|
for (sig = 0; sig < APR_NUMSIG; ++sig)
|
|
if (signal_description[sig] == NULL)
|
|
signal_description[sig] = apr_psprintf(pglobal, "signal #%d", sig);
|
|
}
|
|
|
|
const char *apr_signal_description_get(int signum)
|
|
{
|
|
return
|
|
(signum >= 0 && signum < APR_NUMSIG)
|
|
? signal_description[signum]
|
|
: "unknown signal (number)";
|
|
}
|
|
|
|
#endif /* SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST */
|
|
|
|
#if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2)
|
|
|
|
static void remove_sync_sigs(sigset_t *sig_mask)
|
|
{
|
|
#ifdef SIGABRT
|
|
sigdelset(sig_mask, SIGABRT);
|
|
#endif
|
|
#ifdef SIGBUS
|
|
sigdelset(sig_mask, SIGBUS);
|
|
#endif
|
|
#ifdef SIGEMT
|
|
sigdelset(sig_mask, SIGEMT);
|
|
#endif
|
|
#ifdef SIGFPE
|
|
sigdelset(sig_mask, SIGFPE);
|
|
#endif
|
|
#ifdef SIGILL
|
|
sigdelset(sig_mask, SIGILL);
|
|
#endif
|
|
#ifdef SIGIOT
|
|
sigdelset(sig_mask, SIGIOT);
|
|
#endif
|
|
#ifdef SIGPIPE
|
|
sigdelset(sig_mask, SIGPIPE);
|
|
#endif
|
|
#ifdef SIGSEGV
|
|
sigdelset(sig_mask, SIGSEGV);
|
|
#endif
|
|
#ifdef SIGSYS
|
|
sigdelset(sig_mask, SIGSYS);
|
|
#endif
|
|
#ifdef SIGTRAP
|
|
sigdelset(sig_mask, SIGTRAP);
|
|
#endif
|
|
|
|
/* the rest of the signals removed from the mask in this function
|
|
* absolutely must be removed; you cannot block synchronous signals
|
|
* (requirement of pthreads API)
|
|
*
|
|
* SIGUSR2 is being removed from the mask for the convenience of
|
|
* Purify users (Solaris, HP-UX, SGI) since Purify uses SIGUSR2
|
|
*/
|
|
#ifdef SIGUSR2
|
|
sigdelset(sig_mask, SIGUSR2);
|
|
#endif
|
|
}
|
|
|
|
APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum))
|
|
{
|
|
sigset_t sig_mask;
|
|
#if APR_HAVE_SIGWAIT
|
|
int (*sig_func)(int signum) = (int (*)(int))signal_handler;
|
|
#endif
|
|
|
|
/* This thread will be the one responsible for handling signals */
|
|
sigfillset(&sig_mask);
|
|
|
|
/* On certain platforms, sigwait() returns EINVAL if any of various
|
|
* unblockable signals are included in the mask. This was first
|
|
* observed on AIX and Tru64.
|
|
*/
|
|
#ifdef SIGKILL
|
|
sigdelset(&sig_mask, SIGKILL);
|
|
#endif
|
|
#ifdef SIGSTOP
|
|
sigdelset(&sig_mask, SIGSTOP);
|
|
#endif
|
|
#ifdef SIGCONT
|
|
sigdelset(&sig_mask, SIGCONT);
|
|
#endif
|
|
#ifdef SIGWAITING
|
|
sigdelset(&sig_mask, SIGWAITING);
|
|
#endif
|
|
|
|
/* no synchronous signals should be in the mask passed to sigwait() */
|
|
remove_sync_sigs(&sig_mask);
|
|
|
|
/* On AIX (4.3.3, at least), sigwait() won't wake up if the high-
|
|
* order bit of the second word of flags is turned on. sigdelset()
|
|
* returns an error when trying to turn this off, so we'll turn it
|
|
* off manually.
|
|
*
|
|
* Note that the private fields differ between 32-bit and 64-bit
|
|
* and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on
|
|
* AIX 4.3 32-bit builds and 64-bit builds use the same definition.
|
|
*
|
|
* Applicable AIX fixes such that this is no longer needed:
|
|
*
|
|
* APAR IY23096 for AIX 51B, fix included in AIX 51C, and
|
|
* APAR IY24162 for 43X.
|
|
*/
|
|
#if defined(_AIX)
|
|
#if defined(__64BIT__) && defined(_AIXVERSION_510)
|
|
#ifdef _ALL_SOURCE
|
|
sig_mask.ss_set[3] &= 0x7FFFFFFF;
|
|
#else /* not _ALL_SOURCE */
|
|
sig_mask.__ss_set[3] &= 0x7FFFFFFF;
|
|
#endif
|
|
#else /* not 64-bit build, or 64-bit build on 4.3 */
|
|
#ifdef _ALL_SOURCE
|
|
sig_mask.hisigs &= 0x7FFFFFFF;
|
|
#else /* not _ALL_SOURCE */
|
|
sig_mask.__hisigs &= 0x7FFFFFFF;
|
|
#endif
|
|
#endif
|
|
#endif /* _AIX */
|
|
|
|
while (1) {
|
|
#if APR_HAVE_SIGWAIT
|
|
int signal_received;
|
|
|
|
if (apr_sigwait(&sig_mask, &signal_received) != 0)
|
|
{
|
|
/* handle sigwait() error here */
|
|
}
|
|
|
|
if (sig_func(signal_received) == 1) {
|
|
return APR_SUCCESS;
|
|
}
|
|
#elif HAVE_SIGSUSPEND
|
|
sigsuspend(&sig_mask);
|
|
#else
|
|
#error No apr_sigwait() and no sigsuspend()
|
|
#endif
|
|
}
|
|
}
|
|
|
|
APR_DECLARE(apr_status_t) apr_setup_signal_thread(void)
|
|
{
|
|
sigset_t sig_mask;
|
|
int rv;
|
|
|
|
/* All threads should mask out signals to be handled by
|
|
* the thread doing sigwait().
|
|
*
|
|
* No thread should ever block synchronous signals.
|
|
* See the Solaris man page for pthread_sigmask() for
|
|
* some information. Solaris chooses to knock out such
|
|
* processes when a blocked synchronous signal is
|
|
* delivered, skipping any registered signal handler.
|
|
* AIX doesn't call a signal handler either. At least
|
|
* one level of linux+glibc does call the handler even
|
|
* when the synchronous signal is blocked.
|
|
*/
|
|
sigfillset(&sig_mask);
|
|
remove_sync_sigs(&sig_mask);
|
|
|
|
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
|
|
if ((rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
|
|
rv = errno;
|
|
}
|
|
#else
|
|
if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
|
|
#ifdef HAVE_ZOS_PTHREADS
|
|
rv = errno;
|
|
#endif
|
|
}
|
|
#endif
|
|
return rv;
|
|
}
|
|
|
|
#endif /* APR_HAS_THREADS && ... */
|
|
|
|
APR_DECLARE(apr_status_t) apr_signal_block(int signum)
|
|
{
|
|
#if APR_HAVE_SIGACTION
|
|
sigset_t sig_mask;
|
|
int rv;
|
|
|
|
sigemptyset(&sig_mask);
|
|
|
|
sigaddset(&sig_mask, signum);
|
|
|
|
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
|
|
if ((rv = sigprocmask(SIG_BLOCK, &sig_mask, NULL)) != 0) {
|
|
rv = errno;
|
|
}
|
|
#else
|
|
if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) {
|
|
#ifdef HAVE_ZOS_PTHREADS
|
|
rv = errno;
|
|
#endif
|
|
}
|
|
#endif
|
|
return rv;
|
|
#else
|
|
return APR_ENOTIMPL;
|
|
#endif
|
|
}
|
|
|
|
APR_DECLARE(apr_status_t) apr_signal_unblock(int signum)
|
|
{
|
|
#if APR_HAVE_SIGACTION
|
|
sigset_t sig_mask;
|
|
int rv;
|
|
|
|
sigemptyset(&sig_mask);
|
|
|
|
sigaddset(&sig_mask, signum);
|
|
|
|
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
|
|
if ((rv = sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) {
|
|
rv = errno;
|
|
}
|
|
#else
|
|
if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) {
|
|
#ifdef HAVE_ZOS_PTHREADS
|
|
rv = errno;
|
|
#endif
|
|
}
|
|
#endif
|
|
return rv;
|
|
#else
|
|
return APR_ENOTIMPL;
|
|
#endif
|
|
}
|