出力がシリアルコンソールにリダイレクトされる組み込みLinuxデバイスで実行されるデーモンがあります。
my_daemon > /dev/ttyS0
ただし、ユーザーがexit
シリアルインタフェースでシェルを実行すると、シリアルデバイスが再生成され、シリアルデバイスが一時的に消え、デーモンがクラッシュする可能性があります。
このようなことが起こらないようにする(簡単な)方法はありますか?パイプターゲットが消えた後に再接続を試みるラッパー(またはプロセスと組み合わせた名前付きパイプ)が途中にありますか? 「オフライン」時間をバッファリングする必要はありません。
答え1
次のシェル関数を使用します。
relay () (
#!/bin/sh
sink="${1:-/dev/ttyS0}"
exec 4<&0 2>/dev/null
while :; do
cat 3<"$sink" >/proc/self/fd/3
<&4 cat >/dev/null & sleep 2; kill -s PIPE "$!" || exit
done
)
このように:
my_daemon | relay
#!/bin/sh
shebang( ) のようなものが関数内では何の意味もないようです。コードだけがどのシェルをターゲットにしているかを示します。関数の代わりにスクリプトを作成するには、実行可能ファイルに関数本体を保存すると、shebangが機能します。
いくつかのヒントがあります:
リダイレクトまたは同様のリダイレクトを使用する
cat >/dev/ttyS0
ソリューションには欠陥がある可能性があります。 「シリアルデバイスを再作成する」とは、/dev/ttyS0
存在しない時間枠があることを意味すると仮定します。また、コードを実行しているユーザー(おそらくroot)がにアクセスできるとします/dev/
。>/dev/ttyS0
そのファイルが存在しない場合は、通常のファイルが生成されます。これはテストできますが、! [ -e /dev/ttyS0 ]
テストの前後にファイルが消えることがあります>/dev/ttyS0
。したがって、私は
cat 3<"$sink" >/proc/self/fd/3
基本的$sink
に使用します/dev/ttyS0
。最初のリダイレクトは読み取り用にファイルを開こうとし、2番目のリダイレクトはstdoutを同じファイルにリダイレクトしようとします。秘密は、2番目のリダイレクトが新しいファイルを生成しないことです。/dev/ttyS0
別のアプローチは、ユーザーがアクセスできるがファイルを生成できないように配置することです/dev/
。この場合、このトリックは必要なく、使用されるソリューションは>/dev/ttyS0
安全でなければなりません。何らかの理由でアクセスできない場合は、これが効果的な方法になる可能性があります/proc/self/fd/3
。最初のものcat
は次のとおりです。cat >"$sink"
最初の猫の目的は、受信者にデータを送信することです。リダイレクトが失敗したり、受信者が最終的に消えることがあります。ここで2番目のものがやってくる
cat
。 2番目の目的は、cat
受信者がいないときにデータを削除することです。すぐに再生成する必要がある場合は、/dev/ttyS0
2番目の項目は必要ありませんcat
。しかし、あなたの場合、パス名がすぐに再表示されるかどうかはわかりません。私の考えになければ、代わりに続け/dev/ttyS0
たいと思います。my_daemon
防ぐ。 2番目はcat
続行されます。単純な
cat >/dev/null
ことは良い考えではなく、/dev/ttyS0
再作成後も無期限に実行することができます。秘密は非同期で実行し、数秒後に終了することです。その後、コードが繰り返され、最初のコードがcat
再びシンクを開こうとします。<&4
能力が必要なので必要なものです。ジョブ制御が無効になると(デフォルトでは関数付きのサブシェルまたはスクリプト内にある)、コマンドは&
標準入力がリダイレクトまたは/dev/null
同等のファイルで終了します。前exec 4<&0
とこれのおかげで、2番目の<&4
ものはcat
とにかく関数の標準入力から読み取ることができます。kill
2番目のエントリがcat
もう存在しない場合は失敗する可能性がありますsleep 2
。出るとmy_daemon
これが起こります。kill … || exit
EOF条件を検出する技術です。たとえば、date | relay
Dueにもかかわらず終了する必要がありますsleep
。このトリックがない場合、コードは無限に繰り返されます。EOF の場合、2 番目の PID が
cat
再利用され、kill
誤ったプロセスをターゲットにする可能性があります。 LinuxのAFAIK PIDは順次割り当てられます。シーケンスが約2秒で循環して同じPIDを取得する可能性はほとんどありません。トリックは、2番目のエントリがcat
EOFのために早く終了したときにkill
チェックしてno such process
失敗するので、exit
そのようなことが起こると仮定します。
デフォルト値はです$sink
。最初のコマンドライン引数として指定して、/dev/ttyS0
別のパス名(たとえば)を引き続き使用できます。… | relay foo
一般ファイルをテストするには、ファイルが開いている間に削除する必要があります。それを破壊しないでください。私のテストでは、set -x
何が起こっているのかをよく確認し、Ctrl+d cat
リクエスト時に簡単に終了(最初)。
私のテストプラットフォーム:Linuxカーネル5.15.0、Busybox 1.30.1のsh
()。ash
答え2
たぶん、次のようなものがあります。
バッファーペーストプログラム
#!/bin/sh
while true;do
cat buffer_file > /dev/ttyS0
done
次に、次を実行します。
my_daemon > buffer_file
./bufferpaster.sh
答え3
いいですね。情報がなくても、strace
有効なデバイスファイルを確認/待機できます。デーモンが改行(for read
)で終わる行を出力すると仮定すると、次のようになります。
tty=/dev/ttyS0
my_daemon | (
# Start with a read of 1 line, to catch when the daemon exits, and then "cat" the rest
while read line; do
# check/wait for device file to exist and be writable
until [ -w $tty ]; do sleep 1; done
echo "$line" >> $tty
cat >> $tty
done
)
>>
テストではなくファイルを最初にテストしたい場合に備えて添付します。ttyS0
答え4
stdoutをログファイルに書き込み、initsystem inittab / systemd tail -Fログファイルをシリアルポートに送信します。 Init は、tail がシリアルポートで実行されていることを確認し、ユーザーはデーモンの作成に集中できます。ログローテーションを実行する必要がありますが、一部のユーティリティ(Piper、Multilogなど)を使用できます。以下は、stdoutをパイピングしてログファイルを生成する方法の完全な説明です。https://superuser.com/questions/291368/log-rotation-of-stdout)