Obtener salida de `posix_spawn`


9

Entonces, puedo ejecutar un proceso en Unix / Linux usando POSIX, pero ¿hay alguna forma de almacenar / redirigir tanto el STDOUT como el STDERR del proceso a un archivo? El spawn.hencabezado contiene una desaceleración posix_spawn_file_actions_adddup2que parece relevante, pero no estoy seguro de cómo usarlo.

El proceso genera:

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

El almacenamiento de salida:

...?


1
El tercer parámetro de posix_spwanes un puntero de tipo posix_spawn_file_actions_t(uno que ha dado como NULL). posix_spawnabrirá, cerrará o duplicará los descriptores de archivos heredados del proceso de llamada según lo especificado por el posix_spawn_file_actions_tobjeto. Las posix_spawn_file_actions_{addclose,adddup2}funciones se utilizan para indicar qué sucede con qué fd.
Muru

@muru - ¿Crees que podrías agregar un ejemplo de trabajo? Comprendí que la interacción entre las funciones se realiza mediante una "acción de archivo", pero no está claro cómo encaja exactamente esto o dónde se define la ubicación de fd.
nbubis

Respuestas:


16

Aquí hay un ejemplo mínimo de modificación de descriptores de archivo de un proceso generado, guardado 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);
}

¿Qué hace?

  • El tercer parámetro de posix_spwanes un puntero de tipo posix_spawn_file_actions_t(uno que ha dado como NULL). posix_spawnabrirá, cerrará o duplicará los descriptores de archivos heredados del proceso de llamada según lo especificado por el posix_spawn_file_actions_tobjeto.
  • Entonces comenzamos con un posix_spawn_file_actions_tobjeto ( chiild_fd_actions), y lo inicializamos con posix_spawn_file_actions_init().
  • Ahora, las posix_spawn_file_actions_{addopen,addclose,addup2}funciones se pueden usar para abrir, cerrar o duplicar descriptores de archivo (después de open(3), close(3)y dup2(3)funciones) respectivamente.
  • Entonces tenemos posix_spawn_file_actions_addopenun archivo en /tmp/foo-logel descriptor de archivo 1(también conocido como stdout).
  • Luego pasamos posix_spawn_file_actions_adddup2fd 2(aka stderr) a fd 1.
  • Tenga en cuenta que nada se ha abierto o engañado todavía . Las dos últimas funciones simplemente cambiaron el child_fd_actionsobjeto para tener en cuenta que estas acciones deben tomarse.
  • Y finalmente lo usamos posix_spawncon el child_fd_actionsobjeto.

Probándolo:

$ 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 puede ver, tanto stdout como stderr del proceso generado fueron a /tmp/foo-log.


Tenga en cuenta que posix_spawn*no configure errno. Por lo tanto, no puedes usar perror(). Use algo como en su fprintf(stderr, "...: %s\n", strerror(ret))lugar. Además, a la función principal le falta una return 0declaración.
maxschlepzig

1

Sí tu puedes. Definir la lista correcta de acciones de archivo de generación posix definitivamente es el camino a seguir.

Ejemplo:

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

Compilar y probar:

$ 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

Tenga en cuenta que las posix_spawnfunciones no establecen errno, en cambio, a diferencia de la mayoría de las otras funciones de UNIX, devuelven un código de error. Por lo tanto, no podemos usar, perror()pero tenemos que usar algo como strerror().

Utilizamos dos acciones de generación de archivos: addopen y addup2. El addopen es similar a un normal open()pero también especifica un descriptor de archivo que se cierra automáticamente si ya está abierto (aquí 1, es decir, stdout). El addup2 tiene efectos similares a dup2(), es decir, el descriptor del archivo de destino (aquí 2, es decir, stderr) se cierra atómicamente antes de que 1 se duplique a 2. Esas acciones solo se ejecutan en el elemento secundario creado por posix_spawn, es decir, justo antes de ejecutar el comando especificado.

Me gusta fork(), posix_spawn()y posix_spawnp()volver inmediatamente a los padres. Por lo tanto, tenemos que usar waitid()o waitpid()esperar explícitamente child_pidla terminación.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.