Em qual terminal virtual um determinado processo X está sendo executado?

8

Quando o X inicia, ele procura pelo menor VT não utilizado e anexa a ele. Meu problema é que, quando há vários processos X em execução, preciso identificar qual deles está ativo no momento.

Esta é uma questão * do BSD, porque no linux é fácil: o X configura seu terminal de controle como ttyN , ou, em distribuições muito antigas, é especificado na linha de comando como vtN . Então, estou executando um serviço e vejo que o VT atualmente ativo é tty7 , e há dois servidores X em execução, é fácil dizer qual deles corresponde ao terminal atual. (Este é um caso razoável: talvez o usuário tenha usado a funcionalidade 'switch user' do GNOME / KDE ou executado dois servidores usando startx .) Um exemplo de aplicativo que pode querer seguir o servidor X ativo é x11vnc (que é bifurcado o software que estou desenvolvendo).

No FreeBSD, o terminal de controle não informa nada. Quando X é iniciado a partir de ttyv1, esse continua sendo o terminal de controle.

Atualizar

Eu fiz a devida diligência e li o código X. Depois de caçar, agora está mais claro para mim o que está acontecendo.

Em lnx_init.c , o servidor X usa setsid para fazer uma nova sessão para si mesmo e, em seguida, abre um fd para ttyN logo após fazer um VT_ACTIVATE ioctl nele. Bastante padrão; abrir o fd para um terminal sem nenhum processo de controle de um processo sem terminal de controle associa os dois, e o servidor mantém o fd aberto, então é garantido que o terminal continuará sendo o terminal de controle do servidor X.

Agora, em bsd_init.c , abrindo o fd para o tty a ser usado como o framebuffer não o torna um terminal de controle (e de fato, sem setsid , o BSD Xserver iniciado a partir de xinit em ttyv2 manterá ttyv2 como seu ctty !).

Pergunta mais atualizada e limpa em 2012-04-09.

    
por Nicholas Wilson 27.02.2012 / 23:57

1 resposta

2

Existe um caminho mais geral. Em todas as plataformas com terminais virtuais, incluindo linux e BSD, o Xserver mantém um fd aberto para o terminal em que está sendo executado. No linux, continua sendo uma boa solução verificar o terminal de controle do processo X para distinguir entre múltiplos processos X (use o sétimo campo de /proc/<..>/stat ). Mais geralmente, olhe através da lista de fds abertos do processo X, e só precisa de alguma filtragem simples para sair do terminal onde o Xserver está rodando. (Infelizmente, obter a lista de fds abertos é novamente dependente da plataforma ...) Para plataformas sysctl como o BSD, o código será semelhante a este, além de um tratamento de erros:

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;
}
    
por 09.04.2012 / 18:11