]> granicus.if.org Git - sudo/commitdiff
No need to loop over atomic_writev(), it guarantees to write all
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 30 May 2012 14:50:02 +0000 (10:50 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 30 May 2012 14:50:02 +0000 (10:50 -0400)
data or return an error.

Fix handling of stdout/stderr that contains "\r\n" and handle a
"\r\n" pair that spans a buffer.

--HG--
branch : 1.7

sudoreplay.c

index d60db49999f49056dd7afa5310eedde3c60d36b0..3eb1a54221224965318b0cd554d3218c19911ece 100644 (file)
@@ -241,7 +241,7 @@ main(argc, argv)
     char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
     double seconds, to_wait, speed = 1.0, max_wait = 0;
     sigaction_t sa;
-    size_t len, nbytes, nread, nwritten, off;
+    size_t len, nbytes, nread;
     struct log_info *li;
     struct iovec *iov = NULL;
     int iovcnt = 0, iovmax = 0;
@@ -390,6 +390,8 @@ main(argc, argv)
 #else
     while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
 #endif
+       char last_char = '\0';
+
        if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
            errorx(1, "invalid timing file line: %s", buf);
 
@@ -422,51 +424,59 @@ main(argc, argv)
            nread = fread(buf, 1, len, io_fds[idx].f);
 #endif
            nbytes -= nread;
-           off = 0;
-           do {
-               /* Convert newline to carriage return + linefeed if needed. */
-               if (need_nlcr) {
-                   size_t linelen;
-                   cp = buf + off;
-                   iovcnt = 0;
-                   while ((ep = memchr(cp, '\n', nread - off)) != NULL) {
-                       /* Is there already a carriage return? */
-                       if (cp != ep && ep[-1] == '\r')
-                           continue;
-
-                       /* Store the line in iov followed by \r\n pair. */
-                       if (iovcnt + 3 > iovmax) {
-                           iovmax <<= 1;
-                           iov = erealloc3(iov, iovmax, sizeof(*iov));
-                       }
-                       linelen = (size_t)(ep - cp);
-                       iov[iovcnt].iov_base = cp;
-                       iov[iovcnt].iov_len = linelen;
-                       iovcnt++;
-                       iov[iovcnt].iov_base = "\r\n";
-                       iov[iovcnt].iov_len = 2;
-                       iovcnt++;
-                       off += linelen + 1;
-                       cp = ep + 1;
+
+           /* Convert newline to carriage return + linefeed if needed. */
+           if (need_nlcr) {
+               size_t remainder = nread;
+               size_t linelen;
+               iovcnt = 0;
+               cp = buf;
+               ep = cp - 1;
+               /* Handle a "\r\n" pair that spans a buffer. */
+               if (last_char == '\r' && buf[0] == '\n') {
+                   ep++;
+                   remainder--;
+               }
+               while ((ep = memchr(ep + 1, '\n', remainder)) != NULL) {
+                   /* Is there already a carriage return? */
+                   if (cp != ep && ep[-1] == '\r') {
+                       remainder = (size_t)(&buf[nread - 1] - ep);
+                       continue;
                    }
-                   if (nread - off != 0) {
-                       linelen = nread - off;
-                       iov[iovcnt].iov_base = cp;
-                       iov[iovcnt].iov_len = linelen;
-                       iovcnt++;
-                       off += linelen;
+
+                   /* Store the line in iov followed by \r\n pair. */
+                   if (iovcnt + 3 > iovmax) {
+                       iovmax <<= 1;
+                       iov = erealloc3(iov, iovmax, sizeof(*iov));
                    }
-                   /* Note: off already adjusted above. */
-                   (void)atomic_writev(STDOUT_FILENO, iov, iovcnt);
-               } else {
-                   /* No conversion needed. */
-                   iov[0].iov_base = buf + off;
-                   iov[0].iov_len = nread - off;
-                   iovcnt = 1;
-                   nwritten = atomic_writev(STDOUT_FILENO, iov, iovcnt);
-                   off += nwritten;
+                   linelen = (size_t)(ep - cp) + 1;
+                   iov[iovcnt].iov_base = cp;
+                   iov[iovcnt].iov_len = linelen - 1; /* not including \n */
+                   iovcnt++;
+                   iov[iovcnt].iov_base = "\r\n";
+                   iov[iovcnt].iov_len = 2;
+                   iovcnt++;
+                   cp = ep + 1;
+                   remainder -= linelen;
+               }
+               if (cp - buf != nread) {
+                   /*
+                    * Partial line without a linefeed or multiple lines
+                    * with \r\n pairs.
+                    */
+                   iov[iovcnt].iov_base = cp;
+                   iov[iovcnt].iov_len = nread - (cp - buf);
+                   iovcnt++;
                }
-           } while (nread > off);
+               last_char = buf[nread - 1]; /* stash last char of old buffer */
+           } else {
+               /* No conversion needed. */
+               iov[0].iov_base = buf;
+               iov[0].iov_len = nread;
+               iovcnt = 1;
+           }
+           if (atomic_writev(STDOUT_FILENO, iov, iovcnt) == -1)
+               error(1, "writing to standard output");
        }
     }
     term_restore(STDIN_FILENO, 1);
@@ -577,7 +587,8 @@ atomic_writev(fd, iov, iovcnt)
        }
        if (errno == EINTR)
            continue;
-       error(1, "writing to standard output");
+       nwritten = -1;
+       break;
     }
     return nwritten;
 }