Skip to content

Fix library collision in Termux by isolating binaries in opt/agy/bin#15

Open
Manamama-Gemini-Cloud-AI-01 wants to merge 1 commit into
wallentx:devfrom
Manamama-Gemini-Cloud-AI-01:fix/library-collision-termux
Open

Fix library collision in Termux by isolating binaries in opt/agy/bin#15
Manamama-Gemini-Cloud-AI-01 wants to merge 1 commit into
wallentx:devfrom
Manamama-Gemini-Cloud-AI-01:fix/library-collision-termux

Conversation

@Manamama-Gemini-Cloud-AI-01

Copy link
Copy Markdown

Problem

The current installer places both agy (wrapper) and agy.va39 (glibc binary) directly into ${PREFIX}/bin/.
The agy wrapper resolves its location and adds ../lib to the library search path.
In Termux, ${PREFIX}/bin/../lib is ${PREFIX}/lib/, which contains dummy placeholder libraries (like libpthread.so.0) used for Android compatibility.
These files are linker scripts (a few bytes long), causing the glibc loader to fail with:
error while loading shared libraries: .../lib/libpthread.so.0: file too short

Solution

This PR modifies the installer to:

  1. Install the real binaries into a dedicated directory: ${PREFIX}/opt/agy/bin/.
  2. Create a symlink at ${PREFIX}/bin/agy pointing to the wrapper.
  3. Ensure no real agy.va39 exists in the system bin/ directory.

Since the wrapper resolves its real path via readlink("/proc/self/exe"), it will look for libraries in ${PREFIX}/opt/agy/lib/. Since that directory is empty, it correctly falls back to the glibc system libraries in ${PREFIX}/glibc/lib/, avoiding the collision with Termux's system libraries.

This fix directly addresses the failures reported in issue #10.

Moving binaries to a dedicated directory (opt/agy/bin) and symlinking the wrapper prevents the relative library search from hitting Termux's dummy libraries in /usr/lib.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the installation script to install the agy and agy.va39 binaries into an internal directory (INTERNAL_BIN_DIR) and creates a symlink for agy in the public binary directory (INSTALL_BIN_DIR) to prevent RPATH collisions. A critical issue was identified where the backup and rollback mechanism fails during upgrades because it only backs up the symlink rather than the actual binaries, potentially leaving users with a broken installation if the upgrade fails. A layout-aware backup and rollback solution has been suggested.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread install.sh
Comment on lines +349 to 355
mkdir -p "$INTERNAL_BIN_DIR" || die "Failed to create directory $INTERNAL_BIN_DIR"
install -m 0755 "$EXTRACT_DIR/bin/agy" "$INTERNAL_BIN_DIR/agy" || die "Failed to install agy binary to $INTERNAL_BIN_DIR"
install -m 0755 "$EXTRACT_DIR/bin/agy.va39" "$INTERNAL_BIN_DIR/agy.va39" || die "Failed to install agy.va39 binary to $INTERNAL_BIN_DIR"
ln -sf "$INTERNAL_BIN_DIR/agy" "$INSTALL_BIN_DIR/agy" || die "Failed to create symlink in $INSTALL_BIN_DIR"
# Ensure the secondary binary is not in the system bin to avoid RPATH collision
[[ -f "$INSTALL_BIN_DIR/agy.va39" ]] && rm -f "$INSTALL_BIN_DIR/agy.va39"
rm -rf "$EXTRACT_DIR"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Issue: Broken Backup and Rollback during Upgrades

