* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)xargs.c 5.11 (Berkeley) 6/19/91";
void err
__P((const char *, ...));
register char *p
, *bbp
, *ebp
, **bxp
, **exp
, **xp
;
int cnt
, indouble
, insingle
, nargs
, nflag
, nline
, xflag
;
* POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
* caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
* that the smallest argument is 2 bytes in length, this means that
* the number of arguments is limited to:
* (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
* We arbitrarily limit the number of arguments to 5000. This is
* allowed by POSIX.2 as long as the resulting minimum exec line is
* at least LINE_MAX. Realloc'ing as necessary is possible, but
* probably not worthwhile.
nline
= ARG_MAX
- 4 * 1024;
while ((ch
= getopt(argc
, argv
, "fn:s:tx")) != EOF
)
if ((nargs
= atoi(optarg
)) <= 0)
err("illegal argument count");
* Allocate pointers for the utility name, the utility arguments,
* the maximum arguments to be read from stdin and the trailing
malloc((u_int
)(1 + argc
+ nargs
+ 1) * sizeof(char **))))
err("%s", strerror(errno
));
* Use the user's name for the utility as argv[0], just like the
* shell. Echo is the default. Set up pointers for the user's
cnt
= strlen(*bxp
++ = _PATH_ECHO
);
cnt
+= strlen(*bxp
++ = *argv
) + 1;
* Set up begin/end/traversing pointers into the array. The -n
* count doesn't include the trailing NULL pointer, so the malloc
* added in an extra slot.
exp
= (xp
= bxp
) + nargs
;
* Allocate buffer space for the arguments read from stdin and the
* trailing NULL. Buffer space is defined as the default or specified
* space, minus the length of the utility name and arguments. Set up
* begin/end/traversing pointers into the array. The -s count does
* include the trailing NULL, so the malloc didn't add in an extra
err("insufficient space for command");
if (!(bbp
= malloc((u_int
)nline
+ 1)))
err("%s", strerror(errno
));
ebp
= (argp
= p
= bbp
) + nline
- 1;
for (insingle
= indouble
= 0;;)
/* No arguments since last exec. */
/* Nothing since end of last argument. */
/* Quotes escape tabs and spaces. */
if (insingle
|| indouble
)
/* Empty lines are skipped. */
/* Quotes do not escape newlines. */
arg1
: if (insingle
|| indouble
)
err("unterminated quote");
* If max'd out on args or buffer, or reached EOF,
* run the command. If xflag and max'd out on buffer
* but not on args, object.
if (xp
== exp
|| p
== ebp
|| ch
== EOF
) {
if (xflag
&& xp
!= exp
&& p
== ebp
)
err("insufficient space for arguments");
/* Backslash escapes anything, is escaped by quotes. */
if (!insingle
&& !indouble
&& (ch
= getchar()) == EOF
)
/* If only one argument, not enough buffer space. */
err("insufficient space for argument");
/* Didn't hit argument limit, so if xflag object. */
err("insufficient space for arguments");
(void)fprintf(stderr
, "%s", *argv
);
for (p
= argv
+ 1; *p
; ++p
)
(void)fprintf(stderr
, " %s", *p
);
(void)fprintf(stderr
, "\n");
err("vfork: %s", strerror(errno
));
"xargs: %s: %s.\n", argv
[0], strerror(errno
));
pid
= waitpid(pid
, &status
, 0);
err("waitpid: %s", strerror(errno
));
* If we couldn't invoke the utility or the utility didn't exit
* properly, quit with 127.
* Otherwise, if not specified otherwise, and the utility exits
* non-zero, exit with that value.
if (noinvoke
|| !WIFEXITED(status
) || WIFSIGNALED(status
))
if (!fflag
&& WEXITSTATUS(status
))
exit(WEXITSTATUS(status
));
"usage: xargs [-ft] [[-x] -n number] [-s size] [utility [argument ...]]\n");
err(const char *fmt
, ...)
(void)fprintf(stderr
, "xargs: ");
(void)vfprintf(stderr
, fmt
, ap
);
(void)fprintf(stderr
, "\n");