Introduce sigtimedwait() and sigwaitinfo()

This change also invents sigcountset() and strsignal_r() and improves
the quality of siginfo_t handling.
This commit is contained in:
Justine Tunney 2022-10-10 07:36:07 -07:00
parent 7ae556463a
commit 467a332e38
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
41 changed files with 887 additions and 345 deletions

View file

@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use asan because:
# siginfo_t memory is owned by kernels
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
OVERRIDE_COPTS += \
-ffreestanding \
-fno-sanitize=address
# we can't use asan because:
# ucontext_t memory is owned by xnu kernel
o/$(MODE)/libc/calls/sigenter-xnu.o: private \

View file

@ -556,6 +556,7 @@ static const uint16_t kPledgeStdio[] = {
__NR_linux_prlimit | STDIO, //
__NR_linux_sched_getaffinity, //
__NR_linux_sched_setaffinity, //
__NR_linux_sigtimedwait, //
};
static const uint16_t kPledgeFlock[] = {

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-freebsd.internal.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/ucontext-freebsd.internal.h"
#include "libc/calls/ucontext.h"
@ -75,16 +76,7 @@ privileged void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
g.uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
g.uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
__repmovsb(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
g.si.si_signo = freebsdinfo->si_signo;
g.si.si_errno = freebsdinfo->si_errno;
g.si.si_code = freebsdinfo->si_code;
if (freebsdinfo->si_pid) {
g.si.si_pid = freebsdinfo->si_pid;
g.si.si_uid = freebsdinfo->si_uid;
} else {
g.si.si_addr = (void *)freebsdinfo->si_addr;
}
g.si.si_value = freebsdinfo->si_value;
__siginfo2cosmo(&g.si, (void *)freebsdinfo);
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
ctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;

View file

@ -21,6 +21,7 @@
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo-netbsd.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/ucontext-netbsd.internal.h"
@ -43,13 +44,7 @@ privileged void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
__repstosb(&uc, 0, sizeof(uc));
__repstosb(&si2, 0, sizeof(si2));
si2.si_signo = si->si_signo;
si2.si_code = si->si_code;
si2.si_errno = si->si_errno;
si2.si_pid = si->si_pid;
si2.si_uid = si->si_uid;
si2.si_value = si->si_value;
__siginfo2cosmo(&si2, (void *)si);
uc.uc_mcontext.fpregs = &uc.__fpustate;
uc.uc_flags = ctx->uc_flags;
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;

View file

@ -21,6 +21,7 @@
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo-openbsd.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/ucontext-openbsd.internal.h"
@ -44,17 +45,8 @@ privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
if (~flags & SA_SIGINFO) {
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
__repstosb(&g, 0, sizeof(g));
g.si.si_signo = openbsdinfo->si_signo;
g.si.si_code = openbsdinfo->si_code;
g.si.si_errno = openbsdinfo->si_errno;
if (openbsdinfo->si_pid) {
g.si.si_pid = openbsdinfo->si_pid;
g.si.si_uid = openbsdinfo->si_uid;
} else {
g.si.si_addr = (void *)openbsdinfo->si_addr;
}
g.si.si_value = openbsdinfo->si_value;
__repstosb(&g.uc, 0, sizeof(g.uc));
__siginfo2cosmo(&g.si, (void *)openbsdinfo);
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
__repmovsb(&g.uc.uc_sigmask, &ctx->sc_mask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));

View file

@ -21,6 +21,7 @@
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
@ -492,16 +493,7 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
}
}
if (xnuinfo) {
g.si.si_signo = xnuinfo->si_signo;
g.si.si_errno = xnuinfo->si_errno;
g.si.si_code = xnuinfo->si_code;
if (xnuinfo->si_pid) {
g.si.si_pid = xnuinfo->si_pid;
g.si.si_uid = xnuinfo->si_uid;
} else {
g.si.si_addr = (void *)xnuinfo->si_addr;
}
g.si.si_value = xnuinfo->si_value;
__siginfo2cosmo(&g.si, (void *)xnuinfo);
}
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
if (xnuctx) {

106
libc/calls/siginfo2cosmo.c Normal file
View file

@ -0,0 +1,106 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/dce.h"
#include "libc/sysv/consts/sig.h"
privileged void __siginfo2cosmo(struct siginfo *si,
const union siginfo_meta *m) {
void *si_addr;
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
int32_t si_uid;
int32_t si_status;
int32_t si_timerid;
int32_t si_overrun;
union sigval si_value;
if (IsLinux()) {
*si = m->linux;
return;
} else if (IsFreebsd()) {
si_signo = m->freebsd.si_signo;
si_errno = m->freebsd.si_errno;
si_code = m->freebsd.si_code;
si_pid = m->freebsd.si_pid;
si_uid = m->freebsd.si_uid;
si_status = m->freebsd.si_status;
si_timerid = m->freebsd.si_timerid;
si_overrun = m->freebsd.si_overrun;
si_addr = m->freebsd.si_addr;
si_value = m->freebsd.si_value;
} else if (IsXnu()) {
si_signo = m->xnu.si_signo;
si_errno = m->xnu.si_errno;
si_code = m->xnu.si_code;
si_pid = m->xnu.si_pid;
si_uid = m->xnu.si_uid;
si_status = m->xnu.si_status;
si_timerid = 0;
si_overrun = 0;
si_addr = m->xnu.si_addr;
si_value = m->xnu.si_value;
} else if (IsOpenbsd()) {
si_signo = m->openbsd.si_signo;
si_errno = m->openbsd.si_errno;
si_code = m->openbsd.si_code;
si_pid = m->openbsd.si_pid;
si_uid = m->openbsd.si_uid;
si_status = m->openbsd.si_status;
si_timerid = 0;
si_overrun = 0;
si_addr = m->openbsd.si_addr;
si_value = m->openbsd.si_value;
} else if (IsNetbsd()) {
si_signo = m->netbsd.si_signo;
si_errno = m->netbsd.si_errno;
si_code = m->netbsd.si_code;
si_pid = m->netbsd.si_pid;
si_uid = m->netbsd.si_uid;
si_status = m->netbsd.si_status;
si_timerid = 0;
si_overrun = 0;
si_addr = m->netbsd.si_addr;
si_value = m->netbsd.si_value;
} else {
notpossible;
}
*si = (struct siginfo){0};
si->si_signo = si_signo;
si->si_errno = si_errno;
si->si_code = si_code;
si->si_value = si_value;
if (si_signo == SIGILL || //
si_signo == SIGFPE || //
si_signo == SIGSEGV || //
si_signo == SIGBUS || //
si_signo == SIGTRAP) {
si->si_addr = si_addr;
} else if (si_signo == SIGALRM) {
si->si_timerid = si_timerid;
si->si_overrun = si_overrun;
} else {
si->si_pid = si_pid;
si->si_uid = si_uid;
}
}

View file

@ -17,37 +17,44 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Determines the blocked pending signals
*
* @param pending is where the bitset of pending signals is returned,
* may not be NULL.
* @return -1 w/ EFAULT
* which may not be null
* @return 0 on success, or -1 w/ errno
* @raise EFAULT if `pending` points to invalid memory
* @asyncsignalsafe
*/
int sigpending(sigset_t *pending) {
int rc;
if (IsAsan() && !__asan_is_valid(pending, sizeof(*pending))) {
if (!pending || (IsAsan() && !__asan_is_valid(pending, sizeof(*pending)))) {
rc = efault();
} else if (IsLinux() || IsNetbsd() || IsOpenbsd() || IsFreebsd() || IsXnu()) {
// 128 signals on NetBSD and FreeBSD, 64 on Linux, 32 on OpenBSD and XNU
rc = sys_sigpending(pending, 8);
// 128 signals on NetBSD and FreeBSD, 64 on Linux, 32 on OpenBSD and XNU.
// OpenBSD passes signal sets in words rather than pointers
if (IsOpenbsd()) {
pending->__bits[0] = (unsigned)rc;
rc = 0;
} else if (IsXnu()) {
pending->__bits[0] &= 0xFFFFFFFF;
}
if (IsLinux() || IsOpenbsd() || IsXnu()) {
pending->__bits[1] = 0;
// only modify memory on success
if (!rc) {
// clear unsupported bits
if (IsXnu()) {
pending->__bits[0] &= 0xFFFFFFFF;
}
if (IsLinux() || IsOpenbsd() || IsXnu()) {
pending->__bits[1] = 0;
}
}
} else if (IsWindows()) {
sigemptyset(pending);

75
libc/calls/sigtimedwait.c Normal file
View file

@ -0,0 +1,75 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/sigtimedwait.h"
#include "libc/calls/sigtimedwait.internal.h"
#include "libc/calls/struct/siginfo.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for signal synchronously, w/ timeout.
*
* @param set is signals for which we'll be waiting
* @param info if not null shall receive info about signal
* @param timeout is relative deadline and null means wait forever
* @return signal number on success, or -1 w/ errno
* @raise EINTR if an asynchronous signal was delivered instead
* @raise EINVAL if nanoseconds parameter was out of range
* @raise EAGAIN if deadline expired
* @raise ENOSYS on Windows, XNU, OpenBSD, Metal
* @raise EFAULT if invalid memory was supplied
*/
int sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec *timeout) {
int rc;
char strsig[15];
struct timespec ts;
union siginfo_meta si = {0};
if (IsAsan() && (!__asan_is_valid(set, sizeof(*set)) ||
(info && !__asan_is_valid(info, sizeof(*info))) ||
(timeout && !__asan_is_valid_timespec(timeout)))) {
rc = efault();
} else if (IsLinux() || IsFreebsd() || IsNetbsd()) {
if (timeout) {
// 1. Linux needs its size parameter
// 2. NetBSD modifies timeout argument
ts = *timeout;
rc = sys_sigtimedwait(set, &si, &ts, 8);
} else {
rc = sys_sigtimedwait(set, &si, 0, 8);
}
if (rc != -1 && info) {
__siginfo2cosmo(info, &si);
}
} else {
rc = enosys();
}
STRACE("sigtimedwait(%s, [%s], %s) → %s% m", DescribeSigset(0, set),
DescribeSiginfo(rc, info), DescribeTimespec(0, timeout),
strsignal_r(rc, strsig));
return rc;
}

14
libc/calls/sigtimedwait.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_H_
#define COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_H_
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int sigtimedwait(const sigset_t *, siginfo_t *, const struct timespec *);
int sigwaitinfo(const sigset_t *, siginfo_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_H_ */

View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_INTERNAL_H_
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int sys_sigtimedwait(const sigset_t *, union siginfo_meta *,
const struct timespec *, size_t) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGTIMEDWAIT_INTERNAL_H_ */

33
libc/calls/sigwaitinfo.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/calls/sigtimedwait.h"
/**
* Waits for signal synchronously.
*
* @param set is signals for which we'll be waiting
* @param info if not null shall receive info about signal
* @return signal number on success, or -1 w/ errno
* @raise EINTR if an asynchronous signal was delivered instead
* @raise ENOSYS on OpenBSD, XNU, and Windows
* @see sigtimedwait()
*/
int sigwaitinfo(const sigset_t *mask, siginfo_t *si) {
return sigtimedwait(mask, si, 0);
}

View file

@ -0,0 +1,23 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_META_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_META_INTERNAL_H_
#include "libc/calls/struct/siginfo-freebsd.internal.h"
#include "libc/calls/struct/siginfo-netbsd.internal.h"
#include "libc/calls/struct/siginfo-openbsd.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
union siginfo_meta {
struct siginfo linux;
struct siginfo_xnu xnu;
struct siginfo_freebsd freebsd;
struct siginfo_openbsd openbsd;
struct siginfo_netbsd netbsd;
};
void __siginfo2cosmo(struct siginfo *, const union siginfo_meta *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_META_INTERNAL_H_ */

View file

@ -12,11 +12,13 @@ struct siginfo {
struct {
union {
struct {
/* signals sent by kill() and sigqueue() set these */
int32_t si_pid;
uint32_t si_uid;
};
struct {
int32_t si_timerid; /* SIGALRM */
/* SIGALRM sets these */
int32_t si_timerid;
int32_t si_overrun;
};
};

View file

@ -3,6 +3,7 @@
#include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/mem/alloca.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -10,6 +11,9 @@ int sys_sigqueueinfo(int, const siginfo_t *) hidden;
void __sigenter_xnu(void *, int, int, struct siginfo_xnu *,
struct __darwin_ucontext *) hidden;
const char *DescribeSiginfo(char[300], int, const siginfo_t *);
#define DescribeSiginfo(x, y) DescribeSiginfo(alloca(300), x, y)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_INTERNAL_H_ */

View file

@ -13,11 +13,12 @@ int sigemptyset(sigset_t *) paramsnonnull();
int sigfillset(sigset_t *) paramsnonnull();
int sigandset(sigset_t *, const sigset_t *, const sigset_t *) paramsnonnull();
int sigorset(sigset_t *, const sigset_t *, const sigset_t *) paramsnonnull();
int sigisemptyset(const sigset_t *) paramsnonnull();
int sigisemptyset(const sigset_t *) paramsnonnull() nosideeffect;
int sigismember(const sigset_t *, int) paramsnonnull() nosideeffect;
int sigcountset(const sigset_t *) paramsnonnull() nosideeffect;
int sigprocmask(int, const sigset_t *, sigset_t *);
int sigsuspend(const sigset_t *);
int sigpending(sigset_t *) paramsnonnull() nosideeffect;
int sigpending(sigset_t *);
int pthread_sigmask(int, const sigset_t *, sigset_t *);
COSMOPOLITAN_C_END_

View file

@ -0,0 +1,28 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/str/str.h"
const char *(DescribeErrno)(char buf[12], int x) {
const char *s;
if ((s = _strerrno(x))) return s;
FormatInt32(buf, x);
return buf;
}

View file

@ -16,6 +16,7 @@ const char *DescribeArchPrctlCode(char[12], int);
const char *DescribeCapability(char[20], int);
const char *DescribeClockName(char[32], int);
const char *DescribeDirfd(char[12], int);
const char *DescribeErrno(char[12], int);
const char *DescribeErrnoResult(char[12], int);
const char *DescribeFrame(char[32], int);
const char *DescribeFutexOp(char[64], int);
@ -50,6 +51,7 @@ const char *DescribeRemapFlags(char[48], int);
const char *DescribeRlimitName(char[20], int);
const char *DescribeSchedPolicy(char[48], int);
const char *DescribeSeccompOperation(int);
const char *DescribeSiCode(char[17], int, int);
const char *DescribeSleepFlags(char[16], int);
const char *DescribeSockLevel(char[12], int);
const char *DescribeSockOptname(char[32], int, int);
@ -63,6 +65,7 @@ const char *DescribeWhence(char[12], int);
#define DescribeCapability(x) DescribeCapability(alloca(20), x)
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
#define DescribeErrno(x) DescribeErrno(alloca(12), x)
#define DescribeErrnoResult(x) DescribeErrnoResult(alloca(12), x)
#define DescribeFrame(x) DescribeFrame(alloca(32), x)
#define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x)
@ -94,6 +97,7 @@ const char *DescribeWhence(char[12], int);
#define DescribeRemapFlags(x) DescribeRemapFlags(alloca(48), x)
#define DescribeRlimitName(rl) DescribeRlimitName(alloca(20), rl)
#define DescribeSchedPolicy(x) DescribeSchedPolicy(alloca(48), x)
#define DescribeSiCode(x, y) DescribeSiCode(alloca(17), x, y)
#define DescribeSleepFlags(x) DescribeSleepFlags(alloca(16), x)
#define DescribeSockLevel(x) DescribeSockLevel(alloca(12), x)
#define DescribeSockOptname(x, y) DescribeSockOptname(alloca(32), x, y)

View file

@ -0,0 +1,167 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
static bool IsSiUser(int si_code) {
if (!IsOpenbsd()) {
return si_code == SI_USER;
} else {
return si_code <= 0;
}
}
static void NameIt(char p[17], const char *s, int si_code) {
p = stpcpy(p, s);
FormatInt32(p, si_code);
}
/**
* Returns symbolic name for siginfo::si_code value.
*/
const char *(DescribeSiCode)(char b[17], int sig, int si_code) {
NameIt(b, "SI_", si_code);
if (si_code == SI_QUEUE) {
strcpy(b + 3, "QUEUE"); /* sent by sigqueue(2) */
} else if (si_code == SI_TIMER) {
strcpy(b + 3, "TIMER"); /* sent by setitimer(2) or clock_settime(2) */
} else if (si_code == SI_TKILL) {
strcpy(b + 3, "TKILL"); /* sent by tkill(2), etc. */
} else if (si_code == SI_MESGQ) {
strcpy(b + 3, "MESGQ"); /* sent by mq_notify(2) */
} else if (si_code == SI_MESGQ) {
strcpy(b + 3, "MESGQ"); /* aio completion */
} else if (si_code == SI_ASYNCNL) {
strcpy(b + 3, "ASYNCNL"); /* aio completion for dns; the horror */
} else if (si_code == SI_NOINFO) {
strcpy(b + 3, "NOINFO"); /* no signal specific info available */
} else if (si_code == SI_KERNEL) {
strcpy(b + 3, "KERNEL"); /* sent by kernel */
} else if (IsSiUser(si_code)) {
strcpy(b + 3, "USER"); /* sent by kill(2) i.e. from userspace */
} else if (sig == SIGCHLD) {
NameIt(b, "CLD_", si_code);
if (si_code == CLD_EXITED) {
strcpy(b + 4, "EXITED"); /* child exited */
} else if (si_code == CLD_KILLED) {
strcpy(b + 4, "KILLED"); /* child terminated w/o core */
} else if (si_code == CLD_DUMPED) {
strcpy(b + 4, "DUMPED"); /* child terminated w/ core */
} else if (si_code == CLD_TRAPPED) {
strcpy(b + 4, "TRAPPED"); /* traced child trapped */
} else if (si_code == CLD_STOPPED) {
strcpy(b + 4, "STOPPED"); /* child stopped */
} else if (si_code == CLD_CONTINUED) {
strcpy(b + 4, "CONTINUED"); /* stopped child continued */
}
} else if (sig == SIGTRAP) {
NameIt(b, "TRAP_", si_code);
if (si_code == TRAP_BRKPT) {
strcpy(b + 5, "BRKPT"); /* process breakpoint */
} else if (si_code == TRAP_TRACE) {
strcpy(b + 5, "TRACE"); /* process trace trap */
}
} else if (sig == SIGSEGV) {
NameIt(b, "SEGV_", si_code);
if (si_code == SEGV_MAPERR) {
strcpy(b + 5, "MAPERR"); /* address not mapped to object */
} else if (si_code == SEGV_ACCERR) {
strcpy(b + 5, "ACCERR"); /* invalid permissions for mapped object */
} else if (si_code == SEGV_PKUERR) {
strcpy(b + 5, "PKUERR"); /* FreeBSD: x86: PKU violation */
}
} else if (sig == SIGFPE) {
NameIt(b, "FPE_???", si_code);
if (si_code == FPE_INTDIV) {
strcpy(b + 4, "INTDIV"); /* integer divide by zero */
} else if (si_code == FPE_INTOVF) {
strcpy(b + 4, "INTOVF"); /* integer overflow */
} else if (si_code == FPE_FLTDIV) {
strcpy(b + 4, "FLTDIV"); /* floating point divide by zero */
} else if (si_code == FPE_FLTOVF) {
strcpy(b + 4, "FLTOVF"); /* floating point overflow */
} else if (si_code == FPE_FLTUND) {
strcpy(b + 4, "FLTUND"); /* floating point underflow */
} else if (si_code == FPE_FLTRES) {
strcpy(b + 4, "FLTRES"); /* floating point inexact */
} else if (si_code == FPE_FLTINV) {
strcpy(b + 4, "FLTINV"); /* invalid floating point operation */
} else if (si_code == FPE_FLTSUB) {
strcpy(b + 4, "FLTSUB"); /* subscript out of range */
}
} else if (sig == SIGILL) {
NameIt(b, "ILL_", si_code);
if (si_code == ILL_ILLOPC) {
strcpy(b + 4, "ILLOPC"); /* illegal opcode */
} else if (si_code == ILL_ILLOPN) {
strcpy(b + 4, "ILLOPN"); /* illegal operand */
} else if (si_code == ILL_ILLADR) {
strcpy(b + 4, "ILLADR"); /* illegal addressing mode */
} else if (si_code == ILL_ILLTRP) {
strcpy(b + 4, "ILLTRP"); /* illegal trap */
} else if (si_code == ILL_PRVOPC) {
strcpy(b + 4, "PRVOPC"); /* privileged opcode */
} else if (si_code == ILL_PRVREG) {
strcpy(b + 4, "PRVREG"); /* privileged register */
} else if (si_code == ILL_COPROC) {
strcpy(b + 4, "COPROC"); /* coprocessor error */
} else if (si_code == ILL_BADSTK) {
strcpy(b + 4, "BADSTK"); /* internal stack error */
}
} else if (sig == SIGBUS) {
NameIt(b, "BUS_", si_code);
if (si_code == BUS_ADRALN) {
strcpy(b + 4, "ADRALN"); /* invalid address alignment */
} else if (si_code == BUS_ADRERR) {
strcpy(b + 4, "ADRERR"); /* non-existent physical address */
} else if (si_code == BUS_OBJERR) {
strcpy(b + 4, "OBJERR"); /* object specific hardware error */
} else if (si_code == BUS_OOMERR) {
strcpy(b + 4, "OOMERR"); /* FreeBSD */
} else if (si_code == BUS_MCEERR_AR) {
strcpy(b + 4, "MCEERR_AR"); /* Linux 2.6.32+ */
} else if (si_code == BUS_MCEERR_AO) {
strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */
}
} else if (sig == SIGIO) {
NameIt(b, "POLL_", si_code);
if (si_code == POLL_IN) {
strcpy(b + 5, "IN"); /* data input available */
} else if (si_code == POLL_OUT) {
strcpy(b + 5, "OUT"); /* output buffer available */
} else if (si_code == POLL_MSG) {
strcpy(b + 5, "MSG"); /* input message available */
} else if (si_code == POLL_ERR) {
strcpy(b + 5, "ERR"); /* i/o error */
} else if (si_code == POLL_PRI) {
strcpy(b + 5, "PRI"); /* high priority input available */
} else if (si_code == POLL_HUP) {
strcpy(b + 5, "HUP"); /* device disconnected */
}
} else if (sig == SIGSYS) {
NameIt(b, "SYS_", si_code);
if (si_code == SYS_SECCOMP) {
strcpy(b + 4, "SECCOMP");
}
}
return b;
}

View file

@ -0,0 +1,84 @@
/*-*- 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 2021 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/siginfo.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/weaken.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
#define N 300
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
const char *(DescribeSiginfo)(char buf[N], int rc, const siginfo_t *si) {
int i = 0;
if (rc == -1) return "n/a";
if (!si) return "NULL";
if ((!IsAsan() && kisdangerous(si)) ||
(IsAsan() && !__asan_is_valid(si, sizeof(*si)))) {
ksnprintf(buf, N, "%p", si);
return buf;
}
append("{.si_signo=%s, si_code=%s", strsignal(si->si_signo),
DescribeSiCode(si->si_signo, si->si_code));
if (si->si_errno) {
append(", .si_errno=%s", DescribeErrno(si->si_errno));
}
if (si->si_signo == SIGILL || //
si->si_signo == SIGFPE || //
si->si_signo == SIGSEGV || //
si->si_signo == SIGBUS || //
si->si_signo == SIGTRAP) {
append(", .si_addr=%p, .si_addr_lsb=%d, .si_pkey=%u", si->si_addr,
si->si_addr_lsb, si->si_pkey);
} else if (si->si_signo == SIGALRM) {
append(", .si_timerid=%d, .si_overrun=%d", si->si_timerid, si->si_overrun);
} else {
if (si->si_pid) {
append(", .si_pid=%d", si->si_pid);
}
if (si->si_uid) {
append(", .si_uid=%d", si->si_uid);
}
}
if (si->si_status) {
append(", .si_status=%d", si->si_status);
}
if (si->si_utime) {
append(", .si_utime=%d", si->si_utime);
}
if (si->si_stime) {
append(", .si_stime=%d", si->si_stime);
}
append("}");
return buf;
}

View file

@ -26,9 +26,11 @@
#define N 128
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
bool gotsome;
int i, sig;
bool gotsome;
sigset_t sigset;
if (rc == -1) return "n/a";
@ -43,22 +45,22 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
sigset = *ss;
gotsome = false;
if (popcnt(sigset.__bits[0] & 0xffffffff) > 16) {
i += ksnprintf(buf + i, N - i, "~");
append("~");
sigset.__bits[0] = ~sigset.__bits[0];
sigset.__bits[1] = ~sigset.__bits[1];
}
i += ksnprintf(buf + i, N - i, "{");
append("{");
for (sig = 1; sig < 32; ++sig) {
if (sigismember(&sigset, sig)) {
if (gotsome) {
i += ksnprintf(buf + i, N - i, ",");
append(",");
} else {
gotsome = true;
}
i += ksnprintf(buf + i, N - i, "%s", strsignal(sig) + 3);
append("%s", strsignal(sig) + 3);
}
}
i += ksnprintf(buf + i, N - i, "}");
append("}");
return buf;
}

View file

@ -22,67 +22,64 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
const char *(DescribeStat)(char buf[300], int rc, const struct stat *st) {
int i, n;
#define N 300
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
const char *(DescribeStat)(char buf[N], int rc, const struct stat *st) {
int i = 0;
if (rc == -1) return "n/a";
if (!st) return "NULL";
if ((!IsAsan() && kisdangerous(st)) ||
(IsAsan() && !__asan_is_valid(st, sizeof(*st)))) {
ksnprintf(buf, 300, "%p", st);
ksnprintf(buf, N, "%p", st);
return buf;
}
i = 0;
n = 300;
i += ksnprintf(buf + i, n - i, "{.st_%s=%'ld", "size", st->st_size);
append("{.st_%s=%'ld", "size", st->st_size);
if (st->st_blocks) {
i +=
ksnprintf(buf + i, n - i, ", .st_blocks=%'lu/512", st->st_blocks * 512);
append(", .st_blocks=%'lu/512", st->st_blocks * 512);
}
if (st->st_mode) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%#o", "mode", st->st_mode);
append(", .st_%s=%#o", "mode", st->st_mode);
}
if (st->st_nlink != 1) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "nlink", st->st_nlink);
append(", .st_%s=%'lu", "nlink", st->st_nlink);
}
if (st->st_uid) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "uid", st->st_uid);
append(", .st_%s=%lu", "uid", st->st_uid);
}
if (st->st_gid) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "gid", st->st_gid);
append(", .st_%s=%lu", "gid", st->st_gid);
}
if (st->st_ino) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "ino", st->st_ino);
append(", .st_%s=%lu", "ino", st->st_ino);
}
if (st->st_gen) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "gen", st->st_gen);
append(", .st_%s=%'lu", "gen", st->st_gen);
}
if (st->st_flags) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lx", "flags", st->st_flags);
append(", .st_%s=%lx", "flags", st->st_flags);
}
if (st->st_rdev) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "rdev", st->st_rdev);
append(", .st_%s=%'lu", "rdev", st->st_rdev);
}
if (st->st_blksize != PAGESIZE) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "blksize", st->st_blksize);
append(", .st_%s=%'lu", "blksize", st->st_blksize);
}
if (n - i >= 2) {
buf[i + 0] = '}';
buf[i + 1] = 0;
}
append("}");
return buf;
}

View file

@ -24,8 +24,12 @@
#include "libc/intrin/kprintf.h"
#include "libc/sysv/consts/st.h"
const char *(DescribeStatfs)(char buf[300], int rc, const struct statfs *f) {
int i, n;
#define N 300
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
const char *(DescribeStatfs)(char buf[N], int rc, const struct statfs *f) {
int i = 0;
char ibuf[21];
int64_t flags;
@ -33,90 +37,82 @@ const char *(DescribeStatfs)(char buf[300], int rc, const struct statfs *f) {
if (!f) return "NULL";
if ((!IsAsan() && kisdangerous(f)) ||
(IsAsan() && !__asan_is_valid(f, sizeof(*f)))) {
ksnprintf(buf, 300, "%p", f);
ksnprintf(buf, N, "%p", f);
return buf;
}
i = 0;
n = 300;
i += ksnprintf(buf + i, n - i, "{.f_type=%#lx /* %s */", f->f_type,
f->f_fstypename);
append("{.f_type=%#lx /* %s */", f->f_type, f->f_fstypename);
sizefmt(ibuf, f->f_bsize, 1024);
i += ksnprintf(buf + i, n - i, ", .f_%s=%sb", "bsize", ibuf);
append(", .f_%s=%sb", "bsize", ibuf);
sizefmt(ibuf, f->f_blocks * f->f_bsize, 1024);
i += ksnprintf(buf + i, n - i, ", .f_%s=%sb", "blocks", ibuf);
append(", .f_%s=%sb", "blocks", ibuf);
sizefmt(ibuf, f->f_bfree * f->f_bsize, 1024);
i += ksnprintf(buf + i, n - i, ", .f_%s=%sb", "bfree", ibuf);
append(", .f_%s=%sb", "bfree", ibuf);
sizefmt(ibuf, f->f_bavail * f->f_bsize, 1024);
i += ksnprintf(buf + i, n - i, ", .f_%s=%sb", "bavail", ibuf);
append(", .f_%s=%sb", "bavail", ibuf);
i += ksnprintf(buf + i, n - i, ", .f_%s=%'zu", "files", f->f_files);
i += ksnprintf(buf + i, n - i, ", .f_%s=%'zu", "ffree", f->f_ffree);
i += ksnprintf(buf + i, n - i, ", .f_fsid=%#lx", f->f_fsid);
i += ksnprintf(buf + i, n - i, ", .f_%s=%'zu", "namelen", f->f_namelen);
i += ksnprintf(buf + i, n - i, ", .f_%s=%d", "owner", f->f_owner);
append(", .f_%s=%'zu", "files", f->f_files);
append(", .f_%s=%'zu", "ffree", f->f_ffree);
append(", .f_fsid=%#lx", f->f_fsid);
append(", .f_%s=%'zu", "namelen", f->f_namelen);
append(", .f_%s=%d", "owner", f->f_owner);
flags = f->f_flags;
i += ksnprintf(buf + i, n - i, ", .f_flags=");
append(", .f_flags=");
if (ST_RDONLY && (flags & ST_RDONLY)) {
i += ksnprintf(buf + i, n - i, "ST_RDONLY|");
append("ST_RDONLY|");
flags &= ~ST_RDONLY;
}
if (ST_NOSUID && (flags & ST_NOSUID)) {
i += ksnprintf(buf + i, n - i, "ST_NOSUID|");
append("ST_NOSUID|");
flags &= ~ST_NOSUID;
}
if (ST_NODEV && (flags & ST_NODEV)) {
i += ksnprintf(buf + i, n - i, "ST_NODEV|");
append("ST_NODEV|");
flags &= ~ST_NODEV;
}
if (ST_NOEXEC && (flags & ST_NOEXEC)) {
i += ksnprintf(buf + i, n - i, "ST_NOEXEC|");
append("ST_NOEXEC|");
flags &= ~ST_NOEXEC;
}
if (ST_SYNCHRONOUS && (flags & ST_SYNCHRONOUS)) {
i += ksnprintf(buf + i, n - i, "ST_SYNCHRONOUS|");
append("ST_SYNCHRONOUS|");
flags &= ~ST_SYNCHRONOUS;
}
if (ST_MANDLOCK && (flags & ST_MANDLOCK)) {
i += ksnprintf(buf + i, n - i, "ST_MANDLOCK|");
append("ST_MANDLOCK|");
flags &= ~ST_MANDLOCK;
}
if (ST_WRITE && (flags & ST_WRITE)) {
i += ksnprintf(buf + i, n - i, "ST_WRITE|");
append("ST_WRITE|");
flags &= ~ST_WRITE;
}
if (ST_APPEND && (flags & ST_APPEND)) {
i += ksnprintf(buf + i, n - i, "ST_APPEND|");
append("ST_APPEND|");
flags &= ~ST_APPEND;
}
if (ST_IMMUTABLE && (flags & ST_IMMUTABLE)) {
i += ksnprintf(buf + i, n - i, "ST_IMMUTABLE|");
append("ST_IMMUTABLE|");
flags &= ~ST_IMMUTABLE;
}
if (ST_NOATIME && (flags & ST_NOATIME)) {
i += ksnprintf(buf + i, n - i, "ST_NOATIME|");
append("ST_NOATIME|");
flags &= ~ST_NOATIME;
}
if (ST_NODIRATIME && (flags & ST_NODIRATIME)) {
i += ksnprintf(buf + i, n - i, "ST_NODIRATIME|");
append("ST_NODIRATIME|");
flags &= ~ST_NODIRATIME;
}
if (ST_RELATIME && (flags & ST_RELATIME)) {
i += ksnprintf(buf + i, n - i, "ST_RELATIME|");
append("ST_RELATIME|");
flags &= ~ST_RELATIME;
}
i += ksnprintf(buf + i, n - i, "%#lx", flags);
if (n - i >= 2) {
buf[i + 0] = '}';
buf[i + 1] = 0;
}
append("%#lx}", flags);
return buf;
}

View file

@ -212,7 +212,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
if (!kistextpointer(fmt)) fmt = "!!WONTFMT";
p = b;
f = fmt;
e = p + n;
e = p + n; // assume if n was negative e < p will be the case
for (;;) {
for (;;) {
if (!(c = *f++) || c == '%') break;
@ -502,7 +502,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
case 'G':
x = va_arg(va, int);
if (_weaken(strsignal) && (s = _weaken(strsignal)(x))) {
if (_weaken(strsignal_r) && (s = _weaken(strsignal_r)(x, z))) {
goto FormatString;
} else {
goto FormatDecimal;

View file

@ -23,7 +23,7 @@
* Adds signal to set.
*
* @return 0 on success, or -1 w/ errno
* @raises EINVAL if `1 sig NSIG` isn't the case
* @raise EINVAL if `1 sig NSIG` isn't the case
* @asyncsignalsafe
*/
int sigaddset(sigset_t *set, int sig) {

35
libc/intrin/sigcountset.c Normal file
View file

@ -0,0 +1,35 @@
/*-*- 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
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.
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.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/popcnt.h"
#include "libc/macros.internal.h"
/**
* Returns population count of signal set.
*
* @return value greater than or equal to zero
* @asyncsignalsafe
*/
int sigcountset(const sigset_t *set) {
int r, i;
for (r = i = 0; i < ARRAYLEN(set->__bits); ++i) {
r += popcnt(set->__bits[i]);
}
return r;
}

View file

@ -16,52 +16,26 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/str/str.h"
static char g_strsignal[12];
static char g_strsignal[15];
/**
* Returns string describing signal code.
*
* This returns SIGZERO for 0 which is the empty value. Textual names
* should be available for signals 1 through 32. Signals in the range 33
* and 128 are returned as a `SIG%03d` string. Everything else is SIGWUT
* This returns `"0"` for 0 which is the empty value. Symbolic names
* should be available for signals 1 through 32. If the system supports
* real-time signals, they're returned as `SIGRTMIN+%d`. For all other
* 32-bit signed integer, a plain integer representation is returned.
*
* This function is thread safe when `sig` is a known signal magnum.
* Otherwise a pointer to static memory is returned which is unsafe.
*
* @param sig is signal number which should be in range 1 through 128
* @return pointer to static memory that mutates on subsequent calls
* @return string which is valid code describing signal
* @see strsignal_r() for better thread safety
* @see sigaction()
* @threadsafe
*/
char *strsignal(int sig) {
char *p;
const char *s;
if (!sig) return "0";
if ((s = GetMagnumStr(kSignalNames, sig))) return s;
p = g_strsignal;
p[0] = 'S';
p[1] = 'I';
p[2] = 'G';
p[3] = 0;
if (!sig) {
p[3] = 'Z';
p[4] = 'E';
p[5] = 'R';
p[6] = 'O';
p[7] = 0;
} else if (1 <= sig && sig <= 128) {
p[3] = '0' + sig / 100;
p[4] = '0' + sig / 10 % 10;
p[5] = '0' + sig % 10;
p[6] = 0;
} else {
p[3] = 'W';
p[4] = 'U';
p[5] = 'T';
p[6] = 0;
}
return g_strsignal;
return strsignal_r(sig, g_strsignal);
}

60
libc/intrin/strsignal_r.c Normal file
View file

@ -0,0 +1,60 @@
/*-*- 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
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.
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.
*/
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
/**
* Returns string describing signal code.
*
* This returns `"0"` for 0 which is the empty value. Symbolic names
* should be available for signals 1 through 32. If the system supports
* real-time signals, they're returned as `SIGRTMIN+%d`. For all other
* 32-bit signed integer, a plain integer representation is returned.
*
* @param sig is signal number which should be in range 1 through 128
* @param buf may be used to store output having at least 15 bytes
* @return pointer to .rodata string, or to `buf` after mutating
* @see sigaction()
* @threadsafe
*/
char *strsignal_r(int sig, char buf[hasatleast 15]) {
int i;
char *p;
const char *s;
if (!sig) return "0";
if ((s = GetMagnumStr(kSignalNames, sig))) return s;
if (SIGRTMIN <= sig && sig <= SIGRTMAX) {
sig -= SIGRTMIN;
buf[0] = 'S';
buf[1] = 'I';
buf[2] = 'G';
buf[3] = 'R';
buf[4] = 'T';
buf[5] = 'M';
buf[6] = 'I';
buf[7] = 'N';
buf[8] = '+';
FormatInt32(buf + 9, sig);
} else {
FormatInt32(buf, sig);
}
return buf;
}

View file

@ -1,6 +1,7 @@
#ifndef LIBC_ISYSTEM_SIGNAL_H_
#define LIBC_ISYSTEM_SIGNAL_H_
#include "libc/calls/calls.h"
#include "libc/calls/sigtimedwait.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/sysv/consts/sa.h"

View file

@ -16,154 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
static bool IsSiUser(int si_code) {
if (!IsOpenbsd()) {
return si_code == SI_USER;
} else {
return si_code <= 0;
}
}
static void NameIt(char p[17], const char *s, int si_code) {
p = stpcpy(p, s);
FormatInt32(p, si_code);
}
/**
* Returns symbolic name for siginfo::si_code value.
*/
const char *GetSiCodeName(int sig, int si_code) {
static char b[17];
NameIt(b, "SI_", si_code);
if (si_code == SI_QUEUE) {
strcpy(b + 3, "QUEUE"); /* sent by sigqueue(2) */
} else if (si_code == SI_TIMER) {
strcpy(b + 3, "TIMER"); /* sent by setitimer(2) or clock_settime(2) */
} else if (si_code == SI_TKILL) {
strcpy(b + 3, "TKILL"); /* sent by tkill(2), etc. */
} else if (si_code == SI_MESGQ) {
strcpy(b + 3, "MESGQ"); /* sent by mq_notify(2) */
} else if (si_code == SI_MESGQ) {
strcpy(b + 3, "MESGQ"); /* aio completion */
} else if (si_code == SI_ASYNCNL) {
strcpy(b + 3, "ASYNCNL"); /* aio completion for dns; the horror */
} else if (si_code == SI_NOINFO) {
strcpy(b + 3, "NOINFO"); /* no signal specific info available */
} else if (si_code == SI_KERNEL) {
strcpy(b + 3, "KERNEL"); /* sent by kernel */
} else if (IsSiUser(si_code)) {
strcpy(b + 3, "USER"); /* sent by kill(2) i.e. from userspace */
} else if (sig == SIGCHLD) {
NameIt(b, "CLD_", si_code);
if (si_code == CLD_EXITED) {
strcpy(b + 4, "EXITED"); /* child exited */
} else if (si_code == CLD_KILLED) {
strcpy(b + 4, "KILLED"); /* child terminated w/o core */
} else if (si_code == CLD_DUMPED) {
strcpy(b + 4, "DUMPED"); /* child terminated w/ core */
} else if (si_code == CLD_TRAPPED) {
strcpy(b + 4, "TRAPPED"); /* traced child trapped */
} else if (si_code == CLD_STOPPED) {
strcpy(b + 4, "STOPPED"); /* child stopped */
} else if (si_code == CLD_CONTINUED) {
strcpy(b + 4, "CONTINUED"); /* stopped child continued */
}
} else if (sig == SIGTRAP) {
NameIt(b, "TRAP_", si_code);
if (si_code == TRAP_BRKPT) {
strcpy(b + 5, "BRKPT"); /* process breakpoint */
} else if (si_code == TRAP_TRACE) {
strcpy(b + 5, "TRACE"); /* process trace trap */
}
} else if (sig == SIGSEGV) {
NameIt(b, "SEGV_", si_code);
if (si_code == SEGV_MAPERR) {
strcpy(b + 5, "MAPERR"); /* address not mapped to object */
} else if (si_code == SEGV_ACCERR) {
strcpy(b + 5, "ACCERR"); /* invalid permissions for mapped object */
} else if (si_code == SEGV_PKUERR) {
strcpy(b + 5, "PKUERR"); /* FreeBSD: x86: PKU violation */
}
} else if (sig == SIGFPE) {
NameIt(b, "FPE_???", si_code);
if (si_code == FPE_INTDIV) {
strcpy(b + 4, "INTDIV"); /* integer divide by zero */
} else if (si_code == FPE_INTOVF) {
strcpy(b + 4, "INTOVF"); /* integer overflow */
} else if (si_code == FPE_FLTDIV) {
strcpy(b + 4, "FLTDIV"); /* floating point divide by zero */
} else if (si_code == FPE_FLTOVF) {
strcpy(b + 4, "FLTOVF"); /* floating point overflow */
} else if (si_code == FPE_FLTUND) {
strcpy(b + 4, "FLTUND"); /* floating point underflow */
} else if (si_code == FPE_FLTRES) {
strcpy(b + 4, "FLTRES"); /* floating point inexact */
} else if (si_code == FPE_FLTINV) {
strcpy(b + 4, "FLTINV"); /* invalid floating point operation */
} else if (si_code == FPE_FLTSUB) {
strcpy(b + 4, "FLTSUB"); /* subscript out of range */
}
} else if (sig == SIGILL) {
NameIt(b, "ILL_", si_code);
if (si_code == ILL_ILLOPC) {
strcpy(b + 4, "ILLOPC"); /* illegal opcode */
} else if (si_code == ILL_ILLOPN) {
strcpy(b + 4, "ILLOPN"); /* illegal operand */
} else if (si_code == ILL_ILLADR) {
strcpy(b + 4, "ILLADR"); /* illegal addressing mode */
} else if (si_code == ILL_ILLTRP) {
strcpy(b + 4, "ILLTRP"); /* illegal trap */
} else if (si_code == ILL_PRVOPC) {
strcpy(b + 4, "PRVOPC"); /* privileged opcode */
} else if (si_code == ILL_PRVREG) {
strcpy(b + 4, "PRVREG"); /* privileged register */
} else if (si_code == ILL_COPROC) {
strcpy(b + 4, "COPROC"); /* coprocessor error */
} else if (si_code == ILL_BADSTK) {
strcpy(b + 4, "BADSTK"); /* internal stack error */
}
} else if (sig == SIGBUS) {
NameIt(b, "BUS_", si_code);
if (si_code == BUS_ADRALN) {
strcpy(b + 4, "ADRALN"); /* invalid address alignment */
} else if (si_code == BUS_ADRERR) {
strcpy(b + 4, "ADRERR"); /* non-existent physical address */
} else if (si_code == BUS_OBJERR) {
strcpy(b + 4, "OBJERR"); /* object specific hardware error */
} else if (si_code == BUS_OOMERR) {
strcpy(b + 4, "OOMERR"); /* FreeBSD */
} else if (si_code == BUS_MCEERR_AR) {
strcpy(b + 4, "MCEERR_AR"); /* Linux 2.6.32+ */
} else if (si_code == BUS_MCEERR_AO) {
strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */
}
} else if (sig == SIGIO) {
NameIt(b, "POLL_", si_code);
if (si_code == POLL_IN) {
strcpy(b + 5, "IN"); /* data input available */
} else if (si_code == POLL_OUT) {
strcpy(b + 5, "OUT"); /* output buffer available */
} else if (si_code == POLL_MSG) {
strcpy(b + 5, "MSG"); /* input message available */
} else if (si_code == POLL_ERR) {
strcpy(b + 5, "ERR"); /* i/o error */
} else if (si_code == POLL_PRI) {
strcpy(b + 5, "PRI"); /* high priority input available */
} else if (si_code == POLL_HUP) {
strcpy(b + 5, "HUP"); /* device disconnected */
}
} else if (sig == SIGSYS) {
NameIt(b, "SYS_", si_code);
if (si_code == SYS_SECCOMP) {
strcpy(b + 4, "SECCOMP");
}
}
return b;
return (DescribeSiCode)(b, sig, si_code);
}

View file

@ -203,6 +203,7 @@ wctrans_t wctrans(const char *);
wint_t towctrans(wint_t, wctrans_t);
char *strsignal(int) returnsnonnull libcesque;
char *strsignal_r(int, char[hasatleast 15]) returnsnonnull libcesque;
char *strerror(int) returnsnonnull dontthrow nocallback;
int strerror_r(int, char *, size_t) dontthrow nocallback;
int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback;

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sigtimedwait,0xffffff159ffff080,globl
.scall sys_sigtimedwait,0x1affff159ffff080,globl,hidden

View file

@ -168,11 +168,11 @@ syscon sig SIGPROF 27 27 27 27 27 27 # profiling timer expired;
syscon sig SIGWINCH 28 28 28 28 28 28 # terminal resized; unix consensus & faked on nt
syscon sig SIGIO 29 23 23 23 23 29 # bsd consensus
syscon sig SIGSYS 31 12 12 12 12 31 # wut; bsd consensus
syscon sig SIGINFO 0 29 29 29 29 0 # bsd consensus
syscon sig SIGRTMAX 64 0 126 0 63 0
syscon sig SIGRTMIN 32 0 65 0 33 0
syscon sig SIGEMT 0 7 7 7 7 0 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead
syscon sig SIGPWR 30 30 30 30 32 30 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead
syscon sig SIGINFO 0 29 29 29 29 0 # bsd consensus
syscon sig SIGRTMIN 32 0 65 0 33 32
syscon sig SIGRTMAX 64 0 126 0 63 64
syscon compat SIGPOLL 29 23 23 23 23 29 # same as SIGIO
syscon compat SIGIOT 6 6 6 6 6 6 # PDP-11 feature; same as SIGABRT
@ -1232,7 +1232,7 @@ syscon limits SOMAXCONN 4096 128 128 128 128 2147483647 # maximum
syscon limits _ARG_MAX 128*1024 1024*1024 512*1024 512*1024 256*1024 32767*2 # bsd consensus
syscon limits _NAME_MAX 255 255 255 255 511 255 # probably higher on windows?
syscon limits _PATH_MAX 4096 1024 1024 1024 1024 512 # cosmopolitan libc imposes a lower 512 limit; nt theoretically goes up to 32767
syscon limits _NSIG 64 32 128 32 64 32 # _SIG_MAXSIG on FreeBSD
syscon limits _NSIG 64 32 128 32 64 64 # _SIG_MAXSIG on FreeBSD
# unmount() flags
# a.k.a. umount2() on linux

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon sig,SIGRTMAX,64,0,126,0,63,0
.syscon sig,SIGRTMAX,64,0,126,0,63,64

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon sig,SIGRTMIN,32,0,65,0,33,0
.syscon sig,SIGRTMIN,32,0,65,0,33,32

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon limits,_NSIG,64,32,128,32,64,32
.syscon limits,_NSIG,64,32,128,32,64,64

View file

@ -192,7 +192,7 @@ scall sys_setfsuid 0xfffffffffffff07a globl hidden
scall sys_setfsgid 0xfffffffffffff07b globl hidden
scall sys_capget 0xfffffffffffff07d globl # no wrapper
scall sys_capset 0xfffffffffffff07e globl # no wrapper
scall sys_sigtimedwait 0xffffff159ffff080 globl # no wrapper
scall sys_sigtimedwait 0x1affff159ffff080 globl hidden
scall sys_sigqueue 0xffffff1c8fffffff globl hidden
scall sys_sigqueueinfo 0x0f5ffffffffff081 globl hidden # a.k.a. rt_sigqueueinfo on linux
scall sys_personality 0xfffffffffffff087 globl # no wrapper

View file

@ -20,27 +20,27 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.h"
#include "libc/errno.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
static unsigned OnSignalCnt = 0;
void OnSignal(int sig, siginfo_t *si, void *ctx) {
OnSignalCnt++;
EXPECT_EQ(SIGUSR1, sig);
}
TEST(sigpending, efault) {
ASSERT_SYS(EFAULT, -1, sigpending(0));
}
TEST(sigpending, test) {
sigset_t pending;
sigfillset(&pending);
EXPECT_EQ(0, sigpending(&pending));
unsigned cnt = 0;
for (unsigned sig = 1; sig < NSIG; sig++) {
if (sigismember(&pending, sig)) {
cnt++;
}
}
EXPECT_EQ(0, cnt);
EXPECT_EQ(0, sigcountset(&pending));
struct sigaction sa = {.sa_sigaction = OnSignal, .sa_flags = SA_SIGINFO};
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
@ -51,47 +51,23 @@ TEST(sigpending, test) {
ASSERT_EQ(0, raise(SIGUSR1));
sigfillset(&pending);
EXPECT_EQ(0, sigpending(&pending));
cnt = 0;
for (unsigned sig = 1; sig < NSIG; sig++) {
if (sigismember(&pending, sig)) {
cnt++;
}
}
EXPECT_EQ(1, cnt);
EXPECT_EQ(1, sigcountset(&pending));
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_IGN));
sigemptyset(&pending);
EXPECT_EQ(0, sigpending(&pending));
cnt = 0;
for (unsigned sig = 1; sig < NSIG; sig++) {
if (sigismember(&pending, sig)) {
cnt++;
}
}
EXPECT_EQ(0, cnt);
EXPECT_EQ(0, sigcountset(&pending));
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
ASSERT_EQ(0, raise(SIGUSR1));
EXPECT_EQ(0, sigpending(&pending));
cnt = 0;
for (unsigned sig = 1; sig < NSIG; sig++) {
if (sigismember(&pending, sig)) {
cnt++;
}
}
EXPECT_EQ(1, cnt);
EXPECT_EQ(1, sigcountset(&pending));
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
sigemptyset(&blocked);
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
EXPECT_EQ(0, sigpending(&pending));
cnt = 0;
for (unsigned sig = 1; sig < NSIG; sig++) {
if (sigismember(&pending, sig)) {
cnt++;
}
}
EXPECT_EQ(0, cnt);
EXPECT_EQ(0, sigcountset(&pending));
EXPECT_EQ(1, OnSignalCnt);
}

View file

@ -0,0 +1,75 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sigtimedwait.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/siginfo.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
void SetUp(void) {
if (IsXnu()) exit(0);
if (IsMetal()) exit(0);
if (IsWindows()) exit(0);
if (IsOpenbsd()) exit(0);
}
TEST(sigtimedwait, nullSet_efault) {
ASSERT_SYS(EFAULT, -1, sigtimedwait(0, 0, 0));
}
TEST(sigtimedwait, emptySet_timesOut) {
sigset_t ss = {0};
struct timespec ts = {0, 0};
ASSERT_SYS(EAGAIN, -1, sigtimedwait(&ss, 0, &ts));
}
TEST(sigtimedwait, badTimestamp_einval) {
sigset_t ss = {0};
struct timespec ts = {0, -1};
ASSERT_SYS(EINVAL, -1, sigtimedwait(&ss, 0, &ts));
}
TEST(sigtimedwait, test) {
int pid, ws;
siginfo_t info;
sigset_t ss, oldss;
struct timespec ts = {1, 0};
sigemptyset(&ss);
sigaddset(&ss, SIGUSR1);
ASSERT_SYS(0, 0, sigprocmask(SIG_BLOCK, &ss, &oldss));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
ASSERT_SYS(0, SIGUSR1, sigtimedwait(&ss, &info, &ts));
ASSERT_EQ(SIGUSR1, info.si_signo);
ASSERT_EQ(SI_USER, info.si_code);
ASSERT_EQ(getuid(), info.si_uid);
_Exit(0);
}
ASSERT_SYS(0, 0, kill(pid, SIGUSR1));
ASSERT_SYS(0, pid, wait(&ws));
ASSERT_EQ(0, ws);
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &oldss, 0));
}

View file

@ -49,10 +49,6 @@ static uint64_t Rando(void) {
return x;
}
void SetUp(void) {
__print_maps();
}
static const struct {
const char *want;
const char *fmt;
@ -356,6 +352,30 @@ TEST(ksnprintf, badUtf16) {
}
}
TEST(ksnprintf, negativeOverflowIdiom_isSafe) {
int i, n;
char golden[11];
struct {
char underflow[11];
char buf[11];
char overflow[11];
} u;
memset(golden, -1, 11);
memset(u.underflow, -1, 11);
memset(u.overflow, -1, 11);
i = 0;
n = 11;
i += ksnprintf(u.buf + i, n - i, "hello");
ASSERT_STREQ("hello", u.buf);
i += ksnprintf(u.buf + i, n - i, " world");
ASSERT_STREQ("hello w...", u.buf);
i += ksnprintf(u.buf + i, n - i, " i love you");
ASSERT_STREQ("hello w...", u.buf);
ASSERT_EQ(i, 5 + 6 + 11);
ASSERT_EQ(0, memcmp(golden, u.underflow, 11));
ASSERT_EQ(0, memcmp(golden, u.overflow, 11));
}
TEST(ksnprintf, truncation) {
char buf[16] = {0};
rngset(buf, sizeof(buf) - 1, lemur64, -1);

View file

@ -27,8 +27,13 @@ TEST(strsignal, test) {
EXPECT_STREQ("SIGALRM", strsignal(SIGALRM));
EXPECT_STREQ("SIGUSR1", strsignal(SIGUSR1));
EXPECT_STREQ("SIGSTOP", strsignal(SIGSTOP));
EXPECT_STREQ("SIG099", strsignal(99));
EXPECT_STREQ("SIG100", strsignal(100));
EXPECT_STREQ("SIGWUT", strsignal(-1));
EXPECT_STREQ("SIGWUT", strsignal(9001));
EXPECT_STREQ("666", strsignal(666));
EXPECT_STREQ("-1", strsignal(-1));
EXPECT_STREQ("9001", strsignal(9001));
}
TEST(strsignal, realtime) {
if (!SIGRTMIN) return;
ASSERT_STREQ("SIGRTMIN", strsignal(SIGRTMIN));
ASSERT_STREQ("SIGRTMIN+1", strsignal(SIGRTMIN + 1));
}