bin/169773: sh(1): Resizing causes /bin/sh to repeat edit operations

Steffen Daode Nurpmeso sdaoden at gmail.com
Sat Sep 8 15:45:14 UTC 2012


 |Synopsis: sh(1): Resizing causes /bin/sh to repeat edit operations
 |
 |http://www.freebsd.org/cgi/query-pr.cgi?pr=169773

Oh, what a mess :)
I agree with Mark that the handling of OKCMD is simply wrong, but
it turned out to be wrong to simply use a different value for it.
Also the passing through of errno is incomplete in there.  (The
documented interface doesn't state anything about errno or useful
error handling at all, and however!)

It's a rather quick first diff for editline(3), i have no more
time but since it took almost three hours to come that far someone
else may build on top of it (or simply try it or ... wait for a
second).

I *think* it effectively results in editline(3) behaving the way
it is supposed to work (retrying once after a whatever signal,
then failing for a second one).  Since el_gets() now fails (as it
is supposed to), sh(1) will behave wrong in that the current line
gets "thrown away".  (I guess the supposed way is to temporarily
adjust PROMPT if one wants to continue what is on the line yet?
But i still have no idea of editline(3) :->)

It would be better if editline(3) could be configured to simply
restart upon EINTR, or to fixate that behaviour (for FreeBSD)?
I don't think it is acceptable to loose a line of user content due
to a simple resize?
So long and ciao,

--steffen

diff --git a/lib/libedit/read.c b/lib/libedit/read.c
index 7d7f54b..5b51577 100644
--- a/lib/libedit/read.c
+++ b/lib/libedit/read.c
@@ -238,8 +238,7 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
 	el->el_errno = 0;
 	do {
 		if ((num = el_getc(el, ch)) != 1) {	/* if EOF or error */
-			el->el_errno = num == 0 ? 0 : errno;
-			return (num);
+			return (num < 0 ? 1 : 0);
 		}
 
 #ifdef	KANJI
@@ -294,16 +293,18 @@ read_char(EditLine *el, char *cp)
 
  again:
 	el->el_signal->sig_no = 0;
-	while ((num_read = read(el->el_infd, cp, 1)) == -1) {
+	while ((num_read = read(el->el_infd, cp, 1)) < 0) {
+		int e = errno;
 		if (el->el_signal->sig_no == SIGCONT) {
 			sig_set(el);
 			el_set(el, EL_REFRESH);
 			goto again;
 		}
-		if (!tried && read__fixio(el->el_infd, errno) == 0)
+		if (! tried && read__fixio(el->el_infd, e) == 0)
 			tried = 1;
 		else {
 			*cp = '\0';
+			errno = e;
 			return (-1);
 		}
 	}
@@ -369,8 +370,10 @@ el_getc(EditLine *el, char *cp)
 	(void) fprintf(el->el_errfile, "Reading a character\n");
 #endif /* DEBUG_READ */
 	num_read = (*el->el_read.read_char)(el, cp);
+	if (num_read < 0)
+		el->el_errno = errno;
 #ifdef DEBUG_READ
-	(void) fprintf(el->el_errfile, "Got it %c\n", *cp);
+	(void) fprintf(el->el_errfile, "Got <%c> (return %d)\n", *cp, num_read);
 #endif /* DEBUG_READ */
 	return (num_read);
 }
@@ -511,6 +514,7 @@ el_gets(EditLine *el, int *nread)
 #endif /* DEBUG_EDIT */
 		/* if EOF or error */
 		if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
+			num = -1;
 #ifdef DEBUG_READ
 			(void) fprintf(el->el_errfile,
 			    "Returning from el_gets %d\n", num);



More information about the freebsd-bugs mailing list