ZBLOG

linux启动进程1的时候是如何做到类似ioctl(TIOCSCTTY)的操作的

在 Linux 系统启动过程中,进程 1(init/systemd)的控制终端(/dev/console)的绑定是由内核在内核空间自动完成的,而无需用户空间显式调用 ioctl(TIOCSCTTY)。这一过程涉及内核初始化和进程创建的底层机制。以下是详细分析:


1. 内核启动阶段的控制台初始化

  • 控制台设备注册
    内核在启动时根据以下配置确定主控终端:
    • 通过命令行参数(如 console=ttyS0console=tty0)指定控制台设备。
    • 默认使用 /dev/console 作为系统的主控终端(虚拟终端或串口)。
  • 内核内部关联
    控制台设备在内核中通过 struct console 结构体注册,例如:
    
    // 示例:内核代码中的控制台驱动注册
    register_console(&serial_console); // 注册串口控制台
    

2. 进程1的标准输入/输出与控制终端的绑定

当内核启动第一个用户空间进程(init/systemd)时,会通过以下步骤自动关联控制终端:

(1) 打开标准文件描述符(stdin/stdout/stderr)

  • 内核调用链
    kernel_execve()do_execve()open_stdio_files() (位于 fs/exec.c)中,内核会为进程1打开标准输入、输出、错误文件描述符(fd 0,1,2),并直接指向 /dev/console

  • 关键代码逻辑

    // fs/exec.c (简化)
    static int open_stdio_files(struct linux_binprm *bprm) {
      struct file *f;
      int fd;
    
    
      // stdin (fd=0)
      f = filp_open("/dev/console", O_RDWR, 0);
      fd_install(0, f);
    
    
      // stdout/stderr (fd=1,2)
      f = filp_open("/dev/console", O_WRONLY, 0);
      fd_install(1, f);
      fd_install(2, f);
      return 0;
    }
    

    此时,进程1的 fd 0,1,2 已直接绑定到 /dev/console

**(2) 设置会话和控制终端**

  • 任务属性继承
    进程1的 task_struct (进程描述符)中的控制终端字段 (tty)由父进程(即内核线程)继承而来。由于内核自身没有用户态的控制终端,因此新创建的进程1会获得一个新的会话(session)。
  • 隐式会话创建
    在 Linux Kernel v4.11+ ,如果未显式调用 setsid(),则新进程会自动成为新会话的首进程(session leader),并可能关联到当前有效的控制终端。

3.为什么不需要显式调用 ioctl(TIOCSCTTY)?

  • 用户空间的 ioctl(TIOCSCTTY)
    该操作是用户空间程序主动请求将某个 tty设备设置为自己的控制终端的接口。但进程1的情况不同:
    • /dev/console已在内核空间被直接绑定到 fd 0,1,2
    • 无“抢占”需求:普通程序需要通过 TIOCSCTTY “窃取”终端的控制权(例如登录shell接管终端),而进程1是首个用户态进程,无需竞争。
  • 历史行为兼容性
    早期 Unix系统中,init进程的控制终端由内核硬编码关联;Linux继承了这一设计。

4.验证方法

(a)查看 init/systemd的文件描述符

ls -l /proc/1/fd/{0,1,2} 
#若输出指向/dev/pts/N或/dev/ttyN,则表示实际绑定的终端设备。

(b)检查 init的 tty字段

ps -p 1 -o tty
#若显示 "?" ,表示 systemd可能已关闭与控制终端的直接关联。

©跟踪系统调用

理论上可以尝试用strace观察早期启动过程:

strace -o init.log /sbin/init 

但实际场景中很难捕获到真正的“第一个”init调用。


5.特殊情况与例外

  • 嵌入式系统定制化:
    某些裁剪过的嵌入式Linux可能在initramfs阶段手动操作 /dev/console,但这属于非标准行为。
  • 容器环境:
    容器内的 PID=1通常没有真实物理终端的访问权限。

总结

Linux内核对第一个用户态进程的处理是特殊的:

步骤 说明
硬件初始化 根据命令行参数配置 /dev/console.
创建 init 通过 kernel_execve()加载可执行文件.
自动分配 stdio fd=0,1,2强制绑定到 /dev/console
隐式会话管理 成为 session leader

整个过程完全由内完成——这是为何你找不到显式的 ioctl(TIOCSCTTY).


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=8224

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?