From e5cd2dd980302f328d232d933f646c3dc02828bf Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 27 Aug 2021 09:36:06 +0100 Subject: 49290: Replace stdio for buffered shell input. The previous method allowed memory management to interact with signal handlers, causing occasional crashes on some system. Instead, use a simple pre-allocated buffer and raw system calls. --- Src/input.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 111 insertions(+), 11 deletions(-) (limited to 'Src/input.c') diff --git a/Src/input.c b/Src/input.c index f568cc135..3c6ad7002 100644 --- a/Src/input.c +++ b/Src/input.c @@ -80,11 +80,6 @@ /**/ int SHIN; -/* buffered shell input for non-interactive shells */ - -/**/ -FILE *bshin; - /* != 0 means we are reading input from a string */ /**/ @@ -129,7 +124,116 @@ static struct instacks *instack, *instacktop; static int instacksz = INSTACK_INITIAL; -/* Read a line from bshin. Convert tokens and * +/* Size of buffer for non-interactive command input */ + +#define SHINBUFSIZE 8192 + +/* Input buffer for non-interactive command input */ +static char *shinbuffer; + +/* Pointer into shinbuffer */ +static char *shinbufptr; + +/* End of contents read into shinbuffer */ +static char *shinbufendptr; + +/* Entry on SHIN buffer save stack */ +struct shinsaveentry { + /* Next entry on stack */ + struct shinsaveentry *next; + /* Saved shinbuffer */ + char *buffer; + /* Saved shinbufptr */ + char *ptr; + /* Saved shinbufendptr */ + char *endptr; +}; + +/* SHIN buffer save stack */ +struct shinsaveentry *shinsavestack; + +/* Reset the input buffer for SHIN, discarding any pending input */ + +/**/ +void +shinbufreset(void) +{ + shinbufendptr = shinbufptr = shinbuffer; +} + +/* Allocate a new shinbuffer + * + * Only called at shell initialisation and when saving on the stack. + */ + +/**/ +void +shinbufalloc(void) +{ + shinbuffer = zalloc(SHINBUFSIZE); + shinbufreset(); +} + +/* Save entry on SHIN buffer save stack */ + +/**/ +void +shinbufsave(void) +{ + struct shinsaveentry *entry = + (struct shinsaveentry *)zalloc(sizeof(struct shinsaveentry)); + + entry->next = shinsavestack; + entry->buffer = shinbuffer; + entry->ptr = shinbufptr; + entry->endptr = shinbufendptr; + + shinsavestack = entry; + + shinbufalloc(); +} + +/* Restore entry from SHIN buffer save stack */ + +/**/ +void +shinbufrestore(void) +{ + struct shinsaveentry *entry = shinsavestack; + + zfree(shinbuffer, SHINBUFSIZE); + + shinbuffer = entry->buffer; + shinbufptr = entry->ptr; + shinbufendptr = entry->endptr; + + shinsavestack = entry->next; + zfree(entry, sizeof(struct shinsaveentry)); +} + +/* Get a character from SHIN, -1 if none available */ + +/**/ +static int +shingetchar(void) +{ + int nread; + + if (shinbufptr < shinbufendptr) + return STOUC(*shinbufptr++); + + shinbufreset(); + do { + errno = 0; + nread = read(SHIN, shinbuffer, SHINBUFSIZE); + } while (nread < 0 && errno == EINTR); + if (nread <= 0) + return -1; + shinbufendptr = shinbuffer + nread; + return STOUC(*shinbufptr++); +} + +/* Read a line from SHIN. Convert tokens and * * null characters to Meta c^32 character pairs. */ /**/ @@ -147,11 +251,7 @@ shingetline(void) winch_unblock(); dont_queue_signals(); for (;;) { - /* Can't fgets() here because we need to accept '\0' bytes */ - do { - errno = 0; - c = fgetc(bshin); - } while (c < 0 && errno == EINTR); + c = shingetchar(); if (c < 0 || c == '\n') { winch_block(); restore_queue_signals(q); -- cgit 1.4.1