오보에블로그

[시스템프로그래밍] 리눅스 쉘 (명령어 해석기)만들기 본문

C++ & C#/C++

[시스템프로그래밍] 리눅스 쉘 (명령어 해석기)만들기

(OBO) 2019. 7. 5. 14:32
728x90

A Simple Linux Shell

본 설계 프로젝트에서는 간단한 리눅스 명령어 해석기(일명: smsh)를 스스로 만들어 본다.

설계 및 구현해야 할 smsh는 다음과 같은 명령어를 처리할 수 있어야 한다.

 

  • foreground and background execution (&)
  • multiple commands separated by semicolons
  • history command
  • shell redirection (>, >>, >|, <)
  • shell pipe (ls –la | more)
  • Multiple pipe (ls | grep “^d” | more)
  • cd command

 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>

void print_list(int length,char *buf[]);

int main(){
    char str[1024];
    char *buffer[255];
    int buf_leng = 1;
    int str_len;
    int t;
    int fd;
    char *command[16];
    char *pip_command[16][16];
    char *cur_dir;
    int cmd_num = 0;
    int fdr[2];
    int fdd = 0;
    int p;
    int type = 0;
    int semi = 0;
    int semi_pre_buf_leng =0;
    char his_buf[256];
    char c = '\n';
    pid_t pid;
    int his;
    int bck_gnd = 0;

    // signal(SIGINT,SIG_IGN);
    // signal(SIGQUIT,SIG_IGN);
    // signal(SIGTSTP,SIG_IGN);
    while(1){
        
        type = 0;
        buf_leng = 1;
        cmd_num = 0;
        for(int i=0 ; i < 1024 ; i++) str[i]='\0'; //initialization of str
        if(semi != 0){
            // printf("어서오십시오! 세미월드입니다\n");
            for(int i = semi+1; i < semi_pre_buf_leng; i++){
                strcat(str,buffer[i]);
                strcat(str," ");
            }
            semi = 0;
            semi_pre_buf_leng = 0;
            // printf("%s",str);
        }
        else {
            fgets(str,sizeof(str),stdin);
            his = open("history",O_CREAT|O_RDWR|O_APPEND);
            write(his,str,strlen(str));
            // write(his,&c,1);
            close(his);
            
        }
        for(int i=0; i < 15; i++) { 
            command[i] = NULL;
            buffer[i] = malloc(sizeof(char) * 20);
        }
        for(int i=0; i< 16;i++){
            for(int k = 0; k<16;k++)
                pip_command[i][k] =malloc(sizeof(char) * 20);
        }
        
        str[strlen(str) -1] = '\0';
        str_len = strlen(str);
        // printf("왜 나왔다가 안나왓다가.. ㅜㅠㅜㅠㅜ 길이:%d\n",str_len);
        // print_list(buf_leng,buffer);
        for(int i=0; i< strlen(str);i++){
            // printf("%c",str[i]);
            switch(str[i]){
                case ' ':
                    if(strcmp(buffer[buf_leng],"") != 0)
                        buf_leng++;
                    break;
                case '>':
                    if(buf_leng > 0 && strcmp(buffer[buf_leng-1],">")== 0){
                        strcat(buffer[buf_leng-1],">");
                    }
                    else{
                        if(strcmp(buffer[buf_leng],"") != 0)
                            buf_leng++;
                        strcat(buffer[buf_leng], ">");
                        buf_leng++;
                    }
                    break;
                case '|' :
                    if(strcmp(buffer[buf_leng-1],">")== 0){
                        strcat(buffer[buf_leng-1],"|");
                    }
                    else{
                        if(strcmp(buffer[buf_leng],"") != 0)
                            buf_leng++;
                        strcat(buffer[buf_leng], "|");
                        buf_leng++;
                        type = 1;
                        break;
                    }
                    break;
                case '<' :
                    if(strcmp(buffer[buf_leng],"") != 0)
                        buf_leng++;
                    strcat(buffer[buf_leng], "<");
                    buf_leng++;
                    break;
                case '&' :
                    if(strcmp(buffer[buf_leng],"") != 0)
                        buf_leng++;
                    strcat(buffer[buf_leng], "&");
                    buf_leng++;
                    break;
                case ';' :
                    if(strcmp(buffer[buf_leng],"") != 0)
                        buf_leng++;
                    strcat(buffer[buf_leng], ";");
                    semi = buf_leng;
                    buf_leng++;
                    break;
                
                default:
                    // printf("%d",i);
                    strncat(buffer[buf_leng],&str[i],1);
                    // printf("%s",buffer[buf_leng]);
                    break;
            }
            
        }

        // if(strcmp(buffer[buf_leng-1],"hello") == 0) printf("please..");
        buf_leng++;
        if(semi != 0){
            semi_pre_buf_leng = buf_leng;
            buf_leng = semi;
        }
        // printf("이 밑에거는 왜 실행이 안되는거죠..\n");
        // print_list(buf_leng,buffer);
        switch(type){
            case 0 :
                if((pid = fork() )== 0){
                    // printf("맛있는 포크를 성공시켰습니다\n");
                    t = 1;
                    while(t < buf_leng){
                        if(strcmp(buffer[t],">")== 0){
                            // printf(">가 써져있으니 여기로 오시지요\n 파일 성함이 %s가 맞는 지요?",buffer[t+1]);
                            fd = open(buffer[t+1],O_CREAT | O_RDWR|O_TRUNC);
                            dup2(fd,1);
                            close(fd);
                            t += 2;
                        }
                        else if(strcmp(buffer[t],"<")== 0){
                            fd = open(buffer[t+1],O_RDWR);
                            
                            dup2(fd,0);
                            close(fd);
                            // command[cmd_num] = buffer[t+1];
                            // cmd_num++;
                            t += 2;
                        }
                        else if(strcmp(buffer[t],">>")== 0){
                            fd = open(buffer[t+1],O_CREAT|O_RDWR|O_APPEND);
                            dup2(fd,1);
                            close(fd);
                            t += 2;
                            
                        }
                        else if(strcmp(buffer[t],">|")== 0){
                            fd = open(buffer[t+1],O_CREAT | O_RDWR|O_TRUNC);
                            dup2(fd,1);
                            close(fd);

                            t += 2;
                        }
                        else if(strcmp(buffer[t],"&")== 0){
                            bck_gnd = 0;
                            t += 2;
                        }
                        else{
                            command[cmd_num] = buffer[t];
                            cmd_num++;
                            t++;
                            
                        }
                    }
                    // printf("왜 실행이 안될까요?\n");
                    // printf("커맨드1번째의 값은 이겁니다.%s\n",command[1]);
                    if(strcmp(command[0],"cd")==0){//내장명령어 cd
                        chdir(command[1]);//현재 디렉토리 변경
                    }
                    else if(strcmp(command[0],"history")== 0){
                        his = open("history",O_CREAT|O_RDWR);
                        read(his,his_buf,255);
                        printf("%s",his_buf);
                        bck_gnd = 1;
                    }
                    else{
                        execvp(command[0],command);
                        exit(0);
                    }
                    
                }
                break;
            //pipe
            case 1 :
                // if(fork() == 0){
                    // printf("맛있는 파이프 포크를 성공시켰습니다\n");
                    t = 1;
                    p = 0;
                    while(t < buf_leng){
                        if(strcmp(buffer[t],"|") == 0){
                            pip_command[cmd_num][p] = NULL;
                            cmd_num++;
                            t++;
                            p = 0;
                        }
                        else{
                            
                            strcat(pip_command[cmd_num][p],buffer[t]);
                            // printf("현재 파이프 커맨드%d %d에 %s를 넣고 싶다.. 미칠듯이\n ",cmd_num,p,buffer[t]);
                            // printf("넣어졌는지 확인해볼까? -> %s\n",pip_command[cmd_num][p]);
                            p++;
                            t++;
                        }

                    }
                    pip_command[cmd_num][p] = NULL;
                    p = 0;
                    int i;
                    for(i=0; i<cmd_num; i++){
                        pipe(fdr);
                        switch(fork()){
                            case -1: perror("fork error"); break;
                            case  0:
                                if(close(1) == -1) perror("close1");
                                dup(fdr[1]);
                                if(close(fdr[0]) == -1 || close(fdr[1]) == -1){
                                    perror("close2");
                                }
                                execvp(pip_command[i][0], pip_command[i]);
                                printf("cmd not found");
                                exit(0);
                            default: 
                                close(fdr[1]);
                                dup2(fdr[0], 0);
                        }
                    }
                    execvp(pip_command[i][0], pip_command[i]);
                break;
        
            default :
                if(!bck_gnd){
                    wait(NULL);
                    fflush(stdout);
                }
                else{
                    printf("BACKGROUND PID: %d\n",getpid());
                    bck_gnd = 0;
                    break;
                }
        
        }
        // for(int i=0; i < 15; i++) { free(buffer[i]);}
    }
}


void print_list(int length,char *buf[]){
    for(int i = 1 ; i < length ; i++){
        printf("[%s]\t", buf[i]);
    }
    printf("\n");
}



 

728x90

'C++ & C# > C++' 카테고리의 다른 글

[C++] std::thread 사용법  (0) 2022.02.24
[C++Docs] 타입 최대 최소 define 상수 라이브러리  (0) 2022.01.10
5362 전투드로이드가격  (0) 2018.03.17
10992 별찍기-17  (0) 2018.02.04
10991 별찍기-16  (0) 2018.02.04