Skip to content

Commit 740fda9

Browse files
cuiziweizwxiaoxiang781216
authored andcommitted
system/popen: support no-shell mode via posix_spawnp
When NSH_LIBRARY is not available, dpopen()/popen() can still execute commands by splitting the command string by whitespace and calling posix_spawnp() directly. Shell syntax (pipes, redirects, globbing) is not supported in this mode. Add CONFIG_SYSTEM_POPEN_MAXARGUMENTS (default 7) to control the argv array size for the no-shell path. Remove the hard dependency on NSH_LIBRARY from SYSTEM_POPEN so the feature can be used in minimal configurations without a shell. Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
1 parent 0d35e2e commit 740fda9

2 files changed

Lines changed: 78 additions & 8 deletions

File tree

system/popen/Kconfig

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ config SYSTEM_POPEN
77
bool "popen()/pclose()/dpopen()/dpclose() Functions"
88
default n
99
select SCHED_WAITPID
10-
depends on NSH_LIBRARY && PIPES
10+
depends on PIPES
1111
---help---
1212
Enable support for the popen(), pclose(), dpopen(), and
1313
dpclose() interfaces.
@@ -20,16 +20,20 @@ config SYSTEM_POPEN
2020
popen()/pclose() are thin wrappers around dpopen()/dpclose()
2121
that additionally wrap the fd in a FILE stream.
2222

23-
Commands are executed through the NSH shell (sh -c command),
24-
supporting full shell syntax including pipes, redirects,
25-
and globbing.
23+
When NSH is available (NSH_LIBRARY), commands are executed
24+
through the shell (sh -c command), supporting full shell
25+
syntax including pipes, redirects, and globbing.
26+
27+
When NSH is not available, commands are executed directly
28+
via posix_spawnp(). The command string must be a simple
29+
"program arg1 arg2" form without shell syntax.
2630

2731
if SYSTEM_POPEN
2832

2933
config SYSTEM_POPEN_SHPATH
3034
string "Path to shell command"
3135
default "/bin/sh"
32-
depends on SYSTEM_NSH=m || BUILD_KERNEL
36+
depends on (SYSTEM_NSH=m || BUILD_KERNEL) && NSH_LIBRARY
3337
---help---
3438
This is the full path to the program in a mounted file system that
3539
implements the system() command. That is, a program that starts the
@@ -53,4 +57,17 @@ config SYSTEM_POPEN_PRIORITY
5357
---help---
5458
The priority of the shell.
5559

60+
config SYSTEM_POPEN_MAXARGUMENTS
61+
int "Maximum number of command arguments (no-shell mode)"
62+
default 7
63+
depends on !NSH_LIBRARY
64+
---help---
65+
When NSH is not available, dpopen()/popen() splits the command
66+
string by whitespace into an argv array. This sets the maximum
67+
number of arguments (excluding the program name and the
68+
terminating NULL).
69+
70+
This is analogous to CONFIG_NSH_MAXARGUMENTS but applies
71+
only to the no-shell path.
72+
5673
endif

system/popen/dpopen.c

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sys/wait.h>
2828
#include <sys/ioctl.h>
2929
#include <unistd.h>
30+
#include <string.h>
3031
#include <sched.h>
3132
#include <spawn.h>
3233
#include <debug.h>
@@ -37,7 +38,17 @@
3738
# include <sys/socket.h>
3839
#endif
3940

40-
#include "nshlib/nshlib.h"
41+
#ifdef CONFIG_NSH_LIBRARY
42+
# include "nshlib/nshlib.h"
43+
#endif
44+
45+
/****************************************************************************
46+
* Pre-processor Definitions
47+
****************************************************************************/
48+
49+
#ifndef CONFIG_NSH_LIBRARY
50+
# define DPOPEN_MAX_ARGV (CONFIG_SYSTEM_POPEN_MAXARGUMENTS + 1)
51+
#endif
4152

4253
/****************************************************************************
4354
* Public Functions
@@ -58,6 +69,10 @@
5869
* When NSH is available, commands are executed through the shell
5970
* (sh -c command), supporting full shell syntax.
6071
*
72+
* When NSH is not available, the command is split by whitespace and
73+
* executed directly via posix_spawnp(). Shell syntax (pipes, redirects,
74+
* globbing) is not supported in this mode.
75+
*
6176
* Input Parameters:
6277
* command - The command string to execute
6378
* oflag - O_RDONLY to read child stdout, O_WRONLY to write child stdin,
@@ -74,7 +89,14 @@ int dpopen(FAR const char *command, int oflag, FAR pid_t *pid)
7489
struct sched_param param;
7590
posix_spawnattr_t attr;
7691
posix_spawn_file_actions_t file_actions;
92+
#ifdef CONFIG_NSH_LIBRARY
7793
FAR char *argv[4];
94+
#else
95+
char cmdbuf[PATH_MAX];
96+
FAR char *argv[DPOPEN_MAX_ARGV];
97+
FAR char *saveptr;
98+
int argc = 0;
99+
#endif
78100
int fd[2];
79101
int childfd;
80102
int parentfd;
@@ -224,21 +246,52 @@ int dpopen(FAR const char *command, int oflag, FAR pid_t *pid)
224246
* appropriately.
225247
*/
226248

249+
#ifdef CONFIG_NSH_LIBRARY
250+
/* Shell mode: execute command through sh -c */
251+
227252
argv[1] = "-c";
228253
argv[2] = (FAR char *)command;
229254
argv[3] = NULL;
230255

231-
#ifdef CONFIG_SYSTEM_POPEN_SHPATH
256+
# ifdef CONFIG_SYSTEM_POPEN_SHPATH
232257
argv[0] = CONFIG_SYSTEM_POPEN_SHPATH;
233258
errcode = posix_spawn(pid, argv[0], &file_actions,
234259
&attr, argv, NULL);
235-
#else
260+
# else
236261
*pid = task_spawn("dpopen", nsh_system, &file_actions,
237262
&attr, argv + 1, NULL);
238263
if (*pid < 0)
239264
{
240265
errcode = -*pid;
241266
}
267+
# endif
268+
#else
269+
/* No-shell mode: split command and execute directly via posix_spawnp.
270+
* The command must be in "program arg1 arg2" form -- no shell syntax.
271+
*/
272+
273+
if (strlcpy(cmdbuf, command, sizeof(cmdbuf)) >= sizeof(cmdbuf))
274+
{
275+
errcode = ENAMETOOLONG;
276+
goto errout_with_actions;
277+
}
278+
279+
do
280+
{
281+
argv[argc] = strtok_r(argc ? NULL : cmdbuf, " \t", &saveptr);
282+
}
283+
while (argv[argc] != NULL && ++argc < DPOPEN_MAX_ARGV - 1);
284+
285+
argv[argc] = NULL;
286+
287+
if (argc == 0)
288+
{
289+
errcode = EINVAL;
290+
goto errout_with_actions;
291+
}
292+
293+
errcode = posix_spawnp(pid, argv[0], &file_actions,
294+
&attr, argv, NULL);
242295
#endif
243296

244297
if (errcode != 0)

0 commit comments

Comments
 (0)