"posix_spawn"の出力を取得します。

"posix_spawn"の出力を取得します。

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

プロセスは以下を生成します。

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

出力保存:

...?

答え1

以下は、生成プロセスのファイル記述子を変更する最小の例です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);
}

それは何をしますか?

  • の3番目のパラメータは(指定された)型posix_spwanのポインタです。呼び出しプロセスから継承されたファイル記述子は、オブジェクトで指定されているように開かれ、閉じられたり、コピーされます。posix_spawn_file_actions_tNULLposix_spawnposix_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-log1
  • 次にposix_spawn_file_actions_adddup2fd 2(別名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

答え2

そうそうできます。 posix makefile 操作の正しいリストを定義することは確かに良い方法です。

例:

#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関数は、他のほとんどのUNIX関数とは異なり、errnoを設定せず、エラーコードを返します。だから私たちはperror()そのようなものを使うことはできませんが、それを使うべきですstrerror()

addopenとaddup2という2つのmakefile操作を使用します。 addopenは通常と似ていますopen()が、すでに開いている場合は自動的に閉じるファイル記述子を指定します(ここでは1、stdout)。 addup2には、dup2()1が2にコピーされる前にターゲットファイル記述子(ここでは2、stderr)が自動的に閉じるのと同じ効果があります。これらの操作は、で作成された子孫のみ、posix_spawnつまり指定されたコマンドが実行される前に実行されます。

同様に、fork()すぐに親項目に戻りますposix_spawn()posix_spawnp()したがって、waitid()またはを使用して明示的に終了をwaitpid()待つ必要があります。child_pid

関連情報