Fix NSH redirection hang
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3326 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
5672afedbd
commit
8e96987058
14
ChangeLog
14
ChangeLog
@ -1485,3 +1485,17 @@
|
|||||||
|
|
||||||
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
|
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
|
||||||
Linux 'free' command.
|
Linux 'free' command.
|
||||||
|
* NSH: Correct a redirection bug in NSH. The following would not work; it
|
||||||
|
resulted in a hang after the 'cat /dev/fifo':
|
||||||
|
|
||||||
|
nsh> mkfile /dev/fifo
|
||||||
|
nsh> cd /tmp # /tmp is a mounted RAM disk
|
||||||
|
nsh> cat /dev/fifo > test.txt &
|
||||||
|
nsh> echo "This is a test" > /dev/fifo
|
||||||
|
|
||||||
|
The error was caused because (1) there was a path that resulted in stdout
|
||||||
|
being closed (the "hang") and also (2) the 'cat' command was always outputting
|
||||||
|
to stdout, not to the redirected file descriptor. Now:
|
||||||
|
|
||||||
|
nsh> cat test.txt
|
||||||
|
This is a test
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<tr align="center" bgcolor="#e4e4e4">
|
<tr align="center" bgcolor="#e4e4e4">
|
||||||
<td>
|
<td>
|
||||||
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
|
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
|
||||||
<p>Last Updated: February 27, 2011</p>
|
<p>Last Updated: February 28, 2011</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -2087,6 +2087,20 @@ nuttx-5.19 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
|||||||
|
|
||||||
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
|
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
|
||||||
Linux 'free' command.
|
Linux 'free' command.
|
||||||
|
* NSH: Correct a redirection bug in NSH. The following would not work; it
|
||||||
|
resulted in a hang after the 'cat /dev/fifo':
|
||||||
|
|
||||||
|
nsh> mkfile /dev/fifo
|
||||||
|
nsh> cd /tmp # /tmp is a mounted RAM disk
|
||||||
|
nsh> cat /dev/fifo > test.txt &
|
||||||
|
nsh> echo "This is a test" > /dev/fifo
|
||||||
|
|
||||||
|
The error was caused because (1) there was a path that resulted in stdout
|
||||||
|
being closed (the "hang") and also (2) the 'cat' command was always outputting
|
||||||
|
to stdout, not to the redirected file descriptor. Now:
|
||||||
|
|
||||||
|
nsh> cat test.txt
|
||||||
|
This is a test
|
||||||
|
|
||||||
pascal-2.1 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
pascal-2.1 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
|
|
||||||
#define nsh_clone(v) (v)->clone(v)
|
#define nsh_clone(v) (v)->clone(v)
|
||||||
#define nsh_release(v) (v)->release(v)
|
#define nsh_release(v) (v)->release(v)
|
||||||
|
#define nsh_write(v,b,n) (v)->write(v,b,n)
|
||||||
#define nsh_linebuffer(v) (v)->linebuffer(v)
|
#define nsh_linebuffer(v) (v)->linebuffer(v)
|
||||||
#define nsh_redirect(v,f,s) (v)->redirect(v,f,s)
|
#define nsh_redirect(v,f,s) (v)->redirect(v,f,s)
|
||||||
#define nsh_undirect(v,s) (v)->undirect(v,s)
|
#define nsh_undirect(v,s) (v)->undirect(v,s)
|
||||||
@ -255,6 +256,7 @@ struct nsh_vtbl_s
|
|||||||
void (*addref)(FAR struct nsh_vtbl_s *vtbl);
|
void (*addref)(FAR struct nsh_vtbl_s *vtbl);
|
||||||
void (*release)(FAR struct nsh_vtbl_s *vtbl);
|
void (*release)(FAR struct nsh_vtbl_s *vtbl);
|
||||||
#endif
|
#endif
|
||||||
|
ssize_t (*write)(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
|
||||||
int (*output)(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
int (*output)(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
||||||
FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl);
|
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, FAR uint8_t *save);
|
||||||
|
@ -457,7 +457,7 @@ int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
|
|||||||
|
|
||||||
while (nbyteswritten < nbytesread)
|
while (nbyteswritten < nbytesread)
|
||||||
{
|
{
|
||||||
int n = write(1, buffer, nbytesread);
|
ssize_t n = nsh_write(vtbl, buffer, nbytesread);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
/* EINTR is not an error (but will stop stop the cat) */
|
/* EINTR is not an error (but will stop stop the cat) */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* examples/nsh/nsh_serial.c
|
* examples/nsh/nsh_serial.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -45,6 +45,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
#include "nsh.h"
|
#include "nsh.h"
|
||||||
|
|
||||||
@ -78,6 +80,7 @@ struct serialsave_s
|
|||||||
static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl);
|
static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl);
|
||||||
static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl);
|
static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl);
|
||||||
#endif
|
#endif
|
||||||
|
static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
|
||||||
static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
||||||
static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl);
|
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, FAR uint8_t *save);
|
||||||
@ -109,6 +112,7 @@ static inline FAR struct serial_s *nsh_allocstruct(void)
|
|||||||
pstate->ss_vtbl.clone = nsh_consoleclone;
|
pstate->ss_vtbl.clone = nsh_consoleclone;
|
||||||
pstate->ss_vtbl.release = nsh_consolerelease;
|
pstate->ss_vtbl.release = nsh_consolerelease;
|
||||||
#endif
|
#endif
|
||||||
|
pstate->ss_vtbl.write = nsh_consolewrite;
|
||||||
pstate->ss_vtbl.output = nsh_consoleoutput;
|
pstate->ss_vtbl.output = nsh_consoleoutput;
|
||||||
pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer;
|
pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer;
|
||||||
pstate->ss_vtbl.redirect = nsh_consoleredirect;
|
pstate->ss_vtbl.redirect = nsh_consoleredirect;
|
||||||
@ -170,6 +174,41 @@ static void nsh_closeifnotclosed(struct serial_s *pstate)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nsh_consolewrite
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* write a buffer to the remote shell window.
|
||||||
|
*
|
||||||
|
* Currently only used by cat.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes)
|
||||||
|
{
|
||||||
|
FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
/* The stream is open in a lazy fashion. This is done because the file
|
||||||
|
* descriptor may be opened on a different task than the stream. The
|
||||||
|
* actual open will then occur with the first output from the new task.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nsh_openifnotopen(pstate) != 0)
|
||||||
|
{
|
||||||
|
return (ssize_t)ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the data to the output stream */
|
||||||
|
|
||||||
|
ret = fwrite(buffer, 1, nbytes, pstate->ss_stream);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
dbg("[%d] Failed to send buffer: %d\n", pstate->ss_fd, errno);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nsh_consoleoutput
|
* Name: nsh_consoleoutput
|
||||||
*
|
*
|
||||||
@ -265,7 +304,29 @@ static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl)
|
|||||||
* Name: nsh_consoleredirect
|
* Name: nsh_consoleredirect
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set up for redirected output
|
* Set up for redirected output. This function is called from nsh_parse()
|
||||||
|
* in two different contexts:
|
||||||
|
*
|
||||||
|
* 1) Redirected background commands of the form: command > xyz.text &
|
||||||
|
*
|
||||||
|
* In this case:
|
||||||
|
* - vtbl: A newly allocated and initialized instance created by
|
||||||
|
* nsh_consoleclone,
|
||||||
|
* - fd:- The file descriptor of the redirected output
|
||||||
|
* - save: NULL
|
||||||
|
*
|
||||||
|
* nsh_consolerelease() will perform the clean-up when the clone is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* 2) Redirected foreground commands of the form: command > xyz.txt
|
||||||
|
*
|
||||||
|
* In this case:
|
||||||
|
* - vtbl: The current state structure,
|
||||||
|
* - fd: The file descriptor of the redirected output
|
||||||
|
* - save: Where to save the re-directed registers.
|
||||||
|
*
|
||||||
|
* nsh_consoleundirect() will perform the clean-up after the redirected
|
||||||
|
* command completes.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@ -274,18 +335,39 @@ static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t
|
|||||||
FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
|
FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
|
||||||
FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
|
FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
|
||||||
|
|
||||||
(void)nsh_openifnotopen(pstate);
|
/* Case 1: Redirected foreground commands */
|
||||||
fflush(pstate->ss_stream);
|
|
||||||
if (ssave)
|
if (ssave)
|
||||||
{
|
{
|
||||||
|
/* pstate->ss_stream and ss_fd refer refer to the
|
||||||
|
* currently opened output stream. If the console is open, flush
|
||||||
|
* any pending output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (pstate->ss_stream)
|
||||||
|
{
|
||||||
|
fflush(pstate->ss_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the current fd and stream values. These will be restored
|
||||||
|
* when nsh_consoleundirect() is called.
|
||||||
|
*/
|
||||||
|
|
||||||
ssave->ss_fd = pstate->ss_fd;
|
ssave->ss_fd = pstate->ss_fd;
|
||||||
ssave->ss_stream = pstate->ss_stream;
|
ssave->ss_stream = pstate->ss_stream;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fclose(pstate->ss_stream);
|
/* nsh_consoleclone() set pstate->ss_fd and ss_stream to refer
|
||||||
|
* to standard out. We just want to leave these alone and overwrite
|
||||||
|
* them with the fd for the re-directed stream.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In either case, set the fd of the new, re-directed output and nullify
|
||||||
|
* the output stream (it will be fdopen'ed if it is used).
|
||||||
|
*/
|
||||||
|
|
||||||
pstate->ss_fd = fd;
|
pstate->ss_fd = fd;
|
||||||
pstate->ss_stream = NULL;
|
pstate->ss_stream = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* examples/nsh/nsh_telnetd.c
|
* examples/nsh/nsh_telnetd.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2010 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
*
|
*
|
||||||
* This is a leverage of similar logic from uIP:
|
* This is a leverage of similar logic from uIP:
|
||||||
@ -147,6 +147,7 @@ static void tio_semtake(struct telnetio_s *tio);
|
|||||||
static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl);
|
static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl);
|
||||||
#endif
|
#endif
|
||||||
static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl);
|
static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl);
|
||||||
|
static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
|
||||||
static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
||||||
static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
||||||
static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl);
|
static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl);
|
||||||
@ -195,6 +196,7 @@ static FAR struct telnetd_s *nsh_allocstruct(void)
|
|||||||
pstate->tn_vtbl.clone = nsh_telnetclone;
|
pstate->tn_vtbl.clone = nsh_telnetclone;
|
||||||
pstate->tn_vtbl.release = nsh_telnetrelease;
|
pstate->tn_vtbl.release = nsh_telnetrelease;
|
||||||
#endif
|
#endif
|
||||||
|
pstate->tn_vtbl.write = nsh_telnetwrite;
|
||||||
pstate->tn_vtbl.output = nsh_telnetoutput;
|
pstate->tn_vtbl.output = nsh_telnetoutput;
|
||||||
pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer;
|
pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer;
|
||||||
pstate->tn_vtbl.redirect = nsh_telnetredirect;
|
pstate->tn_vtbl.redirect = nsh_telnetredirect;
|
||||||
@ -537,6 +539,41 @@ static void *nsh_connection(void *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nsh_telnetwrite
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* write a buffer to the remote shell window.
|
||||||
|
*
|
||||||
|
* Currently only used by cat.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes)
|
||||||
|
{
|
||||||
|
struct telnetd_s *pstate = (struct telnetd_s *)vtbl;
|
||||||
|
struct telnetio_s *tio = pstate->u.tn;
|
||||||
|
ssize_t ret = nbytes;
|
||||||
|
|
||||||
|
/* Flush anything already in the output buffer */
|
||||||
|
|
||||||
|
nsh_flush(pstate);
|
||||||
|
|
||||||
|
/* Then write the user buffer */
|
||||||
|
|
||||||
|
nsh_telnetdump(&pstate->tn_vtbl, "Buffer output",(uint8_t*)buffer, nbytes);
|
||||||
|
|
||||||
|
tio_semtake(tio); /* Only one call to send at a time */
|
||||||
|
ret = send(tio->tio_sockfd, buffer, nbytes, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
dbg("[%d] Failed to send buffer: %d\n", tio->tio_sockfd, errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
tio_semgive(tio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nsh_telnetoutput
|
* Name: nsh_telnetoutput
|
||||||
*
|
*
|
||||||
@ -704,7 +741,29 @@ static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl)
|
|||||||
* Name: nsh_telnetredirect
|
* Name: nsh_telnetredirect
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set up for redirected output
|
* Set up for redirected output. This function is called from nsh_parse()
|
||||||
|
* in two different contexts:
|
||||||
|
*
|
||||||
|
* 1) Redirected background commands of the form: command > xyz.text &
|
||||||
|
*
|
||||||
|
* In this case:
|
||||||
|
* - vtbl: A newly allocated and initialized instance created by
|
||||||
|
* nsh_telnetclone,
|
||||||
|
* - fd:- The file descriptor of the redirected output
|
||||||
|
* - save: NULL
|
||||||
|
*
|
||||||
|
* nsh_telnetrelease() will perform the clean-up when the clone is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* 2) Redirected foreground commands of the form: command > xyz.txt
|
||||||
|
*
|
||||||
|
* In this case:
|
||||||
|
* - vtbl: The current state structure,
|
||||||
|
* - fd: The file descriptor of the redirected output
|
||||||
|
* - save: Where to save the re-directed registers.
|
||||||
|
*
|
||||||
|
* nsh_telnetundirect() will perform the clean-up after the redirected
|
||||||
|
* command completes.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user