Browse Source

add time32 ABI compat shims, compat source tree

these files provide the symbols for the traditional 32-bit time_t ABI
on existing 32-bit archs by wrapping the real, internal versions of
the corresponding functions, which always work with 64-bit time_t.
they are written to be as agnostic as possible to the implementation
details of the real functions, so that they can be written once and
mostly forgotten, but they are aware of details of the old (and
sometimes new) ABI, which is okay since ABI is fixed and cannot
change.

a new compat tree is added, separate from src, which the Makefile does
not see or use now, but which archs will be able to add to the build
process. we could also consider moving other things that are compat
shims here, like functions which are purely for glibc-ABI-compat, with
the goal of making it optional or just cleaning up the main src tree
to make the distinction between actual implementation/API files and
ABI-compat shims clear.
Rich Felker 4 years ago
parent
commit
c045032094
64 changed files with 1039 additions and 0 deletions
  1. 24 0
      compat/time32/__xstat.c
  2. 21 0
      compat/time32/adjtime32.c
  3. 10 0
      compat/time32/adjtimex_time32.c
  4. 11 0
      compat/time32/aio_suspend_time32.c
  5. 70 0
      compat/time32/clock_adjtime32.c
  6. 13 0
      compat/time32/clock_getres_time32.c
  7. 18 0
      compat/time32/clock_gettime32.c
  8. 15 0
      compat/time32/clock_nanosleep_time32.c
  9. 9 0
      compat/time32/clock_settime32.c
  10. 9 0
      compat/time32/cnd_timedwait_time32.c
  11. 7 0
      compat/time32/ctime32.c
  12. 7 0
      compat/time32/ctime32_r.c
  13. 7 0
      compat/time32/difftime32.c
  14. 17 0
      compat/time32/fstat_time32.c
  15. 17 0
      compat/time32/fstatat_time32.c
  16. 25 0
      compat/time32/ftime32.c
  17. 10 0
      compat/time32/futimens_time32.c
  18. 12 0
      compat/time32/futimes_time32.c
  19. 12 0
      compat/time32/futimesat_time32.c
  20. 15 0
      compat/time32/getitimer_time32.c
  21. 39 0
      compat/time32/getrusage_time32.c
  22. 19 0
      compat/time32/gettimeofday_time32.c
  23. 7 0
      compat/time32/gmtime32.c
  24. 7 0
      compat/time32/gmtime32_r.c
  25. 7 0
      compat/time32/localtime32.c
  26. 7 0
      compat/time32/localtime32_r.c
  27. 17 0
      compat/time32/lstat_time32.c
  28. 12 0
      compat/time32/lutimes_time32.c
  29. 16 0
      compat/time32/mktime32.c
  30. 9 0
      compat/time32/mq_timedreceive_time32.c
  31. 9 0
      compat/time32/mq_timedsend_time32.c
  32. 9 0
      compat/time32/mtx_timedlock_time32.c
  33. 15 0
      compat/time32/nanosleep_time32.c
  34. 10 0
      compat/time32/ppoll_time32.c
  35. 9 0
      compat/time32/pselect_time32.c
  36. 9 0
      compat/time32/pthread_cond_timedwait_time32.c
  37. 9 0
      compat/time32/pthread_mutex_timedlock_time32.c
  38. 9 0
      compat/time32/pthread_rwlock_timedrdlock_time32.c
  39. 9 0
      compat/time32/pthread_rwlock_timedwrlock_time32.c
  40. 10 0
      compat/time32/pthread_timedjoin_np_time32.c
  41. 10 0
      compat/time32/recvmmsg_time32.c
  42. 13 0
      compat/time32/sched_rr_get_interval_time32.c
  43. 10 0
      compat/time32/select_time32.c
  44. 9 0
      compat/time32/sem_timedwait_time32.c
  45. 10 0
      compat/time32/semtimedop_time32.c
  46. 23 0
      compat/time32/setitimer_time32.c
  47. 10 0
      compat/time32/settimeofday_time32.c
  48. 9 0
      compat/time32/sigtimedwait_time32.c
  49. 17 0
      compat/time32/stat_time32.c
  50. 8 0
      compat/time32/stime32.c
  51. 16 0
      compat/time32/thrd_sleep_time32.c
  52. 15 0
      compat/time32/time32.c
  53. 91 0
      compat/time32/time32.h
  54. 15 0
      compat/time32/time32gm.c
  55. 15 0
      compat/time32/timer_gettime32.c
  56. 25 0
      compat/time32/timer_settime32.c
  57. 16 0
      compat/time32/timerfd_gettime32.c
  58. 26 0
      compat/time32/timerfd_settime32.c
  59. 18 0
      compat/time32/timespec_get_time32.c
  60. 14 0
      compat/time32/utime_time32.c
  61. 11 0
      compat/time32/utimensat_time32.c
  62. 11 0
      compat/time32/utimes_time32.c
  63. 40 0
      compat/time32/wait3_time32.c
  64. 40 0
      compat/time32/wait4_time32.c

+ 24 - 0
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);
+}

+ 21 - 0
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;
+}

+ 10 - 0
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);
+}

+ 11 - 0
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);

+ 70 - 0
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;
+}

+ 13 - 0
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;
+}

+ 18 - 0
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;
+}

+ 15 - 0
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;
+}

+ 9 - 0
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}));
+}

+ 9 - 0
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);
+}

+ 7 - 0
compat/time32/ctime32.c

@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32(time32_t *t)
+{
+	return ctime(&(time_t){*t});
+}

+ 7 - 0
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);
+}

+ 7 - 0
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);
+}

+ 17 - 0
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);

+ 17 - 0
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);

+ 25 - 0
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;
+}

+ 10 - 0
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}}));
+}

+ 12 - 0
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}}));
+}

+ 12 - 0
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}}));
+}

+ 15 - 0
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;
+}

+ 39 - 0
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;
+}

+ 19 - 0
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;
+}

+ 7 - 0
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});
+}

+ 7 - 0
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);
+}

+ 7 - 0
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});
+}

+ 7 - 0
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);
+}

+ 17 - 0
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);

+ 12 - 0
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}}));
+}

+ 16 - 0
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;
+}

+ 9 - 0
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);
+}

+ 9 - 0
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);
+}

+ 9 - 0
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}));
+}

+ 15 - 0
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;
+}

+ 10 - 0
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);
+}

+ 9 - 0
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);
+}

+ 9 - 0
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}));
+}

+ 9 - 0
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}));
+}

+ 9 - 0
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}));
+}

+ 9 - 0
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}));
+}

+ 10 - 0
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}));
+}

+ 10 - 0
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);
+}

+ 13 - 0
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;
+}

+ 10 - 0
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}));
+}

+ 9 - 0
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}));
+}

+ 10 - 0
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}));
+}

+ 23 - 0
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;
+}

+ 10 - 0
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);
+}

+ 9 - 0
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}));
+}

+ 17 - 0
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);

+ 8 - 0
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});
+}

+ 16 - 0
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;
+}

+ 15 - 0
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;
+}

+ 91 - 0
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

+ 15 - 0
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;
+}

+ 15 - 0
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;
+}

+ 25 - 0
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;
+}

+ 16 - 0
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;
+}

+ 26 - 0
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;
+}

+ 18 - 0
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;
+}

+ 14 - 0
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}));
+}

+ 11 - 0
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);
+}

+ 11 - 0
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}}));
+}

+ 40 - 0
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;
+}

+ 40 - 0
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;
+}