Skip to content
justinjeong5 edited this page Oct 25, 2020 · 1 revision

myshell

myshell ver3.0

1.프로젝트 개요

1.1 목표

유닉스의 쉘은 유닉스 운영체제와 유닉스 계통의 시스템을 위한 사용자 인터페이스이다. 쉘을 통해 사용자는 시스템을 원하는 대로 명령하고 제어할 수 있다. 명령과 제어는 커널과 사용자가 소통하기 위해 만들어진 system call을 이용하여 수행된다

그림1

위 그림의 예를 들어 설명하면 커널로 들어가기 위해서는 system call이 필요하다. 유닉스 교재(UNIX 시스템 프로그래밍 Second Edition, KEITH HAVILAND외 2명 저, 홍릉과학출판사)에 따르면 system call을 kernel로 들어가기 위한 “여권(passport)”에 비유하고 잇다. 커널은 항상 메모리에 존재하는 하나의 소프트웨어로 UNIX 시스템의 프로세스 scheduling과 입출력 제어를 다룬다. 본질적으로 kernel은 UNIX에서 운영체제로 인정되는 부분이다. 따라서 모든 사용자 프로세스와 파일 시스템 접근들은 kernel에 의해 자원을 할당 받고, 감독 되고, 제어된다.

위와 같은 특징을 가지는 UNIX의 운영체제, 즉 kernel과 사용자가 “소통”하기 위한 방법이 system call이며, 이 system call을 사용자가 편하게 쓸 수 있도록 해주는 여러 방법 중 하나가 shell이다. 이미 shell에는 bash, csh, ksh, sh, tcsh등의 여러가지가 있다. 이번 프로젝트는 직접 shell을 만들고 필요한 기능을 직접 만들어보면서 system call과 UNIX의 동작에 대해서 자세하게 이해해 보는 것이 프로젝트 Myshell의 목표이다.

1.2 기능

1.2.1 cd(change directory)

유닉스 파일 시스템은 direcrory와 File을 계층적인 트리 구조로 나타낸다. 파일 이름들의 창고와 같은 역할을 하는 directory는 중첩 될 수 있으며 다른 대부분의 운영체제에서 이용하고 있는 개념이다. 프로세스는 현재 작업 중인 directory라는 개념을 가지고 있는데 이 현재 작업중인 directory(current working directory)를 바꾸는 명령이다.

1.2.2 exit

exit는 프로세스를 종료시키는 명령이다. 종료를 하려는 시점에서 자식프로세스가 있는지, 부모프로세스가 있는지 등의 상황을 고려하여 프로그램을 작성해야 좀비 프로세스가 system의 자원을 쓸데 없이 점유하는 상황을 피할 수 있다

1.2.3 background 실행

1.2.2에서 언급한 좀비 프로세스의 개념에는 고아프로세스라는 개념이 있다. 이 개념은 부모프로세스가 자식프로세스를 만들고 난 뒤, 자식 프로세스의 종료 상황을 부모 프로세스가 인지하지 못하여 자식이 종료되지 않는 상황을 이용하는 것이다. 이 개념을 이용하면 부모 프로세스와 상관없이 background에서 자식프로세스가 실행하는 “background 실행”을 구현할 수 있다.

1.2.4 시그널 처리

일반적으로 쉘은 ^C(SIGINT), ^ (SIGQUIT)의 명령을 받아도 종료되지 않는다. 이런 기능을 myshell에도 추가하려면 ^C(SIGINT), ^ (SIGQUIT)에 대한 signal을 받으면 무시하도록 구현해야한다. Signal.h 헤더파일에는 해당 동작을 쉽게 쓸 수 있도록 system call을 제공한다. 이를 이용하면 ^C(SIGINT), ^ (SIGQUIT)뿐만 아니라 다른 여러 수십가지 시그널에 대한 핸들링 동작을 할 수 있다.

1.2.5 Redirection

쉘에서 표준 출력으로 출력을 하면 일반적으로 모니터에 출력하고, 표준 입력으로 입력하면 키보드로 입력을 받는다. 이런 입력 방식은 개발자가 원하는 대로 변경 할 수 있는데, 출력을 모니터가 아닌 다른 파일로, 또는 입력을 키보드가 아닌 파일로부터 입력을 받으면 이것을 입출력 redirection이라고 한다.

1.2.6 Pipe

각각의 프로세스는 입력을 받아 출력물을 만들어 낸다. 어느 프로세스의 출력물이 다른 어느 하나의 프로세스의 입력으로 사용된다면 바로 출력과 입력을 이어주는 기능이 pipe이다. 이를 이용하면 서로 다른 여러 프로세스를 마치 하나인 것처럼 유기적으로 동작하게 할 수 있어서 매우 강력한 기능이다. 파이프는 | 기호를 사용하며 실행파일과 실행파일을 이어주는 역할을 한다.

1.3 한계와 문제점

이번 과제에 해당하는 기능의 구현은 완성했다. 다만 프로그램이 최적의 상황을 유지하며 동작하고 있는지에 대한 확신은 부족하다. 구체적인 예를 들면 백그라운드에서 실행되는 프로세스를 만드는 방법으로 고아 프로세스를 만드는 개념을 이용하였다. 이 부분에서 init 프로세스로 입양된 자식 프로세스가 exec를 실시하면 프로그램의 실행 내용을 터미널 프롬프트에 출력하는 예외 상황이 발생했다. 이를 막기 위해서 자식 프로세스의 표준 입출력에 해당하는 0, 1, 2번 파일 디스크립터를 close하는 방식을 이용했다. Test Case를 실행 했을 때는 원하는 결과가 나왔지만 실행해보지 않은 test case가 모두 실행 될지는 확신이 없다. 프로젝트 기능