From: Djalal Harouni Date: Thu, 17 Apr 2014 00:47:11 +0000 (+0100) Subject: install: create_symlink() check unlink() return value X-Git-Tag: v213~389 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=af7fce1cdb6c0d6ce56bcddccbc31dd3d64a8cd8 install: create_symlink() check unlink() return value create_symlink() do not check the return value of unlink(), this may confuse the user. Before the unlink() call we check the 'force' argument. If it is not set we fail with -EEXIST, otherwise we unlink() the file, therefore the next symlink() should not fail with -EEXIST (do not count races...). However since callers may not have appropriate privileges to unlink() the file we lose the -EPERM or any other errno code of unlink(), and return the -EEXIST of the next symlink(). Fix this by checking unlink() results. Before: $ systemctl --force --root=~/container-03 set-default multi-user.target Failed to set default target: File exists After: $ systemctl --force --root=~/container-03 set-default multi-user.target Failed to set default target: Permission denied --- diff --git a/src/shared/install.c b/src/shared/install.c index 74090463d..633483381 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1170,7 +1170,9 @@ static int create_symlink( if (!force) return -EEXIST; - unlink(new_path); + r = unlink(new_path); + if (r < 0 && errno != ENOENT) + return -errno; if (symlink(old_path, new_path) >= 0) { add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);