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); +}
