From ba646ecd6fecd8f82a5df041fa3818b1f49cb375 Mon Sep 17 00:00:00 2001 From: jh Date: Fri, 5 Mar 2010 15:23:01 +0000 Subject: [PATCH] - Use errx(3) instead of err(3) when checking if snprintf(3) succeeded. snprintf(3) doesn't set errno in the tested cases. - If the same argument reference (for example %1) was specified more than once, the command didn't necessarily fit to the final command buffer. Fix this using a dynamic sbuf buffer. Add a few regression tests for the case. PR: bin/95079 No objections: freebsd-hackers --- tools/regression/usr.bin/Makefile | 3 +- tools/regression/usr.bin/apply/Makefile | 4 ++ tools/regression/usr.bin/apply/regress.00.in | 1 + tools/regression/usr.bin/apply/regress.00.out | 1 + tools/regression/usr.bin/apply/regress.01.out | 1 + tools/regression/usr.bin/apply/regress.01.sh | 15 +++++ tools/regression/usr.bin/apply/regress.sh | 10 +++ tools/regression/usr.bin/apply/regress.t | 6 ++ usr.bin/apply/Makefile | 2 + usr.bin/apply/apply.c | 67 +++++++++---------- 10 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 tools/regression/usr.bin/apply/Makefile create mode 100644 tools/regression/usr.bin/apply/regress.00.in create mode 100644 tools/regression/usr.bin/apply/regress.00.out create mode 100644 tools/regression/usr.bin/apply/regress.01.out create mode 100644 tools/regression/usr.bin/apply/regress.01.sh create mode 100644 tools/regression/usr.bin/apply/regress.sh create mode 100644 tools/regression/usr.bin/apply/regress.t diff --git a/tools/regression/usr.bin/Makefile b/tools/regression/usr.bin/Makefile index 364741b2f66c..da4549a3a8a5 100644 --- a/tools/regression/usr.bin/Makefile +++ b/tools/regression/usr.bin/Makefile @@ -1,6 +1,7 @@ # $FreeBSD$ -SUBDIR= calendar comm file2c join jot m4 printf sed tr uudecode uuencode xargs +SUBDIR= apply calendar comm file2c join jot m4 printf sed tr \ + uudecode uuencode xargs .if !defined(AUTOMATED) SUBDIR+= lastcomm .endif diff --git a/tools/regression/usr.bin/apply/Makefile b/tools/regression/usr.bin/apply/Makefile new file mode 100644 index 000000000000..b937d41a4e4a --- /dev/null +++ b/tools/regression/usr.bin/apply/Makefile @@ -0,0 +1,4 @@ +# $FreeBSD$ + +all: + @m4 ${.CURDIR}/../regress.m4 ${.CURDIR}/regress.sh | sh /dev/stdin ${.CURDIR} diff --git a/tools/regression/usr.bin/apply/regress.00.in b/tools/regression/usr.bin/apply/regress.00.in new file mode 100644 index 000000000000..8282be782435 --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.00.in @@ -0,0 +1 @@ +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 diff --git a/tools/regression/usr.bin/apply/regress.00.out b/tools/regression/usr.bin/apply/regress.00.out new file mode 100644 index 000000000000..c725cb2fa98c --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.00.out @@ -0,0 +1 @@ +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 diff --git a/tools/regression/usr.bin/apply/regress.01.out b/tools/regression/usr.bin/apply/regress.01.out new file mode 100644 index 000000000000..bcf5ab29339a --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.01.out @@ -0,0 +1 @@ +apply: Argument list too long diff --git a/tools/regression/usr.bin/apply/regress.01.sh b/tools/regression/usr.bin/apply/regress.01.sh new file mode 100644 index 000000000000..db5f1d4cd82c --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.01.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# $FreeBSD$ + +SHELL=/bin/sh; export SHELL + +ARG_MAX=$(getconf ARG_MAX) +ARG_MAX_HALF=$((ARG_MAX / 2)) + +apply 'echo %1 %1 %1' $(jot $ARG_MAX_HALF 1 1 | tr -d '\n') 2>&1 + +if [ $? -eq 0 ]; then + return 1 +else + return 0 +fi diff --git a/tools/regression/usr.bin/apply/regress.sh b/tools/regression/usr.bin/apply/regress.sh new file mode 100644 index 000000000000..7cbaae322c82 --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.sh @@ -0,0 +1,10 @@ +# $FreeBSD$ + +echo 1..2 + +REGRESSION_START($1) + +REGRESSION_TEST(`00', `apply "echo %1 %1 %1 %1" $(cat regress.00.in)') +REGRESSION_TEST(`01', `sh regress.01.sh') + +REGRESSION_END() diff --git a/tools/regression/usr.bin/apply/regress.t b/tools/regression/usr.bin/apply/regress.t new file mode 100644 index 000000000000..a82aacd9886f --- /dev/null +++ b/tools/regression/usr.bin/apply/regress.t @@ -0,0 +1,6 @@ +#!/bin/sh +# $FreeBSD$ + +cd `dirname $0` + +m4 ../regress.m4 regress.sh | sh diff --git a/usr.bin/apply/Makefile b/usr.bin/apply/Makefile index ca0f10a2fce8..c23d928a8838 100644 --- a/usr.bin/apply/Makefile +++ b/usr.bin/apply/Makefile @@ -2,5 +2,7 @@ # $FreeBSD$ PROG= apply +DPADD= ${LIBSBUF} +LDADD= -lsbuf .include diff --git a/usr.bin/apply/apply.c b/usr.bin/apply/apply.c index 25ba374d97e9..9c831265c61f 100644 --- a/usr.bin/apply/apply.c +++ b/usr.bin/apply/apply.c @@ -44,10 +44,12 @@ static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94"; __FBSDID("$FreeBSD$"); #include +#include #include #include #include +#include #include #include #include @@ -61,10 +63,13 @@ static int exec_shell(const char *, char *, char *); static void usage(void); int -main(int argc, char *argv[]) { +main(int argc, char *argv[]) +{ + struct sbuf *cmdbuf; + long arg_max; int ch, debug, i, magic, n, nargs, offset, rval; - size_t clen, cmdsize, l; - char *c, *cmd, *name, *p, *q, *shell, *slashp, *tmpshell; + size_t cmdsize; + char *cmd, *name, *p, *shell, *slashp, *tmpshell; debug = 0; magic = '%'; /* Default magic char is `%'. */ @@ -144,13 +149,13 @@ main(int argc, char *argv[]) { p = cmd; offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]); if ((size_t)offset >= cmdsize) - err(1, "snprintf() failed"); + errx(1, "snprintf() failed"); p += offset; cmdsize -= offset; for (i = 1; i <= nargs; i++) { offset = snprintf(p, cmdsize, " %c%d", magic, i); if ((size_t)offset >= cmdsize) - err(1, "snprintf() failed"); + errx(1, "snprintf() failed"); p += offset; cmdsize -= offset; } @@ -164,61 +169,53 @@ main(int argc, char *argv[]) { } else { offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]); if ((size_t)offset >= cmdsize) - err(1, "snprintf() failed"); + errx(1, "snprintf() failed"); nargs = n; } - /* - * Grab some space in which to build the command. Allocate - * as necessary later, but no reason to build it up slowly - * for the normal case. - */ - if ((c = malloc(clen = 1024)) == NULL) + cmdbuf = sbuf_new(NULL, NULL, 1024, SBUF_AUTOEXTEND); + if (cmdbuf == NULL) err(1, NULL); + arg_max = sysconf(_SC_ARG_MAX); + /* * (argc) and (argv) are still offset by one to make it simpler to * expand %digit references. At the end of the loop check for (argc) * equals 1 means that all the (argv) has been consumed. */ for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) { - /* - * Find a max value for the command length, and ensure - * there's enough space to build it. - */ - for (l = strlen(cmd), i = 0; i < nargs; i++) - l += strlen(argv[i+1]); - if (l > clen && (c = realloc(c, clen = l)) == NULL) - err(1, NULL); - + sbuf_clear(cmdbuf); /* Expand command argv references. */ - for (p = cmd, q = c; *p != '\0'; ++p) + for (p = cmd; *p != '\0'; ++p) { if (p[0] == magic && isdigit(p[1]) && p[1] != '0') { - offset = snprintf(q, l, "%s", - argv[(++p)[0] - '0']); - if ((size_t)offset >= l) - err(1, "snprintf() failed"); - q += offset; - l -= offset; - } else - *q++ = *p; + if (sbuf_cat(cmdbuf, argv[(++p)[0] - '0']) + == -1) + errc(1, ENOMEM, "sbuf"); + } else { + if (sbuf_putc(cmdbuf, *p) == -1) + errc(1, ENOMEM, "sbuf"); + } + if (sbuf_len(cmdbuf) > arg_max) + errc(1, E2BIG, NULL); + } /* Terminate the command string. */ - *q = '\0'; + sbuf_finish(cmdbuf); /* Run the command. */ if (debug) - (void)printf("%s\n", c); + (void)printf("%s\n", sbuf_data(cmdbuf)); else - if (exec_shell(c, shell, name)) + if (exec_shell(sbuf_data(cmdbuf), shell, name)) rval = 1; } if (argc != 1) errx(1, "expecting additional argument%s after \"%s\"", - (nargs - argc) ? "s" : "", argv[argc - 1]); + (nargs - argc) ? "s" : "", argv[argc - 1]); free(cmd); - free(c); + sbuf_delete(cmdbuf); free(shell); exit(rval); }