"Posix_spawn" çıktısını alın


9

Bu yüzden POSIX kullanarak Unix / Linux'ta bir işlem çalıştırabilirim, ancak sürecin hem STDOUT hem de STDERR'ını bir dosyaya depolamanın / yeniden yönlendirebilmemin bir yolu var mı? spawn.hBaşlık bir yavaşlama içeriyor posix_spawn_file_actions_adddup2alakalı görünüyor ki, ama emin oldukça nasıl kullanılacağını değilim.

Süreç ortaya çıkar:

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

Çıkış depolama:

...?


1
Üncü parametresi posix_spwanbir tür göstericidir posix_spawn_file_actions_t(sizin belirttiğiniz NULL). nesne posix_spawntarafından belirtilen çağrı sürecinden miras alınan dosya tanımlayıcılarını açar, kapatır veya çoğaltır posix_spawn_file_actions_t. posix_spawn_file_actions_{addclose,adddup2}İşlevler hangi fd ne olacağını belirtmek için kullanılır.
muru

@muru - Çalışan bir örnek ekleyebileceğinizi düşünüyor musunuz? İşlevler arasındaki etkileşimin bir "dosya eylemi" tarafından yapıldığını anladım, ancak bunun tam olarak nasıl bir araya geldiğini veya fd konumunun nerede tanımlandığı açık değil.
nbubis

Yanıtlar:


16

Aşağıda, kaydedilen bir işlemin dosya tanımlayıcılarını değiştirmeye yönelik minimal bir örnek verilmiştir 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);
}

Bu ne işe yarıyor?

  • Üncü parametresi posix_spwantür belirteci posix_spawn_file_actions_t(belirttiğiniz gibi NULL). nesne posix_spawntarafından belirtilen çağrı sürecinden miras alınan dosya tanımlayıcılarını açar, kapatır veya çoğaltır posix_spawn_file_actions_t.
  • Böylece bir posix_spawn_file_actions_tnesne ( chiild_fd_actions) ile başlayıp onu ile başlatırız posix_spawn_file_actions_init().
  • Şimdi, posix_spawn_file_actions_{addopen,addclose,addup2}fonksiyonları (sonra açık kapatma veya yinelenen dosya tanımlayıcıları için de kullanılabilir open(3), close(3)ve dup2(3)sırasıyla fonksiyonlar).
  • Bu yüzden dosya tanımlayıcıya posix_spawn_file_actions_addopenbir dosya (diğer adıyla stdout)./tmp/foo-log1
  • Sonra biz posix_spawn_file_actions_adddup2fd 2(aka stderr) fd 1'e.
  • Henüz hiçbir şeyin açılmadığını veya kopyalanmadığını unutmayın . Son iki işlev child_fd_actions, bu eylemlerin gerçekleştirileceğini belirtmek için nesneyi basitçe değiştirdi .
  • Ve son posix_spawnolarak child_fd_actionsnesneyle birlikte kullanıyoruz .

Test ediliyor:

$ 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

Gördüğünüz gibi, ortaya çıkan sürecin hem stdout hem de stderr'i gitti /tmp/foo-log.


posix_spawn*Errno ayarlamadığını unutmayın . Böylece kullanamazsınız perror(). fprintf(stderr, "...: %s\n", strerror(ret))Bunun gibi bir şey kullanın. Ayrıca, ana işlev bir return 0ifade eksik .
maxschlepzig

1

Evet yapabilirsin. Posix spawn dosya eylemlerinin doğru listesini tanımlamak kesinlikle yoludur.

Misal:

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

Derleyin ve test edin:

$ 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

O Not posix_spawnişlevleri diğer çoğu UNIX işlevleri farklı olarak, bir hata kodu döndürür, bunun yerine, errno yoktur. Bu yüzden kullanamayız perror()ama böyle bir şey kullanmak zorundayız strerror().

İki spawn dosya işlemi kullanıyoruz: addopen ve addup2. Addopen normal bir modele benzer, open()ancak zaten açıksa (burada 1, yani stdout) otomatik olarak kapatılan bir dosya tanımlayıcı da belirtirsiniz. Eklenti2, 1'e dup2()2 kopyalanmadan önce hedef dosya tanımlayıcısına (burada 2, yani stderr) benzer etkilere sahiptir . Bu eylemler yalnızca oluşturulan alt posix_spawnöğede, yani belirtilen komutu çalıştırmadan hemen önce yürütülür .

Gibi fork(), posix_spawn()ve posix_spawnp()hemen ebeveyn dönün. Bu nedenle, sonlandırmayı kullanmak waitid()veya waitpid()açıkça beklemek zorundayız child_pid.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.