それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

getty でttyUSB0/ttyS0 で シリアルコンソールでログインで注意すること/baud rate の初期化

緊急用・非常用メンテナンスのポートとして、シリアルコンソールをセットアップしたときに、アレコレと詰まって混乱した部分をまとめ直しておく。

ポイント

シリアルコンソールログインを登録・起動するとき、ログインできない表示されないなど、トラブル対応に私が調べて知ったことは、次の3点であった

ボーレート

ttyS0 のデフォルトのbaut rate は linuxで実験する限り9600である。

次のコマンドで確認する。

### ボーレート(速度)を表示
sudo stty -F /dev/ttyUSB0 speed
### すべての設定を表示
sudo stty -F /dev/ttyUSB0 -a

ボーレートを指定する。

sudo /usr/bin/stty -F /dev/ttyS0 speed 9600
sudo /usr/bin/stty -F /dev/ttyS0 speed 115200

ボーレート指定なし→設定済が使われる。

screenなどボーレートを指定無しで起動すると、tty に設定済みのボーレートが利用される。設定もしてないときはデフォルト9600が利用される。

たとえば、次のコマンド

sudo /usr/bin/stty -F /dev/ttyS0 speed 9600
sudo screen /dev/ttyS0 

screen コマンドでボーレートを省略している。

この場合、設定済みのbaut rate が利用される。

なので。上記のコマンドは sudo screen /dev/ttyS0 9600 と同じである。

逆もありえる

逆も起こり得るので注意が必要

ボーレートを9600に指定しているが、screen で 115200を使ったため、シリアルポートには115200が設定されたまま残るのである。

$ sudo /usr/bin/stty -F /dev/ttyS0 speed
9600
$ sudo systemctl restart  serial-getty@ttyS0 # 9600で起動している
## ここでちょっとttyを使う。
$ sudo screen /dev/ttyS0 115200
[screen is terminating]
$ sudo /usr/bin/stty -F /dev/ttyS0 speed
115200
$ sudo systemctl restart  serial-getty@ttyS0 # 115200で起動する

コンソールにログインが出てこない、通信ができない、文字が表示されないというときは、無意識に変更してないか、他プログラムでボーレート変更がなかったか、これらを確認するのが肝心である。

screenの利用前と利用後でレートが変わっていることに注意を払う必要がある。

意識してないと嵌まり込む、ときに2台のLinux A,Bをシリアルコンソールで接続していてA→Bの接続後、逆方向へ B→Aでagetty を起動しときなど。ログインを相互にマニュアルで使うときに嵌まり込む。

パーミッションとオーナー

以下は、getty 起動前、起動後、ログイン後のttyUSB0のパーミッションの変化を記録したものである

最初は、dialout である

takuya@pi-zero:~ $ ls  -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0  2月  4 13:41 /dev/ttyUSB0

getty を起動すると、パーミッションとグループが代わる。

takuya@pi-zero:~ $ sudo systemctl start serial-getty@ttyUSB0.service
takuya@pi-zero:~ $ ls  -l /dev/ttyUSB0
crw--w---- 1 root tty 188, 0  2月  4 13:43 /dev/ttyUSB0

シリアルコンソール経由で takuya でログインしたあとである。

takuya@pi-zero:~ $ ls  -l /dev/ttyUSB0
crw------- 1 takuya tty 188, 0  2月  4 13:44 /dev/ttyUSB0
takuya@pi-zero:~ $

ttyUSB0 は許可されたグループで汎用に使える その後getty が起動しシリアルが tty デバイスになるので、 TTY グループになる getty 経由で takuya がログインしたので takuya 以外は使えないようになる。

少し考えれば理解できる。ちょっとしたことだけど、なんでもかんでもtty を 777 にするとか、dialoutに所属すれば使えるって話じゃない。

TTYになるとは、「ユーザーと出入力をやり取りする端末として認知される。」ということですね。ログイン後には「そのユーザー専用のtty端末」として専有される。他ユーザーが不用意にアクセスし入出力を読み取れないようにオーナーが代わる。

systemd serial-getty の問題

ここまで見てきたとおり、ボーレート・パーミッションが頻繁に代わるために、serial-getty で問題が生じることがある。

$ sudo /usr/bin/stty -F /dev/ttyS0 speed
9600
# 9600で起動している
$ sudo systemctl restart  serial-getty@ttyS0 
## ここでちょっとttyを使う。
$ sudo screen /dev/ttyS0 115200
[screen is terminating]
$ sudo /usr/bin/stty -F /dev/ttyS0 speed
115200
# 115200で起動してしまう。
$ sudo systemctl restart  serial-getty@ttyS0 

上記の例のように、ttyUSB0/ttyS0 でログインようにgettyを使っていると、知らない間に、ボーレートが変わってしまうことがある。

この様な問題に対応したいと思う。

getty起動時のボーレート固定

serial-getty@.service は次のように、agetty を起動する記述になっている。

$ sudo systemctl cat  serial-getty@ttyS0
(略)
[Service]
ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,57600,38400,9600 %I $TERM

一見すると、ボーレートを適宜選んでくれるように見える

