緊急用・非常用メンテナンスのポートとして、シリアルコンソールをセットアップしたときに、アレコレと詰まって混乱した部分をまとめ直しておく。
ポイント
シリアルコンソールログインを登録・起動するとき、ログインできない表示されないなど、トラブル対応に私が調べて知ったことは、次の3点であった
- ボーレート/baut rate
- パーミッションとオーナー
- systemd edit
ボーレート
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のシリアルコンソールがボーレートを固定せずに起動しない設定になってることが問題である。
参考資料
- systemd の上書き(edit)について→ configuration - How do I override or configure systemd services? - Ask Ubuntu
- デフォルトのボーレートは9600の件について → The linux system keeps changing the baud rate of the port to default (9600). Is there a better way to change the baud rate of the port permanently? - Unix & Linux Stack Exchange