summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compat/time32/__xstat.c24
-rw-r--r--compat/time32/adjtime32.c21
-rw-r--r--compat/time32/adjtimex_time32.c10
-rw-r--r--compat/time32/aio_suspend_time32.c11
-rw-r--r--compat/time32/clock_adjtime32.c70
-rw-r--r--compat/time32/clock_getres_time32.c13
-rw-r--r--compat/time32/clock_gettime32.c18
-rw-r--r--compat/time32/clock_nanosleep_time32.c15
-rw-r--r--compat/time32/clock_settime32.c9
-rw-r--r--compat/time32/cnd_timedwait_time32.c9
-rw-r--r--compat/time32/ctime32.c7
-rw-r--r--compat/time32/ctime32_r.c7
-rw-r--r--compat/time32/difftime32.c7
-rw-r--r--compat/time32/fstat_time32.c17
-rw-r--r--compat/time32/fstatat_time32.c17
-rw-r--r--compat/time32/ftime32.c25
-rw-r--r--compat/time32/futimens_time32.c10
-rw-r--r--compat/time32/futimes_time32.c12
-rw-r--r--compat/time32/futimesat_time32.c12
-rw-r--r--compat/time32/getitimer_time32.c15
-rw-r--r--compat/time32/getrusage_time32.c39
-rw-r--r--compat/time32/gettimeofday_time32.c19
-rw-r--r--compat/time32/gmtime32.c7
-rw-r--r--compat/time32/gmtime32_r.c7
-rw-r--r--compat/time32/localtime32.c7
-rw-r--r--compat/time32/localtime32_r.c7
-rw-r--r--compat/time32/lstat_time32.c17
-rw-r--r--compat/time32/lutimes_time32.c12
-rw-r--r--compat/time32/mktime32.c16
-rw-r--r--compat/time32/mq_timedreceive_time32.c9
-rw-r--r--compat/time32/mq_timedsend_time32.c9
-rw-r--r--compat/time32/mtx_timedlock_time32.c9
-rw-r--r--compat/time32/nanosleep_time32.c15
-rw-r--r--compat/time32/ppoll_time32.c10
-rw-r--r--compat/time32/pselect_time32.c9
-rw-r--r--compat/time32/pthread_cond_timedwait_time32.c9
-rw-r--r--compat/time32/pthread_mutex_timedlock_time32.c9
-rw-r--r--compat/time32/pthread_rwlock_timedrdlock_time32.c9
-rw-r--r--compat/time32/pthread_rwlock_timedwrlock_time32.c9
-rw-r--r--compat/time32/pthread_timedjoin_np_time32.c10
-rw-r--r--compat/time32/recvmmsg_time32.c10
-rw-r--r--compat/time32/sched_rr_get_interval_time32.c13
-rw-r--r--compat/time32/select_time32.c10
-rw-r--r--compat/time32/sem_timedwait_time32.c9
-rw-r--r--compat/time32/semtimedop_time32.c10
-rw-r--r--compat/time32/setitimer_time32.c23
-rw-r--r--compat/time32/settimeofday_time32.c10
-rw-r--r--compat/time32/sigtimedwait_time32.c9
-rw-r--r--compat/time32/stat_time32.c17
-rw-r--r--compat/time32/stime32.c8
-rw-r--r--compat/time32/thrd_sleep_time32.c16
-rw-r--r--compat/time32/time32.c15
-rw-r--r--compat/time32/time32.h91
-rw-r--r--compat/time32/time32gm.c15
-rw-r--r--compat/time32/timer_gettime32.c15
-rw-r--r--compat/time32/timer_settime32.c25
-rw-r--r--compat/time32/timerfd_gettime32.c16
-rw-r--r--compat/time32/timerfd_settime32.c26
-rw-r--r--compat/time32/timespec_get_time32.c18
-rw-r--r--compat/time32/utime_time32.c14
-rw-r--r--compat/time32/utimensat_time32.c11
-rw-r--r--compat/time32/utimes_time32.c11
-rw-r--r--compat/time32/wait3_time32.c40
-rw-r--r--compat/time32/wait4_time32.c40
64 files changed, 1039 insertions, 0 deletions
diff --git a/compat/time32/__xstat.c b/compat/time32/__xstat.c
new file mode 100644
index 00000000..acfbd3cc
--- /dev/null
+++ b/compat/time32/__xstat.c
@@ -0,0 +1,24 @@
+#include "time32.h"
+#include <sys/stat.h>
+
+struct stat32;
+
+int __fxstat64(int ver, int fd, struct stat32 *buf)
+{
+ return __fstat_time32(fd, buf);
+}
+
+int __fxstatat64(int ver, int fd, const char *path, struct stat32 *buf, int flag)
+{
+ return __fstatat_time32(fd, path, buf, flag);
+}
+
+int __lxstat64(int ver, const char *path, struct stat32 *buf)
+{
+ return __lstat_time32(path, buf);
+}
+
+int __xstat64(int ver, const char *path, struct stat32 *buf)
+{
+ return __stat_time32(path, buf);
+}
diff --git a/compat/time32/adjtime32.c b/compat/time32/adjtime32.c
new file mode 100644
index 00000000..b0042c63
--- /dev/null
+++ b/compat/time32/adjtime32.c
@@ -0,0 +1,21 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+
+int __adjtime32(const struct timeval32 *in32, struct timeval32 *out32)
+{
+ struct timeval out;
+ int r = adjtime((&(struct timeval){
+ .tv_sec = in32->tv_sec,
+ .tv_usec = in32->tv_usec}), &out);
+ if (r) return r;
+ /* We can't range-check the result because success was already
+ * committed by the above call. */
+ if (out32) {
+ out32->tv_sec = out.tv_sec;
+ out32->tv_usec = out.tv_usec;
+ }
+ return r;
+}
diff --git a/compat/time32/adjtimex_time32.c b/compat/time32/adjtimex_time32.c
new file mode 100644
index 00000000..9c6f190a
--- /dev/null
+++ b/compat/time32/adjtimex_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timex.h>
+
+struct timex32;
+
+int __adjtimex_time32(struct timex32 *tx32)
+{
+ return __clock_adjtime32(CLOCK_REALTIME, tx32);
+}
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
new file mode 100644
index 00000000..ed5119bd
--- /dev/null
+++ b/compat/time32/aio_suspend_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <aio.h>
+
+int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct timespec32 *ts32)
+{
+ return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
+
+weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/clock_adjtime32.c b/compat/time32/clock_adjtime32.c
new file mode 100644
index 00000000..5a25b8ac
--- /dev/null
+++ b/compat/time32/clock_adjtime32.c
@@ -0,0 +1,70 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <string.h>
+#include <stddef.h>
+
+struct timex32 {
+ unsigned modes;
+ long offset, freq, maxerror, esterror;
+ int status;
+ long constant, precision, tolerance;
+ struct timeval32 time;
+ long tick, ppsfreq, jitter;
+ int shift;
+ long stabil, jitcnt, calcnt, errcnt, stbcnt;
+ int tai;
+ int __padding[11];
+};
+
+int __clock_adjtime32(clockid_t clock_id, struct timex32 *tx32)
+{
+ struct timex utx = {
+ .modes = tx32->modes,
+ .offset = tx32->offset,
+ .freq = tx32->freq,
+ .maxerror = tx32->maxerror,
+ .esterror = tx32->esterror,
+ .status = tx32->status,
+ .constant = tx32->constant,
+ .precision = tx32->precision,
+ .tolerance = tx32->tolerance,
+ .time.tv_sec = tx32->time.tv_sec,
+ .time.tv_usec = tx32->time.tv_usec,
+ .tick = tx32->tick,
+ .ppsfreq = tx32->ppsfreq,
+ .jitter = tx32->jitter,
+ .shift = tx32->shift,
+ .stabil = tx32->stabil,
+ .jitcnt = tx32->jitcnt,
+ .calcnt = tx32->calcnt,
+ .errcnt = tx32->errcnt,
+ .stbcnt = tx32->stbcnt,
+ .tai = tx32->tai,
+ };
+ int r = clock_adjtime(clock_id, &utx);
+ if (r<0) return r;
+ tx32->modes = utx.modes;
+ tx32->offset = utx.offset;
+ tx32->freq = utx.freq;
+ tx32->maxerror = utx.maxerror;
+ tx32->esterror = utx.esterror;
+ tx32->status = utx.status;
+ tx32->constant = utx.constant;
+ tx32->precision = utx.precision;
+ tx32->tolerance = utx.tolerance;
+ tx32->time.tv_sec = utx.time.tv_sec;
+ tx32->time.tv_usec = utx.time.tv_usec;
+ tx32->tick = utx.tick;
+ tx32->ppsfreq = utx.ppsfreq;
+ tx32->jitter = utx.jitter;
+ tx32->shift = utx.shift;
+ tx32->stabil = utx.stabil;
+ tx32->jitcnt = utx.jitcnt;
+ tx32->calcnt = utx.calcnt;
+ tx32->errcnt = utx.errcnt;
+ tx32->stbcnt = utx.stbcnt;
+ tx32->tai = utx.tai;
+ return r;
+}
diff --git a/compat/time32/clock_getres_time32.c b/compat/time32/clock_getres_time32.c
new file mode 100644
index 00000000..47a24c13
--- /dev/null
+++ b/compat/time32/clock_getres_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_getres_time32(clockid_t clk, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = clock_getres(clk, &ts);
+ if (!r && ts32) {
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ }
+ return r;
+}
diff --git a/compat/time32/clock_gettime32.c b/compat/time32/clock_gettime32.c
new file mode 100644
index 00000000..0cac7bbd
--- /dev/null
+++ b/compat/time32/clock_gettime32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __clock_gettime32(clockid_t clk, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = clock_gettime(clk, &ts);
+ if (r) return r;
+ if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return 0;
+}
diff --git a/compat/time32/clock_nanosleep_time32.c b/compat/time32/clock_nanosleep_time32.c
new file mode 100644
index 00000000..91ef067d
--- /dev/null
+++ b/compat/time32/clock_nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __clock_nanosleep_time32(clockid_t clk, int flags, const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = clock_nanosleep(clk, flags, (&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret==EINTR && rem32 && !(flags & TIMER_ABSTIME)) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/compat/time32/clock_settime32.c b/compat/time32/clock_settime32.c
new file mode 100644
index 00000000..7ca4f0e9
--- /dev/null
+++ b/compat/time32/clock_settime32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_settime32(clockid_t clk, const struct timespec32 *ts32)
+{
+ return clock_settime(clk, (&(struct timespec){
+ .tv_sec = ts32->tv_sec,
+ .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/cnd_timedwait_time32.c b/compat/time32/cnd_timedwait_time32.c
new file mode 100644
index 00000000..314251d1
--- /dev/null
+++ b/compat/time32/cnd_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __cnd_timedwait_time32(cnd_t *restrict c, mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return cnd_timedwait(c, m, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/ctime32.c b/compat/time32/ctime32.c
new file mode 100644
index 00000000..a057274e
--- /dev/null
+++ b/compat/time32/ctime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32(time32_t *t)
+{
+ return ctime(&(time_t){*t});
+}
diff --git a/compat/time32/ctime32_r.c b/compat/time32/ctime32_r.c
new file mode 100644
index 00000000..e1ad2e28
--- /dev/null
+++ b/compat/time32/ctime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32_r(time32_t *t, char *buf)
+{
+ return ctime_r(&(time_t){*t}, buf);
+}
diff --git a/compat/time32/difftime32.c b/compat/time32/difftime32.c
new file mode 100644
index 00000000..5950943a
--- /dev/null
+++ b/compat/time32/difftime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+double __difftime32(time32_t t1, time32_t t2)
+{
+ return difftime(t1, t2);
+}
diff --git a/compat/time32/fstat_time32.c b/compat/time32/fstat_time32.c
new file mode 100644
index 00000000..3e084398
--- /dev/null
+++ b/compat/time32/fstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstat_time32(int fd, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = fstat(fd, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(fstat, fstat64);
diff --git a/compat/time32/fstatat_time32.c b/compat/time32/fstatat_time32.c
new file mode 100644
index 00000000..85dcb008
--- /dev/null
+++ b/compat/time32/fstatat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict st32, int flag)
+{
+ struct stat st;
+ int r = fstatat(fd, path, &st, flag);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(fstatat, fstatat64);
diff --git a/compat/time32/ftime32.c b/compat/time32/ftime32.c
new file mode 100644
index 00000000..166a6dae
--- /dev/null
+++ b/compat/time32/ftime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include <sys/timeb.h>
+#include <errno.h>
+#include <stdint.h>
+
+struct timeb32 {
+ int32_t time;
+ unsigned short millitm;
+ short timezone, dstflag;
+};
+
+int __ftime32(struct timeb32 *tp)
+{
+ struct timeb tb;
+ if (ftime(&tb) < 0) return -1;
+ if (tb.time < INT32_MIN || tb.time > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tp->time = tb.time;
+ tp->millitm = tb.millitm;
+ tp->timezone = tb.timezone;
+ tp->dstflag = tb.dstflag;
+ return 0;
+}
diff --git a/compat/time32/futimens_time32.c b/compat/time32/futimens_time32.c
new file mode 100644
index 00000000..7856f176
--- /dev/null
+++ b/compat/time32/futimens_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __futimens_time32(int fd, const struct timespec32 *times32)
+{
+ return futimens(fd, !times32 ? 0 : ((struct timespec[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+ {.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}));
+}
diff --git a/compat/time32/futimes_time32.c b/compat/time32/futimes_time32.c
new file mode 100644
index 00000000..f29533f1
--- /dev/null
+++ b/compat/time32/futimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimes_time32(int fd, const struct timeval32 times32[2])
+{
+ return futimes(fd, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/futimesat_time32.c b/compat/time32/futimesat_time32.c
new file mode 100644
index 00000000..5a1295bd
--- /dev/null
+++ b/compat/time32/futimesat_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimesat_time32(int dirfd, const char *pathname, const struct timeval32 times32[2])
+{
+ return futimesat(dirfd, pathname, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/getitimer_time32.c b/compat/time32/getitimer_time32.c
new file mode 100644
index 00000000..4bac4bf5
--- /dev/null
+++ b/compat/time32/getitimer_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __getitimer_time32(int which, struct itimerval32 *old32)
+{
+ struct itimerval old;
+ int r = getitimer(which, &old);
+ if (r) return r;
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_usec = old.it_interval.tv_usec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_usec = old.it_value.tv_usec;
+ return 0;
+}
diff --git a/compat/time32/getrusage_time32.c b/compat/time32/getrusage_time32.c
new file mode 100644
index 00000000..d7487dee
--- /dev/null
+++ b/compat/time32/getrusage_time32.c
@@ -0,0 +1,39 @@
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/resource.h>
+
+struct compat_rusage {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+int __getrusage_time32(int who, struct compat_rusage *usage)
+{
+ struct rusage ru;
+ int r = getrusage(who, &ru);
+ if (!r) {
+ usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+ usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+ usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+ usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+ memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+ sizeof(struct compat_rusage) -
+ offsetof(struct compat_rusage, ru_maxrss));
+ }
+ return r;
+}
diff --git a/compat/time32/gettimeofday_time32.c b/compat/time32/gettimeofday_time32.c
new file mode 100644
index 00000000..1f3ce68e
--- /dev/null
+++ b/compat/time32/gettimeofday_time32.c
@@ -0,0 +1,19 @@
+#include "time32.h"
+#include <sys/time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __gettimeofday_time32(struct timeval32 *tv32, void *tz)
+{
+ struct timeval tv;
+ if (!tv32) return 0;
+ int r = gettimeofday(&tv, 0);
+ if (r) return r;
+ if (tv.tv_sec < INT32_MIN || tv.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tv32->tv_sec = tv.tv_sec;
+ tv32->tv_usec = tv.tv_usec;
+ return 0;
+}
diff --git a/compat/time32/gmtime32.c b/compat/time32/gmtime32.c
new file mode 100644
index 00000000..963f0e05
--- /dev/null
+++ b/compat/time32/gmtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32(time32_t *t)
+{
+ return gmtime(&(time_t){*t});
+}
diff --git a/compat/time32/gmtime32_r.c b/compat/time32/gmtime32_r.c
new file mode 100644
index 00000000..7d72bfb3
--- /dev/null
+++ b/compat/time32/gmtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32_r(time32_t *t, struct tm *tm)
+{
+ return gmtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/localtime32.c b/compat/time32/localtime32.c
new file mode 100644
index 00000000..96bc3034
--- /dev/null
+++ b/compat/time32/localtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32(time32_t *t)
+{
+ return localtime(&(time_t){*t});
+}
diff --git a/compat/time32/localtime32_r.c b/compat/time32/localtime32_r.c
new file mode 100644
index 00000000..633ec829
--- /dev/null
+++ b/compat/time32/localtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32_r(time32_t *t, struct tm *tm)
+{
+ return localtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/lstat_time32.c b/compat/time32/lstat_time32.c
new file mode 100644
index 00000000..c1257a14
--- /dev/null
+++ b/compat/time32/lstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = lstat(path, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(lstat, lstat64);
diff --git a/compat/time32/lutimes_time32.c b/compat/time32/lutimes_time32.c
new file mode 100644
index 00000000..7f75cd4a
--- /dev/null
+++ b/compat/time32/lutimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __lutimes_time32(const char *path, const struct timeval32 times32[2])
+{
+ return lutimes(path, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/mktime32.c b/compat/time32/mktime32.c
new file mode 100644
index 00000000..e6f15d51
--- /dev/null
+++ b/compat/time32/mktime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __mktime32(struct tm *tm)
+{
+ struct tm tmp = *tm;
+ time_t t = mktime(&tmp);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ *tm = tmp;
+ return t;
+}
diff --git a/compat/time32/mq_timedreceive_time32.c b/compat/time32/mq_timedreceive_time32.c
new file mode 100644
index 00000000..211cea4b
--- /dev/null
+++ b/compat/time32/mq_timedreceive_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+ssize_t __mq_timedreceive_time32(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec32 *restrict ts32)
+{
+ return mq_timedreceive(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/mq_timedsend_time32.c b/compat/time32/mq_timedsend_time32.c
new file mode 100644
index 00000000..93b697a7
--- /dev/null
+++ b/compat/time32/mq_timedsend_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+int __mq_timedsend_time32(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec32 *ts32)
+{
+ return mq_timedsend(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/mtx_timedlock_time32.c b/compat/time32/mtx_timedlock_time32.c
new file mode 100644
index 00000000..a01f09b8
--- /dev/null
+++ b/compat/time32/mtx_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __mtx_timedlock_time32(mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return mtx_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/nanosleep_time32.c b/compat/time32/nanosleep_time32.c
new file mode 100644
index 00000000..ea6bdd81
--- /dev/null
+++ b/compat/time32/nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __nanosleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = nanosleep((&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret<0 && errno==EINTR && rem32) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
new file mode 100644
index 00000000..43b4b0df
--- /dev/null
+++ b/compat/time32/ppoll_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <poll.h>
+
+int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
+{
+ return ppoll(fds, n, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
new file mode 100644
index 00000000..ecaa8f86
--- /dev/null
+++ b/compat/time32/pselect_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/select.h>
+
+int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
+{
+ return pselect(n, rfds, wfds, efds, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pthread_cond_timedwait_time32.c b/compat/time32/pthread_cond_timedwait_time32.c
new file mode 100644
index 00000000..fba1f2a9
--- /dev/null
+++ b/compat/time32/pthread_cond_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_cond_timedwait_time32(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return pthread_cond_timedwait(c, m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_mutex_timedlock_time32.c b/compat/time32/pthread_mutex_timedlock_time32.c
new file mode 100644
index 00000000..2d29602c
--- /dev/null
+++ b/compat/time32/pthread_mutex_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_mutex_timedlock_time32(pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return pthread_mutex_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedrdlock_time32.c b/compat/time32/pthread_rwlock_timedrdlock_time32.c
new file mode 100644
index 00000000..33df27a4
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedrdlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedrdlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+ return pthread_rwlock_timedrdlock(rw, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedwrlock_time32.c b/compat/time32/pthread_rwlock_timedwrlock_time32.c
new file mode 100644
index 00000000..99f24f73
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedwrlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedwrlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+ return pthread_rwlock_timedwrlock(rw, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_timedjoin_np_time32.c b/compat/time32/pthread_timedjoin_np_time32.c
new file mode 100644
index 00000000..3ec29951
--- /dev/null
+++ b/compat/time32/pthread_timedjoin_np_time32.c
@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_timedjoin_np_time32(pthread_t t, void **res, const struct timespec32 *at32)
+{
+ return pthread_timedjoin_np(t, res, !at32 ? 0 : (&(struct timespec){
+ .tv_sec = at32->tv_sec, .tv_nsec = at32->tv_nsec}));
+}
diff --git a/compat/time32/recvmmsg_time32.c b/compat/time32/recvmmsg_time32.c
new file mode 100644
index 00000000..acf1cfb8
--- /dev/null
+++ b/compat/time32/recvmmsg_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <sys/socket.h>
+
+int __recvmmsg_time32(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec32 *ts32)
+{
+ return recvmmsg(fd, msgvec, vlen, flags, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/sched_rr_get_interval_time32.c b/compat/time32/sched_rr_get_interval_time32.c
new file mode 100644
index 00000000..36cbbaca
--- /dev/null
+++ b/compat/time32/sched_rr_get_interval_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include <time.h>
+#include <sched.h>
+
+int __sched_rr_get_interval_time32(pid_t pid, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = sched_rr_get_interval(pid, &ts);
+ if (r) return r;
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return r;
+}
diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
new file mode 100644
index 00000000..2d8df9ac
--- /dev/null
+++ b/compat/time32/select_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
+{
+ return select(n, rfds, wfds, efds, !tv32 ? 0 : (&(struct timeval){
+ .tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
+}
diff --git a/compat/time32/sem_timedwait_time32.c b/compat/time32/sem_timedwait_time32.c
new file mode 100644
index 00000000..c3469f9b
--- /dev/null
+++ b/compat/time32/sem_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <semaphore.h>
+
+int __sem_timedwait_time32(sem_t *sem, const struct timespec32 *restrict ts32)
+{
+ return sem_timedwait(sem, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/semtimedop_time32.c b/compat/time32/semtimedop_time32.c
new file mode 100644
index 00000000..34ec5281
--- /dev/null
+++ b/compat/time32/semtimedop_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <sys/sem.h>
+#include <time.h>
+
+int __semtimedop_time32(int id, struct sembuf *buf, size_t n, const struct timespec32 *ts32)
+{
+ return semtimedop(id, buf, n, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/setitimer_time32.c b/compat/time32/setitimer_time32.c
new file mode 100644
index 00000000..4651dacb
--- /dev/null
+++ b/compat/time32/setitimer_time32.c
@@ -0,0 +1,23 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __setitimer_time32(int which, const struct itimerval32 *restrict new32, struct itimerval32 *restrict old32)
+{
+ struct itimerval old;
+ int r = setitimer(which, (&(struct itimerval){
+ .it_interval.tv_sec = new32->it_interval.tv_sec,
+ .it_interval.tv_usec = new32->it_interval.tv_usec,
+ .it_value.tv_sec = new32->it_value.tv_sec,
+ .it_value.tv_usec = new32->it_value.tv_usec}), &old);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_usec = old.it_interval.tv_usec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_usec = old.it_value.tv_usec;
+ return 0;
+}
diff --git a/compat/time32/settimeofday_time32.c b/compat/time32/settimeofday_time32.c
new file mode 100644
index 00000000..09e625cb
--- /dev/null
+++ b/compat/time32/settimeofday_time32.c
@@ -0,0 +1,10 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <sys/time.h>
+
+int __settimeofday_time32(const struct timeval32 *tv32, const void *tz)
+{
+ return settimeofday(!tv32 ? 0 : (&(struct timeval){
+ .tv_sec = tv32->tv_sec,
+ .tv_usec = tv32->tv_usec}), 0);
+}
diff --git a/compat/time32/sigtimedwait_time32.c b/compat/time32/sigtimedwait_time32.c
new file mode 100644
index 00000000..6b3aa39c
--- /dev/null
+++ b/compat/time32/sigtimedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <signal.h>
+
+int __sigtimedwait_time32(const sigset_t *restrict set, siginfo_t *restrict si, const struct timespec32 *restrict ts32)
+{
+ return sigtimedwait(set, si, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/stat_time32.c b/compat/time32/stat_time32.c
new file mode 100644
index 00000000..8c6121da
--- /dev/null
+++ b/compat/time32/stat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = stat(path, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(stat, stat64);
diff --git a/compat/time32/stime32.c b/compat/time32/stime32.c
new file mode 100644
index 00000000..cc76364d
--- /dev/null
+++ b/compat/time32/stime32.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+
+int __stime32(const time32_t *t)
+{
+ return stime(&(time_t){*t});
+}
diff --git a/compat/time32/thrd_sleep_time32.c b/compat/time32/thrd_sleep_time32.c
new file mode 100644
index 00000000..59088001
--- /dev/null
+++ b/compat/time32/thrd_sleep_time32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+#include <errno.h>
+
+int __thrd_sleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = thrd_sleep((&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret<0 && errno==EINTR && rem32) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/compat/time32/time32.c b/compat/time32/time32.c
new file mode 100644
index 00000000..4b8fac1c
--- /dev/null
+++ b/compat/time32/time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32(time32_t *p)
+{
+ time_t t = time(0);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ if (p) *p = t;
+ return t;
+}
diff --git a/compat/time32/time32.h b/compat/time32/time32.h
new file mode 100644
index 00000000..fdec17c3
--- /dev/null
+++ b/compat/time32/time32.h
@@ -0,0 +1,91 @@
+#ifndef TIME32_H
+#define TIME32_H
+
+#include <sys/types.h>
+
+typedef long time32_t;
+
+struct timeval32 {
+ long tv_sec;
+ long tv_usec;
+};
+
+struct itimerval32 {
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+struct timespec32 {
+ long tv_sec;
+ long tv_nsec;
+};
+
+struct itimerspec32 {
+ struct timespec32 it_interval;
+ struct timespec32 it_value;
+};
+
+int __adjtime32() __asm__("adjtime");
+int __adjtimex_time32() __asm__("adjtimex");
+int __aio_suspend_time32() __asm__("aio_suspend");
+int __clock_adjtime32() __asm__("clock_adjtime");
+int __clock_getres_time32() __asm__("clock_getres");
+int __clock_gettime32() __asm__("clock_gettime");
+int __clock_nanosleep_time32() __asm__("clock_nanosleep");
+int __clock_settime32() __asm__("clock_settime");
+int __cnd_timedwait_time32() __asm__("cnd_timedwait");
+char *__ctime32() __asm__("ctime");
+char *__ctime32_r() __asm__("ctime_r");
+double __difftime32() __asm__("difftime");
+int __fstat_time32() __asm__("fstat");
+int __fstatat_time32() __asm__("fstatat");
+int __ftime32() __asm__("ftime");
+int __futimens_time32() __asm__("futimens");
+int __futimes_time32() __asm__("futimes");
+int __futimesat_time32() __asm__("futimesat");
+int __getitimer_time32() __asm__("getitimer");
+int __getrusage_time32() __asm__("getrusage");
+int __gettimeofday_time32() __asm__("gettimeofday");
+struct tm *__gmtime32() __asm__("gmtime");
+struct tm *__gmtime32_r() __asm__("gmtime_r");
+struct tm *__localtime32() __asm__("localtime");
+struct tm *__localtime32_r() __asm__("localtime_r");
+int __lstat_time32() __asm__("lstat");
+int __lutimes_time32() __asm__("lutimes");
+time32_t __mktime32() __asm__("mktime");
+ssize_t __mq_timedreceive_time32() __asm__("mq_timedreceive");
+int __mq_timedsend_time32() __asm__("mq_timedsend");
+int __mtx_timedlock_time32() __asm__("mtx_timedlock");
+int __nanosleep_time32() __asm__("nanosleep");
+int __ppoll_time32() __asm__("ppoll");
+int __pselect_time32() __asm__("pselect");
+int __pthread_cond_timedwait_time32() __asm__("pthread_cond_timedwait");
+int __pthread_mutex_timedlock_time32() __asm__("pthread_mutex_timedlock");
+int __pthread_rwlock_timedrdlock_time32() __asm__("pthread_rwlock_timedrdlock");
+int __pthread_rwlock_timedwrlock_time32() __asm__("pthread_rwlock_timedwrlock");
+int __pthread_timedjoin_np_time32() __asm__("pthread_timedjoin_np");
+int __recvmmsg_time32() __asm__("recvmmsg");
+int __sched_rr_get_interval_time32() __asm__("sched_rr_get_interval");
+int __select_time32() __asm__("select");
+int __sem_timedwait_time32() __asm__("sem_timedwait");
+int __semtimedop_time32() __asm__("semtimedop");
+int __setitimer_time32() __asm__("setitimer");
+int __settimeofday_time32() __asm__("settimeofday");
+int __sigtimedwait_time32() __asm__("sigtimedwait");
+int __stat_time32() __asm__("stat");
+int __stime32() __asm__("stime");
+int __thrd_sleep_time32() __asm__("thrd_sleep");
+time32_t __time32() __asm__("time");
+time32_t __time32gm() __asm__("timegm");
+int __timer_gettime32() __asm__("timer_gettime");
+int __timer_settime32() __asm__("timer_settime");
+int __timerfd_gettime32() __asm__("timerfd_gettime");
+int __timerfd_settime32() __asm__("timerfd_settime");
+int __timespec_get_time32() __asm__("timespec_get");
+int __utime_time32() __asm__("utime");
+int __utimensat_time32() __asm__("utimensat");
+int __utimes_time32() __asm__("utimes");
+pid_t __wait3_time32() __asm__("wait3");
+pid_t __wait4_time32() __asm__("wait4");
+
+#endif
diff --git a/compat/time32/time32gm.c b/compat/time32/time32gm.c
new file mode 100644
index 00000000..60d68fbf
--- /dev/null
+++ b/compat/time32/time32gm.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32gm(struct tm *tm)
+{
+ time_t t = timegm(tm);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return t;
+}
diff --git a/compat/time32/timer_gettime32.c b/compat/time32/timer_gettime32.c
new file mode 100644
index 00000000..b4184cc2
--- /dev/null
+++ b/compat/time32/timer_gettime32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_gettime32(timer_t t, struct itimerspec32 *val32)
+{
+ struct itimerspec old;
+ int r = timer_gettime(t, &old);
+ if (r) return r;
+ /* No range checking for consistency with settime */
+ val32->it_interval.tv_sec = old.it_interval.tv_sec;
+ val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ val32->it_value.tv_sec = old.it_value.tv_sec;
+ val32->it_value.tv_nsec = old.it_value.tv_nsec;
+ return 0;
+}
diff --git a/compat/time32/timer_settime32.c b/compat/time32/timer_settime32.c
new file mode 100644
index 00000000..a447e7d4
--- /dev/null
+++ b/compat/time32/timer_settime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_settime32(timer_t t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+ struct itimerspec old;
+ int r = timer_settime(t, flags, (&(struct itimerspec){
+ .it_interval.tv_sec = val32->it_interval.tv_sec,
+ .it_interval.tv_nsec = val32->it_interval.tv_nsec,
+ .it_value.tv_sec = val32->it_value.tv_sec,
+ .it_value.tv_nsec = val32->it_value.tv_nsec}),
+ old32 ? &old : 0);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ if (old32) {
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_nsec = old.it_value.tv_nsec;
+ }
+ return 0;
+}
diff --git a/compat/time32/timerfd_gettime32.c b/compat/time32/timerfd_gettime32.c
new file mode 100644
index 00000000..75e5435f
--- /dev/null
+++ b/compat/time32/timerfd_gettime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_gettime32(int t, struct itimerspec32 *val32)
+{
+ struct itimerspec old;
+ int r = timerfd_gettime(t, &old);
+ if (r) return r;
+ /* No range checking for consistency with settime */
+ val32->it_interval.tv_sec = old.it_interval.tv_sec;
+ val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ val32->it_value.tv_sec = old.it_value.tv_sec;
+ val32->it_value.tv_nsec = old.it_value.tv_nsec;
+ return 0;
+}
diff --git a/compat/time32/timerfd_settime32.c b/compat/time32/timerfd_settime32.c
new file mode 100644
index 00000000..67830d34
--- /dev/null
+++ b/compat/time32/timerfd_settime32.c
@@ -0,0 +1,26 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_settime32(int t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+ struct itimerspec old;
+ int r = timerfd_settime(t, flags, (&(struct itimerspec){
+ .it_interval.tv_sec = val32->it_interval.tv_sec,
+ .it_interval.tv_nsec = val32->it_interval.tv_nsec,
+ .it_value.tv_sec = val32->it_value.tv_sec,
+ .it_value.tv_nsec = val32->it_value.tv_nsec}),
+ old32 ? &old : 0);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ if (old32) {
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_nsec = old.it_value.tv_nsec;
+ }
+ return 0;
+}
diff --git a/compat/time32/timespec_get_time32.c b/compat/time32/timespec_get_time32.c
new file mode 100644
index 00000000..e9ca94cb
--- /dev/null
+++ b/compat/time32/timespec_get_time32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __timespec_get_time32(struct timespec32 *ts32, int base)
+{
+ struct timespec ts;
+ int r = timespec_get(&ts, base);
+ if (!r) return r;
+ if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return 0;
+ }
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return r;
+}
diff --git a/compat/time32/utime_time32.c b/compat/time32/utime_time32.c
new file mode 100644
index 00000000..65f11d46
--- /dev/null
+++ b/compat/time32/utime_time32.c
@@ -0,0 +1,14 @@
+#include "time32.h"
+#include <time.h>
+#include <utime.h>
+
+struct utimbuf32 {
+ time32_t actime;
+ time32_t modtime;
+};
+
+int __utime_time32(const char *path, const struct utimbuf32 *times32)
+{
+ return utime(path, !times32 ? 0 : (&(struct utimbuf){
+ .actime = times32->actime, .modtime = times32->modtime}));
+}
diff --git a/compat/time32/utimensat_time32.c b/compat/time32/utimensat_time32.c
new file mode 100644
index 00000000..c687b8d1
--- /dev/null
+++ b/compat/time32/utimensat_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __utimensat_time32(int fd, const char *path, const struct timespec32 times32[2], int flags)
+{
+ return utimensat(fd, path, !times32 ? 0 : ((struct timespec[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+ {.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}),
+ flags);
+}
diff --git a/compat/time32/utimes_time32.c b/compat/time32/utimes_time32.c
new file mode 100644
index 00000000..59248f62
--- /dev/null
+++ b/compat/time32/utimes_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __utimes_time32(const char *path, const struct timeval32 times32[2])
+{
+ return utimes(path, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/wait3_time32.c b/compat/time32/wait3_time32.c
new file mode 100644
index 00000000..8fe128ed
--- /dev/null
+++ b/compat/time32/wait3_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+pid_t __wait3_time32(int *status, int options, struct compat_rusage *usage)
+{
+ struct rusage ru;
+ int r = wait3(status, options, usage ? &ru : 0);
+ if (!r && usage) {
+ usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+ usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+ usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+ usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+ memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+ sizeof(struct compat_rusage) -
+ offsetof(struct compat_rusage, ru_maxrss));
+ }
+ return r;
+}
diff --git a/compat/time32/wait4_time32.c b/compat/time32/wait4_time32.c
new file mode 100644
index 00000000..918548e7
--- /dev/null
+++ b/compat/time32/wait4_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+pid_t __wait4_time32(pid_t pid, int *status, int options, struct compat_rusage *usage)
+{
+ struct rusage ru;
+ int r = wait4(pid, status, options, usage ? &ru : 0);
+ if (!r && usage) {
+ usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+ usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+ usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+ usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+ memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+ sizeof(struct compat_rusage) -
+ offsetof(struct compat_rusage, ru_maxrss));
+ }
+ return r;
+}