From 9d90121c045c4ab5a2e278e5ec1ae218f03c4fcb Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Sun, 9 Apr 2023 15:37:59 +0200 Subject: [PATCH] alternatives: --keep-foreign incorrectly handles non-existent files Normally alternatives will only refuse to create a link to /etc/alternatives/* if the file already exists and is not a symlink. But alternatives never checked if existing symlink goes to /etc/alternatives/. This is a weird behavior, but we did not want to change the default behavior so we added --keep-foreign option that is more strict and checks that the target if the symlink is in /etc/alternatives/. But we missed the corner-case where there is no file at all and incorrectly reported on error. Fixes #102 (cherry picked from commit bd9b6ccc3f8808edb29f269479064b29e83b465f) --- alternatives.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/alternatives.c b/alternatives.c index 8f0287d3..8f7e9d08 100644 --- a/alternatives.c +++ b/alternatives.c @@ -490,6 +490,12 @@ static int isLink(char *path) { return !!S_ISLNK(sbuf.st_mode); } +static int fileExists(char *path) { + struct stat sbuf; + + return !stat(path, &sbuf); +} + static int facilityBelongsToUs(char *facility, const char *altDir) { char buf[PATH_MAX]; if (readlink(facility, buf, sizeof(buf)) <= 0) @@ -533,7 +539,17 @@ static int makeLinks(struct linkSet *l, const char *altDir, int flags) { sl = alloca(strlen(altDir) + strlen(l->title) + 2); sprintf(sl, "%s/%s", altDir, l->title); - if (isLink(l->facility) && (!FL_KEEP_FOREIGN(flags) || facilityBelongsToUs(l->facility, altDir)) ) { + if (fileExists(l->facility) && !isLink(l->facility)) { + fprintf( + stderr, + _("failed to link %s -> %s: %s exists and it is not a symlink\n"), + l->facility, sl, l->facility); + } else if (FL_KEEP_FOREIGN(flags) && isLink(l->facility) && !facilityBelongsToUs(l->facility, altDir)) { + fprintf( + stderr, + _("failed to link %s -> %s: --keep-foreign was set and link %s points outside %s\n"), + l->facility, sl, l->facility, altDir); + } else { if (FL_TEST(flags)) { printf(_("would link %s -> %s\n"), l->facility, sl); } else { @@ -550,11 +566,7 @@ static int makeLinks(struct linkSet *l, const char *altDir, int flags) { } } } - } else - fprintf( - stderr, - _("failed to link %s -> %s: %s exists and it is either not a symlink or --keep-foreign was set and link points outside %s\n"), - l->facility, sl, l->facility, altDir); + } if (FL_TEST(flags)) { printf(_("would link %s -> %s\n"), sl, l->target);