Auf welchem ​​virtuellen Terminal läuft ein bestimmter X-Prozess?

8

Wenn X gestartet wird, sucht es nach dem niedrigsten nicht verwendeten VT und hängt daran an. Mein Problem ist, dass ich bei mehreren laufenden X-Prozessen feststellen muss, welcher der aktuell aktiven ist.

Dies ist eine * BSD-Frage, da es unter Linux einfach ist: X setzt sein steuerndes Terminal auf ttyNoder bei sehr alten Distributionen in der Befehlszeile als vtN. Ich führe also einen Dienst aus und sehe, dass die derzeit aktive VT aktiv ist tty7und zwei X-Server ausgeführt werden. Es ist leicht zu erkennen, welcher dem aktuellen Terminal entspricht. (Dies ist ein vernünftiger Fall: Möglicherweise hat der Benutzer die GNOME / KDE-Funktion "Benutzer wechseln" verwendet oder zwei Server ausgeführt startx.) Eine Beispielanwendung, die möglicherweise dem aktiven X-Server folgen möchte, ist x11vnc(die aus der von mir entwickelten Software stammt) ).

Unter FreeBSD sagt Ihnen das steuernde Terminal jedoch nichts. Wenn X von ttyv1 aus gestartet wird, bleibt dies das steuernde Terminal.

Aktualisieren

Ich habe die Due Diligence durchgeführt und den X-Code gelesen. Nach einigem Herumjagen ist mir jetzt klarer, was los ist.

In lnx_init.c erstellt der X-Server setsideine neue Sitzung für sich selbst und öffnet anschließend eine fd ttyN, um eine VT_ACTIVATEioctl darauf auszuführen. Ziemlich normal; Das Öffnen des fd für ein Terminal ohne Steuerungsprozess von einem Prozess ohne steuerndes Terminal verbindet die beiden, und der Server hält den fd offen, sodass garantiert ist, dass das Terminal das steuernde Terminal für den X-Server bleibt.

Wenn Sie in bsd_init.c das fd für das tty öffnen , das als Framebuffer verwendet werden soll, wird es nicht zu einem steuernden Terminal (und tatsächlich setsidbehält BSD Xserver, das von xinitttyv2 aus gestartet wurde, ttyv2 als ctty bei!).

Frage weiter aktualisiert und bereinigt am 09.04.2012.

Nicholas Wilson
quelle

Antworten:

3

Es gibt einen allgemeineren Weg. Auf allen Plattformen mit virtuellen Terminals, einschließlich Linux und BSD, behält Xserver eine offene FD für das Terminal bei, auf dem es ausgeführt wird. Unter Linux bleibt es eine gute Lösung, nach dem steuernden Terminal des X-Prozesses zu suchen, um zwischen mehreren X-Prozessen zu unterscheiden (verwenden Sie das siebte Feld von /proc/<..>/stat). Im Allgemeinen sehen Sie sich jedoch die Liste der offenen Felder des X-Prozesses an, und es ist nur eine einfache Filterung erforderlich, um das Terminal zu verlassen, auf dem der X-Server ausgeführt wird. (Leider ist das Abrufen der Liste der offenen fds wieder plattformabhängig ...) Bei sysctlPlattformen wie BSD sieht der Code ähnlich aus, plus einige Fehlerbehandlungen:

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
quelle