나만의 간단한 UNIX shell 만들기

카테고리 없음

2019. 3. 17. 17:58

01. 서론

 

몇가지 리눅스 명령을 실행할 수 있는 나만의 간단한 shell을 만들어 보았다.

 

프롬프트에 시간, 호스트이름, 유저이름 및 디렉토리 이름을 나타내기 위한 몇가지 함수들과

프로세스를 생성하기 위한 fork(), 생성한 프로세스에서 프로그램을 실행하기 위한 execlp(), 그리고 지정한 프로세스가 멈출때까지 기다리는 waitpid() 함수를 사용하였다.

 

02. 코드

 

* myshell.c

#include <stdio.h> // printf()
#include <string.h> // perror(), strlen()
#include <unistd.h> // fork()
#include <sys/wait.h> // waitpid()
#include <time.h> // time(), localtime(), asctime()
#include <stdlib.h> // exit()
#define MAX 255

// print out prompt and get command string from user
void *prompt(char cBuf[]) {
	time_t rawtime;
	struct tm *timeinfo;
	char hBuf[MAX], uBuf[MAX], dBuf[MAX];
	char *now;
	void *ret;

	time(&rawtime); // passed time from Jan 1, 1970
	timeinfo = localtime(&rawtime); // translate rawtime to struct tm type
	now = asctime(timeinfo); // convert to string format

	now[strlen(now)-1] = 0; // convert '\n' to null charactor

	gethostname(hBuf, MAX); // save hostname to hBuf
	getlogin_r(uBuf, MAX); // save username to uBuf
	getcwd(dBuf, MAX); // save directoryname to dBuf

	printf("[%s]%s@%s(%s)$ ", now, hBuf, uBuf, dBuf); // print out prompt

	// get command string and save return value to ret pointer variable.
	// if fgets fails, it returns NULL
	ret = fgets(cBuf, MAX, stdin);

	// convert '\n' to null charactor so that
	// it can be recognized as string
	if(cBuf[strlen(cBuf)-1] == '\n')
		cBuf[strlen(cBuf)-1] = 0;

	return ret;
}

int main()
{
	char cBuf[MAX];
	char *arg;
	pid_t pid;
	int status;

	while(prompt(cBuf)) { // while successful input

		/*
			fork() is called once, returned twice.
			one for parent(return value = pid of child process),
			the other one for child(return value = 0)
		*/

		// pid should be integer greater than or equeal to zero.
		if((pid = fork()) < 0) {
			perror("fork error");
		}
		else if(pid == 0) { // children case

			// split command input string
			// strtok() changes character which is same with delimeter
			// to null character and returns pointer to first character of
			// seperated string.
			strtok(cBuf, " ");
			arg = strtok(NULL, " "); // return null if no more possible seperation

				

			// execlp() need program name for first parameter,
			// argument list until (char*) 0 for more than second parameter,
			// and execute that program.
			if(arg == NULL) // no argument
				execlp(cBuf, cBuf, (char*) 0);
			else { // one argument
				if(strcmp(cBuf, "cd") == 0) {
					chdir(arg);
					_exit(0);
				}
				else
					execlp(cBuf, cBuf, arg, (char*) 0);
			}
			perror("couldn't execute");
		}

		// wait until spawned process finishes.
		waitpid(pid, &status, 0);
	}

	// termination when fgets returns null.
	exit(0);
}

 

03. 실행

devsophia@devsophia-ideapad:~/practice/unixass01$ gcc myshell.c -o myshell
devsophia@devsophia-ideapad:~/practice/unixass01$ ./myshell
[Sun Mar 17 17:45:36 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ ls -al
합계 28
drwxr-xr-x 2 devsophia devsophia  4096  3월 17 17:45 .
drwxr-xr-x 4 devsophia devsophia  4096  3월 17 17:28 ..
-rwxr-xr-x 1 devsophia devsophia 13128  3월 17 17:45 myshell
-rw-r--r-- 1 devsophia devsophia  2336  3월 17 17:23 myshell.c
[Sun Mar 17 17:45:38 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ touch test.c
[Sun Mar 17 17:45:43 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ vim test.c
[Sun Mar 17 17:46:07 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ cat test.c
#include 
int main()
{
	printf("hello world!\n");
	return 0;
}
[Sun Mar 17 17:46:10 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ mkdir dir
[Sun Mar 17 17:46:16 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ ls -al
합계 36
drwxr-xr-x 3 devsophia devsophia  4096  3월 17 17:46 .
drwxr-xr-x 4 devsophia devsophia  4096  3월 17 17:28 ..
drwxr-xr-x 2 devsophia devsophia  4096  3월 17 17:46 dir
-rwxr-xr-x 1 devsophia devsophia 13128  3월 17 17:45 myshell
-rw-r--r-- 1 devsophia devsophia  2336  3월 17 17:23 myshell.c
-rw-r--r-- 1 devsophia devsophia    72  3월 17 17:46 test.c
[Sun Mar 17 17:46:19 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ pwd
/home/devsophia/practice/unixass01
[Sun Mar 17 17:46:27 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ gcc test.c
[Sun Mar 17 17:46:30 2019]devsophia-ideapad@devsophia(/home/devsophia/practice/unixass01)$ ./a.out
hello world!

 

04. 참조

 

Advanced Programming in the UNIX Environment, 리처드 스티븐스 및 스티븐 레이고 지음, 류광 옮김, 퍼스트북