Dapatkan hasil dari `posix_spawn`

9

Jadi saya bisa menjalankan proses di Unix / Linux menggunakan POSIX, tetapi apakah ada cara saya bisa menyimpan / mengarahkan STDOUT dan STDERR dari proses ke file? The spawn.hheader berisi perlambatan posix_spawn_file_actions_adddup2yang terlihat relevan, tapi aku tidak yakin cukup bagaimana menggunakannya.

Proses menelurkan:

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

Penyimpanan output:

...?

nbubis
sumber
1
Parameter ketiga posix_spwanadalah pointer tipe posix_spawn_file_actions_t(yang telah Anda berikan sebagai NULL). posix_spawnakan membuka, menutup, atau menggandakan deskriptor file yang diwarisi dari proses pemanggilan sebagaimana ditentukan oleh posix_spawn_file_actions_tobjek. The posix_spawn_file_actions_{addclose,adddup2}fungsi yang digunakan untuk menunjukkan apa yang terjadi pada yang fd.
muru
@muru - Apakah Anda pikir Anda bisa menambahkan contoh yang berfungsi? Saya mengerti interaksi antara fungsi dilakukan oleh "tindakan file", tetapi tidak jelas bagaimana tepatnya ini cocok bersama, atau di mana lokasi fd didefinisikan.
nbubis

Jawaban:

16

Berikut adalah contoh minimal memodifikasi deskriptor file dari proses spawned, disimpan sebagai 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);
}

Apa fungsinya?

  • Parameter ketiga posix_spwanadalah pointer tipe posix_spawn_file_actions_t(yang telah Anda berikan sebagai NULL). posix_spawnakan membuka, menutup, atau menggandakan deskriptor file yang diwarisi dari proses pemanggilan sebagaimana ditentukan oleh posix_spawn_file_actions_tobjek.
  • Jadi kita mulai dengan posix_spawn_file_actions_tobjek ( chiild_fd_actions), dan menginisialisasi dengan posix_spawn_file_actions_init().
  • Sekarang, posix_spawn_file_actions_{addopen,addclose,addup2}fungsi dapat digunakan untuk membuka, menutup, atau menggandakan deskriptor file (setelah open(3), close(3)dan dup2(3)fungsi) masing-masing.
  • Jadi kita posix_spawn_file_actions_addopenfile di /tmp/foo-logke file descriptor 1(alias stdout).
  • Lalu kita posix_spawn_file_actions_adddup2fd 2(alias stderr) ke fd 1.
  • Perhatikan bahwa tidak ada yang telah dibuka atau ditipu belum . Dua fungsi terakhir hanya mengubah child_fd_actionsobjek untuk mencatat bahwa tindakan ini harus diambil.
  • Dan akhirnya kita gunakan posix_spawndengan child_fd_actionsobjek.

Mengujinya:

$ 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

Seperti yang Anda lihat, baik stdout dan stderr dari proses melahirkan pergi ke /tmp/foo-log.

muru
sumber
Perhatikan bahwa posix_spawn*jangan atur errno. Dengan demikian, Anda tidak dapat menggunakannya perror(). Gunakan sesuatu seperti fprintf(stderr, "...: %s\n", strerror(ret))sebagai gantinya. Juga, fungsi utama tidak memiliki return 0pernyataan.
maxschlepzig
1

Ya kamu bisa. Menentukan daftar yang tepat dari tindakan file spawn posix pasti adalah cara untuk pergi.

Contoh:

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

Kompilasi dan uji:

$ 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

Perhatikan bahwa posix_spawnfungsi - fungsi tidak mengatur errno, sebaliknya, tidak seperti kebanyakan fungsi UNIX lainnya, mereka mengembalikan kode kesalahan. Jadi, kita tidak bisa menggunakan perror()tetapi harus menggunakan sesuatu seperti strerror().

Kami menggunakan dua tindakan file spawn: addopen dan addup2. Addopen mirip dengan normal open()tetapi Anda juga menentukan deskriptor file yang secara otomatis ditutup jika sudah terbuka (di sini 1, yaitu stdout). Addup2 memiliki efek yang mirip dengan dup2(), yaitu deskriptor file target (di sini 2, yaitu stderr) ditutup secara atom sebelum 1 diduplikasi ke 2. Tindakan-tindakan tersebut hanya dijalankan pada anak yang dibuat oleh posix_spawn, yaitu tepat sebelum ia menjalankan perintah yang ditentukan.

Suka fork(), posix_spawn()dan posix_spawnp()segera kembali ke orang tua. Dengan demikian, kita harus menggunakan waitid()atau waitpid()secara eksplisit menunggu child_pidpenghentian.

maxschlepzig
sumber