This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 1af378b1da8a7a209da88d627106b7dedfcb551c
Author: Marco Casaroli <[email protected]>
AuthorDate: Tue Oct 27 17:57:44 2026 +0100

    libs/libc/unistd: Make execvp(), execlp() and execvpe() functions.
    
    <unistd.h> defined execvp, execlp and execvpe as macros of execv, execl
    and execve.  POSIX has execvp() and execlp() as functions, and programs
    that declare them or check for them do not work with a macro: a link
    test does not find them, and a program that declares its own execvpe()
    when the system has none (screen) gets "conflicting types for 'execve'".
    
    Make them functions of libc that do the same as execv(), execl() and
    execve(): NuttX has only one behavior, and with CONFIG_LIBC_ENVPATH
    these also search the PATH.  execl() and execlp() share their code.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 include/unistd.h                |  20 +++---
 libs/libc/libc.csv              |   2 +
 libs/libc/unistd/CMakeLists.txt |   2 +-
 libs/libc/unistd/Make.defs      |   2 +-
 libs/libc/unistd/lib_execl.c    | 133 +++++++++++++++++++++++++---------------
 libs/libc/unistd/lib_execvp.c   |  60 ++++++++++++++++++
 6 files changed, 156 insertions(+), 63 deletions(-)

diff --git a/include/unistd.h b/include/unistd.h
index 4a6f382f435..da114528e14 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -311,17 +311,6 @@
 #  define lockf64                        lockf
 #endif
 
-/* NOTE: NuttX provides only one implementation:  If
- * CONFIG_LIBC_ENVPATH is defined, then only execvp/execlp/execvpe behavior
- * is supported; otherwise, only execv/execl/execve behavior is supported.
- */
-
-#ifdef CONFIG_LIBC_EXECFUNCS
-#  define execvp                         execv
-#  define execlp                         execl
-#  define execvpe                        execve
-#endif
-
 /* Commands for lockf()
  * F_ULOCK - Unlock
  * F_LOCK  - Blocking Exclusive Lock
@@ -473,12 +462,21 @@ int     fchownat(int dirfd, FAR const char *path, uid_t 
owner,
 
 /* Execution of programs from files */
 
+/* NOTE: NuttX provides only one behavior:  If CONFIG_LIBC_ENVPATH is
+ * defined, then execv(), execl() and execve() also search the PATH as
+ * execvp(), execlp() and execvpe() do; otherwise none of them searches it.
+ */
+
 #ifdef CONFIG_LIBC_EXECFUNCS
 int     execl(FAR const char *path, FAR const char *arg0, ...);
 int     execle(FAR const char *path, FAR const char *arg0, ...);
+int     execlp(FAR const char *file, FAR const char *arg0, ...);
 int     execv(FAR const char *path, FAR char * const argv[]);
 int     execve(FAR const char *path, FAR char *const argv[],
                FAR char *const envp[]);
+int     execvp(FAR const char *file, FAR char * const argv[]);
+int     execvpe(FAR const char *file, FAR char * const argv[],
+                FAR char * const envp[]);
 #endif
 
 /* Byte operations */
diff --git a/libs/libc/libc.csv b/libs/libc/libc.csv
index ee03d577bf3..16886e4e316 100644
--- a/libs/libc/libc.csv
+++ b/libs/libc/libc.csv
@@ -61,6 +61,8 @@
 "dq_remlast","nuttx/queue.h","","FAR dq_entry_t *","FAR dq_queue_t *"
 "ether_ntoa","netinet/ether.h","","FAR char *","FAR const struct ether_addr *"
 "execv","unistd.h","defined(CONFIG_LIBC_EXECFUNCS)","int","FAR const char 
*","FAR char *const[]|FAR char *const *"
+"execvp","unistd.h","defined(CONFIG_LIBC_EXECFUNCS)","int","FAR const char 
*","FAR char *const[]|FAR char *const *"
+"execvpe","unistd.h","defined(CONFIG_LIBC_EXECFUNCS)","int","FAR const char 
*","FAR char *const[]|FAR char *const *","FAR char *const[]|FAR char *const *"
 "exit","stdlib.h","","noreturn","int"
 "fchdir","unistd.h","!defined(CONFIG_DISABLE_ENVIRON)","int","int"
 "fclose","stdio.h","defined(CONFIG_FILE_STREAM)","int","FAR FILE *"
diff --git a/libs/libc/unistd/CMakeLists.txt b/libs/libc/unistd/CMakeLists.txt
index 312406e8108..3b361ffbf22 100644
--- a/libs/libc/unistd/CMakeLists.txt
+++ b/libs/libc/unistd/CMakeLists.txt
@@ -109,7 +109,7 @@ if(NOT CONFIG_DISABLE_ENVIRON)
 endif()
 
 if(CONFIG_LIBC_EXECFUNCS)
-  list(APPEND SRCS lib_execl.c lib_execle.c lib_execv.c)
+  list(APPEND SRCS lib_execl.c lib_execle.c lib_execv.c lib_execvp.c)
 endif()
 
 if(NOT CONFIG_DISABLE_MOUNTPOINTS)
diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs
index 2f77ff220ca..f11e534023c 100644
--- a/libs/libc/unistd/Make.defs
+++ b/libs/libc/unistd/Make.defs
@@ -59,7 +59,7 @@ CSRCS += lib_restoredir.c
 endif
 
 ifeq ($(CONFIG_LIBC_EXECFUNCS),y)
