This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new fa2dd7038 system/popen: Avoid copying FILE
fa2dd7038 is described below
commit fa2dd70386be572446d2dad5bd8ed8b56431429d
Author: Nightt <[email protected]>
AuthorDate: Wed Jun 3 09:54:17 2026 +0800
system/popen: Avoid copying FILE
Use fopencookie() to attach the popen fd and shell pid to the returned FILE
stream instead of copying FILE into the popen container.
Keep the upstream dpopen()/dpclose() implementation as the process and
descriptor backend, and make pclose() close the cookie-backed stream directly.
Fixes #2937.
Signed-off-by: Nightt <[email protected]>
---
system/popen/popen.c | 104 ++++++++++++++++++++++++++++++++++-----------------
1 file changed, 70 insertions(+), 34 deletions(-)
diff --git a/system/popen/popen.c b/system/popen/popen.c
index 4f46e6cd2..f4fdfab94 100644
--- a/system/popen/popen.c
+++ b/system/popen/popen.c
@@ -37,17 +37,65 @@
* Private Types
****************************************************************************/
-/* struct popen_file_s is a cast compatible version of FILE that contains
- * the additional PID of the shell processes needed by pclose().
- */
-
struct popen_file_s
{
- FILE copy;
- FILE *original;
+ int fd;
pid_t shell;
};
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: popen_file_read
+ ****************************************************************************/
+
+static ssize_t popen_file_read(FAR void *cookie, FAR char *buf,
+ size_t size)
+{
+ FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+
+ return read(filep->fd, buf, size);
+}
+
+/****************************************************************************
+ * Name: popen_file_write
+ ****************************************************************************/
+
+static ssize_t popen_file_write(FAR void *cookie, FAR const char *buf,
+ size_t size)
+{
+ FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+
+ return write(filep->fd, buf, size);
+}
+
+/****************************************************************************
+ * Name: popen_file_seek
+ ****************************************************************************/
+
+static off_t popen_file_seek(FAR void *cookie, FAR off_t *offset,
+ int whence)
+{
+ set_errno(ESPIPE);
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: popen_file_close
+ ****************************************************************************/
+
+static int popen_file_close(FAR void *cookie)
+{
+ FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+ int ret;
+
+ ret = dpclose(filep->fd, filep->shell);
+ free(filep);
+ return ret < 0 ? ERROR : OK;
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -93,6 +141,15 @@ struct popen_file_s
FILE *popen(FAR const char *command, FAR const char *mode)
{
FAR struct popen_file_s *container;
+ FAR FILE *stream;
+ cookie_io_functions_t popen_io =
+ {
+ .read = popen_file_read,
+ .write = popen_file_write,
+ .seek = popen_file_seek,
+ .close = popen_file_close
+ };
+
int oflag;
int fd;
@@ -142,8 +199,9 @@ FILE *popen(FAR const char *command, FAR const char *mode)
/* Wrap the raw fd in a FILE stream */
- container->original = fdopen(fd, mode);
- if (container->original == NULL)
+ container->fd = fd;
+ stream = fopencookie(container, mode, popen_io);
+ if (stream == NULL)
{
int errcode = errno;
dpclose(fd, container->shell);
@@ -152,8 +210,7 @@ FILE *popen(FAR const char *command, FAR const char *mode)
return NULL;
}
- memcpy(&container->copy, container->original, sizeof(FILE));
- return &container->copy;
+ return stream;
}
/****************************************************************************
@@ -193,33 +250,12 @@ FILE *popen(FAR const char *command, FAR const char *mode)
* stream - The stream reference returned by a previous call to popen()
*
* Returned Value:
- * The child termination status on success, or -1 (ERROR) on failure
- * with errno set.
+ * Zero (OK) is returned on success; otherwise -1 (ERROR) is returned and
+ * errno is set appropriately.
*
****************************************************************************/
int pclose(FILE *stream)
{
- FAR struct popen_file_s *container = (FAR struct popen_file_s *)stream;
- FILE *original;
- pid_t shell;
-
- original = container->original;
-
- /* Set the state of the original file descriptor to the state of the
- * working copy
- */
-
- memcpy(original, &container->copy, sizeof(FILE));
-
- /* Then close the original and free the container (saving the PID of the
- * shell process). Pass -1 to dpclose since fclose already closed the fd.
- */
-
- fclose(original);
-
- shell = container->shell;
- free(container);
-
- return dpclose(-1, shell);
+ return fclose(stream);
}