如果我将 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.c
4501行的表达式上:
(t = tcgetpgrp (shell_tty)) == -1
错误值为ENOTTY
,表示调用进程没有控制终端。
为什么 Bash 在作为 init 调用时没有控制终端?
答案1
这控制终端的bash
是由 准备(打开)的login
。因此,如果bash
直接调用 initskiing login
,则会抛出上面的问题,因为控制终端在处理信号方面起着特殊的作用。
根据源代码登录.c(中util-linux
),调用过程bash
大致login
如下:
main() 调用 fork_session()
/* * Detach the controlling terminal, fork, and create a new session * and reinitialize syslog stuff. */ fork_session(&cxt);
fork 一个新进程。(在
fork_session()
功能上)child_pid = fork();
使新进程成为会话领导者。 为了获得控制终端,该进程必须先成为会话领导者。 (在
fork_session()
功能上)/* start new session */ setsid();
获取会话领导者的控制 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"));
在新进程中执行登录 shell。(返回
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);
更多关于概念的链接控制终端: