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 \
|
||||
unstack update uud uue version vol \
|
||||
whereis which write writeisofs fetch \
|
||||
xargs zdump zmodem pkgin_cd pkgin_all \
|
||||
zdump zmodem pkgin_cd pkgin_all \
|
||||
worldstone updateboot update_bootcfg
|
||||
|
||||
.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 \
|
||||
truncate.1 tty.1 umount.1 uname.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 ..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 \
|
||||
\
|
||||
wc whatis who \
|
||||
xinstall yes
|
||||
xargs xinstall yes
|
||||
|
||||
.if !defined(__MINIX)
|
||||
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