Xが起動すると、未使用の最低VTを検索して接続します。私の問題は、複数のXプロセスが実行されているときにどのプロセスが現在アクティブなプロセスであるかを識別できることです。
これは* BSDの問題です。なぜなら、Linuxでは簡単だからです。 Xは制御端末をに設定するttyN
か、非常に古いディストリビューションではコマンドラインでそれを指定しますvtN
。したがって、サービスを実行しているが現在アクティブなVTがありtty7
、2つのXサーバーが実行されている場合、どのサーバーが現在の端末に対応しているかを簡単に知ることができます。 (これは合理的なシナリオです。おそらく、ユーザーがGNOME / KDEの「ユーザー切り替え」機能を使用するか、2つのサーバーを実行している可能性があります。startx
)アクティブXサーバーの例に従うアプリケーションの例は次のx11vnc
とおりです。 m開発中))。
しかし、FreeBSDでは、制御端末は何も知らない。 X が ttyv1 から始まっても、それはまだ制御端末です。
修正する
私はデューデリジェンスを行い、Xコードを読みました。いくつかの検索を行った後、何が起こっているのかをよりよく知ることができるようになりました。
存在するlnx_init.c、Xサーバーはsetsid
独自に新しいセッションを作成し、直接fdを開いてttyN
ioctlします。VT_ACTIVATE
制御端末のないプロセスから制御プロセスのない端末にfdを開くと、2つの接続が行われ、サーバーはfdを開いたままにして、端末がまだ制御端末であることを保証します。 Xサーバーの。
今bsd_init.c、フレームバッファとして使用するためにttyのfdを開くことは制御端末にはなりません(実際にそうでない場合、setsid
ttyv2で始まるBSD Xserverはxinit
ttyv2をcttyに保ちます!)。
問題は2012年4月9日に追加で更新され、整理されました。
答え1
より一般的なアプローチがあります。 LinuxやBSDを含む仮想端末を持つすべてのプラットフォームでは、Xserverは実行中の端末の公開fdを維持します。 Linuxでは、/proc/<..>/stat
複数のXプロセス(使用されている7番目のフィールド)を区別するためにXプロセスの制御端末を確認することはまだ良い解決策です。ただし、より一般的には、Xプロセス用に開いているfdのリストを見ると、Xserverが実行されている端末を取得するためにいくつかの簡単なフィルタリングが必要です。 (残念ながら、開いているファイル記述子のリストを取得することはプラットフォームによって異なります...)sysctl
BSDなどのプラットフォームでは、コードは次のようになり、いくつかのエラー処理も可能です。
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;
}