BB: manually writes echo's buffer
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Mar 2015 17:43:51 +0000 (12:43 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Mar 2015 17:50:14 +0000 (12:50 -0500)
So setvbuf() may or may not have worked, since we don't get *any* error
feedback from echo!  When we set to linebuffering, fflush() does not
return any errors.  The kernel sets errno and returns -1.  fflush clears
errno at some point and returns 0, instead of EOF.

I spent too much time wading through glibc's 10 levels of indirection
and don't know why this happens.  If we use block buffering instead of
line, fflush works fine.

This limits echo's to 4096 chars.  Whatever.  We're more likely to find
another issue than to have an echo that long.

Make clean and make busybox.

tools/apps/busybox/akaros-patches/1.17.3/0006-echo-linebuffered.patch [deleted file]
tools/apps/busybox/akaros-patches/1.17.3/0007-echo-buffering.patch [new file with mode: 0644]

diff --git a/tools/apps/busybox/akaros-patches/1.17.3/0006-echo-linebuffered.patch b/tools/apps/busybox/akaros-patches/1.17.3/0006-echo-linebuffered.patch
deleted file mode 100644 (file)
index 99c279a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-diff -ur busybox-1.17.3-akaros-orig/coreutils/echo.c busybox-1.17.3-akaros/coreutils/echo.c
---- busybox-1.17.3-akaros-orig/coreutils/echo.c        2015-03-02 11:35:58.782323515 -0500
-+++ busybox-1.17.3-akaros/coreutils/echo.c     2015-03-02 11:37:31.122641120 -0500
-@@ -96,6 +96,10 @@
-       }
-  just_echo:
- #endif
-+      /* brho: need to buffer a full line at a time.  not sure if glibc should
-+       * have this set for stdout or not. */
-+      if (setvbuf(stdout, 0, _IOLBF, 0))
-+              perror("Failed to setvbuf");
-       while (1) {
-               /* arg is already == *argv and isn't NULL */
-               int c;
diff --git a/tools/apps/busybox/akaros-patches/1.17.3/0007-echo-buffering.patch b/tools/apps/busybox/akaros-patches/1.17.3/0007-echo-buffering.patch
new file mode 100644 (file)
index 0000000..9212a2d
--- /dev/null
@@ -0,0 +1,65 @@
+diff -ru busybox-1.17.3-orig/coreutils/echo.c busybox-1.17.3-akaros/coreutils/echo.c
+--- busybox-1.17.3-orig/coreutils/echo.c       2015-03-06 12:06:11.732280338 -0500
++++ busybox-1.17.3-akaros/coreutils/echo.c     2015-03-06 12:34:12.607118758 -0500
+@@ -33,6 +33,12 @@
+ {
+       int ret;
+       const char *arg;
++      /* In lieu of using fputs/fflush, Akaros works better with raw writes.  The
++       * main issue is that we want to have the entire echo sent as one write.
++       * using setvbuf for line buffered mode seems to work, but fflush won't
++       * propagate errors from the kernel. */
++      char write_buf[4096];
++      size_t buf_idx = 0;
+ #if !ENABLE_FEATURE_FANCY_ECHO
+       enum {
+               eflag = '\\',
+@@ -100,12 +106,7 @@
+               /* arg is already == *argv and isn't NULL */
+               int c;
+-              if (!eflag) {
+-                      /* optimization for very common case */
+-                      ret = fputs(arg, stdout);
+-                      if (ret == EOF)
+-                              perror("echo failed");
+-              } else while ((c = *arg++)) {
++              while ((c = *arg++)) {
+                       if (c == eflag) {       /* Check for escape seq. */
+                               if (*arg == 'c') {
+                                       /* '\c' means cancel newline and
+@@ -130,25 +131,27 @@
+                                       c = bb_process_escape_sequence(&arg);
+                               }
+                       }
+-                      bb_putchar(c);
++                      write_buf[buf_idx++] = c;
+               }
+               arg = *++argv;
+               if (!arg)
+                       break;
+-              bb_putchar(' ');
++              write_buf[buf_idx++] = ' ';
+       }
+  newline_ret:
+       if (nflag) {
+-              bb_putchar('\n');
++              write_buf[buf_idx++] = '\n';
+       }
+  ret:
+-      errno = 0;
+-      ret = fflush_all();
+-      if (errno)
++      ret = write(1, write_buf, buf_idx);
++      if (ret == -1) {
+               perror("echo failed");
+-      return ret;
++              return EOF;
++      } else {
++              return 0;
++      }
+ }
+ /*-