init로 호출된 경우 ^C를 intr 신호에 bash 매핑할 수 없는 이유는 무엇입니까?

init로 호출된 경우 ^C를 intr 신호에 bash 매핑할 수 없는 이유는 무엇입니까?

bash를 첫 번째 호출 프로세스(즉, init)로 설정하면 결과적으로 다음이 표시됩니다.

init: cannot set terminal process group (-1): Inappropriate ioctl for device
init: no job control in this shell

그리고 어떤 신호(예: ^C, ^Z)도 작동하지 않습니다.

bash-5.1.12의 소스 코드를 읽으면 문제는 job.c4501행의 표현식에 있습니다.

(t = tcgetpgrp (shell_tty)) == -1

오류 값은 ENOTTY호출 프로세스에 제어 터미널이 없음을 나타내는 입니다.

init로 호출할 때 Bash에 제어 터미널이 없는 이유는 무엇입니까?

답변1

이것제어 터미널bash준비(개봉) 되었습니다 login. 따라서 bashinitskiing을 직접 호출 하면 login제어 터미널이 신호 처리에 특별한 역할을 하기 때문에 위의 문제가 발생합니다.

소스코드에 따르면login.c(중간 util-linux) 호출 프로세스 bash는 대략 login다음과 같습니다.

  1. main()은 fork_session()을 호출합니다.

    /*
     * Detach the controlling terminal, fork, and create a new session
     * and reinitialize syslog stuff.
     */
    fork_session(&cxt);
    
  2. 새로운 프로세스를 포크합니다.( fork_session()기능적으로)

    child_pid = fork();
    
  3. 새 프로세스를 세션 리더로 만듭니다. 터미널 제어권을 얻으려면 먼저 프로세스가 세션 리더가 되어야 합니다. ( fork_session()기능적으로)

    /* start new session */
    setsid();
    
  4. 세션 리더의 제어 tty를 가져옵니다.open세션 리더는 tty를 통해 제어 터미널을 얻습니다. ( fork_session()기능적으로)

    /* make sure we have a controlling tty */
    open_tty(cxt->tty_path);
    openlog("login", LOG_ODELAY, LOG_AUTHPRIV); /* reopen */
    
    /*
     * TIOCSCTTY: steal tty from other process group.
     */
    if (ioctl(0, TIOCSCTTY, 1))
        syslog(LOG_ERR, _("TIOCSCTTY failed: %m"));
    
  5. 새 프로세스에서 로그인 셸을 실행합니다.(반품 main())

    /* if the shell field has a space: treat it like a shell script */
    if (strchr(pwd->pw_shell, ' ')) {
       char *buff;
    
       xasprintf(&buff, "exec %s", pwd->pw_shell);
       child_argv[child_argc++] = "/bin/sh";
       child_argv[child_argc++] = "-sh";
       child_argv[child_argc++] = "-c";
       child_argv[child_argc++] = buff;
    } else {
       char tbuf[PATH_MAX + 2], *p;
    
       tbuf[0] = '-';
       xstrncpy(tbuf + 1, ((p = strrchr(pwd->pw_shell, '/')) ?
                   p + 1 : pwd->pw_shell), sizeof(tbuf) - 1);
    
       child_argv[child_argc++] = pwd->pw_shell;
       child_argv[child_argc++] = xstrdup(tbuf);
    }
    
    child_argv[child_argc++] = NULL;
    
    /* http://www.linux-pam.org/Linux-PAM-html/adg-interface-by-app-expected.html#adg-pam_end */
    (void) pam_end(cxt.pamh, PAM_SUCCESS|PAM_DATA_SILENT);
    
    execvp(child_argv[0], child_argv + 1);
    

개념에 대한 추가 링크제어 터미널:

관련 정보