0

嗨,我在我的操作系统签名中为 UNIX 构建了一个小 minishell,当我编译代码并在我的机器上尝试它时没有错误,但是在自动更正器检查代码的那一刻,它会抛出一个 BROKEN PIPE 错误。这就是我所做的:

int main(void)
{
    descriptorEntrada = dup(STDIN_FILENO);
    descriptorSalida = dup(STDOUT_FILENO);
    descriptorError = dup(STDERR_FILENO);

    char ***argvv = NULL;
    int argvc;
    //char **argv = NULL;
    //int argc;
    char *filev[3] = {NULL, NULL, NULL};
    int bg;
    int ret;
    int status;
    pid_t pid;
    int i, fd[2], entrada, fd1; //fdOut, fd1, saved_stdout; //fdOut;
    setbuf(stdout, NULL); /* Unbuffered */
    setbuf(stdin, NULL);
    mypid=getpid();
    while (1)
    {
        fprintf(stderr, "%s", "msh> "); /* Prompt */
        setSignal();
        restoreDescriptors();
        ret = obtain_order(&argvv, filev, &bg); //external parser (arguments, in/out/err redirect, background)
        if (ret == 0)
            break; /* EOF */
        if (ret == -1)
            continue;   /* Syntax error */
        argvc = ret - 1; /* Line */
        if (argvc == 0)
            continue; /* Empty line */

        if (argvv[1]==NULL){
            if(strcmp(argvv[0][0],"exit")==0){
                exit (0);
            }
            ejecutarComando(argvv,bg,filev);
        } 
        else{
            entrada = STDIN_FILENO;
            if (filev[0]!=NULL){
                entrada=open(filev[0], O_RDONLY);
                if(entrada<0){
                    perror ("Error al abrir el fichero de entrada!\n");
                    exit(1);
                }

            }

            for(i=0;i<argvc-1;i++){
                pipe(fd);
                generarProceso(argvv[i], entrada, fd[1]); //fd[1] escritor del pipe
                if (entrada!=STDIN_FILENO){
                    close(entrada);
                }
                close(fd[1]);
                entrada=fd[0]; //el siguiente hijo lee de aqui
            }
            //ultimo paso
            switch (pid=fork()){
            case -1:
                perror("Error en el fork().\n");
                break;
            case 0: //hijo
                if(entrada!=STDIN_FILENO){
                    dup2(entrada,STDIN_FILENO);
                    close(entrada);
                }
                if(filev[1]!=NULL){ //redirigimos la salida estandar
                    fd1 = creat(filev[1],0666);
                    if (fd1<0){
                        perror("Error al abrir el archivo\n");
                        break;
                    }
                    dup2(fd1,STDOUT_FILENO);
                    close(fd1);
                }
                execvp(argvv[i][0],argvv[i]); 
            default: //padre
                if(waitpid(pid,&status,0)>0)
                    WEXITSTATUS(status);
                else{
                    perror("Error en la ejecucion.\n");
                    break;  
                }
            }
            close(entrada);
        }

    } //end while
    return 0;
}
void setSignal(){
    // SHELL SIGNAL CONTROL////
    signal(SIGINT,SIG_IGN);   //ignoramos SIGINT 
    signal(SIGQUIT,SIG_IGN);  //ignoramos SIGQUIT
    signal(SIGKILL, SIG_IGN); //ignoramos SIGKILL
}

void restoreDescriptors(){
    dup2(descriptorSalida,STDIN_FILENO);
    dup2(descriptorSalida, STDOUT_FILENO);
    dup2(descriptorError,STDERR_FILENO);
}


int ejecutarComando(char *** argvv, int bg, char** filev){
    pid_t pid;
    int status;
    int fdIn, fdErr, fdOut;

    if (bg==0){ //Si el proceso es en foreground hay que manejar signals
        signal(SIGINT,SIG_DFL);
        signal(SIGQUIT,SIG_DFL);
        signal(SIGKILL,SIG_DFL);
    }

    if (filev[0] != NULL){
        fdIn = open(filev[0], O_RDONLY);
        if (fdIn < 0)
        {
            perror("Error al abrir el fichero de entrada!\n");
            return 1;
        }
        dup2(fdIn, STDIN_FILENO);
        close(fdIn);
    }
    if (filev[1] != NULL){
        fdOut = creat(filev[1], 0666);
        if (fdOut < 0){
            perror("Error al abrir el fichero de salida!\n");
            return 1; 
        }
        dup2(fdOut,1);
        close(fdOut);
    }
    if (filev[2] != NULL)
    {
        fdErr = creat(filev[2], 0666);
        if (fdErr < 0)
        {
            perror("Error al abrir el fichero de error!\n");
            return 1;
        }
        dup2(fdErr, STDERR_FILENO);
        close(fdErr);
    }

    if (strcmp(argvv[0][0], "cd") == 0)
    {
        cambiarDirectorio(argvv);
        return 1;
    }
    else if (strcmp(argvv[0][0], "umask") == 0)
    {
        cambiarUmask(argvv);
        return 1;
    }
    else if (strcmp(argvv[0][0], "limit") == 0)
    {
        limiteRecursos(argvv);
        return 1;
    }
    else if (strcmp(argvv[0][0], "set") == 0)
    {
        setVariable(argvv);
        return 1;
    }
    else
    {
        switch(pid=fork()){
            case -1:perror("Error en el fork.\n");
            case 0: execvp(argvv[0][0], argvv[0]);
                    perror("Error al ejecutar el mandato.|n");
                    return 1; 
            default:
                    if (bg==0) //FOREGROUND
                        while(wait(&status)!=pid); //padre espera al hijo
                    else{ //Background
                        bgpid = getpid();
                        printf("%d\n",bgpid);
            }
        }

    }
    return 0; 
}

ejecutarComando 之后的主要部分似乎运作良好,提前感谢您,并为我糟糕的英语感到抱歉。

4

1 回答 1

1

好的,我刚刚发现了错误,我已经写了两次文件描述符“descriptorSalida”。

void restoreDescriptors(){
    dup2(**descriptorEntrada**,STDIN_FILENO);
    dup2(descriptorSalida, STDOUT_FILENO);
    dup2(descriptorError,STDERR_FILENO);
}
于 2019-12-04T12:17:51.200 回答