[PATCH] exec: Print absolute paths for command location queries

Kerin Millar <[email protected]> Sat, 6 Jun 2026 16:36:34 +0100
Newsgroups org.kernel.vger.dash
Message-ID <[email protected]>
POSIX requires that, when reporting the location of a utility found by
searching PATH (or one named with a slash), the pathname written by
type, command -v and command -V be absolute:

    Executable utilities, regular built-in utilities, command_names
    including a <slash> character, and any implementation-provided
    functions that are found using the PATH variable [...] shall be
    written as absolute pathnames.

Presently, dash fails to conform in this regard. Address this issue by
incorporating a helper function that prefixes relative pathnames with
the shell's cached current working directory.

Link: https://lore.kernel.org/dash/[email protected]/
Reported-by: Christoph Anton Mitterer <[email protected]>
Signed-off-by: Kerin Millar <[email protected]>
---
 src/cd.c   | 11 +++++++++++
 src/cd.h   |  1 +
 src/exec.c | 26 ++++++++++++++++++++++----
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/cd.c b/src/cd.c
index bcd1484..c044c3f 100644
--- a/src/cd.c
+++ b/src/cd.c
@@ -330,3 +330,14 @@ setpwd(const char *val, int setold)
 	INTON;
 	setvar("PWD", dir, VEXPORT);
 }
+
+/*
+ * Return the shell's notion of the current working directory.  Unlike the PWD
+ * variable, this cannot be altered by the user.
+ */
+
+const char *
+curpwd(void)
+{
+	return curdir;
+}
diff --git a/src/cd.h b/src/cd.h
index 8763161..2457e9c 100644
--- a/src/cd.h
+++ b/src/cd.h
@@ -33,3 +33,4 @@
 int	cdcmd(int, char **);
 int	pwdcmd(int, char **);
 void	setpwd(const char *, int);
+const char *curpwd(void);
diff --git a/src/exec.c b/src/exec.c
index 6fe0fed..006a241 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -58,6 +58,7 @@
 #include "redir.h"
 #include "eval.h"
 #include "exec.h"
+#include "cd.h"
 #include "builtins.h"
 #include "var.h"
 #include "options.h"
@@ -779,6 +780,24 @@ typecmd(int argc, char **argv)
 	return err;
 }
 
+/*
+ * Print the location of a command, as reported by type, command -v and
+ * command -V.  POSIX requires such pathnames to be absolute.
+ */
+
+static void printpath(struct output *out, const char *p)
+{
+	const char *pwd;
+
+	if (*p != '/' && *(pwd = curpwd()) == '/') {
+		outstr(pwd, out);
+		/* Do not append another slash to / or //. */
+		if (pwd[strlen(pwd) - 1] != '/')
+			outc('/', out);
+	}
+	outstr(p, out);
+}
+
 static int describe_command(struct output *out, char *command,
                             const char *path, int verbose)
 {
@@ -840,12 +859,11 @@ static int describe_command(struct output *out, char *command,
 		}
 		if (verbose) {
 			outfmt(
-				out, " is%s %s",
-				cmdp ? " a tracked alias for" : nullstr, p
+				out, " is%s ",
+				cmdp ? " a tracked alias for" : nullstr
 			);
-		} else {
-			outstr(p, out);
 		}
+		printpath(out, p);
 		break;
 	}
 
-- 
2.53.0