xargs: terminate if line replacement cannot be constructed

If the line with replacement cannot be constructed xargs should
terminate as documented in the man page

We encounter this error, but gnu/xargs doesn't because they have a much
larger limit for created outputs (~10000 lines).

Reviewed by:	oshogbo
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D35574
This commit is contained in:
Tom Jones 2022-07-05 16:03:51 +01:00
parent 62bca9c4df
commit f058359ba5
2 changed files with 16 additions and 7 deletions

View File

@ -12,11 +12,12 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <err.h> #include <err.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
void strnsubst(char **, const char *, const char *, size_t); bool strnsubst(char **, const char *, const char *, size_t);
/* /*
* Replaces str with a string consisting of str with match replaced with * Replaces str with a string consisting of str with match replaced with
@ -26,16 +27,19 @@ void strnsubst(char **, const char *, const char *, size_t);
* str as well as the new contents are handled in an appropriate manner. * str as well as the new contents are handled in an appropriate manner.
* If replstr is NULL, then that internally is changed to a nil-string, so * If replstr is NULL, then that internally is changed to a nil-string, so
* that we can still pretend to do somewhat meaningful substitution. * that we can still pretend to do somewhat meaningful substitution.
* No value is returned. *
* Returns true if truncation was needed to do the replacement, true if
* truncation was not required.
*/ */
void bool
strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
{ {
char *s1, *s2, *this; char *s1, *s2, *this;
bool error = false;
s1 = *str; s1 = *str;
if (s1 == NULL) if (s1 == NULL)
return; return false;
/* /*
* If maxsize is 0 then set it to the length of s1, because we have * If maxsize is 0 then set it to the length of s1, because we have
* to duplicate s1. XXX we maybe should double-check whether the match * to duplicate s1. XXX we maybe should double-check whether the match
@ -67,6 +71,7 @@ strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
if ((strlen(s2) + strlen(s1) + strlen(replstr) - if ((strlen(s2) + strlen(s1) + strlen(replstr) -
strlen(match) + 1) > maxsize) { strlen(match) + 1) > maxsize) {
strlcat(s2, s1, maxsize); strlcat(s2, s1, maxsize);
error = true;
goto done; goto done;
} }
strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1); strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1);
@ -76,7 +81,7 @@ strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
strcat(s2, s1); strcat(s2, s1);
done: done:
*str = s2; *str = s2;
return; return error;
} }
#ifdef TEST #ifdef TEST

View File

@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <locale.h> #include <locale.h>
#include <paths.h> #include <paths.h>
#include <regex.h> #include <regex.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -73,7 +74,7 @@ static void prerun(int, char *[]);
static int prompt(void); static int prompt(void);
static void run(char **); static void run(char **);
static void usage(void); static void usage(void);
void strnsubst(char **, const char *, const char *, size_t); bool strnsubst(char **, const char *, const char *, size_t);
static pid_t xwait(int block, int *status); static pid_t xwait(int block, int *status);
static void xexit(const char *, const int); static void xexit(const char *, const int);
static void waitchildren(const char *, int); static void waitchildren(const char *, int);
@ -517,7 +518,10 @@ prerun(int argc, char *argv[])
while (--argc) { while (--argc) {
*tmp = *avj++; *tmp = *avj++;
if (repls && strstr(*tmp, replstr) != NULL) { if (repls && strstr(*tmp, replstr) != NULL) {
strnsubst(tmp++, replstr, inpline, (size_t)Sflag); if (strnsubst(tmp++, replstr, inpline, (size_t)Sflag)) {
warnx("comamnd line cannot be assembled, too long");
xexit(*argv, 1);
}
if (repls > 0) if (repls > 0)
repls--; repls--;
} else { } else {