为什么我不能在 busybox 中使用 '\t' 模拟自动完成

Why can't I simulate auto-completion with '\t' in busybox

我想利用 busybox 中的自动完成来使用 "yp\t\n[=26=]" 到 运行 “ypdomainname” 命令,但它失败了。我的代码和结果如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>

#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000

int main()
{
    int fd[2];
    pid_t pid;
    FILE *file;
    int status;

    if(pipe(fd) < 0){
        fprintf(stderr, "pipe error!\n");
        return -1;
    }

    if((pid = fork()) < 0){
        fprintf(stderr, "pipe error!\n");
    }else if(pid == 0){     //child
        close(fd[1]);

        int fd_output;
        fd_output = open("result", O_CREAT | O_RDWR, 777);

        if(fd_output != STDOUT_FILENO){
            if(dup2(fd_output, STDOUT_FILENO) != STDOUT_FILENO)
                fprintf(stderr, "dup2 error to stdout\n");
        }

        if(fd[0] != STDIN_FILENO){
            if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
                fprintf(stderr, "dup2 error to stdin\n");
        }
        execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL);
        close(fd[0]);
        close(fd_output);
        return 0;
    }else{                  //parent
        close(fd[0]);

        char buf[MAX_BUF] = "yp";
        buf[2] = '\t';
        buf[3] = '\n';
        buf[4] = '[=10=]';

        write(fd[1], buf, strlen(buf));

        close(fd[1]);
        return 0;
    }

}

Result of my code

让我感到困惑的是,文件 lineedit.c 中的函数 lineedit_read_key() 中的字符没有更改,当字符为 ' 时,它将 运行 函数 input_tab() \t'。 input_tab will be executed when character is '\t'

最近花了点时间学习终端模拟自动补全,还是失败了。我的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <pty.h>

#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000
#define BUFFSIZE 512

typedef void Sigfunc(int);

static void sig_term(int);
static volatile sig_atomic_t sigcaught;

