Linux 断开的符号链接和神秘的(已删除)
我一直在linux上使用proc文件系统,遇到了一些我想澄清的行为Linux 断开的符号链接和神秘的(已删除),linux,bash,symlink,procfs,Linux,Bash,Symlink,Procfs,我一直在linux上使用proc文件系统,遇到了一些我想澄清的行为 /proc中的每个进程都有一个指向其可执行文件的符号链接,/proc/{pid}/exe。如果进程的可执行文件被删除后继续运行,则读取此符号链接将返回可执行文件的路径,并在末尾附加(已删除) 运行此命令时,您甚至可以在系统上看到一些: grep '(deleted)' <(for dir in $(ls /proc | grep -E '^[0-9]+'); do echo "$dir $(readlink /proc/$
/proc
中的每个进程都有一个指向其可执行文件的符号链接,/proc/{pid}/exe
。如果进程的可执行文件被删除后继续运行,则读取此符号链接将返回可执行文件的路径,并在末尾附加(已删除)
运行此命令时,您甚至可以在系统上看到一些:
grep '(deleted)' <(for dir in $(ls /proc | grep -E '^[0-9]+'); do echo "$dir $(readlink /proc/$dir/exe)"; done)
名称后面没有附加(已删除)
!尝试cat-tmpfile.link
可确认链接已断开(cat:tmpfile.link:没有此类文件或目录
)
然而,前几天同样的测试确实导致了一个(已删除)
被附加到readlink的输出中。有什么好处
以下是我想知道的:
- 是否有一系列事件保证
将被删除 附加在名字后面(已删除)
- 为什么
会显示删除的可执行文件的/proc/{pid}/exe
(已删除)
- 如何通过
无任何附加/proc/{pid}/exe
,并保证原件 可执行文件不仅仅被命名为某个可执行文件(已删除)(已删除)
readlink
,但Linux将符号链接更改为指向(已删除)
,即(已删除)
附加到链接的目标。FWIW,特殊的(已删除)
行为在Linux内核函数d_path()
中实现
源注释(在下面的代码片段中)表明,这种特殊行为仅适用于为某些“合成文件系统”(例如procfs
)和“psuedo inode”)动态生成的名称(路径)
/**
* 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;
}
/**
*d_path-返回dentry的路径
*@path:报告路径
*@buf:buffer在中返回值
*@buflen:缓冲区长度
*
*将dentry转换为ASCII路径名。如果条目已被删除
*追加字符串“(已删除)”。请注意,这是不明确的。
*
*返回指向缓冲区的指针或错误代码(如果路径为
*太长了。注意:调用方应该使用返回的指针,而不是传递的指针
*在缓冲区中,使用名称!实现通常从偏移量开始
*进入缓冲区,并且可能在开始时留下0字节。
*
*“buflen”应该是积极的。
*/
char*d_路径(常量结构路径*path,char*buf,int-buflen)
{
char*res=buf+buflen;
结构路径根;
整数误差;
/*
*我们有各种各样的合成文件系统,它们从未被挂载
*这些文件系统dentries从不用于查找目的,并且
*因此,不需要进行散列,它们也不需要名称,直到
*用户想要识别/proc/pid/fd/中的对象
*下面允许我们根据需要为这些对象生成名称:
*
*某些伪索引节点是可装载的。当它们被装载时
*path->dentry==path->mnt->mnt\u root。在这种情况下,不要调用d\u dname
*而是让d_path返回挂载路径。
*/
如果(路径->dentry->d_op&&path->dentry->d_op->d_dname&&
(!IS_ROOT(path->dentry)| path->dentry!=path->mnt->mnt_ROOT))
返回路径->dentry->d_op->d_dname(路径->dentry,buf,buflen);
rcu_读取_锁定();
获取\u fs\u root\u rcu(当前->fs,&root);
错误=删除了路径的路径(路径、&root、&res、&buflen);
rcu_读取_解锁();
如果(错误<0)
res=ERR_PTR(错误);
返回res;
}
这不是我想要的答案,但它让我朝着正确的方向前进。
/**
* 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;
}