nshlib: fix infinite loop on broken stdout in nsh_catfile

When stdout is broken (e.g. PTY master closed), nsh_catfile could spin
forever: write() fails, error logging generates syslog output to
/dev/log, next read() picks it up, write() fails again, ad infinitum.

Two fixes:
- nsh_console: drop the _err() in nsh_consolewrite entirely.  The risk
  is errno-agnostic (EPIPE / EIO / ENOSPC / ...): any failure logged
  here can be re-injected by the syslog backend when OUTFD is bound to
  /dev/log.  Callers already see the failure via the negative return
  value and errno, so on-failure logging at this layer is redundant.
- nsh_fsutils: jump straight from the inner write-failure path to a
  single errout: cleanup label instead of using a two-level break +
  flag check, so a failed write cannot fall through to another read().

Assisted-by: GitHubCopilot:claude-4.7-opus
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
This commit is contained in:
wangjianyu3 2026-05-19 16:42:47 +08:00 committed by Alan C. Assis
parent 72bedd5c5d
commit ed063a0981
2 changed files with 19 additions and 11 deletions

View file

@ -131,18 +131,19 @@ static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl,
FAR const void *buffer, size_t nbytes)
{
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
ssize_t ret;
/* Write the data to the output stream */
/* Write the data to the output stream.
*
* Errors are reported to the caller via the negative return value and
* errno; do NOT _err() here. OUTFD may itself be wired to the syslog
* backend (e.g. nsh_catfile dumping /dev/log on dmesg), in which case
* logging on write failure would produce new bytes, get picked up by
* the next read(), and lock the shell into an infinite loop at the
* highest priority independent of which errno (EPIPE/EIO/ENOSPC/...)
* the underlying device returns.
*/
ret = write(OUTFD(pstate), buffer, nbytes);
if (ret < 0)
{
_err("ERROR: [%d] Failed to send buffer: %d\n",
OUTFD(pstate), errno);
}
return ret;
return write(OUTFD(pstate), buffer, nbytes);
}
/****************************************************************************

View file

@ -228,8 +228,14 @@ int nsh_catfile(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
NSH_ERRNO_OF(errcode));
}
/* Jump straight to cleanup. On a broken stdout (e.g.
* closed PTY master) we must not keep reading: the
* outer loop would otherwise drain /dev/log forever
* when cat is dumping it on dmesg.
*/
ret = ERROR;
break;
goto errout;
}
else
{
@ -255,6 +261,7 @@ int nsh_catfile(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
/* Close the input file and return the result */
errout:
close(fd);
free(buffer);
return ret;