#include #include #include #include #include void File_Input(int option, char *com[5], int background); void File_Output(int option, char *com[5], int background); void Pipe(char *com[5], int background); void Round_robin(int robin, char *com[5], int background); char buf[256]; int main(int argc, char* argv[]) { char blank[] = " "; int status; int i = 0, in, out, back, pipe, robin ; char *token; char *com[5]; while(1) { for(i = 0; i <256; i++) buf[i] = '\0'; //초기화 for(i = 0; i <5; i++) com[i] = '\0'; //초기화 in = 0; out = 0; back = 0; pipe = 0; robin = 0; // 변수 초기화 // 표준입력장치에 프롬프트 표시 write(1, "[MySHELL]$ ", 11); // ^D 혹은 logout입력시 shell종료 if(read(0, buf, 256) == 0 || strcmp(buf, "logout\n") == 0) break; // 공백라인 continue; else if(strlen(buf)<1) continue; buf[strlen(buf) - 1] = '\0'; for(i = 0; i ') { in++; //'>'의 갯수 카운터증가 buf[i] = ' '; } // 명령어에 입력방향전환 기호 있을때 else if(buf[i] == '<') { out++; // '<'의 갯수 카운터 증가 buf[i] = ' '; } // 명령어에 백그라운드 실행 기호가 있을때 if(buf[i] == '&') { back++; // '&'의 갯수 카운터 증가 buf[i] = ' '; } if(buf[i] == '|') { pipe++; // '|'의 갯수 카운터 증가 buf[i] = ' '; } if(buf[i] == ';') { robin++; buf[i] = ' '; } // 입력방향전환과 출력방향전환이 같이 입력되었을때 Error if(in != 0 &&out != 0) { write(1, "Error!!\n", 8); continue; } // blank로 명령어를 분할 token = strtok(buf, blank); i = 0; //명령어 인덱스 while(token != NULL) { com[i] = token; // 명령어를 분할해서 com[i]에 넣음 token = strtok(NULL, blank); i++; } if(in != 0) { File_Input(in, com, back); continue; } else if(out != 0) // 명령에서 입력방향전환 기호가 있을경우 { File_Output(out, com, back); continue; } else if(pipe !=0) { Pipe(com, back); continue; } else if(robin !=0) { Round_robin(robin, com, back); continue; } else { if(fork() == 0) //명령어 실행을 위한 자식 프로세스 생성 { execlp(com[0], buf, com[1], com[2], com[3], com[4], NULL); //입력한 명령 실행 exit(0); } if(back == 0) wait(&status); // 백그라운드가 아니면 부모프로세서가 자식프로세스 종료하기를 기다림 // 명령어에 백그라운드 기호가 있을경우 wait()를 두지않에 백그라운드로 실행 } } return 0; } void File_Input(int option, char *com[5], int background) // 출력방향전환(방향전환기호갯수, 명령어, 벡그라운드유무) { int monitor, status, i = 0; monitor = dup(1); // 표준출력장치를 나중에 다시 열어주기 위해 표준출력장치를 monitor변수에 임시로 넣어둠 close(1) ; for(i = 0; com[i] != NULL; i++); // 명령어가 몇개로 구분되었는지 카운터 => 파일명 추출 위해 switch(option) // 방향전환 기호에 따라 갱신할지 추가할지 결정 { case 1: // 없으면 새로 생성하고, 있으면 기존의 있던걸 삭제하고 쓰기전용으로 새로만듬 open(com[i-1], O_WRONLY | O_CREAT | O_TRUNC); break; case 2: // 없으면 새로 생성하고, 있으면 그 내용에 새로운 내용을 추가 open(com[i-1], O_WRONLY | O_CREAT | O_APPEND); break; } com[i-1] = '\0'; //파일명을 지워줌 if(fork() == 0) // 자식프로세서를 생성해 명령어 실행 { execlp(com[0], buf, com[1], com[2], com[3], com[4], NULL); exit(0); } if(background == 0) wait(&status); close(1); // 열린 파일을 닫음 dup(monitor); // 표준출력장치를 다시 열어줌 } void File_Output(int option, char *com[5], int background) { int i, keyboard, status; keyboard = dup(0); // 나중에 표준입력장치를 다시 열어주기위해 표준입력장치를 keyboard변수에 임시로저장 close(0); // 표준출력장치를 닫아줌 for(i = 0; com[i] != NULL; i++); // 명령어가 몇개로 구분되었는지 카운터 => 파일명 추출 위해 open(com[i-1], O_RDONLY ); // 파일을 읽기 전용으로 염 com[i-1] = '\0'; // 명령어에서 파일명을 지워줌 if(fork() == 0) // 명령어 실행을 위한 자식 프로세서 생성 { execlp(com[0], buf, com[1], com[2], com[3], com[4], NULL); exit(0); } if(background == 0) wait(&status); close(0); // 파일을 닫아줌 dup(keyboard); } void Pipe(char *com[5], int background) // 파이프 구현 { int fds[2]; if(pipe(fds) < 0) { // 파이프 디스크립터를 얻음 perror("pipe"); exit(0); } if(fork()==0){ close(1); // 표준출력을 닫고, dup(fds[1]); // dup를 사용해 파이프의 쓰기 디스크립터인 fds[1]을 복사 close(fds[0]); close(fds[1]); execlp(com[0], com[0], NULL); exit(0); } if(fork()==0){ close(0); // 표준입력을 닫고, dup(fds[0]); // dup를 사용해 파이프의 쓰기 디스크립터인 fds[0]을 복사 close(fds[0]); close(fds[1]); execlp(com[1], com[1], NULL); exit(0); } close(fds[0]); close(fds[1]); while(wait(NULL)>0); } void Round_robin(int robin, char *com[5], int background) // 순차실행 구현 { int i, status; for(i = 0 ; i <= robin;i++) // 받은 명령어 만큼 순차 실행 { if(fork() == 0) { execlp(com[i],com[i], NULL); //입력한 명령 실행 exit(0); } if(background == 0) wait(&status); // 명령어에 백그라운드 기호가 있을경우 wait()를 두지않에 백그라운드로 실행 // 백그라운드가 아니면 부모프로세서가 자식프로세스 종료하기를 기다림 } } }