--- /dev/null
+xargs/pathname.h freebsd usr.bin/xargs/pathname.h 872b698bd4a1bfc0bf008c09228e6fd238809c75
+xargs/strnsubst.c freebsd usr.bin/xargs/strnsubst.c 56640efcbe39386a0152f14fb18a314b85e7e014
+xargs/xargs.1 freebsd usr.bin/xargs/xargs.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da
+xargs/xargs.c freebsd usr.bin/xargs/xargs.c 872b698bd4a1bfc0bf008c09228e6fd238809c75
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $");
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
+#include <err.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include <wchar.h>
-/*
- * Report an error and exit.
- * Use it instead of err(3) to avoid linking-in stdio.
- */
-static void
-errexit(const char *prog, const char *reason)
+static char *
+print_one_char(char *cur, int *bytes_len_out)
{
- char *errstr = strerror(errno);
- write(STDERR_FILENO, prog, strlen(prog));
- write(STDERR_FILENO, ": ", 2);
- write(STDERR_FILENO, reason, strlen(reason));
- write(STDERR_FILENO, ": ", 2);
- write(STDERR_FILENO, errstr, strlen(errstr));
- write(STDERR_FILENO, "\n", 1);
- exit(1);
+ wchar_t wc;
+ int bytes_len = mbtowc(&wc, cur, MB_CUR_MAX);
+ if (bytes_len <= 0) {
+ putchar(*cur);
+ bytes_len = 1;
+ goto out;
+ }
+
+ if (wc != '\\') {
+ putwchar(wc);
+ goto out;
+ }
+
+ cur += bytes_len;
+ bytes_len = 1;
+
+ switch (*cur) {
+ case 'a':
+ putchar('\a');
+ goto out;
+
+ case 'b':
+ putchar('\b');
+ goto out;
+
+ case 'c':
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
+ exit(0);
+
+ case 'f':
+ putchar('\f');
+ goto out;
+
+ case 'n':
+ putchar('\n');
+ goto out;
+
+ case 'r':
+ putchar('\r');
+ goto out;
+
+ case 't':
+ putchar('\t');
+ goto out;
+
+ case 'v':
+ putchar('\v');
+ goto out;
+
+ case '\\':
+ putchar('\\');
+ goto out;
+
+ case '0': {
+ int j = 0, num = 0;
+ while ((*++cur >= '0' && *cur <= '7') &&
+ j++ < 3) {
+ num <<= 3;
+ num |= (*cur - '0');
+ }
+ putchar(num);
+ --cur;
+ goto out;
+ }
+ default:
+ --cur;
+ putchar(*cur);
+ goto out;
+ }
+
+ out:
+ if (bytes_len_out)
+ *bytes_len_out = bytes_len;
+ return cur;
}
-
+
int
main(int argc, char *argv[])
{
- int nflag; /* if not set, output a trailing newline. */
- int veclen; /* number of writev arguments. */
- struct iovec *iov, *vp; /* Elements to write, current element. */
- char space[] = " ";
- char newline[] = "\n";
- char *progname = argv[0];
-
- /* This utility may NOT do getopt(3) option parsing. */
- if (*++argv && !strcmp(*argv, "-n")) {
- ++argv;
- --argc;
+ int nflag = 0;
+ int posix = (getenv("POSIXLY_CORRECT") != NULL || getenv("POSIX_PEDANTIC") != NULL);
+
+ if (!posix && argv[1] && strcmp(argv[1], "-n") == 0)
nflag = 1;
- } else
- nflag = 0;
-
- veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
-
- if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL)
- errexit(progname, "malloc");
-
- while (argv[0] != NULL) {
- size_t len;
-
- len = strlen(argv[0]);
-
- /*
- * If the next argument is NULL then this is this
- * the last argument, therefore we need to check
- * for a trailing \c.
- */
- if (argv[1] == NULL) {
- /* is there room for a '\c' and is there one? */
- if (len >= 2 &&
- argv[0][len - 2] == '\\' &&
- argv[0][len - 1] == 'c') {
- /* chop it and set the no-newline flag. */
- len -= 2;
- nflag = 1;
+
+ for (int i = 0; i < argc; i++) {
+ /* argv[0] == progname */
+ int ignore_arg = (i == 0 || (i == 1 && nflag == 1));
+ int last_arg = (i == (argc - 1));
+ if (!ignore_arg) {
+ char *cur = argv[i];
+ size_t arg_len = strlen(cur);
+ int bytes_len = 0;
+
+ for (const char *end = cur + arg_len; cur < end; cur += bytes_len) {
+ cur = print_one_char(cur, &bytes_len);
}
}
- vp->iov_base = *argv;
- vp++->iov_len = len;
- if (*++argv) {
- vp->iov_base = space;
- vp++->iov_len = 1;
- }
- }
- if (!nflag) {
- veclen++;
- vp->iov_base = newline;
- vp++->iov_len = 1;
- }
- /* assert(veclen == (vp - iov)); */
- while (veclen) {
- int nwrite;
-
- nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
- if (writev(STDOUT_FILENO, iov, nwrite) == -1)
- errexit(progname, "write");
- iov += nwrite;
- veclen -= nwrite;
+ if (last_arg && !nflag)
+ putchar('\n');
+ else if (!last_arg && !ignore_arg)
+ putchar(' ');
+
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
}
+
return 0;
}
static void printsignals(FILE *);
static int signame_to_signum(const char *);
static void usage(void);
+static void print_signum(int, FILE *, char);
#ifdef __APPLE__
#define sys_nsig NSIG
numsig -= 128;
if (numsig <= 0 || numsig >= sys_nsig)
nosig(*argv);
- printf("%s\n", sys_signame[numsig]);
+ print_signum(numsig, stdout, '\n');
return (0);
}
printsignals(stdout);
return (errors);
}
+static void
+print_signum(int numsig, FILE *fp, char separator)
+{
+ char *signame;
+ int i;
+
+ signame = strdup(sys_signame[numsig]);
+
+ for(i = 0; signame[i] != '\0'; i++) {
+ char upper = toupper(signame[i]);
+ signame[i] = upper;
+ }
+ fprintf(fp, "%s%c", signame, separator);
+
+ free(signame);
+}
+
static int
signame_to_signum(const char *sig)
{
int n;
for (n = 1; n < sys_nsig; n++) {
- (void)fprintf(fp, "%s", sys_signame[n]);
+ char sep = ' ';
if (n == (sys_nsig / 2) || n == (sys_nsig - 1))
- (void)fprintf(fp, "\n");
- else
- (void)fprintf(fp, " ");
+ sep = '\n';
+ print_signum(n, fp, sep);
}
}
.\" 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.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 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.
.\"
.\" SUCH DAMAGE.
.\"
.\" @(#)printf.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: head/usr.bin/printf/printf.1 264743 2014-04-21 22:47:18Z pfg $
+.\" $FreeBSD$
.\"
-.Dd April 21, 2014
+.Dd July 1, 2020
.Dt PRINTF 1
.Os
.Sh NAME
Write a <bell> character.
.It Cm \eb
Write a <backspace> character.
-.It Cm \ec
-Ignore remaining characters in this string.
.It Cm \ef
Write a <form-feed> character.
.It Cm \en
octal escapes are
.Cm \e0 Ns Ar num
instead of
-.Cm \e Ns Ar num .
+.Cm \e Ns Ar num
+and that an additional escape sequence
+.Cm \ec
+stops further output from this
+.Nm
+invocation.
.It Cm n$
Allows reordering of the output according to
.Ar argument .
manual page.
.Sh EXIT STATUS
.Ex -std
+.Sh EXAMPLES
+Print the string
+.Qq hello :
+.Bd -literal -offset indent
+$ printf "%s\en" hello
+hello
+.Ed
+.Pp
+Same as above, but notice that the format string is not quoted and hence we
+do not get the expected behavior:
+.Bd -literal -offset indent
+$ printf %s\en hello
+hellon$
+.Ed
+.Pp
+Print arguments forcing sign only for the first argument:
+.Bd -literal -offset indent
+$ printf "%+d\en%d\en%d\en" 1 -2 13
++1
+-2
+13
+.Ed
+.Pp
+Same as above, but the single format string will be applied to the three
+arguments:
+.Bd -literal -offset indent
+$ printf "%+d\en" 1 -2 13
++1
+-2
++13
+.Ed
+.Pp
+Print number using only two digits after the decimal point:
+.Bd -literal -offset indent
+$ printf "%.2f\en" 31.7456
+31.75
+.Ed
.Sh COMPATIBILITY
The traditional
.Bx
behavior of converting arguments of numeric formats not beginning
-with a digit to the
-.Tn ASCII
+with a digit to the ASCII
code of the first character is not supported.
.Sh SEE ALSO
.Xr builtin 1 ,
after the standard library function,
.Xr printf 3 .
.Sh CAVEATS
-.Tn ANSI
-hexadecimal character constants were deliberately not provided.
+ANSI hexadecimal character constants were deliberately not provided.
.Pp
Trying to print a dash ("-") as the first character causes
.Nm
formats with a precision
may not operate as expected.
.Sh BUGS
-Since the floating point numbers are translated from
-.Tn ASCII
-to floating-point and
-then back again, floating-point precision may be lost.
+Since the floating point numbers are translated from ASCII
+to floating-point and then back again, floating-point precision may be lost.
(By default, the number is translated to an IEEE-754 double-precision
value before being printed.
The
/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* 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.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
*
static char const sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
#endif
static const char rcsid[] =
- "$FreeBSD: head/usr.bin/printf/printf.c 279503 2015-03-01 21:46:55Z jilles $";
+ "$FreeBSD$";
#endif /* not lint */
#include <sys/types.h>
#endif
#define PF(f, func) do { \
- char *b = NULL; \
if (havewidth) \
if (haveprec) \
- (void)asprintf(&b, f, fieldwidth, precision, func); \
+ (void)printf(f, fieldwidth, precision, func); \
else \
- (void)asprintf(&b, f, fieldwidth, func); \
+ (void)printf(f, fieldwidth, func); \
else if (haveprec) \
- (void)asprintf(&b, f, precision, func); \
+ (void)printf(f, precision, func); \
else \
- (void)asprintf(&b, f, func); \
- if (b) { \
- (void)fputs(b, stdout); \
- free(b); \
- } \
+ (void)printf(f, func); \
} while (0)
static int asciicode(void);
char *p;
int getout;
- p = strdup(getstr());
- if (p == NULL) {
+ /* Convert "b" to "s" for output. */
+ start[strlen(start) - 1] = 's';
+ if ((p = strdup(getstr())) == NULL) {
warnx("%s", strerror(ENOMEM));
return (NULL);
}
getout = escape(p, 0, &len);
- fputs(p, stdout);
+ /*
+ * Special-case conversion of zero; print it instead of
+ * feeding an empty string to printf("%s") which would not
+ * print anything.
+ */
+ if (len == 1 && p[0] == '\0') {
+ putchar(p[0]);
+ } else {
+ PF(start, p);
+ }
+ /* Restore format for next loop. */
+
free(p);
if (getout)
return (end_fmt);
char p;
p = getchr();
- PF(start, p);
+ if (p != '\0')
+ PF(start, p);
break;
}
case 's': {
<key>OpenSourceProject</key>
<string>printf</string>
<key>OpenSourceVersion</key>
- <string>2015-03-01</string>
+ <string>2020-07-01</string>
<key>OpenSourceWebsiteURL</key>
- <string>http://svnweb.freebsd.org/base/head/usr.bin/printf/</string>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
<key>OpenSourceSCM</key>
- <string>svn co http://svn.freebsd.org/base/head/usr.bin/printf/</string>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
<key>OpenSourceImportDate</key>
- <string>2015-07-23</string>
+ <string>2020-07-23</string>
<key>OpenSourceModifications</key>
<array>
+ <string>65959587: UNIX Conformance | /usr/bin/printf, multiple format assertion failures in VSC</string>
</array>
<key>OpenSourceLicense</key>
<string>bsd</string>
-# $FreeBSD: head/usr.bin/printf/tests/Makefile 299094 2016-05-04 23:20:53Z ngie $
+# $FreeBSD$
PACKAGE= tests
TAP_TESTS_SH= legacy_test
${PACKAGE}FILES+= regress.b.out
+${PACKAGE}FILES+= regress.bwidth.out
${PACKAGE}FILES+= regress.d.out
${PACKAGE}FILES+= regress.f.out
${PACKAGE}FILES+= regress.l1.out
-# $FreeBSD: head/usr.bin/printf/tests/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# $FreeBSD$
# Autogenerated - do NOT edit!
DIRDEPS = \
#!/bin/sh
-# $FreeBSD: head/usr.bin/printf/tests/legacy_test.sh 263227 2014-03-16 08:04:06Z jmmv $
+# $FreeBSD$
SRCDIR="$(dirname "${0}")"; export SRCDIR
-# $FreeBSD: head/usr.bin/printf/tests/regress.sh 266854 2014-05-29 19:48:18Z pfg $
-
-enable -n printf
+# $FreeBSD$
REGRESSION_START($1)
-echo '1..23'
+echo '1..24'
REGRESSION_TEST(`b', `printf "abc%b%b" "def\n" "\cghi"')
REGRESSION_TEST(`d', `printf "%d,%5d,%.5d,%0*d,%.*d\n" 123 123 123 5 123 5 123')
REGRESSION_TEST(`missingpos1', `printf "%1\$*2\$.*s" 1 1 1 2>&1')
REGRESSION_TEST(`missingpos1', `printf "%*1\$.*2\$s" 1 1 1 2>&1')
REGRESSION_TEST(`missingpos1', `printf "%1\$*.*2\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`bwidth', `printf "%8.2b" "a\nb\n"')
REGRESSION_END()
C6868576154725700025D623 /* systime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = systime; sourceTree = BUILT_PRODUCTS_DIR; };
C6868579154725700025D623 /* systime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = systime.c; sourceTree = "<group>"; };
C686857B154725700025D623 /* systime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = systime.1; sourceTree = "<group>"; };
+ CE799E6024AD3B1B00E73238 /* test_time.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = test_time.sh; sourceTree = "<group>"; usesTabs = 1; };
+ CE799E6224B3982200E73238 /* install-files.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-files.sh"; sourceTree = "<group>"; };
+ CE799E6324B3982200E73238 /* builtins.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = builtins.txt; sourceTree = "<group>"; };
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "builtins-manpages.txt"; sourceTree = "<group>"; };
FC5D636814B9808E00123E48 /* conv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv.c; sourceTree = "<group>"; };
FC5D636914B9808E00123E48 /* display.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = display.c; sourceTree = "<group>"; };
FC5D636A14B9808E00123E48 /* hexdump.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hexdump.1; sourceTree = "<group>"; };
FCBA13FA14A141A300AA698B /* test.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test.1; sourceTree = "<group>"; };
FCBA13FB14A141A300AA698B /* test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = "<group>"; };
FCBA13FF14A141A300AA698B /* time.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = time.1; sourceTree = "<group>"; };
- FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = "<group>"; };
+ FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = "<group>"; usesTabs = 1; };
FCBA140314A141A300AA698B /* true.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = true.1; sourceTree = "<group>"; };
FCBA140414A141A300AA698B /* true.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = true.c; sourceTree = "<group>"; };
FCBA140814A141A300AA698B /* uname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uname.1; sourceTree = "<group>"; };
path = systime;
sourceTree = "<group>";
};
+ CE799E5F24AD3B1B00E73238 /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6024AD3B1B00E73238 /* test_time.sh */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ CE799E6124B3982200E73238 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6224B3982200E73238 /* install-files.sh */,
+ CE799E6324B3982200E73238 /* builtins.txt */,
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
FC5D636714B9808E00123E48 /* hexdump */ = {
isa = PBXGroup;
children = (
FC80BF5514A05A2F00C6F7F5 = {
isa = PBXGroup;
children = (
+ CE799E6124B3982200E73238 /* xcodescripts */,
FD60612F1B7D2DDE004BCA6A /* xcconfigs */,
FCBA134014A141A300AA698B /* alias */,
FCBA134514A141A300AA698B /* apply */,
FCBA13FD14A141A300AA698B /* time */ = {
isa = PBXGroup;
children = (
+ CE799E5F24AD3B1B00E73238 /* tests */,
FCBA13FF14A141A300AA698B /* time.1 */,
FCBA140014A141A300AA698B /* time.c */,
);
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
showEnvVarsInLog = 0;
};
FCE30F4D14B619C900CC0294 /* Run Script */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
showEnvVarsInLog = 0;
};
FD6060EF1B7C0590004BCA6A /* mkbuiltins */ = {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "env -i xcrun -sdk macosx cc ${SRCROOT}/sh/mknodes.c -o ${DERIVED_FILE_DIR}/mknodes\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mknodes ${SRCROOT}/sh/nodetypes ${SRCROOT}/sh/nodes.c.pat";
+ shellScript = "mkdir -p ${DERIVED_FILE_DIR}\nenv -i xcrun -sdk macosx cc ${SRCROOT}/sh/mknodes.c -o ${DERIVED_FILE_DIR}/mknodes\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mknodes ${SRCROOT}/sh/nodetypes ${SRCROOT}/sh/nodes.c.pat\n";
};
FD6060F21B7C0744004BCA6A /* mksyntax */ = {
isa = PBXShellScriptBuildPhase;
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>com.apple.keystore.console</key>
+ <true/>
<key>com.apple.private.security.clear-library-validation</key>
<true/>
</dict>
<string>/bin/sh</string>
<string>/AppleInternal/Tests/shell_cmds/printf/legacy_test.sh</string>
</array>
- <key>IgnoreOutput</key>
- <true/>
- <key>TestName</key>
- <string>shell_cmds: printf</string>
+ <key>IgnoreOutput</key><true/>
+ <key>TestName</key><string>shell_cmds.printf</string>
<key>WhenToRun</key>
<array>
<string>PRESUBMISSION</string>
<string>/bin/sh</string>
<string>/AppleInternal/Tests/shell_cmds/test/legacy_test.sh</string>
</array>
- <key>TestName</key>
- <string>shell_cmds: test</string>
+ <key>TestName</key><string>shell_cmds.test</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/time/test_time.sh</string>
+ </array>
+ <key>TestName</key><string>shell_cmds.time</string>
<key>WhenToRun</key>
<array>
<string>PRESUBMISSION</string>
--- /dev/null
+#!/bin/sh
+
+set -o nounset
+
+TIME="${TIME-/usr/bin/time}"
+echo "SUITE: time(1)"
+what $TIME
+echo
+
+EXIT=0
+
+echo TEST: check real time
+
+TIME_SLEEP=`$TIME 2>&1 sleep 1 | sed -n -E 's/[ ]+([0-9]+).*/\1/p'`
+TIME_STATUS=$?
+
+if [ "$TIME_STATUS" -ne "0" ]; then
+ echo FAIL: time failed with "$TIME_STATUS"
+ EXIT=1
+fi
+
+if [ "$TIME_SLEEP" -lt "0" ]; then
+ echo FAIL: time mis-timed sleep
+ EXIT=2
+fi
+
+MONOTONIC=`sysctl -n kern.monotonic.task_thread_counting`
+if [ "$MONOTONIC" -ne "0" ]; then
+ echo TEST: check instructions retired
+
+ TIME_INSTRS=`$TIME -l 2>&1 sleep 1 | sed -E -n '/instructions/p'`
+ if [ -z "$TIME_INSTRS" ]; then
+ echo FAIL: time is not showing instructions retired
+ EXIT=3
+ fi
+else
+ echo SKIP: check instructions retired
+fi
+
+# NB: SIGINT and SIGQUIT work locally, but the automated test harnesses tries to
+# handle those signals itself before the fork.
+
+echo TEST: check child SIGUSR1
+
+TIME_USR1=`$TIME 2>&1 sh -c 'kill -USR1 $$ && sleep 5 && true'`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -eq "0" ]; then
+ echo FAIL: time should allow child to receive SIGUSR1
+ EXIT=4
+fi
+
+echo TEST: check non-existent binary
+TIME_NONEXIST=`$TIME 2>&1 ./this-wont-exist`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -ne "127" ]; then
+ echo FAIL: time should error when measuring a non-existent command
+ EXIT=5
+fi
+
+exit $EXIT
.Nm
utility conforms to
.St -p1003.2-92 .
-.Sh BUGS
-The granularity of seconds on microprocessors is crude and
-can result in times being reported for CPU usage which are too large by
-a second.
* SUCH DAMAGE.
*/
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <libproc.h>
+#include <locale.h>
#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1987, 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93";
-#endif
-__RCSID("$NetBSD: time.c,v 1.9 1997/10/20 03:28:21 lukem Exp $");
-#endif /* not lint */
-
+#include <sysexits.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <time.h>
#include <unistd.h>
-#include <errno.h>
-#include <langinfo.h>
-#include <locale.h>
int lflag;
int portableflag;
+bool child_running = true;
-int main __P((int, char **));
+void
+child_handler(int sig)
+{
+ child_running = false;
+}
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char **argv)
{
int pid;
- int ch, status;
- struct timeval before, after;
+ int ch, status, rusage_ret = -1;
+ uint64_t before_ns, after_ns, duration_ns, duration_secs, duration_frac_ns;
struct rusage ru;
- char * radix = NULL;
+ struct rusage_info_v4 ruinfo;
+ sigset_t sigmask, suspmask, origmask;
-#ifdef __GNUC__ /* XXX: borken gcc */
- (void)&argv;
-#endif
lflag = 0;
- while ((ch = getopt(argc, argv, "lp")) != -1)
+ while ((ch = getopt(argc, argv, "lp")) != -1) {
switch((char)ch) {
case 'p':
portableflag = 1;
break;
case '?':
default:
- fprintf(stderr, "usage: time [-lp] command.\n");
+ fprintf(stderr, "usage: time [-lp] <command>\n");
exit(1);
}
+ }
- if (!(argc -= optind))
+ if (!(argc -= optind)) {
exit(0);
+ }
argv += optind;
- gettimeofday(&before, (struct timezone *)NULL);
- switch(pid = vfork()) {
- case -1: /* error */
- perror("time");
- exit(1);
- /* NOTREACHED */
- case 0: /* child */
+ sigemptyset(&sigmask);
+ /*
+ * Block SIGCHLD so that the check for `child_running` doesn't miss the
+ * handler before calling `sigsuspend` and blocking forever.
+ */
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, &origmask);
+
+ /*
+ * Ensure child signals are handled by the parent prior to fork; otherwise,
+ * they could be missed between the child forking and calling `sigsuspend`.
+ */
+ (void)signal(SIGCHLD, child_handler);
+
+ sigemptyset(&suspmask);
+
+ before_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ /*
+ * NB: Don't add anything between these two lines -- measurement is
+ * happening now.
+ */
+ switch (pid = vfork()) {
+ case -1: /* error */
+ err(EX_OSERR, "time");
+ __builtin_unreachable();
+ case 0: /* child */
+ /*
+ * Allow the child to respond to signals by resetting to the original
+ * signal handling behavior.
+ */
+ (void)sigprocmask(SIG_SETMASK, &origmask, NULL);
execvp(*argv, argv);
perror(*argv);
_exit((errno == ENOENT) ? 127 : 126);
- /* NOTREACHED */
+ __builtin_unreachable();
+ default: /* parent */
+ break;
}
- /* parent */
+ /*
+ * Let the child handle signals that normally exit.
+ */
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
- while (wait3(&status, 0, &ru) != pid);
- gettimeofday(&after, (struct timezone *)NULL);
- if (!WIFEXITED(status))
+
+ while (child_running) {
+ /*
+ * This would be racy, but SIGCHLD is blocked above (as part of
+ * `sigmask`.
+ */
+ sigsuspend(&suspmask);
+ }
+ /*
+ * NB: Minimize what's added between these statements to preserve the
+ * accuracy of the time measurement.
+ */
+ after_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ if (lflag) {
+ rusage_ret = proc_pid_rusage(pid, RUSAGE_INFO_V4, (void **)&ruinfo);
+ }
+ while (wait3(&status, 0, &ru) != pid) {
+ }
+ if (!WIFEXITED(status)) {
fprintf(stderr, "Command terminated abnormally.\n");
- timersub(&after, &before, &after);
+ }
+ duration_ns = after_ns - before_ns;
+ duration_secs = duration_ns / (1000 * 1000 * 1000);
+ duration_frac_ns = duration_ns - (duration_secs * 1000 * 1000 * 1000);
if (portableflag) {
+ char *radix = NULL;
+
setlocale(LC_ALL, "");
radix = nl_langinfo(RADIXCHAR);
radix = ".";
}
- fprintf (stderr, "real %9ld%s%02ld\n",
- (long)after.tv_sec, radix, (long)after.tv_usec/10000);
- fprintf (stderr, "user %9ld%s%02ld\n",
+ fprintf(stderr, "real %9" PRIu64 "%s%02" PRIu64 "\n",
+ duration_secs, radix, duration_frac_ns / (10 * 1000 * 1000));
+ fprintf(stderr, "user %9ld%s%02ld\n",
(long)ru.ru_utime.tv_sec, radix, (long)ru.ru_utime.tv_usec/10000);
- fprintf (stderr, "sys %9ld%s%02ld\n",
+ fprintf(stderr, "sys %9ld%s%02ld\n",
(long)ru.ru_stime.tv_sec, radix, (long)ru.ru_stime.tv_usec/10000);
} else {
- fprintf(stderr, "%9ld.%02ld real ",
- (long)after.tv_sec, (long)after.tv_usec/10000);
+ fprintf(stderr, "%9" PRIu64 ".%02" PRIu64 " real ",
+ duration_secs, duration_frac_ns / (10 * 1000 * 1000));
fprintf(stderr, "%9ld.%02ld user ",
(long)ru.ru_utime.tv_sec, (long)ru.ru_utime.tv_usec/10000);
fprintf(stderr, "%9ld.%02ld sys\n",
}
if (lflag) {
- int hz = 100; /* XXX */
+ int hz = 100; /* XXX */
long ticks;
ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) +
hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000;
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_maxrss, "maximum resident set size");
- fprintf(stderr, "%10ld %s\n", ticks ? ru.ru_ixrss / ticks : 0,
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_ixrss / ticks : 0,
"average shared memory size");
- fprintf(stderr, "%10ld %s\n", ticks ? ru.ru_idrss / ticks : 0,
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_idrss / ticks : 0,
"average unshared data size");
- fprintf(stderr, "%10ld %s\n", ticks ? ru.ru_isrss / ticks : 0,
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_isrss / ticks : 0,
"average unshared stack size");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_minflt, "page reclaims");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_majflt, "page faults");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_nswap, "swaps");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_inblock, "block input operations");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_oublock, "block output operations");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_msgsnd, "messages sent");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_msgrcv, "messages received");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_nsignals, "signals received");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_nvcsw, "voluntary context switches");
- fprintf(stderr, "%10ld %s\n",
+ fprintf(stderr, "%20ld %s\n",
ru.ru_nivcsw, "involuntary context switches");
+
+ if (rusage_ret >= 0) {
+ if (ruinfo.ri_instructions > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_instructions,
+ "instructions retired");
+ }
+ if (ruinfo.ri_cycles > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_cycles,
+ "cycles elapsed");
+ }
+ if (ruinfo.ri_lifetime_max_phys_footprint > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n",
+ ruinfo.ri_lifetime_max_phys_footprint,
+ "peak memory footprint");
+ }
+ }
}
- exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+ exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
}
/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* 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
+ * 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.
*
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * $FreeBSD$
+ *
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
*/
s1 = *str;
if (s1 == NULL)
return;
- s2 = calloc(maxsize, 1);
+ /*
+ * If maxsize is 0 then set it to the length of s1, because we have
+ * to duplicate s1. XXX we maybe should double-check whether the match
+ * 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(1, maxsize);
if (s2 == NULL)
err(1, "calloc");
.\" 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
+.\" 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.
.\"
.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.34 2005/05/21 09:55:09 ru Exp $
.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
.\"
-.Dd August 2, 2004
+.Dd August 4, 2015
.Dt XARGS 1
.Os
.Sh NAME
.Nd "construct argument list(s) and execute utility"
.Sh SYNOPSIS
.Nm
-.Op Fl 0opt
+.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
upon each invocation, followed by some number of the arguments read
from the standard input of
.Nm .
-The utility
-is repeatedly executed until standard input is exhausted.
+This is repeated until standard input is exhausted.
.Pp
Spaces, tabs and newlines may be embedded in arguments using single
(``\ '\ '')
.Ar utility
with the entire line of input.
The resulting arguments, after replacement is done, will not be allowed to grow
-beyond 255 bytes; this is implemented by concatenating as much of the argument
+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 255 bytes.
-The 255 byte limit does not apply to arguments to
+up to
+.Ar replsize
+bytes.
+The size limit does not apply to arguments to
.Ar utility
which do not contain
.Ar replstr ,
directory to
.Pa destdir :
.Pp
-.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -rp % destdir
-.Pp
+.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir
.It Fl L Ar number
Call
.Ar utility
invocations of
.Ar utility
at once.
+If
+.Ar maxprocs
+is set to 0,
+.Nm
+will run as many processes as possible.
.It Fl p
Echo each command to be executed and ask the user whether it should be
executed.
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
+.Fx
+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
+.Fx
+version of
+.Nm .
.It Fl R Ar replacements
Specify the maximum number of arguments that
.Fl I
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 .
is terminated by a signal,
or an invocation of
.Ar utility
-exits with a value of 255.
+exits with a value of 255, the
+.Nm
+utility stops processing input and exits after all invocations of
+.Ar utility
+finish processing.
.Sh LEGACY DESCRIPTION
In legacy mode, the
.Fl L
.St -p1003.2
compliant.
The
-.Fl J , o , P
+.Fl J , o , P, R
and
-.Fl R
+.Fl S
options are non-standard
.Fx
extensions which may not be available on other operating systems.
.Sh HISTORY
The
.Nm
-command appeared in PWB UNIX.
+utility appeared in PWB UNIX.
.Sh BUGS
If
.Ar utility
/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* 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
+ * 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.
*
#endif /* not lint */
#endif
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.57 2005/02/27 02:01:31 gad Exp $");
+__FBSDID("$FreeBSD$");
-#include <sys/param.h>
+#include <sys/types.h>
#include <sys/wait.h>
-
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/resource.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
static void run(char **);
static void usage(void);
void strnsubst(char **, const char *, const char *, size_t);
+static pid_t xwait(int block, int *status);
+static void xexit(const char *, const int);
static void waitchildren(const char *, int);
+static void pids_init(void);
+static int pids_empty(void);
+static int pids_full(void);
+static void pids_add(pid_t pid);
+static int pids_remove(pid_t pid);
+static int findslot(pid_t pid);
+static int findfreeslot(void);
+static void clearslot(int slot);
static int last_was_newline = 1;
static int last_was_blank = 0;
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, wasquoted, xflag;
+static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag;
static int curprocs, maxprocs;
static size_t pad9314053;
+static pid_t *childpids;
static volatile int childerr;
int ch, Jflag, nflag, nline;
size_t nargs;
size_t linelen;
+ struct rlimit rl;
char *endptr;
+ const char *errstr;
inpline = replstr = NULL;
ep = environ;
}
nline -= pad9314053;
maxprocs = 1;
- while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:s:tx")) != -1)
- switch(ch) {
+ while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1)
+ switch (ch) {
case 'E':
eofstr = optarg;
break;
replstr = optarg;
break;
case 'L':
- Lflag = atoi(optarg);
+ Lflag = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-L %s: %s", optarg, errstr);
if (COMPAT_MODE("bin/xargs", "Unix2003")) {
nflag = 0; /* Override */
nargs = 5000;
oflag = 1;
break;
case 'P':
- if ((maxprocs = atoi(optarg)) <= 0)
- errx(1, "max. processes must be >0");
+ maxprocs = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-P %s: %s", optarg, errstr);
+ if (getrlimit(RLIMIT_NPROC, &rl) != 0)
+ errx(1, "getrlimit failed");
+ if (maxprocs == 0 || maxprocs > rl.rlim_cur)
+ maxprocs = rl.rlim_cur;
break;
case 'p':
pflag = 1;
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);
+ nline = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-s %s: %s", optarg, errstr);
pad9314053 = 0; /* assume the -s value is valid */
break;
case 't':
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)
if (replstr != NULL && *replstr == '\0')
errx(1, "replstr may not be empty");
+ pids_init();
+
/*
* 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)
+ if ((av = bxp = malloc(linelen * sizeof(char *))) == NULL)
errx(1, "malloc failed");
/*
foundeof = 0;
- switch(ch = getchar()) {
+ switch (ch = getchar()) {
case EOF:
/* No arguments since last exec. */
- if (p == bbp) {
- waitchildren(*argv, 1);
- exit(rval);
- }
+ if (p == bbp)
+ xexit(*av, rval);
goto arg1;
case ' ':
last_was_blank = 1;
last_was_newline = 1;
/* Quotes do not escape newlines. */
-arg1: if (insingle || indouble)
- errx(1, "unterminated quote");
+arg1: if (insingle || indouble) {
+ warnx("unterminated quote");
+ xexit(*av, 1);
+ }
arg2:
foundeof = *eofstr != '\0' &&
- strcmp(argp, eofstr) == 0;
+ strncmp(argp, eofstr, p - argp) == 0;
#ifdef __APPLE__
/* 6591323: -I specifies that it processes the entire line,
*/
inpline = realloc(inpline, curlen + 2 +
strlen(argp));
- if (inpline == NULL)
- errx(1, "realloc failed");
+ if (inpline == NULL) {
+ warnx("realloc failed");
+ xexit(*av, 1);
+ }
if (curlen == 1)
strcpy(inpline, argp);
else
*/
if (xp == endxp || p + (count * pad9314053) > ebp || ch == EOF ||
(Lflag <= count && xflag) || foundeof) {
- if (xflag && xp != endxp && p + (count * pad9314053) > ebp)
- errx(1, "insufficient space for arguments");
+ if (xflag && xp != endxp && p + (count * pad9314053) > ebp) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
if (jfound) {
for (avj = argv; *avj; avj++)
*xp++ = *avj;
}
prerun(argc, av);
- if (ch == EOF || foundeof) {
- waitchildren(*argv, 1);
- exit(rval);
- }
+ if (ch == EOF || foundeof)
+ xexit(*av, rval);
p = bbp;
xp = bxp;
count = 0;
if (zflag)
goto addch;
/* Backslash escapes anything, is escaped by quotes. */
- if (!insingle && !indouble && (ch = getchar()) == EOF)
- errx(1, "backslash at EOF");
+ if (!insingle && !indouble && (ch = getchar()) == EOF) {
+ warnx("backslash at EOF");
+ xexit(*av, 1);
+ }
/* FALLTHROUGH */
default:
addch: if (p < ebp) {
}
/* If only one argument, not enough buffer space. */
- if (bxp == xp)
- errx(1, "insufficient space for argument");
+ if (bxp == xp) {
+ warnx("insufficient space for argument");
+ xexit(*av, 1);
+ }
/* Didn't hit argument limit, so if xflag object. */
- if (xflag)
- errx(1, "insufficient space for arguments");
+ if (xflag) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
if (jfound) {
for (avj = argv; *avj; avj++)
* 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");
+ tmp = malloc((argc + 1) * sizeof(char *));
+ if (tmp == NULL) {
+ warnx("malloc failed");
+ xexit(*argv, 1);
+ }
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");
+ if ((*tmp++ = strdup(*avj++)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
/*
* For each argument to utility, if we have not used up
while (--argc) {
*tmp = *avj++;
if (repls && strstr(*tmp, replstr) != NULL) {
- strnsubst(tmp++, replstr, inpline, (size_t)255);
+ strnsubst(tmp++, replstr, inpline, (size_t)Sflag);
if (repls > 0)
repls--;
} else {
- if ((*tmp = strdup(*tmp)) == NULL)
- errx(1, "strdup failed");
+ if ((*tmp = strdup(*tmp)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
tmp++;
}
}
}
exec:
childerr = 0;
- switch(pid = vfork()) {
+ switch (pid = vfork()) {
case -1:
- err(1, "vfork");
+ warn("vfork");
+ xexit(*argv, 1);
case 0:
if (oflag) {
if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
childerr = errno;
_exit(1);
}
- curprocs++;
+ pids_add(pid);
waitchildren(*argv, 0);
}
+/*
+ * Wait for a tracked child to exit and return its pid and exit status.
+ *
+ * Ignores (discards) all untracked child processes.
+ * Returns -1 and sets errno to ECHILD if no tracked children exist.
+ * If block is set, waits indefinitely for a child process to exit.
+ * If block is not set and no children have exited, returns 0 immediately.
+ */
+static pid_t
+xwait(int block, int *status) {
+ pid_t pid;
+
+ if (pids_empty()) {
+ errno = ECHILD;
+ return (-1);
+ }
+
+ while ((pid = waitpid(-1, status, block ? 0 : WNOHANG)) > 0)
+ if (pids_remove(pid))
+ break;
+
+ return (pid);
+}
+
+static void
+xexit(const char *name, const int exit_code) {
+ waitchildren(name, 1);
+ exit(exit_code);
+}
+
static void
waitchildren(const char *name, int waitall)
{
pid_t pid;
int status;
+ int cause_exit = 0;
- 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);
- }
+ while ((pid = xwait(waitall || pids_full(), &status)) > 0) {
/*
- * If utility signaled or exited with a value of 255,
- * exit 1-125.
+ * If we couldn't invoke the utility or if utility exited
+ * because of a signal or with a value of 255, warn (per
+ * POSIX), and then wait until all other children have
+ * exited before exiting 1-125. POSIX requires us to stop
+ * reading if child exits because of a signal or with 255,
+ * but it does not require us to exit immediately; waiting
+ * is preferable to orphaning.
*/
- if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
- exit(1);
- if (WEXITSTATUS(status))
- rval = 1;
+ if (childerr != 0 && cause_exit == 0) {
+ errno = childerr;
+ waitall = 1;
+ cause_exit = errno == ENOENT ? 127 : 126;
+ warn("%s", name);
+ } else if (WIFSIGNALED(status)) {
+ waitall = cause_exit = 1;
+ warnx("%s: terminated with signal %d; aborting",
+ name, WTERMSIG(status));
+ } else if (WEXITSTATUS(status) == 255) {
+ waitall = cause_exit = 1;
+ warnx("%s: exited with status 255; aborting", name);
+ } else if (WEXITSTATUS(status))
+ rval = 1;
}
+
+ if (cause_exit)
+ exit(cause_exit);
if (pid == -1 && errno != ECHILD)
- err(1, "wait3");
+ err(1, "waitpid");
+}
+
+#define NOPID (0)
+
+static void
+pids_init(void)
+{
+ int i;
+
+ if ((childpids = malloc(maxprocs * sizeof(*childpids))) == NULL)
+ errx(1, "malloc failed");
+
+ for (i = 0; i < maxprocs; i++)
+ clearslot(i);
+}
+
+static int
+pids_empty(void)
+{
+
+ return (curprocs == 0);
+}
+
+static int
+pids_full(void)
+{
+
+ return (curprocs >= maxprocs);
+}
+
+static void
+pids_add(pid_t pid)
+{
+ int slot;
+
+ slot = findfreeslot();
+ childpids[slot] = pid;
+ curprocs++;
+}
+
+static int
+pids_remove(pid_t pid)
+{
+ int slot;
+
+ if ((slot = findslot(pid)) < 0)
+ return (0);
+
+ clearslot(slot);
+ curprocs--;
+ return (1);
+}
+
+static int
+findfreeslot(void)
+{
+ int slot;
+
+ if ((slot = findslot(NOPID)) < 0)
+ errx(1, "internal error: no free pid slot");
+ return (slot);
+}
+
+static int
+findslot(pid_t pid)
+{
+ int slot;
+
+ for (slot = 0; slot < maxprocs; slot++)
+ if (childpids[slot] == pid)
+ return (slot);
+ return (-1);
+}
+
+static void
+clearslot(int slot)
+{
+
+ childpids[slot] = NOPID;
}
/*
(void)fclose(ttyfp);
return (0);
}
+ response[rsize - 1] = '\0';
match = regexec(&cre, response, 0, NULL, 0);
(void)fclose(ttyfp);
regfree(&cre);
static void
usage(void)
{
+
fprintf(stderr,
-"usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
-" [-L number] [-n number [-x]] [-P maxprocs] [-s size]\n"
-" [utility [argument ...]]\n");
+"usage: xargs [-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");
exit(1);
}
done
set -x
+install -d -o root -g wheel -m 0755 "$DSTROOT"/AppleInternal/Tests/shell_cmds
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/regress.m4 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+install -o root -g wheel -m 0644 "$SRCROOT"/time/tests/test_time.sh \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/shell_cmds.plist \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+
# Skip locate and su targets for iOS
if [ "$TARGET_NAME" = "All_iOS" ]; then
exit 0
install -d -o root -g wheel -m 0755 "$PAMDIR"
install -c -o root -g wheel -m 0644 "$SRCROOT"/su/su.pam "$PAMDIR"/su
-
-install -d -o root -g wheel -m 0755 "$DSTROOT"/AppleInternal/Tests/shell_cmds
-install -o root -g wheel -m 0644 "$SRCROOT"/tests/regress.m4 "$DSTROOT"/AppleInternal/Tests/shell_cmds
-
-install -d -o root -g wheel -m 0755 "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
-install -o root -g wheel -m 0644 "$SRCROOT"/tests/shell_cmds.plist "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests