链接命令是原子的吗?


8

如果有一个过程不断地写入文件,而我想用root来控制文件,则可以执行以下操作:

sudo rm somefile; sudo touch somefile

追加过程是否有可能在这两个命令之间追加到文件?如果是这样,是否有办法确保在这两个命令之间不运行其他命令?


4
这可能是XY问题。您能否解释您要解决的根本问题?
Nate Eldredge

1
@NateEldredge:完全没有。基于我的假想,我无法理解为什么会这样。甚至没有问题。只是好奇。
Darth Egregious

5
该过程实际上可能会继续写入已删除的文件,甚至不会尝试打开新文件。
Random832

我在假设中的假设被证明是有点错误,但是我想您可以将“追加”更改为“打开”或“触摸”,这仍然有意义。
Darth Egregious

Answers:


12

链接的命令行基本上是一个小的Shell脚本。它将使用常规的fork + exec过程运行第一个命令,等待其退出,然后以相同的方式运行第二个命令。在这两个命令之间,shell在其簿记和处理过程中花费了一些任意时间,在此期间,将进行普通的多处理,而任意其他进程可能会执行任意其他操作。因此,答案是否定的。(如果您确实这样做,您会发现该目录的条目somefile消失了,但是文件本身一直保持(因为它是由进程打开的)直到关闭。文件使用的磁盘空间直到这种情况才会被收回。 ,该touch命令将创建一个名称和路径相同的新的,不相关的文件。)

如果您想将文件所有权更改为root,则可以这样做sudo chown root:root somefile(尽管我不确定这将如何影响具有打开文件句柄的进程)。如果要销毁当前文件的内容,请尝试truncate -s 0 somefile(正在运行的进程将继续追加到现在为空的文件中)。如果还有其他事情,也许要弄清楚您想做什么。


谢谢汤姆。我不是很担心我的假设情况。只是想知道这样做是否可行。
Darth Egregious 2015年

关于一般问题,我认为确实没有办法确保Shell脚本中的原子性。您可以使用lockfile等来确保两个协作进程不会彼此踩踏,并且可以使用权限来确保任意进程都不会踩踏您的工作。但是,阻止任何其他程序运行会严重破坏内核的多处理能力。我认为第三环代码根本无法做到这一点。
汤姆·亨特

如果强制性文件锁已启用并且在文件系统上可用,则可以使用它们。
roaima 2015年

5
chown启用somefile不会影响具有somefile文件句柄的进程。
PSkocik

例如,您可以做exec 3>somefile; sudo chmod 0600 somefile; echo hello world >&3; sudo cat somefile; exec 3>&-
PSkocik

6

否。rm命令后面紧跟的touch命令根本不是原子的。这两个命令之间的时间会很长-可能在毫秒范围内。在这段时间内,可能发生很多事情。如果您不走运,您的sudo凭据甚至可能过期。

调用unlinkopen调用的单个程序将为比赛留出更短的窗口,但仍然可能发生。

一种更安全的方法是使用临时名称创建新文件并使用rename系统调用。rename确保使用系统调用“覆盖”名称是原子的。可以使用touch和来实现mv

但是,已打开旧文件进行写入的进程可以在删除旧文件后继续对其进行写入。使用unlink和删除一个文件和使用删除一个文件都是如此rename


3

进程打开了一个文件句柄以供读取后,您对所有权或权限的处理就无关紧要了:该进程可以继续访问文件。您甚至可以删除文件,并且该过程将能够继续通过文件句柄对其进行访问。

将权限视为获取文件句柄的控制门。

如果要自动创建文件,则不要这样做:

sudo rm somefile
sudo touch somefile

您可以考虑一下:

sudo touch anotherfile
sudo perl -e "rename 'anotherfile', 'somefile'"

将自动替换somefileanotherfile。(我更愿意使用,mv -f但我找不到能保证此调用rename(2)系统调用的语句。


也许您可以更新“问题”以解释“控制文件”的含义。您可能在这里遇到XY问题


使用mv -f获得rename(2)的系统调用。没错ln,因为它总是使用link(2)系统调用,因此无法自动替换。 ln -f只是unlink(2)先对目标进行。
彼得·科德斯

@PeterCordes啊,当然,谢谢。我有ln大脑。我不确定如何rename(2)确保参与其中,现在进一步挖掘为时已晚
roaima

POSIX保证mv“应执行等同于”的动作 rename(old, new)pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.htmlmv -f的行为就像mv -i目的地不是可写的,但不是目的地cp -fln -f它将首先取消链接的位置。
彼得·科德斯

2

不是,但

sudo rm somefile; sudo touch somefile

在大多数情况下是安全的。

大多数进程打开文件,然后使用获取的文件描述符访问文件内容。

如果进程打开某文件,则在sh中:

 exec 3>somefile

然后,另一个进程可以自由地取消链接(=删除)somefile,并且第一个进程(在本例中为3)打开了somefile的filedescriptor将继续引用somefile的原始内容,该文件现在处于困境。

sudo touch somefile

将创建一个新的,不相关的somefile,并且所有打开了旧somefile且现在仅使用filedescriptor对其进行引用的进程都不会受到影响,因为它们引用的是另一个文件-现在处于困境。

如果非root进程尝试通过名称引用somefile,则它们将得到EPERM错误,因为新的somefile是root拥有的。

如果要防止同一用户(例如,root)下的多个进程损坏文件,则linux具有强制性和建议性文件锁定。您可以flock在外壳程序脚本中使用该命令来锁定咨询文件(有关更多信息,请参见手册页)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.