Q:

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

I want to use "yp\t\n\0" to run “ypdomainname” command by exploiting auto-completion in busybox, but it failed. my code and result are below:
#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] = '\0';

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

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

}

Result of my code
What makes me confused is that the character is not changed in function lineedit_read_key() in file lineedit.c and it will run the function input_tab() when the character is '\t'.
input_tab will be executed when character is '\t'
Recently, i took some time to learn about terminal to simulate auto-completion, but i still failed. My code is below:
#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] = '\0';
    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] = '\0';
    }

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

like the result of my first try, the result is: ash: yp: not found.

A:

Your code fails because a pipe is not a terminal. Many programs will use isatty(3) and alike to detect if the standard input is connected to a terminal and adjust their behaviour depending on the result.
What you can do is to open a pseudo terminal pair using openpty(3) and run the command with the slave duplicated to its standard input, output and error descriptors, and using the master to communicate with it. Unfortunately I have no time right now writing a full solution as it is rather intricate; I've done it ever in Python and it was tricky even there.

