Отримайте вихід `posix_spawn`


9

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

Процес нересту:

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

Вихідне сховище:

...?


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(aka 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*не встановлюйте помилку. Таким чином, ви не можете використовувати perror(). Використовуйте fprintf(stderr, "...: %s\n", strerror(ret))замість цього щось подібне . Крім того, у головній функції відсутній return 0вислів.
maxschlepzig

1

Так, ти можеш. Визначення правильного списку дій нерестового файлу posix, безумовно, це шлях.

Приклад:

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

Ми використовуємо дві дії нерестового файлу: addopen та addup2. Додаток схожий на звичайний, open()але ви також вказали дескриптор файлу, який автоматично закриється, якщо він уже відкритий (тут 1, тобто stdout). Аддуп2 має подібні ефекти dup2(), тобто дескриптор цільового файлу (тут 2, тобто stderr) атомно закритий, перш ніж 1 дублюється на 2. Ці дії виконуються лише у створеному дочірнім пристроєм posix_spawn, тобто безпосередньо перед виконанням зазначеної команди.

Мовляв fork(), posix_spawn()і posix_spawnp()негайно повертайтеся до батьків. Таким чином, ми повинні використовувати waitid()або waitpid()явно чекати child_pidприпинення дії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.