리눅스 커널 내부구조 10장 #1 쉘 구현

문연수·2021년 11월 12일
0

iamroot (Linux Internal)

목록 보기
14/24

1. 소스 코드

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/wait.h>

typedef bool command_func(int argc, char *argv[]);

struct command {
	char *name;
	char *desc;
	command_func *func;
};

command_func command_cd, command_exit, command_help;

struct command builtin_commnads [] = {
	{ "cd",		"change directory",	command_cd },
	{ "exit",	"exit this shell",	command_exit },
	{ "quit",	"quit tihs shell",	command_exit },
	{ "help",	"show this help",	command_help },
	{ "?",		"show this help",	command_help }
};

const int builtin_commnads_size =   sizeof(builtin_commnads) 
				  / sizeof(struct command);

bool command_cd(int argc, char *argv[])
{
	if (argc == 1) {
		chdir(getenv("HOME"));
	} else if (argc == 2) {
		if (chdir(argv[1]))
			printf("No directory\n");
	} else printf("USAGE: cd [dir]\n");

	return true;
}

bool command_exit(int argc, char *argv[])
{
	return false;
}

bool command_help(int argc, char *argv[])
{
	for (int i = 0; i < builtin_commnads_size; i++)
		printf("%-10s: %s\n", builtin_commnads[i].name,
				      builtin_commnads[i].desc);

	return true;
}

int tokenize(char *buf, char *delims, char *tokens[], int maxTokens)
{
	int count = 0;
	char *token;

	token = strtok(buf, delims);
	while (token != NULL && count < maxTokens) {
		tokens[count] = token;
		count++;
		token = strtok(NULL, delims);
	}

	tokens[count] = NULL;

	return count;
}

bool run(char *line)
{
	const char delims[] = " \r\n\t";
	char *tokens[128];
	int token_count;
	int status;
	pid_t child;

	token_count = tokenize(line, (char *) delims,
			       tokens, sizeof(tokens) / sizeof(char *));
	if (token_count == 0)
		return true;

	for (int i = 0; i < builtin_commnads_size; i++) {
		if (strcmp(builtin_commnads[i].name, tokens[0]) == 0)
			return builtin_commnads[i].func(token_count, tokens);
	}

	child = fork();
	if (child == 0) {
		execvp(tokens[0], tokens);
		printf("No such file\n");
	} else if (child < 0) {
		printf("Failed to fork()\n");
		exit(EXIT_FAILURE);
	} else wait(&status);

	return true;
}

int main(void)
{
	char line[1024];

	while (true) {
		printf("%s $ ", get_current_dir_name());
		fgets(line, sizeof(line) - 1, stdin);
		if (run(line) == false)
			break;
	}

	return 0;
}

2. 코드 해석

크게 어려운 내용은 없고, run() 함수에 핵심적인 코드가 담겨있다. shell 프로그램이 입력받은 명령어를 확인하고, 해당 명령어가 builtin_commands 경우 미리 정의된 동작을 실행, 존재하지 않는 명령어의 경우 execvp() 함수를 통해 실행한다.
execvp 함수의 첫 번째 인자로 전달된 filename 을 찾지 못한다면 PATH 환경변수를 조회하여 프로그램을 실행하므로 shell 프로그램과 큰 차이없이 동작하게 된다.

3. 프로그램 실행

출처

[책] 리눅스 커널 내부구조 (백승제, 최종무 저)
[책] 유닉스 고급 프로그래밍 3판 (리처드 스티븐스, 스티븐스 레이고 지음, 류광 옮김)

profile
2000.11.30

0개의 댓글