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

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

当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进行ioctl。VT_ACTIVATE相当标准;从没有控制终端的进程向没有控制进程的终端打开 fd 会将两者关联起来,并且服务器保持 fd 打开,因此可以保证该终端仍然是 X 服务器的控制终端。

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

问题于 2012 年 4 月 9 日进一步更新和清理。

答案1

有一个更通用的方法。在所有具有虚拟终端的平台上,包括 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;
}

相关内容