diff -r 787e7caf887a -r cf4d2f31660d contrib/chg/chg.c --- a/contrib/chg/chg.c Fri Apr 07 12:11:44 2023 +0200 +++ b/contrib/chg/chg.c Mon Mar 27 17:30:14 2023 -0400 @@ -232,12 +232,17 @@ hgcmd = "hg"; #endif } + /* Set $CHGHG to the path to the seleted hg executable if it wasn't + * already set. This has the effect of ensuring that a new command + * server will be spawned if the existing command server is running from + * an executable at a different path. */ + if (setenv("CHGHG", hgcmd, 1) != 0) + abortmsgerrno("failed to setenv"); return hgcmd; } -static void execcmdserver(const struct cmdserveropts *opts) +static void execcmdserver(const char *hgcmd, const struct cmdserveropts *opts) { - const char *hgcmd = gethgcmd(); const char *baseargv[] = { hgcmd, "serve", "--no-profile", "--cmdserver", @@ -375,11 +380,16 @@ debugmsg("start cmdserver at %s", opts->initsockname); + /* Get the path to the hg executable before we fork because this + * function might update the environment, and we want this to be + * reflected in both the parent and child processes. */ + const char *hgcmd = gethgcmd(); + pid_t pid = fork(); if (pid < 0) abortmsg("failed to fork cmdserver process"); if (pid == 0) { - execcmdserver(opts); + execcmdserver(hgcmd, opts); } else { hgc = retryconnectcmdserver(opts, pid); } @@ -484,7 +494,7 @@ abortmsgerrno("failed to exec original hg"); } -int main(int argc, const char *argv[], const char *envp[]) +int main(int argc, const char *argv[]) { if (getenv("CHGDEBUG")) enabledebugmsg(); @@ -519,7 +529,10 @@ hgc = connectcmdserver(&opts); if (!hgc) abortmsg("cannot open hg client"); - hgc_setenv(hgc, envp); + /* Use `environ(7)` instead of the optional `envp` argument to + * `main` because `envp` does not update when the environment + * changes, but `environ` does. */ + hgc_setenv(hgc, (const char *const *)environ); const char **insts = hgc_validate(hgc, argv + 1, argc - 1); int needreconnect = runinstructions(&opts, insts); free(insts);