linux系统/sbin/init执行过程

本文详细解析了Linux系统的启动过程及用户登录机制,从内核启动到执行/sbin/init,再到用户通过getty和login程序登录系统的过程。同时介绍了如何在特定情况下绕过常规登录流程以解决sudo权限问题。

  对于linux的启动过程,之前一直都是研究到内核运行/sbin/init,启动第一个用户进程为止,因为这部分一直都是在内核态工作,所以对于学习内核还是有帮助的,当时/sbin/init之后的过程也需要明白,今天就总结一下。


   首先大体写一下内核从启动到执行/sbin/init的流程:

    head.S ===> start_kernel ===> rest_init ===> cpu_idle和内核线程init ===》init_post ===> /sbin/init

   

    而init执行后的大体流程是:

     init ===> fork出 getty 按照/etc/inittab 打开相应终端 ===》exec 执行 login验证用户和密码 根据/etc/passwd ===》密码正确,设置一些环境变量 设置主目录  exec执行bash

     getty login bash 是同一个进程

     在工作中之前碰到过一个问题就是客户机器正常进入控制台后sudo su不能获取超级用户权限,说not in sudoer。

     sudo su是使用普通用户密码来获取超级用户权限,但是并不是所有的普通用户都可以用sudo su来获取超级用户权限,具体的授权在/etc/sudoers中。也就是说我们在获取超级用户权限的时候用sudo su,这时系统回去sudoers中查看该申请用户是否在列表中,如果在则该用户获取超级用户权限,此后一段时间该用户则是超级用户权限,时间长短也是在/etc/sudoers中定义的

    这样分析也就是说客户机器上的这个用户没有在sudoers列表中,可以用adduser命令来添加到列表中,但是添加sudoers是需要超级用户权限的。。。这就形成了一个死循环!

   想到的解决办法是在内核启动是参数init=/bin/bash,这样内核启动后不是执行init,而是跳过init gettty login直接执行bash,这样的话没有执行login,系统也就没有启用任何一个用户,这是的控制台就是超级用户权限,这是使用命令adduser将用户添加到sudoer中就可以了,这样该普通用户就可以获取超级用户权限了


