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 1f4f75294b1aa578d0e779dafb9099873aebedcd Author: Marco Casaroli <[email protected]> AuthorDate: Fri Oct 30 11:59:09 2026 +0100 libs/libc: Put the string of putenv() into the environment, as POSIX does. POSIX declares "int putenv(char *string)": the string itself becomes part of the environment, so a later change to the string changes the environment. <stdlib.h> and libc had "const char *", and putenv() copied the string. A program that declares putenv() itself with the POSIX prototype failed to compile with conflicting types, and a change to the string after the call did not change the environment. Use "char *" in <stdlib.h>, in the function and in libc.csv. putenv() now puts the string itself into the array of libc, in the place of the old name=value pair or at the end. libc does not free it: env_removevar() and env_release() free only the blocks of env_alloc(). "NAME=" now sets NAME to an empty value, as in POSIX; before, it removed NAME. env_setvar() was only there so that putenv() could give the name part of its string to setenv(). Move it back into setenv(). Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- include/stdlib.h | 2 +- libs/libc/environ/env_putenv.c | 40 +++++++++++-- libs/libc/environ/env_setenv.c | 125 ++++++++++++++++++----------------------- libs/libc/environ/environ.h | 22 -------- libs/libc/libc.csv | 2 +- 5 files changed, 92 insertions(+), 99 deletions(-) diff --git a/include/stdlib.h b/include/stdlib.h index e5a18f26585..0782f0b3803 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -182,7 +182,7 @@ int getloadavg(FAR double loadavg[], int nelem); FAR char ***get_environ_ptr(void); FAR char *getenv(FAR const char *name); FAR char *secure_getenv(FAR const char *name); -int putenv(FAR const char *string); +int putenv(FAR char *string); int clearenv(void); int setenv(FAR const char *name, FAR const char *value, int overwrite); int unsetenv(FAR const char *name); diff --git a/libs/libc/environ/env_putenv.c b/libs/libc/environ/env_putenv.c index 579119bc7c4..acc8c881997 100644 --- a/libs/libc/environ/env_putenv.c +++ b/libs/libc/environ/env_putenv.c @@ -24,9 +24,11 @@ * Included Files ****************************************************************************/ +#include <assert.h> #include <string.h> #include <errno.h> +#include <nuttx/mutex.h> #include <nuttx/tls.h> #include "environ.h" @@ -46,6 +48,10 @@ * name does exist, then the value of name in the environment is changed to * value. * + * As POSIX requires, the string itself becomes part of the environment: + * a later change to the string changes the environment. libc does not + * copy or free it. + * * Input Parameters: * name=value string describing the environment setting to add/modify * @@ -57,9 +63,11 @@ * ****************************************************************************/ -int putenv(FAR const char *string) +int putenv(FAR char *string) { - FAR const char *pequal; + FAR struct task_info_s *info = task_get_info(); + FAR char *pequal; + ssize_t idx; int ret; /* Verify that a string was passed */ @@ -78,9 +86,33 @@ int putenv(FAR const char *string) return OK; } - /* Then let env_setvar do all of the work */ + DEBUGASSERT(info != NULL); + + nxrmutex_lock(&info->ta_lock); + + /* environ must be an array of libc with room for one more entry */ + + ret = env_reserve(info, 1); + if (ret >= 0) + { + /* Put the string itself in the place of the old name=value pair, or + * at the end. + */ + + idx = env_findvar(info, string, pequal - string); + if (idx >= 0) + { + info->ta_envp[idx] = string; + } + else + { + info->ta_envp[info->ta_envc++] = string; + info->ta_envp[info->ta_envc] = NULL; + } + } + + nxrmutex_unlock(&info->ta_lock); - ret = env_setvar(string, pequal - string, pequal + 1, TRUE); if (ret < 0) { set_errno(-ret); diff --git a/libs/libc/environ/env_setenv.c b/libs/libc/environ/env_setenv.c index edf4619587b..6294ef28836 100644 --- a/libs/libc/environ/env_setenv.c +++ b/libs/libc/environ/env_setenv.c @@ -39,20 +39,70 @@ ****************************************************************************/ /**************************************************************************** - * Name: env_setvar + * Name: setenv + * + * Description: + * The setenv() function adds the variable name to the environment with the + * specified 'value' if the variable 'name" does not exist. If the 'name' + * does exist in the environment, then its value is changed to 'value' if + * 'overwrite' is non-zero; if 'overwrite' is zero, then the value of name + * unaltered. + * + * Input Parameters: + * name - The name of the variable to change + * value - The new value of the variable + * overwrite - Replace any existing value if non-zero. + * + * Returned Value: + * Zero on success + * + * Assumptions: + * Not called from an interrupt handler + * ****************************************************************************/ -int env_setvar(FAR const char *name, size_t namelen, - FAR const char *value, int overwrite) +int setenv(FAR const char *name, FAR const char *value, int overwrite) { FAR struct task_info_s *info = task_get_info(); FAR char *pvar; ssize_t idx; + size_t namelen; size_t varlen; int ret; + /* Verify input parameter */ + + if (!name) + { + set_errno(EINVAL); + return ERROR; + } + + /* if no value is provided, then this is the same as unsetenv (unless + * overwrite is false) + */ + + if (!value || *value == '\0') + { + /* If overwrite is set then this is the same as unsetenv */ + + if (overwrite) + { + return unsetenv(name); + } + else + { + /* Otherwise, it is a request to remove a variable without + * altering it? + */ + + return OK; + } + } + DEBUGASSERT(info != NULL); + namelen = strlen(name); nxrmutex_lock(&info->ta_lock); /* environ must be an array of libc with room for one more entry */ @@ -82,13 +132,6 @@ int env_setvar(FAR const char *name, size_t namelen, env_removevar(info, idx); } - /* An empty value removes the variable */ - - if (*value == '\0') - { - goto out; - } - /* Get the size of the new name=value string. * The +2 is for the '=' and for null terminator */ @@ -104,74 +147,14 @@ int env_setvar(FAR const char *name, size_t namelen, /* Now, put the new name=value string into the environment */ - snprintf(pvar, varlen, "%.*s=%s", (int)namelen, name, value); + snprintf(pvar, varlen, "%s=%s", name, value); info->ta_envp[info->ta_envc++] = pvar; info->ta_envp[info->ta_envc] = NULL; out: nxrmutex_unlock(&info->ta_lock); - return ret; -} - -/**************************************************************************** - * Name: setenv - * - * Description: - * The setenv() function adds the variable name to the environment with the - * specified 'value' if the variable 'name" does not exist. If the 'name' - * does exist in the environment, then its value is changed to 'value' if - * 'overwrite' is non-zero; if 'overwrite' is zero, then the value of name - * unaltered. - * - * Input Parameters: - * name - The name of the variable to change - * value - The new value of the variable - * overwrite - Replace any existing value if non-zero. - * - * Returned Value: - * Zero on success - * - * Assumptions: - * Not called from an interrupt handler - * - ****************************************************************************/ - -int setenv(FAR const char *name, FAR const char *value, int overwrite) -{ - int ret; - - /* Verify input parameter */ - - if (!name) - { - set_errno(EINVAL); - return ERROR; - } - - /* if no value is provided, then this is the same as unsetenv (unless - * overwrite is false) - */ - - if (!value || *value == '\0') - { - /* If overwrite is set then this is the same as unsetenv */ - - if (overwrite) - { - return unsetenv(name); - } - else - { - /* Otherwise, it is a request to remove a variable without - * altering it? - */ - - return OK; - } - } - ret = env_setvar(name, strlen(name), value, overwrite); if (ret < 0) { set_errno(-ret); diff --git a/libs/libc/environ/environ.h b/libs/libc/environ/environ.h index c51d44c2871..8a3f7d85b50 100644 --- a/libs/libc/environ/environ.h +++ b/libs/libc/environ/environ.h @@ -78,28 +78,6 @@ extern "C" ssize_t env_findvar(FAR struct task_info_s *info, FAR const char *pname, size_t namelen); -/**************************************************************************** - * Name: env_setvar - * - * Description: - * setenv() with the length of the name, so that putenv() can pass the - * name part of its string without a copy. An empty value removes the - * variable, as in setenv(). - * - * Input Parameters: - * name - The name of the variable. It needs no terminating NUL. - * namelen - The length of the name. - * value - The new value of the variable. - * overwrite - Replace any existing value if non-zero. - * - * Returned Value: - * Zero (OK) on success; a negated errno value on failure. - * - ****************************************************************************/ - -int env_setvar(FAR const char *name, size_t namelen, - FAR const char *value, int overwrite); - /**************************************************************************** * Name: env_alloc * diff --git a/libs/libc/libc.csv b/libs/libc/libc.csv index 4c7eac03c32..73d2ebd5751 100644 --- a/libs/libc/libc.csv +++ b/libs/libc/libc.csv @@ -269,7 +269,7 @@ "pthread_setname_np","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","pthread_t","const char *" "pthread_setspecific","pthread.h","!defined(CONFIG_DISABLE_PTHREAD) && CONFIG_TLS_NELEM > 0","int","pthread_key_t","FAR const void *" "pthread_yield","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","void" -"putenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char *" +"putenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR char *" "puts","stdio.h","defined(CONFIG_FILE_STREAM)","int","FAR const IPTR char *" "putwc","wchar.h","defined(CONFIG_FILE_STREAM)","wint_t","wchar_t","FAR FILE *" "putwc_unlocked","wchar.h","defined(CONFIG_FILE_STREAM)","wint_t","wchar_t","FAR FILE *"
