ApacheのCOMMAND名をファイル名にしたい

が、できていません。やりたいこととしては以下です。

  1. /proc/pid/cmdlineを動的コンテンツ処理時のみそのコンテンツファイル名(fullpath)にする
  2. プロセス名を動的コンテンツ処理時のみそのコンテンツファイル名(basenam)にする
  3. Apacheそのものは弄らないでモジュールで実現

これでなにがうれしくなるかというと、

  • DSOであってもpsコマンドのCOMMAND項目から負荷の高いコンテンツが一目で分かって調査が楽
  • kill ファイル名ができる(これは運用してみると面倒な副作用があるかも)

ということです。通常は、psコマンドで得られるCOMMAND名やプロセス名はCGIでない場合はhttpdと表示されてしまいます。その場合、負荷の高いhttpdプロセスがあった場合は、ログや/proc以下から必死に対象のコンテンツを探し出さないといけません。これは結構面倒で運用コストもかかります。

そこで、psコマンドで簡単にDSOタイプの動的コンテンツのファイル名が得られたらうれしいよね、ということで、他にも複数やり方はあると思いますが、まずはこのアプローチでこの方法を実装してみようと思いました。これらを実現するモジュールを例えばmod_process_nameとします。

Apacheのプロセス名を変更

現状、2に関してはできています。2は、例えばアクセスチェックのタイミングで、以下のようなコードを書いてやります。

prctl(PR_SET_NAME, basename(r->filename));

これで基本的にはOKで、ps -eo commとかしてやればこれまではhttpdとしか表示されなかったプロセス名が、search.phpなんて表示されたりします。また、最悪の場合は、kill ファイル名等で簡単に負荷の高い子サーバプロセスを殺す事ができます。ただし、プロセス名の上限は16バイトと決まっているので注意が必要です。多分、16バイト超えている文字列は16バイトまでを表示すると思われます。

ApacheのCOMMAND名を変更

しかし、問題は簡単だと思っていたCOMMAND名(/proc/pid/cmdline)の変更がやっかいでした。基本的には、cmdlineを書き換える場合は、argvを書き換えてやれば良いです。例えば、以下です。

strncpy(argv[0], "dummy", 10);

こんな感じの実装を行えば、このコードの直前までは、psコマンドによるCOMMAND項目(cmdline)は例えば./a.outとなり、このコード移行はdummyというCOMMAND名になります。

これを、apacheに実装してやれば良いのですが、apacheのコードは以下のようになっています。まずは、server/main.cのmain()部分です。

442 int main(int argc, const char * const argv[])
443 {

~ (snip) ~

464 
465     process = init_process(&argc, &argv);
466     pglobal = process->pool;
467     pconf = process->pconf;
468     ap_server_argv0 = process->short_name;

const char * cont argv[]で宣言されちゃっているんですよね。これでは、argv自体は定数の扱いになってしまいます。また、モジュールからアクセスできるように、argvのポインタはinit_process()によって、以下のようにprocess_rec構造体に格納されます。これによって、モジュールからリクエスト処理時にrequest_rec構造体を介して参照することが可能になります。これもserver/main.c内です。

275 static process_rec *init_process(int *argc, const char * const * *argv)
276 {   
277     process_rec *process;
278     apr_pool_t *cntx;
279     apr_status_t stat;

~ (snip) ~

310     process = apr_palloc(cntx, sizeof(process_rec));
311     process->pool = cntx;
312 
313     apr_pool_create(&process->pconf, process->pool);
314     apr_pool_tag(process->pconf, "pconf");
315     process->argc = *argc;
316     process->argv = *argv;
317     process->short_name = apr_filepath_name_get((*argv)[0]);
318     return process;
319 }

ですので、モジュールからargvにアクセスするためには、以下のように呼び出します。例えば、適当なフックで以下の関数を呼び出します。

static int process_name_handler(request_rec *r)
{   

~ (snip) ~

const char *argv = r->server->process->argv;

これによって、argvを参照することはできます。しかし、r->server->process->argvはconst char * const * 型ですので一時的に書き換えることができません。また、COMMAND名を変えるためには、r->server->process->argvはポインタであって、このポインタを上書きするだけでは意味がなく、server/main.cにおけるargvポインタが指し示す値そのものをapr_pstrdup等によって書き換えてやる必要があります。

うーん、httpdにパッチを当ててconst charを回避するしか方法はないのでしょうか。もしくは、モジュールからcoolに別の方法でCOMMAND名を変える方法があるのでしょうか。

ここで少し詰まっています。