Signal & (Heredoc)
개요
이번에는 signal에 대해서 구현할 내용을 서술할 것입니다. 저는 과제를 해결할 때 이 부분이 가장 어려웠었습니다. signal과 terminal 관련 함수를 처음 접하기도 했고 아무리 찾아봐도 이 부분에 대해서 깊게 찾을 수 있는 정보가 없었습니다.
따라서 이 부분은 완벽하지 않습니다! 구현보다 과제에서 요구하는 signal의 동작에 중점을 둘 것이니, 참고에 주의하시길 바랍니다.
목표
In interactive mode:
상호작용 모드에서:
◦ ctrl-C displays a new prompt on a new line. →새 줄에 새 프롬프트를 표시.
◦ ctrl-D exits the shell. → 셸을 종료.
◦ ctrl-\ does nothing. → 아무 작업도 수행하지 않음.
적혀있는대로 보면 구현할 것이 3개인데, 사실 12개입니다. shell 상태, blocking 상태, heredoc 상태, 무한 루프 상태 ... 더 있을지 모르겠으나 제가 발견한 것은 그렇습니다.
자 이제 각각의 경우에 어떻게 동작할까요?
1. 쉘을 프롬프트 (커맨드 라인을 입력받는 대기 상황)
- ctrl-C displays a new prompt on a new line. →새 줄에 새 프롬프트를 표시. error code 1.
- ctrl-D exits the shell. → 셸을 종료. *buff에 데이터가 존재하면 동작하지 않음
- ctrl-\ does nothing. → 아무 작업도 수행하지 않음.
2. blocking (cat or grep) *buff에 데이터 존재 유무와 무관
- ctrl-C displays a new prompt on a new line. -> "^C" 출력 후 중지. error code 130.
- ctrl-D exits the shell. → EOF 입력을 종료.
- ctrl-\ does nothing. → "^\Quit: 3" 출력 후 중지. error code 131.
3. heredoc
- ctrl-C displays a new prompt on a new line. -> heredoc 중지. error code 1.
- ctrl-D exits the shell. → EOF 입력을 종료.
- ctrl-\ does nothing. → 아무 작업도 수행하지 않음.
4. 무한 루프 상태 (yes)
- ctrl-C displays a new prompt on a new line. -> "^C" 출력 후 중지. error code 130.
- ctrl-D exits the shell. → 아무 작업도 수행하지 않음.
- ctrl-\ does nothing. → "^\Quit: 3" 출력 후 중지. error code 131.
4번의 무한 루프 상태는 평가지에 없는 내용입니다. 따라서 구현하지 않아도 문제 없고, cat에서 signal을 잘 구현했다면 알아서 되는 케이스 입니다. 클러스터 맥에서는 "ctrl + D" 경우만 차이가 존재하고 나머지는 동일합니다. 입력을 받는 명령어가 아니다보니, 당연하겠지만요. 분명한 것은 둘이 다른 상태라는 것입니다. blocking 상태와 heredoc을 고려했는데 무한 루프 상태를 고려하지 않았다면 재고해 보시기 바랍니다.
Signal 관련 내용은 아니지만, Heredoc이 언급될 부분이 이 챕터 뿐이라 여기서 설명하도록 하겠습니다.
Heredoc 어디까지 구현해야 하는가?
Heredoc이 환경 변수를 확장한다는 사실을 알고 계셨나요? 네, 저도 당했습니다 매우 어지러웠습니다.

다음은 어떤가요?
export a=stop이 적용된 상태라고 생각합시다.
<< $a cat
이 heredoc은 어떻게 입력을 종료할까요?
1. $a를 입력하면 종료된다.
2. stop을 입력하면 종료된다.
3. 둘다 된다.
정답에 따라 여러분의 구현이 매우 골치아파 질 수 있습니다.

"정말 다행입니다." 라고 끝내시면 안됩니다. 커맨드 라인의 환경 변수 해석 시점보다 heredoc이 먼저 진행된다는 것을 반드시 알고 갑시다.
--------------추가--------------
Heredoc의 Limiter가 quote로 둘러싸여 있다면 환경변수를 해석하지 않는다는 것을 알고 계셨나요? 저는 안당했습니다. 그래도 어지럽습니다.

Heredoc은 입력은 get_next_line? readline?
아마 Pipex 과제에서 get_next_line을 사용했기 때문에, 의심 없이 get_next_line을 선택할 것입니다. 다만 문제가 있습니다. 실제로 버퍼를 읽어들이는 부분 readline 함수와 read 함수(get_next_line)가 SIGQUIT에서 차이를 보였습니다. 분명 SIGQUIT는 heredoc 상태에서 무시하도록 설정했음에도 다음과 같은 문제가 발생합니다.

입력 버퍼를 채운 다음 "ctrl + \"를 입력한 뒤 백스페이스로 버퍼를 지우려고 하면 버퍼가 굳어버립니다. bash에서는 그러지 않는데, get_next_line에서 이런 문제가 발생합니다. 그래서 저는 readline을 선택했습니다. 그런데 이것도 문제가 있습니다.

heredoc을 "ctrl + D"로 종료하면, 프롬프트 뒤에 예쁘게 bash가 붙습니다. 하지만 readline을 사용하면 프롬프트에서 줄 바꿈이 한 번 일어나고 minishell이 나타납니다.
get_next_line을 사용하면 굳이 처리해 주지 않아도 bash와 동일하게 되지만, SIGQUIT에서 버퍼가 굳는 상황이 발생하고... readline을 쓰자니 복잡한 터미널을 조작해야 할 상황이 생겨버립니다. 터미널로 입력이 들어가지도 않은 버퍼의 크기를 잴 수 있는지조차도 모르겠습니다.
따라서, 버퍼가 굳는 것이 더 큰 문제로 생각하여 get_next_line을 사용하지 않고 readline을 사용하였습니다. 결국 터미널 관련하여 입력 버퍼를 추적하는 것을 알아내지 못해 해당 결과는 bash와 동일하게 나타내지 못했습니다.
마치며
이렇게 mandatory 정리가 끝났습니다. mandatory 관련해서 생각해 볼 내용들은 전부 이야기 한 것 같습니다. 명령어들의 구현은 여기에서 설명을 했지만, 동작 방식은 보너스의 "&&, ||, ()"들과 같이 묶어 설명하는 편이 좋겠습니다.
보너스도 글이 길어질 것 같습니다. 다음에 뵙겠습니다.
'42Seoul' 카테고리의 다른 글
Philosophers - Mandatory (1) | 2023.12.17 |
---|---|
Minishell - Bonus (1) | 2023.12.15 |
Minishell - Built-in (1) | 2023.11.09 |
Minishell - LCRS hierarchy & BNF production rules (0) | 2023.11.06 |
Minishell (0) | 2023.11.06 |
댓글