Subject: patch for -D_TIME_BITS=64 From: diff --git a/src/libumockdev-preload.c b/src/libumockdev-preload.c index d806125..1c0113d 100644 --- a/src/libumockdev-preload.c +++ b/src/libumockdev-preload.c @@ -24,6 +24,13 @@ /* override -D_FILE_OFFSET_BITS, it breaks us */ #undef _FILE_OFFSET_BITS +#ifdef _TIME_BITS +# if _TIME_BITS == 64 +/* memorize */ +# define TIME_BITS 64 +# endif +# undef _TIME_BITS +#endif /* for getting stat64 */ #define _GNU_SOURCE @@ -58,6 +65,132 @@ #include #include +#ifdef __GLIBC__ +struct __stat64_t64 + { + /* right out of /usr/include/bits/struct_stat_time64_helper.h */ +#ifdef __USE_TIME_BITS64 + /* Content of internal stat64_time64 struct. */ + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* file serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group. */ + __dev_t st_rdev; /* Device number, if device. */ + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +#ifdef __USE_XOPEN2K8 +# ifndef __struct_timespec +# define __struct_timespec struct timespec +# endif + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + __struct_timespec st_atim; + __struct_timespec st_mtim; + __struct_timespec st_ctim; +# define st_atime st_atim.tv_sec +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# undef __struct_timespec +#else +/* The definition should be equal to the 'struct __timespec64' internal + layout. */ +# if __BYTE_ORDER == __BIG_ENDIAN +# define __fieldts64(name) \ + __time64_t name; __int32_t :32; __int32_t name ## nsec +# else +# define __fieldts64(name) \ + __time64_t name; __int32_t name ## nsec; __int32_t :32 +# endif + + __fieldts64 (st_atime); + __fieldts64 (st_mtime); + __fieldts64 (st_ctime); + + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; + +# undef __fieldts64 +#endif + +#else + __dev_t st_dev; /* Device. */ +# ifndef __x86_64__ + unsigned short int __pad1; +# endif +# if defined __x86_64__ || !defined __USE_FILE_OFFSET64 + __ino_t st_ino; /* File serial number. */ +# else + __ino_t __st_ino; /* 32bit file serial number. */ +# endif +# ifndef __x86_64__ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ +# else + __nlink_t st_nlink; /* Link count. */ + __mode_t st_mode; /* File mode. */ +# endif + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ +# ifdef __x86_64__ + int __pad0; +# endif + __dev_t st_rdev; /* Device number, if device. */ +# ifndef __x86_64__ + unsigned short int __pad2; +# endif +# if defined __x86_64__ || !defined __USE_FILE_OFFSET64 + __off_t st_size; /* Size of file, in bytes. */ +# else + __off64_t st_size; /* Size of file, in bytes. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ +# if defined __x86_64__ || !defined __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +# else + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + __syscall_ulong_t st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + __syscall_ulong_t st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + __syscall_ulong_t st_ctimensec; /* Nsecs of last status change. */ +# endif +# ifdef __x86_64__ + __syscall_slong_t __glibc_reserved[3]; +# else +# ifndef __USE_FILE_OFFSET64 + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; +# else + __ino64_t st_ino; /* File serial number. */ +# endif +# endif +#endif /* __USE_TIME_BITS64 */ + }; +#endif /*__GLIBC__*/ + #include "config.h" #include "debug.h" #include "utils.h" @@ -104,11 +237,19 @@ get_libc_func(const char *f) static dev_t dev_of_fd(int fd) { +#ifdef __USE_TIME_BITS64 + struct __stat64_t64 st; +#else struct stat st; +#endif int ret, orig_errno; orig_errno = errno; +#ifdef __USE_TIME_BITS64 + ret = __fstat64_time64(fd, &st); +#else ret = fstat(fd, &st); +#endif errno = orig_errno; if (ret < 0) return 0; @@ -552,6 +695,9 @@ remote_emulate(int fd, int cmd, long arg1, long arg2) libc_func(send, ssize_t, int, const void *, size_t, int); libc_func(recv, ssize_t, int, const void *, size_t, int); libc_func(ioctl, int, int, IOCTL_REQUEST_TYPE, ...); +#if defined(__GLIBC__) && defined(TIME_BITS) && TIME_BITS == 64 + libc_func(__ioctl_time64, int, int, IOCTL_REQUEST_TYPE, ...); +#endif libc_func(read, ssize_t, int, void *, size_t); libc_func(write, ssize_t, int, void *, size_t); struct ioctl_fd_info *fdinfo; @@ -610,7 +756,14 @@ remote_emulate(int fd, int cmd, long arg1, long arg2) case IOCTL_RES_RUN: if (cmd == IOCTL_REQ_IOCTL) +#if defined(__GLIBC__) && defined(TIME_BITS) && TIME_BITS == 64 + /* This is not correct; should switch time32/time64 by + * what caller uses. + */ + res = ___ioctl_time64(fd, arg1, arg2); +#else res = _ioctl(fd, arg1, arg2); +#endif else if (cmd == IOCTL_REQ_READ) res = _read(fd, (char*) arg1, arg2); else if (cmd == IOCTL_REQ_WRITE) @@ -1377,7 +1530,65 @@ WRAP_STAT(,64); WRAP_STAT(l,64); WRAP_FSTATAT(,64); WRAP_FOPEN(,64); -#endif + +/* special case for _TIME_BITS=64 */ + +int __stat64_time64(const char *path, struct __stat64_t64 *st); +int __stat64_time64(const char *path, struct __stat64_t64 *st) +{ + const char *p; + libc_func(__stat64_time64, int, const char*, struct __stat64_t64 *); + int ret; + TRAP_PATH_LOCK; + p = trap_path(path); + if (p == NULL) { + TRAP_PATH_UNLOCK; + return -1; + } + DBG(DBG_PATH, "testbed wrapped " "__" "stat" "64_time64" "(%s) -> %s\n", path, p); + ret = ___stat64_time64(p, st); + TRAP_PATH_UNLOCK; + STAT_ADJUST_MODE; + return ret; +} +int __lstat64_time64(const char *path, struct __stat64_t64 *st); +int __lstat64_time64(const char *path, struct __stat64_t64 *st) +{ + const char *p; + libc_func(__lstat64_time64, int, const char*, struct __stat64_t64 *); + int ret; + TRAP_PATH_LOCK; + p = trap_path(path); + if (p == NULL) { + TRAP_PATH_UNLOCK; + return -1; + } + DBG(DBG_PATH, "testbed wrapped " "__l" "stat" "64_time64" "(%s) -> %s\n", path, p); + ret = ___lstat64_time64(p, st); + TRAP_PATH_UNLOCK; + STAT_ADJUST_MODE; + return ret; +} +int __fstatat64_time64 (int dirfd, const char *path, struct __stat64_t64 *st, int flags); +int __fstatat64_time64 (int dirfd, const char *path, struct __stat64_t64 *st, int flags) +{ + const char *p; + libc_func(__fstatat64_time64, int, int, const char*, struct __stat64_t64 *, int); + int ret; + TRAP_PATH_LOCK; + p = trap_path(path); + if (p == NULL) { + TRAP_PATH_UNLOCK; + return -1; + } + DBG(DBG_PATH, "testbed wrapped " "__" "fstatat" "64_time64" "(%s) -> %s\n", path, p); + ret = ___fstatat64_time64(dirfd, p, st, flags); + TRAP_PATH_UNLOCK; + STAT_ADJUST_MODE; + return ret; +} + +#endif /* __GLIBC__ */ WRAP_3ARGS(ssize_t, -1, readlink, char *, size_t); @@ -1464,7 +1675,7 @@ int fstatfs ## suffix(int fd, struct statfs ## suffix *buf) \ WRAP_FSTATFS(); WRAP_FSTATFS(64); -#endif +#endif /* GLIBC */ int __open_2(const char *path, int flags); int __open64_2(const char *path, int flags); @@ -1687,6 +1898,21 @@ recvmsg(int sockfd, struct msghdr * msg, int flags) return ret; } +#ifdef __GLIBC__ +ssize_t +__recvmsg64(int sockfd, struct msghdr * msg, int flags); +ssize_t +__recvmsg64(int sockfd, struct msghdr * msg, int flags) +{ + libc_func(__recvmsg64, int, int, struct msghdr *, int); + ssize_t ret = ___recvmsg64(sockfd, msg, flags); + + netlink_recvmsg(sockfd, msg, ret); + + return ret; +} +#endif /*__GLIBC__*/ + int socket(int domain, int type, int protocol) { @@ -1804,6 +2030,41 @@ ioctl(int d, IOCTL_REQUEST_TYPE request, ...) return result; } + +#if defined(__GLIBC__) && defined(TIME_BITS) && TIME_BITS == 64 +int +__ioctl_time64(int d, IOCTL_REQUEST_TYPE request, ...); +int +__ioctl_time64(int d, IOCTL_REQUEST_TYPE request, ...) +{ + libc_func(__ioctl_time64, int, int, IOCTL_REQUEST_TYPE, ...); + int result; + va_list ap; + void* arg; + + /* one cannot reliably forward arbitrary varargs + * (http://c-faq.com/varargs/handoff.html), but we know that ioctl gets at + * most one extra argument, and almost all of them are pointers or ints, + * both of which fit into a void*. + */ + va_start(ap, request); + arg = va_arg(ap, void*); + va_end(ap); + + result = remote_emulate(d, IOCTL_REQ_IOCTL, (unsigned int) request, (long) arg); + if (result != UNHANDLED) { + DBG(DBG_IOCTL, "ioctl fd %i request %X: emulated, result %i\n", d, (unsigned) request, result); + return result; + } + + /* fallback to call original ioctl */ + result = ___ioctl_time64(d, request, arg); + DBG(DBG_IOCTL, "ioctl fd %i request %X: original, result %i\n", d, (unsigned) request, result); + + return result; +} +#endif + int isatty(int fd) { diff --git a/tests/test-umockdev.c b/tests/test-umockdev.c index e8a5462..fba19d8 100644 --- a/tests/test-umockdev.c +++ b/tests/test-umockdev.c @@ -1536,13 +1536,17 @@ t_testbed_script_replay_evdev_event_framing(UMockdevTestbedFixture * fixture, UN int fd; char buf[1024]; - struct timeval dummy = {0}; +#if !defined(_TIME_BITS) && _TIME_BITS != 64 + struct timeval dummy_timeval = {0}; +#else +# define dummy_timeval 0,0 +#endif /* Simple evdev stream - x coordinate followed by SYN, times 2 */ struct input_event dummy_events[] = { - {dummy, 0003, 0000, 2534}, - {dummy, 0000, 0000, 0000}, - {dummy, 0003, 0000, 2200}, - {dummy, 0000, 0000, 0000} + {dummy_timeval, 0003, 0000, 2534}, + {dummy_timeval, 0000, 0000, 0000}, + {dummy_timeval, 0003, 0000, 2200}, + {dummy_timeval, 0000, 0000, 0000} }; umockdev_testbed_add_from_string(fixture->testbed,