web-dev-qa-db-ja.com

`posix_spawn`の出力を取得します

したがって、POSIXを使用してUnix/Linuxでプロセスを実行できますが、プロセスのSTDOUTとSTDERRの両方をファイルに保存/リダイレクトできる方法はありますか? _spawn.h_ヘッダーには、関連があるように見える_posix_spawn_file_actions_adddup2_の減速が含まれていますが、その使用方法はよくわかりません。

プロセスが生成します:

posix_spawn(&processID, (char *)"myprocess", NULL, NULL, args, environ);

出力ストレージ:

_...?_

9
nbubis

_foo.c_として保存された、生成されたプロセスのファイル記述子を変更する最小限の例を次に示します。

_#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <spawn.h>

int main(int argc, char* argv[], char *env[])
{
    int ret;
    pid_t child_pid;
    posix_spawn_file_actions_t child_fd_actions;
    if (ret = posix_spawn_file_actions_init (&child_fd_actions))
        perror ("posix_spawn_file_actions_init"), exit(ret);
    if (ret = posix_spawn_file_actions_addopen (&child_fd_actions, 1, "/tmp/foo-log", 
            O_WRONLY | O_CREAT | O_TRUNC, 0644))
        perror ("posix_spawn_file_actions_addopen"), exit(ret);
    if (ret = posix_spawn_file_actions_adddup2 (&child_fd_actions, 1, 2))
        perror ("posix_spawn_file_actions_adddup2"), exit(ret);

    if (ret = posix_spawnp (&child_pid, "date", &child_fd_actions, NULL, argv, env))
        perror ("posix_spawn"), exit(ret);
}
_

それは何をするためのものか?

  • _posix_spwan_の3番目のパラメーターは、タイプ_posix_spawn_file_actions_t_(NULLとして指定したもの)のポインターです。 _posix_spawn_オブジェクトによって指定されたように、呼び出しプロセスから継承されたファイル記述子を_posix_spawn_file_actions_t_で開く、閉じる、または複製します。
  • したがって、_posix_spawn_file_actions_t_オブジェクト(_chiild_fd_actions_)から始め、posix_spawn_file_actions_init()で初期化します。
  • 現在、_posix_spawn_file_actions_{addopen,addclose,addup2}_関数を使用して、ファイル記述子を開く、閉じる、または複製することができます(open(3)close(3)およびdup2(3)関数の後)。
  • したがって、_posix_spawn_file_actions_addopen_のファイルを_/tmp/foo-log_にあるファイル記述子_1_(別名stdout)に変換します。
  • 次に_posix_spawn_file_actions_adddup2_ fd _2_(aka stderr)をfd 1に変換します。
  • まだが開かれていないか、または複製されていないことに注意してください。最後の2つの関数は単に_child_fd_actions_オブジェクトを変更して、これらのアクションが実行されることを示しています。
  • 最後に、_posix_spawn_オブジェクトと_child_fd_actions_を使用します。

それをテストする:

_$ make foo
cc     foo.c   -o foo
$ ./foo
$ cat /tmp/foo-log 
Sun Jan  3 03:48:17 IST 2016
$ ./foo +'%F %R'  
$ cat /tmp/foo-log
2016-01-03 03:48
$  ./foo -d 'foo'  
$ cat /tmp/foo-log
./foo: invalid date ‘foo’
_

ご覧のように、生成されたプロセスのstdoutとstderrの両方が_/tmp/foo-log_に移動しました。

16
muru

はい、できます。 posix spawn fileアクションの正しいリストを定義することは、間違いなく進むべき道です。

例:

#include <errno.h>
#include <fcntl.h>
#include <spawn.h>
#include <stdio.h>
#include <string.h>    
#define CHECK_ERROR(R, MSG) do { if (R) { fprintf(stderr, "%s: %s\n",
        (MSG), strerror(R)); return 1; } } while (0)    
extern char **environ;   
int main(int argc, char **argv)
{
    if (argc < 3) {
        fprintf(stderr, "Call: %s OUTFILE COMMAND [ARG]...\n", argv[0]);
        return 2;
    }
    const char *out_filename = argv[1];
    char **child_argv = argv+2;
    posix_spawn_file_actions_t as;
    int r = posix_spawn_file_actions_init(&as);
    CHECK_ERROR(r, "actions init");
    r = posix_spawn_file_actions_addopen(&as, 1, out_filename,
            O_CREAT | O_TRUNC | O_WRONLY, 0644);
    CHECK_ERROR(r, "addopen");
    r = posix_spawn_file_actions_adddup2(&as, 1, 2);
    CHECK_ERROR(r, "adddup2");
    pid_t child_pid;
    r = posix_spawnp(&child_pid, child_argv[0], &as, NULL,
            child_argv, environ);
    CHECK_ERROR(r, "spawnp");
    r = posix_spawn_file_actions_destroy(&as);
    CHECK_ERROR(r, "actions destroy");
    return 0;
}

コンパイルとテスト:

$ cc -Wall -g -o spawnp spawnp.c
$ ./spawnp log date -I
$ cat log
2018-11-03
$ ./a.out log dat 
spawnp: No such file or directory

posix_spawn関数はerrnoを設定しないことに注意してください。代わりに、他のほとんどのUNIX関数とは異なり、エラーコードを返します。したがって、perror()は使用できませんが、strerror()のようなものを使用する必要があります。

2つのspawn fileアクションを使用します:addopenとaddup2。 addopenは通常のopen()に似ていますが、既に開いている場合(ここでは1、つまりstdout)に自動的に閉じられるファイル記述子も指定します。 addup2はdup2()と同様の効果があります。つまり、ターゲットファイル記述子(ここでは2、つまりstderr)は、1が2に複製される前にアトミックに閉じられます。これらのアクションは、posix_spawnによって作成された子でのみ実行されます。つまり、右指定されたコマンドを実行する前。

fork()と同様に、posix_spawn()およびposix_spawnp()はすぐに親に戻ります。したがって、child_pidの終了を明示的に待機するには、waitid()またはwaitpid()を使用する必要があります。

1
maxschlepzig