bash
다음과 같이 호출될 때프로세스 번호 1커널 옵션을 통해 직접 init=/bin/bash --login
메시지를 표시하기 전에 다음과 같은 내용을 표시합니다.
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
그리고키보드 생성 신호(예: ^Z, ^C, ^)가 작동하지 않습니다..
이 문제를 해결하기 위해 다음과 같은 간단한 프로그램 init1.c
(예: 단순화됨 sulogin
)을 작성했습니다.
/* init1.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
char *options[] = {"--login", NULL};
int tty_fd = -1;
printf("\n----- Bash Init 1 -----\n\n");
/* Make bash as session leader. */
if (setsid() == -1)
{
fprintf(stderr, "%s : %d : %s\n", "setsid()", __LINE__, strerror(errno));
exit(EXIT_FAILURE);
}
/* Make /dev/tty1 as controlling terminal of Bash. */
tty_fd = open("/dev/tty1", O_RDWR);
if (tty_fd == -1)
{
fprintf(stderr, "%s : %d : %s\n", "open()", __LINE__, strerror(errno));
exit(EXIT_FAILURE);
}
/* Re-connect stdin, stdout, stderr to the new tty. */
dup2(tty_fd, STDIN_FILENO);
dup2(tty_fd, STDOUT_FILENO);
dup2(tty_fd, STDERR_FILENO);
close(tty_fd);
execv("/bin/bash", options);
}
다음과 같이 컴파일한 init1
다음 다음과 같이 호출합니다.프로세스 번호 1(즉, Bash는 다음과 같이 실행됩니다.프로세스 번호 1), 이전 오류 메시지가 사라지고 일부 신호(예: Ctrl-C, Ctrl-\)는 작동하지만 작업 제어 신호(예: Ctrl-Z)는 여전히 작동하지 않습니다(예기치 않게).
따라서 작업 제어 신호가 작동하도록 하기 위해 위 코드를 init2.c
다음과 같이 수정했습니다 fork()
.
/* init2.c */
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
char *options[] = {"--login", NULL};
pid_t pid = -1;
int tty_fd = -1;
printf("\n----- Bash Init 2 -----\n\n");
pid = fork();
if (pid < 0)
{
fprintf(stderr, "%s : %d : %s\n", "fork()", __LINE__, strerror(errno));
exit(EXIT_FAILURE);
}
/* Parent. */
if (pid > 0)
{
/* Wait for its child, otherwise all processes would be killed ! */
while (wait(NULL) > 0)
;
exit(EXIT_SUCCESS);
}
/* Child. */
if (setsid() == -1)
{
fprintf(stderr, "%s : %d : %s\n", "setsid()", __LINE__, strerror(errno));
exit(EXIT_FAILURE);
}
/* Make /dev/tty1 as controlling terminal of Bash. */
tty_fd = open("/dev/tty1", O_RDWR);
if (tty_fd == -1)
{
fprintf(stderr, "%s : %d : %s\n", "open()", __LINE__, strerror(errno));
exit(EXIT_FAILURE);
}
/* Re-connect stdin, stdout, stderr to the new tty. */
dup2(tty_fd, STDIN_FILENO);
dup2(tty_fd, STDOUT_FILENO);
dup2(tty_fd, STDERR_FILENO);
close(tty_fd);
execv("/bin/bash", options);
}
다음과 같이 컴파일하고 init2
다음과 같이 호출합니다.프로세스 번호 1(즉, Bash는 1을 제외한 모든 PID로 실행됩니다.) 이번에는 작업 제어 신호가 작동합니다!
하지만 왜 작업 제어 신호가 있는지 이해가 되지 않습니다 init2
(Bash는 그렇지 않습니다).프로세스 번호 1) 그러나 그렇지 않습니다 init1
(Bash는프로세스 번호 1), Bash가 PID 1로 실행될 때 포그라운드 작업이 작업 제어 신호를 무시하는 이유는 무엇입니까? 뭔가 특별한 게 있는 것 같아요프로세스 번호 1.
고쳐 쓰다:
아주 간단한 껍질을 찾았어요뒤죽박죽작업 제어도 github에서 구현되며 단 949줄입니다! init1 및 init2를 사용하여 이 쉘을 실행할 때 동일한 문제가 발생합니다! (덕분에 문제를 해결하기 위해 복잡한 bash 소스 코드를 읽을 필요가 없었습니다. Orz) 문제는 SIGTSTP(^Z)가 도착할 때 즉시 반환되지 않는 waitpid()에 있습니다. 따라서 이 문제는 bash뿐만 아니라 작업 제어를 구현하는 셸에도 관련이 있습니다. 그러나 쉘이 PID 1로 실행 중일 때 SIGTSTP가 도착하면 waitpid()가 반환되지 않는 이유를 이해할 수 없습니다.