在登录到Linux系统中之后,你会发现(使用”top”或”ps –ax”命令)自己终端原来的getty进程已经找不到了。因为getty进程执行了login程序,被替换成了login进程,并且最后被替换成你的登录shell进程。

  当你在”login: “提示符下键入了你的用户名后,getty会读取用户名并且去执行login程序,也把用户名信息传给了它。因此getty进程被替换成了login进程。此时login进程会接着要求你输入口令。在口令检查通过后就会去执行/etc/passwd文件中对应你用户名项中记录的程序。通常这个程序是bash shell程序。因此原来的getty进程最终被替换成了bash进程,对应的这三个程序也就都具有相同的进程ID。

  当注销登录(log out)时,则该终端上的所有进程都会被终止(killed),包括登录shell进程bash。因此,对于在/etc/inittab文件中列出的getty程序,一旦其被替换执行的bash程序被终止或退出,init进程就会为对应终端重新创建一个getty进程。

  login程序则主要用于要求登录用户输入密码。根据用户输入的用户名,它从口令文件passwd中取得对应用户的登录项,然后调用getpass()以显示”password:”提示信息,读取用户键入的密码,然后使用加密算法对键入的密码进行加密处理,并与口令文件中该用户项中pw_passwd字段作比较。如果用户几次键入的密码均无效,则login程序会以出错码1退出执行,表示此次登录过程失败。此时父进程(进程init)的wait()会返回该退出进程的pid,因此会根据记录下来的信息再次创建一个子进程,并在该子进程中针对该终端设备再次执行agetty程序,重复上述过程。

  login程序也可以被用户在运行过程中在shell下当作一个命令执行。此时它可以被用随时从一个用户切换成另一个用户。如果执行时没有给出参数,则login就会显示输入用户名的提示信息。如果用户不是超级用户(root),并且/etc/目录下存在一个名为nologin的文件,那么该文件中的信息就会被显示出来,此次登录过程也随即被终止。

  如果在/etc/usertty文件中对该用户指定了特殊的访问限制,那么这些限制要求必须满足。如果是一个超级用户,那么所使用的登录tty设备必须是在/etc/securetty文件中指定的。

  在所有这些条件满足之后,login同样也会要求用户输入密码并对其进行检查。如果.hushlogin存在的话,login就会执行一个“安静”的登录过程,也即不检查是否有邮件,也不显示上次登录时间和motd文件中的信息。否则如果/var/log/lastlog文件存在的话,就会显示其中的最后登录时间。

  如果用户键入的密码正确,则login就会把当前工作目录(Currend Work Directory)修改成口令文件中指定的该用户的起始工作目录。并把对该终端设备的访问权限修改成用户读/写和组写,设置进程的组ID。然后利用所得到的信息初始化环境变量信息,例如起始目录(HOME=)、使用的shell程序(SHELL=)、用户名(USER=和LOGNAME=)和系统执行程序的默认路径序列(PATH=)。接着显示/etc/motd文件(message-of-the-day)中的文本信息,并检查并显示该用户是否有邮件的信息。最后login程序改变成登录用户的用户ID并执行口令文件中该用户项中指定的shell程序,如bash或csh等。

  如果口令文件/etc/passwd中该用户项中没有指定使用哪个shell程序,系统则会使用默认的/bin/sh程序。如果口令文件中也没有为该用户指定用户起始目录的话,系统就会使用默认的根目录/。有关login程序的一些执行选项和特殊访问限制的说明,请参见Linux系统中的在线手册页(man 8 login)。

  Shell程序是一个复杂的命令行解释程序,是当用户登录系统进行交互操作时执行的程序。它是用户与计算机进行交互操作的地方。它获取用户输入的信息,然后执行命令。用户可以在终端上向shell直接进行交互输入,也可以使用shell脚本文件向shell解释程序输入。在Linux系统中,目前常用的shell有:

  Bourne Again Shell,/bin/bash

  C shell,/bin/csh(或tcsh)

  BSD shell/bin/ash(或bsh)

  在登录过程中,系统(login)会从口令文件用户对应登录项的最后一个字段知道应该为用户执行哪个shell程序。

  shell程序中实现了一个具有流控制结构的语言,使用相当广泛。目前这些shell程序都朝着与IEEE POSIX 1003.2兼容的方向发展,因此它们各自虽然各自有自己的特点,但基本功能已经越来越相象。本书主要介绍bash的工作原理和实现机制,其它几种shell的实现机制与之类似。

  在登录过程中login开始执行shell时,所带参数argv[0]的第一个字符是’-’,表示该shell是作为一个登录shell被执行。此时该shell程序会根据该字符,执行某些与登录过程相应的操作。登录shell会首先从/etc/profile文件以及.profile文件(若存在的话)读取命令并执行。如果在进入shell时设置了ENV环境变量,或者在登录shell的.profile文件中设置了该变量,则shell下一步会从该变量命名的文件中读去命令并执行。因此用户应该把每次登录时都要执行的命令放在.profile文件中,而把每次运行shell都要执行的命令放在ENV变量指定的文件中。设置ENV环境变量的方法是把下列语句放在你起始目录的.profile文件中。

  ENV=$HOME/.anyfilename; export ENV

  在执行shell时,除了一些指定的可选项以外,如果还指定了命令行参数,则shell会把第一个参数看作是一个脚本文件名并执行其中的命令,而其余的参数则被看作是shell的位置参数($1、$2等)。否则shell程序将从其标准输入中读取命令。

  在执行shell程序时可以有很多选项,请参见Linux系统中的有关sh的在线手册页中的说明。


