2020-06-15 14:18:57 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
2020-06-15 14:18:57 +00:00
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
2020-06-15 14:18:57 +00:00
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
2021-02-08 17:19:00 +00:00
|
|
|
#include "libc/assert.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/bits/bits.h"
|
|
|
|
#include "libc/calls/calls.h"
|
|
|
|
#include "libc/calls/internal.h"
|
2021-02-03 14:22:51 +00:00
|
|
|
#include "libc/calls/sigbits.h"
|
2020-11-25 16:19:00 +00:00
|
|
|
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
|
|
|
#include "libc/calls/struct/sigaction-linux.internal.h"
|
2021-02-05 17:44:54 +00:00
|
|
|
#include "libc/calls/struct/sigaction-netbsd.h"
|
2020-11-25 16:19:00 +00:00
|
|
|
#include "libc/calls/struct/sigaction-openbsd.internal.h"
|
|
|
|
#include "libc/calls/struct/sigaction-xnu.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/struct/sigaction.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
#include "libc/calls/typedef/sigaction_f.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/ucontext.h"
|
|
|
|
#include "libc/dce.h"
|
|
|
|
#include "libc/limits.h"
|
|
|
|
#include "libc/macros.h"
|
|
|
|
#include "libc/mem/mem.h"
|
|
|
|
#include "libc/runtime/runtime.h"
|
|
|
|
#include "libc/str/str.h"
|
|
|
|
#include "libc/sysv/consts/sa.h"
|
|
|
|
#include "libc/sysv/consts/sig.h"
|
|
|
|
#include "libc/sysv/errfuns.h"
|
|
|
|
|
|
|
|
union metasigaction {
|
|
|
|
struct sigaction cosmo;
|
2021-02-04 03:35:29 +00:00
|
|
|
struct sigaction_linux linux;
|
|
|
|
struct sigaction_freebsd freebsd;
|
|
|
|
struct sigaction_openbsd openbsd;
|
2021-02-05 17:44:54 +00:00
|
|
|
struct sigaction_netbsd netbsd;
|
2021-02-04 03:35:29 +00:00
|
|
|
struct sigaction_xnu_in xnu_in;
|
|
|
|
struct sigaction_xnu_out xnu_out;
|
2020-06-15 14:18:57 +00:00
|
|
|
};
|
|
|
|
|
2021-02-02 16:14:45 +00:00
|
|
|
#ifndef SWITCHEROO
|
2020-06-15 14:18:57 +00:00
|
|
|
#define SWITCHEROO(S1, S2, A, B, C, D) \
|
|
|
|
do { \
|
|
|
|
autotype((S2).A) a = (typeof((S2).A))(S1).A; \
|
|
|
|
autotype((S2).B) b = (typeof((S2).B))(S1).B; \
|
|
|
|
autotype((S2).C) c = (typeof((S2).C))(S1).C; \
|
|
|
|
typeof((S2).D) d; \
|
|
|
|
memset(&d, 0, sizeof(d)); \
|
|
|
|
memcpy(&d, &((S1).D), MIN(sizeof(d), sizeof((S1).D))); \
|
|
|
|
(S2).A = a; \
|
|
|
|
(S2).B = b; \
|
|
|
|
(S2).C = c; \
|
|
|
|
memset(&((S2).D), 0, sizeof((S2).D)); \
|
|
|
|
memcpy(&((S2).D), &d, MIN(sizeof(d), sizeof((S2).D))); \
|
|
|
|
} while (0);
|
2021-02-02 16:14:45 +00:00
|
|
|
#endif
|
2020-06-15 14:18:57 +00:00
|
|
|
|
2021-02-05 17:44:54 +00:00
|
|
|
static void sigaction_cosmo2native(union metasigaction *sa) {
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!sa) return;
|
2020-11-25 16:19:00 +00:00
|
|
|
switch (__hostos) {
|
2020-06-15 14:18:57 +00:00
|
|
|
case LINUX:
|
|
|
|
SWITCHEROO(sa->cosmo, sa->linux, sa_handler, sa_flags, sa_restorer,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case XNU:
|
|
|
|
SWITCHEROO(sa->cosmo, sa->xnu_in, sa_handler, sa_flags, sa_restorer,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case FREEBSD:
|
|
|
|
SWITCHEROO(sa->cosmo, sa->freebsd, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case OPENBSD:
|
|
|
|
SWITCHEROO(sa->cosmo, sa->openbsd, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
2021-02-05 17:44:54 +00:00
|
|
|
case NETBSD:
|
|
|
|
SWITCHEROO(sa->cosmo, sa->netbsd, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
2020-06-15 14:18:57 +00:00
|
|
|
default:
|
2020-11-28 20:01:51 +00:00
|
|
|
break;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 17:44:54 +00:00
|
|
|
static void sigaction_native2cosmo(union metasigaction *sa) {
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!sa) return;
|
2020-11-25 16:19:00 +00:00
|
|
|
switch (__hostos) {
|
2020-06-15 14:18:57 +00:00
|
|
|
case LINUX:
|
|
|
|
SWITCHEROO(sa->linux, sa->cosmo, sa_handler, sa_flags, sa_restorer,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case XNU:
|
|
|
|
SWITCHEROO(sa->xnu_out, sa->cosmo, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case FREEBSD:
|
|
|
|
SWITCHEROO(sa->freebsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
|
|
|
case OPENBSD:
|
|
|
|
SWITCHEROO(sa->openbsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
2021-02-05 17:44:54 +00:00
|
|
|
case NETBSD:
|
|
|
|
SWITCHEROO(sa->netbsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
|
|
|
|
sa_mask);
|
|
|
|
break;
|
2020-06-15 14:18:57 +00:00
|
|
|
default:
|
2020-11-28 20:01:51 +00:00
|
|
|
break;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Installs handler for kernel interrupt, e.g.:
|
|
|
|
*
|
2020-12-26 10:09:07 +00:00
|
|
|
* void GotCtrlC(int sig, siginfo_t *si, ucontext_t *ctx);
|
|
|
|
* struct sigaction sa = {.sa_sigaction = GotCtrlC,
|
|
|
|
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
|
|
|
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
2020-06-15 14:18:57 +00:00
|
|
|
*
|
|
|
|
* @see xsigaction() for a much better api
|
|
|
|
* @asyncsignalsafe
|
2021-02-03 06:17:53 +00:00
|
|
|
* @vforksafe
|
2020-06-15 14:18:57 +00:00
|
|
|
*/
|
|
|
|
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
2021-02-05 17:44:54 +00:00
|
|
|
int64_t arg4, arg5;
|
2020-06-15 14:18:57 +00:00
|
|
|
int rc, rva, oldrva;
|
|
|
|
struct sigaction *ap, copy;
|
2021-02-08 17:19:00 +00:00
|
|
|
assert(sizeof(struct sigaction) > sizeof(struct sigaction_linux) &&
|
|
|
|
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_in) &&
|
|
|
|
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_out) &&
|
|
|
|
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
|
|
|
|
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
|
|
|
|
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd));
|
2021-02-24 04:23:19 +00:00
|
|
|
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
|
2021-02-03 14:22:51 +00:00
|
|
|
if (!(0 < sig && sig < NSIG)) return einval();
|
|
|
|
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!act) {
|
|
|
|
rva = (int32_t)(intptr_t)SIG_DFL;
|
|
|
|
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
|
|
|
rva = (int)(intptr_t)act->sa_handler;
|
|
|
|
} else if ((intptr_t)act->sa_handler >= (intptr_t)&_base + kSigactionMinRva &&
|
|
|
|
(intptr_t)act->sa_handler < (intptr_t)&_base + INT_MAX) {
|
|
|
|
rva = (int)((uintptr_t)act->sa_handler - (uintptr_t)&_base);
|
|
|
|
} else {
|
|
|
|
return efault();
|
|
|
|
}
|
2021-02-03 14:22:51 +00:00
|
|
|
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
|
|
|
return einval();
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!IsWindows()) {
|
2021-02-05 17:44:54 +00:00
|
|
|
if (act) {
|
|
|
|
memcpy(©, act, sizeof(copy));
|
|
|
|
ap = ©
|
|
|
|
if (IsXnu()) {
|
|
|
|
ap->sa_restorer = (void *)&__xnutrampoline;
|
|
|
|
ap->sa_handler = (void *)&__xnutrampoline;
|
|
|
|
} else if (IsLinux()) {
|
|
|
|
if (!(ap->sa_flags & SA_RESTORER)) {
|
|
|
|
ap->sa_flags |= SA_RESTORER;
|
|
|
|
ap->sa_restorer = &__restore_rt;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
2021-02-05 17:44:54 +00:00
|
|
|
} else if (IsNetbsd()) {
|
|
|
|
ap->sa_sigaction = act->sa_sigaction;
|
|
|
|
} else if (rva >= kSigactionMinRva) {
|
|
|
|
ap->sa_sigaction = (sigaction_f)__sigenter;
|
|
|
|
}
|
|
|
|
sigaction_cosmo2native((union metasigaction *)ap);
|
|
|
|
} else {
|
|
|
|
ap = NULL;
|
|
|
|
}
|
|
|
|
if (IsXnu()) {
|
|
|
|
arg4 = (int64_t)(intptr_t)oldact; /* from go code */
|
|
|
|
arg5 = 0;
|
|
|
|
} else if (IsNetbsd()) {
|
|
|
|
if (ap) {
|
|
|
|
arg4 = (int64_t)(intptr_t)&__restore_rt_netbsd;
|
|
|
|
arg5 = 2; /* netbsd/lib/libc/arch/x86_64/sys/__sigtramp2.S */
|
2021-01-17 01:52:15 +00:00
|
|
|
} else {
|
2021-02-05 17:44:54 +00:00
|
|
|
arg4 = 0;
|
|
|
|
arg5 = 0; /* netbsd/lib/libc/arch/x86_64/sys/__sigtramp2.S */
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-02-05 17:44:54 +00:00
|
|
|
arg4 = 8; /* or linux whines */
|
|
|
|
arg5 = 0;
|
|
|
|
}
|
|
|
|
if ((rc = sys_sigaction(sig, ap, oldact, arg4, arg5)) != -1) {
|
|
|
|
sigaction_native2cosmo((union metasigaction *)oldact);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (oldact) {
|
|
|
|
memset(oldact, 0, sizeof(*oldact));
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
}
|
2021-02-03 14:22:51 +00:00
|
|
|
if (rc != -1 && !__vforked) {
|
2020-06-15 14:18:57 +00:00
|
|
|
if (oldact) {
|
2021-01-28 23:49:15 +00:00
|
|
|
oldrva = __sighandrvas[sig];
|
2020-08-25 11:23:25 +00:00
|
|
|
oldact->sa_sigaction = (sigaction_f)(
|
|
|
|
oldrva < kSigactionMinRva ? oldrva : (intptr_t)&_base + oldrva);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
if (act) {
|
2021-01-28 23:49:15 +00:00
|
|
|
__sighandrvas[sig] = rva;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|