プログラマーズマガジン Linux、UNIXの擬似端末



 擬似端末はtelnetデーモンやxtermなどアプリケーション内でログインプロセスや シェルを動作させたいときなどに使用します。ちょうどパイプと同じような働きを します。telnetデーモンやxtermでは次のように擬似端末が使われます。
telnet <-> ネットワーク <-> telnetd <-> 擬似端末 <-> loginやshell
xterm <-> 擬似端末 <-> loginやshell
擬似端末にはmaster側とslave側がありslave側をloginやshellが使用します。 擬似端末は限りある資源で使用する時には、まず誰も使っていない擬似端末を キープしてしまう必要があります。擬似端末は/devの下に用意されており lsコマンドなどで見ることができます。SVR4ならばls /dev/ptsで見ることが できます(/devices/pseudo/pts...へのリンク)。また、BSD系ならls /dev/pty*で 表示されます。擬似端末を使ってログインしているユーザがいればwhoコマンドで pts/0のように表示されます。
 擬似端末のプログラミングはSVR4とBSD系でかなり異なります。両方を比較して 説明していきます。

(1)SVR4での擬似端末の確保
・/dev/ptmxというデバイスをオープンします。オープンしたファイルディスクリプタ をmaster側(master FD)として使用します。
・master FDにたいしgrantpt()、unlockpt()を実行します。
・slave側のデバイス名はptsname()で取得します。
	master =  open("/dev/ptmx", O_RDWR|O_NOCTTY);
	grantpt(master);
	unlockpt(master);

	strcpy(devtty_name, ptsname(master));

(2)BSD系での擬似端末の確保
・/dev/ptyXYという(X、Yを変化させていく)デバイスを順番にオープンしてオープン可能な デバイスを見つけます。 ・slave側のデバイス名は/dev/ttyXYを使用します。
	strcpy(ptyname, "/dev/ptyXY");
	for(...){
		pty_name[8] = 'p'、'q'、...順番に変化させていく
		pty_name[9] = '0'、'1'、...順番に変化させていく
		master = open(pty_name, O_RDWR);
		if(master != -1)
			break;
	}

	strcpy(devtty_name, pty_name);
	dev_tty_name[5] = 't';
(3)slave側の準備
・どのような用途で使うかにもよりますが、ログインプロセスを実行するような 場合はここでfork()します。
・取得したslave側のデバイス名でオープンしファイルディスクリプタをslave側( slave FD)とします。
・必用ならioctl()で設定を行います。
・ログインプロセスを実行するような場合は、dup2を使って標準入出力などをslaveに 置き換え必要なプロセスを実行します。

(4)データのやり取り
・キーボードからの入力はmaster FDにwriteすればshellプロセスなどに渡されます。
・実行したプロセスの出力結果はslave FDがわから書き込まれ、master FDをreadすれば 受け取れます。