열렬히.뛰기

exam04

école 42 > exam04

시험 시작

  • id / pwexam / exam
  • shell에 바로 examshell 이라고 치기
    • ./examshell 이라고 치면 실행이 안됨.
  • git init 치지 말아야 함! 중요!
  • rendu 폴더에서 git add . git commit -m git push 하기

문제

python
Assignment name  : microshell
Expected files   : *.c *.h
Allowed functions: malloc, free, write, close, fork, waitpid, signal, kill, exit, chdir, execve, dup, dup2, pipe, strcmp, strncmp
--------------------------------------------------------------------------------------

Write a program that will behave like executing a shell command
- The command line to execute will be the arguments of this program
- Executable's path will be absolute or relative but your program must not build a path (from the PATH variable for example)
- You must implement "|" and ";" like in bash
	- we will never try a "|" immediately followed or preceded by nothing or "|" or ";"
- Your program must implement the built-in command cd only with a path as argument (no '-' or without parameters)
	- if cd has the wrong number of argument your program should print in STDERR "error: cd: bad arguments" followed by a '\n'
	- if cd failed your program should print in STDERR "error: cd: cannot change directory to path_to_change" followed by a '\n' with path_to_change replaced by the argument to cd
	- a cd command will never be immediately followed or preceded by a "|"
- You don't need to manage any type of wildcards (*, ~ etc...)
- You don't need to manage environment variables ($BLA ...)
- If a system call, except execve and chdir, returns an error your program should immediatly print "error: fatal" in STDERR followed by a '\n' and the program should exit
- If execve failed you should print "error: cannot execute executable_that_failed" in STDERR followed by a '\n' with executable_that_failed replaced with the path of the failed executable (It should be the first argument of execve)
- Your program should be able to manage more than hundreds of "|" even if we limit the number of "open files" to less than 30.

for example this should work:
$>./microshell /bin/ls "|" /usr/bin/grep microshell ";" /bin/echo i love my microshell
microshell
i love my microshell
$>

Hints:
Don't forget to pass the environment variable to execve

Hints:
Do not leak file descriptors!

구현

헤더

c
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

main 함수

c
int main(int ac, char **av, char **env)
{
	int i = 0;
	int status = 0;

	if (ac > 1)
	{
		while (av[i] && av[++i])
		{
			av += i; // 포인터 av의 위치는 항상 |나 ;로 가게끔 설정
			i = 0;
			while (av[i] && strcmp(av[i], "|") && strcmp(av[i], ";"))
				i++;
			if (!strcmp(*av, "cd")) // 포인터 *av가 cd를 가리킬 경우
				status = cd(av, i);
			else if (i)
				status = exec(av, env, i);
		}
	}
	return (status);
}

cd 함수와 err 함수

c
int err(char *str)
{
	while (*str)
		write(2, str++, 1);
	return (1);
}

int cd(char **av, int i)
{
	if (i != 2)
		return (err("error: cd: bad arguments\n"));
	else if (chdir(av[1]) == -1)
		return (err("error: cd : cannot change directory to "), err(av[1]), err("\n"));
	return (0);
}

exec 함수

c
int exec(char **av, char **env, int i)
{
	int fd[2];
	int status;
	int has_pipe = av[i] && !strcmp(av[i], "|");

	if (has_pipe && pipe(fd) == -1)
		return (err("error: fatal\n"));
	
	int pid = fork();
	if (!pid)
	{
		av[i] = 0;
		if (has_pipe && (dup2(fd[1], 1) == -1 || close(fd[0]) == -1 || close(fd[1]) == -1))
			return (err("error: fatal\n"));
		execve(*av, av, env);
		return (err("error: cannot execute "), err(*av), err("\n"));
	}

	waitpid(pid, &status, 0);
	if (has_pipe && (dup2(fd[0], 0) == -1 || close(fd[0]) == -1 || close(fd[1]) == -1))
		return (err("error: fatal\n"));
	return (WIFEXITED(status) && WEXITSTATUS(status));
}

참고 사이트

github.com/pasqualerossi/42-School-Exam-Rank-04 github.com/JCluzet/42_EXAM
c
bash -c "$(curl https://grademe.fr)"