summaryrefslogtreecommitdiff
path: root/src/shared/path-util.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2014-04-24 01:44:10 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2014-05-15 15:29:58 +0200
commit12ed81d9c88406234c20e9261ae8c8b992d8bc4d (patch)
treea18bc3403e26772f3d00c3d01c9c33cd05770e48 /src/shared/path-util.c
parent62b002337727093c21d020c730bd65971f7783a7 (diff)
Make systemctl --root look for files in the proper places
Running systemctl enable/disable/set-default/... with the --root option under strace reveals that it accessed various files and directories in the main fs, and not underneath the specified root. This can lead to correct results only when the layout and configuration in the container are identical, which often is not the case. Fix this by adding the specified root to all file access operations. This patch does not handle some corner cases: symlinks which point outside of the specified root might be interpreted differently than they would be by the kernel if the specified root was the real root. But systemctl does not create such symlinks by itself, and I think this is enough of a corner case not to be worth the additional complexity of reimplementing link chasing in systemd. Also, simplify the code in a few places and remove an hypothetical memory leak on error.
Diffstat (limited to 'src/shared/path-util.c')
-rw-r--r--src/shared/path-util.c49
1 files changed, 38 insertions, 11 deletions
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 69fcb1660a..8bf9a3cf96 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -167,36 +167,63 @@ char **path_strv_canonicalize_absolute(char **l, const char *prefix) {
STRV_FOREACH(s, l) {
char *t, *u;
+ _cleanup_free_ char *orig = NULL;
- if (!path_is_absolute(*s))
+ if (!path_is_absolute(*s)) {
+ free(*s);
continue;
+ }
if (prefix) {
- t = strappend(prefix, *s);
- free(*s);
- *s = NULL;
-
+ orig = *s;
+ t = strappend(prefix, orig);
if (!t) {
enomem = true;
continue;
}
- } else {
+ } else
t = *s;
- *s = NULL;
- }
errno = 0;
u = canonicalize_file_name(t);
if (!u) {
- if (errno == ENOENT)
- u = t;
- else {
+ if (errno == ENOENT) {
+ if (prefix) {
+ u = orig;
+ orig = NULL;
+ free(t);
+ } else
+ u = t;
+ } else {
free(t);
if (errno == ENOMEM || errno == 0)
enomem = true;
continue;
}
+ } else if (prefix) {
+ char *x;
+
+ free(t);
+ x = path_startswith(u, prefix);
+ if (x) {
+ /* restore the slash if it was lost */
+ if (!startswith(x, "/"))
+ *(--x) = '/';
+
+ t = strdup(x);
+ free(u);
+ if (!t) {
+ enomem = true;
+ continue;
+ }
+ u = t;
+ } else {
+ /* canonicalized path goes outside of
+ * prefix, keep the original path instead */
+ u = orig;
+ orig = NULL;
+ }
} else
free(t);