ssize_t writen(int fd, const void *ptr, size_t n){
    size_t nleft;
    ssize_t nwritten;

    nleft = n;
    while(nleft > 0){
        if((nwritten = write(fd, ptr, nleft)) < 0){
            if(nleft == n){
                return(-1); 
            }else{
                break; 
            }
        }else if(nwritten == 0) {
            break;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }
    return(n - nleft);
}

Sigfunc *signal_intr(int signo, Sigfunc *func){
    struct sigaction act;
    struct sigaction oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef  SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

int ptym_open(char *pts_name, int pts_namesz)
{
    char ptr[50];
    int fdm;
    int err;

    if((fdm = posix_openpt(O_RDWR)) < 0){
        return(-1);
    }   
    if(grantpt(fdm) < 0){ 
        goto errout;
    }           
    if(unlockpt(fdm) < 0){  
        goto errout;
    }       

    if(ptsname_r(fdm, ptr, 50) != 0){
        goto errout;
    }

    strncpy(pts_name, ptr, pts_namesz);
    pts_name[pts_namesz - 1] = '[=11=]';
    return(fdm);            /* return fd of master */
errout:
    err = errno;
    close(fdm);
    errno = err;
    return(-1);
}

int ptys_open(char *pts_name){
    int fds;

    if((fds = open(pts_name, O_RDWR)) < 0)
        return(-1);

    return(fds);
}

pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz, const struct termios *slave_termios, const struct winsize *slave_winsize){
    int     fdm, fds;
    pid_t   pid;
    char    pts_name[20];

    if((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0){
        fprintf(stderr, "can't open master pty: %s, error %d", pts_name, fdm);
    }   

    if(slave_name != NULL) {
        strncpy(slave_name, pts_name, slave_namesz);
        slave_name[slave_namesz - 1] = '[=11=]';
    }

    if((pid = fork()) < 0) {
        return(-1);
    }else if (pid == 0) {       /* child */
        if(setsid() < 0){
            fprintf(stderr, "setsid error");
        }

        if((fds = ptys_open(pts_name)) < 0){
            fprintf(stderr, "can't open slave pty");
        }
        close(fdm);     

        if(slave_termios != NULL) {
            if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
                fprintf(stderr, "tcsetattr error on slave pty");
        }
        if(slave_winsize != NULL) {
            if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
                fprintf(stderr, "TIOCSWINSZ error on slave pty");
        }

        if(dup2(fds, STDIN_FILENO) != STDIN_FILENO){
            fprintf(stderr, "dup2 error to stdin");
        }
        if(dup2(fds, STDOUT_FILENO) != STDOUT_FILENO){
            fprintf(stderr, "dup2 error to stdout");
        }
        if(dup2(fds, STDERR_FILENO) != STDERR_FILENO){
            fprintf(stderr, "dup2 error to stderr");
        }
        if(fds != STDIN_FILENO && fds != STDOUT_FILENO && fds != STDERR_FILENO){
            close(fds);
        }
        return(0);      
    } else {                    /* parent */
        *ptrfdm = fdm;  
        return(pid);    
    }
}

void loop(int ptym, int ignoreeof)
{
    pid_t   child;
    int     nread;
    char    buf[BUFFSIZE];

    if((child = fork()) < 0) {
        fprintf(stderr, "fork error");
    }else if(child == 0) {  
        /*for ( ; ; ){
            if((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0){
                fprintf(stderr, "read error from stdin");
            }else if(nread == 0){
                break;
            }

            if(writen(ptym, buf, nread) != nread)
                fprintf(stderr, "writen error to master pty");
        }*/
        char *temp_buf = "yp\t\n";
        if(writen(ptym, temp_buf, strlen(temp_buf)) != strlen(temp_buf)){
            fprintf(stderr, "writen error to master pty");
        }

        if(ignoreeof == 0){
            kill(getppid(), SIGTERM);
        }

        exit(0);
    }

    if (signal_intr(SIGTERM, sig_term) == SIG_ERR)
        fprintf(stderr, "signal_intr error for SIGTERM");

    for( ; ; ){
        if ((nread = read(ptym, buf, BUFFSIZE)) <= 0){

        }
        //printf("nread = %d\n", nread);
        if (writen(STDOUT_FILENO, buf, nread) != nread){
            fprintf(stderr, "writen error to stdout");
        }
    }

    if (sigcaught == 0){
        printf("sigcaught == 0 and kill child\n");
        kill(child, SIGTERM);
    }   
}

static void sig_term(int signo)
{
    sigcaught = 1;      
}

int main(int argc, char *argv[]){
    int fd[2];
    pid_t pid;
    FILE *file;
    int status;
    int fdm;
    int ignoreeof;
    char slave_name[40];
    struct termios orig_termios;
    struct winsize size;

    pid = pty_fork(&fdm, slave_name, sizeof(slave_name), &orig_termios, &size);
    if(pid < 0){
        fprintf(stderr, "fork error!\n");
    }else if(pid == 0){  //child
        if(execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL) < 0){
            fprintf(stderr, "can't execute: %s", DEFAULT_BUSYBOX_PATH);
        }
        /*if(execvp(argv[1], &argv[1]) < 0){
            fprintf(stderr, "can't execute: %s", argv[1]);
        }*/
    }

    loop(fdm, ignoreeof);
}

像我第一次尝试的结果,结果是:ash: yp: not found.

您的代码失败,因为管道不是终端。许多程序将使用 isatty(3) 等来检测标准输入是否连接到终端并根据结果调整它们的行为。

你可以做的是使用 openpty(3) 和 运行 命令打开一个伪终端对,从站复制到它的标准输入、输出和错误描述符,并使用主站进行通信用它。不幸的是,我现在没有时间写一个完整的解决方案,因为它相当复杂;我曾经在 Python 做过,即使在那里也很棘手。