From: Rich Felker Date: Thu, 19 Dec 2019 01:48:58 +0000 (-0500) Subject: convert ioctl time64 fallbacks to table-driven framework X-Git-Tag: v1.2.0~50 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=221b1a1d0ae5de7ddc76a577f591f7ded090cc44;p=oweals%2Fmusl.git 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. --- 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