На каком виртуальном терминале работает данный X-процесс?

8

Когда 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, которое будет использоваться в качестве кадрового буфера, не делает его управляющим терминалом (и фактически, при отсутствии setsidBSD Xserver, запущенный с xinitttyv2, будет хранить ttyv2 в качестве своего ctty!).

Вопрос далее обновляется и очищается 2012-04-09.

Николас Уилсон
источник

Ответы:

3

Есть более общий способ. На всех платформах с виртуальными терминалами, включая linux и BSD, Xserver сохраняет открытый fd для терминала, на котором он работает. В Linux остается хорошим решением проверить управляющий терминал процесса X, чтобы различать несколько процессов X (используйте седьмое поле /proc/<..>/stat). В более общем смысле, посмотрите список открытых файлов X-процесса, и для того, чтобы выйти из терминала, на котором работает X-сервер, требуется лишь простая фильтрация. (К сожалению, получение списка открытых 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;
}
Николас Уилсон
источник