Bashを使用したSTDIN注入のための対話型プロセスラッピング

Bashを使用したSTDIN注入のための対話型プロセスラッピング

SIGTERMを完全に無視するゲームサーバープログラム(SRCDS)を実行しています。サーバーを完全にシャットダウンする唯一の方法は、インタラクティブに「quit」と入力することです。

SIGTERMをキャプチャしてプログラムのSTDINに「終了」を送信するbashスクリプトでこのプログラムをラップする方法はありますか?それ以外の場合、通常の操作では、ラッパーはSTDINとSTDOUTがまったく存在しないかのように渡す必要があります。

私が達成したい目標の図:

一般外科:

--- STDIN --->  |             |  --- STDIN --->  |                |
                | Bash Script |                  | Server Program |
<-- STDOUT ---  |             |  <-- STDOUT ---  |                |

SIGTERMは以下を送信します。

                                     "quit"
--- STDIN --->  |             |  --- STDIN --->  |                |
-- SIGTERM -->  | Bash Script |                  | Server Program |
<-- STDOUT ---  |             |  <-- STDOUT ---  |                |

答え1

プログラムが端末で実行されると予想されるかどうかによって異なります。もしそうなら、これはできませんbash。同様のものを使用する必要がありますexpect。例:

ラッパー。予想:

puts "<<< pid=[pid] >>>"
spawn {*}$argv
trap {send "quit\n"} SIGTERM
interact

BCを例に挙げましょう。

expect wrapper.expect bc -q

<<< pid=4771 >>>
spawn bc -q

kill 4771別のウィンドウでAを使用すると、行がexpectに転送されます。これは子プロセスのpidではなくプロセスのpidです。quitbc4771expectbc

別のオプションは、ioctlを使用してTIOCSTI現在の端末に行を挿入することです。quitただし、これはシェルでは実行できず、まだ小さなC(またはPerl、Pythonなど)プログラムが必要です。呼び出しますioctl()TIOCSTIすでにOpenBSDではシステムから削除されます)。

答え2

この試み:

#!/bin/bash

coproc cat -n  # replace 'cat -n' with actual server program to be launched

# first some necessary file-descriptors fiddling
exec {srv_input}>&${COPROC[1]}-
exec {srv_output}<&${COPROC[0]}-

# background commands to relay normal stdin/stdout activity
cat <&0 >&${srv_input} &
cat <&${srv_output} >&1 &

# set signal handler up
term_received=false ; trap 'term_received=true' SIGTERM

# endless loop waiting for events
while true; do
    # wait for server to exit or sigterm received
    wait ${COPROC_PID}
    exit_status=$?
    # if sigterm received:
    if [ $exit_status -gt 128 ] && $term_received ; then
        # kill proxy command relaying stdin to server
        kill %2
        # send quit to server's stdin
        echo $'\n'quit >&${srv_input}
        # close server's stdin
        exec {srv_input}<&-
        # wait for actual server to exit
        wait ${COPROC_PID}
        exit $?
    # something else happened: kill proxy commands and exit with server's own exit status
    else
        kill %2
        kill %3
    fi
    exit $exit_status
done

このスクリプトがあなたの質問に答えたら、より完全な説明を追加します。

関連情報