drm-shim: implement stat/fstat when xstat variants are not there
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>
Thu, 29 Jul 2021 14:35:19 +0000 (17:35 +0300)
committerMarge Bot <eric+marge@anholt.net>
Mon, 2 Aug 2021 00:19:26 +0000 (00:19 +0000)
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 027095065dfb79 ("drm-shim: fix compile with glibc >= 2.33")
Acked-by: Emma Anholt <emma@anholt.net>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12129>

src/drm-shim/drm_shim.c

index 61967ec..9566d42 100644 (file)
@@ -77,11 +77,18 @@ REAL_FUNCTION_POINTER(readdir64);
 REAL_FUNCTION_POINTER(readlink);
 REAL_FUNCTION_POINTER(realpath);
 
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 33
+#define HAS_XSTAT __GLIBC__ == 2 && __GLIBC_MINOR__ < 33
+
+#if HAS_XSTAT
 REAL_FUNCTION_POINTER(__xstat);
 REAL_FUNCTION_POINTER(__xstat64);
 REAL_FUNCTION_POINTER(__fxstat);
 REAL_FUNCTION_POINTER(__fxstat64);
+#else
+REAL_FUNCTION_POINTER(stat);
+REAL_FUNCTION_POINTER(stat64);
+REAL_FUNCTION_POINTER(fstat);
+REAL_FUNCTION_POINTER(fstat64);
 #endif
 
 /* Full path of /dev/dri/renderD* */
@@ -209,11 +216,16 @@ init_shim(void)
    GET_FUNCTION_POINTER(readlink);
    GET_FUNCTION_POINTER(realpath);
 
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 33
+#if HAS_XSTAT
    GET_FUNCTION_POINTER(__xstat);
    GET_FUNCTION_POINTER(__xstat64);
    GET_FUNCTION_POINTER(__fxstat);
    GET_FUNCTION_POINTER(__fxstat64);
+#else
+   GET_FUNCTION_POINTER(stat);
+   GET_FUNCTION_POINTER(stat64);
+   GET_FUNCTION_POINTER(fstat);
+   GET_FUNCTION_POINTER(fstat64);
 #endif
 
    get_dri_render_node_minor();
@@ -278,7 +290,7 @@ PUBLIC int open(const char *path, int flags, ...)
 }
 PUBLIC int open64(const char*, int, ...) __attribute__((alias("open")));
 
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 33
+#if HAS_XSTAT
 /* Fakes stat to return character device stuff for our fake render node. */
 PUBLIC int __xstat(int ver, const char *path, struct stat *st)
 {
@@ -379,6 +391,106 @@ PUBLIC int __fxstat64(int ver, int fd, struct stat64 *st)
 
    return 0;
 }
+
+#else
+
+PUBLIC int stat(const char* path, struct stat* stat_buf)
+{
+   init_shim();
+
+   /* Note: call real stat if we're in the process of probing for a free
+    * render node!
+    */
+   if (render_node_minor == -1)
+      return real_stat(path, stat_buf);
+
+   /* Fool libdrm's probe of whether the /sys dir for this char dev is
+    * there.
+    */
+   char *sys_dev_drm_dir;
+   nfasprintf(&sys_dev_drm_dir,
+              "/sys/dev/char/%d:%d/device/drm",
+              DRM_MAJOR, render_node_minor);
+   if (strcmp(path, sys_dev_drm_dir) == 0) {
+      free(sys_dev_drm_dir);
+      return 0;
+   }
+   free(sys_dev_drm_dir);
+
+   if (strcmp(path, render_node_path) != 0)
+      return real_stat(path, stat_buf);
+
+   memset(stat_buf, 0, sizeof(*stat_buf));
+   stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
+   stat_buf->st_mode = S_IFCHR;
+
+   return 0;
+}
+
+PUBLIC int stat64(const char* path, struct stat64* stat_buf)
+{
+   init_shim();
+
+   /* Note: call real stat if we're in the process of probing for a free
+    * render node!
+    */
+   if (render_node_minor == -1)
+      return real_stat64(path, stat_buf);
+
+   /* Fool libdrm's probe of whether the /sys dir for this char dev is
+    * there.
+    */
+   char *sys_dev_drm_dir;
+   nfasprintf(&sys_dev_drm_dir,
+              "/sys/dev/char/%d:%d/device/drm",
+              DRM_MAJOR, render_node_minor);
+   if (strcmp(path, sys_dev_drm_dir) == 0) {
+      free(sys_dev_drm_dir);
+      return 0;
+   }
+   free(sys_dev_drm_dir);
+
+   if (strcmp(path, render_node_path) != 0)
+      return real_stat64(path, stat_buf);
+
+   memset(stat_buf, 0, sizeof(*stat_buf));
+   stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
+   stat_buf->st_mode = S_IFCHR;
+
+   return 0;
+}
+
+PUBLIC int fstat(int fd, struct stat* stat_buf)
+{
+   init_shim();
+
+   struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
+
+   if (!shim_fd)
+      return real_fstat(fd, stat_buf);
+
+   memset(stat_buf, 0, sizeof(*stat_buf));
+   stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
+   stat_buf->st_mode = S_IFCHR;
+
+   return 0;
+}
+
+PUBLIC int fstat64(int fd, struct stat64* stat_buf)
+{
+   init_shim();
+
+   struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
+
+   if (!shim_fd)
+      return real_fstat64(fd, stat_buf);
+
+   memset(stat_buf, 0, sizeof(*stat_buf));
+   stat_buf->st_rdev = makedev(DRM_MAJOR, render_node_minor);
+   stat_buf->st_mode = S_IFCHR;
+
+   return 0;
+}
 #endif
 
 /* Tracks if the opendir was on /dev/dri. */