无论我重建 plocate 数据库多少次,我都会得到:
/var/lib/plocate/plocate.db: has version 4294967295, expected 0 or 1; please rebuild it.
我到底是怎么做到的?
/sbin/updatedb.plocate:
linux-vdso.so.1 (0x0000007f1c7d4000)
libzstd.so.1 => /lib/aarch64-linux-gnu/libzstd.so.1 (0x0000007f1c6c0000)
libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000007f1c490000)
libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000007f1c3f0000)
libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000007f1c3c0000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007f1c210000)
/lib/ld-linux-aarch64.so.1 (0x0000003000000000)
/bin/plocate:
linux-vdso.so.1 (0x00000077e07be000)
liburing.so.2 => /lib/aarch64-linux-gnu/liburing.so.2 (0x00000077e0760000)
libzstd.so.1 => /lib/aarch64-linux-gnu/libzstd.so.1 (0x00000077e0690000)
libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x00000077e0460000)
libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x00000077e0430000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x00000077e0280000)
/lib/ld-linux-aarch64.so.1 (0x0000003000000000)
libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x00000077e01e0000)
plocate 1.1.15
Copyright 2020 Steinar H. Gunderson
License GPLv2+: GNU GPL version 2 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
updatedb (plocate) 1.1.15
Copyright (C) 2007 Red Hat, Inc. All rights reserved.
This software is distributed under the GPL v.2.
This program is provided with NO WARRANTY, to the extent permitted by law.
答案1
TL;DR 这是由于 Android/ 的限制termux/proroot但可以通过 plocate 中的代码更改来解决,该代码位于1.1.20发布。
4294967295
(即0xffffffff
)是(uint32_t)-1
。这是 plocate 的 updatedb 用作哨兵版本号的值,用于检测未完全写入的数据库文件。
当 plocate 的 updatedb 生成数据库时,它首先使用虚拟值(包括上面的错误版本号)写出一个标头块。
写入数据库的其余部分后,它会返回覆盖标头,这次使用正确的值(包括正确的版本值,目前1
)。
由于数据库输出流正在写入未链接的文件(用 打开O_TMPFILE
),因此该文件现在必须链接到其实际路径。
这代码大致是:
/* Open database */
fd = open(path.c_str(), O_WRONLY | O_TMPFILE, 0640);
outfp = fdopen(fd, "wb");
/* Write dummy header. */
...
/* Write database. */
...
/* Write real header */
fseek(outfp, 0, SEEK_SET);
fwrite(&hdr, sizeof(hdr), 1, outfp);
/* Link database path */
snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", fileno(outfp));
linkat(AT_FDCWD, procpath, AT_FDCWD, outfile.c_str(), AT_SYMLINK_FOLLOW);
fclose(outfp);
这是在 Android 上执行的,Android 不允许创建非特权硬链接,因此上述操作linkat
通常会失败。
但是,它正在执行proot
,正在实施处理程序例如linkat(..., "/proc/X/fd/Y", ..., AT_SYMLINK_FOLLOW)
,在这种情况下,FD 用于未链接的文件。
“有效linkat
”是因为 proot 的处理程序复制内容未链接的文件,linkat
在通话时。这可能比没有好,但是对原始文件描述符的任何进一步写入都不会写入文件系统上的文件。
在 的情况下,没有进一步的写入 - 但最终和调用之间updatedb
也没有。缺少通常没问题,因为随后会刷新输出缓冲区。然而,随着 proot 的实现,这种模式会导致数据丢失。fflush
fwrite
linkat
fflush
fclose
linkat
似乎没有公共错误跟踪器,但我已将此问题报告给ptrace plocate 作者。添加fflush
可以解决该问题,否则是无害的。更新:解决于994819b。