特定のXプロセスが実行されている仮想端末はどれですか?


8

Xが起動すると、Xは未使用の最低のVTを検索し、それにアタッチします。私の問題は、実行中のXプロセスが複数ある場合、現在アクティブなプロセスを特定できるようにする必要があることです。

これは* BSDの質問です。Linuxでは簡単です。Xは制御端末をに設定するttyNか、非常に古いディストリビューションでは、コマンドラインでと指定されていvtNます。したがって、サービスを実行していて、現在アクティブなVTがtty7であり、2つのXサーバーが実行されていることがわかります。どちらが現在の端末に対応するかは簡単にわかります。(これは合理的なケースです:おそらく、ユーザーはGNOME / KDEの「ユーザー切り替え」機能を使用したか、を使用して2つのサーバーを実行しましたstartx。)アクティブなXサーバーをフォローしたいアプリケーションの例はx11vnc(私が開発しているソフトウェアから分岐したものです) )。

ただし、FreeBSDでは、制御端末は何も通知しません。Xがttyv1から起動されると、制御端末のままになります。

更新

私はデューデリジェンスを行い、Xコードを読みました。探し回った後、何が起こっているのかがはっきりしました。

lnx_init.c、Xサーバが行いsetsid、その後にFD開き、自身のために新鮮なセッションを作るためにttyN行うにストレートの後にVT_ACTIVATE、その上のioctl。かなり標準的です。制御端末のないプロセスから端末にfdを開くと、その2つが関連付けられ、サーバーはfdを開いたままにするため、端末がXサーバーの制御端末として残ることが保証されます。

現在、bsd_init.cで、フレームバッファーとして使用するためにttyにfdを開いても、制御端末にはなりません(実際には、なしのsetsid場合、xinitttyv2 から起動したBSD Xserverはttyv2をcttyとして保持します!)。

質問は2012-04-09にさらに更新およびクリーンアップされました。

回答:


3

より一般的な方法があります。LinuxやBSDを含む、仮想端末を備えたすべてのプラットフォームで、Xserverは、それが実行されている端末へのオープンfdを保持します。Linuxでは、複数のXプロセスを区別するためにXプロセスの制御ターミナルをチェックすることは、依然として良い解決策です(の7番目のフィールドを使用/proc/<..>/stat)。ただし、より一般的には、Xプロセスの開いているfdsのリストを確認します。Xserverが実行されている端末を取得するには、いくつかの単純なフィルタリングが必要です。(残念ながら、オープンfdsのリストを取得することもプラットフォームに依存します...)sysctlBSDなどのプラットフォームの場合、コードは次のようになり、いくつかのエラー処理が行われます。

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.