単純なシェル リダイレクトによって、/dev/ptmx
新しい疑似端末が取得されるようです。
$ ls /dev/pts; ls /dev/pts </dev/ptmx
0 1 2 ptmx
0 1 2 3 ptmx
fd クレームを所有するプロセスが/dev/ptmx
終了するとすぐに消えますが、保持するのは簡単です。
$ PS1='<$(ls -1 "$@" /dev/pts/*|uniq -u)> $ ' \
exec 3<>/dev/ptmx "$0" -si -- /dev/pts/*
</dev/pts/3> $ ls /dev/pts; exec 3>&-
0 1 2 3 ptmx
<> $ ls /dev/pts; exec 3<>/dev/ptmx
0 1 2 ptmx
</dev/pts/3> $ exit
擬似端末を得るには、単にopen()
on するだけで十分のようです。これでシェルが -/dev/ptmx
(またはリダイレクトを実行するプロセス)- pty のマスター側の所有者。
しかし、スレーブ側をどのように割り当てるか - またはできるスレーブ側を割り当てますか? 割り当てられる場合、何ができますか? 読み取り/書き込み/フラッシュのタイミングに影響を与えることはできますかstty
? 参照時に、スレーブ側のプロセスは新しい pty にリンクしますか/dev/tty
?
答え1
@muruがコメントで指摘しているように、シェルだけで作成されたptyをインターフェースする簡単な方法はないようです。私は一部を除いてすべて管理しましたunlockpt()
。私が読んだものによるとここカーネルには、新しく作成された pty ロックを無効にするためのコンパイル時オプションがいくつかあるかもしれませんが、私はそれをしたくありませんでした。そのため、別の方法を実行しました。
実際は必要ありませんでしたgrantpt()
。ここ/dev/pts/[num]
デバイス ファイルの UID/GID を変更するだけです。ただし、man mount
それを処理するより簡単な方法があります。devpts
マウント オプションをいくつか示します。
uid=value
そしてgid=value
- 新しく作成されたPTYの所有者またはグループを指定された値に設定します。何も指定されていない場合は、作成プロセスのUIDとGIDに設定されます。たとえば、 端末 GID 5のグループに属し、
gid=5
新しく作成されたPTYは端末グループ。
- 新しく作成されたPTYの所有者またはグループを指定された値に設定します。何も指定されていない場合は、作成プロセスのUIDとGIDに設定されます。たとえば、 端末 GID 5のグループに属し、
私のシステムでは、デフォルトですでにそのようになっていました。しかし、それを読んだ後、結局変更したいかもしれないと気づきました。次のセクションには次のように書かれています。
ptmxmode=value
- ファイルシステム内の新しい ptmx デバイス ノードのモードを設定します
devpts
。 - 複数のインスタンスのサポート
devpts
(上記のオプションを参照)により、各インスタンスはファイルシステムnewinstance
のルートにプライベートptmxノードを持ちます。devpts
(通常/dev/pts/ptmx
)。 - カーネルの古いバージョンとの互換性のため、新しい ptmx ノードのデフォルト モードは です
0000
。 は、ptmx ノードのより便利なモードを指定するため、オプションを指定するptmxmode=value
場合はこれを強くお勧めします。newinstance
- ファイルシステム内の新しい ptmx デバイス ノードのモードを設定します
そうしなくてもうまくいったのですが、私はそのアイデアが気に入ったので0640
、カーネルドキュメントちなみに、カーネル ドキュメント リンクでは、マウント オプションについて詳しく説明しています。これは非常に優れており、基本的にマウントnewinstance
ごとに個別に名前空間化された pty グループを取得できるようになります。/dev/ptmx
とにかく、その他主に以下のとおりです。
mount -o remount,newinstance,gid=5,ptmxmode=0640 /dev/pts
mount --bind /dev/pts/ptmx /dev/ptmx
...カーネルのドキュメントで推奨されているように - 理由についてはリンクを参照してください。また、 に数行追加することで、上記のコマンドの効果を永続的にしました/etc/fstab
。
そして...
<<\C cc -xc - -o pts
#include <stdio.h>
int main(int argc, char *argv[]) {
if(unlockpt(0)) return 2;
char *ptsname(int fd);
printf("%s\n",ptsname(0));
return argc - 1;
}
C
これは、stdin を呼び出そうとする小さな C プログラムをコンパイルしunlockpt()
、成功した場合は新しく作成されロック解除された pty の名前を出力し、stdout
そうでない場合は何も言わずに 2 を返します。
それができたら、自分で作れるスクリーニングされた次のようなプロセス:
exec 3<>/dev/ptmx
...現在のシェルでマスター側の fd を取得するには...
(setsid -c "$0" -i 2>&1|tee log) <>"$(./pts <&3)" 3>&- >&0 &
これにより、疑似端末の反対側でバックグラウンドで対話型シェルが実行されます。シェルは、印刷されたものすべてを>&3
ユーザー入力として解釈します。
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$ hey
$
基本的に、バックグラウンドでログに記録されたインタラクティブな通訳者が得られる(または、これらで実行したいその他のもの)ala はscreen
それほどオーバーヘッドがなく、任意のファイル記述子を選択できます。
現在のシェルが所有するマスター側のfdは、スレーブ側の入力を提供する唯一の手段であり、現在のシェルプロセスによってのみ書き込み可能です。(そしてその子供たち)書き込みによって相手側と通信することができ>&3
、必要に応じて同じファイルまたはログ ファイルから読み取ることができます。
そしてstty
結局ターミナル上で動作します:
mikeserv@localhost$ echo stty -a ">$(tty)" >&3
speed 38400 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc
-ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl
echoke