X가 시작되면 사용되지 않은 가장 낮은 VT를 검색하여 연결합니다. 내 문제는 여러 X 프로세스가 실행 중일 때 어느 프로세스가 현재 활성 프로세스인지 식별할 수 있어야 한다는 것입니다.
이는 *BSD 문제입니다. 왜냐하면 Linux에서는 간단하기 때문입니다. X는 제어 터미널을 로 설정 ttyN
하거나 아주 오래된 배포판에서는 명령줄에서 이를 지정합니다 vtN
. 그래서 서비스를 실행 중인데 현재 활성화된 VT가 이고 tty7
, 두 개의 X 서버가 실행 중이면 어떤 서버가 현재 터미널에 해당하는지 쉽게 알 수 있습니다. (이것은 합리적인 시나리오입니다. 아마도 사용자가 GNOME/KDE의 "사용자 전환" 기능을 사용하거나 두 개의 서버를 실행 중일 수 있습니다 startx
.) 활성 X 서버의 예를 따르려는 예제 응용 프로그램은 다음 x11vnc
과 같습니다. m 개발 중)).
그러나 FreeBSD에서는 제어 터미널이 아무 것도 알려주지 않습니다. X가 ttyv1에서 시작되면 여전히 제어 터미널입니다.
고쳐 쓰다
나는 실사를 수행하고 X 코드를 읽었습니다. 몇 가지 검색을 한 후에 이제 무슨 일이 일어나고 있는지 더 잘 알 수 있게 되었습니다.
존재하다lnx_init.c, X 서버는 setsid
자체적으로 새 세션을 생성한 다음 fd를 직접 열어 ttyN
ioctl합니다. VT_ACTIVATE
제어 터미널이 없는 프로세스에서 제어 프로세스가 없는 터미널로 fd를 여는 것은 두 가지를 연결하고 서버는 fd를 열어두므로 터미널이 여전히 제어 터미널임을 보장합니다. X 서버의.
지금bsd_init.c, 프레임 버퍼로 사용하기 위해 tty의 fd를 여는 것은 제어 터미널로 만들지 않습니다(사실 그렇지 않은 경우 setsid
ttyv2에서 시작된 BSD Xserver는 xinit
ttyv2를 ctty로 유지합니다!).
문제는 2012년 4월 9일에 추가로 업데이트되고 정리되었습니다.
답변1
보다 일반적인 접근 방식이 있습니다. Linux 및 BSD를 포함하여 가상 터미널이 있는 모든 플랫폼에서 Xserver는 실행 중인 터미널에 대해 공개 fd를 유지 관리합니다. Linux에서는 /proc/<..>/stat
여러 X 프로세스(사용된 일곱 번째 필드)를 구별하기 위해 X 프로세스의 제어 터미널을 확인하는 것이 여전히 좋은 솔루션입니다. 그러나 보다 일반적으로 X 프로세스에 대해 열려 있는 fd 목록을 살펴보면 Xserver가 실행 중인 터미널을 가져오는 데 몇 가지 간단한 필터링만 필요합니다. (불행히도 열린 파일 설명자 목록을 가져오는 것은 플랫폼에 따라 다릅니다...) sysctl
BSD와 같은 플랫폼의 경우 코드는 다음과 유사하며 일부 오류 처리도 가능합니다.
int ttyByOpenFds(int curPid) {
int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_FILEDESC, curPid };
size_t sizeGuess = 50*sizeof(kinfo_file);
char* buf = malloc(sizeGuess);
int rv = sysctl(ctl, 4, buf, &sizeGuess, 0, 0);
if (rv < 0 && errno == ESRCH) return 0;
else if (rv < 0 && errno == ENOMEM) { /* try again */ }
else if (rv < 0) throw SystemException("unexpected error getting args", errno);
char* position = buf;
while (position < buf + sizeGuess) {
kinfo_file* kfp = reinterpret_cast<kinfo_file*>(position);
position += kfp->kf_structsize;
if (kfp->kf_type != KF_TYPE_VNODE) continue;
if (kfp->kf_vnode_type != KF_VTYPE_VCHR) continue;
if (kfp->kf_fd < 0) continue;
char* name = devname(kfp->kf_un.kf_file.kf_file_rdev, S_IFCHR);
if (!name) continue;
unsigned int ttynum = 0;
if (sscanf(name, "ttyv%u", &ttynum) != 1) continue;
if (ttynum < 8 && kfp->kf_fd <= 2) continue; // stderr going to a console
return ttynum;
}
return 0;
}