シリアルを介してgettyを設定しようとすると、ジョブ制御は機能しません。

シリアルを介してgettyを設定しようとすると、ジョブ制御は機能しません。

シリアル経由でログインするようにgettyを設定しようとしています(主に実験用)。

ほとんどすべての構成で同じ現象が発生します。デフォルトのシェルがある場合は、bashログイン後に次のメッセージが表示されます。

-bash: cannot set terminal process group (15297): Inappropriate ioctl for device
-bash: no job control in this shell

その後、動作しないことを証明するためにCtrl + Cを使用してプログラムを停止することはできません。

$ sleep 30
^C

そして何の信号も送信されないようです。

私が試した設定は次のとおりです。

私はこれら2つのコマンドを試しました

# copied from raspberry pi:
sudo /sbin/agetty --keep-baud 115200,38400,9600 ttyUSB0 vt220
# something else I read somewhere
sudo getty -L ttyUSB0 9600 vt100
# (I know I'm mixing and matching a lot of differences but the result is the same)

私はscreenとpicocomをクライアントとして使ってみました。

私はrasberry piをサーバーとして使用し、2つの異なるUbuntuラップトップを試してみました。

私は2つのFTDI、2つのRS-485 USBアダプタ、ゲッティ側の内蔵RS232、クライアント側のUSB RS232を使ってみました。

また、デフォルトのシェルをshとdashに変更してみました。メッセージを受信できませんでしたが、Ctrl + Cはまだ期待どおりに機能しません。

興味深いのは、Raspberry Piが自動的に設定し、/dev/ttyAMA0私が入力したgettyコマンドを正しく使用すると、ジョブ制御が機能することです!

そして端末設定もほぼ同じです。 (実際には-iutf8を除く)

FTDI接続とpicocomを実行するための端末設定は次のとおりです。

$ stty -a -F /dev/ttyUSB0
speed 9600 baud; rows 24; columns 80; 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 = <undef>; discard = <undef>; 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 -flusho -extproc
$ stty -a -F /dev/ttyUSB1
speed 9600 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;
discard = ^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 -flusho -extproc

私は何が間違っていましたか? Raspberry Piに組み込まれているシリアルポートの組み込み構成で動作するのはなぜですか?

答え1

違いは、コマンドにあるのではなく、コマンドが実行される環境にあります。

通常、gettyはシステムサービスマネージャ(init)から直接生成されます。 systemdでは.service、SysVの世界ではinittabエントリがあります(init.dスクリプトではありません!)。これと他の端末で生成されるものとの間にはいくつかの違いがあります。

まず、端末で開始されたプロセスはそれを自分の資産に継承します。「制御端末」、これはシェルジョブ制御の最も重要なパラメータです。ps auxor - サービスプロセスps -efでこれを見ることができ、最初はcttyがないので、gettyがマークされた端末を開くときにシェルが実行されると、その端末はジョブ制御のための制御端末になります。

ただし、xtermで開始されたgettyは入力/出力がシリアルポートにルーティングされますが、xterm ptyは制御ttyのままです。 getty自体は気にしませんが、シェルはそうではありません。返品間違った制御 tty を継承すると、ジョブ制御ができなくなります。

$ ps -C agetty
  PID TTY          TIME CMD
 1136 tty1     00:00:00 agetty
14022 pts/22   00:00:00 agetty
      ^-- should be ttyS0!

制御端末は/ dev / ttyを定義し、ジョブ制御信号が送信されるプロセスを定義し、端末が閉じられたときに終了するプロセス(SIGHUP)を定義します。シェルがstdin / out ttyとは異なる制御ttyを継承すると、あらゆる種類の奇妙なことが発生する可能性があります。

プロセスは、setid()呼び出しなど、さまざまな方法で古い端末から切り離すことができます。伝統的に、/etc/init.dスクリプトはプロセスを「デーモン化する」ためにこれを行いますが、gettyは自動的にそれを使用しません。予期しないこのように実行されるため、プログラムされません。 (setsidこれが起こるように強制的に使用できるツールがありますが、してはいけないここでも使えます。最初から正しい方法で作業を実行する必要があります。 )

理想的にはsystemctl start serial-getty@ttyUSB0gettyをクリーンな環境で実行してみてください。カスタマイズオプションが必要な場合は、systemctl edit [--full]gettyを直接実行するよりもサービスをカスタマイズすることをお勧めします。 (systemdを使用していない場合は編集してください/etc/inittab。通常は例が含まれています。inittabtelinit qを再ロードするには実行してください。)

シェルで開始されたプロセスとサービスマネージャを介して開始されたプロセスとの間には、比較的マイナーな違いがたくさんあります。 stdin/stdout/stderr はターミナルで最初に始まります (getty はプロセスを閉じて再び開きますが、すべてのサービスがこれを行うわけではありません)。変数は「sudo」から継承され、これはcgroupのリソース制限に影響を与える可能性があり、systemd-logindセッションは継承され、SELinuxセキュリティコンテキストを開始できません。 (またはAppArmorプロファイルまたはSMACKタグ)が継承されます(使用している場合)。

関連情報