When upgrading from a previous installation that already uses the new layout:

  1. $INSTALL_BIN_DIR/agy is a symbolic link pointing to $INTERNAL_BIN_DIR/agy.
  2. The backup logic on lines 340-343 checks [[ -f "$INSTALL_BIN_DIR/agy" ]] (which resolves to true because the symlink target exists) and moves the symlink itself to $AGY_BAK.
  3. The actual binaries in $INTERNAL_BIN_DIR/agy and $INTERNAL_BIN_DIR/agy.va39 are not backed up.
  4. The installer then overwrites the real binaries in $INTERNAL_BIN_DIR with the new versions.
  5. If the installation fails or is cancelled later (e.g., during verification or the version test), the cleanup function attempts to restore $AGY_BAK to $INSTALL_BIN_DIR/agy. This merely restores the old symlink pointing to the newly overwritten (and potentially broken/failed) binary in $INTERNAL_BIN_DIR, leaving the user with a broken installation.

Solution:

Redefine the cleanup function dynamically within this block to be layout-aware, back up the internal binaries if they exist, and ensure they are correctly restored or cleaned up on failure.

INTERNAL_AGY_BAK=""
INTERNAL_AGY_VA39_BAK=""
cleanup() {
  printf "\033[?25h"
  [[ -n "${TMP_LOGO:-}" && -f "$TMP_LOGO" ]] && rm -f "$TMP_LOGO"
  [[ -n "${GLIBC_LOG:-}" && -f "$GLIBC_LOG" ]] && rm -f "$GLIBC_LOG"
  [[ -n "${GLIBC_PCT:-}" && -f "$GLIBC_PCT" ]] && rm -f "$GLIBC_PCT"
  [[ -d "$EXTRACT_DIR" ]] && rm -rf "$EXTRACT_DIR"
  if [[ "${INSTALL_SUCCESS:-0}" -ne 1 ]]; then
    [[ -f "$TMP" ]] && rm -f "$TMP"
    if [[ -n "${AGY_BAK:-}" && -f "$AGY_BAK" && -z "${INTERNAL_AGY_BAK:-}" ]]; then
      mv -f "$AGY_BAK" "$INSTALL_BIN_DIR/agy" || true
      [[ -n "${AGY_VA39_BAK:-}" && -f "$AGY_VA39_BAK" ]] && mv -f "$AGY_VA39_BAK" "$INSTALL_BIN_DIR/agy.va39" || true
    elif [[ -n "${INTERNAL_AGY_BAK:-}" && -f "$INTERNAL_AGY_BAK" ]]; then
      rm -f "$INSTALL_BIN_DIR/agy" "$INSTALL_BIN_DIR/agy.va39"
      mv -f "$INTERNAL_AGY_BAK" "$INTERNAL_BIN_DIR/agy" || true
      [[ -n "${INTERNAL_AGY_VA39_BAK:-}" && -f "$INTERNAL_AGY_VA39_BAK" ]] && mv -f "$INTERNAL_AGY_VA39_BAK" "$INTERNAL_BIN_DIR/agy.va39" || true
      ln -sf "$INTERNAL_BIN_DIR/agy" "$INSTALL_BIN_DIR/agy" || true
      [[ -n "${AGY_BAK:-}" && -f "$AGY_BAK" ]] && rm -f "$AGY_BAK" || true
    else
      rm -f "$INSTALL_BIN_DIR/agy" "$INSTALL_BIN_DIR/agy.va39"
      rm -f "$INTERNAL_BIN_DIR/agy" "$INTERNAL_BIN_DIR/agy.va39"
      rmdir "$INTERNAL_BIN_DIR" 2>/dev/null || true
    fi
  else
    [[ -n "${AGY_BAK:-}" && -f "$AGY_BAK" ]] && rm -f "$AGY_BAK" || true
    [[ -n "${AGY_VA39_BAK:-}" && -f "$AGY_VA39_BAK" ]] && rm -f "$AGY_VA39_BAK" || true
    [[ -n "${INTERNAL_AGY_BAK:-}" && -f "$INTERNAL_AGY_BAK" ]] && rm -f "$INTERNAL_AGY_BAK" || true
    [[ -n "${INTERNAL_AGY_VA39_BAK:-}" && -f "$INTERNAL_AGY_VA39_BAK" ]] && rm -f "$INTERNAL_AGY_VA39_BAK" || true
  fi
}

