Em qual terminal virtual está executando um determinado processo X?

8

Quando o X inicia, ele procura o VT mais baixo não utilizado e o anexa a ele. Meu problema é que, quando há vários processos X em execução, preciso identificar qual é o atualmente ativo.

Esta é uma pergunta * BSD, porque no linux é fácil: X define seu terminal de controle ttyNou, em distribuições muito antigas, é especificado na linha de comando como vtN. Portanto, estou executando um serviço e vejo que o VT atualmente ativo está tty7e há dois servidores X em execução, é fácil saber 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 tenha executado dois servidores usando startx). Um exemplo de aplicativo que pode querer seguir o servidor X ativo é x11vnc(que é bifurcado do software que estou desenvolvendo). )

No FreeBSD, porém, o terminal de controle não diz nada. Quando o X é iniciado a partir de ttyv1, esse permanece o terminal de controle.

Atualizar

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

No arquivo lnx_init.c , o servidor X faz setsiduma nova sessão para si próprio e, em seguida, abre um fd para ttyNlogo depois para VT_ACTIVATEexecutar um ioctl nele. Bastante padrão; abrir o fd para um terminal sem processo de controle de um processo sem terminal de controle associa os dois, e o servidor mantém o fd aberto, por isso é garantido que o terminal continuará sendo o terminal de controle do servidor X.

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

Pergunta atualizada e limpa em 09/04/2012.

Nicholas Wilson
fonte

Respostas:

3

Existe uma maneira mais geral. Em todas as plataformas com terminais virtuais, incluindo linux e BSD, o Xserver mantém um fd aberto no terminal em que está sendo executado. No linux, continua sendo uma boa solução verificar se o terminal de controle do processo X distingue entre vários processos X (use o sétimo campo de /proc/<..>/stat). De maneira mais geral, consulte a lista de arquivos abertos do processo X, e ele precisa apenas de uma filtragem simples para sair do terminal em que o Xserver está executando. (Infelizmente, obter a lista de fds abertos é novamente dependente da plataforma ...) Para sysctlplataformas como BSD, o código será semelhante a esse, além de algum tratamento de erro:

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
fonte