Sur quel terminal virtuel s'exécute un processus X donné?

8

Lorsque X démarre, il recherche le VT inutilisé le plus bas et s'y attache. Mon problème est que lorsqu'il y a plusieurs processus X en cours d'exécution, je dois être en mesure d'identifier celui qui est actuellement actif.

C'est une question * BSD, car sur linux c'est facile: X définit son terminal de contrôle pour être ttyN, ou, sur les très anciennes distributions, il est spécifié sur la ligne de commande comme vtN. Donc, j'exécute un service et je vois que le VT actuellement actif est tty7, et qu'il y a deux serveurs X en cours d'exécution, il est facile de dire lequel correspond au terminal actuel. (C'est un cas raisonnable: peut-être que l'utilisateur a utilisé la fonctionnalité de changement d'utilisateur de GNOME / KDE ou a exécuté deux serveurs à l'aide startx.) Un exemple d'application qui pourrait vouloir suivre le serveur X actif est x11vnc(qui est issu du logiciel que je développe ).

Sur FreeBSD cependant, le terminal de contrôle ne vous dit rien. Lorsque X est démarré à partir de ttyv1, cela reste le terminal de contrôle.

Mise à jour

J'ai fait preuve de diligence raisonnable et j'ai lu le code X. Après avoir chassé, il est maintenant plus clair pour moi ce qui se passe.

Dans lnx_init.c , le serveur X setsideffectue une nouvelle session pour lui-même, puis ouvre un fd ttyNjuste après pour faire un VT_ACTIVATEioctl dessus. Assez standard; l'ouverture du fd à un terminal sans processus de contrôle à partir d'un processus sans terminal de contrôle associe les deux, et le serveur garde le fd ouvert, il est donc garanti que le terminal restera le terminal de contrôle pour le serveur X.

Maintenant, dans bsd_init.c , ouvrir le fd au tty à utiliser comme framebuffer n'en fait pas un terminal de contrôle (et en fait, sans setsid, BSD Xserver démarré à partir xinitde ttyv2 gardera ttyv2 comme ctty!).

Question encore mise à jour et nettoyée le 2012-04-09.

Nicholas Wilson
la source

Réponses:

3

Il existe une manière plus générale. Sur toutes les plates-formes dotées de terminaux virtuels, y compris linux et BSD, Xserver conserve un fd ouvert sur le terminal sur lequel il fonctionne. Sur linux, il reste une bonne solution pour vérifier le terminal de contrôle du processus X pour distinguer plusieurs processus X (utilisez le septième champ de /proc/<..>/stat). Plus généralement cependant, parcourez la liste des fds ouverts du processus X, et il n'a besoin que d'un simple filtrage pour sortir du terminal sur lequel Xserver s'exécute. (Malheureusement, obtenir la liste des fds ouverts dépend à nouveau de la plate-forme ...) Pour les sysctlplates-formes comme BSD, le code ressemblera à ceci, plus une gestion des erreurs:

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
la source