Uzyskaj wynik działania `posix_spawn`


9

Mogę więc uruchomić proces w systemie Unix / Linux przy użyciu POSIX, ale czy jest jakiś sposób, aby zapisać / przekierować STDOUT i STDERR procesu do pliku? spawn.hNagłówek zawiera spowolnienie posix_spawn_file_actions_adddup2który wygląda istotne, ale nie jestem pewien, dość, jak go używać.

Proces spawnowania:

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

Pamięć wyjściowa:

...?


1
Trzecim parametrem posix_spwanjest wskaźnik typu posix_spawn_file_actions_t(ten, który podałeś jako NULL). posix_spawnotworzy, zamknie lub powieli deskryptory plików odziedziczone po procesie wywoływania określonym przez posix_spawn_file_actions_tobiekt. Te posix_spawn_file_actions_{addclose,adddup2}funkcje są używane, aby wskazać, co się dzieje, z którym fd.
muru

@muru - Czy uważasz, że możesz dodać działający przykład? Zrozumiałem, że interakcja między funkcjami jest wykonywana przez „akcję pliku”, ale nie jest jasne, jak dokładnie to pasuje do siebie, ani gdzie zdefiniowana jest lokalizacja fd.
nbubis

Odpowiedzi:


16

Oto minimalny przykład modyfikacji deskryptorów plików spawnowanego procesu, zapisany jako 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);
}

Co to robi?

  • Trzeci parametr posix_spwanto wskaźnik typu posix_spawn_file_actions_t(ten, który podałeś jako NULL). posix_spawnotworzy, zamknie lub powieli deskryptory plików odziedziczone po procesie wywoływania określonym przez posix_spawn_file_actions_tobiekt.
  • Zaczynamy od posix_spawn_file_actions_tobiektu ( chiild_fd_actions) i inicjalizujemy go posix_spawn_file_actions_init().
  • Teraz, gdy posix_spawn_file_actions_{addopen,addclose,addup2}funkcje mogą być wykorzystywane do otwierania, zamykania lub powielonych deskryptorów (po open(3), close(3)i dup2(3)funkcje), odpowiednio.
  • Więc posix_spawn_file_actions_addopenplik na /tmp/foo-logdo pliku deskryptora 1(aka stdout).
  • Następnie my posix_spawn_file_actions_adddup2fd 2(aka stderr) do fd 1.
  • Należy pamiętać, że nic nie zostało otwarte lub nabrać jeszcze . Dwie ostatnie funkcje po prostu zmieniły child_fd_actionsobiekt, aby zauważyć, że należy podjąć te działania.
  • I wreszcie używamy posix_spawnz child_fd_actionsprzedmiotem.

Testowanie:

$ 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

Jak widać, zarówno stdout, jak i stderr odrodzonego procesu poszły do /tmp/foo-log.


Pamiętaj, że posix_spawn*nie ustawiaj errno. Dlatego nie możesz używać perror(). fprintf(stderr, "...: %s\n", strerror(ret))Zamiast tego użyj czegoś takiego . Ponadto w głównej funkcji brakuje return 0instrukcji.
maxschlepzig

1

Tak, możesz. Zdecydowanie słuszne jest zdefiniowanie właściwej listy akcji odradzania plików posix.

Przykład:

#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;
}

Skompiluj i przetestuj:

$ 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

Zauważ, że posix_spawnfunkcje nie ustawiają errno, zamiast tego, w przeciwieństwie do większości innych funkcji UNIX, zwracają kod błędu. Dlatego nie możemy użyć, perror()ale musimy użyć czegoś takiego strerror().

Używamy dwóch akcji plików spawn: addopen i addup2. Addopen jest podobny do normalnego, open()ale określasz także deskryptor pliku, który jest automatycznie zamykany, jeśli jest już otwarty (tutaj 1, tzn. Standardowe wyjście). Addup2 ma podobne efekty dup2(), tj. Deskryptor pliku docelowego (tutaj 2, tj. Stderr) jest atomowo zamykany, zanim 1 zostanie zduplikowany do 2. Te akcje są wykonywane tylko w podrzędnym utworzonym przez posix_spawn, tj. Tuż przed wykonaniem określonego polecenia.

Jak fork(), posix_spawn()i posix_spawnp()natychmiast wrócić do rodziców. W związku z tym musimy wykorzystać waitid()lub waitpid()wyraźnie poczekać na child_pidzakończenie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.