From: Yousong Zhou Date: Tue, 11 Jul 2017 03:07:23 +0000 (+0800) Subject: pkg_alternatives: pass if the desired symlink already exists X-Git-Url: http://git.openwrt.org/?p=project%2Fopkg-lede.git;a=commitdiff_plain;h=52fc0069b50b9be89ae3b525b98741123461dd0a pkg_alternatives: pass if the desired symlink already exists This can happen when opkg installs, then configures multiple alternatives in a batch. Symlink to the highest prio alternative will be created in the initial configuring stage causing later symlink call fail with EEXIST Configuring busybox. ... symlink("/sbin/ip-full", "/home/yousong/j/t/lede-imagebuilder-mvebu.Linux-x86_64/build_dir/target-arm_cortex-a9+vfpv3_musl_eabi/root-mvebu/sbin/ip") = 0 ... Configuring ip-full. ... symlink("/sbin/ip-full", "/home/yousong/j/t/lede-imagebuilder-mvebu.Linux-x86_64/build_dir/target-arm_cortex-a9+vfpv3_musl_eabi/root-mvebu/sbin/ip") = -1 EEXIST (File exists) ... While at it, "mkdir -p" dirname(path_in_dest) before symlink in case the following symlink call may fail with ENOENT Ref: https://github.com/openwrt/packages/issues/4567 Reported-by: Aner Andros Signed-off-by: Yousong Zhou --- diff --git a/libopkg/pkg_alternatives.c b/libopkg/pkg_alternatives.c index 890b510..50e9d12 100644 --- a/libopkg/pkg_alternatives.c +++ b/libopkg/pkg_alternatives.c @@ -16,8 +16,10 @@ #include #include /* stat */ #include +#include /* dirname */ #include +#include "file_util.h" #include "libbb/libbb.h" #include "opkg_message.h" #include "pkg.h" @@ -76,9 +78,27 @@ static int pkg_alternatives_update_path(pkg_t *pkg, const pkg_vec_t *installed, } else if (errno != ENOENT) { goto out; } - r = symlink(the_alt->altpath, path_in_dest); - if (r) - opkg_msg(ERROR, "failed symlinking %s -> %s\n", path_in_dest, the_alt->altpath); + { + char *path_copy = xstrdup(path_in_dest); + char *path_parent = dirname(path_copy); + + r = file_mkdir_hier(path_parent, 0755); + free(path_copy); + if (r) { + goto out; + } + r = symlink(the_alt->altpath, path_in_dest); + if (r && errno == EEXIST) { + /* + * the strcmp & unlink check above will make sure that if EEXIST + * happens, the symlink target also matches + */ + r = 0; + } + if (r) { + opkg_perror(ERROR, "failed symlinking %s -> %s", path_in_dest, the_alt->altpath); + } + } } else { unlink(path_in_dest); r = 0;