しかし、screen 115200 でボーレートを変更後に起動すると agetty は 115200 に、screen 9600で利用後に起動すると、agetty は 9600になる。

困ったものである。起動時に固定できないのか。

対応策には3つが考えられる。

  • 自分で service を書く
  • 起動前にttyのレートを設定し直す
  • 起動時のオプションを変える。

3つの対応策をそれぞれ systemd のコンフィグで解釈すると

  • 自分で service を書く→ service 新規作成
  • 起動前にttyのレートを設定し直す → ExecStartPreを追加
  • 起動時のオプションを変える。 → ExecStartを上書き

となる。

楽に管理するなら、上書き・追記をすればいいのである。

上書き・追記をする方法として sytemd edit コマンドでoverrideが可能である。

systemctl override でExecStartPreを追加対応する。

systemd のユニットに定義を「追加」するのはとても楽ちんである。

sudo systemctl edit serial-getty@ttyUSB0.service

上記のコマンドで$EDITORが起動し、追加したい項目を記入できる

たとえば、/usr/bin/stty -F /dev/ttyUSB0 speed 115200 をagetty の起動前に挟み込みたい場合は次のように追記すればいい

[Service]
ExecStartPre=/usr/bin/stty -F /dev/%I speed 115200

ExecStartPre はその名の通り、ExecStartより先に実行される。 %I はサービス・ユニット名称から取られる serial-getty@ttyUSB0.service はもともとserial-getty@.service として定義されているので serial-getty@ttyUSB0.service を作ったら %I=ttyUSB0になる。

EDITORを終了したら、自動的に systemctl daemon-reload が呼ばれるので

sudo systemctl status serial-getty@ttyUSB0.service

で、状況を確認すればいい、記述ミスがあれば status に出てくる

最後に起動すれば、オッケデーである。 これでttyUSB0 のボーレートを設定して起動するのである。

ExecStartPreではなくExecStart記入すればいいのではないかと思うかもれない。 これは、できない。ExecStartは複数記述できるために、systemctl edit では追記になり、上書きにならないのである。(ほんとsystemctl はめんどくさい しかも、Type=よってeditの上書き動作が違う)

起動時のオプションを変える。 → ExecStartを上書き

ちょっとsystemctl を齧った人が思いつくのが、この方法だと思う。

コピーして上書きする

cp /lib/systemd/system/serial-getty@ttyUSB0.service /etc/systemd/system
sudo -E vim /etc/systemd/system/serial-getty@ttyUSB0.service

でもちょっとまってほしい。systemdにはコピー上書きする方法がある。

systemctl edit --full による 完全なコピー作成

systemctl edit --full を使えば、先のコマンド cp と同じことを一気にやってくれる。

sudo systemctl edit --full serial-getty@ttyUSB0.service

コピー作成して定義を上書き

getty を起動するときに、レートを固定するように既存の ExecStartコメントアウトして起動すればいいのである。

#ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,57600,38400,9600 %I $TERM
ExecStart=-/sbin/agetty -o '-p -- \\u' 115200 %I $TERM

service 新規作成は不要

慣れた人は自分で service を書くぜ!と考えがちですが、わざわざ記述しなくても、似たようなことは追記・コピー(edit/ edit --full ) で可能なのです。

2023-10-01

baud rate がふとした瞬間に書き換わっていた。

また注意しないといけない。

agetty のbaud raite と 、現在の baud rate をあわせてあげる。

ssh  server.lan "sudo /sbin/agetty -o '-p -- \\u' 115200 /dev/ttyS1"
ssh  client.lan "sudo /sbin/agetty -o '-p -- \\u' 115200 /dev/ttyUSB0"

stty -F /dev/ttyUSB0 speed で速度を確認。

ssh client.lan "sudo stty -F /dev/ttyUSB0 speed"

screen 起動時に指定する

ssh client.lan
sudo screen /dev/ttyUSB0 115200

受け側は、systemdなのでbaud rate が boot 時にGrubなどで変わってる可能性がある。

ssh server.lan
sudo /sbin/agetty -o '-p -- \\u' 115200 /dev/ttyS1
sudo systemctl status serial-getty@ttyS1.service
sudo systemctl enable serial-getty@ttyS1.service
sudo systemctl restart serial-getty@ttyS1.service

無事に接続できたら、二度と変わらないように edit して追記する。

sudo systemctl edit serial-getty@ttyS1.service --full

まとめ

serial-getty@.serviceパーミッションとボーレートで混乱してスタックするので、ちゃんと確認する手段を調べてから、利用するのがいい。

画面が表示されない!ログインのダイアログが出てこない!ログが流れてこない!と焦ってUSBシリアルデバイスを変えてみたり、中華製シリアルUSB変換を疑う前に、ちゃんと一つずつ確認すのが肝心だった。

とくに、systemdの動作は、謎が多いので本当に苦労させられる。最初はusb認識前にagetty ttyUSBで起動してるんじゃないかと疑ったりもしたし本当に苦労した

systemd のserial-gettyのシリアルコンソールがボーレートを固定せずに起動しない設定になってることが問題である。

参考資料