summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/params.yo4
-rw-r--r--Src/init.c117
-rw-r--r--configure.ac19
4 files changed, 145 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 32fd0780d..b2c847da5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 2db4210eb..57d10b8bd 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -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
diff --git a/Src/init.c b/Src/init.c
index 7e98af44c..ffb017e22 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -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)
diff --git a/configure.ac b/configure.ac
index e6ced85d9..d8a17791a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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 ---------------------------------