Hi,

Currently, jot(1) restricts arguments given to the `-s', `-b' and `-w'
options to BUFSIZ characters; this is a typical misuse of that constant,
which has essentially nothing to do with the expected maximum size of
argv's elements.  Besides, I have actually hit this limit multiple times
recently, so I decided to fix it.

In the case of `-s', this was trivial.

In the case of `-b' and `-w', the quick and dirty solution would have
been to declare a larger `format' buffer, but the proper way is to
allocate the required length dynamically, as shown below.

Index: jot.c
===================================================================
RCS file: /cvs/src/usr.bin/jot/jot.c,v
retrieving revision 1.41
diff -u -p -r1.41 jot.c
--- jot.c       30 Dec 2017 07:21:10 -0000      1.41
+++ jot.c       31 Dec 2017 13:50:59 -0000
@@ -59,8 +59,8 @@ static double begin   = 1;
 static double  ender   = 100;
 static double  step    = 1;
 
-static char    format[BUFSIZ];
-static char    sepstring[BUFSIZ] = "\n";
+static char    *format = NULL;
+static char    *sepstring = "\n";
 static int     prec = -1;
 static bool    boring;
 static bool    chardata;
@@ -85,7 +85,7 @@ main(int argc, char *argv[])
        unsigned int    mask = 0;
        int             n = 0;
        int             ch;
-       const   char    *errstr;
+       const char      *errstr;
 
        if (pledge("stdio", NULL) == -1)
                err(1, "pledge");
@@ -94,9 +94,9 @@ main(int argc, char *argv[])
                switch (ch) {
                case 'b':
                        boring = true;
-                       if (strlcpy(format, optarg, sizeof(format)) >=
-                           sizeof(format))
-                               errx(1, "-b word too long");
+                       free(format);
+                       if ((format = strdup(optarg)) == NULL)
+                               err(1, NULL);
                        break;
                case 'c':
                        chardata = true;
@@ -114,14 +114,12 @@ main(int argc, char *argv[])
                        randomize = true;
                        break;
                case 's':
-                       if (strlcpy(sepstring, optarg, sizeof(sepstring)) >=
-                           sizeof(sepstring))
-                               errx(1, "-s string too long");
+                       sepstring = optarg;
                        break;
                case 'w':
-                       if (strlcpy(format, optarg, sizeof(format)) >=
-                           sizeof(format))
-                               errx(1, "-w word too long");
+                       free(format);
+                       if ((format = strdup(optarg)) == NULL)
+                               err(1, NULL);
                        break;
                default:
                        usage();
@@ -176,7 +174,8 @@ main(int argc, char *argv[])
                    argv[4]);
        }
 
-       getformat();
+       if (!boring)
+               getformat();
 
        if (!randomize) {
                /*
@@ -356,32 +355,29 @@ static void
 getformat(void)
 {
        char    *p, *p2;
-       int dot, hash, space, sign, numbers = 0;
-       size_t sz;
+       int     n, dot, hash, space, sign, numbers;
+       size_t  len = 0;
 
-       if (boring)                             /* no need to bother */
-               return;
-       for (p = format; *p != '\0'; p++)       /* look for '%' */
-               if (*p == '%') {
-                       if (*(p+1) != '%')
-                               break;
-                       p++;                    /* leave %% alone */
-               }
-       sz = sizeof(format) - strlen(format) - 1;
-       if (*p == '\0' && !chardata) {
-               int n;
-
-               n = snprintf(p, sz, "%%.%df", prec);
-               if (n == -1 || n >= (int)sz)
-                       errx(1, "-w word too long");
-       } else if (*p == '\0' && chardata) {
-               if (strlcpy(p, "%c", sz) >= sz)
-                       errx(1, "-w word too long");
+       if ((p = format) != NULL) {
+               while ((p = strchr(p, '%')) != NULL && p[1] == '%')
+                       p += 2;
+               len = strlen(format);
+       }
+       if (p == NULL && !chardata) {
+               if ((n = snprintf(NULL, 0, "%%.%df", prec)) == -1 ||
+                   (format = realloc(format, len + n + 1)) == NULL ||
+                   snprintf(format + len, n + 1, "%%.%df", prec) != n)
+                       err(1, NULL);
+       } else if (p == NULL && chardata) {
+               if ((format = realloc(format, len + sizeof("%c"))) == NULL)
+                       err(1, NULL);
+               strcpy(format + len, "%c");
                intdata = true;
        } else if (*(p+1) == '\0') {
                /* cannot end in single '%' */
-               if (strlcat(format, "%", sizeof(format)) >= sizeof(format))
-                       errx(1, "-w word too long");
+               if ((format = realloc(format, len + sizeof("%"))) == NULL)
+                       err(1, NULL);
+               strcpy(format + len, "%");
        } else {
                /*
                 * Allow conversion format specifiers of the form
@@ -456,9 +452,10 @@ fmt_broken:
                                p++;
                        else if (*p == '%' && *(p+1) == '\0') {
                                /* cannot end in single '%' */
-                               if (strlcat(format, "%", sizeof(format)) >=
-                                   sizeof(format))
-                                       errx(1, "-w word too long");
+                               if ((format = realloc(format,
+                                   len + sizeof("%"))) == NULL)
+                                       err(1, NULL);
+                               strcpy(format + len, "%");
                                break;
                        }
        }

Regards,

kshe

Reply via email to