리눅스

[리눅스] 미니쉘 만들기

폭풍저그김탁구 2021. 10. 23. 15:50

시스템 관련 수업을 들으면서, 미니쉘 만들기 실습을 진행했다.

이전 과제에서 기본 미니쉘을 제작했고, 이번 과제에서는 리다이렉션과 파이프를 적용했다.

난이도를 낮추어 한 줄에 하나의 IPC만 허용하였다.

 

선배님의 과제와 인터넷을 참고하여 진행하였는데... 이전 과제를 최대한 변형하지 않고 진행하려고 하니 코드가 아주 엉망이 됐다ㅋㅋㅋㅋ...

하면서 너무너무 거슬렸지만 제출이 우선이라서 그냥 패스 ㅎㅎ..

 

Pipe

// pipe cmd function
void ex_launchPipe(char **args, char **argsPipe)
{
    int pipefd[2];
    pid_t pid1, pid2;

	//pipe
    if (pipe(pipefd) < 0)
    {
        printf("\nPipe could not be initialized");
        return;
    }

    pid1 = fork();
    if (pid1 == 0)
    {
        // child 1
        dup2(pipefd[1], STDOUT_FILENO);
        close(pipefd[0]);
        close(pipefd[1]);

        if (execvp(args[0], args) == -1)
        {
            perror("caanot execute: child 1");
            exit(0);
        }
    }

    else
    {
        // parent
        pid2 = fork();

        if (pid2 == 0)
        {
            // child 2
            dup2(pipefd[0], STDIN_FILENO);
            close(pipefd[1]);
            close(pipefd[0]);
            if (execvp(argsPipe[0], argsPipe) == -1)
            {
                perror("caanot execute");
                exit(0);
            }
        }
        else
        {
            close(pipefd[1]);
            wait(NULL);
            wait(NULL);
        }
    }
}

위 코드는 단순하게 파이프 처리하는 함수이다. 다른 main함수, 입출력 함수는 뺐다. 이미 구글에 자료도 많고 우선 내 코드는 너무 더럽고... 아래 긱포긱과 교안을 적당히 섞어 만들었다.

 

참고: https://www.geeksforgeeks.org/making-linux-shell-c/

 

Making your own Linux Shell in C - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

* error 발생 부분
-문제: 출력을 하고도 계속 입력을 받음.

 

다른 코드를 봐도 별 다른 게 없어서 나는 내 컴퓨터 문제인 줄 알았다ㅋㅋㅋ 그래서 그냥 제출을 했는데 우연찮게 나와 같은 문제를 겪고 있는 블로그를 발견했다!

 

-해결: 마지막 else{~~} 줄에서 close(pipefd[1]); 를 추가

출력 파이프(?)를 닫아주지 않아서 입력 파이프가 계속 도는 거라고 이해했다. 사실 파이프를 제대로 이해한 게 아니어서 맞는지는 모르겠지만 입력하니 바로 해결됐다. 구글 감사합니다!

 

참고: https://2pound2pound.tistory.com/104

 

[개발 일지] 2020년 2월 10일 - Shell(piping, dup2(), pipe())

int lsh_launch_pipe(char** args, char** argsPipe) { int pipefd[2]; pid_t p1, p2; if (pipe(pipefd) < 0) { fprintf(stderr, "Pipe could not be initialized"); return 0; } p1 = fork(); if (p1 < 0) { fpri..

2pound2pound.tistory.com

 


redirection

int ex_dealArg(char *line, char **args, char **argsPipe)
{
    int redirectionFlag;

    // Yes pipe
    if (piped)
    {
        //파이프 처리 부분(생략함)
    }
    else
    {
        char *tptr;
        if ((tptr = strchr(line, '>')) != NULL)
        {
            int i = 0;
            char *ptr = strtok(line, " ");

            while (ptr != NULL)
            {
                args[i++] = ptr;
                if (tptr == ptr)
                {
                	//리다이렉션 부분 기억 포인터
                    redirectionFlag = i;
                    args[i - 1] = NULL;
                }
                ptr = strtok(NULL, " ");
            }
            args[i] = NULL;

            umask(0);
            int tableNum = open(args[redirectionFlag], O_RDWR | O_CREAT, 0777);
            char path[100];
            sprintf(path, "/bin/%s", args[0]);

            if (fork() == 0)
            {
                dup2(tableNum, STDOUT_FILENO);
                execv(path, args);
            }
            else
            {
                wait(NULL);
            }
        }
        else if ((tptr = strchr(line, '<')) != NULL)
        {
            int i = 0;
            char *ptr = strtok(line, " ");

            while (ptr != NULL)
            {
                args[i++] = ptr;
                if (tptr == ptr)
                {
                    redirectionFlag = i;
                    args[i - 1] = NULL;
                }
                ptr = strtok(NULL, " ");
            }
            args[i] = NULL;

            umask(0);
            int tableNum = open(args[redirectionFlag], O_RDWR | O_CREAT, 0777);
            char path[100];
            sprintf(path, "/bin/%s", args[0]);

            if (fork() == 0)
            {
                dup2(tableNum, STDIN_FILENO);
                execv(path, args);
            }
            else
            {
                wait(NULL);
            }
        }
        else
        {
            //일반 cmd 처리 부분(생략함)
        }
    }
}

 

생각보다 리다이렉션 관련해서 구글링이 안 나와서 실망했음ㅎㅎ.. 위 코드는 매우 매우 대충 짠 코드입니다. 다른 코드들과 다르게 함수로 따로 빼지 않고 그냥 한 함수에서 다 처리해버렸음. 이걸 가장 마지막에 짠 코드여서 그런가 돌아가는 방식은 가장 맘에 드는데 밀린 과제가 많아서 그냥 패스했습니다.

결과만 잘 나오면 되는 거 아닐까...ㅎ

 


시스템은 저랑 안 맞는 거 같습니다.

'리눅스' 카테고리의 다른 글

[리눅스] 파이프와 리다이렉션의 차이  (0) 2021.11.13