Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 断开的符号链接和神秘的(已删除)_Linux_Bash_Symlink_Procfs - Fatal编程技术网

Linux 断开的符号链接和神秘的(已删除)

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/$

我一直在linux上使用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;
}