Linux中chroot与pivot_root的区别

本文介绍了chroot和pivot_root两个Linux命令的功能及使用方法。chroot允许在指定的root目录运行命令,常用于隔离环境运行不可靠程序或构建自定义Linux系统。pivot_root则用于完全切换系统的root文件系统,并移除对旧root文件系统的依赖。
1. chroot: 在指定的root目录运行命令
参考"info root"中的例子,我把/bin/ls拷贝至~/myroot后,
运行"$ sudo chroot ~/myroot /ls -Rl /", 结果得到下面的错误结果:
“chroot: cannot run command `/ls': No such file or directory”.

事实上,"info root"中提到,如果执行的命令属于动态链接可执行文件,需要把依赖的共享库文件拷贝到新的root相关目录中。
运行,"$ ldd ~/myroot/ls",发现依赖于以下库:

    linux-gate.so.1 =>  (0x00795000)
    librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x00e7a000)
    libselinux.so.1 => /lib/libselinux.so.1 (0x00748000)
    libacl.so.1 => /lib/libacl.so.1 (0x00fbf000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
    libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x0053d000)
    /lib/ld-linux.so.2 (0x003ba000)
    libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0x002f5000)
    libattr.so.1 => /lib/libattr.so.1 (0x00255000)

在myroot下建立lib目录,然后把上诉库文件拷贝至该目录。重新运行chroot,成功。

chroot通常用于运行一些不可靠的程序,这样比较安全。
chroot也通常用于手动建立一个linux系统,属于LFS项目的重要部分。LFS项目(Linux from Scratch),提供方法和建议来建立自己定制的linux系统,包括全部通过源代码。

LFS用于学习linux系统以及定制小的系统非常有帮助。

2. exec命令在当前shell执行一个命令,同时结束该shell。exec可以用于用一种新的shell替换原来的shell,比如 "$exec ksh"。

3. pivot_root: 改变root文件系统
   用法:pivot_root new_root put_old
   描述:pivot_root把当前进程的root文件系统放到put_old目录,而使new_root成为新的root文件系统。
例子:
   从127.0.0.1:/home/qianjiang/nfsroot挂载新的文件系统并且运行init
   a. 拷贝sh,ls至nfsroot/bin,以及相关的共享库至nfsroot/lib
   b. 在nfsroot下面建立目录old_root
   c. mount -o ro 127.0.0.1:/home/qianjiang/nfsroot /mnt
   d. cd /mnt
   e. pivot_root . old_root

“这个时候,会发现比如"ls /"显示的是nfsroot下面的文件;"ls old_root"显示的是之前文件系统root下面的文件。”
   
   f. exec chroot . sh -c "umount /old_root; exec /sbin/init' \
         <dev/console >dev/console 2>&1

pivot_root和chroot的主要区别是,pivot_root主要是把整个系统切换到一个新的root目录,而移除对之前root文件系统的依赖,这样你就能够umount原先的root文件系统。而chroot是针对某个进程,而系统的其它部分依旧运行于老的root目录。
// SPDX-License-Identifier: GPL-2.0 #include <linux/unistd.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/minix_fs.h> #include <linux/romfs_fs.h> #include <linux/initrd.h> #include <linux/sched.h> #include <linux/freezer.h> #include <linux/kmod.h> #include <uapi/linux/mount.h> #include "do_mounts.h" unsigned long initrd_start, initrd_end; int initrd_below_start_ok; unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ static int __initdata mount_initrd = 1; phys_addr_t phys_initrd_start __initdata; unsigned long phys_initrd_size __initdata; static int __init no_initrd(char *str) { mount_initrd = 0; return 1; } __setup("noinitrd", no_initrd); static int __init early_initrdmem(char *p) { phys_addr_t start; unsigned long size; char *endp; start = memparse(p, &endp); if (*endp == ',') { size = memparse(endp + 1, NULL); phys_initrd_start = start; phys_initrd_size = size; } return 0; } early_param("initrdmem", early_initrdmem); static int __init early_initrd(char *p) { return early_initrdmem(p); } early_param("initrd", early_initrd); static int __init init_linuxrc(struct subprocess_info *info, struct cred *new) { ksys_unshare(CLONE_FS | CLONE_FILES); console_on_rootfs(); /* move initrd over / and chdir/chroot in initrd root */ init_chdir("/root"); init_mount(".", "/", NULL, MS_MOVE, NULL); init_chroot("."); ksys_setsid(); return 0; } static void __init handle_initrd(void) { struct subprocess_info *info; static char *argv[] = { "linuxrc", NULL, }; extern char *envp_init[]; int error; pr_warn("using deprecated initrd support, will be removed in 2021.\n"); real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); init_mkdir("/old", 0700); init_chdir("/old"); /* * In case that a resume from disk is carried out by linuxrc or one of * its children, we need to tell the freezer not to wait for us. */ current->flags |= PF_FREEZER_SKIP; info = call_usermodehelper_setup("/linuxrc", argv, envp_init, GFP_KERNEL, init_linuxrc, NULL, NULL); if (!info) return; call_usermodehelper_exec(info, UMH_WAIT_PROC); current->flags &= ~PF_FREEZER_SKIP; /* move initrd to rootfs' /old */ init_mount("..", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ init_chroot(".."); if (new_decode_dev(real_root_dev) == Root_RAM0) { init_chdir("/old"); return; } init_chdir("/"); ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); error = init_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okay\n"); else { if (error == -ENOENT) printk("/initrd does not exist. Ignored.\n"); else printk("failed\n"); printk(KERN_NOTICE "Unmounting old root\n"); init_umount("/old", MNT_DETACH); } } bool __init initrd_load(void) { if (mount_initrd) { create_dev("/dev/ram", Root_RAM0); /* * Load the initrd data into /dev/ram0. Execute it as initrd * unless /dev/ram0 is supposed to be our actual root device, * in that case the ram disk is just set up here, and gets * mounted in the normal path. */ if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { init_unlink("/initrd.image"); handle_initrd(); return true; } } init_unlink("/initrd.image"); return false; }
10-24
这段代码是Linux内核中用于处理initrd(初始RAM磁盘)的代码。它负责加载挂载initrd,并在适当的时候切换到真正的根文件系统。以下是代码的主要功能解析: 1. **initrd的初始化**: - `phys_initrd_start``phys_initrd_size`变量用于存储initrd在物理内存中的起始地址大小。 - `no_initrd`函数通过`__setup("noinitrd", no_initrd)`解析命令行参数,如果用户指定了`noinitrd`参数,则禁用initrd支持。 - `early_initrdmem``early_initrd`函数通过`early_param`解析initrd的内存地址大小。 2. **initrd的处理**: - `handle_initrd`函数负责挂载initrd,并执行其中的`linuxrc`脚本。它首先将initrd挂载到rootfs的`/root`目录下,然后创建一个子进程执行`linuxrc`。 - 在`init_linuxrc`函数中,进行了文件系统的切换,将当前工作目录移动到initrd的根目录并执行chroot操作。 3. **initrd的卸载**: - 在`handle_initrd`函数的最后,initrd会被移动到`/old`目录,并且根文件系统会切换回真正的根设备。 - 如果切换成功,旧的根文件系统会被卸载。 4. **initrd的加载**: - `initrd_load`函数负责加载initrd镜像文件`/initrd.image`,并根据情况决定是否调用`handle_initrd`来处理initrd。 ### 示例格式 快速排序的基本思想是选择一个基准元素 ```python def quick_sort(arr): if len(arr) <= 1: return arr else: # 选择基准值 pivot = arr[len(arr) // 2] # 分别存放比基准小大的元素 left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] # 递归地对左右两边进行快排,并合并结果 return quick_sort(left) + middle + quick_sort(right)```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值