我正在尝试在 EKS 上运行 Alpine Linux 的 Docker 容器中覆盖/etc/resolv.conf。复制和移动都失败:
~ # cp /tmp/resolv.conf /etc/resolv.conf
cp: can't create '/etc/resolv.conf': File exists
~ # mv /tmp/resolv.conf /etc/resolv.conf
mv: can't rename '/tmp/resolv.conf': Resource busy
但是 shell 重定向成功,并保留了 inode:
~ # ls -li /etc/resolv.conf
1412461 -rw-r--r-- 1 root root 131 Feb 17 20:45 /etc/resolv.conf
~ # cat /tmp/resolv.conf.1386 > /etc/resolv.conf
~ # ls -li /etc/resolv.conf
1412461 -rw-r--r-- 1 root root 39 Feb 18 19:17 /etc/resolv.conf
为什么重定向在繁忙的文件上成功?
重定向不会更改文件所在的目录,而mv
会更改。当 - 就像这里一样 - 当你的"目录条目"实际上是一个挂载点时,这一点至关重要,内核正在覆盖目录条目并且不允许公开通常的内容。
那是:
mv foo bar
做什么
mv foo bar
。在操作系统级别,调用系统调用rename("foo", "bar")
,将目录条目bar
替换为目录条目当前指向foo
的索引节点。它根本不打开或更改预先存在的bar
文件;它唯一要做的就是更改以前包含该文件的目录,改为指向条目中具有相同名称的不同文件。
echo hello > bar
做什么
相比之下,echo hello >bar
根本不会更改目录条目;它只是更改目录条目指向的文件。具体来说,它运行open("bar", O_TRUNC)
,并write(<fdno>, "hellon")
open()
返回的文件描述符。
那么,cp
在做什么呢?
。这是个好问题。通常,cp
就地修改现有文件。您可以按如下方式进行测试:
echo ORIGINAL > file1
ln file1 file2
echo REPLACED > file3
cp file3 file1
cat file2
如果cp
用一个全新的文件替换file1
,那么与file2
关联的索引节点将保持不变(包含"ORIGINAL")。但是,事实并非如此 -file2
仅直接标识file1
为其输出文件的cp
修改,将该文件更改为包含REPLACED
。
我需要查看strace cp /tmp/resolv.conf /etc/resolv.conf
的输出来诊断所描述的行为。