From 221b1a1d0ae5de7ddc76a577f591f7ded090cc44 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 18 Dec 2019 20:48:58 -0500 Subject: [PATCH] convert ioctl time64 fallbacks to table-driven framework with the current set of supported ioctls, this conversion is hardly an improvement, but it sets the stage for being able to do alsa, v4l2, ppp, and other ioctls with timespec/timeval-derived types. without this capability, a lot of functionality users depend on would stop working with the time64 switchover. --- src/misc/ioctl.c | 83 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c index 6f31d4bc..48613b3d 100644 --- a/src/misc/ioctl.c +++ b/src/misc/ioctl.c @@ -3,8 +3,63 @@ #include #include #include +#include +#include #include "syscall.h" +#define alignof(t) offsetof(struct { char c; t x; }, x) + +#define W 1 +#define R 2 +#define WR 3 + +struct ioctl_compat_map { + int new_req, old_req, old_size; + char dir, force_align; + int offsets[4]; +}; + +static const struct ioctl_compat_map compat_map[] = { + { SIOCGSTAMP, SIOCGSTAMP_OLD, 8, R, 0, { 0, -1, -1, -1 } }, + { SIOCGSTAMPNS, SIOCGSTAMPNS_OLD, 8, R, 0, { 0, -1, -1, -1 } }, +}; + +static void convert_ioctl_struct(const struct ioctl_compat_map *map, char *old, char *new, int dir) +{ + int new_offset = 0; + int old_offset = 0; + int old_size = map->old_size; + if (!(dir & map->dir)) return; + for (int i=0; i < sizeof map->offsets / sizeof *map->offsets; i++) { + int ts_offset = map->offsets[i]; + if (ts_offset < 0) break; + int len = ts_offset-old_offset; + if (dir==W) memcpy(old+old_offset, new+new_offset, len); + else memcpy(new+new_offset, old+old_offset, len); + new_offset += len; + old_offset += len; + long long new_ts[2]; + long old_ts[2]; + int align = map->force_align ? sizeof(time_t) : alignof(time_t); + new_offset += (align-1) & -new_offset; + if (dir==W) { + memcpy(new_ts, new+new_offset, sizeof new_ts); + old_ts[0] = new_ts[0]; + old_ts[1] = new_ts[1]; + memcpy(old+old_offset, old_ts, sizeof old_ts); + } else { + memcpy(old_ts, old+old_offset, sizeof old_ts); + new_ts[0] = old_ts[0]; + new_ts[1] = old_ts[1]; + memcpy(new+new_offset, new_ts, sizeof new_ts); + } + new_offset += sizeof new_ts; + old_offset += sizeof old_ts; + } + if (dir==W) memcpy(old+old_offset, new+new_offset, old_size-old_offset); + else memcpy(new+new_offset, old+old_offset, old_size-old_offset); +} + int ioctl(int fd, int req, ...) { void *arg; @@ -13,23 +68,17 @@ int ioctl(int fd, int req, ...) arg = va_arg(ap, void *); va_end(ap); 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]; + if (r==-ENOTTY) { + for (int i=0; i