mkdir -p "$INTERNAL_BIN_DIR" || die "Failed to create directory $INTERNAL_BIN_DIR"
if [[ -f "$INTERNAL_BIN_DIR/agy" ]]; then
  INTERNAL_AGY_BAK="$INTERNAL_BIN_DIR/agy.bak.$$"
  mv -f "$INTERNAL_BIN_DIR/agy" "$INTERNAL_AGY_BAK" || die "Failed to back up existing agy binary from $INTERNAL_BIN_DIR"
fi
if [[ -f "$INTERNAL_BIN_DIR/agy.va39" ]]; then
  INTERNAL_AGY_VA39_BAK="$INTERNAL_BIN_DIR/agy.va39.bak.$$"
  mv -f "$INTERNAL_BIN_DIR/agy.va39" "$INTERNAL_AGY_VA39_BAK" || die "Failed to back up existing agy.va39 binary from $INTERNAL_BIN_DIR"
fi

install -m 0755 "$EXTRACT_DIR/bin/agy" "$INTERNAL_BIN_DIR/agy" || die "Failed to install agy binary to $INTERNAL_BIN_DIR"
install -m 0755 "$EXTRACT_DIR/bin/agy.va39" "$INTERNAL_BIN_DIR/agy.va39" || die "Failed to install agy.va39 binary to $INTERNAL_BIN_DIR"
ln -sf "$INTERNAL_BIN_DIR/agy" "$INSTALL_BIN_DIR/agy" || die "Failed to create symlink in $INSTALL_BIN_DIR"
[[ -f "$INSTALL_BIN_DIR/agy.va39" ]] && rm -f "$INSTALL_BIN_DIR/agy.va39"
rm -rf "$EXTRACT_DIR"

@Manamama

Manamama commented Jun 8, 2026

Copy link
Copy Markdown

Human here. Re:

The current installer places both agy (wrapper) and agy.va39 (glibc binary) directly into ${PREFIX}/bin/.

not exactly, they before this PR land in some ./bin/agy , e.g.:

ls -la ~/Downloads/bin/ && file ~/Downloads/bin/agy*                          │
│                                                                                        │
│ ... first 3 lines hidden (Ctrl+O to show) ...                                          │
│ -rwx------.  1 u0_a278 u0_a278     18416 Jun  4 02:50 agy                              │
│ -rwx------.  1 u0_a278 u0_a278 158879496 Jun  4 02:50 agy.va39 

relative to $(pwd), methinks, but indeed, the above is not in default $PATH, hence this PR

@wallentx

wallentx commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Human here. Re:

The current installer places both agy (wrapper) and agy.va39 (glibc binary) directly into ${PREFIX}/bin/.

not exactly, they before this PR land in some ./bin/agy , e.g.:

ls -la ~/Downloads/bin/ && file ~/Downloads/bin/agy*                          │
│                                                                                        │
│ ... first 3 lines hidden (Ctrl+O to show) ...                                          │
│ -rwx------.  1 u0_a278 u0_a278     18416 Jun  4 02:50 agy                              │
│ -rwx------.  1 u0_a278 u0_a278 158879496 Jun  4 02:50 agy.va39 

relative to $(pwd), methinks, but indeed, the above is not in default $PATH, hence this PR

@Manamama Thanks! Since we've figured out that the official agy seems to work on proot, I'm considering shifting things to simplify our patch, as well as install.sh so that we don't have to worry about proot. I believe that this will resolve the collision that you are reporting, but I want to test it in a clean termux setup. I'm going to try to get a termux that will run in a container to execute in CI so we can catch things like this.

I'll do some local testing first and see what I come up with before making any changes to the repo, and I want to hold on merging anything that might impact anyone currently using this that would break their agy upgrade path. I'll report back with what I find.

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.

3 participants