提交 221b1a1d 编写于 作者: R Rich Felker

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.
上级 b3290956
......@@ -3,8 +3,63 @@
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
#include <string.h>
#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==-ENOTTY) {
for (int i=0; i<sizeof compat_map/sizeof *compat_map; i++) {
if (compat_map[i].new_req != req) continue;
union {
long long align;
char buf[256];
} u;
convert_ioctl_struct(&compat_map[i], u.buf, arg, W);
r = __syscall(SYS_ioctl, fd, compat_map[i].old_req, u.buf);
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];
convert_ioctl_struct(&compat_map[i], u.buf, arg, R);
}
}
return __syscall_ret(r);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册