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:
patacongo 2011-03-01 02:32:50 +00:00
parent 5672afedbd
commit 8e96987058
6 changed files with 180 additions and 9 deletions

View File

@ -1485,3 +1485,17 @@
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
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

View File

@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<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>
</tr>
</table>
@ -2087,6 +2087,20 @@ nuttx-5.19 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* NSH: 'mem' command renamed to 'free'. Output is now more similar to the
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 &lt;spudmonkey@racsa.co.cr&gt;

View File

@ -177,6 +177,7 @@
#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_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)
@ -255,6 +256,7 @@ struct nsh_vtbl_s
void (*addref)(FAR struct nsh_vtbl_s *vtbl);
void (*release)(FAR struct nsh_vtbl_s *vtbl);
#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, ...);
FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl);
void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save);

View File

@ -457,7 +457,7 @@ int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
while (nbyteswritten < nbytesread)
{
int n = write(1, buffer, nbytesread);
ssize_t n = nsh_write(vtbl, buffer, nbytesread);
if (n < 0)
{
/* EINTR is not an error (but will stop stop the cat) */

View File

@ -1,7 +1,7 @@
/****************************************************************************
* 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>
*
* Redistribution and use in source and binary forms, with or without
@ -45,6 +45,8 @@
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <debug.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 void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl);
#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 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);
@ -109,6 +112,7 @@ static inline FAR struct serial_s *nsh_allocstruct(void)
pstate->ss_vtbl.clone = nsh_consoleclone;
pstate->ss_vtbl.release = nsh_consolerelease;
#endif
pstate->ss_vtbl.write = nsh_consolewrite;
pstate->ss_vtbl.output = nsh_consoleoutput;
pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer;
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
*
@ -265,7 +304,29 @@ static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl)
* Name: nsh_consoleredirect
*
* 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 serialsave_s *ssave = (FAR struct serialsave_s *)save;
(void)nsh_openifnotopen(pstate);
fflush(pstate->ss_stream);
/* Case 1: Redirected foreground commands */
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_stream = pstate->ss_stream;
}
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_stream = NULL;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* 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>
*
* 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);
#endif
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_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
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.release = nsh_telnetrelease;
#endif
pstate->tn_vtbl.write = nsh_telnetwrite;
pstate->tn_vtbl.output = nsh_telnetoutput;
pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer;
pstate->tn_vtbl.redirect = nsh_telnetredirect;
@ -537,6 +539,41 @@ static void *nsh_connection(void *arg)
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
*
@ -704,7 +741,29 @@ static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl)
* Name: nsh_telnetredirect
*
* 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.
*
****************************************************************************/