¿En qué terminal virtual se ejecuta un determinado proceso X?

8

Cuando X comienza, busca el VT no utilizado más bajo y se le asigna. Mi problema es que cuando hay varios procesos X en ejecución, necesito poder identificar cuál es el actualmente activo.

Esta es una pregunta * BSD, porque en Linux es fácil: X establece que su terminal de control sea ttyN, o, en distribuciones muy antiguas, se especifica en la línea de comandos como vtN. Entonces, estoy ejecutando un servicio y veo que el VT actualmente activo es tty7, y hay dos servidores X ejecutándose, es fácil saber cuál corresponde al terminal actual. (Este es un caso razonable: quizás el usuario usó la funcionalidad 'cambiar de usuario' de GNOME / KDE o ejecutó dos servidores usando startx). Una aplicación de ejemplo que podría querer seguir al servidor X activo es x11vnc(que está bifurcada por el software que estoy desarrollando )

Sin embargo, en FreeBSD, el terminal de control no le dice nada. Cuando X se inicia desde ttyv1, ese sigue siendo el terminal de control.

Actualizar

Hice la diligencia debida y leí el código X. Después de buscar un poco, ahora es más claro para mí lo que está sucediendo.

En lnx_init.c , el servidor X hace setsiduna sesión nueva para sí mismo, luego abre un archivo fd ttyNpara realizar un VT_ACTIVATEioctl en él. Bastante estándar; abrir el fd a un terminal sin proceso de control desde un proceso sin terminal de control asocia los dos, y el servidor mantiene el fd abierto, por lo que se garantiza que el terminal seguirá siendo el terminal de control para el servidor X.

Ahora, en bsd_init.c , abrir el fd en el tty para usarlo como framebuffer no lo convierte en un terminal de control (y, de hecho, sin setsidBSD Xserver iniciado desde xinitttyv2 mantendrá ttyv2 como su ctty!).

Pregunta actualizada y limpiada el 09/04/2012.

Nicholas Wilson
fuente

Respuestas:

3

Hay una forma más general. En todas las plataformas con terminales virtuales, incluidos Linux y BSD, Xserver retiene un fd abierto en el terminal en el que se ejecuta. En Linux, sigue siendo una buena solución verificar el terminal de control del proceso X para distinguir entre múltiples procesos X (use el séptimo campo de /proc/<..>/stat). Sin embargo, de manera más general, mire a través de la lista de fds abiertos del proceso X, y solo necesita un filtrado simple para salir del terminal en el que se ejecuta Xserver. (Desafortunadamente, obtener la lista de fds abiertos depende nuevamente de la plataforma ...) Para sysctlplataformas como BSD, el código será similar a esto, más algunos errores de manejo:

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;
}
Nicholas Wilson
fuente