Ottieni l'output di `posix_spawn`


9

Quindi posso eseguire un processo in Unix / Linux usando POSIX, ma c'è un modo per archiviare / reindirizzare sia lo STDOUT che lo STDERR del processo su un file? L' spawn.hintestazione contiene una decelerazione posix_spawn_file_actions_adddup2che sembra rilevante, ma non sono sicuro di come usarla.

Il processo si genera:

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

La memoria di output:

...?


1
Il terzo parametro di posix_spwanè un puntatore di tipo posix_spawn_file_actions_t(uno che hai dato come NULL). posix_spawnaprirà, chiuderà o duplicerà i descrittori di file ereditati dal processo di chiamata come specificato posix_spawn_file_actions_tdall'oggetto. Le posix_spawn_file_actions_{addclose,adddup2}funzioni sono usate per indicare cosa succede a quale fd.
Muru,

@muru - Pensi di poter aggiungere un esempio funzionante? Ho capito che l'interazione tra le funzioni è fatta da una "azione file", ma non è chiaro come si combini esattamente o dove sia definita la posizione fd.
nbubis,

Risposte:


16

Ecco un esempio minimo di modifica dei descrittori di file di un processo generato, salvato come 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);
}

Che cosa fa?

  • Il terzo parametro di posix_spwanè un puntatore di tipo posix_spawn_file_actions_t(uno che hai dato come NULL). posix_spawnaprirà, chiuderà o duplicerà i descrittori di file ereditati dal processo di chiamata come specificato posix_spawn_file_actions_tdall'oggetto.
  • Quindi iniziamo con un posix_spawn_file_actions_toggetto ( chiild_fd_actions) e inizializziamo con posix_spawn_file_actions_init().
  • Ora, le posix_spawn_file_actions_{addopen,addclose,addup2}funzioni possono essere utilizzate per aprire, chiudere o duplicare i descrittori di file (dopo il open(3), close(3)e le dup2(3)funzioni) rispettivamente.
  • Quindi abbiamo posix_spawn_file_actions_addopenun file al /tmp/foo-logdescrittore di file 1(aka stdout).
  • Quindi abbiamo posix_spawn_file_actions_adddup2fd 2(aka stderr) in fd 1.
  • Nota che nulla è stato aperto o ingannato ancora . Le ultime due funzioni hanno semplicemente cambiato l' child_fd_actionsoggetto per notare che queste azioni devono essere intraprese.
  • E infine usiamo posix_spawncon l' child_fd_actionsoggetto.

Provandolo:

$ 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

Come puoi vedere, sia stdout che stderr del processo generato sono andati a /tmp/foo-log.


Si noti che posix_spawn*non impostare errno. Pertanto, non è possibile utilizzare perror(). Usa fprintf(stderr, "...: %s\n", strerror(ret))invece qualcosa di simile . Inoltre, nella funzione principale manca return 0un'istruzione.
maxschlepzig,

1

Si, puoi. Definire la giusta lista di azioni di file spawn posix è sicuramente la strada da percorrere.

Esempio:

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

Compilare e testare:

$ 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

Si noti che le posix_spawnfunzioni non impostano errno, invece, a differenza della maggior parte delle altre funzioni UNIX, restituiscono un codice di errore. Pertanto, non possiamo usare perror()ma dobbiamo usare qualcosa di simile strerror().

Utilizziamo due azioni del file di spawn: addopen e addup2. L'adopen è simile a un normale open()ma si specifica anche un descrittore di file che viene automaticamente chiuso se già aperto (qui 1, cioè stdout). L'addup2 ha effetti simili a dup2(), ovvero il descrittore del file di destinazione (qui 2, ovvero stderr) viene chiuso atomicamente prima che 1 sia duplicato su 2. Tali azioni vengono eseguite solo nel figlio creato da posix_spawn, ovvero proprio prima che esegua il comando specificato.

Mi piace fork(), posix_spawn()e posix_spawnp()torna immediatamente al genitore. Pertanto, dobbiamo utilizzare waitid()o waitpid()attendere esplicitamente child_pidla risoluzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.