给定的 X 进程在哪个虚拟终端上运行?

Nic*_*son 9 freebsd xorg x11

当 X 启动时,它会搜索最低的未使用 VT,并附加到它。我的问题是,当有多个正在运行的 X 进程时,我需要能够确定哪个是当前活动的进程。

这是一个 *BSD 问题,因为在 linux 上这很容易:X 将其控制终端设置为ttyN,或者,在非常旧的发行版中,它在命令行中指定为vtN. 所以,我正在运行一个服务,我看到当前活动的VT是tty7,并且有两个X服务器在运行,很容易分辨出哪个对应于当前终端。(这是一个合理的情况:也许用户使用了 GNOME/KDE 的“切换用户”功能或使用 运行了两个服务器startx。)可能想要跟踪活动 X 服务器的示例应用程序是x11vnc(它是从我正在开发的软件中分叉出来的) )。

但是在 FreeBSD 上,控制终端不会告诉你任何事情。当 X 从 ttyv1 启动时,它仍然是控制终端。

更新

我已经做了尽职调查并阅读了 X 代码。经过一番摸索,我现在更清楚发生了什么。

lnx_init.c 中,X 服务器确实setsid为自己创建了一个新会话,然后直接打开一个 fd 对其ttyN进行VT_ACTIVATEioctl。相当标准;从没有控制终端的进程向没有控制进程的终端打开 fd 将两者关联起来,服务器保持 fd 打开,因此可以保证终端将保持 X 服务器的控制终端。

现在,在bsd_init.c 中,打开 fd 到 tty 以用作帧缓冲区并不会使其成为控制终端(事实上,如果没有setsid,从xinitttyv2 上启动的 BSD Xserver将保持 ttyv2 作为其 ctty!)。

问题于 2012-04-09 进一步更新和清理。

Nic*_*son 3

有一个更通用的方法。在所有具有虚拟终端的平台上,包括 Linux 和 BSD,Xserver 都会为其运行的终端保留一个开放的 fd。在 Linux 上,检查 X 进程的控制终端以区分多个 X 进程(使用 的第七个字段/proc/<..>/stat)仍然是一个很好的解决方案。但更一般地说,查看 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;
}
Run Code Online (Sandbox Code Playgroud)