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, 리처드 스티븐스 및 스티븐 레이고 지음, 류광 옮김, 퍼스트북