install + llama_cpp backend: cycle-24 hardening

Three real findings from cycle 24 reviewers:

1. install.sh:231 + studio/setup.sh:413 -- main \$STUDIO_HOME
   resolvers used the same bare \`cd -- ... && pwd\` form that cycle 23
   only fixed for the --tauri guard. Switch both to:
       \$(CDPATH= cd -P -- "\$override" && pwd -P)
   so relative custom-root values don't get CDPATH-prefixed or have
   the cd-on-CDPATH stdout newline contaminate the captured value.

2. install.sh --tauri legacy root used logical \$HOME/.unsloth/studio
   while the override side was canonicalized via pwd -P. A symlinked
   \$HOME (e.g. /home/alice -> /u/alice) made the comparison fail even
   when both sides pointed at the same directory. Canonicalize the
   legacy side too when the dir exists.

3. studio/backend/core/inference/llama_cpp.py:_find_llama_server_binary
   searched \$STUDIO_HOME/llama.cpp first then ~/.unsloth/llama.cpp
   in default-mode installs. setup.sh / setup.ps1 only install llama.cpp
   under \$STUDIO_HOME/llama.cpp in env-override mode; in default mode
   it always lives at ~/.unsloth/llama.cpp. The post-PR search would
   pick up a stale partial install at ~/.unsloth/studio/llama.cpp over
   the real legacy binary.

   Mirror setup's legacy-equality check: when studio_root() resolves
   equal to ~/.unsloth/studio, search ONLY the legacy ~/.unsloth/llama.cpp.
   Otherwise (env-override custom root), search custom first, legacy
   fallback.
This commit is contained in:
Daniel Han 2026-04-26 22:43:38 +00:00
commit 1103f34699
3 changed files with 30 additions and 10 deletions

View file

@ -101,6 +101,13 @@ if [ "$TAURI_MODE" = true ]; then
_tauri_override_abs=${_tauri_override_abs%/}
done
_tauri_legacy_root="$HOME/.unsloth/studio"
# Apply the same physical-path canonicalization to the legacy root
# so a symlinked $HOME (e.g. /home/alice -> /u/alice) doesn't make
# the comparison fail when both sides point at the same directory.
if [ -d "$_tauri_legacy_root" ]; then
_tauri_legacy_root=$(CDPATH= cd -P -- "$_tauri_legacy_root" 2>/dev/null && pwd -P) \
|| _tauri_legacy_root="$HOME/.unsloth/studio"
fi
while [ "$_tauri_legacy_root" != "/" ] \
&& [ "${_tauri_legacy_root%/}" != "$_tauri_legacy_root" ]; do
_tauri_legacy_root=${_tauri_legacy_root%/}
@ -228,7 +235,9 @@ _resolve_studio_destinations() {
if [ -n "$_override" ]; then
mkdir -p -- "$_override" 2>/dev/null || { echo "ERROR: STUDIO_HOME=$_override cannot be created." >&2; exit 1; }
[ -w "$_override" ] || { echo "ERROR: STUDIO_HOME=$_override is not writable." >&2; exit 1; }
STUDIO_HOME="$(cd -- "$_override" && pwd)" || exit 1
# CDPATH= prevents `cd` from echoing a CDPATH-prefixed path on stdout
# if the user has CDPATH set; -P / pwd -P canonicalizes symlinks.
STUDIO_HOME="$(CDPATH= cd -P -- "$_override" && pwd -P)" || exit 1
DATA_DIR="$STUDIO_HOME/share"
_LOCAL_BIN="$STUDIO_HOME/bin"
_STUDIO_HOME_REDIRECT=env

View file

@ -491,17 +491,27 @@ class LlamaCppBackend:
if win_bin.is_file():
return str(win_bin)
# 2-4. Search both the resolved Studio root (custom installs) AND
# the legacy ~/.unsloth/llama.cpp. setup.sh / setup.ps1 install
# under $STUDIO_HOME/llama.cpp when env-override is active and
# under ~/.unsloth/llama.cpp for default installs.
# 2-4. Mirror setup.sh / setup.ps1's install layout:
# - In env-override mode (custom Studio root != legacy default),
# llama.cpp is installed under $STUDIO_HOME/llama.cpp.
# - Otherwise (default install or HOME redirect), llama.cpp is
# installed at ~/.unsloth/llama.cpp (sibling of the Studio dir).
# Default-mode searches must NOT look at $STUDIO_HOME/llama.cpp,
# to avoid picking a stale partial install from a previous failed
# install over the real legacy binary.
legacy_llama = Path.home() / ".unsloth" / "llama.cpp"
try:
from utils.paths.storage_roots import studio_root as _sr # noqa: WPS433
search_roots = [_sr() / "llama.cpp", Path.home() / ".unsloth" / "llama.cpp"]
except ImportError:
search_roots = [Path.home() / ".unsloth" / "llama.cpp"]
# De-dupe while preserving order (in case studio_root() == legacy).
_resolved_sr = _sr()
_legacy_studio = Path.home() / ".unsloth" / "studio"
if _resolved_sr.resolve() == _legacy_studio.resolve():
search_roots = [legacy_llama]
else:
search_roots = [_resolved_sr / "llama.cpp", legacy_llama]
except (ImportError, OSError, ValueError):
search_roots = [legacy_llama]
# De-dupe while preserving order (defensive in case both resolve equal).
_seen: set[str] = set()
for unsloth_home in [
r for r in search_roots if str(r) not in _seen and not _seen.add(str(r))

View file

@ -410,7 +410,8 @@ case "$_studio_override" in
esac
if [ -n "$_studio_override" ]; then
mkdir -p -- "$_studio_override"
STUDIO_HOME="$(cd -- "$_studio_override" && pwd)" || exit 1
# CDPATH= prevents CDPATH-prefixed echo; -P canonicalizes symlinks.
STUDIO_HOME="$(CDPATH= cd -P -- "$_studio_override" && pwd -P)" || exit 1
else
STUDIO_HOME="$HOME/.unsloth/studio"
fi