allow screen blank for privacy

This commit is contained in:
JerryXiao 2023-08-11 00:25:26 +08:00
parent e7b8b59156
commit 3586a776a4
Signed by: Jerry
GPG key ID: 22618F758B5BE2E5
6 changed files with 210 additions and 2 deletions

View file

@ -19,7 +19,7 @@ IF(NOT HAVE_LINUX_API_HEADERS)
message(FATAL_ERROR "linux-api-headers not found")
ENDIF()
add_executable(kmsvnc kmsvnc.c drm.c input.c keymap.c va.c)
add_executable(kmsvnc kmsvnc.c drm.c input.c keymap.c va.c drm_master.c)
target_include_directories(kmsvnc PUBLIC
${LIBDRM_INCLUDEDIR}
${LIBDRM_INCLUDEDIR}/libdrm

84
drm.c
View file

@ -10,6 +10,7 @@
#include "drm.h"
#include "va.h"
#include "drm_master.h"
extern struct kmsvnc_data *kmsvnc;
@ -154,6 +155,17 @@ void drm_sync_noop(int drmfd)
void drm_cleanup() {
if (kmsvnc->drm) {
if (kmsvnc->drm->gamma && kmsvnc->drm->gamma->size && kmsvnc->drm->gamma->red && kmsvnc->drm->gamma->green && kmsvnc->drm->gamma->blue) {
if (drmModeCrtcSetGamma(kmsvnc->drm->drm_master_fd ?: kmsvnc->drm->drm_fd, kmsvnc->drm->plane->crtc_id, kmsvnc->drm->gamma->size, kmsvnc->drm->gamma->red, kmsvnc->drm->gamma->green, kmsvnc->drm->gamma->blue)) perror("Failed to restore gamma");
}
if (kmsvnc->drm->gamma && kmsvnc->drm->gamma->red) {
free(kmsvnc->drm->gamma->red);
kmsvnc->drm->gamma->red = kmsvnc->drm->gamma->green = kmsvnc->drm->gamma->blue = NULL;
}
if (kmsvnc->drm->gamma) {
free(kmsvnc->drm->gamma);
kmsvnc->drm->gamma = NULL;
}
if (kmsvnc->drm->drm_ver) {
drmFreeVersion(kmsvnc->drm->drm_ver);
kmsvnc->drm->drm_ver = NULL;
@ -202,6 +214,10 @@ void drm_cleanup() {
close(kmsvnc->drm->drm_fd);
kmsvnc->drm->drm_fd = 0;
}
if (kmsvnc->drm->drm_master_fd > 0) {
close(kmsvnc->drm->drm_master_fd);
kmsvnc->drm->drm_master_fd = 0;
}
if (kmsvnc->drm->plane_res) {
drmModeFreePlaneResources(kmsvnc->drm->plane_res);
kmsvnc->drm->plane_res = NULL;
@ -458,6 +474,14 @@ int drm_open() {
{
KMSVNC_FATAL("card %s open failed: %s\n", kmsvnc->card, strerror(errno));
}
if (kmsvnc->screen_blank && !drmIsMaster(drm->drm_fd)) {
drm->drm_master_fd = drm_get_master_fd();
drm->drm_master_fd = drm->drm_master_fd > 0 ? drm->drm_master_fd : 0;
if (kmsvnc->debug_enabled) {
fprintf(stderr, "not master client, master fd %d\n", drm->drm_master_fd);
}
}
drm->drm_ver = drmGetVersion(drm->drm_fd);
printf("drm driver is %s\n", drm->drm_ver->name);
@ -469,6 +493,66 @@ int drm_open() {
if (drm_refresh_planes(1)) return 1;
if (kmsvnc->screen_blank) {
drm->gamma = malloc(sizeof(struct kmsvnc_drm_gamma_data));
if (!drm->gamma) KMSVNC_FATAL("memory allocation error at %s:%d\n", __FILE__, __LINE__);
memset(drm->gamma, 0, sizeof(struct kmsvnc_drm_gamma_data));
drmModeCrtc *target_crtc = drmModeGetCrtc(drm->drm_fd, drm->plane->crtc_id);
if (target_crtc) {
drm->gamma->size = (uint32_t)target_crtc->gamma_size;
drm->gamma->red = malloc(drm->gamma->size*sizeof(uint16_t)*3);
if (!drm->gamma->size) {
fprintf(stderr, "drm->gamma->size = %u, not setting gamma.\n", drm->gamma->size);
}
else if (!drm->gamma->red) {
fprintf(stderr, "memory allocation error at %s:%d\n", __FILE__, __LINE__);
fprintf(stderr, "not setting gamma.\n");
}
else {
memset(drm->gamma->red, 0, drm->gamma->size*sizeof(uint16_t)*3);
drm->gamma->green = drm->gamma->red + drm->gamma->size;
drm->gamma->blue = drm->gamma->red + drm->gamma->size*2;
if (kmsvnc->screen_blank_restore) {
int step = 0x10000 / drm->gamma->size;
for (int i = 0; i < drm->gamma->size; i++) {
drm->gamma->red[i] = drm->gamma->green[i] = drm->gamma->blue[i] = step * i;
}
}
else {
// legacy api, but weston also uses this, so whatever
drmModeCrtcGetGamma(drm->drm_fd, drm->plane->crtc_id, drm->gamma->size, drm->gamma->red, drm->gamma->green, drm->gamma->blue);
}
if (kmsvnc->debug_enabled) {
for (int i = 0; i < drm->gamma->size; i++) {
fprintf(stderr, "gamma: %05d %05hu %05hu %05hu\n", i, drm->gamma->red[i], drm->gamma->green[i], drm->gamma->blue[i]);
}
}
uint16_t *new_gamma_red = malloc(drm->gamma->size*sizeof(uint16_t)*3);
if (!new_gamma_red) {
fprintf(stderr, "memory allocation error at %s:%d\n", __FILE__, __LINE__);
fprintf(stderr, "not setting gamma.\n");
}
else {
memset(new_gamma_red, 0, drm->gamma->size*sizeof(uint16_t)*3);
uint16_t *new_gamma_green = new_gamma_red + drm->gamma->size;
uint16_t *new_gamma_blue = new_gamma_red + drm->gamma->size*2;
if (drmModeCrtcSetGamma(drm->drm_master_fd ?: drm->drm_fd, drm->plane->crtc_id, drm->gamma->size, new_gamma_red, new_gamma_green, new_gamma_blue)) perror("Failed to set gamma");
}
if (new_gamma_red) {
free(new_gamma_red);
new_gamma_red = NULL;
}
}
}
else {
fprintf(stderr, "Did not get a crtc structure, not setting gamma.\n");
}
if (target_crtc) {
drmModeFreeCrtc(target_crtc);
target_crtc = NULL;
}
}
drm->mfb = drmModeGetFB2(drm->drm_fd, drm->plane->fb_id);
if (!drm->mfb) {
KMSVNC_FATAL("Failed to get framebuffer %u: %s\n", drm->plane->fb_id, strerror(errno));

99
drm_master.c Normal file
View file

@ -0,0 +1,99 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#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 && drmIsMaster(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 = count - 1; n > 0; 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;
}

5
drm_master.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#include "kmsvnc.h"
int drm_get_master_fd();

View file

@ -238,6 +238,8 @@ static struct argp_option kmsvnc_main_options[] = {
{"input-height", 0xff07, "0", 0, "Explicitly set input height"},
{"input-offx", 0xff08, "0", 0, "Set input offset of x axis on a multi display system"},
{"input-offy", 0xff09, "0", 0, "Set input offset of y axis on a multi display system"},
{"screen-blank", 0xff0a, 0, OPTION_ARG_OPTIONAL, "Blank screen with gamma set on crtc"},
{"screen-blank-restore-linear", 0xff0b, 0, OPTION_ARG_OPTIONAL, "Restore linear values on exit in case of messed up gamma"},
{"wakeup", 'w', 0, OPTION_ARG_OPTIONAL, "Move mouse to wake the system up before start"},
{"disable-input", 'i', 0, OPTION_ARG_OPTIONAL, "Disable uinput"},
{"desktop-name", 'n', "kmsvnc", 0, "Specify vnc desktop name"},
@ -337,6 +339,12 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
kmsvnc->input_offy = offset_y;
}
break;
case 0xff0a:
kmsvnc->screen_blank = 1;
break;
case 0xff0b:
kmsvnc->screen_blank_restore = 1;
break;
case 'w':
kmsvnc->input_wakeup = 1;
break;

View file

@ -42,6 +42,8 @@ struct kmsvnc_data
int input_height;
int input_offx;
int input_offy;
char screen_blank;
char screen_blank_restore;
struct kmsvnc_drm_data *drm;
struct kmsvnc_input_data *input;
struct kmsvnc_keymap_data *keymap;
@ -85,9 +87,18 @@ struct kmsvnc_drm_funcs
void (*convert)(const char *, int, int, char *);
};
struct kmsvnc_drm_gamma_data
{
uint32_t size;
uint16_t *red;
uint16_t *green;
uint16_t *blue;
};
struct kmsvnc_drm_data
{
int drm_fd;
int drm_master_fd;
drmVersionPtr drm_ver;
int prime_fd;
drmModePlane *plane;
@ -95,7 +106,7 @@ struct kmsvnc_drm_data
drmModePlaneRes *plane_res;
drmModeFB2 *mfb;
drmModeFB2 *cursor_mfb;
u_int32_t plane_id;
uint32_t plane_id;
int mmap_fd;
size_t mmap_size;
off_t mmap_offset;
@ -113,6 +124,7 @@ struct kmsvnc_drm_data
size_t kms_cpy_tmp_buf_len;
char *kms_cursor_buf;
size_t kms_cursor_buf_len;
struct kmsvnc_drm_gamma_data *gamma;
};
struct kmsvnc_va_data