diff options
author | jh <jh@FreeBSD.org> | 2010-03-05 15:23:01 +0000 |
---|---|---|
committer | jh <jh@FreeBSD.org> | 2010-03-05 15:23:01 +0000 |
commit | ba646ecd6fecd8f82a5df041fa3818b1f49cb375 (patch) | |
tree | 411318be07df3cec7aa3f6855cc1e38c3aea5ee5 /usr.bin/apply | |
parent | 94e741a5e69d24673cb9820a57dd0397eb65f6ce (diff) | |
download | FreeBSD-src-ba646ecd6fecd8f82a5df041fa3818b1f49cb375.zip FreeBSD-src-ba646ecd6fecd8f82a5df041fa3818b1f49cb375.tar.gz |
- 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
Diffstat (limited to 'usr.bin/apply')
-rw-r--r-- | usr.bin/apply/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/apply/apply.c | 67 |
2 files changed, 34 insertions, 35 deletions
diff --git a/usr.bin/apply/Makefile b/usr.bin/apply/Makefile index ca0f10a..c23d928 100644 --- a/usr.bin/apply/Makefile +++ b/usr.bin/apply/Makefile @@ -2,5 +2,7 @@ # $FreeBSD$ PROG= apply +DPADD= ${LIBSBUF} +LDADD= -lsbuf .include <bsd.prog.mk> diff --git a/usr.bin/apply/apply.c b/usr.bin/apply/apply.c index 25ba374..9c83126 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 <sys/types.h> +#include <sys/sbuf.h> #include <sys/wait.h> #include <ctype.h> #include <err.h> +#include <errno.h> #include <paths.h> #include <signal.h> #include <stdio.h> @@ -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); } |