<think>我们面对的问题:用户修改了/sbin/init文件导致系统无法启动。 根据之前的对话,我们已经知道: - /sbin/init系统启动的第一个用户空间进程(PID=1),通常是一个指向实际初始化系统(如systemd或upstart)的软链接。 - 用户可能直接修改或覆盖了该文件,导致链接断裂,系统启动时找不到正确的初始化程序。 解决方案的核心步骤: 1. 进入救援环境(如Live CD或GRUB命令行) 2. 挂载原系统的根分区 3. 进入原系统的根环境(chroot) 4. 重建/sbin/init的软链接(指向正确的初始化程序,如/lib/systemd/systemd) 5. 检查并修复可能的相关问题 6. 重启系统 根据用户提供的引用[2]中提到:在GRUB命令行中检查发现/sbin/init不存在(原本是软链接,指向/lib/systemd/systemd),而/lib/systemd/systemd文件实际存在。因此,我们可以通过修改内核启动参数临时指定init程序为/lib/systemd/systemd来启动系统,然后再修复/sbin/init的链接。 这里提供两种方法: 方法一:通过GRUB临时修改内核启动参数,指定init程序路径(适用于可以进入GRUB命令行的情况) 方法二:使用Live CD/USB挂载系统分区,然后修复软链接(通用方法) 下面详细说明两种方法: ### 方法一:通过GRUB临时修改内核启动参数(仅用于临时启动进入系统,然后修复软链接) 1. **重启系统,进入GRUB菜单** - 在系统启动时,按住`Shift`(某些系统可能是`Esc`)键进入GRUB菜单。 2. **进入GRUB命令行** - 在GRUB菜单中,按`c`键进入命令行模式。 3. **手动引导系统** - 在GRUB命令行中,首先查看磁盘分区: ``` ls ``` 记录下你的根分区(例如`(hd0,msdos1)`)和/boot分区(如果有单独分区)。 - 加载内核和initramfs,并指定init程序: ```grub linux (hd0,msdos1)/boot/vmlinuz-xxx root=/dev/sda1 ro init=/lib/systemd/systemd ``` 其中: - `(hd0,msdos1)/boot/vmlinuz-xxx` 是你的内核文件路径(用`Tab`键补全) - `root=/dev/sda1` 指定根分区(根据实际情况修改,注意GRUB中的设备命名与Linux不同,这里用GRUB的设备名,而root参数用的是Linux设备名,通常GRUB的`(hd0,msdos1)`对应Linux的`/dev/sda1`) - `init=/lib/systemd/systemd` 指定init程序为`/lib/systemd/systemd`(代替原本的/sbin/init) - 加载initramfs(如果有): ```grub initrd (hd0,msdos1)/boot/initrd.img-xxx ``` - 启动系统: ```grub boot ``` 4. **进入系统后修复软链接** - 如果成功进入系统,立即修复/sbin/init的软链接: ```bash sudo ln -sf /lib/systemd/systemd /sbin/init ``` - 然后重启系统,检查是否恢复正常启动。 ### 方法二:使用Live CD/USB挂载系统分区修复(推荐,更稳妥) 1. **准备Live环境** - 使用其他电脑下载Linux Live USB(如Ubuntu Live CD)并制作启动盘。 - 从Live USB启动,选择“试用Ubuntu”(Try Ubuntu)。 2. **挂载原系统分区** - 打开终端,查找原系统的根分区: ```bash sudo fdisk -l ``` 找到原系统的根分区(例如`/dev/sda1`)。 - 挂载根分区到`/mnt`: ```bash sudo mount /dev/sda1 /mnt ``` - 挂载必要的虚拟文件系统: ```bash sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo mount --bind /dev /mnt/dev sudo mount --bind /dev/pts /mnt/dev/pts sudo mount --bind /run /mnt/run # 如果存在/run目录,最好也挂载 ``` 3. **切换到原系统环境(chroot)** ```bash sudo chroot /mnt ``` 4. **修复/sbin/init软链接** - 检查当前初始化系统(通常是systemd): ```bash # 确认systemd的位置 ls -l /lib/systemd/systemd ``` 如果存在,则重建软链接: ```bash ln -sf /lib/systemd/systemd /sbin/init ``` 或者,如果系统使用upstart(较老的系统): ```bash ln -sf /sbin/upstart /sbin/init ``` - 验证链接: ```bash ls -l /sbin/init ``` 应该显示指向正确路径的链接。 5. **退出chroot并重启** ```bash exit # 退出chroot环境 sudo umount -R /mnt # 卸载挂载点 reboot ``` ### 注意事项 - **系统差异**:不同Linux发行版的初始化系统可能不同,常见的有systemd(现代主流)、upstart(旧版Ubuntu)、sysvinit(更老)。请根据实际情况选择正确的init程序路径。 - **路径确认**:在修复前,务必确认目标init程序(如`/lib/systemd/systemd`)是否存在。如果不存在,可能需要重装初始化系统包。 - **备份与恢复**:如果修改/sbin/init之前有备份,也可以从备份恢复。 ### 相关问题 §§相关问题§§ 1. 如何判断Linux系统使用的是systemd、upstart还是sysvinit? 2. 在GRUB引导时如何临时修改内核参数以进入单用户模式? 3. 使用Live CD修复系统时,如何挂载LVM或加密分区? 4. 系统启动过程中,内核如何定位并执行init程序? ### 引用说明 在Linux系统中,`/sbin/init`通常是一个指向实际初始化系统的软链接,修改或覆盖该文件会导致系统启动失败[^1][^2]。通过恢复软链接到正确的初始化程序(如systemd)可以解决此问题[^2]。 [^1]: 引用自用户提供的参考内容:linux系统/sbin/init执行过程。 [^2]: 引用自用户提供的GRUB命令行修复思路。 </think>### Linux修改/sbin/init文件后无法启动的解决方法 当`/sbin/init`文件被修改后导致系统无法启动时,这是因为Linux内核启动后加载的第一个用户空间程序(PID=1)被破坏。以下是两种修复方法: --- #### **方法1:通过GRUB临时指定init路径(推荐)** 1. **进入GRUB命令行** - 开机时按住`Shift`键调出GRUB菜单 - 按`e`键编辑启动参数 2. **修改内核启动参数** - 找到以`linux`开头的行 - 在行尾添加:`init=/lib/systemd/systemd` (完整示例:`linux /boot/vmlinuz... ro quiet splash init=/lib/systemd/systemd`) - 按`Ctrl+X`或`F10`启动 3. **修复软链接** ```bash sudo ln -sf /lib/systemd/systemd /sbin/init # 重建软链接 sudo systemctl daemon-reload # 重载服务配置 reboot ``` --- #### **方法2:使用Live CD/USB修复** 1. **启动Live环境** - 使用Ubuntu/Debian Live USB启动 - 选择"Try Ubuntu" 2. **挂载原系统分区** ```bash sudo fdisk -l # 确认根分区(如/dev/sda2) sudo mount /dev/sda2 /mnt # 挂载根分区 sudo mount /dev/sda1 /mnt/boot # 挂载boot分区(如存在) sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys ``` 3. **重建init链接** ```bash sudo chroot /mnt ln -sf /lib/systemd/systemd /sbin/init # 重建软链接 # 验证链接:ls -l /sbin/init 应显示 -> /lib/systemd/systemd exit # 退出chroot ``` 4. **卸载并重启** ```bash sudo umount -R /mnt reboot ``` --- ### 关键原理说明 1. **/sbin/init的作用** Linux内核启动后执行的第一个用户空间程序,负责初始化系统服务[^1]。其标准位置为: $$ \text{/sbin/init} \rightarrow \text{/lib/systemd/systemd} $$ 2. **修复本质** 重建被破坏的软链接关系: ```bash ln -sf /lib/systemd/systemd /sbin/init ``` 这恢复内核到用户空间的传递链: $$ \text{kernel} \rightarrow \text{initramfs} \rightarrow \text{/sbin/init} \rightarrow \text{systemd} $$ 3. **预防措施** - 修改前备份:`sudo cp /sbin/init ~/init_backup` - 避免直接修改:使用`systemctl edit`修改服务 - 软链接验证:`file /sbin/init`应显示"symbolic link" > 💡 引用[2]案例证明:当`/sbin/init`丢失时,通过在GRUB指定`init=/lib/systemd/systemd`可临时恢复系统[^2]。现代Linux中,systemd已成为默认初始化系统[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值