diff --git a/bin/xbps-create/xbps-create.1 b/bin/xbps-create/xbps-create.1 index a698257a..b338066e 100644 --- a/bin/xbps-create/xbps-create.1 +++ b/bin/xbps-create/xbps-create.1 @@ -83,6 +83,10 @@ A list of required shared libraries, separated by whitespaces. Example: .It Fl -alternatives Ar list A list of alternatives provided by this package, separated by whitespaces. Example: .Ar 'group:symlink:target group2:symlink:target' . +If +.Em symlink +is a relative path, the symlink will be created relative to +.Em target . .El .Sh SEE ALSO .Xr xbps-checkvers 1 , diff --git a/lib/package_alternatives.c b/lib/package_alternatives.c index 60897350..958c9f10 100644 --- a/lib/package_alternatives.c +++ b/lib/package_alternatives.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "xbps_api_impl.h" @@ -39,9 +40,6 @@ * These functions implement the alternatives framework. */ -/* - * XXX TODO: relative symlinks. - */ static char * left(const char *str) { @@ -74,7 +72,18 @@ remove_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) str = xbps_array_get(a, i); l = left(xbps_string_cstring_nocopy(str)); assert(l); - lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); + if (l[0] != '/') { + const char *tgt; + char *tgt_dup, *tgt_dir; + tgt = right(xbps_string_cstring_nocopy(str)); + tgt_dup = strdup(tgt); + assert(tgt_dup); + tgt_dir = dirname(tgt_dup); + lnk = xbps_xasprintf("%s%s/%s", xhp->rootdir, tgt_dir, l); + free(tgt_dup); + } else { + lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); + } xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_REMOVED, 0, NULL, "Removing '%s' alternatives group symlink: %s", grname, l); unlink(lnk); @@ -102,7 +111,16 @@ create_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) assert(l); tgt = right(xbps_string_cstring_nocopy(str)); assert(tgt); - lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); + if (l[0] != '/') { + char *tgt_dup, *tgt_dir; + tgt_dup = strdup(tgt); + assert(tgt_dup); + tgt_dir = dirname(tgt_dup); + lnk = xbps_xasprintf("%s%s/%s", xhp->rootdir, tgt_dir, l); + free(tgt_dup); + } else { + lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); + } xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_ADDED, 0, NULL, "Creating '%s' alternatives group symlink: %s -> %s", grname, l, tgt); unlink(lnk); diff --git a/tests/xbps/xbps-alternatives/main.sh b/tests/xbps/xbps-alternatives/main.sh index b32c06f1..e090f8ab 100644 --- a/tests/xbps/xbps-alternatives/main.sh +++ b/tests/xbps/xbps-alternatives/main.sh @@ -28,6 +28,34 @@ register_one_body() { atf_check_equal $rv 0 } +atf_test_case register_one_relative + +register_one_relative_head() { + atf_set "descr" "xbps-alternatives: register one pkg wth an alternatives group that has a relative path" +} +register_one_relative_body() { + mkdir -p repo pkg_A/usr/bin + touch pkg_A/usr/bin/fileA + cd repo + xbps-create -A noarch -n A-1.1_1 -s "A pkg" --alternatives "file:../file:/usr/bin/fileA" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -r root --repository=repo -ydv A + atf_check_equal $? 0 + rv=1 + if [ -e root/usr/bin/fileA ]; then + lnk=$(readlink root/usr/file) + if [ "$lnk" = "/usr/bin/fileA" ]; then + rv=0 + fi + echo "A lnk: $lnk" + fi + atf_check_equal $rv 0 +} + atf_test_case register_dups register_dups_head() { @@ -119,6 +147,31 @@ unregister_one_body() { atf_check_equal $rv 0 } +atf_test_case unregister_one_relative + +unregister_one_relative_head() { + atf_set "descr" "xbps-alternatives: unregister one pkg with an alternatives group that has a relative path" +} +unregister_one_relative_body() { + mkdir -p repo pkg_A/usr/bin + touch pkg_A/usr/bin/fileA + cd repo + xbps-create -A noarch -n A-1.1_1 -s "A pkg" --alternatives "file:file:/usr/bin/fileA" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -r root --repository=repo -ydv A + atf_check_equal $? 0 + xbps-remove -r root -yvd A + rv=1 + if [ ! -L root/usr/bin/file -a ! -e root/usr/bin/fileA ]; then + rv=0 + fi + atf_check_equal $rv 0 +} + atf_test_case unregister_multi unregister_multi_head() { @@ -286,9 +339,11 @@ set_pkg_group_body() { atf_init_test_cases() { atf_add_test_case register_one + atf_add_test_case register_one_relative atf_add_test_case register_dups atf_add_test_case register_multi atf_add_test_case unregister_one + atf_add_test_case unregister_one_relative atf_add_test_case unregister_multi atf_add_test_case set_pkg atf_add_test_case set_pkg_group