From ab6b88073cbcc81753799af2f05040f9f1767ceb Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 5 Sep 2022 22:04:24 -0500 Subject: [PATCH] Fix build with _FILE_OFFSET_BITS=64 --- app/app.pro | 2 +- app/masterhook.c | 79 ++-------------------------------- app/masterhook_internal.c | 90 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 76 deletions(-) create mode 100644 app/masterhook_internal.c diff --git a/app/app.pro b/app/app.pro index c72ea990..dc21b854 100644 --- a/app/app.pro +++ b/app/app.pro @@ -271,7 +271,7 @@ libdrm { linux { message(Master hooks enabled) - SOURCES += masterhook.c + SOURCES += masterhook.c masterhook_internal.c LIBS += -ldl } } diff --git a/app/masterhook.c b/app/masterhook.c index 1180ea57..4eace66d 100644 --- a/app/masterhook.c +++ b/app/masterhook.c @@ -11,9 +11,12 @@ #define _GNU_SOURCE +// NOTE: This file MUST NOT include fcntl.h due to open() -> open64() +// redirection that happens when _FILE_OFFSET_BITS=64! +// See masterhook_internal.c for details. + #include #include -#include #include #include #include @@ -21,16 +24,6 @@ #include #include -// __OPEN_NEEDS_MODE is a glibc-ism, so define it ourselves for other libc -#ifndef __OPEN_NEEDS_MODE -#ifdef __O_TMPFILE -# define __OPEN_NEEDS_MODE(oflag) \ - (((oflag) & O_CREAT) != 0 || ((oflag) & __O_TMPFILE) == __O_TMPFILE) -#else -# define __OPEN_NEEDS_MODE(oflag) (((oflag) & O_CREAT) != 0) -#endif -#endif - // We require SDL 2.0.15+ to hook because it supports sharing // the DRM FD with our code. This avoids having multiple DRM FDs // in flight at the same time which would significantly complicate @@ -96,12 +89,6 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, // master on the Qt FD to allow the new FD to have master. int openHook(const char *funcname, const char *pathname, int flags, va_list va); -// fcntl.h may define open to open64 which will cause us to define open64 twice. -// Remove this redirection to allow our hooks to build properly with _FILE_OFFSET_BITS=64. -#ifdef open -#undef open -#endif - int open(const char *pathname, int flags, ...) { va_list va; @@ -120,64 +107,6 @@ int open64(const char *pathname, int flags, ...) return fd; } -int openHook(const char *funcname, const char *pathname, int flags, va_list va) -{ - int fd; - mode_t mode; - - // Call the real thing to do the open operation - if (__OPEN_NEEDS_MODE(flags)) { - mode = va_arg(va, mode_t); - fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode); - } - else { - mode = 0; - fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags); - } - - // If the file was successfully opened and we have a DRM master FD, - // check if the FD we just opened is a DRM device. - if (fd >= 0 && g_QtDrmMasterFd != -1) { - if (strncmp(pathname, "/dev/dri/card", 13) == 0) { - // It's a DRM device, but is it _our_ DRM device? - struct stat64 fdstat; - - fstat64(fd, &fdstat); - if (g_DrmMasterStat.st_dev == fdstat.st_dev && - g_DrmMasterStat.st_ino == fdstat.st_ino) { - // It is our device. Time to do the magic! - - // This code assumes SDL only ever opens a single FD - // for a given DRM device. - SDL_assert(g_SdlDrmMasterFd == -1); - - // Drop master on Qt's FD so we can pick it up for SDL. - if (drmDropMaster(g_QtDrmMasterFd) < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Failed to drop master on Qt DRM FD: %d", - errno); - // Hope for the best - return fd; - } - - // We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN, - // but since we just dropped the master, we can become master by - // simply creating a new FD. Let's do it. - close(fd); - if (__OPEN_NEEDS_MODE(flags)) { - fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode); - } - else { - fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags); - } - g_SdlDrmMasterFd = fd; - } - } - } - - return fd; -} - // Our close() hook handles restoring DRM master to the Qt FD // after SDL closes its DRM FD. int close(int fd) diff --git a/app/masterhook_internal.c b/app/masterhook_internal.c new file mode 100644 index 00000000..5bebe0ff --- /dev/null +++ b/app/masterhook_internal.c @@ -0,0 +1,90 @@ +// This file contains the private implementation of the open() hook +// which must be in a separate compilation unit due to fcntl.h doing +// unwanted redirection of open() to open64(). + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include +#include + +// __OPEN_NEEDS_MODE is a glibc-ism, so define it ourselves for other libc +#ifndef __OPEN_NEEDS_MODE +#ifdef __O_TMPFILE +# define __OPEN_NEEDS_MODE(oflag) \ + (((oflag) & O_CREAT) != 0 || ((oflag) & __O_TMPFILE) == __O_TMPFILE) +#else +# define __OPEN_NEEDS_MODE(oflag) (((oflag) & O_CREAT) != 0) +#endif +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 15) + +extern int g_QtDrmMasterFd; +extern struct stat64 g_DrmMasterStat; +extern int g_SdlDrmMasterFd; + +int openHook(const char *funcname, const char *pathname, int flags, va_list va) +{ + int fd; + mode_t mode; + + // Call the real thing to do the open operation + if (__OPEN_NEEDS_MODE(flags)) { + mode = va_arg(va, mode_t); + fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode); + } + else { + mode = 0; + fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags); + } + + // If the file was successfully opened and we have a DRM master FD, + // check if the FD we just opened is a DRM device. + if (fd >= 0 && g_QtDrmMasterFd != -1) { + if (strncmp(pathname, "/dev/dri/card", 13) == 0) { + // It's a DRM device, but is it _our_ DRM device? + struct stat64 fdstat; + + fstat64(fd, &fdstat); + if (g_DrmMasterStat.st_dev == fdstat.st_dev && + g_DrmMasterStat.st_ino == fdstat.st_ino) { + // It is our device. Time to do the magic! + + // This code assumes SDL only ever opens a single FD + // for a given DRM device. + SDL_assert(g_SdlDrmMasterFd == -1); + + // Drop master on Qt's FD so we can pick it up for SDL. + if (drmDropMaster(g_QtDrmMasterFd) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to drop master on Qt DRM FD: %d", + errno); + // Hope for the best + return fd; + } + + // We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN, + // but since we just dropped the master, we can become master by + // simply creating a new FD. Let's do it. + close(fd); + if (__OPEN_NEEDS_MODE(flags)) { + fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode); + } + else { + fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags); + } + g_SdlDrmMasterFd = fd; + } + } + } + + return fd; +} +#endif