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
|
||||
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">
|
||||
<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 <spudmonkey@racsa.co.cr>
|
||||
|
||||
* 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 <spudmonkey@racsa.co.cr>
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user