The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=cf74b63d61b49db848ecc20b87e7ee5f16671320

commit cf74b63d61b49db848ecc20b87e7ee5f16671320
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2026-03-10 10:18:08 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2026-03-10 10:18:08 +0000

    yes: Completely overengineer
    
    If we're going to overengineer this, we may as well go all the way.
    
    * If multiple arguments are given, concatenate them into a space-
      separated list like GNU coreutils does.
    
    * When duplicating the expletive, do so exponentially.
    
    * Most importantly, don't modify the memory that argv points to.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    kevans, allanjude
    Differential Revision:  https://reviews.freebsd.org/D55617
---
 usr.bin/yes/yes.1 |  6 +++--
 usr.bin/yes/yes.c | 75 +++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 57 insertions(+), 24 deletions(-)

diff --git a/usr.bin/yes/yes.1 b/usr.bin/yes/yes.1
index 8ed8beab0d28..689031345dc3 100644
--- a/usr.bin/yes/yes.1
+++ b/usr.bin/yes/yes.1
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 4, 2014
+.Dd March 2, 2026
 .Dt YES 1
 .Os
 .Sh NAME
@@ -33,7 +33,7 @@
 .Nd be repetitively affirmative
 .Sh SYNOPSIS
 .Nm
-.Op Ar expletive
+.Op Ar expletive ...
 .Sh DESCRIPTION
 The
 .Nm
@@ -42,6 +42,8 @@ utility outputs
 or, by default,
 .Dq y ,
 forever.
+If multiple arguments are given, they are concatenated into a single
+space-separated string.
 .Sh SEE ALSO
 .Xr jot 1 ,
 .Xr seq 1
diff --git a/usr.bin/yes/yes.c b/usr.bin/yes/yes.c
index d9e896b6ea27..53224603cf95 100644
--- a/usr.bin/yes/yes.c
+++ b/usr.bin/yes/yes.c
@@ -35,40 +35,71 @@
 #include <string.h>
 #include <unistd.h>
 
+/*
+ * Default expletive
+ */
+#define EXP    "y\n"
+#define EXPLEN strlen(EXP)
+
+/*
+ * Optimum and maximum buffer size.  The optimum is just a little less
+ * than the default value of kern.ipc.pipe_mindirect; writing more than
+ * that is significantly slower, but we want to get as close as possible
+ * to minimize the number of system calls.  The maximum is enough for a
+ * maximal command line plus a newline and terminating NUL.
+ */
+#define OPTBUF 8190
+#define MAXBUF (ARG_MAX + 2)
+
 int
 main(int argc, char **argv)
 {
-       char buf[8192];
-       char y[2] = { 'y', '\n' };
-       char * exp = y;
-       size_t buflen = 0;
-       size_t explen = sizeof(y);
-       size_t more;
-       ssize_t ret;
+       static char buf[MAXBUF] = EXP;
+       char *end = buf + sizeof(buf), *exp, *pos = buf + EXPLEN;
+       size_t buflen, explen = EXPLEN;
+       ssize_t wlen = 0;
 
        if (caph_limit_stdio() < 0 || caph_enter() < 0)
                err(1, "capsicum");
 
-       if (argc > 1) {
-               exp = argv[1];
-               explen = strlen(exp) + 1;
-               exp[explen - 1] = '\n';
-       }
+       argc -= 1;
+       argv += 1;
 
-       if (explen <= sizeof(buf)) {
-               while (buflen < sizeof(buf) - explen) {
-                       memcpy(buf + buflen, exp, explen);
-                       buflen += explen;
+       /* Assemble the expletive */
+       if (argc > 0) {
+               /* Copy positional arguments into expletive buffer */
+               for (pos = buf, end = buf + sizeof(buf);
+                    argc > 0 && pos < end; argc--, argv++) {
+                       /* Separate with spaces */
+                       if (pos > buf)
+                               *pos++ = ' ';
+                       exp = *argv;
+                       while (*exp != '\0' && pos < end)
+                               *pos++ = *exp++;
                }
-               exp = buf;
-               explen = buflen;
+               /* This should not be possible, but check anyway */
+               if (pos > end - 2)
+                       pos = end - 2;
+               *pos++ = '\n';
+               explen = pos - buf;
        }
 
-       more = explen;
-       while ((ret = write(STDOUT_FILENO, exp + (explen - more), more)) > 0)
-               if ((more -= ret) == 0)
-                       more = explen;
+       /*
+        * Double until we're past OPTBUF, then reduce buflen to exactly
+        * OPTBUF.  It doesn't matter if that's not a multiple of explen;
+        * the modulo operation in the write loop will take care of that.
+        */
+       for (buflen = explen; buflen < OPTBUF; pos += buflen, buflen += buflen)
+               memcpy(pos, buf, buflen);
+       if (explen < OPTBUF && buflen > OPTBUF)
+               buflen = OPTBUF;
 
+       /* Dump it to stdout */
+       end = (pos = buf) + buflen;
+       do {
+               pos = buf + (pos - buf + wlen) % explen;
+               wlen = write(STDOUT_FILENO, pos, end - pos);
+       } while (wlen > 0);
        err(1, "stdout");
        /*NOTREACHED*/
 }

Reply via email to