编程思维-如何破解rsync -a不a的问题

rsync 有个 -a 参数,归档模式用于保证文件和文件stat都被复制。但是神奇的事情发生了。在rsync服务器上明明是root用户,rsync到本地之后变成了nobody,说好的 -a ,文件owner给我 a 哪去了。如何排查?

1 对比正常rsync服务器的配置

找了正常服务器的rsyncd.conf,对比无异常。配置无异常,说明不是服务端的问题,那也不能是客户端的问题,客户端没配置,只有参数。

2 对比rsync服务器的文件

在rsync服务器touch一个文件,rsync正常,owner被保留了,说明是文件的问题。哪文件到底出了什么问题,都是root,到底有啥不同呢?

3 复制异常文件

cp 复制异常文件,rsync正常,owner被保留了。用 cp -a 复制文件,rsync异常,owner变成了nobody。为什么?借助 strace 发现有 fsetxattr(4,"user.rsync.%stat","100755 0,0 1000:1000",20,0)=0 这样的调用,问题肯定出在这儿。

4 fake-super

rsync有fake-super参数,客户端和服务端都有,为啥要引入这个参数呢?因为rsync不是想a就能a的,它自己先得有权限。例如以非root从服务端rsync root文件,虽然rsync很想保留文件owner是root,但是它没权限呀,这样file的owner属性不就丢了吗?

所以rsync引入了fake-super参数,虽然没权限把文件改成owner,但是可以找个地方记下来文件的owner是root,记哪呢?答案是文件扩展属性。

下面的例子:因为zzyong没有nobody权限,所以nobody被记在了扩展属性中。注意,如果没有 --fake-super ,则不会记录扩展属性,owner没被保留,丢了。

# sudo -u zzyong rsync --fake-super -a rsync_server::backup/dbnet .
# ls -l
-rwxr-xr-x 1 zzyong zzyong 649842 Nov 27  2017 dbnet
# getfattr -d dbnet
# file: dbnet
user.rsync.%stat="100755 0,0 1000:1000"

下面的例子:因为root有nobody权限,所以变成了nobody,注意这里没有 --fake-super ,并且扩展属性被清空了。

# rsync -a rsync_server::backup/dbnet .
# ls -l dbnet
-rwxr-xr-x 1 nobody nobody 649842 Nov 27  2017 dbnet
# getfattr dbnetget

下面的例子:虽然root有nobody权限,但是使用了 --fake-super ,仍然是root,保留了扩展属性

# rsync --fake-super -a rsync_server::backup/dbnet .
# ls -l dbnet
-rwxr-xr-x 1 root root 649842 Nov 27  2017 dbnet
# getfattr dbnet
# file: dbnet
user.rsync.%stat="100755 0,0 1000:1000"

5 问题原因

到这里原因基本找到了,因为文件rsync涉及多个业务,不知道哪个环节加了文件扩展属性,这个属性在合适的时候显露出来了。

6 总结

要看文件,仅仅看内容和stat的是不够的,必须考虑到其它属性。同样,要备份,仅仅cp是不够的,必须 cp -a --preserve=all

Author: zhengzhiyong

Created: 2020-11-14 六 07:56

Validate