Nhận đầu ra của `posix_spawn`


9

Vì vậy, tôi có thể chạy một quy trình trong Unix / Linux bằng POSIX, nhưng có cách nào để tôi có thể lưu trữ / chuyển hướng cả STDOUT và STDERR của quy trình sang một tệp không? Các spawn.htiêu đề chứa một giảm tốc của posix_spawn_file_actions_adddup2trông có liên quan, nhưng tôi không chắc chắn khá làm thế nào để sử dụng nó.

Quá trình sinh sản:

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

Bộ lưu trữ đầu ra:

...?


1
Thông số thứ ba của posix_spwanlà một con trỏ kiểu posix_spawn_file_actions_t(một bạn đã cho là NULL). posix_spawnsẽ mở, đóng hoặc sao chép mô tả tệp được kế thừa từ quá trình gọi theo quy định của posix_spawn_file_actions_tđối tượng. Các posix_spawn_file_actions_{addclose,adddup2}chức năng được sử dụng để chỉ ra những gì xảy ra với fd.
muru

@muru - Bạn có nghĩ rằng bạn có thể thêm một ví dụ làm việc? Tôi hiểu rằng sự tương tác giữa các chức năng được thực hiện bằng một "hành động tập tin", nhưng không rõ chính xác điều này khớp với nhau như thế nào, hoặc vị trí của fd được xác định.
nbubis

Câu trả lời:


16

Dưới đây là một ví dụ tối thiểu về sửa đổi mô tả tệp của một quy trình được sinh ra, được lưu dưới dạng 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);
}

Nó làm gì?

  • Tham số thứ ba của posix_spwanlà một con trỏ kiểu posix_spawn_file_actions_t(một bạn đã cho là NULL). posix_spawnsẽ mở, đóng hoặc sao chép mô tả tệp được kế thừa từ quá trình gọi theo quy định của posix_spawn_file_actions_tđối tượng.
  • Vì vậy, chúng tôi bắt đầu với một posix_spawn_file_actions_tđối tượng ( chiild_fd_actions) và khởi tạo nó với posix_spawn_file_actions_init().
  • Bây giờ, các posix_spawn_file_actions_{addopen,addclose,addup2}chức năng có thể được sử dụng để mở, đóng hoặc trùng lặp file descriptor (sau khi open(3), close(3)dup2(3)các chức năng) tương ứng.
  • Vì vậy, chúng tôi posix_spawn_file_actions_addopenmột tập tin tại /tmp/foo-logđể mô tả tập tin 1(còn gọi là thiết bị xuất chuẩn).
  • Sau đó, chúng tôi posix_spawn_file_actions_adddup2fd 2(aka stderr) đến fd 1.
  • Lưu ý rằng không có gì đã được mở hoặc bị lừa chưa . Hai chức năng cuối cùng chỉ đơn giản là thay đổi child_fd_actionsđối tượng để lưu ý rằng những hành động này sẽ được thực hiện.
  • Và cuối cùng chúng ta sử dụng posix_spawnvới child_fd_actionsđối tượng.

Kiểm tra nó ra:

$ 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

Như bạn có thể thấy, cả stdout và stderr của quá trình sinh sản đã đi đến /tmp/foo-log.


Lưu ý rằng posix_spawn*không đặt errno. Vì vậy, bạn không thể sử dụng perror(). Sử dụng một cái gì đó như fprintf(stderr, "...: %s\n", strerror(ret))thay thế. Ngoài ra, chức năng chính là thiếu một return 0tuyên bố.
maxschlepzig

1

Vâng, bạn có thể. Xác định đúng danh sách các hành động tập tin sinh sản posix chắc chắn là cách để đi.

Thí dụ:

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

Biên dịch và kiểm tra:

$ 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

Lưu ý rằng các posix_spawnhàm không đặt errno, thay vào đó, không giống như hầu hết các hàm UNIX khác, chúng trả về mã lỗi. Vì vậy, chúng ta không thể sử dụng perror()mà phải sử dụng một cái gì đó như strerror().

Chúng tôi sử dụng hai hành động tập tin sinh sản: addopen và addup2. Addopen tương tự như bình thường open()nhưng bạn cũng chỉ định một bộ mô tả tệp sẽ tự động đóng nếu đã mở (ở đây 1, tức là thiết bị xuất chuẩn). Addup2 có các hiệu ứng tương tự dup2(), tức là bộ mô tả tệp đích (ở đây 2, tức là stderr) được đóng nguyên tử trước khi 1 được sao chép thành 2. Các hành động đó chỉ được thực hiện trong con được tạo bởi posix_spawn, tức là ngay trước khi nó thực thi lệnh được chỉ định.

Thích fork(), posix_spawn()posix_spawnp()ngay lập tức trở về với cha mẹ. Vì vậy, chúng tôi phải sử dụng waitid()hoặc waitpid()chờ đợi một cách rõ ràng về việc child_pidchấm dứt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.