feat(nsh): input (stdin) redirection
This adds support for `<` to redirect input on nsh commands.
This commit is contained in:
parent
875f2fcc1e
commit
96100b30f2
@ -43,13 +43,15 @@
|
||||
* New application is run in a separate task context (and thread).
|
||||
*
|
||||
* Input Parameter:
|
||||
* filename - Name of the linked-in binary to be started.
|
||||
* argv - Argument list
|
||||
* redirfile - If output is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* oflags - If output is redirected, this parameter will provide the
|
||||
* open flags to use. This will support file replacement
|
||||
* of appending to an existing file.
|
||||
* filename - Name of the linked-in binary to be started.
|
||||
* argv - Argument list
|
||||
* redirfile_in - If input is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* redirfile_out - If output is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* oflags - If output is redirected, this parameter will provide the
|
||||
* open flags to use. This will support file replacement
|
||||
* of appending to an existing file.
|
||||
*
|
||||
* Returned Value:
|
||||
* This is an end-user function, so it follows the normal convention:
|
||||
@ -59,7 +61,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
int exec_builtin(FAR const char *appname, FAR char * const *argv,
|
||||
FAR const char *redirfile, int oflags)
|
||||
FAR const char *redirfile_in, FAR const char *redirfile_out,
|
||||
int oflags)
|
||||
{
|
||||
FAR const struct builtin_s *builtin;
|
||||
posix_spawnattr_t attr;
|
||||
@ -144,14 +147,29 @@ int exec_builtin(FAR const char *appname, FAR char * const *argv,
|
||||
|
||||
#endif
|
||||
|
||||
/* Is input being redirected? */
|
||||
|
||||
if (redirfile_in)
|
||||
{
|
||||
/* Set up to close open redirfile and set to stdin (0) */
|
||||
|
||||
ret = posix_spawn_file_actions_addopen(&file_actions, 0,
|
||||
redirfile_in, O_RDONLY, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
serr("ERROR: posix_spawn_file_actions_addopen failed: %d\n", ret);
|
||||
goto errout_with_actions;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is output being redirected? */
|
||||
|
||||
if (redirfile)
|
||||
if (redirfile_out)
|
||||
{
|
||||
/* Set up to close open redirfile and set to stdout (1) */
|
||||
|
||||
ret = posix_spawn_file_actions_addopen(&file_actions, 1,
|
||||
redirfile, oflags, 0644);
|
||||
redirfile_out, oflags, 0644);
|
||||
if (ret != 0)
|
||||
{
|
||||
serr("ERROR: posix_spawn_file_actions_addopen failed: %d\n", ret);
|
||||
|
@ -64,13 +64,15 @@ extern "C"
|
||||
* New application is run in a separate task context (and thread).
|
||||
*
|
||||
* Input Parameter:
|
||||
* filename - Name of the linked-in binary to be started.
|
||||
* argv - Argument list
|
||||
* redirfile - If output is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* oflags - If output is redirected, this parameter will provide the
|
||||
* open flags to use. This will support file replacement
|
||||
* of appending to an existing file.
|
||||
* filename - Name of the linked-in binary to be started.
|
||||
* argv - Argument list
|
||||
* redirfile_in - If input is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* redirfile_out - If output is redirected, this parameter will be non-NULL
|
||||
* and will provide the full path to the file.
|
||||
* oflags - If output is redirected, this parameter will provide the
|
||||
* open flags to use. This will support file replacement
|
||||
* of appending to an existing file.
|
||||
*
|
||||
* Returned Value:
|
||||
* This is an end-user function, so it follows the normal convention:
|
||||
@ -80,7 +82,8 @@ extern "C"
|
||||
****************************************************************************/
|
||||
|
||||
int exec_builtin(FAR const char *appname, FAR char * const *argv,
|
||||
FAR const char *redirfile, int oflags);
|
||||
FAR const char *redirfile_in, FAR const char *redirfile_out,
|
||||
int oflags);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
14
nshlib/nsh.h
14
nshlib/nsh.h
@ -654,15 +654,16 @@ enum nsh_npflags_e
|
||||
struct nsh_parser_s
|
||||
{
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
bool np_bg; /* true: The last command executed in background */
|
||||
bool np_bg; /* true: The last command executed in background */
|
||||
#endif
|
||||
bool np_redirect; /* true: Output from the last command was re-directed */
|
||||
bool np_fail; /* true: The last command failed */
|
||||
bool np_redir_out; /* true: Output from the last command was re-directed */
|
||||
bool np_redir_in; /* true: Input from the last command was re-directed */
|
||||
bool np_fail; /* true: The last command failed */
|
||||
#ifndef CONFIG_NSH_DISABLESCRIPT
|
||||
uint8_t np_flags; /* See nsh_npflags_e above */
|
||||
uint8_t np_flags; /* See nsh_npflags_e above */
|
||||
#endif
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
int np_nice; /* "nice" value applied to last background cmd */
|
||||
int np_nice; /* "nice" value applied to last background cmd */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NSH_DISABLESCRIPT
|
||||
@ -852,7 +853,8 @@ int nsh_command(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char *argv[]);
|
||||
|
||||
#ifdef CONFIG_NSH_BUILTIN_APPS
|
||||
int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
|
||||
FAR char **argv, FAR const char *redirfile, int oflags);
|
||||
FAR char **argv, FAR const char *redirfile_in,
|
||||
FAR const char *redirfile_out, int oflags);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NSH_FILE_APPS
|
||||
|
@ -98,6 +98,10 @@ static int nsh_clone_console(FAR struct console_stdio_s *pstate)
|
||||
|
||||
OUTFD(pstate) = 1;
|
||||
|
||||
/* Setup stdin */
|
||||
|
||||
INFD(pstate) = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
|
||||
FAR char **argv, FAR const char *redirfile, int oflags)
|
||||
FAR char **argv, FAR const char *redirfile_in,
|
||||
FAR const char *redirfile_out, int oflags)
|
||||
{
|
||||
#if !defined(CONFIG_NSH_DISABLEBG) && defined(CONFIG_SCHED_CHILD_STATUS)
|
||||
struct sigaction act;
|
||||
@ -101,7 +102,7 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
|
||||
* applications.
|
||||
*/
|
||||
|
||||
ret = exec_builtin(cmd, argv, redirfile, oflags);
|
||||
ret = exec_builtin(cmd, argv, redirfile_in, redirfile_out, oflags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* The application was successfully started with pre-emption disabled.
|
||||
|
@ -47,6 +47,7 @@ struct serialsave_s
|
||||
{
|
||||
int cn_errfd; /* Re-directed error output file descriptor */
|
||||
int cn_outfd; /* Re-directed output file descriptor */
|
||||
int cn_infd; /* Re-directed input file descriptor */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -68,8 +69,8 @@ static int nsh_erroroutput(FAR struct nsh_vtbl_s *vtbl,
|
||||
FAR const char *fmt, ...) printf_like(2, 3);
|
||||
#endif
|
||||
static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl);
|
||||
static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd,
|
||||
FAR uint8_t *save);
|
||||
static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd_in,
|
||||
int fd_out, FAR uint8_t *save);
|
||||
static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl,
|
||||
FAR uint8_t *save);
|
||||
static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl,
|
||||
@ -100,8 +101,14 @@ static void nsh_closeifnotclosed(struct console_stdio_s *pstate)
|
||||
close(ERRFD(pstate));
|
||||
}
|
||||
|
||||
if (INFD(pstate) >= 0 && INFD(pstate) != STDIN_FILENO)
|
||||
{
|
||||
close(INFD(pstate));
|
||||
}
|
||||
|
||||
ERRFD(pstate) = -1;
|
||||
OUTFD(pstate) = -1;
|
||||
INFD(pstate) = -1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -290,8 +297,8 @@ static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd,
|
||||
FAR uint8_t *save)
|
||||
static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd_in,
|
||||
int fd_out, FAR uint8_t *save)
|
||||
{
|
||||
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
|
||||
FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
|
||||
@ -306,11 +313,13 @@ static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd,
|
||||
|
||||
ERRFD(ssave) = ERRFD(pstate);
|
||||
OUTFD(ssave) = OUTFD(pstate);
|
||||
INFD(ssave) = INFD(pstate);
|
||||
}
|
||||
|
||||
/* Set the fd of the new. */
|
||||
|
||||
OUTFD(pstate) = fd;
|
||||
OUTFD(pstate) = fd_out;
|
||||
INFD(pstate) = fd_in;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -330,6 +339,7 @@ static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl,
|
||||
nsh_closeifnotclosed(pstate);
|
||||
ERRFD(pstate) = ERRFD(ssave);
|
||||
OUTFD(pstate) = OUTFD(ssave);
|
||||
INFD(pstate) = INFD(ssave);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -395,6 +405,10 @@ FAR struct console_stdio_s *nsh_newconsole(bool isctty)
|
||||
/* Initialize the output stream */
|
||||
|
||||
OUTFD(pstate) = STDOUT_FILENO;
|
||||
|
||||
/* Initialize the input stream */
|
||||
|
||||
INFD(pstate) = STDIN_FILENO;
|
||||
}
|
||||
|
||||
return pstate;
|
||||
|
@ -41,18 +41,18 @@
|
||||
|
||||
/* Method access macros */
|
||||
|
||||
#define nsh_clone(v) (v)->clone(v)
|
||||
#define nsh_release(v) (v)->release(v)
|
||||
#define nsh_write(v,b,n) (v)->write(v,b,n)
|
||||
#define nsh_ioctl(v,c,a) (v)->ioctl(v,c,a)
|
||||
#define nsh_linebuffer(v) (v)->linebuffer(v)
|
||||
#define nsh_redirect(v,f,s) (v)->redirect(v,f,s)
|
||||
#define nsh_undirect(v,s) (v)->undirect(v,s)
|
||||
#define nsh_exit(v,s) (v)->exit(v,s)
|
||||
#define nsh_clone(v) (v)->clone(v)
|
||||
#define nsh_release(v) (v)->release(v)
|
||||
#define nsh_write(v,b,n) (v)->write(v,b,n)
|
||||
#define nsh_ioctl(v,c,a) (v)->ioctl(v,c,a)
|
||||
#define nsh_linebuffer(v) (v)->linebuffer(v)
|
||||
#define nsh_redirect(v,fi,fo,s) (v)->redirect(v,fi,fo,s)
|
||||
#define nsh_undirect(v,s) (v)->undirect(v,s)
|
||||
#define nsh_exit(v,s) (v)->exit(v,s)
|
||||
|
||||
#ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# define nsh_error(v, ...) (v)->error(v, ##__VA_ARGS__)
|
||||
# define nsh_output(v, ...) (v)->output(v, ##__VA_ARGS__)
|
||||
# define nsh_error(v, ...) (v)->error(v, ##__VA_ARGS__)
|
||||
# define nsh_output(v, ...) (v)->output(v, ##__VA_ARGS__)
|
||||
# define nsh_none(v, ...) \
|
||||
do { if (0) nsh_output_none(v, ##__VA_ARGS__); } while (0)
|
||||
#else
|
||||
@ -85,7 +85,7 @@
|
||||
|
||||
#else
|
||||
|
||||
# define INFD(p) 0
|
||||
# define INFD(p) ((p)->cn_infd)
|
||||
|
||||
#endif
|
||||
|
||||
@ -121,7 +121,8 @@ struct nsh_vtbl_s
|
||||
int (*output)(FAR struct nsh_vtbl_s *vtbl, FAR const char *fmt, ...)
|
||||
printf_like(2, 3);
|
||||
FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl);
|
||||
void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save);
|
||||
void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd_in, int fd_out,
|
||||
FAR uint8_t *save);
|
||||
void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save);
|
||||
void (*exit)(FAR struct nsh_vtbl_s *vtbl, int status) noreturn_function;
|
||||
|
||||
@ -163,6 +164,7 @@ struct console_stdio_s
|
||||
#ifdef CONFIG_NSH_ALTCONDEV
|
||||
int cn_confd; /* Console I/O file descriptor */
|
||||
#endif
|
||||
int cn_infd; /* Input file descriptor (possibly redirected) */
|
||||
int cn_outfd; /* Output file descriptor (possibly redirected) */
|
||||
int cn_errfd; /* Error Output file descriptor (possibly redirected) */
|
||||
|
||||
|
@ -131,7 +131,8 @@
|
||||
struct cmdarg_s
|
||||
{
|
||||
FAR struct nsh_vtbl_s *vtbl; /* For front-end interaction */
|
||||
int fd; /* FD for output redirection */
|
||||
int fd_in; /* FD for output redirection */
|
||||
int fd_out; /* FD for output redirection */
|
||||
int argc; /* Number of arguments in argv */
|
||||
FAR char *argv[MAX_ARGV_ENTRIES]; /* Argument list */
|
||||
};
|
||||
@ -176,13 +177,13 @@ static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl,
|
||||
static void nsh_releaseargs(struct cmdarg_s *arg);
|
||||
static pthread_addr_t nsh_child(pthread_addr_t arg);
|
||||
static struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
|
||||
int fd, int argc, FAR char *argv[]);
|
||||
int fd_in, int fd_out, int argc, FAR char *argv[]);
|
||||
#endif
|
||||
|
||||
static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result);
|
||||
static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
int argc, FAR char *argv[], FAR const char *redirfile,
|
||||
int oflags);
|
||||
int argc, FAR char *argv[], FAR const char *redirfile_in,
|
||||
FAR const char *redirfile_out, int oflags);
|
||||
|
||||
#ifdef CONFIG_NSH_CMDPARMS
|
||||
static FAR char *nsh_filecat(FAR struct nsh_vtbl_s *vtbl, FAR char *s1,
|
||||
@ -258,7 +259,7 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
|
||||
|
||||
#ifdef CONFIG_NSH_CMDPARMS
|
||||
static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline,
|
||||
FAR const char *redirfile);
|
||||
FAR const char *redirfile_out);
|
||||
#endif
|
||||
|
||||
static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline);
|
||||
@ -275,8 +276,9 @@ static const char g_line_separator[] = "\"'#;\n";
|
||||
#ifdef CONFIG_NSH_ARGCAT
|
||||
static const char g_arg_separator[] = "`$";
|
||||
#endif
|
||||
static const char g_redirect1[] = ">";
|
||||
static const char g_redirect2[] = ">>";
|
||||
static const char g_redirect_out1[] = ">";
|
||||
static const char g_redirect_out2[] = ">>";
|
||||
static const char g_redirect_in1[] = "<";
|
||||
#ifdef NSH_HAVE_VARS
|
||||
static const char g_exitstatus[] = "?";
|
||||
static const char g_success[] = "0";
|
||||
@ -454,9 +456,16 @@ static void nsh_releaseargs(struct cmdarg_s *arg)
|
||||
* the file descriptor
|
||||
*/
|
||||
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out)
|
||||
{
|
||||
close(arg->fd);
|
||||
close(arg->fd_out);
|
||||
}
|
||||
|
||||
/* Same for the input */
|
||||
|
||||
if (vtbl->np.np_redir_in)
|
||||
{
|
||||
close(arg->fd_in);
|
||||
}
|
||||
|
||||
/* Released the cloned vtbl instance */
|
||||
@ -504,7 +513,8 @@ static pthread_addr_t nsh_child(pthread_addr_t arg)
|
||||
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
static struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
|
||||
int fd, int argc, FAR char *argv[])
|
||||
int fd_in, int fd_out, int argc,
|
||||
FAR char *argv[])
|
||||
{
|
||||
struct cmdarg_s *ret = (struct cmdarg_s *)zalloc(sizeof(struct cmdarg_s));
|
||||
int i;
|
||||
@ -512,7 +522,8 @@ static struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
|
||||
if (ret)
|
||||
{
|
||||
ret->vtbl = vtbl;
|
||||
ret->fd = fd;
|
||||
ret->fd_in = fd_in;
|
||||
ret->fd_out = fd_out;
|
||||
ret->argc = argc;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
@ -594,9 +605,11 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
|
||||
|
||||
static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
int argc, FAR char *argv[],
|
||||
FAR const char *redirfile, int oflags)
|
||||
FAR const char *redirfile_in,
|
||||
FAR const char *redirfile_out, int oflags)
|
||||
{
|
||||
int fd = -1;
|
||||
int fd_in = STDIN_FILENO;
|
||||
int fd_out = STDOUT_FILENO;
|
||||
int ret;
|
||||
|
||||
/* DO NOT CHANGE THE ORDERING OF THE FOLLOWING STEPS
|
||||
@ -634,7 +647,8 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NSH_BUILTIN_APPS
|
||||
ret = nsh_builtin(vtbl, argv[0], argv, redirfile, oflags);
|
||||
ret = nsh_builtin(vtbl, argv[0], argv, redirfile_in, redirfile_out,
|
||||
oflags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* nsh_builtin() returned 0 or 1. This means that the built-in
|
||||
@ -671,7 +685,7 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NSH_FILE_APPS
|
||||
ret = nsh_fileapp(vtbl, argv[0], argv, redirfile, oflags);
|
||||
ret = nsh_fileapp(vtbl, argv[0], argv, redirfile_out, oflags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* nsh_fileapp() returned 0 or 1. This means that the built-in
|
||||
@ -692,7 +706,7 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
|
||||
/* Redirected output? */
|
||||
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out)
|
||||
{
|
||||
/* Open the redirection file. This file will eventually
|
||||
* be closed by a call to either nsh_release (if the command
|
||||
@ -700,8 +714,26 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
* command is executed in the foreground.
|
||||
*/
|
||||
|
||||
fd = open(redirfile, oflags, 0666);
|
||||
if (fd < 0)
|
||||
fd_out = open(redirfile_out, oflags, 0666);
|
||||
if (fd_out < 0)
|
||||
{
|
||||
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
/* Redirected input? */
|
||||
|
||||
if (vtbl->np.np_redir_in)
|
||||
{
|
||||
/* Open the redirection file. This file will eventually
|
||||
* be closed by a call to either nsh_release (if the command
|
||||
* is executed in the background) or by nsh_undirect if the
|
||||
* command is executed in the foreground.
|
||||
*/
|
||||
|
||||
fd_in = open(redirfile_in, O_RDONLY, 0);
|
||||
if (fd_in < 0)
|
||||
{
|
||||
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
|
||||
goto errout;
|
||||
@ -735,7 +767,7 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
|
||||
/* Create a container for the command arguments */
|
||||
|
||||
args = nsh_cloneargs(bkgvtbl, fd, argc, argv);
|
||||
args = nsh_cloneargs(bkgvtbl, fd_in, fd_out, argc, argv);
|
||||
if (!args)
|
||||
{
|
||||
nsh_release(bkgvtbl);
|
||||
@ -744,9 +776,9 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
|
||||
/* Handle redirection of output via a file descriptor */
|
||||
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out || vtbl->np.np_redir_in)
|
||||
{
|
||||
nsh_redirect(bkgvtbl, fd, NULL);
|
||||
nsh_redirect(bkgvtbl, fd_in, fd_out, NULL);
|
||||
}
|
||||
|
||||
/* Get the execution priority of this task */
|
||||
@ -824,11 +856,11 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
{
|
||||
uint8_t save[SAVE_SIZE];
|
||||
|
||||
/* Handle redirection of output via a file descriptor */
|
||||
/* Handle redirection of stdin/stdout file descriptor */
|
||||
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out || vtbl->np.np_redir_in)
|
||||
{
|
||||
nsh_redirect(vtbl, fd, save);
|
||||
nsh_redirect(vtbl, fd_in, fd_out, save);
|
||||
}
|
||||
|
||||
/* Then execute the command in "foreground" -- i.e., while the user
|
||||
@ -844,7 +876,7 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
* file descriptor.
|
||||
*/
|
||||
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out || vtbl->np.np_redir_in)
|
||||
{
|
||||
nsh_undirect(vtbl, save);
|
||||
}
|
||||
@ -867,9 +899,14 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
|
||||
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
errout_with_redirect:
|
||||
if (vtbl->np.np_redirect)
|
||||
if (vtbl->np.np_redir_out)
|
||||
{
|
||||
close(fd);
|
||||
close(fd_out);
|
||||
}
|
||||
|
||||
if (vtbl->np.np_redir_in)
|
||||
{
|
||||
close(fd_in);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1719,15 +1756,23 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl,
|
||||
if (*(pbegin + 1) == '>')
|
||||
{
|
||||
*saveptr = pbegin + 2;
|
||||
argument = (FAR char *)g_redirect2;
|
||||
argument = (FAR char *)g_redirect_out2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*saveptr = pbegin + 1;
|
||||
argument = (FAR char *)g_redirect1;
|
||||
argument = (FAR char *)g_redirect_out1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Does the token begin with '<' -- redirection of input? */
|
||||
|
||||
if (*pbegin == '<')
|
||||
{
|
||||
*saveptr = pbegin + 1;
|
||||
argument = (FAR char *)g_redirect_in1;
|
||||
}
|
||||
|
||||
/* Does the token begin with '#' -- comment */
|
||||
|
||||
else if (*pbegin == '#')
|
||||
@ -2411,7 +2456,7 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
|
||||
|
||||
#ifdef CONFIG_NSH_CMDPARMS
|
||||
static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline,
|
||||
FAR const char *redirfile)
|
||||
FAR const char *redirfile_out)
|
||||
{
|
||||
NSH_MEMLIST_TYPE memlist;
|
||||
NSH_ALIASLIST_TYPE alist;
|
||||
@ -2447,8 +2492,8 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline,
|
||||
|
||||
/* Output is always redirected. Remember the current redirection state */
|
||||
|
||||
redirsave = vtbl->np.np_redirect;
|
||||
vtbl->np.np_redirect = true;
|
||||
redirsave = vtbl->np.np_redir_out;
|
||||
vtbl->np.np_redir_out = true;
|
||||
|
||||
/* Parse out the command at the beginning of the line */
|
||||
|
||||
@ -2506,7 +2551,7 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline,
|
||||
|
||||
/* Then execute the command */
|
||||
|
||||
ret = nsh_execute(vtbl, argc, argv, redirfile,
|
||||
ret = nsh_execute(vtbl, argc, argv, NULL, redirfile_out,
|
||||
O_WRONLY | O_CREAT | O_TRUNC);
|
||||
|
||||
/* Restore the backgrounding and redirection state */
|
||||
@ -2515,7 +2560,7 @@ exit:
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
vtbl->np.np_bg = bgsave;
|
||||
#endif
|
||||
vtbl->np.np_redirect = redirsave;
|
||||
vtbl->np.np_redir_out = redirsave;
|
||||
|
||||
NSH_ALIASLIST_FREE(vtbl, &alist);
|
||||
NSH_MEMLIST_FREE(&memlist);
|
||||
@ -2538,11 +2583,16 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
FAR char *argv[MAX_ARGV_ENTRIES];
|
||||
FAR char *saveptr;
|
||||
FAR char *cmd;
|
||||
FAR char *redirfile = NULL;
|
||||
FAR char *redirfile_out = NULL;
|
||||
FAR char *redirfile_in = NULL;
|
||||
int oflags = 0;
|
||||
int argc;
|
||||
int ret;
|
||||
bool redirect_save = false;
|
||||
bool redirect_out_save = false;
|
||||
bool redirect_in_save = false;
|
||||
size_t redirect_out1_len = strlen(g_redirect_out1);
|
||||
size_t redirect_out2_len = strlen(g_redirect_out2);
|
||||
size_t redirect_in1_len = strlen(g_redirect_in1);
|
||||
|
||||
/* Initialize parser state */
|
||||
|
||||
@ -2554,7 +2604,8 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
vtbl->np.np_bg = false;
|
||||
#endif
|
||||
|
||||
vtbl->np.np_redirect = false;
|
||||
vtbl->np.np_redir_out = false;
|
||||
vtbl->np.np_redir_in = false;
|
||||
|
||||
/* Parse out the command at the beginning of the line */
|
||||
|
||||
@ -2619,16 +2670,13 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
* argv[0]: The command name.
|
||||
* argv[1]: The beginning of argument (up to
|
||||
* CONFIG_NSH_MAXARGUMENTS)
|
||||
* argv[argc-3]: Possibly '>' or '>>'
|
||||
* argv[argc-2]: Possibly <file>
|
||||
* argv[argc-1]: Possibly '&'
|
||||
* argv[argc]: NULL terminating pointer
|
||||
*
|
||||
* Maximum size is CONFIG_NSH_MAXARGUMENTS+5
|
||||
*/
|
||||
|
||||
argv[0] = cmd;
|
||||
for (argc = 1; argc < MAX_ARGV_ENTRIES - 1; argc++)
|
||||
for (argc = 1; argc < MAX_ARGV_ENTRIES - 1; )
|
||||
{
|
||||
int isenvvar = 0; /* flag for if an environment variable gets expanded */
|
||||
|
||||
@ -2685,6 +2733,81 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
argv[argc] = pbegin;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(argv[argc], g_redirect_out2, redirect_out2_len))
|
||||
{
|
||||
FAR char *arg;
|
||||
if (argv[argc][redirect_out2_len])
|
||||
{
|
||||
arg = &argv[argc][redirect_out2_len];
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = nsh_argument(vtbl, &saveptr, &memlist, NULL, &isenvvar);
|
||||
}
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
nsh_error(vtbl, g_fmtarginvalid, cmd);
|
||||
ret = ERROR;
|
||||
goto dynlist_free;
|
||||
}
|
||||
|
||||
redirect_out_save = vtbl->np.np_redir_out;
|
||||
vtbl->np.np_redir_out = true;
|
||||
oflags = O_WRONLY | O_CREAT | O_APPEND;
|
||||
redirfile_out = nsh_getfullpath(vtbl, arg);
|
||||
}
|
||||
else if (!strncmp(argv[argc], g_redirect_out1, redirect_out1_len))
|
||||
{
|
||||
FAR char *arg;
|
||||
if (argv[argc][redirect_out1_len])
|
||||
{
|
||||
arg = &argv[argc][redirect_out1_len];
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = nsh_argument(vtbl, &saveptr, &memlist, NULL, &isenvvar);
|
||||
}
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
nsh_error(vtbl, g_fmtarginvalid, cmd);
|
||||
ret = ERROR;
|
||||
goto dynlist_free;
|
||||
}
|
||||
|
||||
redirect_out_save = vtbl->np.np_redir_out;
|
||||
vtbl->np.np_redir_out = true;
|
||||
oflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
redirfile_out = nsh_getfullpath(vtbl, arg);
|
||||
}
|
||||
else if (!strncmp(argv[argc], g_redirect_in1, redirect_in1_len))
|
||||
{
|
||||
FAR char *arg;
|
||||
if (argv[argc][redirect_in1_len])
|
||||
{
|
||||
arg = &argv[argc][redirect_in1_len];
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = nsh_argument(vtbl, &saveptr, &memlist, NULL, &isenvvar);
|
||||
}
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
nsh_error(vtbl, g_fmtarginvalid, cmd);
|
||||
ret = ERROR;
|
||||
goto dynlist_free;
|
||||
}
|
||||
|
||||
redirect_in_save = vtbl->np.np_redir_in;
|
||||
vtbl->np.np_redir_in = true;
|
||||
redirfile_in = nsh_getfullpath(vtbl, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
argc++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the command should run in background */
|
||||
@ -2697,33 +2820,6 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if the output was re-directed using > or >> */
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
/* Check for redirection to a new file */
|
||||
|
||||
if (strcmp(argv[argc - 2], g_redirect1) == 0)
|
||||
{
|
||||
redirect_save = vtbl->np.np_redirect;
|
||||
vtbl->np.np_redirect = true;
|
||||
oflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
redirfile = nsh_getfullpath(vtbl, argv[argc - 1]);
|
||||
argc -= 2;
|
||||
}
|
||||
|
||||
/* Check for redirection by appending to an existing file */
|
||||
|
||||
else if (strcmp(argv[argc - 2], g_redirect2) == 0)
|
||||
{
|
||||
redirect_save = vtbl->np.np_redirect;
|
||||
vtbl->np.np_redirect = true;
|
||||
oflags = O_WRONLY | O_CREAT | O_APPEND;
|
||||
redirfile = nsh_getfullpath(vtbl, argv[argc - 1]);
|
||||
argc -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Last argument vector must be empty */
|
||||
|
||||
argv[argc] = NULL;
|
||||
@ -2737,16 +2833,22 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
|
||||
|
||||
/* Then execute the command */
|
||||
|
||||
ret = nsh_execute(vtbl, argc, argv, redirfile, oflags);
|
||||
ret = nsh_execute(vtbl, argc, argv, redirfile_in, redirfile_out, oflags);
|
||||
|
||||
/* Free any allocated resources */
|
||||
|
||||
/* Free the redirected output file path */
|
||||
|
||||
if (redirfile)
|
||||
if (redirfile_out)
|
||||
{
|
||||
nsh_freefullpath(redirfile);
|
||||
vtbl->np.np_redirect = redirect_save;
|
||||
nsh_freefullpath(redirfile_out);
|
||||
vtbl->np.np_redir_out = redirect_out_save;
|
||||
}
|
||||
|
||||
if (redirfile_in)
|
||||
{
|
||||
nsh_freefullpath(redirfile_in);
|
||||
vtbl->np.np_redir_out = redirect_in_save;
|
||||
}
|
||||
|
||||
dynlist_free:
|
||||
|
@ -54,7 +54,7 @@ static int nsh_script_redirect(FAR struct nsh_vtbl_s *vtbl,
|
||||
fd = open(CONFIG_NSH_SCRIPT_REDIRECT_PATH, 0666);
|
||||
if (fd > 0)
|
||||
{
|
||||
nsh_redirect(vtbl, fd, save);
|
||||
nsh_redirect(vtbl, 0, fd, save);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,8 @@ int cmd_time(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
bool bgsave;
|
||||
#endif
|
||||
bool redirsave;
|
||||
bool redirsave_out;
|
||||
bool redirsave_in;
|
||||
int ret;
|
||||
|
||||
/* Get the current time */
|
||||
@ -315,7 +316,8 @@ int cmd_time(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
bgsave = vtbl->np.np_bg;
|
||||
#endif
|
||||
redirsave = vtbl->np.np_redirect;
|
||||
redirsave_out = vtbl->np.np_redir_out;
|
||||
redirsave_in = vtbl->np.np_redir_in;
|
||||
|
||||
/* Execute the command */
|
||||
|
||||
@ -354,7 +356,8 @@ int cmd_time(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
||||
#ifndef CONFIG_NSH_DISABLEBG
|
||||
vtbl->np.np_bg = bgsave;
|
||||
#endif
|
||||
vtbl->np.np_redirect = redirsave;
|
||||
vtbl->np.np_redir_out = redirsave_out;
|
||||
vtbl->np.np_redir_out = redirsave_in;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ int main(int argc, FAR char *argv[])
|
||||
}
|
||||
|
||||
bypass[0] = (FAR char *)builtin->name;
|
||||
ret = exec_builtin(builtin->name, bypass, NULL, 0);
|
||||
ret = exec_builtin(builtin->name, bypass, NULL, NULL, 0);
|
||||
if (ret >= 0)
|
||||
{
|
||||
waitpid(ret, &ret, WUNTRACED);
|
||||
|
Loading…
Reference in New Issue
Block a user