Importing usr.bin/xargs
Change-Id: I6a8ce6a8eee31942abb4db797672da7d00dfa43d
This commit is contained in:
parent
3dab66925c
commit
00785f561f
11 changed files with 1200 additions and 594 deletions
|
@ -30,7 +30,7 @@ SUBDIR= add_route arp ash at backup btrace \
|
||||||
truncate tty udpstat umount uname \
|
truncate tty udpstat umount uname \
|
||||||
unstack update uud uue version vol \
|
unstack update uud uue version vol \
|
||||||
whereis which write writeisofs fetch \
|
whereis which write writeisofs fetch \
|
||||||
xargs zdump zmodem pkgin_cd pkgin_all \
|
zdump zmodem pkgin_cd pkgin_all \
|
||||||
worldstone updateboot update_bootcfg
|
worldstone updateboot update_bootcfg
|
||||||
|
|
||||||
.if ${MACHINE_ARCH} == "i386"
|
.if ${MACHINE_ARCH} == "i386"
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
PROG= xargs
|
|
||||||
MAN=
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
|
|
@ -1,426 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 1990 The Regents of the University of California.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This code is derived from software contributed to Berkeley by
|
|
||||||
* John B. Roll Jr.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 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
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef lint
|
|
||||||
char copyright[] =
|
|
||||||
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
|
|
||||||
All rights reserved.\n";
|
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
#ifndef lint
|
|
||||||
#if 0
|
|
||||||
static char sccsid[] = "@(#)xargs.c 5.11 (Berkeley) 6/19/91";
|
|
||||||
#endif
|
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#if __minix
|
|
||||||
#define _PATH_ECHO "/bin/echo"
|
|
||||||
#else
|
|
||||||
#include "pathnames.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ARG_MAX
|
|
||||||
#define ARG_MAX (sizeof(int) == 2 ? 4096 : 128 * 1024)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int exit_status = 0;
|
|
||||||
int tflag;
|
|
||||||
void err(const char *, ...);
|
|
||||||
void run(char **argv);
|
|
||||||
void usage(void);
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
extern int optind;
|
|
||||||
extern char *optarg;
|
|
||||||
register int ch;
|
|
||||||
register char *p, *bbp, *ebp, **bxp, **exp, **xp;
|
|
||||||
int cnt, indouble, insingle, nargs, nflag, nline, xflag, zflag;
|
|
||||||
char **av, *argp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
#if !__minix || __minix_vmd
|
|
||||||
nargs = 5000;
|
|
||||||
nline = ARG_MAX - 4 * 1024;
|
|
||||||
#else
|
|
||||||
/* Things are more cramped under standard Minix. */
|
|
||||||
nargs = 80 * sizeof(int);
|
|
||||||
nline = ARG_MAX - 512 * sizeof(int);
|
|
||||||
#endif
|
|
||||||
nflag = xflag = zflag = 0;
|
|
||||||
while ((ch = getopt(argc, argv, "n:s:tx0")) != EOF)
|
|
||||||
switch(ch) {
|
|
||||||
case 'n':
|
|
||||||
nflag = 1;
|
|
||||||
if ((nargs = atoi(optarg)) <= 0)
|
|
||||||
err("illegal argument count");
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
nline = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
tflag = 1;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
xflag = 1;
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
zflag = 1;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
if (xflag && !nflag)
|
|
||||||
usage();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate pointers for the utility name, the utility arguments,
|
|
||||||
* the maximum arguments to be read from stdin and the trailing
|
|
||||||
* NULL.
|
|
||||||
*/
|
|
||||||
if (!(av = bxp =
|
|
||||||
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
|
|
||||||
* arguments.
|
|
||||||
*/
|
|
||||||
if (!*argv)
|
|
||||||
cnt = strlen(*bxp++ = _PATH_ECHO);
|
|
||||||
else {
|
|
||||||
cnt = 0;
|
|
||||||
do {
|
|
||||||
cnt += strlen(*bxp++ = *argv) + 1;
|
|
||||||
} while (*++argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
* slot.
|
|
||||||
*/
|
|
||||||
nline -= cnt;
|
|
||||||
if (nline <= 0)
|
|
||||||
err("insufficient space for command");
|
|
||||||
|
|
||||||
if (!(bbp = malloc((u_int)nline + 1)))
|
|
||||||
err("%s", strerror(errno));
|
|
||||||
ebp = (argp = p = bbp) + nline - 1;
|
|
||||||
|
|
||||||
if (zflag) {
|
|
||||||
/* Read pathnames terminated by null bytes as produced by
|
|
||||||
* find ... -print0. No comments in this code, see further
|
|
||||||
* below.
|
|
||||||
*/
|
|
||||||
for (;;)
|
|
||||||
switch(ch = getchar()) {
|
|
||||||
case EOF:
|
|
||||||
if (p == bbp)
|
|
||||||
exit(exit_status);
|
|
||||||
|
|
||||||
if (argp == p) {
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
exit(exit_status);
|
|
||||||
}
|
|
||||||
/*FALL THROUGH*/
|
|
||||||
case '\0':
|
|
||||||
if (argp == p)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
*p = '\0';
|
|
||||||
*xp++ = argp;
|
|
||||||
|
|
||||||
if (xp == exp || p == ebp || ch == EOF) {
|
|
||||||
if (xflag && xp != exp && p == ebp)
|
|
||||||
err(
|
|
||||||
"insufficient space for arguments");
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
if (ch == EOF)
|
|
||||||
exit(exit_status);
|
|
||||||
p = bbp;
|
|
||||||
xp = bxp;
|
|
||||||
} else
|
|
||||||
++p;
|
|
||||||
argp = p;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (p < ebp) {
|
|
||||||
*p++ = ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bxp == xp)
|
|
||||||
err("insufficient space for argument");
|
|
||||||
if (xflag)
|
|
||||||
err("insufficient space for arguments");
|
|
||||||
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
xp = bxp;
|
|
||||||
cnt = ebp - argp;
|
|
||||||
bcopy(argp, bbp, cnt);
|
|
||||||
p = (argp = bbp) + cnt;
|
|
||||||
*p++ = ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
for (insingle = indouble = 0;;)
|
|
||||||
switch(ch = getchar()) {
|
|
||||||
case EOF:
|
|
||||||
/* No arguments since last exec. */
|
|
||||||
if (p == bbp)
|
|
||||||
exit(exit_status);
|
|
||||||
|
|
||||||
/* Nothing since end of last argument. */
|
|
||||||
if (argp == p) {
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
exit(exit_status);
|
|
||||||
}
|
|
||||||
goto arg1;
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
/* Quotes escape tabs and spaces. */
|
|
||||||
if (insingle || indouble)
|
|
||||||
goto addch;
|
|
||||||
goto arg2;
|
|
||||||
case '\n':
|
|
||||||
/* Empty lines are skipped. */
|
|
||||||
if (argp == p)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Quotes do not escape newlines. */
|
|
||||||
arg1: if (insingle || indouble)
|
|
||||||
err("unterminated quote");
|
|
||||||
|
|
||||||
arg2: *p = '\0';
|
|
||||||
*xp++ = argp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
if (ch == EOF)
|
|
||||||
exit(exit_status);
|
|
||||||
p = bbp;
|
|
||||||
xp = bxp;
|
|
||||||
} else
|
|
||||||
++p;
|
|
||||||
argp = p;
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
if (indouble)
|
|
||||||
goto addch;
|
|
||||||
insingle = !insingle;
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
if (insingle)
|
|
||||||
goto addch;
|
|
||||||
indouble = !indouble;
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
/* Backslash escapes anything, is escaped by quotes. */
|
|
||||||
if (!insingle && !indouble && (ch = getchar()) == EOF)
|
|
||||||
err("backslash at EOF");
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
default:
|
|
||||||
addch: if (p < ebp) {
|
|
||||||
*p++ = ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If only one argument, not enough buffer space. */
|
|
||||||
if (bxp == xp)
|
|
||||||
err("insufficient space for argument");
|
|
||||||
/* Didn't hit argument limit, so if xflag object. */
|
|
||||||
if (xflag)
|
|
||||||
err("insufficient space for arguments");
|
|
||||||
|
|
||||||
*xp = NULL;
|
|
||||||
run(av);
|
|
||||||
xp = bxp;
|
|
||||||
cnt = ebp - argp;
|
|
||||||
bcopy(argp, bbp, cnt);
|
|
||||||
p = (argp = bbp) + cnt;
|
|
||||||
*p++ = ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
void run(char **argv)
|
|
||||||
{
|
|
||||||
register char **p;
|
|
||||||
pid_t pid;
|
|
||||||
int noinvoke;
|
|
||||||
int status;
|
|
||||||
int pfd[2];
|
|
||||||
|
|
||||||
if (tflag) {
|
|
||||||
(void)fprintf(stderr, "%s", *argv);
|
|
||||||
for (p = argv + 1; *p; ++p)
|
|
||||||
(void)fprintf(stderr, " %s", *p);
|
|
||||||
(void)fprintf(stderr, "\n");
|
|
||||||
(void)fflush(stderr);
|
|
||||||
}
|
|
||||||
if (pipe(pfd) < 0) err("pipe: %s", strerror(errno));
|
|
||||||
|
|
||||||
switch(pid = fork()) {
|
|
||||||
case -1:
|
|
||||||
err("fork: %s", strerror(errno));
|
|
||||||
case 0:
|
|
||||||
close(pfd[0]);
|
|
||||||
fcntl(pfd[1], F_SETFD, fcntl(pfd[1], F_GETFD) | FD_CLOEXEC);
|
|
||||||
|
|
||||||
execvp(argv[0], argv);
|
|
||||||
noinvoke = (errno == ENOENT) ? 127 : 126;
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"xargs: %s exec failed: %s.\n", argv[0], strerror(errno));
|
|
||||||
|
|
||||||
/* Modern way of returning noinvoke instead of a dirty vfork()
|
|
||||||
* trick: (kjb)
|
|
||||||
*/
|
|
||||||
write(pfd[1], &noinvoke, sizeof(noinvoke));
|
|
||||||
_exit(-1);
|
|
||||||
}
|
|
||||||
close(pfd[1]);
|
|
||||||
if (read(pfd[0], &noinvoke, sizeof(noinvoke)) < sizeof(noinvoke))
|
|
||||||
noinvoke = 0;
|
|
||||||
close(pfd[0]);
|
|
||||||
|
|
||||||
pid = waitpid(pid, &status, 0);
|
|
||||||
if (pid == -1)
|
|
||||||
err("waitpid: %s", strerror(errno));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we couldn't invoke the utility or the utility didn't exit
|
|
||||||
* properly, quit with 127 or 126 respectively.
|
|
||||||
*/
|
|
||||||
if (noinvoke)
|
|
||||||
exit(noinvoke);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* According to POSIX, we have to exit if the utility exits with
|
|
||||||
* a 255 status, or is interrupted by a signal. xargs is allowed
|
|
||||||
* to return any exit status between 1 and 125 in these cases, but
|
|
||||||
* we'll use 124 and 125, the same values used by GNU xargs.
|
|
||||||
*/
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
if (WEXITSTATUS (status) == 255) {
|
|
||||||
fprintf (stderr, "xargs: %s exited with status 255\n",
|
|
||||||
argv[0]);
|
|
||||||
exit(124);
|
|
||||||
} else if (WEXITSTATUS (status) != 0) {
|
|
||||||
exit_status = 123;
|
|
||||||
}
|
|
||||||
} else if (WIFSTOPPED (status)) {
|
|
||||||
fprintf (stderr, "xargs: %s terminated by signal %d\n",
|
|
||||||
argv[0], WSTOPSIG (status));
|
|
||||||
exit(125);
|
|
||||||
} else if (WIFSIGNALED (status)) {
|
|
||||||
fprintf (stderr, "xargs: %s terminated by signal %d\n",
|
|
||||||
argv[0], WTERMSIG (status));
|
|
||||||
exit(125);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usage(void)
|
|
||||||
{
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"usage: xargs [-t0] [[-x] -n number] [-s size] [utility [argument ...]]\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void err(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
(void)fprintf(stderr, "xargs: ");
|
|
||||||
(void)vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
(void)fprintf(stderr, "\n");
|
|
||||||
exit(1);
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
|
@ -21,7 +21,7 @@ MAN= ash.1 at.1 \
|
||||||
term.1 termcap.1 tget.1 time.1 tr.1 true.1 \
|
term.1 termcap.1 tget.1 time.1 tr.1 true.1 \
|
||||||
truncate.1 tty.1 umount.1 uname.1 \
|
truncate.1 tty.1 umount.1 uname.1 \
|
||||||
uud.1 uue.1 vol.1 whereis.1 which.1 \
|
uud.1 uue.1 vol.1 whereis.1 which.1 \
|
||||||
write.1 xargs.1 yap.1 linkfarm.1 pkg_view.1
|
write.1 yap.1 linkfarm.1 pkg_view.1
|
||||||
|
|
||||||
MLINKS += ash.1 sh.1
|
MLINKS += ash.1 sh.1
|
||||||
MLINKS += ash.1 ..1
|
MLINKS += ash.1 ..1
|
||||||
|
|
161
man/man1/xargs.1
161
man/man1/xargs.1
|
@ -1,161 +0,0 @@
|
||||||
.\" Copyright (c) 1990 The Regents of the University of California.
|
|
||||||
.\" All rights reserved.
|
|
||||||
.\"
|
|
||||||
.\" This code is derived from software contributed to Berkeley by
|
|
||||||
.\" John B. Roll Jr. and the Institute of Electrical and Electronics
|
|
||||||
.\" Engineers, Inc.
|
|
||||||
.\"
|
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
|
||||||
.\" modification, are permitted provided that the following conditions
|
|
||||||
.\" are met:
|
|
||||||
.\" 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
|
|
||||||
.\" SUCH DAMAGE.
|
|
||||||
.\"
|
|
||||||
.\" @(#)xargs.1 5.5 (Berkeley) 6/27/91
|
|
||||||
.\"
|
|
||||||
.TH XARGS 1 "June 27, 1991"
|
|
||||||
.UC 7
|
|
||||||
.SH NAME
|
|
||||||
xargs \- construct argument list(s) and execute utility.
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B xargs
|
|
||||||
.RB [ \-ft0 ]
|
|
||||||
.RB [[ \-x ]
|
|
||||||
.B \-n
|
|
||||||
.IR number ]
|
|
||||||
.RB [ \-s
|
|
||||||
.IR size ]
|
|
||||||
.RI [ utility
|
|
||||||
.RI [ argument " ...]]"
|
|
||||||
.SH DESCRIPTION
|
|
||||||
The
|
|
||||||
.B xargs
|
|
||||||
utility reads space, tab, newline and end-of-file delimited arguments
|
|
||||||
from the standard input and executes the specified
|
|
||||||
.I utility
|
|
||||||
with them as arguments.
|
|
||||||
.PP
|
|
||||||
The utility and any arguments specified on the command line are given
|
|
||||||
to the
|
|
||||||
.I utility
|
|
||||||
upon each invocation, followed by some number of the arguments read
|
|
||||||
from standard input.
|
|
||||||
The
|
|
||||||
.I utility
|
|
||||||
is repeatedly executed until standard input is exhausted.
|
|
||||||
.PP
|
|
||||||
Spaces, tabs and newlines may be embedded in arguments using single (`` ' '')
|
|
||||||
or double (``"'') quotes or backslashes (``\e'').
|
|
||||||
Single quotes escape all non-single quote characters, excluding newlines,
|
|
||||||
up to the matching single quote.
|
|
||||||
Double quotes escape all non-double quote characters, excluding newlines,
|
|
||||||
up to the matching double quote.
|
|
||||||
Any single character, including newlines, may be escaped by a backslash.
|
|
||||||
.PP
|
|
||||||
The options are as follows:
|
|
||||||
.TP
|
|
||||||
.BI \-n " number"
|
|
||||||
Set the maximum number of arguments taken from standard input for each
|
|
||||||
invocation of the utility.
|
|
||||||
An invocation of
|
|
||||||
.I utility
|
|
||||||
will use less than
|
|
||||||
.I number
|
|
||||||
standard input arguments if the number of bytes accumulated (see the
|
|
||||||
.I \-s
|
|
||||||
option) exceeds the specified
|
|
||||||
.I size
|
|
||||||
or there are fewer than
|
|
||||||
.I number
|
|
||||||
arguments remaining for the last invocation of
|
|
||||||
.IR utility .
|
|
||||||
The current default value for
|
|
||||||
.I number
|
|
||||||
is 5000.
|
|
||||||
.TP
|
|
||||||
.BI \-s " size"
|
|
||||||
Set the maximum number of bytes for the command line length provided to
|
|
||||||
.IR utility .
|
|
||||||
The sum of the length of the utility name and the arguments passed to
|
|
||||||
.I utility
|
|
||||||
(including NULL terminators) will be less than or equal to this number.
|
|
||||||
The current default value for
|
|
||||||
.I size
|
|
||||||
is ARG_MAX - 2048.
|
|
||||||
.TP
|
|
||||||
.B \-t
|
|
||||||
Echo the command to be executed to standard error immediately before it
|
|
||||||
is executed.
|
|
||||||
.TP
|
|
||||||
.B \-x
|
|
||||||
Force
|
|
||||||
.B xargs
|
|
||||||
to terminate immediately if a command line containing
|
|
||||||
.I number
|
|
||||||
arguments will not fit in the specified (or default) command line length.
|
|
||||||
.TP
|
|
||||||
.B \-0
|
|
||||||
Read null-byte terminated pathnames from standard input as may have been
|
|
||||||
produced by the
|
|
||||||
.B \-print0
|
|
||||||
option of
|
|
||||||
.BR find (1).
|
|
||||||
This is a MINIX 3 specific extension to
|
|
||||||
.BR xargs .
|
|
||||||
.PP
|
|
||||||
If no
|
|
||||||
.I utility
|
|
||||||
is specified,
|
|
||||||
.BR echo (1)
|
|
||||||
is used.
|
|
||||||
.PP
|
|
||||||
Undefined behavior may occur if
|
|
||||||
.I utility
|
|
||||||
reads from the standard input.
|
|
||||||
.PP
|
|
||||||
.B Xargs
|
|
||||||
exits with an exit status of 0 if no error occurs.
|
|
||||||
If
|
|
||||||
.I utility
|
|
||||||
cannot be invoked, is terminated by a signal or terminates without
|
|
||||||
calling
|
|
||||||
.BR exit (2),
|
|
||||||
.B xargs
|
|
||||||
exits with an exit status of 127.
|
|
||||||
If
|
|
||||||
.I utility
|
|
||||||
exits with an exit status other than 0,
|
|
||||||
.B xargs
|
|
||||||
exits with that exit status.
|
|
||||||
Otherwise,
|
|
||||||
.B xargs
|
|
||||||
exits with an exit status of 1.
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.BR echo (1),
|
|
||||||
.BR find (1).
|
|
||||||
.SH STANDARDS
|
|
||||||
The
|
|
||||||
.B xargs
|
|
||||||
utility is expected to be POSIX 1003.2 compliant.
|
|
|
@ -31,7 +31,7 @@ SUBDIR= \
|
||||||
uniq \
|
uniq \
|
||||||
\
|
\
|
||||||
wc whatis who \
|
wc whatis who \
|
||||||
xinstall yes
|
xargs xinstall yes
|
||||||
|
|
||||||
.if !defined(__MINIX)
|
.if !defined(__MINIX)
|
||||||
SUBDIR+= ../external/zlib/pigz/bin/pigz
|
SUBDIR+= ../external/zlib/pigz/bin/pigz
|
||||||
|
|
7
usr.bin/xargs/Makefile
Normal file
7
usr.bin/xargs/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# $NetBSD: Makefile,v 1.5 2009/04/14 22:15:29 lukem Exp $
|
||||||
|
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||||
|
|
||||||
|
PROG= xargs
|
||||||
|
SRCS= xargs.c strnsubst.c
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
36
usr.bin/xargs/pathnames.h
Normal file
36
usr.bin/xargs/pathnames.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 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
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _PATH_ECHO "/bin/echo"
|
115
usr.bin/xargs/strnsubst.c
Normal file
115
usr.bin/xargs/strnsubst.c
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/* $xMach: strnsubst.c,v 1.3 2002/02/23 02:10:24 jmallett Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 J. Mallett. All rights reserved.
|
||||||
|
* You may do whatever you want with this file as long as
|
||||||
|
* the above copyright and this notice remain intact, along
|
||||||
|
* with the following statement:
|
||||||
|
* For the man who taught me vi, and who got too old, too young.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
__FBSDID("$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.8 2005/12/30 23:22:50 jmallett Exp $");
|
||||||
|
#endif
|
||||||
|
__RCSID("$NetBSD: strnsubst.c,v 1.1 2007/04/18 15:56:07 christos Exp $");
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void strnsubst(char **, const char *, const char *, size_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Replaces str with a string consisting of str with match replaced with
|
||||||
|
* replstr as many times as can be done before the constructed string is
|
||||||
|
* maxsize bytes large. It does not free the string pointed to by str, it
|
||||||
|
* is up to the calling program to be sure that the original contents of
|
||||||
|
* 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
|
||||||
|
* that we can still pretend to do somewhat meaningful substitution.
|
||||||
|
* No value is returned.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
|
||||||
|
{
|
||||||
|
char *s1, *s2, *this;
|
||||||
|
|
||||||
|
s1 = *str;
|
||||||
|
if (s1 == NULL)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
* If maxsize is 0 then set it to to the length of s1, because we have
|
||||||
|
* to duplicate s1. XXX we maybe should double-check whether the match
|
||||||
|
* appears in s1. If it doesn't, then we also have to set the length
|
||||||
|
* to the length of s1, to avoid modifying the argument. It may make
|
||||||
|
* sense to check if maxsize is <= strlen(s1), because in that case we
|
||||||
|
* want to return the unmodified string, too.
|
||||||
|
*/
|
||||||
|
if (maxsize == 0) {
|
||||||
|
match = NULL;
|
||||||
|
maxsize = strlen(s1) + 1;
|
||||||
|
}
|
||||||
|
s2 = calloc(maxsize, 1);
|
||||||
|
if (s2 == NULL)
|
||||||
|
err(1, "calloc");
|
||||||
|
|
||||||
|
if (replstr == NULL)
|
||||||
|
replstr = "";
|
||||||
|
|
||||||
|
if (match == NULL || replstr == NULL || maxsize == strlen(s1)) {
|
||||||
|
(void)strlcpy(s2, s1, maxsize);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
this = strstr(s1, match);
|
||||||
|
if (this == NULL)
|
||||||
|
break;
|
||||||
|
if ((strlen(s2) + strlen(s1) + strlen(replstr) -
|
||||||
|
strlen(match) + 1) > maxsize) {
|
||||||
|
(void)strlcat(s2, s1, maxsize);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(void)strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1);
|
||||||
|
(void)strcat(s2, replstr);
|
||||||
|
s1 = this + strlen(match);
|
||||||
|
}
|
||||||
|
(void)strcat(s2, s1);
|
||||||
|
done:
|
||||||
|
*str = s2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
char *x, *y, *z, *za;
|
||||||
|
|
||||||
|
x = "{}%$";
|
||||||
|
strnsubst(&x, "%$", "{} enpury!", 255);
|
||||||
|
y = x;
|
||||||
|
strnsubst(&y, "}{}", "ybir", 255);
|
||||||
|
z = y;
|
||||||
|
strnsubst(&z, "{", "v ", 255);
|
||||||
|
za = z;
|
||||||
|
strnsubst(&z, NULL, za, 255);
|
||||||
|
if (strcmp(z, "v ybir enpury!") == 0)
|
||||||
|
(void)printf("strnsubst() seems to work!\n");
|
||||||
|
else
|
||||||
|
(void)printf("strnsubst() is broken.\n");
|
||||||
|
(void)printf("%s\n", z);
|
||||||
|
free(x);
|
||||||
|
free(y);
|
||||||
|
free(z);
|
||||||
|
free(za);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
387
usr.bin/xargs/xargs.1
Normal file
387
usr.bin/xargs/xargs.1
Normal file
|
@ -0,0 +1,387 @@
|
||||||
|
.\" $NetBSD: xargs.1,v 1.23 2012/10/13 14:18:17 njoly Exp $
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 1990, 1991, 1993
|
||||||
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" This code is derived from software contributed to Berkeley by
|
||||||
|
.\" John B. Roll Jr. and the Institute of Electrical and Electronics
|
||||||
|
.\" Engineers, Inc.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 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. 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
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" @(#)xargs.1 8.1 (Berkeley) 6/6/93
|
||||||
|
.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.40 2010/12/11 08:32:16 joel Exp $
|
||||||
|
.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
|
||||||
|
.\"
|
||||||
|
.Dd December 21, 2010
|
||||||
|
.Dt XARGS 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm xargs
|
||||||
|
.Nd "construct argument list(s) and execute utility"
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl 0oprt
|
||||||
|
.Op Fl E Ar eofstr
|
||||||
|
.Oo
|
||||||
|
.Fl I Ar replstr
|
||||||
|
.Op Fl R Ar replacements
|
||||||
|
.Op Fl S Ar replsize
|
||||||
|
.Oc
|
||||||
|
.Op Fl J Ar replstr
|
||||||
|
.Op Fl L Ar number
|
||||||
|
.Oo
|
||||||
|
.Fl n Ar number
|
||||||
|
.Op Fl x
|
||||||
|
.Oc
|
||||||
|
.Op Fl P Ar maxprocs
|
||||||
|
.Op Fl s Ar size
|
||||||
|
.Op Ar utility Op Ar argument ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility reads space, tab, newline and end-of-file delimited strings
|
||||||
|
from the standard input and executes
|
||||||
|
.Ar utility
|
||||||
|
with the strings as
|
||||||
|
arguments.
|
||||||
|
.Pp
|
||||||
|
Any arguments specified on the command line are given to
|
||||||
|
.Ar utility
|
||||||
|
upon each invocation, followed by some number of the arguments read
|
||||||
|
from the standard input of
|
||||||
|
.Nm .
|
||||||
|
This is repeated until standard input is exhausted.
|
||||||
|
.Pp
|
||||||
|
Spaces, tabs and newlines may be embedded in arguments using single
|
||||||
|
(``\ '\ '')
|
||||||
|
or double (``"'') quotes or backslashes (``\e'').
|
||||||
|
Single quotes escape all non-single quote characters, excluding newlines,
|
||||||
|
up to the matching single quote.
|
||||||
|
Double quotes escape all non-double quote characters, excluding newlines,
|
||||||
|
up to the matching double quote.
|
||||||
|
Any single character, including newlines, may be escaped by a backslash.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl 0
|
||||||
|
Change
|
||||||
|
.Nm
|
||||||
|
to expect NUL
|
||||||
|
(``\e0'')
|
||||||
|
characters as separators, instead of spaces and newlines.
|
||||||
|
This is expected to be used in concert with the
|
||||||
|
.Fl print0
|
||||||
|
function in
|
||||||
|
.Xr find 1 .
|
||||||
|
.It Fl E Ar eofstr
|
||||||
|
Use
|
||||||
|
.Ar eofstr
|
||||||
|
as a logical EOF marker.
|
||||||
|
.It Fl I Ar replstr
|
||||||
|
Execute
|
||||||
|
.Ar utility
|
||||||
|
for each input line, replacing one or more occurrences of
|
||||||
|
.Ar replstr
|
||||||
|
in up to
|
||||||
|
.Ar replacements
|
||||||
|
(or 5 if no
|
||||||
|
.Fl R
|
||||||
|
flag is specified) arguments to
|
||||||
|
.Ar utility
|
||||||
|
with the entire line of input.
|
||||||
|
The resulting arguments, after replacement is done, will not be allowed to grow
|
||||||
|
beyond
|
||||||
|
.Ar replsize
|
||||||
|
(or 255 if no
|
||||||
|
.Fl S
|
||||||
|
flag is specified)
|
||||||
|
bytes; this is implemented by concatenating as much of the argument
|
||||||
|
containing
|
||||||
|
.Ar replstr
|
||||||
|
as possible, to the constructed arguments to
|
||||||
|
.Ar utility ,
|
||||||
|
up to
|
||||||
|
.Ar replsize
|
||||||
|
bytes.
|
||||||
|
The size limit does not apply to arguments to
|
||||||
|
.Ar utility
|
||||||
|
which do not contain
|
||||||
|
.Ar replstr ,
|
||||||
|
and furthermore, no replacement will be done on
|
||||||
|
.Ar utility
|
||||||
|
itself.
|
||||||
|
Implies
|
||||||
|
.Fl x .
|
||||||
|
.It Fl J Ar replstr
|
||||||
|
If this option is specified,
|
||||||
|
.Nm
|
||||||
|
will use the data read from standard input to replace the first occurrence of
|
||||||
|
.Ar replstr
|
||||||
|
instead of appending that data after all other arguments.
|
||||||
|
This option will not affect how many arguments will be read from input
|
||||||
|
.Pq Fl n ,
|
||||||
|
or the size of the command(s)
|
||||||
|
.Nm
|
||||||
|
will generate
|
||||||
|
.Pq Fl s .
|
||||||
|
The option just moves where those arguments will be placed in the command(s)
|
||||||
|
that are executed.
|
||||||
|
The
|
||||||
|
.Ar replstr
|
||||||
|
must show up as a distinct
|
||||||
|
.Ar argument
|
||||||
|
to
|
||||||
|
.Nm .
|
||||||
|
It will not be recognized if, for instance, it is in the middle of a
|
||||||
|
quoted string.
|
||||||
|
Furthermore, only the first occurrence of the
|
||||||
|
.Ar replstr
|
||||||
|
will be replaced.
|
||||||
|
For example, the following command will copy the list of files and
|
||||||
|
directories which start with an uppercase letter in the current
|
||||||
|
directory to
|
||||||
|
.Pa destdir :
|
||||||
|
.Pp
|
||||||
|
.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -rp % destdir
|
||||||
|
.It Fl L Ar number
|
||||||
|
Call
|
||||||
|
.Ar utility
|
||||||
|
for every
|
||||||
|
.Ar number
|
||||||
|
lines read.
|
||||||
|
If EOF is reached and fewer lines have been read than
|
||||||
|
.Ar number
|
||||||
|
then
|
||||||
|
.Ar utility
|
||||||
|
will be called with the available lines.
|
||||||
|
.It Fl n Ar number
|
||||||
|
Set the maximum number of arguments taken from standard input for each
|
||||||
|
invocation of
|
||||||
|
.Ar utility .
|
||||||
|
An invocation of
|
||||||
|
.Ar utility
|
||||||
|
will use less than
|
||||||
|
.Ar number
|
||||||
|
standard input arguments if the number of bytes accumulated (see the
|
||||||
|
.Fl s
|
||||||
|
option) exceeds the specified
|
||||||
|
.Ar size
|
||||||
|
or there are fewer than
|
||||||
|
.Ar number
|
||||||
|
arguments remaining for the last invocation of
|
||||||
|
.Ar utility .
|
||||||
|
The current default value for
|
||||||
|
.Ar number
|
||||||
|
is 5000.
|
||||||
|
.It Fl o
|
||||||
|
Reopen stdin as
|
||||||
|
.Pa /dev/tty
|
||||||
|
in the child process before executing the command.
|
||||||
|
This is useful if you want
|
||||||
|
.Nm
|
||||||
|
to run an interactive application.
|
||||||
|
.It Fl P Ar maxprocs
|
||||||
|
Parallel mode: run at most
|
||||||
|
.Ar maxprocs
|
||||||
|
invocations of
|
||||||
|
.Ar utility
|
||||||
|
at once.
|
||||||
|
.It Fl p
|
||||||
|
Echo each command to be executed and ask the user whether it should be
|
||||||
|
executed.
|
||||||
|
An affirmative response,
|
||||||
|
.Ql y
|
||||||
|
in the POSIX locale,
|
||||||
|
causes the command to be executed, any other response causes it to be
|
||||||
|
skipped.
|
||||||
|
No commands are executed if the process is not attached to a terminal.
|
||||||
|
.It Fl r
|
||||||
|
Compatibility with GNU
|
||||||
|
.Nm .
|
||||||
|
The GNU version of
|
||||||
|
.Nm
|
||||||
|
runs the
|
||||||
|
.Ar utility
|
||||||
|
argument at least once, even if
|
||||||
|
.Nm
|
||||||
|
input is empty, and it supports a
|
||||||
|
.Fl r
|
||||||
|
option to inhibit this behavior.
|
||||||
|
The
|
||||||
|
.Nx
|
||||||
|
version of
|
||||||
|
.Nm
|
||||||
|
does not run the
|
||||||
|
.Ar utility
|
||||||
|
argument on empty input, but it supports the
|
||||||
|
.Fl r
|
||||||
|
option for command-line compatibility with GNU
|
||||||
|
.Nm ;
|
||||||
|
but the
|
||||||
|
.Fl r
|
||||||
|
option does nothing in the
|
||||||
|
.Nx
|
||||||
|
version of
|
||||||
|
.Nm .
|
||||||
|
.It Fl R Ar replacements
|
||||||
|
Specify the maximum number of arguments that
|
||||||
|
.Fl I
|
||||||
|
will do replacement in.
|
||||||
|
If
|
||||||
|
.Ar replacements
|
||||||
|
is negative, the number of arguments in which to replace is unbounded.
|
||||||
|
.It Fl S Ar replsize
|
||||||
|
Specify the amount of space (in bytes) that
|
||||||
|
.Fl I
|
||||||
|
can use for replacements.
|
||||||
|
The default for
|
||||||
|
.Ar replsize
|
||||||
|
is 255.
|
||||||
|
.It Fl s Ar size
|
||||||
|
Set the maximum number of bytes for the command line length provided to
|
||||||
|
.Ar utility .
|
||||||
|
The sum of the length of the utility name, the arguments passed to
|
||||||
|
.Ar utility
|
||||||
|
(including
|
||||||
|
.Dv NULL
|
||||||
|
terminators) and the current environment will be less than or equal to
|
||||||
|
this number.
|
||||||
|
The current default value for
|
||||||
|
.Ar size
|
||||||
|
is
|
||||||
|
.Dv ARG_MAX
|
||||||
|
- 4096.
|
||||||
|
.It Fl t
|
||||||
|
Echo the command to be executed to standard error immediately before it
|
||||||
|
is executed.
|
||||||
|
.It Fl x
|
||||||
|
Force
|
||||||
|
.Nm
|
||||||
|
to terminate immediately if a command line containing
|
||||||
|
.Ar number
|
||||||
|
arguments will not fit in the specified (or default) command line length.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Ar utility
|
||||||
|
is omitted,
|
||||||
|
.Xr echo 1
|
||||||
|
is used.
|
||||||
|
.Pp
|
||||||
|
Undefined behavior may occur if
|
||||||
|
.Ar utility
|
||||||
|
reads from the standard input.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility exits immediately (without processing any further input) if a
|
||||||
|
command line cannot be assembled,
|
||||||
|
.Ar utility
|
||||||
|
cannot be invoked, an invocation of
|
||||||
|
.Ar utility
|
||||||
|
is terminated by a signal,
|
||||||
|
or an invocation of
|
||||||
|
.Ar utility
|
||||||
|
exits with a value of 255.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /dev/tty -compact
|
||||||
|
.It Pa /dev/tty
|
||||||
|
used to read responses in prompt mode
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Nm
|
||||||
|
exits with one of the following values:
|
||||||
|
.Bl -tag -width Ds -compact
|
||||||
|
.It 0
|
||||||
|
All invocations of
|
||||||
|
.Ar utility
|
||||||
|
returned a zero exit status.
|
||||||
|
.It 123
|
||||||
|
One or more invocations of
|
||||||
|
.Ar utility
|
||||||
|
returned a nonzero exit status.
|
||||||
|
.It 124
|
||||||
|
The
|
||||||
|
.Ar utility
|
||||||
|
exited with a 255 exit status.
|
||||||
|
.It 125
|
||||||
|
The
|
||||||
|
.Ar utility
|
||||||
|
was killed or stopped by a signal.
|
||||||
|
.It 126
|
||||||
|
The
|
||||||
|
.Ar utility
|
||||||
|
was found but could not be invoked.
|
||||||
|
.It 127
|
||||||
|
The
|
||||||
|
.Ar utility
|
||||||
|
could not be found.
|
||||||
|
.It 1
|
||||||
|
Some other error occurred.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr echo 1 ,
|
||||||
|
.Xr find 1 ,
|
||||||
|
.Xr execvp 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is expected to be
|
||||||
|
.St -p1003.2
|
||||||
|
compliant.
|
||||||
|
The
|
||||||
|
.Fl J , o , P , R ,
|
||||||
|
and
|
||||||
|
.Fl S
|
||||||
|
options are non-standard
|
||||||
|
.Fx
|
||||||
|
extensions which may not be available on other operating systems.
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility appeared in PWB UNIX 1.0.
|
||||||
|
It made its first BSD appearance in the 4.3 Reno release.
|
||||||
|
.Pp
|
||||||
|
The meaning of 123, 124, and 125 exit values and the
|
||||||
|
.Fl 0
|
||||||
|
option were taken from GNU xargs.
|
||||||
|
.Sh BUGS
|
||||||
|
If
|
||||||
|
.Ar utility
|
||||||
|
attempts to invoke another command such that the number of arguments or the
|
||||||
|
size of the environment is increased, it risks
|
||||||
|
.Xr execvp 3
|
||||||
|
failing with
|
||||||
|
.Er E2BIG .
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility does not take multibyte characters into account when performing
|
||||||
|
string comparisons for the
|
||||||
|
.Fl I
|
||||||
|
and
|
||||||
|
.Fl J
|
||||||
|
options, which may lead to incorrect results in some locales.
|
652
usr.bin/xargs/xargs.c
Normal file
652
usr.bin/xargs/xargs.c
Normal file
|
@ -0,0 +1,652 @@
|
||||||
|
/* $NetBSD: xargs.c,v 1.20 2010/12/17 11:32:57 plunky Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* John B. Roll Jr.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 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. 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
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__COPYRIGHT("@(#) Copyright (c) 1990, 1993\
|
||||||
|
The Regents of the University of California. All rights reserved.");
|
||||||
|
#if 0
|
||||||
|
static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
|
||||||
|
__FBSDID("$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.62 2006/01/01 22:59:54 jmallett Exp $");
|
||||||
|
#endif
|
||||||
|
__RCSID("$NetBSD: xargs.c,v 1.20 2010/12/17 11:32:57 plunky Exp $");
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <langinfo.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
|
||||||
|
static void parse_input(int, char *[]);
|
||||||
|
static void prerun(int, char *[]);
|
||||||
|
static int prompt(void);
|
||||||
|
static void run(char **);
|
||||||
|
static void usage(void) __dead;
|
||||||
|
void strnsubst(char **, const char *, const char *, size_t);
|
||||||
|
static void waitchildren(const char *, int);
|
||||||
|
|
||||||
|
static char echo[] = _PATH_ECHO;
|
||||||
|
static char **av, **bxp, **ep, **endxp, **xp;
|
||||||
|
static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
|
||||||
|
static const char *eofstr;
|
||||||
|
static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
|
||||||
|
static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag;
|
||||||
|
static int curprocs, maxprocs;
|
||||||
|
|
||||||
|
static volatile int childerr;
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
long arg_max;
|
||||||
|
int ch, Jflag, nargs, nflag, nline;
|
||||||
|
size_t linelen;
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
|
setprogname(argv[0]);
|
||||||
|
|
||||||
|
inpline = replstr = NULL;
|
||||||
|
ep = environ;
|
||||||
|
eofstr = "";
|
||||||
|
Jflag = nflag = 0;
|
||||||
|
|
||||||
|
(void)setlocale(LC_ALL, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SUSv3 says of the exec family of functions:
|
||||||
|
* The number of bytes available for the new process'
|
||||||
|
* combined argument and environment lists is {ARG_MAX}. It
|
||||||
|
* is implementation-defined whether null terminators,
|
||||||
|
* pointers, and/or any alignment bytes are included in this
|
||||||
|
* total.
|
||||||
|
*
|
||||||
|
* SUSv3 says of xargs:
|
||||||
|
* ... the combined argument and environment lists ...
|
||||||
|
* shall not exceed {ARG_MAX}-2048.
|
||||||
|
*
|
||||||
|
* To be conservative, we use ARG_MAX - 4K, and we do include
|
||||||
|
* nul terminators and pointers in the calculation.
|
||||||
|
*
|
||||||
|
* Given that the smallest argument is 2 bytes in length, this
|
||||||
|
* means that the number of arguments is limited to:
|
||||||
|
*
|
||||||
|
* (ARG_MAX - 4K - LENGTH(env + 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.
|
||||||
|
*/
|
||||||
|
nargs = 5000;
|
||||||
|
if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
|
||||||
|
errx(1, "sysconf(_SC_ARG_MAX) failed");
|
||||||
|
nline = arg_max - 4 * 1024;
|
||||||
|
while (*ep != NULL) {
|
||||||
|
/* 1 byte for each '\0' */
|
||||||
|
nline -= strlen(*ep++) + 1 + sizeof(*ep);
|
||||||
|
}
|
||||||
|
maxprocs = 1;
|
||||||
|
while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1)
|
||||||
|
switch (ch) {
|
||||||
|
case 'E':
|
||||||
|
eofstr = optarg;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
Jflag = 0;
|
||||||
|
Iflag = 1;
|
||||||
|
Lflag = 1;
|
||||||
|
replstr = optarg;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
Iflag = 0;
|
||||||
|
Jflag = 1;
|
||||||
|
replstr = optarg;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
Lflag = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nflag = 1;
|
||||||
|
if ((nargs = atoi(optarg)) <= 0)
|
||||||
|
errx(1, "illegal argument count");
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
oflag = 1;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
if ((maxprocs = atoi(optarg)) <= 0)
|
||||||
|
errx(1, "max. processes must be >0");
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
pflag = 1;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
Rflag = strtol(optarg, &endptr, 10);
|
||||||
|
if (*endptr != '\0')
|
||||||
|
errx(1, "replacements must be a number");
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
/* GNU compatibility */
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
Sflag = strtoul(optarg, &endptr, 10);
|
||||||
|
if (*endptr != '\0')
|
||||||
|
errx(1, "replsize must be a number");
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
nline = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
tflag = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
xflag = 1;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
zflag = 1;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (!Iflag && Rflag)
|
||||||
|
usage();
|
||||||
|
if (!Iflag && Sflag)
|
||||||
|
usage();
|
||||||
|
if (Iflag && !Rflag)
|
||||||
|
Rflag = 5;
|
||||||
|
if (Iflag && !Sflag)
|
||||||
|
Sflag = 255;
|
||||||
|
if (xflag && !nflag)
|
||||||
|
usage();
|
||||||
|
if (Iflag || Lflag)
|
||||||
|
xflag = 1;
|
||||||
|
if (replstr != NULL && *replstr == '\0')
|
||||||
|
errx(1, "replstr may not be empty");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate pointers for the utility name, the utility arguments,
|
||||||
|
* the maximum arguments to be read from stdin and the trailing
|
||||||
|
* NULL.
|
||||||
|
*/
|
||||||
|
linelen = 1 + argc + nargs + 1;
|
||||||
|
if ((av = bxp = malloc(linelen * sizeof(char **))) == NULL)
|
||||||
|
errx(1, "malloc failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* arguments.
|
||||||
|
*/
|
||||||
|
if (*argv == NULL)
|
||||||
|
cnt = strlen(*bxp++ = echo);
|
||||||
|
else {
|
||||||
|
do {
|
||||||
|
if (Jflag && strcmp(*argv, replstr) == 0) {
|
||||||
|
char **avj;
|
||||||
|
jfound = 1;
|
||||||
|
argv++;
|
||||||
|
for (avj = argv; *avj; avj++)
|
||||||
|
cnt += strlen(*avj) + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cnt += strlen(*bxp++ = *argv) + 1;
|
||||||
|
} while (*++argv != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
endxp = (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
|
||||||
|
* slot.
|
||||||
|
*/
|
||||||
|
nline -= cnt;
|
||||||
|
if (nline <= 0)
|
||||||
|
errx(1, "insufficient space for command");
|
||||||
|
|
||||||
|
if ((bbp = malloc((size_t)(nline + 1))) == NULL)
|
||||||
|
errx(1, "malloc failed");
|
||||||
|
ebp = (argp = p = bbp) + nline - 1;
|
||||||
|
for (;;)
|
||||||
|
parse_input(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_input(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int ch, foundeof;
|
||||||
|
char **avj;
|
||||||
|
|
||||||
|
foundeof = 0;
|
||||||
|
|
||||||
|
switch (ch = getchar()) {
|
||||||
|
case EOF:
|
||||||
|
/* No arguments since last exec. */
|
||||||
|
if (p == bbp) {
|
||||||
|
waitchildren(*argv, 1);
|
||||||
|
exit(rval);
|
||||||
|
}
|
||||||
|
goto arg1;
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
/* Quotes escape tabs and spaces. */
|
||||||
|
if (insingle || indouble || zflag)
|
||||||
|
goto addch;
|
||||||
|
goto arg2;
|
||||||
|
case '\0':
|
||||||
|
if (zflag) {
|
||||||
|
/*
|
||||||
|
* Increment 'count', so that nulls will be treated
|
||||||
|
* as end-of-line, as well as end-of-argument. This
|
||||||
|
* is needed so -0 works properly with -I and -L.
|
||||||
|
*/
|
||||||
|
count++;
|
||||||
|
goto arg2;
|
||||||
|
}
|
||||||
|
goto addch;
|
||||||
|
case '\n':
|
||||||
|
if (zflag)
|
||||||
|
goto addch;
|
||||||
|
count++; /* Indicate end-of-line (used by -L) */
|
||||||
|
|
||||||
|
/* Quotes do not escape newlines. */
|
||||||
|
arg1: if (insingle || indouble)
|
||||||
|
errx(1, "unterminated quote");
|
||||||
|
arg2:
|
||||||
|
foundeof = *eofstr != '\0' &&
|
||||||
|
strncmp(argp, eofstr, (size_t)(p - argp)) == 0;
|
||||||
|
|
||||||
|
/* Do not make empty args unless they are quoted */
|
||||||
|
if ((argp != p || wasquoted) && !foundeof) {
|
||||||
|
*p++ = '\0';
|
||||||
|
*xp++ = argp;
|
||||||
|
if (Iflag) {
|
||||||
|
size_t curlen;
|
||||||
|
|
||||||
|
if (inpline == NULL)
|
||||||
|
curlen = 0;
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* If this string is not zero
|
||||||
|
* length, append a space for
|
||||||
|
* separation before the next
|
||||||
|
* argument.
|
||||||
|
*/
|
||||||
|
if ((curlen = strlen(inpline)) != 0)
|
||||||
|
(void)strcat(inpline, " ");
|
||||||
|
}
|
||||||
|
curlen++;
|
||||||
|
/*
|
||||||
|
* Allocate enough to hold what we will
|
||||||
|
* be holding in a second, and to append
|
||||||
|
* a space next time through, if we have
|
||||||
|
* to.
|
||||||
|
*/
|
||||||
|
inpline = realloc(inpline, curlen + 2 +
|
||||||
|
strlen(argp));
|
||||||
|
if (inpline == NULL)
|
||||||
|
errx(1, "realloc failed");
|
||||||
|
if (curlen == 1)
|
||||||
|
(void)strcpy(inpline, argp);
|
||||||
|
else
|
||||||
|
(void)strcat(inpline, argp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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. Having reached the limit
|
||||||
|
* of input lines, as specified by -L is the same as
|
||||||
|
* maxing out on arguments.
|
||||||
|
*/
|
||||||
|
if (xp == endxp || p > ebp || ch == EOF ||
|
||||||
|
(Lflag <= count && xflag) || foundeof) {
|
||||||
|
if (xflag && xp != endxp && p > ebp)
|
||||||
|
errx(1, "insufficient space for arguments");
|
||||||
|
if (jfound) {
|
||||||
|
for (avj = argv; *avj; avj++)
|
||||||
|
*xp++ = *avj;
|
||||||
|
}
|
||||||
|
prerun(argc, av);
|
||||||
|
if (ch == EOF || foundeof) {
|
||||||
|
waitchildren(*argv, 1);
|
||||||
|
exit(rval);
|
||||||
|
}
|
||||||
|
p = bbp;
|
||||||
|
xp = bxp;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
argp = p;
|
||||||
|
wasquoted = 0;
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
if (indouble || zflag)
|
||||||
|
goto addch;
|
||||||
|
insingle = !insingle;
|
||||||
|
wasquoted = 1;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
if (insingle || zflag)
|
||||||
|
goto addch;
|
||||||
|
indouble = !indouble;
|
||||||
|
wasquoted = 1;
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
if (zflag)
|
||||||
|
goto addch;
|
||||||
|
/* Backslash escapes anything, is escaped by quotes. */
|
||||||
|
if (!insingle && !indouble && (ch = getchar()) == EOF)
|
||||||
|
errx(1, "backslash at EOF");
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
addch: if (p < ebp) {
|
||||||
|
*p++ = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If only one argument, not enough buffer space. */
|
||||||
|
if (bxp == xp)
|
||||||
|
errx(1, "insufficient space for argument");
|
||||||
|
/* Didn't hit argument limit, so if xflag object. */
|
||||||
|
if (xflag)
|
||||||
|
errx(1, "insufficient space for arguments");
|
||||||
|
|
||||||
|
if (jfound) {
|
||||||
|
for (avj = argv; *avj; avj++)
|
||||||
|
*xp++ = *avj;
|
||||||
|
}
|
||||||
|
prerun(argc, av);
|
||||||
|
xp = bxp;
|
||||||
|
cnt = ebp - argp;
|
||||||
|
(void)memcpy(bbp, argp, (size_t)cnt);
|
||||||
|
p = (argp = bbp) + cnt;
|
||||||
|
*p++ = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do things necessary before run()'ing, such as -I substitution,
|
||||||
|
* and then call run().
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
prerun(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char **tmp, **tmp2, **avj;
|
||||||
|
int repls;
|
||||||
|
|
||||||
|
repls = Rflag;
|
||||||
|
|
||||||
|
if (argc == 0 || repls == 0) {
|
||||||
|
*xp = NULL;
|
||||||
|
run(argv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avj = argv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory to hold the argument list, and
|
||||||
|
* a NULL at the tail.
|
||||||
|
*/
|
||||||
|
tmp = malloc((argc + 1) * sizeof(char**));
|
||||||
|
if (tmp == NULL)
|
||||||
|
errx(1, "malloc failed");
|
||||||
|
tmp2 = tmp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the first argument and iterate over it, we
|
||||||
|
* cannot do strnsubst() to it.
|
||||||
|
*/
|
||||||
|
if ((*tmp++ = strdup(*avj++)) == NULL)
|
||||||
|
errx(1, "strdup failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each argument to utility, if we have not used up
|
||||||
|
* the number of replacements we are allowed to do, and
|
||||||
|
* if the argument contains at least one occurrence of
|
||||||
|
* replstr, call strnsubst(), else just save the string.
|
||||||
|
* Iterations over elements of avj and tmp are done
|
||||||
|
* where appropriate.
|
||||||
|
*/
|
||||||
|
while (--argc) {
|
||||||
|
*tmp = *avj++;
|
||||||
|
if (repls && strstr(*tmp, replstr) != NULL) {
|
||||||
|
strnsubst(tmp++, replstr, inpline, (size_t)Sflag);
|
||||||
|
if (repls > 0)
|
||||||
|
repls--;
|
||||||
|
} else {
|
||||||
|
if ((*tmp = strdup(*tmp)) == NULL)
|
||||||
|
errx(1, "strdup failed");
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run it.
|
||||||
|
*/
|
||||||
|
*tmp = NULL;
|
||||||
|
run(tmp2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walk from the tail to the head, free along the way.
|
||||||
|
*/
|
||||||
|
for (; tmp2 != tmp; tmp--)
|
||||||
|
free(*tmp);
|
||||||
|
/*
|
||||||
|
* Now free the list itself.
|
||||||
|
*/
|
||||||
|
free(tmp2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the input line buffer, if we have one.
|
||||||
|
*/
|
||||||
|
if (inpline != NULL) {
|
||||||
|
free(inpline);
|
||||||
|
inpline = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run(char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char **avec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user wants to be notified of each command before it is
|
||||||
|
* executed, notify them. If they want the notification to be
|
||||||
|
* followed by a prompt, then prompt them.
|
||||||
|
*/
|
||||||
|
if (tflag || pflag) {
|
||||||
|
(void)fprintf(stderr, "%s", *argv);
|
||||||
|
for (avec = argv + 1; *avec != NULL; ++avec)
|
||||||
|
(void)fprintf(stderr, " %s", *avec);
|
||||||
|
/*
|
||||||
|
* If the user has asked to be prompted, do so.
|
||||||
|
*/
|
||||||
|
if (pflag)
|
||||||
|
/*
|
||||||
|
* If they asked not to exec, return without execution
|
||||||
|
* but if they asked to, go to the execution. If we
|
||||||
|
* could not open their tty, break the switch and drop
|
||||||
|
* back to -t behaviour.
|
||||||
|
*/
|
||||||
|
switch (prompt()) {
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
goto exec;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(void)fprintf(stderr, "\n");
|
||||||
|
(void)fflush(stderr);
|
||||||
|
}
|
||||||
|
exec:
|
||||||
|
childerr = 0;
|
||||||
|
switch (vfork()) {
|
||||||
|
case -1:
|
||||||
|
err(1, "vfork");
|
||||||
|
/*NOTREACHED*/
|
||||||
|
case 0:
|
||||||
|
if (oflag) {
|
||||||
|
if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
|
||||||
|
err(1, "can't open /dev/tty");
|
||||||
|
} else {
|
||||||
|
fd = open(_PATH_DEVNULL, O_RDONLY);
|
||||||
|
}
|
||||||
|
if (fd > STDIN_FILENO) {
|
||||||
|
if (dup2(fd, STDIN_FILENO) != 0)
|
||||||
|
err(1, "can't dup2 to stdin");
|
||||||
|
(void)close(fd);
|
||||||
|
}
|
||||||
|
(void)execvp(argv[0], argv);
|
||||||
|
childerr = errno;
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
curprocs++;
|
||||||
|
waitchildren(*argv, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
waitchildren(const char *name, int waitall)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while ((pid = waitpid(-1, &status, !waitall && curprocs < maxprocs ?
|
||||||
|
WNOHANG : 0)) > 0) {
|
||||||
|
curprocs--;
|
||||||
|
/* If we couldn't invoke the utility, exit. */
|
||||||
|
if (childerr != 0) {
|
||||||
|
errno = childerr;
|
||||||
|
err(errno == ENOENT ? 127 : 126, "%s", name);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* According to POSIX, we have to exit if the utility exits
|
||||||
|
* with a 255 status, or is interrupted by a signal. xargs
|
||||||
|
* is allowed to return any exit status between 1 and 125
|
||||||
|
* in these cases, but we'll use 124 and 125, the same
|
||||||
|
* values used by GNU xargs.
|
||||||
|
*/
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
if (WEXITSTATUS (status) == 255) {
|
||||||
|
warnx ("%s exited with status 255", name);
|
||||||
|
exit(124);
|
||||||
|
} else if (WEXITSTATUS (status) != 0) {
|
||||||
|
rval = 123;
|
||||||
|
}
|
||||||
|
} else if (WIFSIGNALED (status)) {
|
||||||
|
if (WTERMSIG(status) < NSIG) {
|
||||||
|
warnx("%s terminated by SIG%s", name,
|
||||||
|
sys_signame[WTERMSIG(status)]);
|
||||||
|
} else {
|
||||||
|
warnx("%s terminated by signal %d", name,
|
||||||
|
WTERMSIG(status));
|
||||||
|
}
|
||||||
|
exit(125);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pid == -1 && errno != ECHILD)
|
||||||
|
err(1, "waitpid");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prompt the user about running a command.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
prompt(void)
|
||||||
|
{
|
||||||
|
regex_t cre;
|
||||||
|
size_t rsize;
|
||||||
|
int match;
|
||||||
|
char *response;
|
||||||
|
FILE *ttyfp;
|
||||||
|
|
||||||
|
if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
|
||||||
|
return (2); /* Indicate that the TTY failed to open. */
|
||||||
|
(void)fprintf(stderr, "?...");
|
||||||
|
(void)fflush(stderr);
|
||||||
|
if ((response = fgetln(ttyfp, &rsize)) == NULL ||
|
||||||
|
regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) {
|
||||||
|
(void)fclose(ttyfp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
response[rsize - 1] = '\0';
|
||||||
|
match = regexec(&cre, response, 0, NULL, 0);
|
||||||
|
(void)fclose(ttyfp);
|
||||||
|
regfree(&cre);
|
||||||
|
return (match == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void)fprintf(stderr,
|
||||||
|
"Usage: %s [-0opt] [-E eofstr] [-I replstr [-R replacements] [-S replsize]]\n"
|
||||||
|
" [-J replstr] [-L number] [-n number [-x]] [-P maxprocs]\n"
|
||||||
|
" [-s size] [utility [argument ...]]\n", getprogname());
|
||||||
|
exit(1);
|
||||||
|
}
|
Loading…
Reference in a new issue