Obter saída de 'posix_spawn'

8

Assim, posso executar um processo no Unix / Linux usando o POSIX, mas existe alguma maneira de armazenar / redirecionar o STDOUT e o STDERR do processo para um arquivo? O cabeçalho spawn.h contém uma desaceleração de posix_spawn_file_actions_adddup2 que parece relevante, mas não tenho certeza de como usá-lo.

O processo desova:

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

O armazenamento de saída:

...?

    
por nbubis 02.01.2016 / 22:24

2 respostas

13

Veja um exemplo mínimo de modificação de descritores de arquivos de um processo gerado, salvo como 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);
}

O que isso faz?

  • O terceiro parâmetro de posix_spwan é um ponteiro do tipo posix_spawn_file_actions_t (um que você forneceu como NULL ). posix_spawn abrirá, fechará ou duplicará os descritores de arquivos herdados do processo de chamada, conforme especificado pelo objeto posix_spawn_file_actions_t .
  • Portanto, começamos com um objeto posix_spawn_file_actions_t ( chiild_fd_actions ) e inicializamos com posix_spawn_file_actions_init() .
  • Agora, as funções posix_spawn_file_actions_{addopen,addclose,addup2} podem ser usadas para abrir, fechar ou duplicar descritores de arquivos (depois das funções open(3) , close(3) e dup2(3) ) respectivamente.
  • Então, posix_spawn_file_actions_addopen um arquivo em /tmp/foo-log para o descritor de arquivo 1 (também conhecido como stdout).
  • Então, posix_spawn_file_actions_adddup2 fd 2 (também conhecido como stderr ) para fd 1.
  • Observe que nada foi aberto ou enganado ainda . As duas últimas funções simplesmente alteraram o objeto child_fd_actions para observar que essas ações devem ser tomadas.
  • E, finalmente, usamos posix_spawn com o objeto child_fd_actions .

Teste:

$ 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’

Como você pode ver, stdout e stderr do processo gerado foram para /tmp/foo-log .

    
por 02.01.2016 / 23:28
1

Sim, você pode. Definindo a lista certa de ações de arquivos de posix spawn definitivamente é o caminho a percorrer.

Exemplo:

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

Compile e teste:

$ 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

Observe que as funções posix_spawn não definem errno; em vez disso, diferentemente da maioria das outras funções do UNIX, elas retornam um código de erro. Assim, não podemos usar perror() , mas temos que usar algo como strerror() .

Nós usamos duas ações de arquivo spawn: addopen e addup2. O addopen é semelhante a um% normalopen(), mas você também especifica um descritor de arquivo que é automaticamente fechado se já estiver aberto (aqui 1, ou seja, stdout). O addup2 tem efeitos similares a dup2() , ou seja, o descritor do arquivo de destino (aqui 2, por exemplo, stderr) é atomicamente fechado antes de 1 ser duplicado para 2. Essas ações são executadas apenas no filho criado por posix_spawn , ou seja, execs o comando especificado.

Como fork() , posix_spawn() e posix_spawnp() retornam imediatamente ao pai. Assim, temos que usar waitid() ou waitpid() para esperar explicitamente na terminação de child_pid .

    
por 03.11.2018 / 13:17

Tags