execve()
「vi」などを実行し、すべての IO を親プロセスにリダイレクトできる分岐した子プロセスを取得するにはどうすればよいですか?
組み込み Linux プロセスから、ネットワーク経由で接続された PC ソフトウェア インターフェイスにシェルを渡そうとしています。シェル プロセスの IO は、既存のプロトコルを介したネットワーク トランスポート用のアプリ固有のメッセージにパッケージ化されます。
最初に、単にpipe2()
, fork()
, dup2()
,を使用して IO をリダイレクトしていexecve()
ました。これにより、リモート側で tty が得られなかったためscreen
、などは機能しませんでした。
現在、私は を使用してforkpty
おり、screen
ほとんどが機能しますが、他の多くは機能しません ( vi
、stty
、など)。現在の問題は、子プロセスが tty を制御していないことです。
私は TIOCSCTTY を試してみましたが、うまくいきませんでした。
これが多かれ少なかれ私が持っているものです:
bool ExternalProcess::launch(...)
{
...
winsize winSize;
winSize.ws_col = 80;
winSize.ws_row = 25;
winSize.ws_xpixel = 10;
winSize.ws_ypixel = 10;
_pid = forkpty(&_stdin, NULL, NULL, &winSize);
//ioctl(_stdin, TIOCNOTTY, NULL);
if (!_pid && (_pid != -1))
{
// this is the child process
char tty[4096];
strncpy(tty, ttyname(STDIN_FILENO), sizeof(tty));
tty[sizeof(tty)-1]=0;
FILE* fp = fopen("debug.txt", "wt"); // no error checking - temporary test code
fprintf(fp, "slave TTY %s", tty);
//if (ioctl(_stdin, TIOCSCTTY, NULL) < 0)
if (ioctl(STDIN_FILENO, TIOCSCTTY, NULL) < 0)
{
fprintf(fp, "ioctl() TIOCSCTTY %s\n", strerror(errno));
fflush(fp);
}
else
{
fprintf(fp, "SET CONTROLLING TTY!");
fflush(fp);
}
fclose(fp);
// command, args, env populated elsewhere
execve(command, args, env);
...
// fail path
_exit(-1);
return false;
}
_stdout = _stdin;
...
// enter select() loop reading/writing _stdin, _stdout
}
デバッグ ファイルに次のような結果が表示されます。
slave TTY /dev/pts/5
SET CONTROLLING TTY!
しかし、まだ多くのアプリがtcsetattr()
エラーで失敗しています。これは tty の制御の問題であると考えるのは正しいですか? どうすれば修正できますか?
編集
微修正。STDIN_FILENO で ioctl TIOCSCTTY を実行すると、上記のデバッグ ファイルのように動作しますが、親プロセスへの IO リダイレクトが中断されます。
編集2
わかりました、私はこれをよりよく理解し始めています。tcsetattr() の背後にある ioctl のカーネル ソースを見ると、tty を変更しようとすると、呼び出しているプロセスに SIGTTIN と SIGTTOU が送信されています。
これを実行できるのはフォアグラウンド プロセスだけであり、それらはバックグラウンド プロセスであるかのように実行されます。フォーク後、execve() の前にこれらのシグナルを SIG_IGN に設定しようとしましたが、うまくいきませんでした。これのセマンティクスは理解できますが、私のリダイレクト シナリオでは、execve() されたプロセスがフォアグラウンド プロセスであるかのように動作しても安全です。問題は...どうやってそうするのですか?手がかりを求めて、引き続きカーネル コードを検索します。