POSIX requires that PATH searching be done only if the identifier
(aka "file") has no '/' (if it has, it is a "path").
    
Allow searching qualified filenames, i.e. Resource Identifier,
like dk/ctl, vect/in/dxf by setting an environment variable
PATH_SEARCH_OPT with the setting 'Q' in the definition.
    
It works in all the three shells (sh(1), ksh(1) and csh(1)) as
well as with all the utilities using exec[lv]p or posit_spawnp (also
then system(3)).
    
A man page pathsearch(7) is added explaining this all.

The diff is attached and this can be also retrieved as:
commit 502cb391d594a2722cca46e135f79c02516981d5

with https://github.com/tlaronde/BeSiDe

diff --git a/include/pathsearch.h b/include/pathsearch.h
new file mode 100644
index 000000000000..59df79021843
--- /dev/null
+++ b/include/pathsearch.h
@@ -0,0 +1,34 @@
+/*
+ * Written by Thierry Laronde <tlaro...@kergis.com> 2024-09
+ * Public domain.
+ * See pathsearch(7).
+ */
+
+#ifndef _PATHSEARCH_H_
+#define        _PATHSEARCH_H_
+
+#include <string.h>
+
+/*
+ * For the feature testing macros, the parameters are environment
+ * variable values of the same but upper case name.
+ */
+#define PATH_SEARCH_OPT_QFILENAME 'q'
+#define PATH_SEARCH_OPT_QFILENAME_FORCED 'Q'
+#define        PATH_SEARCH_QFILENAME_ON(path_search_opt) \
+( (path_search_opt) != NULL \
+       && strchr(path_search_opt, PATH_SEARCH_OPT_QFILENAME_FORCED) != NULL )
+
+/*
+ * A qualified filename should be considered a Resource Identifier
+ * to be contrasted to a Locator (where a resource lies in the
+ * namespace). See pathsearch(7).
+ */
+#define PATH_SEARCH_IS_QFILENAME(name, name_len) \
+       ( (name) != NULL && (name_len) != 0 \
+               && (name)[0] != '/' && strstr(name, "./") == NULL \
+               && (name)[(name_len)-1] != '/' \
+               && (name)[(name_len)-1] != '.' )
+
+#endif /* !_PATHSEARCH_H_ */
+
diff --git a/share/man/man7/pathsearch.7 b/share/man/man7/pathsearch.7
new file mode 100644
index 000000000000..6ecc313e772b
--- /dev/null
+++ b/share/man/man7/pathsearch.7
@@ -0,0 +1,234 @@
+.\"
+.\" Public Domain.
+.\"
+.Dd September 29, 2024
+.Dt PATHSEARCH 7
+.Os
+.Sh NAME
+.Nm pathsearch
+.Nd when and how the search of a file to execute is handled.
+.Sh DESCRIPTION
+A program to execute is given to a shell, to one of the
+.Xr exec 3
+or 
+.Xr posix_spawn 3
+family of functions in two forms: either as a
+.Em locator
+specifying exactly (even if implicitely) where the file is, or as an
+.Em identifier
+to be searched in order to be located. (POSIX generally use
+.Em path
+as a mean to imply a locator and
+.Em file
+to imply an identifier.)
+.Pp
+The shells
+.Xr sh 1 ,
+.Xr ksh 1 ,
+.Xr csh 1 ,
+as well as the variants of the
+.Xr execlp 3
+and
+.Xr execvp 3
+functions, and the
+.Xr posix_spawnp 3
+function (used by the implementation of
+.Xr system 3 )
+handle both locators and identifiers. The other variants of
+.Xr exec 3
+or
+.Xr posix_spawn 3
+expect only locators and do no path searching.
+.Pp
+For the path searching, two environment variables drive the searching:
+.Em PATH
+and
+.Em PATH_SEARCH_OPT .
+.Pp
+In order for the searching to be done, the command given as argument
+has to be identified as an identifier, and not as a locator.
+.Pp
+The traditional POSIX rule for this is simple: when path searching is
+to be attempted, if the command name given does not contain a
+.Ql \&/ ,
+it is considered an identifier and is then searched. Otherwise, it is a
+locator and no search is done.
+.Pp
+Hence, with the traditional behavior, given a command as 
+.Qq bar/foo ,
+no path searching would be done and this will be tried in the current
+working directory.
+.Pp
+The rules concerning what is an identifier can be changed using the
+.Em PATH_SEARCH_OPT
+variable. See below
+.Sx Extending identifiers to qualified filenames .
+.Pp
+When the argument is considered an identifier (according to whatever
+rule), it is not searched everywhere but only in the directories
+specified in the
+.Em PATH
+environment variable.
+.Pp
+The
+.Em PATH
+is a sequence of colon
+.Ql \&:
+separated directory pathnames to be tried, in turn, for locating the
+identified resource. Initially, it is set to
+.Pp
+.Dl /usr/bin:/bin:/usr/pkg/bin:/usr/local/bin
+by
+.Xr login 1 .
+It can be redefined later.
+.Pp
+An empty dir specification (that can be expressed in PATH by a leading
+or a trailing colon, or by two consecutive colons) means the current
+working directory. This is considered a security risk since, by the very
+nature of the current working, what will be executed depends on the
+context.  It is thus highly recommended to verify that an empty dir
+alternative has not slipped by mistake in the PATH definition.
+.Pp
+The
+.Xr sh 1
+syntax allows for example to interpolate a dir specification via a
+variable, but offers means to protect the PATH from having by mistake
+a current working dir definition because the variable is not defined
+or empty, in this way:
+.Pp
+.Dl PATH="/bin:/usr/bin:${MYSCRIPTS:+${MYSCRIPTS}:}/usr/pkg/bin"
+.Pp
+or
+.Pp
+.Dl PATH="/bin:/usr/bin${MYSCRIPTS:+:${MYSCRIPTS}}:/usr/pkg/bin"
+.Pp
+The trick here is that the variable is only expanded if it is
+defined and not empty, and, in this case only, a
+.Ql \&:
+colon is added to its definition. The result being that if the
+.Em MYSCRIPTS
+variable were not defined or empty, this will not result in two
+consecutive colons, adding by mistake the current working directory as
+an alternative dir to search in. See
+.Xr sh 1
+for an explanation of the syntax.
+.Ss Extending identifiers to qualified filenames
+The environment variable
+.Em PATH_SEARCH_OPT
+can be defined to change the path searching.
+.Pp
+The definition of the PATH_SEARCH_OPT is a string of ASCII letters
+(the options are case sensitive).
+.Pp
+At the moment, only one option is defined:
+.Bl -tag -width "Q"
+.It Q
+The rule identifying an identifier is changed to allow qualified
+filenames like
+.Qq bar/foo
+to be searched for with the PATH. A
+.Em qualified filename
+is a Resource Identifier (not a locator) consisting of a sequence
+of one or more components separated by
+.Ql / ,
+the sequence not starting or ending by a
+.Ql /
+and any component not ending by a
+.Ql \&. .
+Thus
+.Qq fs/create ,
+.Qq fs/ck ,
+.Qq fs/mount ,
+.Qq fs/ctl
+are all qualified filenames, as well as
+.Qq texlive/latex
+or
+.Qq kertex/latex ,
+as well as (G.R.A.S.S. example)
+.Qq vect/in/dxf .
+But 
+.Qq /vect/in/dxf
+is not an identifier but a locator, as well as
+.Qq ./vect/in/dxf
+or
+.Qq vect/in/dxf.
+in this latter case because of the trailing dot of the last component.
+.El
+.Sh IMPLEMENTATION NOTES
+Since the behavior can not be changed only at a shell level, there
+has to be a mean to inform both the shell and the libc to change the
+behavior. Hence the
+.Em PATH_SEARCH_OPT
+environment variable. And since it would be suboptimal to create
+another variable when something has to be optionally changed in the way
+the path is searched, the variable has to have a definition.
+.Pp
+The upper case was chosen because, initially, there was a lower case
+variant meaning: do qualified filename searching if not
+.Em POSIXLY_CORRECT .
+But if this extended behavior is not, strictly speaking, POSIX
+compliant, it is not a violation of the spirit: a qualified filename
+is an identifier, not a locator that is a path wandering instruction; a
+qualified filename can not escape the directory. In this sense, and
+without judging the relevance of the notion of a
+.Qq restricted shell ,
+as is expressed, for example, in
+.Xr ksh 1 ,
+a qualified filename is neither absolute nor relative, so is
+compatible with the notion. So the lower case variant was dropped, but
+the principle of distinguishing between lower case (conditional) and
+upper case (mandatory) is retained for possible further extensions.
+.Pp
+The new rule was designed so it can match the meaning (an identifier
+not a locator), be compatible with a Unix filesystem hierarchy, and
+easy to test. The restriction of no ending
+.Ql \&.
+was initially for the simplicity and thus efficiency of testing. But
+it makes some sense. 
+.Ql \&.
+and
+.Qq \&.\&.
+and not identifiers (they are not uniq and do not exist as names in
+any filesystem) but are
+.Qq pronoun
+locators. They end with a dot. So any sequence ending with a dot can
+be reserved for the group of pronoun locators allowing extensions
+of the notion.
+.Pp
+The fact that, when extended filenames search is requested, a command
+passed as
+.Qq bar/foo
+will be searched and not executed in the current directory, thus
+imposing, if it was actually the intention to do so, to specify it as
+.Qq ./bar/foo
+is not considered a slight inconvenient but an improvement.
+.Sh SEE ALSO
+.Xr environ 7 ,
+.Xr exec 3 ,
+.Xr posix_spawn 3 ,
+.Xr sh 1 ,
+.Xr ksh 1 ,
+.Xr csh 1 .
+.Sh SOURCES
+.Pa include/pathsearch.h
+.Pp lib/libc/gen/execvp.c
+.Pp lib/libc/gen/posix_spawnp.c
+.Pp bin/sh/exec.c
+.Pp bin/ksh/exec.c
+.Pp bin/csh/exec.c
+.Sh HISTORY
+Allowing qualified filenames for commands to be searched (not exactly
+with the same rules) was first encountered by the author in the
+.Em Plan9
+system.
+.Sh AUTHOR
+.An "Thierry Laronde" Aq Mt tlaro...@kergis.com .
+.Pp
+The
+.Xr sh 1
+way of defining the
+.Ev PATH
+with interpolated variables, protecting from undefined ones, comes
+from
+.An "Robert Elz" Aq Mt k...@munnari.oz.au .
+
diff --git a/bin/csh/exec.c b/bin/csh/exec.c
index bd06892a1c92..b45e1d3d5222 100644
--- a/bin/csh/exec.c
+++ b/bin/csh/exec.c
@@ -45,6 +45,7 @@ __RCSID("$NetBSD: exec.c,v 1.33 2019/01/05 16:54:00 christos 
Exp $");
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pathsearch.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -55,7 +56,8 @@ __RCSID("$NetBSD: exec.c,v 1.33 2019/01/05 16:54:00 christos 
Exp $");
 
 /*
  * System level search and execute of a command.  We look in each directory
- * for the specified command name.  If the name contains a '/' then we
+ * for the specified command name.  If the name contains a '/' and
+ * qualified filenames is not on (see pathsearch.7) then we
  * execute only the full path name.  If there is no search path then we
  * execute only full path names.
  */
@@ -194,13 +196,26 @@ doexec(Char **v, struct command *t)
     sigemptyset(&nsigset);
     (void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
     /*
-     * If no path, no words in path, or a / in the filename then restrict the
-     * command search.
+     * If no path, no words in path, or a / in the filename but not
+     * doing qualified filename, then restrict the command search.
      */
-    if (pathv == 0 || pathv->vec[0] == 0 || slash)
+    {
+    const char *path_search_opt;
+    size_t ln;
+    int do_qfilename;
+
+    ln = strlen(short2str(*av));
+
+    path_search_opt = getenv("PATH_SEARCH_OPT");
+    do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+       && PATH_SEARCH_IS_QFILENAME(short2str(*av), ln);
+
+    if (pathv == 0 || pathv->vec[0] == 0
+       || (do_qfilename == 0 && slash) )
        pv = justabs;
     else
        pv = pathv->vec;
+    }
     sav = Strspl(STRslash, *av);       /* / command name for postpending */
     Vsav = sav;
     if (havhash)
@@ -510,12 +525,21 @@ iscommand(Char *name)
     Char **pv, *sav;
     int hashval, hashval1, i;
     int slash;
+    const char *path_search_opt;
+    size_t ln;
+    int do_qfilename;
 
     hashval = 0;
     slash = any(short2str(name), '/');
     v = adrof(STRpath);
     
-    if (v == 0 || v->vec[0] == 0 || slash)
+    ln = strlen(short2str(name));
+
+    path_search_opt = getenv("PATH_SEARCH_OPT");
+    do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(short2str(name), ln);
+
+    if (v == 0 || v->vec[0] == 0 || (do_qfilename == 0 && slash) )
        pv = justabs;
     else
        pv = v->vec;
@@ -700,10 +724,20 @@ tellmewhat(struct wordent *lexp, Char *str)
     if ((i = iscommand(sp->word)) != 0) {
        Char **pv;
        struct varent *v;
+       const char *path_search_opt;
+       size_t ln;
+       int do_qfilename;
        int    slash = any(short2str(sp->word), '/');
 
+       ln = strlen(short2str(sp->word));
+
+       path_search_opt = getenv("PATH_SEARCH_OPT");
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(short2str(sp->word), ln);
+
+
        v = adrof(STRpath);
-       if (v == 0 || v->vec[0] == 0 || slash)
+       if (v == 0 || v->vec[0] == 0 || (do_qfilename == 0 && slash) )
            pv = justabs;
        else
            pv = v->vec;
diff --git a/bin/ksh/exec.c b/bin/ksh/exec.c
index 721f301f393f..0bf7d6e0cecd 100644
--- a/bin/ksh/exec.c
+++ b/bin/ksh/exec.c
@@ -11,6 +11,7 @@ __RCSID("$NetBSD: exec.c,v 1.28 2018/06/03 12:18:29 kamil Exp 
$");
 
 #include <sys/stat.h>
 #include <ctype.h>
+#include <pathsearch.h>
 #include <stdbool.h>
 
 #include "sh.h"
@@ -575,7 +576,17 @@ comexec(t, tp, ap, flags)
                rv = subst_exstat;
                goto Leave;
        } else if (!tp) {
-               if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {
+               const char *path_search_opt;
+               int ln;
+               int do_qfilename;
+
+               ln = strlen(cp);
+               path_search_opt = str_val(global("PATH_SEARCH_OPT"));
+               do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+                       && PATH_SEARCH_IS_QFILENAME(cp, ln);
+
+               if (Flag(FRESTRICTED) && do_qfilename == 0
+                       && ksh_strchr_dirsep(cp)) {
                        warningf(true, "%s: restricted", cp);
                        rv = 1;
                        goto Leave;
@@ -899,8 +910,16 @@ findcom(name, flags)
        int insert = Flag(FTRACKALL);   /* insert if not found */
        char *fpath;                    /* for function autoloading */
        char *npath;
+       const char *path_search_opt;
+       size_t ln;
+       int do_qfilename;
+
+       ln = strlen(name);
+       path_search_opt = str_val(global("PATH_SEARCH_OPT"));
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(name, ln);
 
-       if (ksh_strchr_dirsep(name) != NULL) {
+       if (do_qfilename == 0 && ksh_strchr_dirsep(name) != NULL) {
                insert = 0;
                /* prevent FPATH search below */
                flags &= ~FC_FUNC;
@@ -1050,18 +1069,26 @@ search(name, pathx, mode, errnop)
        const char *sp, *p;
        char *xp;
        XString xs;
+       const char *path_search_opt;
        int namelen;
+       int do_qfilename;
 
        if (errnop)
                *errnop = 0;
 
-       if (ksh_strchr_dirsep(name)) {
+       namelen = strlen(name);
+
+       path_search_opt = str_val(global("PATH_SEARCH_OPT"));
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(name, namelen);
+
+       if (do_qfilename == 0 && ksh_strchr_dirsep(name)) {
                if (search_access(name, mode, errnop) == 0)
                        return (char *)__UNCONST(name);
                return NULL;
        }
 
-       namelen = strlen(name) + 1;
+       ++namelen;      /* to include terminal nul */
        Xinit(xs, xp, 128, ATEMP);
 
        sp = pathx;
diff --git a/bin/sh/exec.c b/bin/sh/exec.c
index 4b1c5885371c..09dc0cd09a66 100644
--- a/bin/sh/exec.c
+++ b/bin/sh/exec.c
@@ -47,6 +47,7 @@ __RCSID("$NetBSD: exec.c,v 1.59 2024/07/12 07:30:30 kre Exp 
$");
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <pathsearch.h>        /* PATH_SEARCH_OPT */
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -125,12 +126,26 @@ void
 shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
 {
        char *cmdname;
+#ifndef SMALL
+       const char *path_search_opt;
+       size_t ln;
+       int do_qfilename;
+#endif
        int e, action;
        struct stat statb;
 
        action = E_EXEC;
 
+#ifndef SMALL
+       ln = strlen(argv[0]);
+       path_search_opt = lookupvar("PATH_SEARCH_OPT");
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(argv[0], ln);
+
+       if (do_qfilename == 0 && strchr(argv[0], '/') != NULL) {
+#else
        if (strchr(argv[0], '/') != NULL) {
+#endif
                tryexec(argv[0], argv, envp, vforked);
                e = errno;
                if (e == EACCES && stat(argv[0], &statb) == -1)
@@ -574,9 +589,27 @@ find_command(char *name, struct cmdentry *entry, int act, 
const char *path)
        struct stat statb;
        int e;
        int (*bltin)(int,char **);
+#ifndef SMALL
+       const char *path_search_opt;
+       size_t ln;
+       int do_qfilename;
+#endif
 
+#ifndef SMALL
+       ln = strlen(name);
+       path_search_opt = lookupvar("PATH_SEARCH_OPT");
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(name, ln);
+
+       /*
+        * If not searching for a qualified filename, then if the name
+        * contains a slash, don't use PATH or hash table.
+        */
+       if (do_qfilename == 0 && strchr(name, '/') != NULL) {
+#else
        /* If name contains a slash, don't use PATH or hash table */
        if (strchr(name, '/') != NULL) {
+#endif
                if (act & DO_ABS) {
                        while (stat(name, &statb) < 0) {
 #ifdef SYSV
diff --git a/distrib/sets/lists/comp/mi b/distrib/sets/lists/comp/mi
index a2274fb94a4b..021b9d2eea1f 100644
--- a/distrib/sets/lists/comp/mi
+++ b/distrib/sets/lists/comp/mi
@@ -3191,6 +3191,7 @@
 ./usr/include/openssl/x509v3err.h              comp-c-include
 ./usr/include/panel.h                          comp-c-include
 ./usr/include/paths.h                          comp-c-include
+./usr/include/pathsearch.h                     comp-c-include
 ./usr/include/pcap-namedb.h                    comp-c-include
 ./usr/include/pcap.h                           comp-c-include
 ./usr/include/pcap/bpf.h                       comp-c-include
diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi
index e1d4e9c3e2f1..3ddc26880564 100644
--- a/distrib/sets/lists/man/mi
+++ b/distrib/sets/lists/man/mi
@@ -6148,6 +6148,7 @@
 ./usr/share/man/man7/openssl-threads.7         man-crypto-man          
.man,openssl=30
 ./usr/share/man/man7/orders.7                  man-reference-man       .man
 ./usr/share/man/man7/packages.7                        man-obsolete            
obsolete
+./usr/share/man/man7/pathsearch.7              man-reference-man
 ./usr/share/man/man7/pcap-filter.7             man-netutil-man         .man
 ./usr/share/man/man7/pcap-linktype.7           man-netutil-man         .man
 ./usr/share/man/man7/pcap-tstamp.7             man-netutil-man         .man
diff --git a/distrib/sets/lists/manhtml/mi b/distrib/sets/lists/manhtml/mi
index 0427facdeab2..9c1d76b19182 100644
--- a/distrib/sets/lists/manhtml/mi
+++ b/distrib/sets/lists/manhtml/mi
@@ -2370,6 +2370,7 @@
 ./usr/share/man/html7/openssl-glossary.html    man-crypto-htmlman              
html,openssl=30
 ./usr/share/man/html7/openssl-threads.html     man-crypto-htmlman              
html,openssl=30
 ./usr/share/man/html7/orders.html              man-reference-htmlman   html
+./usr/share/man/html7/pathsearch.html          man-reference-htmlman   html
 ./usr/share/man/html7/pcap-filter.html         man-netutil-htmlman     html
 ./usr/share/man/html7/pcap-linktype.html       man-netutil-htmlman     html
 ./usr/share/man/html7/pcap-tstamp.html         man-netutil-htmlman     html
diff --git a/include/Makefile b/include/Makefile
index f7e000fb2cb2..1ac92f38c095 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -16,7 +16,7 @@ INCS= a.out.h aio.h ar.h assert.h atomic.h \
        login_cap.h lwp.h malloc.h math.h md2.h \
        memory.h mntopts.h monetary.h mpool.h mqueue.h \
        ndbm.h netconfig.h netdb.h netgroup.h nlist.h nl_types.h nsswitch.h \
-       paths.h pwd.h quota.h randomid.h ranlib.h re_comp.h regex.h regexp.h \
+       paths.h pathsearch.h pwd.h quota.h randomid.h ranlib.h re_comp.h 
regex.h regexp.h \
        resolv.h res_update.h rmt.h sched.h search.h semaphore.h setjmp.h \
        string.h sgtty.h signal.h spawn.h stab.h stddef.h stdio.h \
        stdlib.h stdnoreturn.h strings.h stringlist.h struct.h sysexits.h \
diff --git a/lib/libc/gen/execvp.c b/lib/libc/gen/execvp.c
index d29e2a0fc6d2..3219a99e7796 100644
--- a/lib/libc/gen/execvp.c
+++ b/lib/libc/gen/execvp.c
@@ -47,6 +47,7 @@ __RCSID("$NetBSD: execvp.c,v 1.32 2024/01/20 14:52:47 
christos Exp $");
 #include <limits.h>
 #include <unistd.h>
 #include <paths.h>
+#include <pathsearch.h>
 #include "reentrant.h"
 #include "extern.h"
 
@@ -62,9 +63,11 @@ execvpe(const char *name, char * const *argv, char * const * 
envp)
        int cnt;
        size_t lp, ln;
        int eacces = 0;
+       int do_qfilename;
        unsigned int etxtbsy = 0;
        char buf[PATH_MAX];
        const char *bp, *path, *p;
+       const char *path_search_opt;
 
        _DIAGASSERT(name != NULL);
 
@@ -74,8 +77,16 @@ execvpe(const char *name, char * const *argv, char * const * 
envp)
                goto done;
        }
        ln = strlen(name);
-       /* If it's an absolute or relative path name, it's easy. */
-       if (strchr(name, '/')) {
+
+       path_search_opt = getenv("PATH_SEARCH_OPT");
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(name, ln);
+
+       /* 
+        * If it's an absolute or relative path name (and not a
+        * qualified filename and asked to search for it), it's easy.
+        */
+       if (do_qfilename == 0 && strchr(name, '/')) {
                bp = name;
                path = "";
                goto retry;
diff --git a/lib/libc/gen/posix_spawnp.c b/lib/libc/gen/posix_spawnp.c
index 2474bbe6970c..7e7e20e04313 100644
--- a/lib/libc/gen/posix_spawnp.c
+++ b/lib/libc/gen/posix_spawnp.c
@@ -39,6 +39,7 @@ __RCSID("$NetBSD: posix_spawnp.c,v 1.4 2020/05/11 14:54:34 
kre Exp $");
 #include <assert.h>
 #include <errno.h>
 #include <paths.h>
+#include <pathsearch.h>
 #include <spawn.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -53,15 +54,23 @@ int posix_spawnp(pid_t * __restrict pid, const char * 
__restrict file,
 {
        char fpath[FILENAME_MAX];
        const char *path, *p;
+       const char *path_search_opt;
        size_t lp, ln;
        int err;
+       int do_qfilename;
 
        _DIAGASSERT(file != NULL);
 
+       ln = strlen(file);
+       path_search_opt = getenv("PATH_SEARCH_OPT");
+       do_qfilename = PATH_SEARCH_QFILENAME_ON(path_search_opt)
+               && PATH_SEARCH_IS_QFILENAME(file, ln);
+
        /*
-        * If there is a / in the name, fall straight through to posix_spawn().
+        * If not treating a qualified filename, and there is a / in
+        *  the name, fall straight through to posix_spawn().
         */
-       if (strchr(file, '/') != NULL)
+       if (do_qfilename == 0 && strchr(file, '/') != NULL)
                return posix_spawn(pid, file, fa, sa, cav, env);
 
        /* Get the path we're searching. */
@@ -72,7 +81,6 @@ int posix_spawnp(pid_t * __restrict pid, const char * 
__restrict file,
         * Find an executable image with the given name in the PATH
         */
 
-       ln = strlen(file);
        err = 0;
        do {
                /* Find the end of this path element. */
diff --git a/share/man/man7/Makefile b/share/man/man7/Makefile
index 9a8ab4202f52..d40457be1d81 100644
--- a/share/man/man7/Makefile
+++ b/share/man/man7/Makefile
@@ -20,6 +20,7 @@ MAN+= module.7
 MAN+=  nls.7
 MAN+=  operator.7
 MAN+=  orders.7
+MAN+=  pathsearch.7
 MAN+=  pkgsrc.7
 MAN+=  release.7
 MAN+=  rfc6056.7
diff --git a/share/man/man7/environ.7 b/share/man/man7/environ.7
index b1c06f50ed4d..f88dbe818528 100644
--- a/share/man/man7/environ.7
+++ b/share/man/man7/environ.7
@@ -29,7 +29,7 @@
 .\"
 .\"    @(#)environ.7   8.3 (Berkeley) 4/19/94
 .\"
-.Dd January 21, 2011
+.Dd September 29, 2024
 .Dt ENVIRON 7
 .Os
 .Sh NAME
@@ -174,6 +174,9 @@ is set to
 .Pp
 initially by
 .Xr login 1 .
+.It Ev PATH_SEARCH_OPT
+options to change the way path searching is done. Initially unset. See
+.Xr pathsearch 7 .
 .It Ev PRINTER
 The name of the default printer to be used by
 .Xr lpr 1 ,
-- 
        Thierry Laronde <tlaronde +AT+ kergis +dot+ com>
                     http://www.kergis.com/
                    http://kertex.kergis.com/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89  250D 52B1 AE95 6006 F40C

Reply via email to