給定的 X 程序在哪個虛擬終端上執行?
當 X 啟動時,它會搜尋最低的未使用 VT,並附加到它。我的問題是,當有多個正在執行的 X 程序時,我需要能夠確定哪一個是目前活動的。
這是一個 *BSD 問題,因為在 linux 上很容易:X 將其控制終端設置為
ttyN
,或者,在非常舊的發行版上,它在命令行上指定為vtN
. 所以,我正在執行一個服務,我看到目前活動的 VT 是tty7
,並且有兩個 X 伺服器在執行,很容易分辨哪一個對應於目前終端。(這是一個合理的案例:也許使用者使用了 GNOME/KDE 的“切換使用者”功能,或者使用startx
.x11vnc
)。但是在 FreeBSD 上,控制終端不會告訴您任何資訊。當 X 從 ttyv1 啟動時,它仍然是控制終端。
更新
我已經完成了盡職調查並閱讀了 X 程式碼。在四處尋找之後,我現在更清楚發生了什麼。
在lnx_init.c中,X 伺服器
setsid
會為自己創建一個新會話,然後ttyN
直接打開一個 fd 以對其執行VT_ACTIVATE
ioctl。相當標準;從沒有控制終端的程序向沒有控制程序的終端打開fd將兩者關聯起來,並且伺服器保持fd打開,因此可以保證終端仍然是X伺服器的控制終端。現在,在bsd_init.c中,將 fd 打開到 tty 以用作幀緩衝區並不會使其成為控制終端(事實上,如果沒有
setsid
,從 ttyv2 啟動的 BSD Xserverxinit
將保持 ttyv2 作為其 ctty!)。問題在 2012-04-09 進一步更新和清理。
還有一種更通用的方法。在所有具有虛擬終端的平台上,包括 linux 和 BSD,Xserver 都會為執行它的終端保留一個打開的 fd。在 linux 上,檢查 X 程序的控制終端以區分多個 X 程序(使用 的第七個欄位
/proc/<..>/stat
)仍然是一個很好的解決方案。更一般地說,查看 X 程序的打開 fd 列表,它只需要一些簡單的過濾就可以得到執行 Xserver 的終端。(不幸的是,獲取打開的 fds 列表又是依賴於平台的……)對於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; }