#define _GNU_SOURCE #include #include #include #include #include #include #include #include "drm_master.h" extern struct kmsvnc_data *kmsvnc; static inline int clone_fd(pid_t pid, int target_fd) { int pidfd = syscall(SYS_pidfd_open, pid, 0); if (pidfd <= 0) { perror("pidfd_open"); return -1; } int cloned = syscall(SYS_pidfd_getfd, pidfd, target_fd, 0); if (cloned <= 0) { perror("pidfd_getfd"); } close(pidfd); return cloned; } static inline int cmp_fds(pid_t pid, const char *drm_pth) { if (pid == 1) return -1; char path[PATH_MAX+1]; snprintf(path, PATH_MAX+1, "/proc/%d/fd", pid); struct dirent **fdlist; int count = scandir(path, &fdlist, NULL, versionsort); int ret = -1; if (count >= 0) { for (int n = 0; n < count; n++) { if (ret == -1 && fdlist[n]->d_type == DT_LNK) { char link_pth[PATH_MAX+1]; char real_pth[PATH_MAX+1]; snprintf(link_pth, PATH_MAX+1, "%s/%s", path, fdlist[n]->d_name); memset(real_pth, 0, PATH_MAX+1); realpath(link_pth, real_pth); if (!strncmp(real_pth, drm_pth, PATH_MAX)) { int fd = atoi(fdlist[n]->d_name); if (fd > 0) { int cloned = clone_fd(pid, fd); if (cloned > 0 && !drmSetMaster(cloned)) { ret = cloned; //if (kmsvnc->debug_enabled) { fprintf(stderr, "found drm master pid=%d, fd=%d, cloned=%d\n", pid, fd, cloned); //} } else { if (cloned > 0) close(cloned); } } } } free(fdlist[n]); fdlist[n] = NULL; } free(fdlist); fdlist = NULL; } return ret; } int drm_get_master_fd() { char drm_pth[PATH_MAX+1]; memset(drm_pth, 0, PATH_MAX+1); realpath(kmsvnc->card, drm_pth); struct dirent **proclist; int count = scandir("/proc", &proclist, NULL, versionsort); int ret = -1; if (count >= 0) { for (int n = 0; n < count; n++) { if (ret == -1 && proclist[n]->d_type == DT_DIR) { pid_t pid = (pid_t)atoi(proclist[n]->d_name); if (pid > 0) { int cloned = cmp_fds(pid, drm_pth); if (cloned > 0) { ret = cloned; } } } free(proclist[n]); proclist[n] = NULL; } free(proclist); proclist = NULL; } else { perror("open /proc"); } return ret; }