51639: new parameter ZSH_EXEPATH (full path of zsh executable)

The full pathname is obatined by a reliable method on macOS and systems
that support procfs. But on other systems (FreeBSD, OpenBSD, ...) it is
guessed from argv[0], PWD and PATH.
master
Jun-ichi Takimoto 1 year ago
parent 8a9aea907a
commit e5f8cc99f5

@ -1,3 +1,9 @@
2023-04-11 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
* 51639: Doc/Zsh/params.yo, Src/init.c, configure.ac: add new
parameter ZSH_EXEPATH that is set to the full pathname of the
executable file of the current zsh
2023-04-09 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
* 51631: Doc/Zsh/params.yo, Src/init.c: initialize $_ by copying

@ -1112,6 +1112,10 @@ item(tt(ZSH_EXECUTION_STRING))(
If the shell was started with the option tt(-c), this contains
the argument passed to the option. Otherwise it is not set.
)
vindex(ZSH_EXEPATH)
item(tt(ZSH_EXEPATH))(
Full pathname of the executable file of the current zsh process.
)
vindex(ZSH_NAME)
item(tt(ZSH_NAME))(
Expands to the basename of the command used to invoke this instance

@ -246,6 +246,9 @@ loop(int toplevel, int justonce)
static int restricted;
/* original argv[0]. This is already metafied */
static char *argv0;
/**/
static void
parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
@ -257,7 +260,7 @@ parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
if (**argv == '-')
flags |= PARSEARGS_LOGIN;
argzero = posixzero = *argv++;
argv0 = argzero = posixzero = *argv++;
SHIN = 0;
/*
@ -893,6 +896,106 @@ init_term(void)
return 1;
}
/*
* Get (or guess) the absolute pathname of the current zsh exeutable.
* Try OS-specific method, and if it fails, guess the absolute pathname
* from argv0, pwd, and PATH. 'name' and 'cwd' are unmetefied versions of
* argv0 and pwd.
* Returns a zalloc()ed string (not metafied), or NULL if failed.
*/
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
/**/
static char *
getmypath(const char *name, const char *cwd)
{
char *buf;
int namelen;
if (!name)
return NULL;
if (*name == '-')
++name;
if ((namelen = strlen(name)) == 0)
return NULL;
#if defined(__APPLE__)
{
uint32_t n = PATH_MAX;
int ret;
buf = (char *)zalloc(PATH_MAX);
if ((ret = _NSGetExecutablePath(buf, &n)) < 0) {
/* try again with increased buffer size */
buf = (char *)zrealloc(buf, n);
ret = _NSGetExecutablePath(buf, &n);
}
if (ret == 0 && strlen(buf) > 0)
return buf;
else
free(buf);
}
#elif defined(PROC_SELF_EXE)
{
ssize_t n;
buf = (char *)zalloc(PATH_MAX);
n = readlink(PROC_SELF_EXE, buf, PATH_MAX);
if (n > 0 && n < PATH_MAX) {
buf[n] = '\0';
return buf;
}
else
free(buf);
}
#endif
/* guess the absolute pathname of 'name' */
if (name[namelen-1] == '/') /* name should not end with '/' */
return NULL;
else if (name[0] == '/') {
/* name is already an absolute pathname */
return ztrdup(name);
}
else if (strchr(name, '/')) {
/* relative path */
if (!cwd)
return NULL;
buf = (char *)zalloc(strlen(cwd) + namelen + 2);
sprintf(buf, "%s/%s", cwd, name);
return buf;
}
#ifdef HAVE_REALPATH
else {
/* search each dir in PARH */
const char *path, *sep;
char *real, *try;
int pathlen, dirlen;
path = getenv("PATH");
if (!path || (pathlen = strlen(path)) == 0)
return NULL;
/* for simplicity, allocate buf even if REALPATH_ACCEPTS_NULL is on */
buf = (char *)zalloc(PATH_MAX);
try = (char *)zalloc(pathlen + namelen + 2);
do {
sep = strchr(path, ':');
dirlen = sep ? sep - path : strlen(path);
strncpy(try, path, dirlen);
try[dirlen] = '/';
try[dirlen+1] = '\0';
strcat(try, name);
real = realpath(try, buf);
if (sep)
path = sep + 1;
} while (!real && sep);
free(try);
if (!real)
free(buf);
return real; /* this may be NULL */
}
#endif
return NULL;
}
/* Initialize lots of global variables and hash tables */
/**/
@ -1195,6 +1298,18 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
/* Colour sequences for outputting colours in prompts and zle */
set_default_colour_sequences();
/* ZSH_EXEPATH */
{
char *mypath, *exename, *cwd;
exename = unmetafy(ztrdup(argv0), NULL);
cwd = pwd ? unmetafy(ztrdup(pwd), NULL) : NULL;
mypath = getmypath(exename, cwd);
free(exename);
free(cwd);
if (mypath) {
setsparam("ZSH_EXEPATH", metafy(mypath, -1, META_REALLOC));
}
}
if (cmd)
setsparam("ZSH_EXECUTION_STRING", ztrdup(cmd));
if (runscript)

@ -2011,6 +2011,25 @@ if test x$zsh_cv_sys_path_dev_fd != xno; then
AC_DEFINE_UNQUOTED(PATH_DEV_FD, "$zsh_cv_sys_path_dev_fd")
fi
dnl ----------------------------------------------------
dnl CHECK FOR SYMLINK TO THE CURRENT EXECUTABLE IN /proc
dnl ----------------------------------------------------
dnl Linux: /proc/self/exe
dnl NetBSD: /proc/curproc/exe (or /proc/self/exe, but not /proc/curproc/file)
dnl DragonFly: /proc/curproc/file
dnl Solaris: /proc/self/path/a.out
AH_TEMPLATE([PROC_SELF_EXE],
[Define to the path of the symlink to the current executable file.])
AC_CACHE_CHECK(for symlink to the current executable in /proc,
zsh_cv_proc_self_exe,
[for zsh_cv_proc_self_exe in /proc/self/exe /proc/curproc/exe \
/proc/curproc/file /proc/self/path/a.out no; do
test -L $zsh_cv_proc_self_exe && break
done])
if test x$zsh_cv_proc_self_exe != xno; then
AC_DEFINE_UNQUOTED(PROC_SELF_EXE, "$zsh_cv_proc_self_exe")
fi
dnl ---------------------------------
dnl CHECK FOR RFS SUPERROOT DIRECTORY
dnl ---------------------------------

Loading…
Cancel
Save