-
Notifications
You must be signed in to change notification settings - Fork 10.4k
feat(zsh-fork): update patch to support command origins #12053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Build the Codex-patched zsh used by shell-tool-mcp. | ||
| # | ||
| # Defaults are intentionally override-friendly: | ||
| # CODEX_REPO Codex repo root containing shell-tool-mcp/patches | ||
| # ZSH_SRC_DIR Working clone location for zsh source | ||
| # INSTALL_PREFIX Install prefix for make install | ||
| # JOBS Parallel jobs for make | ||
| # ZSH_REMOTE Upstream zsh remote | ||
| # INSTALL_DOCS Set to 1 to run full `make install` (includes manpages) | ||
|
|
||
| ZSH_COMMIT="77045ef899e53b9598bebc5a41db93a548a40ca6" | ||
| ZSH_REMOTE="${ZSH_REMOTE:-https://git.code.sf.net/p/zsh/code}" | ||
| INSTALL_PREFIX="${INSTALL_PREFIX:-$HOME/.local/codex-zsh-${ZSH_COMMIT:0:7}}" | ||
|
|
||
| SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" | ||
|
|
||
| resolve_codex_repo() { | ||
| if [[ -n "${CODEX_REPO:-}" ]]; then | ||
| printf '%s\n' "$CODEX_REPO" | ||
| return | ||
| fi | ||
|
|
||
| # Most reliable when this script is run from inside the codex repo. | ||
| local from_script | ||
| from_script="$(cd -- "$SCRIPT_DIR/.." && pwd)" | ||
| if [[ -f "$from_script/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then | ||
| printf '%s\n' "$from_script" | ||
| return | ||
| fi | ||
|
|
||
| # Common local workspace layouts. | ||
| if [[ -f "$HOME/repos/codex/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then | ||
| printf '%s\n' "$HOME/repos/codex" | ||
| return | ||
| fi | ||
|
|
||
| if [[ -f "$HOME/code/codex/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then | ||
| printf '%s\n' "$HOME/code/codex" | ||
| return | ||
| fi | ||
|
|
||
| echo "Could not locate codex repo. Set CODEX_REPO=/path/to/codex." >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| resolve_zsh_src_dir() { | ||
| if [[ -n "${ZSH_SRC_DIR:-}" ]]; then | ||
| printf '%s\n' "$ZSH_SRC_DIR" | ||
| return | ||
| fi | ||
|
|
||
| if [[ -d "$HOME/repos/zsh/.git" ]]; then | ||
| printf '%s\n' "$HOME/repos/zsh" | ||
| return | ||
| fi | ||
|
|
||
| if [[ -d "$HOME/code/zsh/.git" ]]; then | ||
| printf '%s\n' "$HOME/code/zsh" | ||
| return | ||
| fi | ||
|
|
||
| # Fallback for users without an existing clone. | ||
| printf '%s\n' "$HOME/src/zsh-code" | ||
| } | ||
|
|
||
| CODEX_REPO="$(resolve_codex_repo)" | ||
| ZSH_SRC_DIR="$(resolve_zsh_src_dir)" | ||
| PATCH_FILE="$CODEX_REPO/shell-tool-mcp/patches/zsh-exec-wrapper.patch" | ||
|
|
||
| if [[ ! -f "$PATCH_FILE" ]]; then | ||
| echo "Patch file not found: $PATCH_FILE" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ -z "${JOBS:-}" ]]; then | ||
| if command -v nproc >/dev/null 2>&1; then | ||
| JOBS="$(nproc)" | ||
| elif command -v sysctl >/dev/null 2>&1; then | ||
| JOBS="$(sysctl -n hw.ncpu)" | ||
| else | ||
| JOBS=4 | ||
| fi | ||
| fi | ||
|
|
||
| mkdir -p "$(dirname -- "$ZSH_SRC_DIR")" | ||
|
|
||
| if [[ ! -d "$ZSH_SRC_DIR/.git" ]]; then | ||
| git clone "$ZSH_REMOTE" "$ZSH_SRC_DIR" | ||
| fi | ||
|
|
||
| git -C "$ZSH_SRC_DIR" fetch --depth 1 origin "$ZSH_COMMIT" | ||
| git -C "$ZSH_SRC_DIR" checkout --detach -f "$ZSH_COMMIT" | ||
| git -C "$ZSH_SRC_DIR" reset --hard "$ZSH_COMMIT" | ||
|
|
||
| if git -C "$ZSH_SRC_DIR" apply --reverse --check "$PATCH_FILE" >/dev/null 2>&1; then | ||
| echo "Patch already applied: $PATCH_FILE" | ||
| else | ||
| git -C "$ZSH_SRC_DIR" apply --check "$PATCH_FILE" | ||
| git -C "$ZSH_SRC_DIR" apply "$PATCH_FILE" | ||
| fi | ||
|
|
||
| ( | ||
| cd "$ZSH_SRC_DIR" | ||
| ./Util/preconfig | ||
| ./configure --prefix="$INSTALL_PREFIX" | ||
| make -j"$JOBS" | ||
| if [[ "${INSTALL_DOCS:-0}" == "1" ]]; then | ||
| make install | ||
| else | ||
| make install.bin | ||
| fi | ||
| ) | ||
|
|
||
| cat <<OUT | ||
|
|
||
| Built patched zsh successfully. | ||
| Binary: | ||
| $INSTALL_PREFIX/bin/zsh | ||
|
|
||
| Quick checks: | ||
| $INSTALL_PREFIX/bin/zsh --version | ||
| $INSTALL_PREFIX/bin/zsh -fc '/bin/echo smoke-zsh' | ||
| OUT | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,228 @@ | ||
| diff --git a/Src/exec.c b/Src/exec.c | ||
| index 27bca11..baea760 100644 | ||
| index 27bca110c..4e5000be3 100644 | ||
| --- a/Src/exec.c | ||
| +++ b/Src/exec.c | ||
| @@ -507,7 +507,9 @@ zexecve(char *pth, char **argv, char **newenvp) | ||
| @@ -507,7 +507,12 @@ zexecve(char *pth, char **argv, char **newenvp) | ||
| { | ||
| int eno; | ||
| static char buf[PATH_MAX * 2+1]; | ||
| - char **eep; | ||
| + char **eep, **exec_argv; | ||
| + char **eep, **exec_argv, **wrapper_envp; | ||
| + char *orig_pth = pth; | ||
| + char *exec_wrapper; | ||
| + char wrapper_origin_buf[64]; | ||
| + int wrapper_origin_len; | ||
| + int wrapper_envc, wrapper_origin_idx; | ||
|
|
||
| unmetafy(pth, NULL); | ||
| for (eep = argv; *eep; eep++) | ||
| @@ -526,8 +528,17 @@ zexecve(char *pth, char **argv, char **newenvp) | ||
| @@ -526,8 +531,51 @@ zexecve(char *pth, char **argv, char **newenvp) | ||
|
|
||
| if (newenvp == NULL) | ||
| newenvp = environ; | ||
| + exec_argv = argv; | ||
| + /* Use the command env by default; wrapper mode may replace this with an | ||
| + * explicitly rebuilt envp so origin metadata is guaranteed to be present | ||
| + * even when execve does not use the process-global environ. */ | ||
| + wrapper_envp = newenvp; | ||
| + if ((exec_wrapper = getenv("EXEC_WRAPPER")) && | ||
| + *exec_wrapper && !inblank(*exec_wrapper)) { | ||
| + /* zexecve callers provide spare argv slots before argv[0] for | ||
| + * interpreter dispatch; reuse those slots to trampoline through the | ||
| + * wrapper binary while preserving the original target path. */ | ||
| + exec_argv = argv - 2; | ||
| + exec_argv[0] = exec_wrapper; | ||
| + exec_argv[1] = orig_pth; | ||
| + wrapper_origin_len = sprintf(wrapper_origin_buf, | ||
| + "CODEX_ZSH_EXEC_BRIDGE_WRAPPER_ORIGIN=%d", | ||
| + zsh_exec_wrapper_origin); | ||
| + if (wrapper_origin_len > 0 && | ||
| + wrapper_origin_len < (int)sizeof(wrapper_origin_buf)) { | ||
| + wrapper_envc = 0; | ||
| + wrapper_origin_idx = -1; | ||
| + for (eep = newenvp; *eep; eep++) { | ||
| + if (strncmp(*eep, "CODEX_ZSH_EXEC_BRIDGE_WRAPPER_ORIGIN=", | ||
| + sizeof("CODEX_ZSH_EXEC_BRIDGE_WRAPPER_ORIGIN=") - 1) == 0) | ||
| + wrapper_origin_idx = wrapper_envc; | ||
| + wrapper_envc++; | ||
| + } | ||
| + wrapper_envp = zalloc((wrapper_envc + 2) * sizeof(char *)); | ||
| + if (wrapper_origin_idx >= 0) { | ||
| + for (wrapper_envc = 0; newenvp[wrapper_envc]; wrapper_envc++) | ||
| + wrapper_envp[wrapper_envc] = | ||
| + wrapper_envc == wrapper_origin_idx ? | ||
| + wrapper_origin_buf : newenvp[wrapper_envc]; | ||
| + wrapper_envp[wrapper_envc] = NULL; | ||
| + } else { | ||
| + for (wrapper_envc = 0; newenvp[wrapper_envc]; wrapper_envc++) | ||
| + wrapper_envp[wrapper_envc] = newenvp[wrapper_envc]; | ||
| + wrapper_envp[wrapper_envc++] = wrapper_origin_buf; | ||
| + wrapper_envp[wrapper_envc] = NULL; | ||
| + } | ||
| + } | ||
| + pth = exec_wrapper; | ||
| + } | ||
| winch_unblock(); | ||
| - execve(pth, argv, newenvp); | ||
| + execve(pth, exec_argv, newenvp); | ||
| + execve(pth, exec_argv, wrapper_envp); | ||
| + pth = orig_pth; | ||
|
|
||
| /* If the execve returns (which in general shouldn't happen), * | ||
| * then check for an errno equal to ENOEXEC. This errno is set * | ||
| diff --git a/Src/init.c b/Src/init.c | ||
| index 20b8cc7fd..b6d5c9c9a 100644 | ||
| --- a/Src/init.c | ||
| +++ b/Src/init.c | ||
| @@ -59,6 +59,9 @@ int underscoreused; | ||
| /**/ | ||
| int sourcelevel; | ||
|
|
||
| +/**/ | ||
| +int zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; | ||
| + | ||
| /* the shell tty fd */ | ||
|
|
||
| /**/ | ||
| @@ -1450,14 +1453,25 @@ init_signals(void) | ||
| void | ||
| run_init_scripts(void) | ||
| { | ||
| + int old_origin; | ||
| + | ||
| noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_SIGNAL; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; | ||
|
|
||
| if (EMULATION(EMULATE_KSH|EMULATE_SH)) { | ||
| - if (islogin) | ||
| + if (islogin) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| source("/etc/profile"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| if (unset(PRIVILEGED)) { | ||
| - if (islogin) | ||
| + if (islogin) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| sourcehome(".profile"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
|
|
||
| if (interact) { | ||
| noerrs = 2; | ||
| @@ -1467,16 +1481,26 @@ run_init_scripts(void) | ||
| if (!parsestr(&s)) { | ||
| singsub(&s); | ||
| noerrs = 0; | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; | ||
| source(s); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| } | ||
| } | ||
| noerrs = 0; | ||
| } | ||
| - } else | ||
| + } else { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| source("/etc/suid_profile"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| } else { | ||
| #ifdef GLOBAL_ZSHENV | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; | ||
| source(GLOBAL_ZSHENV); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| #endif | ||
|
|
||
| if (isset(RCS) && unset(PRIVILEGED)) | ||
| @@ -1492,33 +1516,61 @@ run_init_scripts(void) | ||
| } | ||
| } | ||
|
|
||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; | ||
| sourcehome(".zshenv"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| } | ||
| if (islogin) { | ||
| #ifdef GLOBAL_ZPROFILE | ||
| - if (isset(RCS) && isset(GLOBALRCS)) | ||
| + if (isset(RCS) && isset(GLOBALRCS)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| source(GLOBAL_ZPROFILE); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| #endif | ||
| - if (isset(RCS) && unset(PRIVILEGED)) | ||
| + if (isset(RCS) && unset(PRIVILEGED)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| sourcehome(".zprofile"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| } | ||
| if (interact) { | ||
| #ifdef GLOBAL_ZSHRC | ||
| - if (isset(RCS) && isset(GLOBALRCS)) | ||
| + if (isset(RCS) && isset(GLOBALRCS)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; | ||
| source(GLOBAL_ZSHRC); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| #endif | ||
| - if (isset(RCS) && unset(PRIVILEGED)) | ||
| + if (isset(RCS) && unset(PRIVILEGED)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; | ||
| sourcehome(".zshrc"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| } | ||
| if (islogin) { | ||
| #ifdef GLOBAL_ZLOGIN | ||
| - if (isset(RCS) && isset(GLOBALRCS)) | ||
| + if (isset(RCS) && isset(GLOBALRCS)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| source(GLOBAL_ZLOGIN); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| #endif | ||
| - if (isset(RCS) && unset(PRIVILEGED)) | ||
| + if (isset(RCS) && unset(PRIVILEGED)) { | ||
| + old_origin = zsh_exec_wrapper_origin; | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; | ||
| sourcehome(".zlogin"); | ||
| + zsh_exec_wrapper_origin = old_origin; | ||
| + } | ||
| } | ||
| } | ||
| + zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; | ||
| noerrexit = 0; | ||
| nohistsave = 0; | ||
| } | ||
| diff --git a/Src/zsh.h b/Src/zsh.h | ||
| index 5bda04e88..c0750cf45 100644 | ||
| --- a/Src/zsh.h | ||
| +++ b/Src/zsh.h | ||
| @@ -2215,6 +2215,14 @@ enum source_return { | ||
| SOURCE_ERROR = 2 | ||
| }; | ||
|
|
||
| +enum exec_wrapper_origin { | ||
| + EXEC_WRAPPER_ORIGIN_USER_COMMAND = 0, | ||
| + EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP = 1, | ||
| + EXEC_WRAPPER_ORIGIN_RC_STARTUP = 2 | ||
| +}; | ||
| + | ||
| +extern int zsh_exec_wrapper_origin; | ||
| + | ||
| enum noerrexit_bits { | ||
| /* Suppress ERR_EXIT and traps: global */ | ||
| NOERREXIT_EXIT = 1, |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script advertises
ZSH_REMOTEas an override, but the fetch step is hardcoded toorigin. IfZSH_SRC_DIRalready exists andoriginpoints elsewhere (or lacks the pinned commit), the build fails or fetches from the wrong upstream. This makes the documented override ineffective for common existing-clone workflows.Useful? React with 👍 / 👎.