Re: read() builtin doesn't read integer value /proc files (but bash's does)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


2010/9/3 Jilles Tjoelker <jilles@xxxxxxxx>:
> This patch assumes that the file descriptor is discarded afterwards (its
> position does not matter). Therefore the very common construct
>  while read x; do
>    ...
>  done
> stops working.

Ohh.. thanks for that, I didn't see it.

Actually "while read x" continues to work.
But "reopening the file" doesn't as in :

read a b < datafile
echo ${a} ${b}
read a b < datafile
echo ${a} ${b}

I attached an updated patch that corrects this pb by discarding the
buffer when opening a new file.
I also put everything in new files (bufreadcmd.c & .h), in order to
ease its understanding.

--
Steve Schnepp
http://blog.pwkf.org/


>
> A possible fix is to check first if the input supports seeking. If it
> does, use the buffering and at the end of the line seek backwards for
> the number of bytes remaining in the buffer. If it does not, read one
> byte at a time.
>
> --
> Jilles Tjoelker
>


--
Steve Schnepp
http://blog.pwkf.org/
Common subdirectories: dash-0.5.4/src/bltin and dash-0.5.4-patched/src/bltin
diff -puN dash-0.5.4/src/bufreadcmd.c dash-0.5.4-patched/src/bufreadcmd.c
--- dash-0.5.4/src/bufreadcmd.c	1970-01-01 01:00:00.000000000 +0100
+++ dash-0.5.4-patched/src/bufreadcmd.c	2010-09-04 12:31:46.000000000 +0200
@@ -0,0 +1,59 @@
+/*
+ * Offers a buffered read builtin
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "bufreadcmd.h"
+
+#ifdef BUF_READ_BUILTIN_DISABLED
+int dup2_wrapper(int old, int new) {
+	return dup2(old, new);
+}
+int read_stdin_bufferred(char *c) {
+	return read(0, buffer, 1);
+}
+#else // BUF_READ_BUILTIN_DISABLED
+
+/*
+ * Reads from fd 0, with a CHUNK_READ_SIZE,
+ * but emitting one char at a time
+ */
+#define CHUNK_READ_SIZE 32
+static char buffer[CHUNK_READ_SIZE];
+static int buffer_offset = 0;
+static int buffer_len = 0;
+
+int read_stdin_bufferred(char* c) {
+       if (buffer_len == 0) {
+               // No caracter left, resetting buffer & read some more
+               buffer_offset = 0;
+               buffer_len = read(0, buffer, CHUNK_READ_SIZE);
+
+               if (buffer_len == 0) {
+                       // Nothing to read anymore
+                       return 0;
+               }
+       }
+
+       // Still some character left
+       *c = buffer[buffer_offset++];
+       buffer_len--;
+
+       return 1;
+}
+
+static void _flush_readcmd(int fd) {
+	if (fd == 0) { 
+		// Flush the buffer, discarding its content
+		buffer_len = 0;
+	}
+}
+
+/* Intercept dup2() calls */
+int dup2_wrapper(int old, int new) {
+	_flush_readcmd(new);
+	return dup2(old, new);
+}
+#endif // BUF_READ_BUILTIN_DISABLED
diff -puN dash-0.5.4/src/bufreadcmd.h dash-0.5.4-patched/src/bufreadcmd.h
--- dash-0.5.4/src/bufreadcmd.h	1970-01-01 01:00:00.000000000 +0100
+++ dash-0.5.4-patched/src/bufreadcmd.h	2010-09-04 12:23:53.000000000 +0200
@@ -0,0 +1,3 @@
+/* Used for flushing the readcmd read() buffer */
+int dup2_wrapper(int to, int from);
+int read_stdin_bufferred(char *c);
Common subdirectories: dash-0.5.4/src/.deps and dash-0.5.4-patched/src/.deps
diff -puN dash-0.5.4/src/eval.c dash-0.5.4-patched/src/eval.c
--- dash-0.5.4/src/eval.c	2007-07-13 10:26:42.000000000 +0200
+++ dash-0.5.4-patched/src/eval.c	2010-09-04 12:24:55.000000000 +0200
@@ -64,6 +64,8 @@
 #include "myhistedit.h"
 #endif
 
+#include "bufreadcmd.h"
+
 
 /* flags in argument to evaltree */
 #define EV_EXIT 01		/* exit after evaluating tree */
@@ -543,11 +545,12 @@ evalpipe(union node *n, int flags)
 				close(pip[0]);
 			}
 			if (prevfd > 0) {
-				dup2(prevfd, 0);
+				dup2_wrapper(prevfd, 0);
+
 				close(prevfd);
 			}
 			if (pip[1] > 1) {
-				dup2(pip[1], 1);
+				dup2_wrapper(pip[1], 1);
 				close(pip[1]);
 			}
 			evaltreenr(lp->n, flags);
