Commit 8df9d1a4142311c084ffeeacb67cd34d190eff74
Committed by
Al Viro
1 parent
ffd1f4ed5b
Exists in
master
and in
7 other branches
vfs: show unreachable paths in getcwd and proc
Prepend "(unreachable)" to path strings if the path is not reachable from the current root. Two places updated are - the return string from getcwd() - and symlinks under /proc/$PID. Other uses of d_path() are left unchanged (we know that some old software crashes if /proc/mounts is changed). Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 4 changed files with 57 additions and 5 deletions Side-by-side Diff
fs/dcache.c
... | ... | @@ -2019,6 +2019,11 @@ |
2019 | 2019 | return prepend_path(path, root, buf, buflen); |
2020 | 2020 | } |
2021 | 2021 | |
2022 | +static int prepend_unreachable(char **buffer, int *buflen) | |
2023 | +{ | |
2024 | + return prepend(buffer, buflen, "(unreachable)", 13); | |
2025 | +} | |
2026 | + | |
2022 | 2027 | /** |
2023 | 2028 | * d_path - return the path of a dentry |
2024 | 2029 | * @path: path to report |
... | ... | @@ -2064,6 +2069,39 @@ |
2064 | 2069 | } |
2065 | 2070 | EXPORT_SYMBOL(d_path); |
2066 | 2071 | |
2072 | +/** | |
2073 | + * d_path_with_unreachable - return the path of a dentry | |
2074 | + * @path: path to report | |
2075 | + * @buf: buffer to return value in | |
2076 | + * @buflen: buffer length | |
2077 | + * | |
2078 | + * The difference from d_path() is that this prepends "(unreachable)" | |
2079 | + * to paths which are unreachable from the current process' root. | |
2080 | + */ | |
2081 | +char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | |
2082 | +{ | |
2083 | + char *res = buf + buflen; | |
2084 | + struct path root; | |
2085 | + struct path tmp; | |
2086 | + int error; | |
2087 | + | |
2088 | + if (path->dentry->d_op && path->dentry->d_op->d_dname) | |
2089 | + return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | |
2090 | + | |
2091 | + get_fs_root(current->fs, &root); | |
2092 | + spin_lock(&dcache_lock); | |
2093 | + tmp = root; | |
2094 | + error = path_with_deleted(path, &tmp, &res, &buflen); | |
2095 | + if (!error && !path_equal(&tmp, &root)) | |
2096 | + error = prepend_unreachable(&res, &buflen); | |
2097 | + spin_unlock(&dcache_lock); | |
2098 | + path_put(&root); | |
2099 | + if (error) | |
2100 | + res = ERR_PTR(error); | |
2101 | + | |
2102 | + return res; | |
2103 | +} | |
2104 | + | |
2067 | 2105 | /* |
2068 | 2106 | * Helper function for dentry_operations.d_dname() members |
2069 | 2107 | */ |
2070 | 2108 | |
2071 | 2109 | |
2072 | 2110 | |
... | ... | @@ -2173,14 +2211,22 @@ |
2173 | 2211 | if (!d_unlinked(pwd.dentry)) { |
2174 | 2212 | unsigned long len; |
2175 | 2213 | struct path tmp = root; |
2176 | - char * cwd; | |
2214 | + char *cwd = page + PAGE_SIZE; | |
2215 | + int buflen = PAGE_SIZE; | |
2177 | 2216 | |
2178 | - cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); | |
2217 | + prepend(&cwd, &buflen, "\0", 1); | |
2218 | + error = prepend_path(&pwd, &tmp, &cwd, &buflen); | |
2179 | 2219 | spin_unlock(&dcache_lock); |
2180 | 2220 | |
2181 | - error = PTR_ERR(cwd); | |
2182 | - if (IS_ERR(cwd)) | |
2221 | + if (error) | |
2183 | 2222 | goto out; |
2223 | + | |
2224 | + /* Unreachable from current root */ | |
2225 | + if (!path_equal(&tmp, &root)) { | |
2226 | + error = prepend_unreachable(&cwd, &buflen); | |
2227 | + if (error) | |
2228 | + goto out; | |
2229 | + } | |
2184 | 2230 | |
2185 | 2231 | error = -ERANGE; |
2186 | 2232 | len = PAGE_SIZE + page - cwd; |
fs/proc/base.c
include/linux/dcache.h
... | ... | @@ -315,6 +315,7 @@ |
315 | 315 | |
316 | 316 | extern char *__d_path(const struct path *path, struct path *root, char *, int); |
317 | 317 | extern char *d_path(const struct path *, char *, int); |
318 | +extern char *d_path_with_unreachable(const struct path *, char *, int); | |
318 | 319 | extern char *__dentry_path(struct dentry *, char *, int); |
319 | 320 | extern char *dentry_path(struct dentry *, char *, int); |
320 | 321 |
include/linux/path.h
... | ... | @@ -12,5 +12,10 @@ |
12 | 12 | extern void path_get(struct path *); |
13 | 13 | extern void path_put(struct path *); |
14 | 14 | |
15 | +static inline int path_equal(const struct path *path1, const struct path *path2) | |
16 | +{ | |
17 | + return path1->mnt == path2->mnt && path1->dentry == path2->dentry; | |
18 | +} | |
19 | + | |
15 | 20 | #endif /* _LINUX_PATH_H */ |