実行可能ファイルへのシンボリックリンクが複数ある場合に、ラッパースクリプトを使用して呼び出しをログに記録する方法


8

短い話:システムの動作を追跡するために実行可能ファイルが呼び出される方法を追跡したいと思います。私が実行可能ファイルを持っているとしましょう:

/usr/bin/do_stuff

そして実際には、symlinkを介してさまざまな名前で呼び出されます。

/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff

等々。明らかに、do_stuff受け取った最初の引数を使用して、実際に実行されるアクションを決定します。残りの引数は、それに照らして処理されます。

これまでの呼び出し/usr/bin/do_stuff(および引数の完全なリスト)を記録したいと思います。シンボリックリンクがない場合は、スクリプトに移動do_stuffdo_stuff_realて記述します

#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"

ただし、呼び出された名前が調べられることがわかっているので、これは機能しません。同じことを実現するスクリプトをどのように記述しますdo_stuffか?

記録のために、これらの行での回答を避けるために:

  • Cで(execveを使用して)実行できることはわかっていますが、この場合はシェルスクリプトを使用するだけではるかに簡単です。
  • 単純にdo_stuffロギングプログラムに置き換えることはできません。

回答:


6

あなたは、多くの場合などのユーティリティの場合にはこれを見busyboxて、呼び出しに応じて、異なる振る舞いを/こと、一つの実行可能で一般的なUNIXユーティリティのほとんどを提供することができ、プログラムを busybox、機能の全体の多くを行うことができacpidzcat

そして、それは通常、argv[0]へのパラメーターを見ることによって、何をすべきかを決定しますmain()。そして、それは単純な比較であってはなりません。のargv[0]ようなものかもしれないしsleep、そうかもしれない/bin/sleepし、同じことをすることを決定するべきだからです。言い換えれば、この道は物事をより複雑にするでしょう。

したがって、ワーカープログラムによって正しく行われた場合、ロギングラッパーは次のようなものから実行でき/bin/realstuff/make_tea、ワーカーがargv[0]ベース名のみを参照する場合は、適切な関数が実行されます。

#!/bin/sh -
myexec=/tmp/MYEXEC$$
mybase=`basename -- "$0"`

echo "$0 $@" >> logfile

mkdir "$myexec" || exit
ln -fs /usr/bin/real/do_stuff "$myexec/$mybase" || exit
"$myexec/$mybase" "$@"
ret=$?
rm -rf "$myexec"
exit "$ret"

上記の例では、argv[0]のようなものを読んでください/tmp/MYEXEC4321/make_tea(4321はのためのPIDをした場合は/bin/shベース名のトリガすべきことRAN)make_teaの挙動を

あなたがしたい場合argv[0]、それはラッパーなしでどうなるかの正確なコピーであることを、あなたは厳しい問題を抱えています。で始まる絶対ファイルパスのため/。あなたは新しいものを作ることはできません/bin/sleep (あなたがchrootそこに行きたくないと私は思いません)。お気づきのように、を使ってそれを行うこともできますexec()が、それはシェルラッパーではありません。

エイリアスを使用してロガーをヒットし、スクリプトラッパーの代わりにベースプログラムを開始することを検討しましたか?限られた一連のイベントしかキャッチしませんが、気になるイベントはおそらくそれらだけです。


basenameをsedに置き換える必要がありましたが、それ以外はうまく機能します。
Neil Townsend

1
@ NeilTownsend、POSIX では、basenameの代わりにsh使用できますmybase=${0##*/}
ステファンChazelas

@StéphaneChazelasのbasenameような呼び出しbasename -- foo.barは私には馴染みがなく、Linuxシステムでテストした結果foo.bar、スクリプトが壊れる結果が生成されました。それは一般的な方法ですか?
2016年

basename -- foo.bar戻りfoo.bar、期待どおりにbasename -- --foo--/bar戻りますbarbasename "$foo"$foo始まらないことが保証できる場合にのみ機能します-。任意の引数でコマンドを呼び出す一般的な構文はcmd -x -y -- "$argument"です。cmd "$argument"あなたが意味しない限り、間違っていますcmd "$option_or_arg"。現在、一部のコマンド(のいくつかの歴史的な実装を含むbasename)はサポートし--ていないため、移植性と信頼性のどちらかを選択する必要がある場合があります。
ステファンChazelas

6

あなたが使用することができますexec -a(に見られるようなbashksh93zshmkshyashではなくPOSIXまだ)を指定するために使用されるargv[0]コマンドには、実行されています:

#! /bin/bash -
printf '%s\n' "$0 $*" >> /some/log
exec -a "$0" /usr/bin/do_stuff_real "$@"

そのことに注意$0されていないargv[0]コマンドが受け取ることを。これは、渡されたexecve()(および引数としてに渡された)スクリプトのパスですが、bash目的にはこれで十分です。

例として、次のようmake_teaに呼び出されたとします。

execv("/usr/bin/make_tea", ["make_tea", "--sugar=2"])

シェルは通常、コマンドを名前で呼び出す(実行可能ファイルをで検索する$PATH)ときに行うので、ラッパーは次のことを行います。

execv("/usr/bin/do_stuff_real", ["/usr/bin/make_tea", "--sugar=2"])

それは違います:

execv("/usr/bin/do_stuff_real", ["make_tea", "--sugar=2"])

それはdo_stuff_realお茶を作ることを意図していることを知っているのでそれで十分です。

これが問題になるのは、do_stuffが次のように呼び出された場合です。

execv("/usr/bin/do_stuff", ["/usr/bin/make_tea", "--sugar=2"])

これは次のように翻訳されます。

execv("/usr/bin/do_stuff_real", ["/usr/bin/do_stuff", "--sugar=2"])

これは通常の操作では発生しませんが、ラッパーがそのようなことを行うことに注意してください。

ほとんどのシステムでは、argv[0]スクリプトに渡されたとして、インタプリタは(ここではいったん失われる/bin/bash)が実行される(ほとんどのシステム上のインタプリタのは、彼女バングライン上で指定したパスであるので、シェルスクリプトはそれについてできることは何がありません)。argv[0]

渡す場合はargv[0]、実行可能ファイルをコンパイルする必要があります。何かのようなもの:

#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
   /* add logging */
   execve("/usr/bin/do_stuff_real", argv, envp);
   perror("execve");
   return 127;
}

+1:これは正しい答えです。ただし、私が取り組んでいるシステムのシェルでは、execに-aオプションが提供されていません...
Neil Townsend

@NeilTownsend可能であれば、perlまたはそれと同じようなことができpythonます。の古いバージョンはをzshサポートしていませんでしたがexec -aARGV0=the-argv-0 cmd args代わりにいつでも使用できます。
ステファンChazelas

これはbusyboxベースのマシンであるため、シェルはashのようであり、-aフラグがないようです。または、少なくとも、このバージョンでは。ファームウェアの作業を行っており、予想外のことを実行するのに十分なほど明確に把握していないため、起動方法を理解するためだけに、ファームウェアに追加しすぎないようにしています。ARGV0はzshだけのものだと思いますか?
Neil Townsend 2016年

@NeilTownsend、はい、それはzsh専用のものです。持っていたとしてもzsh(今は持っていないことが明確になっていますが)、古すぎてもまだ使用できるというARGV0ことです。
ステファンChazelas

十分に公正-「見事であるが、実際のあいまいな状況では実際に機能しなかった」というあなたの答えを確認できた場合、私はそうします
Neil Townsend
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.