@@ -625,7 +628,7 @@ evalbackcmd(union node *n, struct backcm
 			FORCEINTON;
 			close(pip[0]);
 			if (pip[1] != 1) {
-				dup2(pip[1], 1);
+				dup2_wrapper(pip[1], 1);
 				close(pip[1]);
 			}
 			eflag = 0;
diff -puN dash-0.5.4/src/Makefile dash-0.5.4-patched/src/Makefile
--- dash-0.5.4/src/Makefile	2010-09-04 13:06:05.000000000 +0200
+++ dash-0.5.4-patched/src/Makefile	2010-09-04 13:08:26.000000000 +0200
@@ -57,7 +57,7 @@ am__objects_1 = alias.$(OBJEXT) arith_yy
 	miscbltin.$(OBJEXT) mystring.$(OBJEXT) options.$(OBJEXT) \
 	parser.$(OBJEXT) redir.$(OBJEXT) show.$(OBJEXT) trap.$(OBJEXT) \
 	output.$(OBJEXT) printf.$(OBJEXT) system.$(OBJEXT) \
-	test.$(OBJEXT) times.$(OBJEXT) var.$(OBJEXT)
+	test.$(OBJEXT) times.$(OBJEXT) var.$(OBJEXT) bufreadcmd.$(OBJEXT)
 am_dash_OBJECTS = $(am__objects_1) arith.$(OBJEXT)
 dash_OBJECTS = $(am_dash_OBJECTS)
 dash_DEPENDENCIES = builtins.o init.o nodes.o signames.o syntax.o
@@ -169,14 +169,14 @@ dash_CFILES = \
 	alias.c arith_yylex.c cd.c error.c eval.c exec.c expand.c \
 	histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
 	mystring.c options.c parser.c redir.c show.c trap.c output.c \
-	bltin/printf.c system.c bltin/test.c bltin/times.c var.c
+	bltin/printf.c system.c bltin/test.c bltin/times.c var.c bufreadcmd.c
 
 dash_SOURCES = \
 	$(dash_CFILES) arith.y \
 	alias.h bltin/bltin.h cd.h error.h eval.h exec.h expand.h hetio.h \
 	init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
 	myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
-	show.h system.h trap.h var.h
+	show.h system.h trap.h var.h bufreadcmd.h
 
 dash_LDADD = builtins.o init.o nodes.o signames.o syntax.o
 HELPERS = mkinit mksyntax mknodes mksignames
diff -puN dash-0.5.4/src/miscbltin.c dash-0.5.4-patched/src/miscbltin.c
--- dash-0.5.4/src/miscbltin.c	2007-07-13 10:26:43.000000000 +0200
+++ dash-0.5.4-patched/src/miscbltin.c	2010-09-04 12:23:21.000000000 +0200
@@ -55,16 +55,17 @@
 #include "miscbltin.h"
 #include "mystring.h"
 #include "main.h"
+#include "bufreadcmd.h"
 
 #undef rflag
 
 
-
 /*
  * The read builtin.  The -e option causes backslashes to escape the
  * following character.
  *
  * This uses unbuffered input, which may be avoidable in some cases.
+ * XXX - Uses _read_bufferred() that chunks read(), but emits one char at a time
  */
 
 int
@@ -104,7 +105,7 @@ readcmd(int argc, char **argv)
 	backslash = 0;
 	STARTSTACKSTR(p);
 	for (;;) {
-		if (read(0, &c, 1) != 1) {
+		if (read_stdin_bufferred(&c) != 1) {
 			status = 1;
 			break;
 		}
diff -puN dash-0.5.4/src/miscbltin.h dash-0.5.4-patched/src/miscbltin.h
--- dash-0.5.4/src/miscbltin.h	2007-07-13 10:26:43.000000000 +0200
+++ dash-0.5.4-patched/src/miscbltin.h	2010-09-04 10:46:02.000000000 +0200
@@ -29,3 +29,6 @@
 int readcmd(int, char **);
 int umaskcmd(int, char **);
 int ulimitcmd(int, char **);
+
+/* Used for flushing the readcmd read() buffer */
+void flush_readcmd(int fd);
diff -puN dash-0.5.4/src/redir.c dash-0.5.4-patched/src/redir.c
--- dash-0.5.4/src/redir.c	2007-07-13 10:26:43.000000000 +0200
+++ dash-0.5.4-patched/src/redir.c	2010-09-04 12:25:49.000000000 +0200
@@ -56,6 +56,8 @@
 #include "memalloc.h"
 #include "error.h"
 
+#include "bufreadcmd.h"
+
 
 #define REALLY_CLOSED -3	/* fd that was closed and still is */
 #define EMPTY -2		/* marks an unused slot in redirtab */
@@ -265,14 +267,14 @@ dupredirect(redir, f)
 				memory[fd] = 1;
 			else
 #endif
-				if (dup2(f, fd) < 0) {
+				if (dup2_wrapper(f, fd) < 0) {
 					err = errno;
 					goto err;
 				}
 			return;
 		}
 		f = fd;
-	} else if (dup2(f, fd) < 0)
+	} else if (dup2_wrapper(f, fd) < 0)
 		err = errno;
 
 	close(f);
@@ -354,7 +356,7 @@ popredir(int drop)
 			break;
 		default:
 			if (!drop)
-				dup2(rp->renamed[i], i);
+				dup2_wrapper(rp->renamed[i], i);
 			close(rp->renamed[i]);
 			break;
 		}

[LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

Powered by Linux