Получить вывод `posix_spawn`

9

Таким образом, я могу запустить процесс в Unix / Linux, используя POSIX, но есть ли способ сохранить / перенаправить как STDOUT, так и STDERR процесса в файл? spawn.hЗаголовок содержит замедление , posix_spawn_file_actions_adddup2который выглядит уместно, но я не уверен , совсем как его использовать.

Процесс порождения:

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

Выходное хранилище:

...?

nbubis
источник
1
Третий параметр posix_spwan- это указатель типа posix_spawn_file_actions_t(тот, который вы указали как NULL). posix_spawnоткроет, закроет или продублирует файловые дескрипторы, унаследованные от вызывающего процесса, как указано posix_spawn_file_actions_tобъектом. Эти posix_spawn_file_actions_{addclose,adddup2}функции используются для обозначения того, что происходит с каким дескриптором.
Муру
@muru - Как вы думаете, вы могли бы добавить рабочий пример? Я понял, что взаимодействие между функциями осуществляется с помощью «действия с файлом», но не ясно, как именно это сочетается, или где определяется местоположение fd.
nbubis

Ответы:

16

Вот минимальный пример изменения файловых дескрипторов порожденного процесса, сохраненный как 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- это указатель типа 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_adddup2FD 2(ака stderr) до FD 1.
  • Обратите внимание , что ничего не было открыто или обманут еще . Последние две функции просто изменили 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.

Мур
источник
Обратите внимание, что posix_spawn*не установить errno. Таким образом, вы не можете использовать perror(). Используйте что-то вроде fprintf(stderr, "...: %s\n", strerror(ret))этого. Также в основной функции отсутствует return 0оператор.
maxschlepzig
1

Да, ты можешь. Определить правильный список действий в файле posix spawn определенно стоит.

Пример:

#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().

Мы используем два действия spawn file: addopen и addup2. Addopen похож на обычный, open()но вы также указываете дескриптор файла, который автоматически закрывается, если он уже открыт (здесь 1, т.е. stdout). Addup2 имеет аналогичные эффекты dup2(), т. Е. Дескриптор целевого файла (здесь 2, то есть stderr) атомарно закрывается до того, как 1 дублируется до 2. Эти действия выполняются только в дочернем объекте, созданном , т. Е. Непосредственно posix_spawnперед выполнением указанной команды.

Как fork(), posix_spawn()и posix_spawnp()сразу же вернуться к родителю. Таким образом, мы должны использовать waitid()или waitpid()явно ждать child_pidзавершения.

maxschlepzig
источник