Skip to content

fix: relative symlink resolution in install script#1244

Open
V-Subhankar-infy wants to merge 3 commits into
devcontainers:mainfrom
V-Subhankar-infy:main
Open

fix: relative symlink resolution in install script#1244
V-Subhankar-infy wants to merge 3 commits into
devcontainers:mainfrom
V-Subhankar-infy:main

Conversation

@V-Subhankar-infy

@V-Subhankar-infy V-Subhankar-infy commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Fixes relative symlink resolution in the install script for split local layouts (e.g. a launcher in ~/.local/bin pointing to a payload in ~/.local/lib/devcontainers). The wrapper now resolves its own location with portable POSIX shell built-ins instead of GNU-specific readlink -f, so devcontainer works regardless of the caller's working directory and shell environment (Linux, macOS, BSD).

Fixes #1232

Root Cause

A single readlink call plus cd "$(dirname ...)" && pwd resolved relative symlink targets against the caller's CWD rather than the link's own directory, and the readlink -f fallback isn't portable to macOS/BSD.

Reproduction of error

./install.sh --prefix "$HOME/.local/lib/devcontainers"
ln -s ../lib/devcontainers/bin/devcontainer "$HOME/.local/bin/devcontainer"
export PATH="$HOME/.local/bin:$PATH"
cd "$HOME" && devcontainer --version   # cd: ../lib/devcontainers/bin: No such file or directory

Fix

The script-location resolver now walks the symlink chain one hop at a time, cd-ing into each link's directory before reading the next target, then canonicalizes the final directory. This replaces the previous single readlink resolution.

Why It Works

  • Correct relative resolution: enters each link's directory before reading the next target, so relative symlinks resolve against the link, not the CWD.
  • CWD-independent: finalized with cd -P … && pwd for an absolute, canonical path.
  • Portable: POSIX-only (readlink, ${var%/*}, cd -P, pwd) — no readlink -f/realpath.
  • Safe: runs in a subshell with CDPATH= cleared; no leaked cd or stray output.

Validation

Regression test confirms a relative symlink launched from another directory exits 0 and reports the installed CLI version.

Scope & Risk

One resolution block; no install/download changes. Direct execution and absolute symlinks are unchanged. Low risk, plus improved cross-platform portability.

Credits

Thanks to @klmr for the portable POSIX symlink-resolution approach.

@V-Subhankar-infy V-Subhankar-infy changed the title Fix relative symlink resolution in install script fix: relative symlink resolution in install script Jun 11, 2026
@V-Subhankar-infy V-Subhankar-infy marked this pull request as ready for review June 14, 2026 09:37
@V-Subhankar-infy V-Subhankar-infy requested a review from a team as a code owner June 14, 2026 09:37
@V-Subhankar-infy V-Subhankar-infy marked this pull request as draft June 19, 2026 10:05
@klmr

klmr commented Jun 19, 2026

Copy link
Copy Markdown

Beware that readlink -f support has only been added to macOS fairly recently. A portable alternative is much more convoluted, alas:

--- a/devcontainer      2026-06-19 15:12:58
+++ b/devcontainer      2026-06-19 15:13:11
@@ -6,15 +6,22 @@

 # Resolve the installation directory
 # Handle both direct execution and symlinked scenarios
-if [ -L "$0" ]; then
-    # Follow symlink
-    SCRIPT_PATH="$(readlink "$0" 2>/dev/null || readlink -f "$0" 2>/dev/null || echo "$0")"
-else
-    SCRIPT_PATH="$0"
-fi
-
-# Get absolute path to script directory
-SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
+SCRIPT_DIR="$(
+    CDPATH=
+    self=$0
+
+    while [ -L "$self" ]; do
+        cd -- "${self%/*}" >/dev/null || :
+        self=$(readlink "${self##*/}")
+    done
+
+    case "$self" in
+        (*/*) ;;
+        (*) self=./$self ;;
+    esac
+
+    cd -P -- "${self%/*}" >/dev/null && pwd
+)"
 INSTALL_DIR="$(dirname "$SCRIPT_DIR")"

 # Paths to bundled components

(Reference/explanation: https://stackoverflow.com/a/246128/1968)

@V-Subhankar-infy V-Subhankar-infy force-pushed the main branch 3 times, most recently from d34e588 to e612da1 Compare June 22, 2026 10:20
@V-Subhankar-infy V-Subhankar-infy marked this pull request as ready for review July 13, 2026 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install.sh wrapper relative link not resolved correctly

2 participants