1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define INCL_DOSEXCEPTIONS /* for OS2 */ 18#include "apr_arch_threadproc.h" 19#include "apr_private.h" 20#include "apr_pools.h" 21#include "apr_signal.h" 22#include "apr_strings.h" 23 24#include <assert.h> 25#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H 26#include <pthread.h> 27#endif 28 29#ifdef SIGWAIT_TAKES_ONE_ARG 30#define apr_sigwait(a,b) ((*(b)=sigwait((a)))<0?-1:0) 31#else 32#define apr_sigwait(a,b) sigwait((a),(b)) 33#endif 34 35APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum) 36{ 37#ifdef OS2 38 /* SIGTERM's don't work too well in OS/2 (only affects other EMX 39 * programs). CGIs may not be, esp. REXX scripts, so use a native 40 * call instead 41 */ 42 if (signum == SIGTERM) { 43 return APR_OS2_STATUS(DosSendSignalException(proc->pid, 44 XCPT_SIGNAL_BREAK)); 45 } 46#endif /* OS2 */ 47 48 if (kill(proc->pid, signum) == -1) { 49 return errno; 50 } 51 52 return APR_SUCCESS; 53} 54 55 56#if APR_HAVE_SIGACTION 57 58#if defined(__NetBSD__) || defined(DARWIN) 59static void avoid_zombies(int signo) 60{ 61 int exit_status; 62 63 while (waitpid(-1, &exit_status, WNOHANG) > 0) { 64 /* do nothing */ 65 } 66} 67#endif /* DARWIN */ 68 69/* 70 * Replace standard signal() with the more reliable sigaction equivalent 71 * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" 72 * (the version that does not automatically restart system calls). 73 */ 74APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func) 75{ 76 struct sigaction act, oact; 77 78 act.sa_handler = func; 79 sigemptyset(&act.sa_mask); 80 act.sa_flags = 0; 81#ifdef SA_INTERRUPT /* SunOS */ 82 act.sa_flags |= SA_INTERRUPT; 83#endif 84#if defined(__osf__) && defined(__alpha) 85 /* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */ 86 87 /* this is required on Tru64 to cause child processes to 88 * disappear gracefully - XPG4 compatible 89 */ 90 if ((signo == SIGCHLD) && (func == SIG_IGN)) { 91 act.sa_flags |= SA_NOCLDWAIT; 92 } 93#endif 94#if defined(__NetBSD__) || defined(DARWIN) 95 /* ignoring SIGCHLD or leaving the default disposition doesn't avoid zombies, 96 * and there is no SA_NOCLDWAIT flag, so catch the signal and reap status in 97 * the handler to avoid zombies 98 */ 99 if ((signo == SIGCHLD) && (func == SIG_IGN)) { 100 act.sa_handler = avoid_zombies; 101 } 102#endif 103 if (sigaction(signo, &act, &oact) < 0) 104 return SIG_ERR; 105 return oact.sa_handler; 106} 107 108#endif /* HAVE_SIGACTION */ 109 110/* AC_DECL_SYS_SIGLIST defines either of these symbols depending 111 * on the version of autoconf used. */ 112#if defined(SYS_SIGLIST_DECLARED) || HAVE_DECL_SYS_SIGLIST 113 114void apr_signal_init(apr_pool_t *pglobal) 115{ 116} 117const char *apr_signal_description_get(int signum) 118{ 119 return (signum >= 0) ? sys_siglist[signum] : "unknown signal (number)"; 120} 121 122#else /* !(SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST) */ 123 124/* we need to roll our own signal description stuff */ 125 126#if defined(NSIG) 127#define APR_NUMSIG NSIG 128#elif defined(_NSIG) 129#define APR_NUMSIG _NSIG 130#elif defined(__NSIG) 131#define APR_NUMSIG __NSIG 132#else 133#define APR_NUMSIG 33 /* breaks on OS/390 with < 33; 32 is o.k. for most */ 134#endif 135 136static const char *signal_description[APR_NUMSIG]; 137 138#define store_desc(index, string) \ 139 do { \ 140 if (index >= APR_NUMSIG) { \ 141 assert(index < APR_NUMSIG); \ 142 } \ 143 else { \ 144 signal_description[index] = string; \ 145 } \ 146 } while (0) 147 148void apr_signal_init(apr_pool_t *pglobal) 149{ 150 int sig; 151 152 store_desc(0, "Signal 0"); 153 154#ifdef SIGHUP 155 store_desc(SIGHUP, "Hangup"); 156#endif 157#ifdef SIGINT 158 store_desc(SIGINT, "Interrupt"); 159#endif 160#ifdef SIGQUIT 161 store_desc(SIGQUIT, "Quit"); 162#endif 163#ifdef SIGILL 164 store_desc(SIGILL, "Illegal instruction"); 165#endif 166#ifdef SIGTRAP 167 store_desc(SIGTRAP, "Trace/BPT trap"); 168#endif 169#ifdef SIGIOT 170 store_desc(SIGIOT, "IOT instruction"); 171#endif 172#ifdef SIGABRT 173 store_desc(SIGABRT, "Abort"); 174#endif 175#ifdef SIGEMT 176 store_desc(SIGEMT, "Emulator trap"); 177#endif 178#ifdef SIGFPE 179 store_desc(SIGFPE, "Arithmetic exception"); 180#endif 181#ifdef SIGKILL 182 store_desc(SIGKILL, "Killed"); 183#endif 184#ifdef SIGBUS 185 store_desc(SIGBUS, "Bus error"); 186#endif 187#ifdef SIGSEGV 188 store_desc(SIGSEGV, "Segmentation fault"); 189#endif 190#ifdef SIGSYS 191 store_desc(SIGSYS, "Bad system call"); 192#endif 193#ifdef SIGPIPE 194 store_desc(SIGPIPE, "Broken pipe"); 195#endif 196#ifdef SIGALRM 197 store_desc(SIGALRM, "Alarm clock"); 198#endif 199#ifdef SIGTERM 200 store_desc(SIGTERM, "Terminated"); 201#endif 202#ifdef SIGUSR1 203 store_desc(SIGUSR1, "User defined signal 1"); 204#endif 205#ifdef SIGUSR2 206 store_desc(SIGUSR2, "User defined signal 2"); 207#endif 208#ifdef SIGCLD 209 store_desc(SIGCLD, "Child status change"); 210#endif 211#ifdef SIGCHLD 212 store_desc(SIGCHLD, "Child status change"); 213#endif 214#ifdef SIGPWR 215 store_desc(SIGPWR, "Power-fail restart"); 216#endif 217#ifdef SIGWINCH 218 store_desc(SIGWINCH, "Window changed"); 219#endif 220#ifdef SIGURG 221 store_desc(SIGURG, "urgent socket condition"); 222#endif 223#ifdef SIGPOLL 224 store_desc(SIGPOLL, "Pollable event occurred"); 225#endif 226#ifdef SIGIO 227 store_desc(SIGIO, "socket I/O possible"); 228#endif 229#ifdef SIGSTOP 230 store_desc(SIGSTOP, "Stopped (signal)"); 231#endif 232#ifdef SIGTSTP 233 store_desc(SIGTSTP, "Stopped"); 234#endif 235#ifdef SIGCONT 236 store_desc(SIGCONT, "Continued"); 237#endif 238#ifdef SIGTTIN 239 store_desc(SIGTTIN, "Stopped (tty input)"); 240#endif 241#ifdef SIGTTOU 242 store_desc(SIGTTOU, "Stopped (tty output)"); 243#endif 244#ifdef SIGVTALRM 245 store_desc(SIGVTALRM, "virtual timer expired"); 246#endif 247#ifdef SIGPROF 248 store_desc(SIGPROF, "profiling timer expired"); 249#endif 250#ifdef SIGXCPU 251 store_desc(SIGXCPU, "exceeded cpu limit"); 252#endif 253#ifdef SIGXFSZ 254 store_desc(SIGXFSZ, "exceeded file size limit"); 255#endif 256 257 for (sig = 0; sig < APR_NUMSIG; ++sig) 258 if (signal_description[sig] == NULL) 259 signal_description[sig] = apr_psprintf(pglobal, "signal #%d", sig); 260} 261 262const char *apr_signal_description_get(int signum) 263{ 264 return 265 (signum >= 0 && signum < APR_NUMSIG) 266 ? signal_description[signum] 267 : "unknown signal (number)"; 268} 269 270#endif /* SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST */ 271 272#if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2) 273 274static void remove_sync_sigs(sigset_t *sig_mask) 275{ 276#ifdef SIGABRT 277 sigdelset(sig_mask, SIGABRT); 278#endif 279#ifdef SIGBUS 280 sigdelset(sig_mask, SIGBUS); 281#endif 282#ifdef SIGEMT 283 sigdelset(sig_mask, SIGEMT); 284#endif 285#ifdef SIGFPE 286 sigdelset(sig_mask, SIGFPE); 287#endif 288#ifdef SIGILL 289 sigdelset(sig_mask, SIGILL); 290#endif 291#ifdef SIGIOT 292 sigdelset(sig_mask, SIGIOT); 293#endif 294#ifdef SIGPIPE 295 sigdelset(sig_mask, SIGPIPE); 296#endif 297#ifdef SIGSEGV 298 sigdelset(sig_mask, SIGSEGV); 299#endif 300#ifdef SIGSYS 301 sigdelset(sig_mask, SIGSYS); 302#endif 303#ifdef SIGTRAP 304 sigdelset(sig_mask, SIGTRAP); 305#endif 306 307/* the rest of the signals removed from the mask in this function 308 * absolutely must be removed; you cannot block synchronous signals 309 * (requirement of pthreads API) 310 * 311 * SIGUSR2 is being removed from the mask for the convenience of 312 * Purify users (Solaris, HP-UX, SGI) since Purify uses SIGUSR2 313 */ 314#ifdef SIGUSR2 315 sigdelset(sig_mask, SIGUSR2); 316#endif 317} 318 319APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)) 320{ 321 sigset_t sig_mask; 322#if APR_HAVE_SIGWAIT 323 int (*sig_func)(int signum) = (int (*)(int))signal_handler; 324#endif 325 326 /* This thread will be the one responsible for handling signals */ 327 sigfillset(&sig_mask); 328 329 /* On certain platforms, sigwait() returns EINVAL if any of various 330 * unblockable signals are included in the mask. This was first 331 * observed on AIX and Tru64. 332 */ 333#ifdef SIGKILL 334 sigdelset(&sig_mask, SIGKILL); 335#endif 336#ifdef SIGSTOP 337 sigdelset(&sig_mask, SIGSTOP); 338#endif 339#ifdef SIGCONT 340 sigdelset(&sig_mask, SIGCONT); 341#endif 342#ifdef SIGWAITING 343 sigdelset(&sig_mask, SIGWAITING); 344#endif 345 346 /* no synchronous signals should be in the mask passed to sigwait() */ 347 remove_sync_sigs(&sig_mask); 348 349 /* On AIX (4.3.3, at least), sigwait() won't wake up if the high- 350 * order bit of the second word of flags is turned on. sigdelset() 351 * returns an error when trying to turn this off, so we'll turn it 352 * off manually. 353 * 354 * Note that the private fields differ between 32-bit and 64-bit 355 * and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on 356 * AIX 4.3 32-bit builds and 64-bit builds use the same definition. 357 * 358 * Applicable AIX fixes such that this is no longer needed: 359 * 360 * APAR IY23096 for AIX 51B, fix included in AIX 51C, and 361 * APAR IY24162 for 43X. 362 */ 363#if defined(_AIX) 364#if defined(__64BIT__) && defined(_AIXVERSION_510) 365#ifdef _ALL_SOURCE 366 sig_mask.ss_set[3] &= 0x7FFFFFFF; 367#else /* not _ALL_SOURCE */ 368 sig_mask.__ss_set[3] &= 0x7FFFFFFF; 369#endif 370#else /* not 64-bit build, or 64-bit build on 4.3 */ 371#ifdef _ALL_SOURCE 372 sig_mask.hisigs &= 0x7FFFFFFF; 373#else /* not _ALL_SOURCE */ 374 sig_mask.__hisigs &= 0x7FFFFFFF; 375#endif 376#endif 377#endif /* _AIX */ 378 379 while (1) { 380#if APR_HAVE_SIGWAIT 381 int signal_received; 382 383 if (apr_sigwait(&sig_mask, &signal_received) != 0) 384 { 385 /* handle sigwait() error here */ 386 } 387 388 if (sig_func(signal_received) == 1) { 389 return APR_SUCCESS; 390 } 391#elif HAVE_SIGSUSPEND 392 sigsuspend(&sig_mask); 393#else 394#error No apr_sigwait() and no sigsuspend() 395#endif 396 } 397} 398 399APR_DECLARE(apr_status_t) apr_setup_signal_thread(void) 400{ 401 sigset_t sig_mask; 402 int rv; 403 404 /* All threads should mask out signals to be handled by 405 * the thread doing sigwait(). 406 * 407 * No thread should ever block synchronous signals. 408 * See the Solaris man page for pthread_sigmask() for 409 * some information. Solaris chooses to knock out such 410 * processes when a blocked synchronous signal is 411 * delivered, skipping any registered signal handler. 412 * AIX doesn't call a signal handler either. At least 413 * one level of linux+glibc does call the handler even 414 * when the synchronous signal is blocked. 415 */ 416 sigfillset(&sig_mask); 417 remove_sync_sigs(&sig_mask); 418 419#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS 420 if ((rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { 421 rv = errno; 422 } 423#else 424 if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { 425#ifdef HAVE_ZOS_PTHREADS 426 rv = errno; 427#endif 428 } 429#endif 430 return rv; 431} 432 433#endif /* APR_HAS_THREADS && ... */ 434 435APR_DECLARE(apr_status_t) apr_signal_block(int signum) 436{ 437#if APR_HAVE_SIGACTION 438 sigset_t sig_mask; 439 int rv; 440 441 sigemptyset(&sig_mask); 442 443 sigaddset(&sig_mask, signum); 444 445#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS 446 if ((rv = sigprocmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { 447 rv = errno; 448 } 449#else 450 if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { 451#ifdef HAVE_ZOS_PTHREADS 452 rv = errno; 453#endif 454 } 455#endif 456 return rv; 457#else 458 return APR_ENOTIMPL; 459#endif 460} 461 462APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) 463{ 464#if APR_HAVE_SIGACTION 465 sigset_t sig_mask; 466 int rv; 467 468 sigemptyset(&sig_mask); 469 470 sigaddset(&sig_mask, signum); 471 472#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS 473 if ((rv = sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { 474 rv = errno; 475 } 476#else 477 if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { 478#ifdef HAVE_ZOS_PTHREADS 479 rv = errno; 480#endif 481 } 482#endif 483 return rv; 484#else 485 return APR_ENOTIMPL; 486#endif 487} 488