summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/complex/cacosh.c2
-rw-r--r--src/fenv/loongarch64/fenv.S78
-rw-r--r--src/fenv/riscv32/fenv-sf.c3
-rw-r--r--src/fenv/riscv32/fenv.S56
-rw-r--r--src/internal/atomic.h2
-rw-r--r--src/internal/dynlink.h8
-rw-r--r--src/internal/emulate_wait4.c55
-rw-r--r--src/internal/fork_impl.h2
-rw-r--r--src/internal/ksigaction.h5
-rw-r--r--src/internal/syscall.h12
-rw-r--r--src/ipc/semtimedop.c3
-rw-r--r--src/ldso/loongarch64/dlsym.s7
-rw-r--r--src/ldso/riscv32/dlsym.s6
-rw-r--r--src/ldso/riscv64/tlsdesc.s32
-rw-r--r--src/ldso/sh/dlsym.s2
-rw-r--r--src/linux/cache.c3
-rw-r--r--src/linux/clone.c56
-rw-r--r--src/linux/preadv2.c17
-rw-r--r--src/linux/pwritev2.c17
-rw-r--r--src/linux/statx.c42
-rw-r--r--src/linux/wait4.c4
-rw-r--r--src/locale/iconv.c9
-rw-r--r--src/math/acoshl.c10
-rw-r--r--src/math/fma.c2
-rw-r--r--src/math/logf.c2
-rw-r--r--src/math/powl.c34
-rw-r--r--src/math/riscv32/copysign.c15
-rw-r--r--src/math/riscv32/copysignf.c15
-rw-r--r--src/math/riscv32/fabs.c15
-rw-r--r--src/math/riscv32/fabsf.c15
-rw-r--r--src/math/riscv32/fma.c15
-rw-r--r--src/math/riscv32/fmaf.c15
-rw-r--r--src/math/riscv32/fmax.c15
-rw-r--r--src/math/riscv32/fmaxf.c15
-rw-r--r--src/math/riscv32/fmin.c15
-rw-r--r--src/math/riscv32/fminf.c15
-rw-r--r--src/math/riscv32/sqrt.c15
-rw-r--r--src/math/riscv32/sqrtf.c15
-rw-r--r--src/math/sqrtl.c4
-rw-r--r--src/misc/getopt.c3
-rw-r--r--src/misc/mntent.c46
-rw-r--r--src/misc/nftw.c4
-rw-r--r--src/misc/syslog.c3
-rw-r--r--src/mq/mq_notify.c47
-rw-r--r--src/multibyte/mbrtowc.c2
-rw-r--r--src/network/accept4.c4
-rw-r--r--src/network/dns_parse.c11
-rw-r--r--src/network/gethostbyaddr.c2
-rw-r--r--src/network/gethostbyname2.c2
-rw-r--r--src/network/getifaddrs.c14
-rw-r--r--src/network/getnameinfo.c9
-rw-r--r--src/network/getservbyport_r.c4
-rw-r--r--src/network/inet_pton.c1
-rw-r--r--src/network/lookup.h2
-rw-r--r--src/network/lookup_name.c7
-rw-r--r--src/network/res_msend.c36
-rw-r--r--src/network/sendmsg.c7
-rw-r--r--src/process/_Fork.c28
-rw-r--r--src/process/posix_spawn.c7
-rw-r--r--src/process/riscv64/vfork.s12
-rw-r--r--src/process/waitpid.c2
-rw-r--r--src/regex/glob.c2
-rw-r--r--src/search/hsearch.c4
-rw-r--r--src/select/poll.c9
-rw-r--r--src/select/ppoll.c (renamed from src/linux/ppoll.c)2
-rw-r--r--src/select/select.c1
-rw-r--r--src/setjmp/loongarch64/longjmp.S32
-rw-r--r--src/setjmp/loongarch64/setjmp.S34
-rw-r--r--src/setjmp/powerpc/longjmp.S8
-rw-r--r--src/setjmp/riscv32/longjmp.S42
-rw-r--r--src/setjmp/riscv32/setjmp.S41
-rw-r--r--src/signal/loongarch64/restore.s (renamed from src/signal/mips/restore.s)15
-rw-r--r--src/signal/loongarch64/sigsetjmp.s25
-rw-r--r--src/signal/mips64/restore.s11
-rw-r--r--src/signal/mipsn32/restore.s11
-rw-r--r--src/signal/riscv32/restore.s8
-rw-r--r--src/signal/riscv32/sigsetjmp.s23
-rw-r--r--src/signal/sh/sigsetjmp.s2
-rw-r--r--src/signal/sigaction.c5
-rw-r--r--src/stat/fchmodat.c7
-rw-r--r--src/stat/fstatat.c1
-rw-r--r--src/stat/statvfs.c1
-rw-r--r--src/stdio/pclose.c2
-rw-r--r--src/stdio/vfprintf.c31
-rw-r--r--src/stdio/vfwprintf.c43
-rw-r--r--src/stdio/vsnprintf.c5
-rw-r--r--src/stdio/vswprintf.c4
-rw-r--r--src/string/strverscmp.c6
-rw-r--r--src/string/wcscmp.c2
-rw-r--r--src/string/wcsncmp.c2
-rw-r--r--src/string/wmemcmp.c2
-rw-r--r--src/thread/loongarch64/__set_thread_area.s7
-rw-r--r--src/thread/loongarch64/__unmapself.s7
-rw-r--r--src/thread/loongarch64/clone.s29
-rw-r--r--src/thread/loongarch64/syscall_cp.s29
-rw-r--r--src/thread/pthread_atfork.c8
-rw-r--r--src/thread/pthread_cancel.c7
-rw-r--r--src/thread/pthread_detach.c8
-rw-r--r--src/thread/riscv32/__set_thread_area.s6
-rw-r--r--src/thread/riscv32/__unmapself.s7
-rw-r--r--src/thread/riscv32/clone.s34
-rw-r--r--src/thread/riscv32/syscall_cp.s29
-rw-r--r--src/thread/sem_getvalue.c3
-rw-r--r--src/thread/sem_post.c12
-rw-r--r--src/thread/sem_timedwait.c10
-rw-r--r--src/thread/sem_trywait.c6
-rw-r--r--src/thread/synccall.c8
-rw-r--r--src/time/__year_to_secs.c4
-rw-r--r--src/time/strftime.c8
-rw-r--r--src/time/timer_create.c2
-rw-r--r--src/unistd/dup3.c6
-rw-r--r--src/unistd/faccessat.c2
-rw-r--r--src/unistd/pipe2.c1
-rw-r--r--src/unistd/pwrite.c11
-rw-r--r--src/unistd/pwritev.c10
-rw-r--r--src/unistd/setxid.c2
116 files changed, 1311 insertions, 232 deletions
diff --git a/src/complex/cacosh.c b/src/complex/cacosh.c
index 76127f75..55b857ce 100644
--- a/src/complex/cacosh.c
+++ b/src/complex/cacosh.c
@@ -1,6 +1,6 @@
#include "complex_impl.h"
-/* acosh(z) = i acos(z) */
+/* acosh(z) = ±i acos(z) */
double complex cacosh(double complex z)
{
diff --git a/src/fenv/loongarch64/fenv.S b/src/fenv/loongarch64/fenv.S
new file mode 100644
index 00000000..9c38599e
--- /dev/null
+++ b/src/fenv/loongarch64/fenv.S
@@ -0,0 +1,78 @@
+#ifndef __loongarch_soft_float
+
+#ifdef BROKEN_LOONGARCH_FCSR_ASM
+#define FCSR $r0
+#else
+#define FCSR $fcsr0
+#endif
+
+.global feclearexcept
+.type feclearexcept,@function
+feclearexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ andn $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global feraiseexcept
+.type feraiseexcept,@function
+feraiseexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ or $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global fetestexcept
+.type fetestexcept,@function
+fetestexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ and $a0, $t1, $a0
+ jr $ra
+
+.global fegetround
+.type fegetround,@function
+fegetround:
+ movfcsr2gr $t0, FCSR
+ andi $a0, $t0, 0x300
+ jr $ra
+
+.global __fesetround
+.hidden __fesetround
+.type __fesetround,@function
+__fesetround:
+ li.w $t0, 0x300
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ andn $t1, $t1, $t0
+ or $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global fegetenv
+.type fegetenv,@function
+fegetenv:
+ movfcsr2gr $t0, FCSR
+ st.w $t0, $a0, 0
+ li.w $a0, 0
+ jr $ra
+
+.global fesetenv
+.type fesetenv,@function
+fesetenv:
+ addi.d $t0, $a0, 1
+ beq $t0, $r0, 1f
+ ld.w $t0, $a0, 0
+1: movgr2fcsr FCSR, $t0
+ li.w $a0, 0
+ jr $ra
+
+#endif
diff --git a/src/fenv/riscv32/fenv-sf.c b/src/fenv/riscv32/fenv-sf.c
new file mode 100644
index 00000000..ecd3cb5c
--- /dev/null
+++ b/src/fenv/riscv32/fenv-sf.c
@@ -0,0 +1,3 @@
+#ifndef __riscv_flen
+#include "../fenv.c"
+#endif
diff --git a/src/fenv/riscv32/fenv.S b/src/fenv/riscv32/fenv.S
new file mode 100644
index 00000000..0ea78bf9
--- /dev/null
+++ b/src/fenv/riscv32/fenv.S
@@ -0,0 +1,56 @@
+#ifdef __riscv_flen
+
+.global feclearexcept
+.type feclearexcept, %function
+feclearexcept:
+ csrc fflags, a0
+ li a0, 0
+ ret
+
+.global feraiseexcept
+.type feraiseexcept, %function
+feraiseexcept:
+ csrs fflags, a0
+ li a0, 0
+ ret
+
+.global fetestexcept
+.type fetestexcept, %function
+fetestexcept:
+ frflags t0
+ and a0, t0, a0
+ ret
+
+.global fegetround
+.type fegetround, %function
+fegetround:
+ frrm a0
+ ret
+
+.global __fesetround
+.type __fesetround, %function
+__fesetround:
+ fsrm t0, a0
+ li a0, 0
+ ret
+
+.global fegetenv
+.type fegetenv, %function
+fegetenv:
+ frcsr t0
+ sw t0, 0(a0)
+ li a0, 0
+ ret
+
+.global fesetenv
+.type fesetenv, %function
+fesetenv:
+ li t2, -1
+ li t1, 0
+ beq a0, t2, 1f
+ lw t1, 0(a0)
+1: fscsr t1
+ li a0, 0
+ ret
+
+#endif
diff --git a/src/internal/atomic.h b/src/internal/atomic.h
index 96c1552d..8f71c8cd 100644
--- a/src/internal/atomic.h
+++ b/src/internal/atomic.h
@@ -194,7 +194,7 @@ static inline void a_store(volatile int *p, int v)
#ifndef a_barrier
#define a_barrier a_barrier
-static void a_barrier()
+static inline void a_barrier()
{
volatile int tmp = 0;
a_cas(&tmp, 0, 0);
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 830354eb..40c743e2 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -73,6 +73,10 @@ struct fdpic_dummy_loadmap {
#define DL_NOMMU_SUPPORT 0
#endif
+#ifndef TLSDESC_BACKWARDS
+#define TLSDESC_BACKWARDS 0
+#endif
+
#if !DL_FDPIC
#define IS_RELATIVE(x,s) ( \
(R_TYPE(x) == REL_RELATIVE) || \
@@ -92,6 +96,10 @@ struct fdpic_dummy_loadmap {
#define DT_DEBUG_INDIRECT 0
#endif
+#ifndef DT_DEBUG_INDIRECT_REL
+#define DT_DEBUG_INDIRECT_REL 0
+#endif
+
#define AUX_CNT 32
#define DYN_CNT 37
diff --git a/src/internal/emulate_wait4.c b/src/internal/emulate_wait4.c
new file mode 100644
index 00000000..f6303412
--- /dev/null
+++ b/src/internal/emulate_wait4.c
@@ -0,0 +1,55 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+#ifndef SYS_wait4
+hidden long __emulate_wait4(int pid, int *status, int options, void *kru, int cp)
+{
+ idtype_t t;
+ int r;
+ siginfo_t info;
+
+ info.si_pid = 0;
+ if (pid < -1) {
+ t = P_PGID;
+ pid = -pid;
+ } else if (pid == -1) {
+ t = P_ALL;
+ } else if (pid == 0) {
+ t = P_PGID;
+ } else {
+ t = P_PID;
+ }
+
+ if (cp) r = __syscall_cp(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+ else r = __syscall(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+
+ if (r<0) return r;
+
+ if (info.si_pid && status) {
+ int sw=0;
+ switch (info.si_code) {
+ case CLD_CONTINUED:
+ sw = 0xffff;
+ break;
+ case CLD_DUMPED:
+ sw = info.si_status&0x7f | 0x80;
+ break;
+ case CLD_EXITED:
+ sw = (info.si_status&0xff) << 8;
+ break;
+ case CLD_KILLED:
+ sw = info.si_status&0x7f;
+ break;
+ case CLD_STOPPED:
+ case CLD_TRAPPED:
+ /* see ptrace(2); the high bits of si_status can contain */
+ /* PTRACE_EVENT_ values which must be preserved */
+ sw = (info.si_status << 8) + 0x7f;
+ break;
+ }
+ *status = sw;
+ }
+
+ return info.si_pid;
+}
+#endif
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h
index 354e733b..f995fce2 100644
--- a/src/internal/fork_impl.h
+++ b/src/internal/fork_impl.h
@@ -17,3 +17,5 @@ extern hidden volatile int *const __vmlock_lockptr;
hidden void __malloc_atfork(int);
hidden void __ldso_atfork(int);
hidden void __pthread_key_atfork(int);
+
+hidden void __post_Fork(int);
diff --git a/src/internal/ksigaction.h b/src/internal/ksigaction.h
index 8ebd5938..ef333f33 100644
--- a/src/internal/ksigaction.h
+++ b/src/internal/ksigaction.h
@@ -6,8 +6,13 @@
struct k_sigaction {
void (*handler)(int);
unsigned long flags;
+#ifdef SA_RESTORER
void (*restorer)(void);
+#endif
unsigned mask[2];
+#ifndef SA_RESTORER
+ void *unused;
+#endif
};
hidden void __restore(), __restore_rt();
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 4a446157..33d981f9 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -391,6 +391,18 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a,
#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__)
#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__))
+#ifdef SYS_wait4
+#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d)
+#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d)
+#else
+hidden long __emulate_wait4(int, int *, int, void *, int);
+#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0)
+#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1)
+#endif
+
+#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d))
+#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d))
+
hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned);
hidden void *__vdsosym(const char *, const char *);
diff --git a/src/ipc/semtimedop.c b/src/ipc/semtimedop.c
index 1632e7b0..a104af21 100644
--- a/src/ipc/semtimedop.c
+++ b/src/ipc/semtimedop.c
@@ -7,7 +7,8 @@
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
-#if !defined(SYS_semtimedop) && !defined(SYS_ipc)
+#if !defined(SYS_semtimedop) && !defined(SYS_ipc) || \
+ SYS_semtimedop == SYS_semtimedop_time64
#define NO_TIME32 1
#else
#define NO_TIME32 0
diff --git a/src/ldso/loongarch64/dlsym.s b/src/ldso/loongarch64/dlsym.s
new file mode 100644
index 00000000..26fabcdb
--- /dev/null
+++ b/src/ldso/loongarch64/dlsym.s
@@ -0,0 +1,7 @@
+.global dlsym
+.hidden __dlsym
+.type dlsym,@function
+dlsym:
+ move $a2, $ra
+ la.global $t0, __dlsym
+ jr $t0
diff --git a/src/ldso/riscv32/dlsym.s b/src/ldso/riscv32/dlsym.s
new file mode 100644
index 00000000..2bafd72d
--- /dev/null
+++ b/src/ldso/riscv32/dlsym.s
@@ -0,0 +1,6 @@
+.global dlsym
+.hidden __dlsym
+.type dlsym, %function
+dlsym:
+ mv a2, ra
+ tail __dlsym
diff --git a/src/ldso/riscv64/tlsdesc.s b/src/ldso/riscv64/tlsdesc.s
new file mode 100644
index 00000000..bef8b322
--- /dev/null
+++ b/src/ldso/riscv64/tlsdesc.s
@@ -0,0 +1,32 @@
+.text
+.global __tlsdesc_static
+.hidden __tlsdesc_static
+.type __tlsdesc_static,%function
+__tlsdesc_static:
+ ld a0,8(a0)
+ jr t0
+
+.global __tlsdesc_dynamic
+.hidden __tlsdesc_dynamic
+.type __tlsdesc_dynamic,%function
+__tlsdesc_dynamic:
+ add sp,sp,-16
+ sd t1,(sp)
+ sd t2,8(sp)
+
+ ld t2,-8(tp) # t2=dtv
+
+ ld a0,8(a0) # a0=&{modidx,off}
+ ld t1,8(a0) # t1=off
+ ld a0,(a0) # a0=modidx
+ sll a0,a0,3 # a0=8*modidx
+
+ add a0,a0,t2 # a0=dtv+8*modidx
+ ld a0,(a0) # a0=dtv[modidx]
+ add a0,a0,t1 # a0=dtv[modidx]+off
+ sub a0,a0,tp # a0=dtv[modidx]+off-tp
+
+ ld t1,(sp)
+ ld t2,8(sp)
+ add sp,sp,16
+ jr t0
diff --git a/src/ldso/sh/dlsym.s b/src/ldso/sh/dlsym.s
index 11a6fff5..34f3c35c 100644
--- a/src/ldso/sh/dlsym.s
+++ b/src/ldso/sh/dlsym.s
@@ -5,7 +5,7 @@
dlsym:
mov.l L1, r0
1: braf r0
- mov.l @r15, r6
+ sts pr, r6
.align 2
L1: .long __dlsym@PLT-(1b+4-.)
diff --git a/src/linux/cache.c b/src/linux/cache.c
index 0eb051c2..e76f7812 100644
--- a/src/linux/cache.c
+++ b/src/linux/cache.c
@@ -21,7 +21,7 @@ weak_alias(__cachectl, cachectl);
#ifdef SYS_riscv_flush_icache
#define VDSO_FLUSH_ICACHE_SYM "__vdso_flush_icache"
-#define VDSO_FLUSH_ICACHE_VER "LINUX_4.5"
+#define VDSO_FLUSH_ICACHE_VER "LINUX_4.15"
static void *volatile vdso_func;
@@ -45,6 +45,7 @@ int __riscv_flush_icache(void *start, void *end, unsigned long int flags)
if (!r) return r;
if (r != -ENOSYS) return __syscall_ret(r);
}
+ return syscall(SYS_riscv_flush_icache, start, end, flags);
}
weak_alias(__riscv_flush_icache, riscv_flush_icache);
#endif
diff --git a/src/linux/clone.c b/src/linux/clone.c
index 8c1af7d3..257c1cec 100644
--- a/src/linux/clone.c
+++ b/src/linux/clone.c
@@ -4,18 +4,62 @@
#include <sched.h>
#include "pthread_impl.h"
#include "syscall.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+struct clone_start_args {
+ int (*func)(void *);
+ void *arg;
+ sigset_t sigmask;
+};
+
+static int clone_start(void *arg)
+{
+ struct clone_start_args *csa = arg;
+ __post_Fork(0);
+ __restore_sigs(&csa->sigmask);
+ return csa->func(csa->arg);
+}
int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
+ struct clone_start_args csa;
va_list ap;
- pid_t *ptid, *ctid;
- void *tls;
+ pid_t *ptid = 0, *ctid = 0;
+ void *tls = 0;
+
+ /* Flags that produce an invalid thread/TLS state are disallowed. */
+ int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID;
+
+ if ((flags & badflags) || !stack)
+ return __syscall_ret(-EINVAL);
va_start(ap, arg);
- ptid = va_arg(ap, pid_t *);
- tls = va_arg(ap, void *);
- ctid = va_arg(ap, pid_t *);
+ if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID))
+ ptid = va_arg(ap, pid_t *);
+ if (flags & CLONE_CHILD_SETTID) {
+ tls = va_arg(ap, void *);
+ ctid = va_arg(ap, pid_t *);
+ }
va_end(ap);
- return __syscall_ret(__clone(func, stack, flags, arg, ptid, tls, ctid));
+ /* If CLONE_VM is used, it's impossible to give the child a consistent
+ * thread structure. In this case, the best we can do is assume the
+ * caller is content with an extremely restrictive execution context
+ * like the one vfork() would provide. */
+ if (flags & CLONE_VM) return __syscall_ret(
+ __clone(func, stack, flags, arg, ptid, tls, ctid));
+
+ __block_all_sigs(&csa.sigmask);
+ LOCK(__abort_lock);
+
+ /* Setup the a wrapper start function for the child process to do
+ * mimic _Fork in producing a consistent execution state. */
+ csa.func = func;
+ csa.arg = arg;
+ int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid);
+
+ __post_Fork(ret);
+ __restore_sigs(&csa.sigmask);
+ return __syscall_ret(ret);
}
diff --git a/src/linux/preadv2.c b/src/linux/preadv2.c
new file mode 100644
index 00000000..5e7ab70f
--- /dev/null
+++ b/src/linux/preadv2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t preadv2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_preadv
+ if (!flags) {
+ if (ofs==-1) return readv(fd, iov, count);
+ return syscall_cp(SYS_preadv, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32));
+ }
+#endif
+ return syscall_cp(SYS_preadv2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/pwritev2.c b/src/linux/pwritev2.c
new file mode 100644
index 00000000..ece90d7c
--- /dev/null
+++ b/src/linux/pwritev2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t pwritev2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_pwritev
+ if (!flags) {
+ if (ofs==-1) return writev(fd, iov, count);
+ return syscall_cp(SYS_pwritev, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32));
+ }
+#endif
+ return syscall_cp(SYS_pwritev2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/statx.c b/src/linux/statx.c
new file mode 100644
index 00000000..4616bff4
--- /dev/null
+++ b/src/linux/statx.c
@@ -0,0 +1,42 @@
+#define _GNU_SOURCE
+#include <sys/stat.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/sysmacros.h>
+#include <errno.h>
+
+int statx(int dirfd, const char *restrict path, int flags, unsigned mask, struct statx *restrict stx)
+{
+ int ret = __syscall(SYS_statx, dirfd, path, flags, mask, stx);
+
+#ifndef SYS_fstatat
+ return __syscall_ret(ret);
+#endif
+
+ if (ret != -ENOSYS) return __syscall_ret(ret);
+
+ struct stat st;
+ ret = fstatat(dirfd, path, &st, flags);
+ if (ret) return ret;
+
+ stx->stx_dev_major = major(st.st_dev);
+ stx->stx_dev_minor = minor(st.st_dev);
+ stx->stx_ino = st.st_ino;
+ stx->stx_mode = st.st_mode;
+ stx->stx_nlink = st.st_nlink;
+ stx->stx_uid = st.st_uid;
+ stx->stx_gid = st.st_gid;
+ stx->stx_size = st.st_size;
+ stx->stx_blksize = st.st_blksize;
+ stx->stx_blocks = st.st_blocks;
+ stx->stx_atime.tv_sec = st.st_atim.tv_sec;
+ stx->stx_atime.tv_nsec = st.st_atim.tv_nsec;
+ stx->stx_mtime.tv_sec = st.st_mtim.tv_sec;
+ stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec;
+ stx->stx_ctime.tv_sec = st.st_ctim.tv_sec;
+ stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec;
+ stx->stx_btime = (struct statx_timestamp){.tv_sec=0, .tv_nsec=0};
+ stx->stx_mask = STATX_BASIC_STATS;
+
+ return 0;
+}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index 83650e34..fb08c0d0 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -12,7 +12,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
if (ru) {
long long kru64[18];
r = __syscall(SYS_wait4_time64, pid, status, options, kru64);
- if (!r) {
+ if (r > 0) {
ru->ru_utime = (struct timeval)
{ .tv_sec = kru64[0], .tv_usec = kru64[1] };
ru->ru_stime = (struct timeval)
@@ -26,7 +26,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
}
#endif
char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
- r = __syscall(SYS_wait4, pid, status, options, dest);
+ r = __sys_wait4(pid, status, options, dest);
if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
long kru[4];
memcpy(kru, dest, 4*sizeof(long));
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
index 3047c27b..7fb2e1ef 100644
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -49,10 +49,10 @@ static const unsigned char charmaps[] =
"ucs4\0utf32\0\0\313"
"ucs2\0\0\314"
"eucjp\0\0\320"
-"shiftjis\0sjis\0\0\321"
+"shiftjis\0sjis\0cp932\0\0\321"
"iso2022jp\0\0\322"
"gb18030\0\0\330"
-"gbk\0\0\331"
+"gbk\0cp936\0windows936\0\0\331"
"gb2312\0\0\332"
"big5\0bigfive\0cp950\0big5hkscs\0\0\340"
"euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
@@ -340,6 +340,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
c++;
d -= 159;
}
+ if (c>=84) goto ilseq;
c = jis0208[c][d];
if (!c) goto ilseq;
break;
@@ -403,6 +404,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (c < 128) break;
if (c < 0xa1) goto ilseq;
case GBK:
+ if (c == 128) {
+ c = 0x20ac;
+ break;
+ }
case GB18030:
if (c < 128) break;
c -= 0x81;
diff --git a/src/math/acoshl.c b/src/math/acoshl.c
index 8d4b43f6..943cec17 100644
--- a/src/math/acoshl.c
+++ b/src/math/acoshl.c
@@ -10,14 +10,18 @@ long double acoshl(long double x)
long double acoshl(long double x)
{
union ldshape u = {x};
- int e = u.i.se & 0x7fff;
+ int e = u.i.se;
if (e < 0x3fff + 1)
- /* |x| < 2, invalid if x < 1 or nan */
+ /* 0 <= x < 2, invalid if x < 1 */
return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1)));
if (e < 0x3fff + 32)
- /* |x| < 0x1p32 */
+ /* 2 <= x < 0x1p32 */
return logl(2*x - 1/(x+sqrtl(x*x-1)));
+ if (e & 0x8000)
+ /* x < 0 or x = -0, invalid */
+ return (x - x) / (x - x);
+ /* 0x1p32 <= x or nan */
return logl(x) + 0.693147180559945309417232121458176568L;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
diff --git a/src/math/fma.c b/src/math/fma.c
index 0c6f90c9..adfadca8 100644
--- a/src/math/fma.c
+++ b/src/math/fma.c
@@ -53,7 +53,7 @@ double fma(double x, double y, double z)
return x*y + z;
if (nz.e >= ZEROINFNAN) {
if (nz.e > ZEROINFNAN) /* z==0 */
- return x*y + z;
+ return x*y;
return z;
}
diff --git a/src/math/logf.c b/src/math/logf.c
index 7ee5d7fe..e4c2237c 100644
--- a/src/math/logf.c
+++ b/src/math/logf.c
@@ -53,7 +53,7 @@ float logf(float x)
tmp = ix - OFF;
i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
k = (int32_t)tmp >> 23; /* arithmetic shift */
- iz = ix - (tmp & 0x1ff << 23);
+ iz = ix - (tmp & 0xff800000);
invc = T[i].invc;
logc = T[i].logc;
z = (double_t)asfloat(iz);
diff --git a/src/math/powl.c b/src/math/powl.c
index 5b6da07b..6f64ea71 100644
--- a/src/math/powl.c
+++ b/src/math/powl.c
@@ -212,25 +212,33 @@ long double powl(long double x, long double y)
}
if (x == 1.0)
return 1.0; /* 1**y = 1, even if y is nan */
- if (x == -1.0 && !isfinite(y))
- return 1.0; /* -1**inf = 1 */
if (y == 0.0)
return 1.0; /* x**0 = 1, even if x is nan */
if (y == 1.0)
return x;
- if (y >= LDBL_MAX) {
- if (x > 1.0 || x < -1.0)
- return INFINITY;
- if (x != 0.0)
- return 0.0;
- }
- if (y <= -LDBL_MAX) {
- if (x > 1.0 || x < -1.0)
+ /* if y*log2(x) < log2(LDBL_TRUE_MIN)-1 then x^y uflows to 0
+ if y*log2(x) > -log2(LDBL_TRUE_MIN)+1 > LDBL_MAX_EXP then x^y oflows
+ if |x|!=1 then |log2(x)| > |log(x)| > LDBL_EPSILON/2 so
+ x^y oflows/uflows if |y|*LDBL_EPSILON/2 > -log2(LDBL_TRUE_MIN)+1 */
+ if (fabsl(y) > 2*(-LDBL_MIN_EXP+LDBL_MANT_DIG+1)/LDBL_EPSILON) {
+ /* y is not an odd int */
+ if (x == -1.0)
+ return 1.0;
+ if (y == INFINITY) {
+ if (x > 1.0 || x < -1.0)
+ return INFINITY;
return 0.0;
- if (x != 0.0 || y == -INFINITY)
+ }
+ if (y == -INFINITY) {
+ if (x > 1.0 || x < -1.0)
+ return 0.0;
return INFINITY;
+ }
+ if ((x > 1.0 || x < -1.0) == (y > 0))
+ return huge * huge;
+ return twom10000 * twom10000;
}
- if (x >= LDBL_MAX) {
+ if (x == INFINITY) {
if (y > 0.0)
return INFINITY;
return 0.0;
@@ -253,7 +261,7 @@ long double powl(long double x, long double y)
yoddint = 1;
}
- if (x <= -LDBL_MAX) {
+ if (x == -INFINITY) {
if (y > 0.0) {
if (yoddint)
return -INFINITY;
diff --git a/src/math/riscv32/copysign.c b/src/math/riscv32/copysign.c
new file mode 100644
index 00000000..c7854178
--- /dev/null
+++ b/src/math/riscv32/copysign.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double copysign(double x, double y)
+{
+ __asm__ ("fsgnj.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../copysign.c"
+
+#endif
diff --git a/src/math/riscv32/copysignf.c b/src/math/riscv32/copysignf.c
new file mode 100644
index 00000000..a125611a
--- /dev/null
+++ b/src/math/riscv32/copysignf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float copysignf(float x, float y)
+{
+ __asm__ ("fsgnj.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../copysignf.c"
+
+#endif
diff --git a/src/math/riscv32/fabs.c b/src/math/riscv32/fabs.c
new file mode 100644
index 00000000..5290b6f0
--- /dev/null
+++ b/src/math/riscv32/fabs.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fabs(double x)
+{
+ __asm__ ("fabs.d %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../fabs.c"
+
+#endif
diff --git a/src/math/riscv32/fabsf.c b/src/math/riscv32/fabsf.c
new file mode 100644
index 00000000..f5032e35
--- /dev/null
+++ b/src/math/riscv32/fabsf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fabsf(float x)
+{
+ __asm__ ("fabs.s %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../fabsf.c"
+
+#endif
diff --git a/src/math/riscv32/fma.c b/src/math/riscv32/fma.c
new file mode 100644
index 00000000..99b05713
--- /dev/null
+++ b/src/math/riscv32/fma.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fma(double x, double y, double z)
+{
+ __asm__ ("fmadd.d %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+ return x;
+}
+
+#else
+
+#include "../fma.c"
+
+#endif
diff --git a/src/math/riscv32/fmaf.c b/src/math/riscv32/fmaf.c
new file mode 100644
index 00000000..f9dc47ed
--- /dev/null
+++ b/src/math/riscv32/fmaf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaf(float x, float y, float z)
+{
+ __asm__ ("fmadd.s %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+ return x;
+}
+
+#else
+
+#include "../fmaf.c"
+
+#endif
diff --git a/src/math/riscv32/fmax.c b/src/math/riscv32/fmax.c
new file mode 100644
index 00000000..023709cd
--- /dev/null
+++ b/src/math/riscv32/fmax.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmax(double x, double y)
+{
+ __asm__ ("fmax.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmax.c"
+
+#endif
diff --git a/src/math/riscv32/fmaxf.c b/src/math/riscv32/fmaxf.c
new file mode 100644
index 00000000..863d2bd1
--- /dev/null
+++ b/src/math/riscv32/fmaxf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaxf(float x, float y)
+{
+ __asm__ ("fmax.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmaxf.c"
+
+#endif
diff --git a/src/math/riscv32/fmin.c b/src/math/riscv32/fmin.c
new file mode 100644
index 00000000..a4e3b067
--- /dev/null
+++ b/src/math/riscv32/fmin.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmin(double x, double y)
+{
+ __asm__ ("fmin.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmin.c"
+
+#endif
diff --git a/src/math/riscv32/fminf.c b/src/math/riscv32/fminf.c
new file mode 100644
index 00000000..32156e80
--- /dev/null
+++ b/src/math/riscv32/fminf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fminf(float x, float y)
+{
+ __asm__ ("fmin.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fminf.c"
+
+#endif
diff --git a/src/math/riscv32/sqrt.c b/src/math/riscv32/sqrt.c
new file mode 100644
index 00000000..867a504c
--- /dev/null
+++ b/src/math/riscv32/sqrt.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double sqrt(double x)
+{
+ __asm__ ("fsqrt.d %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../sqrt.c"
+
+#endif
diff --git a/src/math/riscv32/sqrtf.c b/src/math/riscv32/sqrtf.c
new file mode 100644
index 00000000..610c2cf8
--- /dev/null
+++ b/src/math/riscv32/sqrtf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float sqrtf(float x)
+{
+ __asm__ ("fsqrt.s %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../sqrtf.c"
+
+#endif
diff --git a/src/math/sqrtl.c b/src/math/sqrtl.c
index 1b9f19c7..a231b3f2 100644
--- a/src/math/sqrtl.c
+++ b/src/math/sqrtl.c
@@ -205,7 +205,7 @@ long double sqrtl(long double x)
top = (top + 0x3fff) >> 1;
/* r ~ 1/sqrt(m) */
- static const uint64_t three = 0xc0000000;
+ const uint64_t three = 0xc0000000;
uint64_t r, s, d, u, i;
i = (ix.hi >> 42) % 128;
r = (uint32_t)__rsqrt_tab[i] << 16;
@@ -227,7 +227,7 @@ long double sqrtl(long double x)
r = mul64(u, r) << 1;
/* |r sqrt(m) - 1| < 0x1.c001p-59, switch to 128bit */
- static const u128 threel = {.hi=three<<32, .lo=0};
+ const u128 threel = {.hi=three<<32, .lo=0};
u128 rl, sl, dl, ul;
rl.hi = r;
rl.lo = 0;
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index c3f66995..b02b81c3 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring)
if (optstring[i] == ':') {
optarg = 0;
if (optstring[i+1] != ':' || optpos) {
- optarg = argv[optind++] + optpos;
+ optarg = argv[optind++];
+ if (optpos) optarg += optpos;
optpos = 0;
}
if (optind > argc) {
diff --git a/src/misc/mntent.c b/src/misc/mntent.c
index d404fbe3..78bf0cd0 100644
--- a/src/misc/mntent.c
+++ b/src/misc/mntent.c
@@ -20,6 +20,42 @@ int endmntent(FILE *f)
return 1;
}
+static char *unescape_ent(char *beg)
+{
+ char *dest = beg;
+ const char *src = beg;
+ while (*src) {
+ const char *val;
+ unsigned char cval = 0;
+ if (*src != '\\') {
+ *dest++ = *src++;
+ continue;
+ }
+ if (src[1] == '\\') {
+ ++src;
+ *dest++ = *src++;
+ continue;
+ }
+ val = src + 1;
+ for (int i = 0; i < 3; ++i) {
+ if (*val >= '0' && *val <= '7') {
+ cval <<= 3;
+ cval += *val++ - '0';
+ } else {
+ break;
+ }
+ }
+ if (cval) {
+ *dest++ = cval;
+ src = val;
+ } else {
+ *dest++ = *src++;
+ }
+ }
+ *dest = 0;
+ return beg;
+}
+
struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
{
int n[8], use_internal = (linebuf == SENTINEL);
@@ -45,7 +81,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
len = strlen(linebuf);
if (len > INT_MAX) continue;
for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len;
- sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
+ sscanf(linebuf, " %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %d %d",
n, n+1, n+2, n+3, n+4, n+5, n+6, n+7,
&mnt->mnt_freq, &mnt->mnt_passno);
} while (linebuf[n[0]] == '#' || n[1]==len);
@@ -55,10 +91,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
linebuf[n[5]] = 0;
linebuf[n[7]] = 0;
- mnt->mnt_fsname = linebuf+n[0];
- mnt->mnt_dir = linebuf+n[2];
- mnt->mnt_type = linebuf+n[4];
- mnt->mnt_opts = linebuf+n[6];
+ mnt->mnt_fsname = unescape_ent(linebuf+n[0]);
+ mnt->mnt_dir = unescape_ent(linebuf+n[2]);
+ mnt->mnt_type = unescape_ent(linebuf+n[4]);
+ mnt->mnt_opts = unescape_ent(linebuf+n[6]);
return mnt;
}
diff --git a/src/misc/nftw.c b/src/misc/nftw.c
index fcd25a73..71bc62ee 100644
--- a/src/misc/nftw.c
+++ b/src/misc/nftw.c
@@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
int err;
struct FTW lev;
+ st.st_dev = st.st_ino = 0;
+
if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
type = FTW_SLN;
@@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
type = FTW_F;
}
- if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
+ if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)
return 0;
new.chain = h;
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
index 7dc0c1be..710202f9 100644
--- a/src/misc/syslog.c
+++ b/src/misc/syslog.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include "lock.h"
#include "fork_impl.h"
+#include "locale_impl.h"
static volatile int lock[1];
static char log_ident[32];
@@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap)
now = time(NULL);
gmtime_r(&now, &tm);
- strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+ strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE);
pid = (log_opt & LOG_PID) ? getpid() : 0;
l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",
diff --git a/src/mq/mq_notify.c b/src/mq/mq_notify.c
index 221591c7..0e1e6c7a 100644
--- a/src/mq/mq_notify.c
+++ b/src/mq/mq_notify.c
@@ -4,11 +4,14 @@
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
+#include <semaphore.h>
#include "syscall.h"
struct args {
- pthread_barrier_t barrier;
+ sem_t sem;
int sock;
+ mqd_t mqd;
+ int err;
const struct sigevent *sev;
};
@@ -20,8 +23,19 @@ static void *start(void *p)
int s = args->sock;
void (*func)(union sigval) = args->sev->sigev_notify_function;
union sigval val = args->sev->sigev_value;
+ struct sigevent sev2;
+ static const char zeros[32];
+ int err;
+
+ sev2.sigev_notify = SIGEV_THREAD;
+ sev2.sigev_signo = s;
+ sev2.sigev_value.sival_ptr = (void *)&zeros;
+
+ args->err = err = -__syscall(SYS_mq_notify, args->mqd, &sev2);
+ sem_post(&args->sem);
+ if (err) return 0;
- pthread_barrier_wait(&args->barrier);
+ pthread_detach(pthread_self());
n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL);
close(s);
if (n==sizeof buf && buf[sizeof buf - 1] == 1)
@@ -35,8 +49,8 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
pthread_attr_t attr;
pthread_t td;
int s;
- struct sigevent sev2;
- static const char zeros[32];
+ int cs;
+ sigset_t allmask, origmask;
if (!sev || sev->sigev_notify != SIGEV_THREAD)
return syscall(SYS_mq_notify, mqd, sev);
@@ -44,30 +58,35 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0);
if (s < 0) return -1;
args.sock = s;
+ args.mqd = mqd;
if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes;
else pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_barrier_init(&args.barrier, 0, 2);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ sem_init(&args.sem, 0, 0);
+ sigfillset(&allmask);
+ pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
if (pthread_create(&td, &attr, start, &args)) {
__syscall(SYS_close, s);
+ pthread_sigmask(SIG_SETMASK, &origmask, 0);
errno = EAGAIN;
return -1;
}
+ pthread_sigmask(SIG_SETMASK, &origmask, 0);
- pthread_barrier_wait(&args.barrier);
- pthread_barrier_destroy(&args.barrier);
-
- sev2.sigev_notify = SIGEV_THREAD;
- sev2.sigev_signo = s;
- sev2.sigev_value.sival_ptr = (void *)&zeros;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+ sem_wait(&args.sem);
+ sem_destroy(&args.sem);
- if (syscall(SYS_mq_notify, mqd, &sev2) < 0) {
- pthread_cancel(td);
+ if (args.err) {
__syscall(SYS_close, s);
+ pthread_join(td, 0);
+ pthread_setcancelstate(cs, 0);
+ errno = args.err;
return -1;
}
+ pthread_setcancelstate(cs, 0);
return 0;
}
diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c
index c94819e7..7824997e 100644
--- a/src/multibyte/mbrtowc.c
+++ b/src/multibyte/mbrtowc.c
@@ -8,7 +8,7 @@ size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate
static unsigned internal_state;
unsigned c;
const unsigned char *s = (const void *)src;
- const unsigned N = n;
+ const size_t N = n;
wchar_t dummy;
if (!st) st = (void *)&internal_state;
diff --git a/src/network/accept4.c b/src/network/accept4.c
index 59ab1726..765a38ed 100644
--- a/src/network/accept4.c
+++ b/src/network/accept4.c
@@ -9,6 +9,10 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int
if (!flg) return accept(fd, addr, len);
int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0);
if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret;
+ if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) {
+ errno = EINVAL;
+ return -1;
+ }
ret = accept(fd, addr, len);
if (ret<0) return ret;
if (flg & SOCK_CLOEXEC)
diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
index e6ee19d9..09813112 100644
--- a/src/network/dns_parse.c
+++ b/src/network/dns_parse.c
@@ -1,7 +1,7 @@
#include <string.h>
#include "lookup.h"
-int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
+int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx)
{
int qdcount, ancount;
const unsigned char *p;
@@ -12,21 +12,20 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
p = r+12;
qdcount = r[4]*256 + r[5];
ancount = r[6]*256 + r[7];
- if (qdcount+ancount > 64) return -1;
while (qdcount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ if (p>r+rlen-6)
return -1;
p += 5 + !!*p;
}
while (ancount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ if (p>r+rlen-12)
return -1;
p += 1 + !!*p;
len = p[8]*256 + p[9];
- if (p+len > r+rlen) return -1;
- if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
+ if (len+10 > r+rlen-p) return -1;
+ if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1;
p += 10 + len;
}
return 0;
diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c
index 598e2241..c3cacaac 100644
--- a/src/network/gethostbyaddr.c
+++ b/src/network/gethostbyaddr.c
@@ -20,5 +20,5 @@ struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)
err = gethostbyaddr_r(a, l, af, h,
(void *)(h+1), size-sizeof *h, &res, &h_errno);
} while (err == ERANGE);
- return err ? 0 : h;
+ return res;
}
diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c
index dc9d6621..bd0da7f8 100644
--- a/src/network/gethostbyname2.c
+++ b/src/network/gethostbyname2.c
@@ -21,5 +21,5 @@ struct hostent *gethostbyname2(const char *name, int af)
err = gethostbyname2_r(name, af, h,
(void *)(h+1), size-sizeof *h, &res, &h_errno);
} while (err == ERANGE);
- return err ? 0 : h;
+ return res;
}
diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c
index fed75bd8..74df4d6c 100644
--- a/src/network/getifaddrs.c
+++ b/src/network/getifaddrs.c
@@ -39,8 +39,8 @@ struct ifaddrs_storage {
};
struct ifaddrs_ctx {
- struct ifaddrs_storage *first;
- struct ifaddrs_storage *last;
+ struct ifaddrs *first;
+ struct ifaddrs *last;
struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
};
@@ -195,9 +195,9 @@ static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
}
if (ifs->ifa.ifa_name) {
- if (!ctx->first) ctx->first = ifs;
- if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa;
- ctx->last = ifs;
+ if (!ctx->first) ctx->first = &ifs->ifa;
+ if (ctx->last) ctx->last->ifa_next = &ifs->ifa;
+ ctx->last = &ifs->ifa;
} else {
free(ifs);
}
@@ -210,7 +210,7 @@ int getifaddrs(struct ifaddrs **ifap)
int r;
memset(ctx, 0, sizeof *ctx);
r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
- if (r == 0) *ifap = &ctx->first->ifa;
- else freeifaddrs(&ctx->first->ifa);
+ if (r == 0) *ifap = ctx->first;
+ else freeifaddrs(ctx->first);
return r;
}
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
index 949e1811..133c15b3 100644
--- a/src/network/getnameinfo.c
+++ b/src/network/getnameinfo.c
@@ -58,6 +58,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i
if ((p=strchr(line, '#'))) *p++='\n', *p=0;
for (p=line; *p && !isspace(*p); p++);
+ if (!*p) continue;
*p++ = 0;
if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0)
continue;
@@ -108,10 +109,10 @@ static void reverse_services(char *buf, int port, int dgram)
__fclose_ca(f);
}
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
{
if (rr != RR_PTR) return 0;
- if (__dn_expand(packet, (const unsigned char *)packet + 512,
+ if (__dn_expand(packet, (const unsigned char *)packet + plen,
data, c, 256) <= 0)
*(char *)c = 0;
return 0;
@@ -161,8 +162,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
query[3] = 0; /* don't need AD flag */
int rlen = __res_send(query, qlen, reply, sizeof reply);
buf[0] = 0;
- if (rlen > 0)
+ if (rlen > 0) {
+ if (rlen > sizeof reply) rlen = sizeof reply;
__dns_parse(reply, rlen, dns_parse_callback, buf);
+ }
}
if (!*buf) {
if (flags & NI_NAMEREQD) return EAI_NONAME;
diff --git a/src/network/getservbyport_r.c b/src/network/getservbyport_r.c
index b7f21c6b..e4cc3079 100644
--- a/src/network/getservbyport_r.c
+++ b/src/network/getservbyport_r.c
@@ -26,7 +26,7 @@ int getservbyport_r(int port, const char *prots,
/* Align buffer */
i = (uintptr_t)buf & sizeof(char *)-1;
if (!i) i = sizeof(char *);
- if (buflen < 3*sizeof(char *)-i)
+ if (buflen <= 3*sizeof(char *)-i)
return ERANGE;
buf += sizeof(char *)-i;
buflen -= sizeof(char *)-i;
@@ -46,6 +46,8 @@ int getservbyport_r(int port, const char *prots,
case EAI_MEMORY:
case EAI_SYSTEM:
return ENOMEM;
+ case EAI_OVERFLOW:
+ return ERANGE;
default:
return ENOENT;
case 0:
diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c
index d36c3689..bcbdd9ef 100644
--- a/src/network/inet_pton.c
+++ b/src/network/inet_pton.c
@@ -54,6 +54,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0)
if (s[j]!='.' || (i<6 && brk<0)) return 0;
need_v4=1;
i++;
+ ip[i&7]=0;
break;
}
s += j+1;
diff --git a/src/network/lookup.h b/src/network/lookup.h
index ef662725..54b2f8b5 100644
--- a/src/network/lookup.h
+++ b/src/network/lookup.h
@@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in
hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);
hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
-hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *);
#endif
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index 5f6867cb..35218185 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -109,15 +109,15 @@ struct dpc_ctx {
#define RR_CNAME 5
#define RR_AAAA 28
-#define ABUF_SIZE 768
+#define ABUF_SIZE 4800
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
{
char tmp[256];
int family;
struct dpc_ctx *ctx = c;
if (rr == RR_CNAME) {
- if (__dn_expand(packet, (const unsigned char *)packet + ABUF_SIZE,
+ if (__dn_expand(packet, (const unsigned char *)packet + plen,
data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
strcpy(ctx->canon, tmp);
return 0;
@@ -179,6 +179,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
for (i=nq-1; i>=0; i--) {
ctx.rrtype = qtypes[i];
+ if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i];
__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
}
diff --git a/src/network/res_msend.c b/src/network/res_msend.c
index 11c6aa0e..86c2fcf4 100644
--- a/src/network/res_msend.c
+++ b/src/network/res_msend.c
@@ -25,7 +25,8 @@ static void cleanup(void *p)
static unsigned long mtime()
{
struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS)
+ clock_gettime(CLOCK_REALTIME, &ts);
return (unsigned long)ts.tv_sec * 1000
+ ts.tv_nsec / 1000000;
}
@@ -132,6 +133,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
family = AF_INET;
sl = sizeof sa.sin;
}
+
+ /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
+ if (fd >= 0 && family == AF_INET6) {
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
+ for (i=0; i<nns; i++) {
+ if (ns[i].sin.sin_family != AF_INET) continue;
+ memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
+ &ns[i].sin.sin_addr, 4);
+ memcpy(ns[i].sin6.sin6_addr.s6_addr,
+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ ns[i].sin6.sin6_family = AF_INET6;
+ ns[i].sin6.sin6_flowinfo = 0;
+ ns[i].sin6.sin6_scope_id = 0;
+ }
+ }
+
sa.sin.sin_family = family;
if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
if (fd >= 0) close(fd);
@@ -151,21 +168,6 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
pthread_cleanup_push(cleanup, pfd);
pthread_setcancelstate(cs, 0);
- /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
- if (family == AF_INET6) {
- setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
- for (i=0; i<nns; i++) {
- if (ns[i].sin.sin_family != AF_INET) continue;
- memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
- &ns[i].sin.sin_addr, 4);
- memcpy(ns[i].sin6.sin6_addr.s6_addr,
- "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
- ns[i].sin6.sin6_family = AF_INET6;
- ns[i].sin6.sin6_flowinfo = 0;
- ns[i].sin6.sin6_scope_id = 0;
- }
- }
-
memset(alens, 0, sizeof *alens * nqueries);
retry_interval = timeout / attempts;
@@ -286,7 +288,7 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
};
step_mh(&mh, apos[i]);
r = recvmsg(pfd[i].fd, &mh, 0);
- if (r < 0) goto out;
+ if (r <= 0) goto out;
apos[i] += r;
if (apos[i] < 2) continue;
int alen = alen_buf[i][0]*256 + alen_buf[i][1];
diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c
index 80cc5f41..acdfdf29 100644
--- a/src/network/sendmsg.c
+++ b/src/network/sendmsg.c
@@ -8,13 +8,16 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
{
#if LONG_MAX > INT_MAX
struct msghdr h;
- struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c;
+ /* Kernels before 2.6.38 set SCM_MAX_FD to 255, allocate enough
+ * space to support an SCM_RIGHTS ancillary message with 255 fds.
+ * Kernels since 2.6.38 set SCM_MAX_FD to 253. */
+ struct cmsghdr chbuf[CMSG_SPACE(255*sizeof(int))/sizeof(struct cmsghdr)+1], *c;
if (msg) {
h = *msg;
h.__pad1 = h.__pad2 = 0;
msg = &h;
if (h.msg_controllen) {
- if (h.msg_controllen > 1024) {
+ if (h.msg_controllen > sizeof chbuf) {
errno = ENOMEM;
return -1;
}
diff --git a/src/process/_Fork.c b/src/process/_Fork.c
index fb0fdc2c..9c07792d 100644
--- a/src/process/_Fork.c
+++ b/src/process/_Fork.c
@@ -5,24 +5,16 @@
#include "lock.h"
#include "pthread_impl.h"
#include "aio_impl.h"
+#include "fork_impl.h"
static void dummy(int x) { }
weak_alias(dummy, __aio_atfork);
-pid_t _Fork(void)
+void __post_Fork(int ret)
{
- pid_t ret;
- sigset_t set;
- __block_all_sigs(&set);
- LOCK(__abort_lock);
-#ifdef SYS_fork
- ret = __syscall(SYS_fork);
-#else
- ret = __syscall(SYS_clone, SIGCHLD, 0);
-#endif
if (!ret) {
pthread_t self = __pthread_self();
- self->tid = __syscall(SYS_gettid);
+ self->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
self->robust_list.off = 0;
self->robust_list.pending = 0;
self->next = self->prev = self;
@@ -32,6 +24,20 @@ pid_t _Fork(void)
}
UNLOCK(__abort_lock);
if (!ret) __aio_atfork(1);
+}
+
+pid_t _Fork(void)
+{
+ pid_t ret;
+ sigset_t set;
+ __block_all_sigs(&set);
+ LOCK(__abort_lock);
+#ifdef SYS_fork
+ ret = __syscall(SYS_fork);
+#else
+ ret = __syscall(SYS_clone, SIGCHLD, 0);
+#endif
+ __post_Fork(ret);
__restore_sigs(&set);
return __syscall_ret(ret);
}
diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c
index 728551b3..8294598b 100644
--- a/src/process/posix_spawn.c
+++ b/src/process/posix_spawn.c
@@ -4,6 +4,7 @@
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
+#include <errno.h>
#include <sys/wait.h>
#include "syscall.h"
#include "lock.h"
@@ -156,7 +157,11 @@ static int child(void *args_vp)
fail:
/* Since sizeof errno < PIPE_BUF, the write is atomic. */
ret = -ret;
- if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0);
+ if (ret) {
+ int r;
+ do r = __syscall(SYS_write, p, &ret, sizeof ret);
+ while (r<0 && r!=-EPIPE);
+ }
_exit(127);
}
diff --git a/src/process/riscv64/vfork.s b/src/process/riscv64/vfork.s
new file mode 100644
index 00000000..c93dca23
--- /dev/null
+++ b/src/process/riscv64/vfork.s
@@ -0,0 +1,12 @@
+.global vfork
+.type vfork,@function
+vfork:
+ /* riscv does not have SYS_vfork, so we must use clone instead */
+ /* note: riscv's clone = clone(flags, sp, ptidptr, tls, ctidptr) */
+ li a7, 220
+ li a0, 0x100 | 0x4000 | 17 /* flags = CLONE_VM | CLONE_VFORK | SIGCHLD */
+ mv a1, sp
+ /* the other arguments are ignoreable */
+ ecall
+ .hidden __syscall_ret
+ j __syscall_ret
diff --git a/src/process/waitpid.c b/src/process/waitpid.c
index 1b65bf05..80231862 100644
--- a/src/process/waitpid.c
+++ b/src/process/waitpid.c
@@ -3,5 +3,5 @@
pid_t waitpid(pid_t pid, int *status, int options)
{
- return syscall_cp(SYS_wait4, pid, status, options, 0);
+ return sys_wait4_cp(pid, status, options, 0);
}
diff --git a/src/regex/glob.c b/src/regex/glob.c
index a4906446..87bae084 100644
--- a/src/regex/glob.c
+++ b/src/regex/glob.c
@@ -265,7 +265,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i
if (append(&tail, pat, strlen(pat), 0))
return GLOB_NOSPACE;
cnt++;
- } else
+ } else if (!error)
return GLOB_NOMATCH;
}
diff --git a/src/search/hsearch.c b/src/search/hsearch.c
index b3ac8796..2634a67f 100644
--- a/src/search/hsearch.c
+++ b/src/search/hsearch.c
@@ -41,9 +41,9 @@ static int resize(size_t nel, struct hsearch_data *htab)
{
size_t newsize;
size_t i, j;
+ size_t oldsize = htab->__tab->mask + 1;
ENTRY *e, *newe;
ENTRY *oldtab = htab->__tab->entries;
- ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1;
if (nel > MAXSIZE)
nel = MAXSIZE;
@@ -56,7 +56,7 @@ static int resize(size_t nel, struct hsearch_data *htab)
htab->__tab->mask = newsize - 1;
if (!oldtab)
return 1;
- for (e = oldtab; e < oldend; e++)
+ for (e = oldtab; e < oldtab + oldsize; e++)
if (e->key) {
for (i=keyhash(e->key),j=1; ; i+=j++) {
newe = htab->__tab->entries + (i & htab->__tab->mask);
diff --git a/src/select/poll.c b/src/select/poll.c
index c84c8a99..7883dfab 100644
--- a/src/select/poll.c
+++ b/src/select/poll.c
@@ -8,8 +8,13 @@ int poll(struct pollfd *fds, nfds_t n, int timeout)
#ifdef SYS_poll
return syscall_cp(SYS_poll, fds, n, timeout);
#else
+#if SYS_ppoll_time64 == SYS_ppoll
+ typedef long long ppoll_ts_t[2];
+#else
+ typedef long ppoll_ts_t[2];
+#endif
return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ?
- &((struct timespec){ .tv_sec = timeout/1000,
- .tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8);
+ ((ppoll_ts_t){ timeout/1000, timeout%1000*1000000 }) : 0,
+ 0, _NSIG/8);
#endif
}
diff --git a/src/linux/ppoll.c b/src/select/ppoll.c
index e614600a..9a0bf929 100644
--- a/src/linux/ppoll.c
+++ b/src/select/ppoll.c
@@ -1,4 +1,4 @@
-#define _GNU_SOURCE
+#define _BSD_SOURCE
#include <poll.h>
#include <signal.h>
#include <errno.h>
diff --git a/src/select/select.c b/src/select/select.c
index 8a786884..f1d72863 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -33,6 +33,7 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict
((syscall_arg_t[]){ 0, _NSIG/8 }));
if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
return __syscall_ret(r);
+ s = CLAMP(s);
#endif
#ifdef SYS_select
return syscall_cp(SYS_select, n, rfds, wfds, efds,
diff --git a/src/setjmp/loongarch64/longjmp.S b/src/setjmp/loongarch64/longjmp.S
new file mode 100644
index 00000000..896d2e26
--- /dev/null
+++ b/src/setjmp/loongarch64/longjmp.S
@@ -0,0 +1,32 @@
+.global _longjmp
+.global longjmp
+.type _longjmp,@function
+.type longjmp,@function
+_longjmp:
+longjmp:
+ ld.d $ra, $a0, 0
+ ld.d $sp, $a0, 8
+ ld.d $r21,$a0, 16
+ ld.d $fp, $a0, 24
+ ld.d $s0, $a0, 32
+ ld.d $s1, $a0, 40
+ ld.d $s2, $a0, 48
+ ld.d $s3, $a0, 56
+ ld.d $s4, $a0, 64
+ ld.d $s5, $a0, 72
+ ld.d $s6, $a0, 80
+ ld.d $s7, $a0, 88
+ ld.d $s8, $a0, 96
+#ifndef __loongarch_soft_float
+ fld.d $fs0, $a0, 104
+ fld.d $fs1, $a0, 112
+ fld.d $fs2, $a0, 120
+ fld.d $fs3, $a0, 128
+ fld.d $fs4, $a0, 136
+ fld.d $fs5, $a0, 144
+ fld.d $fs6, $a0, 152
+ fld.d $fs7, $a0, 160
+#endif
+ sltui $a0, $a1, 1
+ add.d $a0, $a0, $a1
+ jr $ra
diff --git a/src/setjmp/loongarch64/setjmp.S b/src/setjmp/loongarch64/setjmp.S
new file mode 100644
index 00000000..d158a3d2
--- /dev/null
+++ b/src/setjmp/loongarch64/setjmp.S
@@ -0,0 +1,34 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp,@function
+.type _setjmp,@function
+.type setjmp,@function
+__setjmp:
+_setjmp:
+setjmp:
+ st.d $ra, $a0, 0
+ st.d $sp, $a0, 8
+ st.d $r21,$a0, 16
+ st.d $fp, $a0, 24
+ st.d $s0, $a0, 32
+ st.d $s1, $a0, 40
+ st.d $s2, $a0, 48
+ st.d $s3, $a0, 56
+ st.d $s4, $a0, 64
+ st.d $s5, $a0, 72
+ st.d $s6, $a0, 80
+ st.d $s7, $a0, 88
+ st.d $s8, $a0, 96
+#ifndef __loongarch_soft_float
+ fst.d $fs0, $a0, 104
+ fst.d $fs1, $a0, 112
+ fst.d $fs2, $a0, 120
+ fst.d $fs3, $a0, 128
+ fst.d $fs4, $a0, 136
+ fst.d $fs5, $a0, 144
+ fst.d $fs6, $a0, 152
+ fst.d $fs7, $a0, 160
+#endif
+ move $a0, $zero
+ jr $ra
diff --git a/src/setjmp/powerpc/longjmp.S b/src/setjmp/powerpc/longjmp.S
index 611389fe..465e4cd7 100644
--- a/src/setjmp/powerpc/longjmp.S
+++ b/src/setjmp/powerpc/longjmp.S
@@ -42,10 +42,10 @@ longjmp:
bl 1f
.hidden __hwcap
.long __hwcap-.
-1: mflr 4
- lwz 5, 0(4)
- lwzx 4, 4, 5
- andis. 4, 4, 0x80
+1: mflr 6
+ lwz 5, 0(6)
+ lwzx 6, 6, 5
+ andis. 6, 6, 0x80
beq 1f
.long 0x11c35b01 /* evldd 14,88(3) */
.long 0x11e36301 /* ... */
diff --git a/src/setjmp/riscv32/longjmp.S b/src/setjmp/riscv32/longjmp.S
new file mode 100644
index 00000000..f9cb3318
--- /dev/null
+++ b/src/setjmp/riscv32/longjmp.S
@@ -0,0 +1,42 @@
+.global __longjmp
+.global _longjmp
+.global longjmp
+.type __longjmp, %function
+.type _longjmp, %function
+.type longjmp, %function
+__longjmp:
+_longjmp:
+longjmp:
+ lw s0, 0(a0)
+ lw s1, 4(a0)
+ lw s2, 8(a0)
+ lw s3, 12(a0)
+ lw s4, 16(a0)
+ lw s5, 20(a0)
+ lw s6, 24(a0)
+ lw s7, 28(a0)
+ lw s8, 32(a0)
+ lw s9, 36(a0)
+ lw s10, 40(a0)
+ lw s11, 44(a0)
+ lw sp, 48(a0)
+ lw ra, 52(a0)
+
+#ifndef __riscv_float_abi_soft
+ fld fs0, 56(a0)
+ fld fs1, 64(a0)
+ fld fs2, 72(a0)
+ fld fs3, 80(a0)
+ fld fs4, 88(a0)
+ fld fs5, 96(a0)
+ fld fs6, 104(a0)
+ fld fs7, 112(a0)
+ fld fs8, 120(a0)
+ fld fs9, 128(a0)
+ fld fs10, 136(a0)
+ fld fs11, 144(a0)
+#endif
+
+ seqz a0, a1
+ add a0, a0, a1
+ ret
diff --git a/src/setjmp/riscv32/setjmp.S b/src/setjmp/riscv32/setjmp.S
new file mode 100644
index 00000000..8a75cf55
--- /dev/null
+++ b/src/setjmp/riscv32/setjmp.S
@@ -0,0 +1,41 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp, %function
+.type _setjmp, %function
+.type setjmp, %function
+__setjmp:
+_setjmp:
+setjmp:
+ sw s0, 0(a0)
+ sw s1, 4(a0)
+ sw s2, 8(a0)
+ sw s3, 12(a0)
+ sw s4, 16(a0)
+ sw s5, 20(a0)
+ sw s6, 24(a0)
+ sw s7, 28(a0)
+ sw s8, 32(a0)
+ sw s9, 36(a0)
+ sw s10, 40(a0)
+ sw s11, 44(a0)
+ sw sp, 48(a0)
+ sw ra, 52(a0)
+
+#ifndef __riscv_float_abi_soft
+ fsd fs0, 56(a0)
+ fsd fs1, 64(a0)
+ fsd fs2, 72(a0)
+ fsd fs3, 80(a0)
+ fsd fs4, 88(a0)
+ fsd fs5, 96(a0)
+ fsd fs6, 104(a0)
+ fsd fs7, 112(a0)
+ fsd fs8, 120(a0)
+ fsd fs9, 128(a0)
+ fsd fs10, 136(a0)
+ fsd fs11, 144(a0)
+#endif
+
+ li a0, 0
+ ret
diff --git a/src/signal/mips/restore.s b/src/signal/loongarch64/restore.s
index b6dadce0..d90a8ebb 100644
--- a/src/signal/mips/restore.s
+++ b/src/signal/loongarch64/restore.s
@@ -1,15 +1,10 @@
-.set noreorder
-
.global __restore_rt
-.hidden __restore_rt
-.type __restore_rt,@function
-__restore_rt:
- li $2, 4193
- syscall
-
.global __restore
+.hidden __restore_rt
.hidden __restore
+.type __restore_rt,@function
.type __restore,@function
+__restore_rt:
__restore:
- li $2, 4119
- syscall
+ li.w $a7, 139
+ syscall 0
diff --git a/src/signal/loongarch64/sigsetjmp.s b/src/signal/loongarch64/sigsetjmp.s
new file mode 100644
index 00000000..9c0e3ae2
--- /dev/null
+++ b/src/signal/loongarch64/sigsetjmp.s
@@ -0,0 +1,25 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp,@function
+.type __sigsetjmp,@function
+sigsetjmp:
+__sigsetjmp:
+ beq $a1, $zero, 1f
+ st.d $ra, $a0, 184
+ st.d $s0, $a0, 200 #184+8+8
+ move $s0, $a0
+
+ la.global $t0, setjmp
+ jirl $ra, $t0, 0
+
+ move $a1, $a0 # Return from 'setjmp' or 'longjmp'
+ move $a0, $s0
+ ld.d $ra, $a0, 184
+ ld.d $s0, $a0, 200 #184+8+8
+
+.hidden __sigsetjmp_tail
+ la.global $t0, __sigsetjmp_tail
+ jr $t0
+1:
+ la.global $t0, setjmp
+ jr $t0
diff --git a/src/signal/mips64/restore.s b/src/signal/mips64/restore.s
deleted file mode 100644
index 401f8e73..00000000
--- a/src/signal/mips64/restore.s
+++ /dev/null
@@ -1,11 +0,0 @@
-.set noreorder
-.global __restore_rt
-.global __restore
-.hidden __restore_rt
-.hidden __restore
-.type __restore_rt,@function
-.type __restore,@function
-__restore_rt:
-__restore:
- li $2,5211
- syscall
diff --git a/src/signal/mipsn32/restore.s b/src/signal/mipsn32/restore.s
deleted file mode 100644
index 4cd4e1b4..00000000
--- a/src/signal/mipsn32/restore.s
+++ /dev/null
@@ -1,11 +0,0 @@
-.set noreorder
-.global __restore_rt
-.global __restore
-.hidden __restore_rt
-.hidden __restore
-.type __restore_rt,@function
-.type __restore,@function
-__restore_rt:
-__restore:
- li $2,6211
- syscall
diff --git a/src/signal/riscv32/restore.s b/src/signal/riscv32/restore.s
new file mode 100644
index 00000000..40012c75
--- /dev/null
+++ b/src/signal/riscv32/restore.s
@@ -0,0 +1,8 @@
+.global __restore
+.type __restore, %function
+__restore:
+.global __restore_rt
+.type __restore_rt, %function
+__restore_rt:
+ li a7, 139 # SYS_rt_sigreturn
+ ecall
diff --git a/src/signal/riscv32/sigsetjmp.s b/src/signal/riscv32/sigsetjmp.s
new file mode 100644
index 00000000..c1caeab1
--- /dev/null
+++ b/src/signal/riscv32/sigsetjmp.s
@@ -0,0 +1,23 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp, %function
+.type __sigsetjmp, %function
+sigsetjmp:
+__sigsetjmp:
+ bnez a1, 1f
+ tail setjmp
+1:
+
+ sw ra, 152(a0)
+ sw s0, 164(a0)
+ mv s0, a0
+
+ call setjmp
+
+ mv a1, a0
+ mv a0, s0
+ lw s0, 164(a0)
+ lw ra, 152(a0)
+
+.hidden __sigsetjmp_tail
+ tail __sigsetjmp_tail
diff --git a/src/signal/sh/sigsetjmp.s b/src/signal/sh/sigsetjmp.s
index 1e2270be..f0f604e2 100644
--- a/src/signal/sh/sigsetjmp.s
+++ b/src/signal/sh/sigsetjmp.s
@@ -27,7 +27,7 @@ __sigsetjmp:
mov.l 3f, r0
4: braf r0
- mov.l @(4+8,r4), r8
+ mov.l @(4+8,r6), r8
9: mov.l 5f, r0
6: braf r0
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
index 2203471b..e45308fa 100644
--- a/src/signal/sigaction.c
+++ b/src/signal/sigaction.c
@@ -44,8 +44,11 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact
}
}
ksa.handler = sa->sa_handler;
- ksa.flags = sa->sa_flags | SA_RESTORER;
+ ksa.flags = sa->sa_flags;
+#ifdef SA_RESTORER
+ ksa.flags |= SA_RESTORER;
ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
+#endif
memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
}
int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
index bc581050..92c9d1b0 100644
--- a/src/stat/fchmodat.c
+++ b/src/stat/fchmodat.c
@@ -5,13 +5,16 @@
int fchmodat(int fd, const char *path, mode_t mode, int flag)
{
- if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag);
+ if (!flag) return syscall(SYS_fchmodat, fd, path, mode);
+
+ int ret = __syscall(SYS_fchmodat2, fd, path, mode, flag);
+ if (ret != -ENOSYS) return __syscall_ret(ret);
if (flag != AT_SYMLINK_NOFOLLOW)
return __syscall_ret(-EINVAL);
struct stat st;
- int ret, fd2;
+ int fd2;
char proc[15+3*sizeof(int)];
if (fstatat(fd, path, &st, flag))
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index 04506375..9eed063b 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -36,6 +36,7 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric
{
struct statx stx;
+ flag |= AT_NO_AUTOMOUNT;
int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx);
if (ret) return ret;
diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c
index bfbb5fee..bc12da8b 100644
--- a/src/stat/statvfs.c
+++ b/src/stat/statvfs.c
@@ -39,6 +39,7 @@ static void fixup(struct statvfs *out, const struct statfs *in)
out->f_fsid = in->f_fsid.__val[0];
out->f_flag = in->f_flags;
out->f_namemax = in->f_namelen;
+ out->f_type = in->f_type;
}
int statvfs(const char *restrict path, struct statvfs *restrict buf)
diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c
index 080a4262..c64da405 100644
--- a/src/stdio/pclose.c
+++ b/src/stdio/pclose.c
@@ -7,7 +7,7 @@ int pclose(FILE *f)
int status, r;
pid_t pid = f->pipe_pid;
fclose(f);
- while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR);
+ while ((r=__sys_wait4(pid, &status, 0, 0)) == -EINTR);
if (r<0) return __syscall_ret(r);
return status;
}
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index 9b961e7f..497c5e19 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -52,7 +52,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = CHAR, S('C') = INT,
+ S('c') = INT, S('C') = UINT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -62,7 +62,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('c') = UINT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
@@ -132,7 +132,7 @@ static void pop_arg(union arg *arg, int type, va_list *ap)
static void out(FILE *f, const char *s, size_t l)
{
- if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
+ if (!ferror(f)) __fwritex((void *)s, l, f);
}
static void pad(FILE *f, char c, int w, int l, int fl)
@@ -437,7 +437,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
unsigned st, ps;
int cnt=0, l=0;
size_t i;
- char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+ char buf[sizeof(uintmax_t)*3];
const char *prefix;
int t, pl;
wchar_t wc[2], *ws;
@@ -478,8 +478,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
if (*s=='*') {
if (isdigit(s[1]) && s[2]=='$') {
l10n=1;
- nl_type[s[1]-'0'] = INT;
- w = nl_arg[s[1]-'0'].i;
+ if (!f) nl_type[s[1]-'0'] = INT, w = 0;
+ else w = nl_arg[s[1]-'0'].i;
s+=3;
} else if (!l10n) {
w = f ? va_arg(*ap, int) : 0;
@@ -491,8 +491,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
/* Read precision */
if (*s=='.' && s[1]=='*') {
if (isdigit(s[2]) && s[3]=='$') {
- nl_type[s[2]-'0'] = INT;
- p = nl_arg[s[2]-'0'].i;
+ if (!f) nl_type[s[2]-'0'] = INT, p = 0;
+ else p = nl_arg[s[2]-'0'].i;
s+=4;
} else if (!l10n) {
p = f ? va_arg(*ap, int) : 0;
@@ -521,13 +521,18 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
if (st==NOARG) {
if (argpos>=0) goto inval;
} else {
- if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
- else if (f) pop_arg(&arg, st, ap);
+ if (argpos>=0) {
+ if (!f) nl_type[argpos]=st;
+ else arg=nl_arg[argpos];
+ } else if (f) pop_arg(&arg, st, ap);
else return 0;
}
if (!f) continue;
+ /* Do not process any new directives once in error state. */
+ if (ferror(f)) return -1;
+
z = buf + sizeof(buf);
prefix = "-+ 0X0x";
pl = 0;
@@ -583,6 +588,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
}
p = MAX(p, z-a + !arg.i);
break;
+ narrow_c:
case 'c':
*(a=z-(p=1))=arg.i;
fl &= ~ZERO_PAD;
@@ -597,6 +603,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
fl &= ~ZERO_PAD;
break;
case 'C':
+ if (!arg.i) goto narrow_c;
wc[0] = arg.i;
wc[1] = 0;
arg.p = wc;
@@ -672,7 +679,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
FLOCK(f);
olderr = f->flags & F_ERR;
- if (f->mode < 1) f->flags &= ~F_ERR;
+ f->flags &= ~F_ERR;
if (!f->buf_size) {
saved_buf = f->buf;
f->buf = internal_buf;
@@ -688,7 +695,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
f->buf_size = 0;
f->wpos = f->wbase = f->wend = 0;
}
- if (f->flags & F_ERR) ret = -1;
+ if (ferror(f)) ret = -1;
f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c
index 85b036c3..59d5471b 100644
--- a/src/stdio/vfwprintf.c
+++ b/src/stdio/vfwprintf.c
@@ -45,7 +45,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = CHAR, S('C') = INT,
+ S('c') = INT, S('C') = UINT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -55,7 +55,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('c') = UINT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
@@ -125,7 +125,13 @@ static void pop_arg(union arg *arg, int type, va_list *ap)
static void out(FILE *f, const wchar_t *s, size_t l)
{
- while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f);
+ while (l-- && !ferror(f)) fputwc(*s++, f);
+}
+
+static void pad(FILE *f, int n, int fl)
+{
+ if ((fl & LEFT_ADJ) || !n || ferror(f)) return;
+ fprintf(f, "%*s", n, "");
}
static int getint(wchar_t **s) {
@@ -242,6 +248,10 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
}
if (!f) continue;
+
+ /* Do not process any new directives once in error state. */
+ if (ferror(f)) return -1;
+
t = s[-1];
if (ps && (t&15)==3) t&=~32;
@@ -258,25 +268,22 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
}
continue;
case 'c':
+ case 'C':
if (w<1) w=1;
- if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
- fputwc(btowc(arg.i), f);
- if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
+ pad(f, w-1, fl);
+ out(f, &(wchar_t){t=='C' ? arg.i : btowc(arg.i)}, 1);
+ pad(f, w-1, fl^LEFT_ADJ);
l = w;
continue;
- case 'C':
- fputwc(arg.i, f);
- l = 1;
- continue;
case 'S':
a = arg.p;
z = a + wcsnlen(a, p<0 ? INT_MAX : p);
if (p<0 && *z) goto overflow;
p = z-a;
if (w<p) w=p;
- if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ pad(f, w-p, fl);
out(f, a, p);
- if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ pad(f, w-p, fl^LEFT_ADJ);
l=w;
continue;
case 'm':
@@ -289,14 +296,14 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
if (p<0 && *bs) goto overflow;
p=l;
if (w<p) w=p;
- if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ pad(f, w-p, fl);
bs = arg.p;
while (l--) {
i=mbtowc(&wc, bs, MB_LEN_MAX);
bs+=i;
- fputwc(wc, f);
+ out(f, &wc, 1);
}
- if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ pad(f, w-p, fl^LEFT_ADJ);
l=w;
continue;
}
@@ -340,8 +347,8 @@ overflow:
int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
{
va_list ap2;
- int nl_type[NL_ARGMAX] = {0};
- union arg nl_arg[NL_ARGMAX];
+ int nl_type[NL_ARGMAX+1] = {0};
+ union arg nl_arg[NL_ARGMAX+1];
int olderr;
int ret;
@@ -357,7 +364,7 @@ int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
olderr = f->flags & F_ERR;
f->flags &= ~F_ERR;
ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
- if (f->flags & F_ERR) ret = -1;
+ if (ferror(f)) ret = -1;
f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c
index b3510a63..409b9c85 100644
--- a/src/stdio/vsnprintf.c
+++ b/src/stdio/vsnprintf.c
@@ -45,11 +45,6 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
.cookie = &c,
};
- if (n > INT_MAX) {
- errno = EOVERFLOW;
- return -1;
- }
-
*c.s = 0;
return vfprintf(&f, fmt, ap);
}
diff --git a/src/stdio/vswprintf.c b/src/stdio/vswprintf.c
index 7f98c5c9..5e9a4dad 100644
--- a/src/stdio/vswprintf.c
+++ b/src/stdio/vswprintf.c
@@ -18,6 +18,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l)
if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1)
return -1;
while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) {
+ if (!i) i=1;
s+=i;
l-=i;
c->l--;
@@ -50,9 +51,6 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis
if (!n) {
return -1;
- } else if (n > INT_MAX) {
- errno = EOVERFLOW;
- return -1;
}
r = vfwprintf(&f, fmt, ap);
sw_write(&f, 0, 0);
diff --git a/src/string/strverscmp.c b/src/string/strverscmp.c
index 4daf276d..16c1da22 100644
--- a/src/string/strverscmp.c
+++ b/src/string/strverscmp.c
@@ -18,9 +18,9 @@ int strverscmp(const char *l0, const char *r0)
else if (c!='0') z=0;
}
- if (l[dp]!='0' && r[dp]!='0') {
- /* If we're not looking at a digit sequence that began
- * with a zero, longest digit string is greater. */
+ if (l[dp]-'1'<9U && r[dp]-'1'<9U) {
+ /* If we're looking at non-degenerate digit sequences starting
+ * with nonzero digits, longest digit string is greater. */
for (j=i; isdigit(l[j]); j++)
if (!isdigit(r[j])) return 1;
if (isdigit(r[j])) return -1;
diff --git a/src/string/wcscmp.c b/src/string/wcscmp.c
index 26eeee70..286ec3ea 100644
--- a/src/string/wcscmp.c
+++ b/src/string/wcscmp.c
@@ -3,5 +3,5 @@
int wcscmp(const wchar_t *l, const wchar_t *r)
{
for (; *l==*r && *l && *r; l++, r++);
- return *l - *r;
+ return *l < *r ? -1 : *l > *r;
}
diff --git a/src/string/wcsncmp.c b/src/string/wcsncmp.c
index 4ab32a92..2b3558bf 100644
--- a/src/string/wcsncmp.c
+++ b/src/string/wcsncmp.c
@@ -3,5 +3,5 @@
int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n)
{
for (; n && *l==*r && *l && *r; n--, l++, r++);
- return n ? *l - *r : 0;
+ return n ? (*l < *r ? -1 : *l > *r) : 0;
}
diff --git a/src/string/wmemcmp.c b/src/string/wmemcmp.c
index 2a193263..717d77b1 100644
--- a/src/string/wmemcmp.c
+++ b/src/string/wmemcmp.c
@@ -3,5 +3,5 @@
int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
{
for (; n && *l==*r; n--, l++, r++);
- return n ? *l-*r : 0;
+ return n ? (*l < *r ? -1 : *l > *r) : 0;
}
diff --git a/src/thread/loongarch64/__set_thread_area.s b/src/thread/loongarch64/__set_thread_area.s
new file mode 100644
index 00000000..021307fc
--- /dev/null
+++ b/src/thread/loongarch64/__set_thread_area.s
@@ -0,0 +1,7 @@
+.global __set_thread_area
+.hidden __set_thread_area
+.type __set_thread_area,@function
+__set_thread_area:
+ move $tp, $a0
+ move $a0, $zero
+ jr $ra
diff --git a/src/thread/loongarch64/__unmapself.s b/src/thread/loongarch64/__unmapself.s
new file mode 100644
index 00000000..719ad056
--- /dev/null
+++ b/src/thread/loongarch64/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type __unmapself, @function
+__unmapself:
+ li.d $a7, 215 # call munmap
+ syscall 0
+ li.d $a7, 93 # call exit
+ syscall 0
diff --git a/src/thread/loongarch64/clone.s b/src/thread/loongarch64/clone.s
new file mode 100644
index 00000000..a165b365
--- /dev/null
+++ b/src/thread/loongarch64/clone.s
@@ -0,0 +1,29 @@
+#__clone(func, stack, flags, arg, ptid, tls, ctid)
+# a0, a1, a2, a3, a4, a5, a6
+# sys_clone(flags, stack, ptid, ctid, tls)
+# a0, a1, a2, a3, a4
+
+.global __clone
+.hidden __clone
+.type __clone,@function
+__clone:
+ bstrins.d $a1, $zero, 3, 0 #stack to 16 align
+ # Save function pointer and argument pointer on new thread stack
+ addi.d $a1, $a1, -16
+ st.d $a0, $a1, 0 # save function pointer
+ st.d $a3, $a1, 8 # save argument pointer
+ or $a0, $a2, $zero
+ or $a2, $a4, $zero
+ or $a3, $a6, $zero
+ or $a4, $a5, $zero
+ ori $a7, $zero, 220
+ syscall 0 # call clone
+
+ beqz $a0, 1f # whether child process
+ jirl $zero, $ra, 0 # parent process return
+1:
+ ld.d $t8, $sp, 0 # function pointer
+ ld.d $a0, $sp, 8 # argument pointer
+ jirl $ra, $t8, 0 # call the user's function
+ ori $a7, $zero, 93
+ syscall 0 # child process exit
diff --git a/src/thread/loongarch64/syscall_cp.s b/src/thread/loongarch64/syscall_cp.s
new file mode 100644
index 00000000..c057a97b
--- /dev/null
+++ b/src/thread/loongarch64/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type __syscall_cp_asm,@function
+
+__syscall_cp_asm:
+__cp_begin:
+ ld.w $a0, $a0, 0
+ bnez $a0, __cp_cancel
+ move $t8, $a1 # reserve system call number
+ move $a0, $a2
+ move $a1, $a3
+ move $a2, $a4
+ move $a3, $a5
+ move $a4, $a6
+ move $a5, $a7
+ move $a7, $t8
+ syscall 0
+__cp_end:
+ jr $ra
+__cp_cancel:
+ la.local $t8, __cancel
+ jr $t8
diff --git a/src/thread/pthread_atfork.c b/src/thread/pthread_atfork.c
index 76497401..26d32543 100644
--- a/src/thread/pthread_atfork.c
+++ b/src/thread/pthread_atfork.c
@@ -1,7 +1,13 @@
#include <pthread.h>
+#include <errno.h>
#include "libc.h"
#include "lock.h"
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
+
static struct atfork_funcs {
void (*prepare)(void);
void (*parent)(void);
@@ -34,7 +40,7 @@ void __fork_handler(int who)
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
struct atfork_funcs *new = malloc(sizeof *new);
- if (!new) return -1;
+ if (!new) return ENOMEM;
LOCK(lock);
new->next = funcs;
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
index 2d3a98ea..139a6fc8 100644
--- a/src/thread/pthread_cancel.c
+++ b/src/thread/pthread_cancel.c
@@ -56,7 +56,12 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
_sigaddset(&uc->uc_sigmask, SIGCANCEL);
- if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {
+ if (self->cancelasync) {
+ pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0);
+ __cancel();
+ }
+
+ if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {
uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel;
#ifdef CANCEL_GOT
uc->uc_mcontext.MC_GOT = CANCEL_GOT;
diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c
index 77772af2..d73a500e 100644
--- a/src/thread/pthread_detach.c
+++ b/src/thread/pthread_detach.c
@@ -5,8 +5,12 @@ static int __pthread_detach(pthread_t t)
{
/* If the cas fails, detach state is either already-detached
* or exiting/exited, and pthread_join will trap or cleanup. */
- if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE)
- return __pthread_join(t, 0);
+ if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) {
+ int cs;
+ __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+ __pthread_join(t, 0);
+ __pthread_setcancelstate(cs, 0);
+ }
return 0;
}
diff --git a/src/thread/riscv32/__set_thread_area.s b/src/thread/riscv32/__set_thread_area.s
new file mode 100644
index 00000000..828154d2
--- /dev/null
+++ b/src/thread/riscv32/__set_thread_area.s
@@ -0,0 +1,6 @@
+.global __set_thread_area
+.type __set_thread_area, %function
+__set_thread_area:
+ mv tp, a0
+ li a0, 0
+ ret
diff --git a/src/thread/riscv32/__unmapself.s b/src/thread/riscv32/__unmapself.s
new file mode 100644
index 00000000..2849119c
--- /dev/null
+++ b/src/thread/riscv32/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type __unmapself, %function
+__unmapself:
+ li a7, 215 # SYS_munmap
+ ecall
+ li a7, 93 # SYS_exit
+ ecall
diff --git a/src/thread/riscv32/clone.s b/src/thread/riscv32/clone.s
new file mode 100644
index 00000000..3102239d
--- /dev/null
+++ b/src/thread/riscv32/clone.s
@@ -0,0 +1,34 @@
+# __clone(func, stack, flags, arg, ptid, tls, ctid)
+# a0, a1, a2, a3, a4, a5, a6
+
+# syscall(SYS_clone, flags, stack, ptid, tls, ctid)
+# a7 a0, a1, a2, a3, a4
+
+.global __clone
+.type __clone, %function
+__clone:
+ # Save func and arg to stack
+ addi a1, a1, -16
+ sw a0, 0(a1)
+ sw a3, 4(a1)
+
+ # Call SYS_clone
+ mv a0, a2
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ li a7, 220 # SYS_clone
+ ecall
+
+ beqz a0, 1f
+ # Parent
+ ret
+
+ # Child
+1: lw a1, 0(sp)
+ lw a0, 4(sp)
+ jalr a1
+
+ # Exit
+ li a7, 93 # SYS_exit
+ ecall
diff --git a/src/thread/riscv32/syscall_cp.s b/src/thread/riscv32/syscall_cp.s
new file mode 100644
index 00000000..079d1ba0
--- /dev/null
+++ b/src/thread/riscv32/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type __syscall_cp_asm, %function
+__syscall_cp_asm:
+__cp_begin:
+ lw t0, 0(a0)
+ bnez t0, __cp_cancel
+
+ mv t0, a1
+ mv a0, a2
+ mv a1, a3
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ mv a5, a7
+ lw a6, 0(sp)
+ mv a7, t0
+ ecall
+__cp_end:
+ ret
+__cp_cancel:
+ tail __cancel
diff --git a/src/thread/sem_getvalue.c b/src/thread/sem_getvalue.c
index d9d83071..c0b7762d 100644
--- a/src/thread/sem_getvalue.c
+++ b/src/thread/sem_getvalue.c
@@ -1,8 +1,9 @@
#include <semaphore.h>
+#include <limits.h>
int sem_getvalue(sem_t *restrict sem, int *restrict valp)
{
int val = sem->__val[0];
- *valp = val < 0 ? 0 : val;
+ *valp = val & SEM_VALUE_MAX;
return 0;
}
diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c
index 31e3293d..5c2517f2 100644
--- a/src/thread/sem_post.c
+++ b/src/thread/sem_post.c
@@ -1,17 +1,21 @@
#include <semaphore.h>
+#include <limits.h>
#include "pthread_impl.h"
int sem_post(sem_t *sem)
{
- int val, waiters, priv = sem->__val[2];
+ int val, new, waiters, priv = sem->__val[2];
do {
val = sem->__val[0];
waiters = sem->__val[1];
- if (val == SEM_VALUE_MAX) {
+ if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) {
errno = EOVERFLOW;
return -1;
}
- } while (a_cas(sem->__val, val, val+1+(val<0)) != val);
- if (val<0 || waiters) __wake(sem->__val, 1, priv);
+ new = val + 1;
+ if (waiters <= 1)
+ new &= ~0x80000000;
+ } while (a_cas(sem->__val, val, new) != val);
+ if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv);
return 0;
}
diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
index 58d3ebfe..aa67376c 100644
--- a/src/thread/sem_timedwait.c
+++ b/src/thread/sem_timedwait.c
@@ -1,4 +1,5 @@
#include <semaphore.h>
+#include <limits.h>
#include "pthread_impl.h"
static void cleanup(void *p)
@@ -13,14 +14,15 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
if (!sem_trywait(sem)) return 0;
int spins = 100;
- while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin();
+ while (spins-- && !(sem->__val[0] & SEM_VALUE_MAX) && !sem->__val[1])
+ a_spin();
while (sem_trywait(sem)) {
- int r;
+ int r, priv = sem->__val[2];
a_inc(sem->__val+1);
- a_cas(sem->__val, 0, -1);
+ a_cas(sem->__val, 0, 0x80000000);
pthread_cleanup_push(cleanup, (void *)(sem->__val+1));
- r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]);
+ r = __timedwait_cp(sem->__val, 0x80000000, CLOCK_REALTIME, at, priv);
pthread_cleanup_pop(1);
if (r) {
errno = r;
diff --git a/src/thread/sem_trywait.c b/src/thread/sem_trywait.c
index 04edf46b..beb435da 100644
--- a/src/thread/sem_trywait.c
+++ b/src/thread/sem_trywait.c
@@ -1,12 +1,12 @@
#include <semaphore.h>
+#include <limits.h>
#include "pthread_impl.h"
int sem_trywait(sem_t *sem)
{
int val;
- while ((val=sem->__val[0]) > 0) {
- int new = val-1-(val==1 && sem->__val[1]);
- if (a_cas(sem->__val, val, new)==val) return 0;
+ while ((val=sem->__val[0]) & SEM_VALUE_MAX) {
+ if (a_cas(sem->__val, val, val-1)==val) return 0;
}
errno = EAGAIN;
return -1;
diff --git a/src/thread/synccall.c b/src/thread/synccall.c
index a6b177c0..38597254 100644
--- a/src/thread/synccall.c
+++ b/src/thread/synccall.c
@@ -11,7 +11,7 @@ weak_alias(dummy_0, __tl_unlock);
static int target_tid;
static void (*callback)(void *), *context;
-static sem_t target_sem, caller_sem;
+static sem_t target_sem, caller_sem, exit_sem;
static void dummy(void *p)
{
@@ -33,7 +33,7 @@ static void handler(int sig)
/* Inform caller we've complered the callback and wait
* for the caller to release us to return. */
sem_post(&caller_sem);
- sem_wait(&target_sem);
+ sem_wait(&exit_sem);
/* Inform caller we are returning and state is destroyable. */
sem_post(&caller_sem);
@@ -62,6 +62,7 @@ void __synccall(void (*func)(void *), void *ctx)
sem_init(&target_sem, 0, 0);
sem_init(&caller_sem, 0, 0);
+ sem_init(&exit_sem, 0, 0);
if (!libc.threads_minus_1 || __syscall(SYS_gettid) != self->tid)
goto single_threaded;
@@ -107,12 +108,13 @@ single_threaded:
/* Only release the caught threads once all threads, including the
* caller, have returned from the callback function. */
for (i=0; i<count; i++)
- sem_post(&target_sem);
+ sem_post(&exit_sem);
for (i=0; i<count; i++)
sem_wait(&caller_sem);
sem_destroy(&caller_sem);
sem_destroy(&target_sem);
+ sem_destroy(&exit_sem);
pthread_setcancelstate(cs, 0);
__tl_unlock();
diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c
index 2824ec6d..b42f5a6d 100644
--- a/src/time/__year_to_secs.c
+++ b/src/time/__year_to_secs.c
@@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap)
return 31536000*(y-70) + 86400*leaps;
}
- int cycles, centuries, leaps, rem;
+ int cycles, centuries, leaps, rem, dummy;
- if (!is_leap) is_leap = &(int){0};
+ if (!is_leap) is_leap = &dummy;
cycles = (year-100) / 400;
rem = (year-100) % 400;
if (rem < 0) {
diff --git a/src/time/strftime.c b/src/time/strftime.c
index cc53d536..c40246db 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <langinfo.h>
#include <locale.h>
+#include <ctype.h>
#include <time.h>
#include <limits.h>
#include "locale_impl.h"
@@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
- width = strtoul(f, &p, 10);
+ if (isdigit(*f)) {
+ width = strtoul(f, &p, 10);
+ } else {
+ width = 0;
+ p = (void *)f;
+ }
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
diff --git a/src/time/timer_create.c b/src/time/timer_create.c
index cd32c945..9216b3ab 100644
--- a/src/time/timer_create.c
+++ b/src/time/timer_create.c
@@ -61,7 +61,7 @@ static void *start(void *arg)
int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)
{
- volatile static int init = 0;
+ static volatile int init = 0;
pthread_t td;
pthread_attr_t attr;
int r;
diff --git a/src/unistd/dup3.c b/src/unistd/dup3.c
index f919f791..40798bde 100644
--- a/src/unistd/dup3.c
+++ b/src/unistd/dup3.c
@@ -9,12 +9,14 @@ int __dup3(int old, int new, int flags)
int r;
#ifdef SYS_dup2
if (old==new) return __syscall_ret(-EINVAL);
- if (flags & O_CLOEXEC) {
+ if (flags) {
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
if (r!=-ENOSYS) return __syscall_ret(r);
+ if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL);
}
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
- if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
+ if (r >= 0 && (flags & O_CLOEXEC))
+ __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
#else
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
#endif
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
index 557503eb..43052dd7 100644
--- a/src/unistd/faccessat.c
+++ b/src/unistd/faccessat.c
@@ -53,7 +53,7 @@ int faccessat(int fd, const char *filename, int amode, int flag)
if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
ret = -EBUSY;
__syscall(SYS_close, p[0]);
- __syscall(SYS_wait4, pid, &status, __WCLONE, 0);
+ __sys_wait4(pid, &status, __WCLONE, 0);
__restore_sigs(&set);
diff --git a/src/unistd/pipe2.c b/src/unistd/pipe2.c
index f24f74fb..a096990b 100644
--- a/src/unistd/pipe2.c
+++ b/src/unistd/pipe2.c
@@ -8,6 +8,7 @@ int pipe2(int fd[2], int flag)
if (!flag) return pipe(fd);
int ret = __syscall(SYS_pipe2, fd, flag);
if (ret != -ENOSYS) return __syscall_ret(ret);
+ if (flag & ~(O_CLOEXEC|O_NONBLOCK)) return __syscall_ret(-EINVAL);
ret = pipe(fd);
if (ret) return ret;
if (flag & O_CLOEXEC) {
diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c
index 869b69f0..a008b3ec 100644
--- a/src/unistd/pwrite.c
+++ b/src/unistd/pwrite.c
@@ -1,7 +1,18 @@
+#define _GNU_SOURCE
#include <unistd.h>
+#include <sys/uio.h>
+#include <fcntl.h>
#include "syscall.h"
ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
{
+ if (ofs == -1) ofs--;
+ int r = __syscall_cp(SYS_pwritev2, fd,
+ (&(struct iovec){ .iov_base = (void *)buf, .iov_len = size }),
+ 1, (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND);
+ if (r != -EOPNOTSUPP && r != -ENOSYS)
+ return __syscall_ret(r);
+ if (fcntl(fd, F_GETFL) & O_APPEND)
+ return __syscall_ret(-EOPNOTSUPP);
return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL_PRW(ofs));
}
diff --git a/src/unistd/pwritev.c b/src/unistd/pwritev.c
index becf9deb..44a53d85 100644
--- a/src/unistd/pwritev.c
+++ b/src/unistd/pwritev.c
@@ -1,10 +1,18 @@
-#define _BSD_SOURCE
+#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
+#include <fcntl.h>
#include "syscall.h"
ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs)
{
+ if (ofs == -1) ofs--;
+ int r = __syscall_cp(SYS_pwritev2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND);
+ if (r != -EOPNOTSUPP && r != -ENOSYS)
+ return __syscall_ret(r);
+ if (fcntl(fd, F_GETFL) & O_APPEND)
+ return __syscall_ret(-EOPNOTSUPP);
return syscall_cp(SYS_pwritev, fd, iov, count,
(long)(ofs), (long)(ofs>>32));
}
diff --git a/src/unistd/setxid.c b/src/unistd/setxid.c
index 487c1a16..a629ed4b 100644
--- a/src/unistd/setxid.c
+++ b/src/unistd/setxid.c
@@ -30,5 +30,5 @@ int __setxid(int nr, int id, int eid, int sid)
* trigger the safety kill above. */
struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .ret = 1 };
__synccall(do_setxid, &c);
- return __syscall_ret(c.ret);
+ return __syscall_ret(c.ret > 0 ? -EAGAIN : c.ret);
}