2016-10-16 18 views
13

Tôi đang viết chương trình đọc đầu vào từ stdin, thao tác đầu vào và ghi đầu ra thành giá trị chuẩn. Tuy nhiên, nhiều chương trình kiểm tra xem stdin là một thiết bị đầu cuối hay một đường ống (bằng cách gọi một hàm như isatty) và tạo ra kết quả khác nhau. Làm cách nào để chương trình của tôi giả vờ là TTY?Viết chương trình giả vờ là TTY

Giải pháp sẽ hoạt động trên cả Linux và macOS. Bất kỳ ngôn ngữ lập trình nào tạo ra một nhị phân độc lập đều được chấp nhận, nhưng Go được ưu tiên.

Lưu ý rằng tôi đang đặt câu hỏi lập trình, không yêu cầu công cụ. Vì vậy, những thứ như script hoặc unbuffer không phải là thứ mà tôi đang tìm kiếm.

+0

Có cách tiếp cận thú vị đằng kia: http://unix.stackexchange.com/a/249764/65275 – coredump

+0

Cảm ơn, nhưng tất cả những giải pháp phụ thuộc vào một số bên ngoài chương trình. Tôi cần phải viết một chương trình độc lập hoạt động mà không yêu cầu hệ thống máy khách phải cài đặt một số thứ nhất định. – Ethan

+3

[Câu hỏi về Exchange Stack của Unix và Linux] (http://unix.stackexchange.com/q/21147/12106) có thể phù hợp hơn. Thuật ngữ bạn thực sự muốn tìm kiếm là * pseudo tty * (hoặc * pty *). –

Trả lời

1

Sau đây là mã làm việc đầy đủ để chạy lệnh trong một pty và bắt đầu ra của nó. (Không như nhiều dòng như bạn có thể nghĩ.)

#include <signal.h> 
#include <stdlib.h> 
#include <sysexits.h> 
#include <unistd.h> 
#include <util.h> 

pid_t child = 0; 

void sighandler(int signum) { 
    if (child > 0) { 
    killpg(child, signum); 
    exit(signum); 
    } 
} 

// Run a command in a pty. 
// Usage: /path/to/this/binary command to run 
int main(int argc, char *argv[]) { 
    if (argc < 2) { 
    return EX_USAGE; 
    } 

    int master; 
    child = forkpty(&master, NULL, NULL, NULL); 

    if (child == -1) { 
    perror("failed to fork pty"); 
    return EX_OSERR; 
    } 

    if (child == 0) { 
    // we're in the child process, so replace it with the command 
    execvp(argv[1], argv + 1); 
    perror("failed to execute command"); 
    return EX_OSERR; 
    } 

    // trap kill signals and forward them to child process 
    signal(SIGHUP, sighandler); 
    signal(SIGINT, sighandler); 
    signal(SIGTERM, sighandler); 

    const int buf_size = 1024; 
    char buf[buf_size]; 
    fd_set fds; 
    ssize_t bytes_read; 

    // forward the output continuously 
    while (1) { 
    FD_ZERO(&fds); 
    FD_SET(master, &fds); 

    if (select(master + 1, &fds, NULL, NULL, NULL) > 0 && FD_ISSET(master, &fds)) { 
     bytes_read = read(master, buf, buf_size); 
     if (bytes_read <= 0) { 
     return EXIT_SUCCESS; 
     } 

     if (write(STDOUT_FILENO, buf, bytes_read) != bytes_read) { 
     perror("failed to write to stdout"); 
     return EX_OSERR; 
     } 
    } 
    } 
} 
Các vấn đề liên quan