ioctl: add fallback for new time64 SIOCGSTAMP[NS]
authorRich Felker <dalias@aerifal.cx>
Wed, 31 Jul 2019 03:48:25 +0000 (23:48 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 1 Aug 2019 00:21:04 +0000 (20:21 -0400)
without this, the SIOCGSTAMP and SIOCGSTAMPNS ioctl commands, for
obtaining timestamps, would stop working on pre-5.1 kernels after
time_t is switched to 64-bit and their values are changed to the new
time64 versions.

new code is written such that it's statically unreachable on 64-bit
archs, and on existing 32-bit archs until the macro values are changed
to activate 64-bit time_t.

arch/sh/syscall_arch.h
src/internal/syscall.h
src/misc/ioctl.c

index 48f61d9..628d8d3 100644 (file)
@@ -88,3 +88,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
 }
 
 #define SYSCALL_IPC_BROKEN_MODE
+
+#define SIOCGSTAMP_OLD   (2U<<30 | 's'<<8 | 100 | 8<<16)
+#define SIOCGSTAMPNS_OLD (2U<<30 | 's'<<8 | 101 | 8<<16)
index 16edf30..9f2784d 100644 (file)
@@ -306,6 +306,13 @@ hidden long __syscall_ret(unsigned long),
 #define SO_SNDTIMEO_OLD  21
 #endif
 
+#ifndef SIOCGSTAMP_OLD
+#define SIOCGSTAMP_OLD 0x8906
+#endif
+#ifndef SIOCGSTAMPNS_OLD
+#define SIOCGSTAMPNS_OLD 0x8907
+#endif
+
 #ifdef SYS_open
 #define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE)
 #define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
index 5a41f0e..6f31d4b 100644 (file)
@@ -1,5 +1,8 @@
 #include <sys/ioctl.h>
 #include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
 #include "syscall.h"
 
 int ioctl(int fd, int req, ...)
@@ -9,5 +12,25 @@ int ioctl(int fd, int req, ...)
        va_start(ap, req);
        arg = va_arg(ap, void *);
        va_end(ap);
-       return syscall(SYS_ioctl, fd, req, arg);
+       int r = __syscall(SYS_ioctl, fd, req, arg);
+       if (r==-ENOTTY) switch (req) {
+       case SIOCGSTAMP:
+       case SIOCGSTAMPNS:
+               if (SIOCGSTAMP==SIOCGSTAMP_OLD) break;
+               if (req==SIOCGSTAMP) req=SIOCGSTAMP_OLD;
+               if (req==SIOCGSTAMPNS) req=SIOCGSTAMPNS_OLD;
+               long t32[2];
+               r = __syscall(SYS_ioctl, fd, req, t32);
+               if (r<0) break;
+               if (req==SIOCGSTAMP_OLD) {
+                       struct timeval *tv = arg;
+                       tv->tv_sec = t32[0];
+                       tv->tv_usec = t32[1];
+               } else {
+                       struct timespec *ts = arg;
+                       ts->tv_sec = t32[0];
+                       ts->tv_nsec = t32[1];
+               }
+       }
+       return __syscall_ret(r);
 }