시스템 관련 수업을 들으면서, 미니쉘 만들기 실습을 진행했다.
이전 과제에서 기본 미니쉘을 제작했고, 이번 과제에서는 리다이렉션과 파이프를 적용했다.
난이도를 낮추어 한 줄에 하나의 IPC만 허용하였다.
선배님의 과제와 인터넷을 참고하여 진행하였는데... 이전 과제를 최대한 변형하지 않고 진행하려고 하니 코드가 아주 엉망이 됐다ㅋㅋㅋㅋ...
하면서 너무너무 거슬렸지만 제출이 우선이라서 그냥 패스 ㅎㅎ..
Pipe
// pipe cmd function
void ex_launchPipe(char **args, char **argsPipe)
{
int pipefd[2];
pid_t pid1, pid2;
//pipe
if (pipe(pipefd) < 0)
{
printf("\nPipe could not be initialized");
return;
}
pid1 = fork();
if (pid1 == 0)
{
// child 1
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]);
close(pipefd[1]);
if (execvp(args[0], args) == -1)
{
perror("caanot execute: child 1");
exit(0);
}
}
else
{
// parent
pid2 = fork();
if (pid2 == 0)
{
// child 2
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[1]);
close(pipefd[0]);
if (execvp(argsPipe[0], argsPipe) == -1)
{
perror("caanot execute");
exit(0);
}
}
else
{
close(pipefd[1]);
wait(NULL);
wait(NULL);
}
}
}
위 코드는 단순하게 파이프 처리하는 함수이다. 다른 main함수, 입출력 함수는 뺐다. 이미 구글에 자료도 많고 우선 내 코드는 너무 더럽고... 아래 긱포긱과 교안을 적당히 섞어 만들었다.
참고: https://www.geeksforgeeks.org/making-linux-shell-c/
Making your own Linux Shell in C - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
* error 발생 부분
-문제: 출력을 하고도 계속 입력을 받음.
다른 코드를 봐도 별 다른 게 없어서 나는 내 컴퓨터 문제인 줄 알았다ㅋㅋㅋ 그래서 그냥 제출을 했는데 우연찮게 나와 같은 문제를 겪고 있는 블로그를 발견했다!
-해결: 마지막 else{~~} 줄에서 close(pipefd[1]); 를 추가
출력 파이프(?)를 닫아주지 않아서 입력 파이프가 계속 도는 거라고 이해했다. 사실 파이프를 제대로 이해한 게 아니어서 맞는지는 모르겠지만 입력하니 바로 해결됐다. 구글 감사합니다!
참고: https://2pound2pound.tistory.com/104
[개발 일지] 2020년 2월 10일 - Shell(piping, dup2(), pipe())
int lsh_launch_pipe(char** args, char** argsPipe) { int pipefd[2]; pid_t p1, p2; if (pipe(pipefd) < 0) { fprintf(stderr, "Pipe could not be initialized"); return 0; } p1 = fork(); if (p1 < 0) { fpri..
2pound2pound.tistory.com
redirection
int ex_dealArg(char *line, char **args, char **argsPipe)
{
int redirectionFlag;
// Yes pipe
if (piped)
{
//파이프 처리 부분(생략함)
}
else
{
char *tptr;
if ((tptr = strchr(line, '>')) != NULL)
{
int i = 0;
char *ptr = strtok(line, " ");
while (ptr != NULL)
{
args[i++] = ptr;
if (tptr == ptr)
{
//리다이렉션 부분 기억 포인터
redirectionFlag = i;
args[i - 1] = NULL;
}
ptr = strtok(NULL, " ");
}
args[i] = NULL;
umask(0);
int tableNum = open(args[redirectionFlag], O_RDWR | O_CREAT, 0777);
char path[100];
sprintf(path, "/bin/%s", args[0]);
if (fork() == 0)
{
dup2(tableNum, STDOUT_FILENO);
execv(path, args);
}
else
{
wait(NULL);
}
}
else if ((tptr = strchr(line, '<')) != NULL)
{
int i = 0;
char *ptr = strtok(line, " ");
while (ptr != NULL)
{
args[i++] = ptr;
if (tptr == ptr)
{
redirectionFlag = i;
args[i - 1] = NULL;
}
ptr = strtok(NULL, " ");
}
args[i] = NULL;
umask(0);
int tableNum = open(args[redirectionFlag], O_RDWR | O_CREAT, 0777);
char path[100];
sprintf(path, "/bin/%s", args[0]);
if (fork() == 0)
{
dup2(tableNum, STDIN_FILENO);
execv(path, args);
}
else
{
wait(NULL);
}
}
else
{
//일반 cmd 처리 부분(생략함)
}
}
}
생각보다 리다이렉션 관련해서 구글링이 안 나와서 실망했음ㅎㅎ.. 위 코드는 매우 매우 대충 짠 코드입니다. 다른 코드들과 다르게 함수로 따로 빼지 않고 그냥 한 함수에서 다 처리해버렸음. 이걸 가장 마지막에 짠 코드여서 그런가 돌아가는 방식은 가장 맘에 드는데 밀린 과제가 많아서 그냥 패스했습니다.
결과만 잘 나오면 되는 거 아닐까...ㅎ
시스템은 저랑 안 맞는 거 같습니다.
'리눅스' 카테고리의 다른 글
[리눅스] 파이프와 리다이렉션의 차이 (0) | 2021.11.13 |
---|