자체 생성된 Linux 쉘에서 리디렉션 [닫기]

자체 생성된 Linux 쉘에서 리디렉션 [닫기]

나는 내 자신의 쉘을 작성하고 있습니다. redirection( >및 )을 구현하고 싶습니다 >>. 이를 위해 dup2()시스템 호출을 사용했습니다. 그러나 내가 입력한 명령에 리디렉션이 있으면 다른 명령은 내가 사용하지 않거나 포함되어 있지 >않더라도 >>이전 리디렉션을 따릅니다 . 이전 파일 설명자를 닫는 것이 누락되었나요? 또한 >를 사용하더라도 출력은 항상 파일에 추가됩니다.

아래는 내 코드입니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <setjmp.h>
#include <signal.h>
#include <fcntl.h>
#include <stdbool.h>

#define MAXLINE 259
#define PROMPT "> "
#define MAX_ARG_LIST    200
//-Wno-write-strings to g++ compiler to supress warnings

extern char **environ;

#define MAX_CMD_SIZE    50
#define SEARCH_FOR_CMD  -1
typedef void (*buildInFunc) (char **);
typedef struct {
    char cmd[MAX_CMD_SIZE];
    buildInFunc func;
} builtInCmd;

// built-in commands
void execExit(char *cmd[]);
void execCd(char *cmd[]);
builtInCmd builtInCmds[] = {
        {"exit",    execExit  },
        {"cd",  execCd }
};
int builtInCnt = sizeof(builtInCmds)/sizeof(builtInCmd);
int isBuiltIn(char *cmd);

void execBuiltIn(int i, char *cmd[]);

// capture SIG_INT and recover
sigjmp_buf ctrlc_buf;
void ctrl_hndlr(int signo) {
    siglongjmp(ctrlc_buf, 1);
}

int main(int argc, char *argv[]) {

    char line[MAXLINE];
    pid_t childPID;
    int argn; char *args[MAX_ARG_LIST];
    int cmdn;
        char *in_file,*out_file;
        char *gt=">";       //truncate redirection char pointer
        char *gtgt=">>";    //append redirection char pointer        
        int in_fd,out_fd;   //
        bool out_fd_present=false;  //checks if > or >> string is present

    // setup SIG_INT handler
    if (signal(SIGINT, ctrl_hndlr) == SIG_ERR)
        fputs("ERROR: failed to register interrupts in kernel.\n", stderr);

    // setup longjmp buffer
    while (sigsetjmp(ctrlc_buf, 1) != 0) ;

    for(;;) {
    // prompt and get commandline
        fputs(PROMPT, stdout);
        fgets(line, MAXLINE, stdin);
        if (feof(stdin)) break; // exit on end of input

    // process commandline
        if (line[strlen(line)-1] == '\n')
            line[strlen(line)-1] = '\0';
        // build argument list
        args[argn=0]=strtok(line, " \t");
                while(args[argn]!=NULL && argn<MAX_ARG_LIST){

                        args[++argn]=strtok(NULL," \t");
                        //if append >> redirection present
                        if(strcmp( args[argn-1],gtgt ) == 0){
                            out_fd_present=true;
                            out_file=args[argn];
                            argn=argn-2;
                            out_fd = open(out_file, O_WRONLY | O_APPEND | O_CREAT,S_IRWXG | S_IRWXO | S_IRWXU);
                            //printf("\n >> found\n");                            
                        }
                        //if trncate > redirection present
                        else if(strcmp( args[argn-1],gt ) == 0){
                            out_fd_present=true;
                            out_file=args[argn];
                            argn=argn-2;
                            out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXG | S_IRWXO | S_IRWXU);
                            //printf("\n > found\n");
                        }
                        printf("args[%d]=%s\n",argn-1,args[argn-1]);
                }


    // execute commandline
    if ((cmdn = isBuiltIn(args[0]))>-1) {
        execBuiltIn(cmdn, args);
    } else {
        childPID = fork();
                int save_out;
        if (childPID == 0) {
                    if(out_fd_present){
                        int a;
                        save_out = dup(STDOUT_FILENO);
                        dup2(out_fd,1);
                        close(out_fd);                        
                    }
                        execvp(args[0], args);                        
            fputs("ERROR: can't execute command.\n", stderr);
            _exit(1);
        } else {
            waitpid(childPID, NULL, 0);
        }
    }

    // cleanup
                fflush(stderr);
                fflush(stdout);
    }

    return 0;
}

int isBuiltIn(char *cmd) {
    int i = 0;        
    while (i<builtInCnt) {
        if (strcmp(cmd,builtInCmds[i].cmd)==0)
            break;
        ++i;
    }
    return i<builtInCnt?i:-1;
}

void execBuiltIn(int i, char *cmd[]) {
    if (i == SEARCH_FOR_CMD)
        i = isBuiltIn(cmd[0]);
    if (i >= 0 && i < builtInCnt)
        builtInCmds[i].func(cmd);
    else
        fprintf(stderr, "ERROR: unknown built-in command\n");
}

void execExit(char *cmd[]) {        
    exit(0);
}
void execCd(char *cmd[]){
    chdir(cmd[1]);
}

답변1

간단한 논리 오류가 있습니다. 또는 를 감지하면 out_fd_present절대로 재설정하지 않습니다(예: 루프 상단에서).true>>>false

나는 당신의 "껍질"이 장난감 껍질이라고 추측하고 있지만, 다른 질문도 많이 있다는 것을 언급해야 합니다. 예를 들어, out_fd상위 및 save_out하위 프로세스에서 누출이 발생합니다(이것은 무엇을 위한 것입니까?). strcmpstring 을 호출할 수 있는 버그가 있습니다 NULL. 이에 대한 또 다른 그림이 있습니다 chdir. 구문과 기능도 쉘이 "해야 하는" 작업(리디렉션 연산자의 위치, umask, 간격 및 토큰화 등)과 다릅니다. 문체상의 불일치는 말할 것도 없고(못생긴 낙타 상자와 뱀 상자가 모두 사용되었습니다). 쉘을 구현하려면, 심지어 장난감 쉘이라도 먼저 좋은 디자인부터 시작해야 할 것입니다.

관련 정보