Xorg

給定的 X 程序在哪個虛擬終端上執行?

  • April 9, 2012

當 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_ACTIVATEioctl。相當標準;從沒有控制終端的程序向沒有控制程序的終端打開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;
}

引用自:https://unix.stackexchange.com/questions/32884