我有 2 个文件: /MyDir/a 和 /MyDir/MySubDir/b 并且正在运行一个 bash 脚本,我想向其中添加代码以使文件 /a 指向文件 /b,但仅限于当前进程及其后代。
为了使 /MyDir/a 指向 /MyDir/MySubDir/b 仅在当前进程(不包括其后代)的上下文中,我尝试首先通过运行一个小命令使当前进程在其自己的安装命名空间中运行我的脚本中执行的 C 程序
unshare(CLONE_NEWNS)
进而
mount --bind /MyDir/MySubDir/b /MyDir/a.
不幸的是,这并没有像我预期的那样工作,因为尽管系统调用报告成功,但安装仍然对其他进程可见。
在另一次尝试中,我尝试通过调用从 C 代码进行挂载
mount("/MyDir/a", "/MyDir/MySubDir/b", "ext3", MS_BIND, null)
但这不起作用,因为挂载根本没有生效(尽管调用报告成功)。
有没有办法使用 bash 脚本在当前进程及其后代的上下文中使 /MyDir/a 指向 /MyDir/MySubDir/b ?
我还阅读了一些有关 chroot 的内容,但这仅适用于 / 目录...是否有类似于 chroot 的内容仅适用于特定子目录?
谢谢你的时间!
答案1
仅 shell 的解决方案是:
对于交互式 shell:
# unshare --mount
# mount --bind /MyDir/MySubDir/b /MyDir/a
#
以非交互方式,在不必了解这些设置的脚本之前:
# unshare --mount sh -c 'mount --bind /MyDir/MySubDir/b /MyDir/a; exec somethingelse'
这取消共享联机帮助页还警告有关共享子树挂载的问题。如果您必须禁用它们,请考虑添加例如--make-private
挂载。
正如 Hauke 所说,您必须确保在创建命名空间后不要立即离开它,因为它会消失。
如果需要,有一种无需进程即可维护名称空间的方法。由于它涉及到挂载,因此对于挂载命名空间来说有点棘手。这是一个交互式示例:
shell1# unshare --mount
shell1# echo $$
12345
shell1#
shell2# : > /root/mntreference
shell2# mount --bind /proc/12345/ns/mnt /root/mntreference
现在,只要保持挂载该引用,即使没有进程再使用它,命名空间也不会消失。使用nsenter --mount=/root/mntreference
将进入它,因此您可以轻松地在其中运行其他脚本。
使用 C 中的等效项应该不成问题。
答案2
不幸的是你还没有解释C程序和脚本是如何关联的。
该问题的一个可能(此处可能)原因是:您从脚本调用 C 程序,但命名空间更改仅在 C 程序(以及可能的子程序)内有效。该程序存在后,所有后续命令的情况都不会改变。
execve()
您应该通过调用所需的 shell从 C 程序启动 shell 。
答案3
正如其他人所解释的,您需要创建名称空间(使用unshare
)并在其中运行命令。
如果您需要一个不需要root、信号和返回状态处理正确的预制解决方案,您可以使用该faketree
实用程序。可用在 github 上这里, 有一个博客文章描述其用途和目的。
可以用作:
faketree --mount /MyDir/MySubDir/b:/MyDir/a -- /path/to/your/script.sh