-CSRCS += lib_execl.c lib_execle.c lib_execv.c
+CSRCS += lib_execl.c lib_execle.c lib_execv.c lib_execvp.c
 endif
 
 ifneq ($(CONFIG_DISABLE_MOUNTPOINTS),y)
diff --git a/libs/libc/unistd/lib_execl.c b/libs/libc/unistd/lib_execl.c
index 4ba1d2dba93..e39f5207f1d 100644
--- a/libs/libc/unistd/lib_execl.c
+++ b/libs/libc/unistd/lib_execl.c
@@ -53,6 +53,73 @@
  * Private Data
  ****************************************************************************/
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int lib_execl(FAR const char *path, FAR const char *arg0,
+                     va_list ap)
+{
+  FAR char **argv = NULL;
+  FAR char *arg = (FAR char *)arg0;
+  size_t nargs;
+  va_list ap2;
+  int argc;
+  int ret;
+
+  /* Count the number of arguments */
+
+  va_copy(ap2, ap);
+  nargs = 0;
+
+  while (arg != NULL)
+    {
+      /* Yes.. increment the number of arguments.  Here is a sanity
+       * check to prevent running away with an unterminated argv[] list.
+       * MAX_EXECL_ARGS should be sufficiently large that this never
+       * happens in normal usage.
+       */
+
+      if (++nargs > MAX_EXECL_ARGS)
+        {
+          set_errno(E2BIG);
+          va_end(ap2);
+          return ERROR;
+        }
+
+      arg = va_arg(ap2, FAR char *);
+    }
+
+  va_end(ap2);
+
+  /* Allocate a temporary argv[] array */
+
+  argv = (FAR char **)lib_malloc((nargs + 1) * sizeof(FAR char *));
+  if (argv == NULL)
+    {
+      set_errno(ENOMEM);
+      return ERROR;
+    }
+
+  argv[0] = (FAR char *)arg0;
+
+  /* Collect the arguments into the argv[] array */
+
+  for (argc = 1; argc <= nargs; argc++)
+    {
+      argv[argc] = va_arg(ap, FAR char *);
+    }
+
+  /* Then let execv() do the real work */
+
+  ret = execv(path, argv);
+
+  /* Free the allocated argv[] list */
+
+  lib_free(argv);
+  return ret;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -117,66 +184,32 @@
 
 int execl(FAR const char *path, FAR const char *arg0, ...)
 {
-  FAR char **argv = NULL;
-  FAR char *arg = (FAR char *)arg0;
-  size_t nargs;
   va_list ap;
-  int argc;
   int ret;
 
-  /* Count the number of arguments */
-
   va_start(ap, arg0);
-  nargs = 0;
-
-  while (arg != NULL)
-    {
-      /* Yes.. increment the number of arguments.  Here is a sanity
-       * check to prevent running away with an unterminated argv[] list.
-       * MAX_EXECL_ARGS should be sufficiently large that this never
-       * happens in normal usage.
-       */
-
-      if (++nargs > MAX_EXECL_ARGS)
-        {
-          set_errno(E2BIG);
-          va_end(ap);
-          return ERROR;
-        }
-
-      arg = va_arg(ap, FAR char *);
-    }
-
+  ret = lib_execl(path, arg0, ap);
   va_end(ap);
+  return ret;
+}
 
-  /* Allocate a temporary argv[] array */
-
-  argv = (FAR char **)lib_malloc((nargs + 1) * sizeof(FAR char *));
-  if (argv == NULL)
-    {
-      set_errno(ENOMEM);
-      return ERROR;
-    }
-
-  argv[0] = (FAR char *)arg0;
+/****************************************************************************
+ * Name: execlp
+ *
+ * Description:
+ *   The same as execl().  NuttX has only one behavior: with
+ *   CONFIG_LIBC_ENVPATH, execl() also searches the PATH for file.
+ *
+ ****************************************************************************/
 
-  /* Collect the arguments into the argv[] array */
+int execlp(FAR const char *file, FAR const char *arg0, ...)
+{
+  va_list ap;
+  int ret;
 
   va_start(ap, arg0);
-  for (argc = 1; argc <= nargs; argc++)
-    {
-      argv[argc] = va_arg(ap, FAR char *);
-    }
-
+  ret = lib_execl(file, arg0, ap);
   va_end(ap);
-
-  /* Then let execv() do the real work */
-
-  ret = execv(path, argv);
-
-  /* Free the allocated argv[] list */
-
-  lib_free(argv);
   return ret;
 }
 
diff --git a/libs/libc/unistd/lib_execvp.c b/libs/libc/unistd/lib_execvp.c
new file mode 100644
index 00000000000..1d18a19cbca
--- /dev/null
+++ b/libs/libc/unistd/lib_execvp.c
@@ -0,0 +1,60 @@
+/****************************************************************************
+ * libs/libc/unistd/lib_execvp.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <unistd.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: execvp
+ *
+ * Description:
+ *   The same as execv().  NuttX has only one behavior: with
+ *   CONFIG_LIBC_ENVPATH, execv() also searches the PATH for file.
+ *
+ ****************************************************************************/
+
+int execvp(FAR const char *file, FAR char * const argv[])
+{
+  return execv(file, argv);
+}
+
+/****************************************************************************
+ * Name: execvpe
+ *
+ * Description:
+ *   The same as execve().  NuttX has only one behavior: with
+ *   CONFIG_LIBC_ENVPATH, execve() also searches the PATH for file.
+ *
+ ****************************************************************************/
+
+int execvpe(FAR const char *file, FAR char * const argv[],
+            FAR char * const envp[])
+{
+  return execve(file, argv, envp);
+}

Reply via email to