From 47d9aef863d2b1c3e210a0137c855acd0210a43f Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 4 Aug 2020 19:31:37 +0000 Subject: [PATCH] shell_cmds-216.40.4.tar.gz --- .upstream_base_commits | 4 + echo/echo.c | 185 +++++++++------- kill/kill.c | 27 ++- printf/printf.1 | 64 ++++-- printf/printf.c | 41 ++-- printf/printf.plist.part | 9 +- printf/tests/Makefile | 3 +- printf/tests/Makefile.depend | 2 +- printf/tests/legacy_test.sh | 2 +- printf/tests/regress.bwidth.out | 1 + printf/tests/regress.sh | 7 +- shell_cmds.xcodeproj/project.pbxproj | 32 ++- su/su_entitlements.plist | 2 + tests/shell_cmds.plist | 22 +- time/tests/test_time.sh | 60 ++++++ time/time.1 | 4 - time/time.c | 189 ++++++++++------ xargs/pathnames.h | 10 +- xargs/strnsubst.c | 14 +- xargs/xargs.1 | 82 +++++-- xargs/xargs.c | 308 +++++++++++++++++++++------ xcodescripts/install-files.sh | 20 +- 22 files changed, 789 insertions(+), 299 deletions(-) create mode 100644 .upstream_base_commits create mode 100644 printf/tests/regress.bwidth.out create mode 100755 time/tests/test_time.sh diff --git a/.upstream_base_commits b/.upstream_base_commits new file mode 100644 index 0000000..23f2adb --- /dev/null +++ b/.upstream_base_commits @@ -0,0 +1,4 @@ +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 diff --git a/echo/echo.c b/echo/echo.c index 629e22f..6189420 100644 --- a/echo/echo.c +++ b/echo/echo.c @@ -41,97 +41,122 @@ static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93"; #include __FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $"); -#include -#include - -#include -#include -#include +#include +#include #include #include -#include +#include -/* - * 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; } diff --git a/kill/kill.c b/kill/kill.c index 258f691..bd4d908 100644 --- a/kill/kill.c +++ b/kill/kill.c @@ -62,6 +62,7 @@ static void nosig(const char *); 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 @@ -93,7 +94,7 @@ main(int argc, char *argv[]) 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); @@ -155,6 +156,23 @@ main(int argc, char *argv[]) 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) { @@ -188,11 +206,10 @@ printsignals(FILE *fp) 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); } } diff --git a/printf/printf.1 b/printf/printf.1 index 59643b5..226b87b 100644 --- a/printf/printf.1 +++ b/printf/printf.1 @@ -12,7 +12,7 @@ .\" 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. .\" @@ -29,9 +29,9 @@ .\" 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 @@ -87,8 +87,6 @@ are as follows: Write a character. .It Cm \eb Write a character. -.It Cm \ec -Ignore remaining characters in this string. .It Cm \ef Write a character. .It Cm \en @@ -289,7 +287,12 @@ The permitted escape sequences are slightly different in that 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 . @@ -313,12 +316,48 @@ Consult the 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 , @@ -340,8 +379,7 @@ It is modeled 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 @@ -361,10 +399,8 @@ and 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 diff --git a/printf/printf.c b/printf/printf.c index 438b85e..6cc09ae 100644 --- a/printf/printf.c +++ b/printf/printf.c @@ -1,4 +1,7 @@ /*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2018 Staysail Systems, Inc. * Copyright 2014 Garrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 1993 @@ -12,7 +15,7 @@ * 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. * @@ -46,7 +49,7 @@ static char const copyright[] = 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 @@ -70,20 +73,15 @@ static const char rcsid[] = #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); @@ -378,13 +376,25 @@ printf_doformat(char *fmt, int *rval) 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); @@ -394,7 +404,8 @@ printf_doformat(char *fmt, int *rval) char p; p = getchr(); - PF(start, p); + if (p != '\0') + PF(start, p); break; } case 's': { diff --git a/printf/printf.plist.part b/printf/printf.plist.part index 58f0040..a040cf7 100644 --- a/printf/printf.plist.part +++ b/printf/printf.plist.part @@ -2,15 +2,16 @@ OpenSourceProject printf OpenSourceVersion - 2015-03-01 + 2020-07-01 OpenSourceWebsiteURL - http://svnweb.freebsd.org/base/head/usr.bin/printf/ + https://github.com/freebsd/freebsd/tree/master/usr.bin/printf OpenSourceSCM - svn co http://svn.freebsd.org/base/head/usr.bin/printf/ + https://github.com/freebsd/freebsd/tree/master/usr.bin/printf OpenSourceImportDate - 2015-07-23 + 2020-07-23 OpenSourceModifications + 65959587: UNIX Conformance | /usr/bin/printf, multiple format assertion failures in VSC OpenSourceLicense bsd diff --git a/printf/tests/Makefile b/printf/tests/Makefile index 7d014a5..b4ea79b 100644 --- a/printf/tests/Makefile +++ b/printf/tests/Makefile @@ -1,10 +1,11 @@ -# $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 diff --git a/printf/tests/Makefile.depend b/printf/tests/Makefile.depend index 0fd1616..f80275d 100644 --- a/printf/tests/Makefile.depend +++ b/printf/tests/Makefile.depend @@ -1,4 +1,4 @@ -# $FreeBSD: head/usr.bin/printf/tests/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $ +# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/printf/tests/legacy_test.sh b/printf/tests/legacy_test.sh index 7b1f694..a919deb 100644 --- a/printf/tests/legacy_test.sh +++ b/printf/tests/legacy_test.sh @@ -1,5 +1,5 @@ #!/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 diff --git a/printf/tests/regress.bwidth.out b/printf/tests/regress.bwidth.out new file mode 100644 index 0000000..9e2ff61 --- /dev/null +++ b/printf/tests/regress.bwidth.out @@ -0,0 +1 @@ + a diff --git a/printf/tests/regress.sh b/printf/tests/regress.sh index 2f68c7d..a2cf5fb 100644 --- a/printf/tests/regress.sh +++ b/printf/tests/regress.sh @@ -1,10 +1,8 @@ -# $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') @@ -29,5 +27,6 @@ REGRESSION_TEST(`missingpos1', `printf "%*.*1\$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(`missingpos1', `printf "%1\$*.*2\$s" 1 1 1 2>&1') +REGRESSION_TEST(`bwidth', `printf "%8.2b" "a\nb\n"') REGRESSION_END() diff --git a/shell_cmds.xcodeproj/project.pbxproj b/shell_cmds.xcodeproj/project.pbxproj index f46f071..9a52eeb 100644 --- a/shell_cmds.xcodeproj/project.pbxproj +++ b/shell_cmds.xcodeproj/project.pbxproj @@ -1546,6 +1546,10 @@ 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 = ""; }; C686857B154725700025D623 /* systime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = systime.1; sourceTree = ""; }; + CE799E6024AD3B1B00E73238 /* test_time.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = test_time.sh; sourceTree = ""; usesTabs = 1; }; + CE799E6224B3982200E73238 /* install-files.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-files.sh"; sourceTree = ""; }; + CE799E6324B3982200E73238 /* builtins.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = builtins.txt; sourceTree = ""; }; + CE799E6424B3982200E73238 /* builtins-manpages.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "builtins-manpages.txt"; sourceTree = ""; }; FC5D636814B9808E00123E48 /* conv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv.c; sourceTree = ""; }; FC5D636914B9808E00123E48 /* display.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = display.c; sourceTree = ""; }; FC5D636A14B9808E00123E48 /* hexdump.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hexdump.1; sourceTree = ""; }; @@ -1661,7 +1665,7 @@ FCBA13FA14A141A300AA698B /* test.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test.1; sourceTree = ""; }; FCBA13FB14A141A300AA698B /* test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = ""; }; FCBA13FF14A141A300AA698B /* time.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = time.1; sourceTree = ""; }; - FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = ""; }; + FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = ""; usesTabs = 1; }; FCBA140314A141A300AA698B /* true.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = true.1; sourceTree = ""; }; FCBA140414A141A300AA698B /* true.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = true.c; sourceTree = ""; }; FCBA140814A141A300AA698B /* uname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uname.1; sourceTree = ""; }; @@ -2194,6 +2198,24 @@ path = systime; sourceTree = ""; }; + CE799E5F24AD3B1B00E73238 /* tests */ = { + isa = PBXGroup; + children = ( + CE799E6024AD3B1B00E73238 /* test_time.sh */, + ); + path = tests; + sourceTree = ""; + }; + CE799E6124B3982200E73238 /* xcodescripts */ = { + isa = PBXGroup; + children = ( + CE799E6224B3982200E73238 /* install-files.sh */, + CE799E6324B3982200E73238 /* builtins.txt */, + CE799E6424B3982200E73238 /* builtins-manpages.txt */, + ); + path = xcodescripts; + sourceTree = ""; + }; FC5D636714B9808E00123E48 /* hexdump */ = { isa = PBXGroup; children = ( @@ -2222,6 +2244,7 @@ FC80BF5514A05A2F00C6F7F5 = { isa = PBXGroup; children = ( + CE799E6124B3982200E73238 /* xcodescripts */, FD60612F1B7D2DDE004BCA6A /* xcconfigs */, FCBA134014A141A300AA698B /* alias */, FCBA134514A141A300AA698B /* apply */, @@ -2712,6 +2735,7 @@ FCBA13FD14A141A300AA698B /* time */ = { isa = PBXGroup; children = ( + CE799E5F24AD3B1B00E73238 /* tests */, FCBA13FF14A141A300AA698B /* time.1 */, FCBA140014A141A300AA698B /* time.c */, ); @@ -3906,7 +3930,7 @@ ); 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 */ = { @@ -3921,7 +3945,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh"; + shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n"; showEnvVarsInLog = 0; }; FD6060EF1B7C0590004BCA6A /* mkbuiltins */ = { @@ -3959,7 +3983,7 @@ ); 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; diff --git a/su/su_entitlements.plist b/su/su_entitlements.plist index a9f77f2..a96cb44 100644 --- a/su/su_entitlements.plist +++ b/su/su_entitlements.plist @@ -2,6 +2,8 @@ + com.apple.keystore.console + com.apple.private.security.clear-library-validation diff --git a/tests/shell_cmds.plist b/tests/shell_cmds.plist index 3794d3d..bdeb182 100644 --- a/tests/shell_cmds.plist +++ b/tests/shell_cmds.plist @@ -12,10 +12,8 @@ /bin/sh /AppleInternal/Tests/shell_cmds/printf/legacy_test.sh - IgnoreOutput - - TestName - shell_cmds: printf + IgnoreOutput + TestNameshell_cmds.printf WhenToRun PRESUBMISSION @@ -28,8 +26,20 @@ /bin/sh /AppleInternal/Tests/shell_cmds/test/legacy_test.sh - TestName - shell_cmds: test + TestNameshell_cmds.test + WhenToRun + + PRESUBMISSION + NIGHTLY + + + + Command + + /bin/sh + /AppleInternal/Tests/shell_cmds/time/test_time.sh + + TestNameshell_cmds.time WhenToRun PRESUBMISSION diff --git a/time/tests/test_time.sh b/time/tests/test_time.sh new file mode 100755 index 0000000..6cf002d --- /dev/null +++ b/time/tests/test_time.sh @@ -0,0 +1,60 @@ +#!/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 diff --git a/time/time.1 b/time/time.1 index 8c4ca8c..b4e7017 100644 --- a/time/time.1 +++ b/time/time.1 @@ -114,7 +114,3 @@ The .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. diff --git a/time/time.c b/time/time.c index 0a3cb47..afaaed0 100644 --- a/time/time.c +++ b/time/time.c @@ -33,52 +33,48 @@ * SUCH DAMAGE. */ +#include +#include +#include +#include +#include +#include #include -#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 #include #include #include #include #include +#include #include +#include #include +#include #include -#include -#include -#include 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; @@ -88,37 +84,88 @@ main(argc, argv) break; case '?': default: - fprintf(stderr, "usage: time [-lp] command.\n"); + fprintf(stderr, "usage: time [-lp] \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); @@ -126,15 +173,15 @@ main(argc, argv) 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", @@ -142,41 +189,57 @@ main(argc, argv) } 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); } diff --git a/xargs/pathnames.h b/xargs/pathnames.h index 3f05b3d..45c0fff 100644 --- a/xargs/pathnames.h +++ b/xargs/pathnames.h @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -10,11 +12,7 @@ * 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. * @@ -30,6 +28,8 @@ * 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 */ diff --git a/xargs/strnsubst.c b/xargs/strnsubst.c index 4b3f9b6..b00b319 100644 --- a/xargs/strnsubst.c +++ b/xargs/strnsubst.c @@ -36,7 +36,19 @@ strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) 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"); diff --git a/xargs/xargs.1 b/xargs/xargs.1 index 90551f9..b9d5add 100644 --- a/xargs/xargs.1 +++ b/xargs/xargs.1 @@ -13,11 +13,7 @@ .\" 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. .\" @@ -37,7 +33,7 @@ .\" $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 @@ -45,11 +41,12 @@ .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 @@ -74,8 +71,7 @@ Any arguments specified on the command line are given to 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 (``\ '\ '') @@ -115,13 +111,20 @@ 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 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 , @@ -160,8 +163,7 @@ 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 -.Pp +.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir .It Fl L Ar number Call .Ar utility @@ -211,6 +213,11 @@ Parallel mode: run at most 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. @@ -220,6 +227,34 @@ 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 +.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 @@ -227,6 +262,13 @@ 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 . @@ -272,7 +314,11 @@ cannot be invoked, an invocation of 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 @@ -314,16 +360,16 @@ utility is expected to be .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 diff --git a/xargs/xargs.c b/xargs/xargs.c index 2316012..a1ee480 100644 --- a/xargs/xargs.c +++ b/xargs/xargs.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -13,11 +15,7 @@ * 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. * @@ -48,11 +46,13 @@ static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include -__FBSDID("$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.57 2005/02/27 02:01:31 gad Exp $"); +__FBSDID("$FreeBSD$"); -#include +#include #include - +#include +#include +#include #include #include #include @@ -79,7 +79,17 @@ static int prompt(void); 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; @@ -89,9 +99,10 @@ 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, 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; @@ -104,7 +115,9 @@ main(int argc, char *argv[]) int ch, Jflag, nflag, nline; size_t nargs; size_t linelen; + struct rlimit rl; char *endptr; + const char *errstr; inpline = replstr = NULL; ep = environ; @@ -137,8 +150,8 @@ main(int argc, char *argv[]) } 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; @@ -154,7 +167,9 @@ main(int argc, char *argv[]) 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; @@ -172,8 +187,13 @@ main(int argc, char *argv[]) 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; @@ -183,8 +203,18 @@ main(int argc, char *argv[]) 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': @@ -205,8 +235,12 @@ main(int argc, char *argv[]) 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) @@ -214,13 +248,15 @@ main(int argc, char *argv[]) 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"); /* @@ -279,13 +315,11 @@ parse_input(int argc, char *argv[]) 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; @@ -323,11 +357,13 @@ parse_input(int argc, char *argv[]) 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, @@ -370,8 +406,10 @@ arg2: */ 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 @@ -388,17 +426,17 @@ arg2: */ 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; @@ -423,8 +461,10 @@ arg2: 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) { @@ -433,11 +473,15 @@ 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++) @@ -481,17 +525,21 @@ prerun(int argc, char *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"); + 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 @@ -504,12 +552,14 @@ prerun(int argc, char *argv[]) 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++; } } @@ -578,9 +628,10 @@ run(char **argv) } 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) @@ -597,35 +648,156 @@ exec: 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; } /* @@ -649,6 +821,7 @@ prompt(void) (void)fclose(ttyfp); return (0); } + response[rsize - 1] = '\0'; match = regexec(&cre, response, 0, NULL, 0); (void)fclose(ttyfp); regfree(&cre); @@ -658,9 +831,10 @@ prompt(void) 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); } diff --git a/xcodescripts/install-files.sh b/xcodescripts/install-files.sh index 11dcad9..3710fcb 100644 --- a/xcodescripts/install-files.sh +++ b/xcodescripts/install-files.sh @@ -31,6 +31,20 @@ for manpage in `cat "$SRCROOT/xcodescripts/builtins-manpages.txt"`; do 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 @@ -50,9 +64,3 @@ echo ".so man8/locate.updatedb.8" > "$MANDIR"/man8/locate.mklocatedb.8 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 -- 2.45.2