在 Linux 用户模式下退出 init 的正确方法

标签 c linux linux-kernel init user-mode-linux

我使用自定义 initrd 在用户模式下编译了 Linux 内核 5.6,创建方法如下:

mkdir initrd
cd initrd
mkdir bin dev etc home mnt proc sys usr
mknod dev/console c 5 1

initrd/init.c初始化文件

#include <stdio.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("init\n");

    mount("none", "/proc", "proc", MS_MGC_VAL, "");
    mount("none", "/sys", "sysfs", MS_MGC_VAL, "");
    mount("none", "/dev", "devtmpfs", MS_MGC_VAL, "");

    if (access("/dev/ubda", F_OK) != -1) {
        printf("/dev/ubda exists\n");
    } else {
        printf("/dev/ubda not exists\n");
    }

    return EXIT_SUCCESS;
}

此程序检查由 ubd0=... 选项传递的磁盘。

使用 gcc -static -o init init.c 编译。

毕竟我编译了内核

make mrproper
make mrproper ARCH=um
make defconfig ARCH=um
make menuconfig ARCH=um
make linux ARCH=um

我更改了 .config 文件中的以下选项(使用 menuconfig)

CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="initrd"
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y

毕竟我尝试运行 ./linux mem=32M 一切看起来都很好,除了退出

$ ./linux mem=32M
Core dump limits :
    soft - NONE
    hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking environment variables for a tempdir...none found
Checking if /dev/shm is on tmpfs...OK
Checking PROT_EXEC mmap in /dev/shm...OK
Adding 15400960 bytes to physical memory to account for exec-shield gap
Linux version 5.6.0 (root@d97bfdd0b529) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #1 Mon Apr 20 14:47:21 UTC 2020
Built 1 zonelists, mobility grouping on.  Total pages: 11788
Kernel command line: mem=32M root=98:0
Dentry cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
Inode-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
mem auto-init: stack:off, heap alloc:off, heap free:off
Memory: 26524K/47808K available (2998K kernel code, 1137K rwdata, 956K rodata, 142K init, 167K bss, 21284K reserved, 0K cma-reserved)
NR_IRQS: 16
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrating delay loop... 6966.47 BogoMIPS (lpj=34832384)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
devtmpfs: initialized
random: get_random_u32 called from bucket_table_alloc+0x118/0x141 with crng_init=0
umid_file_name : buffer too short
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: 0, 6144 bytes, linear)
NET: Registered protocol family 16
clocksource: Switched to clocksource timer
VFS: Disk quotas dquot_6.6.0
VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes, linear)
TCP established hash table entries: 512 (order: 0, 4096 bytes, linear)
TCP bind hash table entries: 512 (order: 0, 4096 bytes, linear)
TCP: Hash tables configured (established 512 bind 512)
UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
NET: Registered protocol family 1
printk: console [stderr0] disabled
mconsole (version 2) initialized on /root/.uml/BolhBq/mconsole
Checking host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=13 bucket_order=0
io scheduler mq-deadline registered
io scheduler kyber registered
NET: Registered protocol family 17
9pnet: Installing 9P2000 support
Initialized stdio console driver
Console initialized on /dev/tty0
printk: console [tty0] enabled
Initializing software serial port version 1
printk: console [mc-1] enabled
Failed to initialize ubd device 0 :Couldn't determine size of device's file
epollctl add err fd 0, Operation not permitted
This architecture does not have kernel memory protection.
Run /init as init process
init
/dev/ubda not exists
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
CPU: 0 PID: 1 Comm: init Not tainted 5.6.0 #1
Stack:
 6282bcb0 602f95fa 62826000 6038c6db
 6006cd66 6001e201 6282bcc0 602f963f
 6282bde0 6003c7ee 00412000 62a8bec0
Call Trace:
 [<6006cd66>] ? printk+0x0/0x94
 [<6003d5a8>] ? exit_mm+0x0/0x223
 [<600214a8>] show_stack+0x13b/0x155
 [<602f95fa>] ? dump_stack_print_info+0xe2/0xeb
 [<6006cd66>] ? printk+0x0/0x94
 [<602f963f>] dump_stack+0x2a/0x2c
 [<6003c7ee>] panic+0x18c/0x3be
 [<6003c662>] ? panic+0x0/0x3be
 [<6008bbf6>] ? acct_collect+0x0/0x1df
 [<60022177>] ? flush_tlb_page+0x12e/0x1f5
 [<600672f2>] ? up_read+0x10/0x12
 [<60067388>] ? __percpu_up_read+0x1a/0x1c
 [<600455fd>] ? cgroup_threadgroup_change_end.isra.29+0x2e/0x30
 [<6003d5a8>] ? exit_mm+0x0/0x223
 [<6003de69>] do_exit+0x220/0x914
 [<6003f33b>] sys_exit_group+0x0/0x16
 [<6003f351>] __wake_up_parent+0x0/0x25
 [<6002345b>] handle_syscall+0x79/0xa7
 [<60036012>] userspace+0x483/0x510
 [<600201fa>] new_thread_handler+0xb0/0xb2

如何正确退出?

最佳答案

init 进程绝不能退出。退出 init 的正确方法是关闭。

#include <linux/reboot.h>

int main(int argc, char *argv[]) {
  // ...
  // return EXIT_SUCCESS;

  sync();
  reboot(LINUX_REBOOT_MAGIC1, 
     LINUX_REBOOT_MAGIC2, 
     LINUX_REBOOT_CMD_POWER_OFF, 0);
}

在 glibc 和大多数替代 libc(包括 uclibc、dietlibc、musl 和其他一些)下,一些涉及的常量已获得符号名称 RB_*,并且库调用是围绕系统调用的 1-argument 包装器:

#include <sys/reboot.h>

int main(int argc, char *argv[]) {
  // ...
  // return EXIT_SUCCESS;

  sync();
  reboot(RB_POWER_OFF);
}

对于停止或重启系统的 cmd 值,成功调用 reboot() 不会返回。

关于在 Linux 用户模式下退出 init 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61327011/

相关文章:

c - C 中的堆排序,索引 0 问题

c++ - `sqlite3` 忽略 `sqlite3_busy_timeout` 吗?

linux - 将秒数转换为 hh :mm:ss format (or whatever format Excel or LibreOffice likes) and insert it back to a csv file in Bash

linux-kernel - cdev 及其关联的文件操作如何工作?

linux - Arduino 蓝牙 N64 Controller - 编写 Linux 驱动程序?

assembly - 当D-cache关闭时使D-cache失效的目的是什么?

c - 改变可变参数

c - 终端如何从标准输出读取并在屏幕上绘制文本?

windows - 我应该在什么操作系统上托管颠覆?

linux - 如何通过ftp在远程之间传输文件?