Bri*_*ker 5 linux bash symlink procfs
我一直在用 linux 上的 proc 文件系统做一些事情,我遇到了一些我想澄清的行为。
每个进程/proc都有一个指向它的可执行文件的符号链接,/proc/{pid}/exe. 如果一个进程在其可执行文件被删除后继续运行,读取此符号链接将返回可执行文件的路径,(deleted)并附加到末尾。
运行此命令,您甚至可能会在系统上看到一些:
grep '(deleted)' <(for dir in $(ls /proc | grep -E '^[0-9]+'); do echo "$dir $(readlink /proc/$dir/exe)"; done)
Run Code Online (Sandbox Code Playgroud)
我尝试使用一些简单的 bash 命令重新创建此行为:
>>> echo "temporary file" >> tmpfile.test
>>> ln -s tmpfile.test tmpfile.link
>>> rm tmpfile.test
>>> readlink tmpfile.link
tmpfile.test
Run Code Online (Sandbox Code Playgroud)
没有(deleted)附加到名称!尝试cat tmpfile.link确认链接已断开 ( cat: tmpfile.link: No such file or directory)。
然而,前几天,同样的测试确实导致了一个(deleted)被附加到 readlink 的输出。是什么赋予了?
这是我想知道的:
(deleted)将附加到名称?/proc/{pid}/exe显示(deleted)已删除的可执行文件?/proc/{pid}/exe
不附加任何内容的情况下获取可执行文件的名称(deleted)并保证原始可执行文件不只是命名some_executable (deleted)?FWIW,特殊<filename> (deleted)行为在 Linux 内核函数中实现d_path():https://elixir.bootlin.com/linux/v4.1.13/source/fs/dcache.c#L3080。
源注释(在下面的代码片段中)表明特殊行为仅适用于某些“合成文件系统”(例如)和“伪索引节点”动态生成的名称(路径)procfs。
/**
* d_path - return the path of a dentry
* @path: path to report
* @buf: buffer to return value in
* @buflen: buffer length
*
* Convert a dentry into an ASCII path name. If the entry has been deleted
* the string " (deleted)" is appended. Note that this is ambiguous.
*
* Returns a pointer into the buffer or an error code if the path was
* too long. Note: Callers should use the returned pointer, not the passed
* in buffer, to use the name! The implementation often starts at an offset
* into the buffer, and may leave 0 bytes at the start.
*
* "buflen" should be positive.
*/
char *d_path(const struct path *path, char *buf, int buflen)
{
char *res = buf + buflen;
struct path root;
int error;
/*
* We have various synthetic filesystems that never get mounted. On
* these filesystems dentries are never used for lookup purposes, and
* thus don't need to be hashed. They also don't need a name until a
* user wants to identify the object in /proc/pid/fd/. The little hack
* below allows us to generate a name for these objects on demand:
*
* Some pseudo inodes are mountable. When they are mounted
* path->dentry == path->mnt->mnt_root. In that case don't call d_dname
* and instead have d_path return the mounted path.
*/
if (path->dentry->d_op && path->dentry->d_op->d_dname &&
(!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
rcu_read_lock();
get_fs_root_rcu(current->fs, &root);
error = path_with_deleted(path, &root, &res, &buflen);
rcu_read_unlock();
if (error < 0)
res = ERR_PTR(error);
return res;
}
Run Code Online (Sandbox Code Playgroud)