Mercurial > illumos > git > illumos-joyent
changeset 25410:c82a295850fb
6782 head can't handle embedded nul characters
13150 head -v doesn't work with a single file
Reviewed by: Andy Fiddaman <andy@omniosce.org>
Approved by: Richard Lowe <richlowe@richlowe.net>
line wrap: on
line diff
--- a/exception_lists/copyright Tue Sep 08 09:41:54 2020 +0300 +++ b/exception_lists/copyright Sat Sep 12 15:43:24 2020 -0700 @@ -390,6 +390,8 @@ usr/src/test/util-tests/tests/dis/*/*.out usr/src/test/util-tests/tests/grep_xpg4/files/gout* usr/src/test/util-tests/tests/grep_xpg4/files/test* +usr/src/test/util-tests/tests/head/*.in +usr/src/test/util-tests/tests/head/*.out usr/src/test/util-tests/tests/libsff/*.out usr/src/test/zfs-tests/tests/functional/history/*Z usr/src/test/zfs-tests/tests/functional/history/*txt
--- a/usr/src/cmd/head/head.c Tue Sep 08 09:41:54 2020 +0300 +++ b/usr/src/cmd/head/head.c Sat Sep 12 15:43:24 2020 -0700 @@ -25,7 +25,7 @@ */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 @@ -38,6 +38,7 @@ */ /* * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright 2020 Oxide Computer Company */ @@ -47,6 +48,7 @@ #include <locale.h> #include <string.h> #include <ctype.h> +#include <err.h> #define DEF_LINE_COUNT 10 @@ -70,6 +72,7 @@ int isline = 1; int error = 0; int quiet = 0; + int verbose = 0; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ @@ -122,9 +125,11 @@ break; case 'q': quiet = 1; + verbose = 0; break; case 'v': quiet = 0; + verbose = 1; break; default: Usage(); @@ -154,8 +159,13 @@ if (around) (void) putchar('\n'); - if (fileCount > 1) - (void) printf("==> %s <==\n", argv[optind]); + if (fileCount > 1 || verbose != 0) { + const char *file = argv[optind]; + if (file == NULL) { + file = "standard input"; + } + (void) printf("==> %s <==\n", file); + } } if (argv[optind] != NULL) @@ -176,27 +186,34 @@ char lbuf[BUFSIZ]; size_t len; - while (cnt > 0 && fgets(lbuf, sizeof (lbuf), input) != 0) { - len = strlen(lbuf); + while (cnt > 0) { + len = fread(lbuf, sizeof (char), sizeof (lbuf) / sizeof (char), + input); + if (len == 0) { + return; + } + if (isline) { - (void) printf("%s", lbuf); - /* - * only count as a line if buffer read ends with newline - */ - if (len > 0) { - if (lbuf[len - 1] == '\n') { - (void) fflush(stdout); + size_t i; + for (i = 0; i < len; i++) { + if (lbuf[i] == '\n') { cnt--; + if (cnt == 0) { + i++; + break; + } } } + len = i; } else { if (len > cnt) { - lbuf[cnt] = '\0'; len = cnt; } - (void) printf("%s", lbuf); cnt -= len; - (void) fflush(stdout); + } + + if (fwrite(lbuf, sizeof (char), len, stdout) != len) { + err(EXIT_FAILURE, "failed to write to stdout"); } } }
--- a/usr/src/man/man1/head.1 Tue Sep 08 09:41:54 2020 +0300 +++ b/usr/src/man/man1/head.1 Sat Sep 12 15:43:24 2020 -0700 @@ -46,26 +46,22 @@ .\" Portions Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved .\" Portions Copyright (c) 2013, Joyent, Inc. All Rights Reserved .\" -.TH HEAD 1 "Mar 4, 2013" +.TH HEAD 1 "Sep 12, 2020" .SH NAME head \- display first few lines of files .SH SYNOPSIS .SS "/usr/bin/head" -.LP .nf -\fB/usr/bin/head\fR [\fB-q\fR] [\fB-v\fR] [\fB-number\fR ] [ \fB-n\fR \fInumber\fR ] [ \fB-c\fR \fInumber\fR] [\fIfilename\fR]... +\fB/usr/bin/head\fR [\fB-q\fR] [\fB-v\fR] [\fB-\fR\fInumber\fR ] [ \fB-n\fR \fInumber\fR ] [ \fB-c\fR \fInumber\fR] [\fIfilename\fR]... .fi .SS "ksh93" -.LP .nf \fBhead\fR [\fB-qv\fR] [\fB-n\fR \fIlines\fR] [\fB-c\fR \fIchars\fR] [\fB-s\fR \fIskip\fR] [\fIfilename\fR]... .fi .SH DESCRIPTION .SS "/usr/bin/head" -.sp -.LP The \fBhead\fR utility copies the first \fInumber\fR of lines of each \fIfilename\fR to the standard output. If no \fIfilename\fR is given, \fBhead\fR copies lines from the standard input. The default value of @@ -93,8 +89,6 @@ .sp .SS "ksh93" -.sp -.LP The \fBhead\fR built-in in \fBksh93\fR is associated with the \fB/bin\fR and \fB/usr/bin\fR paths. It is invoked when \fBhead\fR is executed without a pathname prefix and the pathname search finds a \fB/bin/head\fR or @@ -145,8 +139,6 @@ For backwards compatibility, \fB-number\fR is equivalent to \fB-n\fR number. .SH OPTIONS .SS "/usr/bin/head" -.sp -.LP The following options are supported by \fB/usr/bin/head\fR: .sp .ne 2 @@ -195,7 +187,8 @@ \fB-v\fR .ad .RS 13n -\fBhead\fR will always print a header in between each specified file. +\fBhead\fR will always print a header before each file, even if only one +file is specified. .RE .sp @@ -203,8 +196,6 @@ If no options are specified, \fBhead\fR acts as if \fB-n\fR \fB10\fR had been specified. .SS "ksh93" -.sp -.LP The following options are supported by the head built-in command in \fBksh93\fR: .sp @@ -273,8 +264,6 @@ .RE .SH OPERANDS -.sp -.LP The following operand is supported: .sp .ne 2 @@ -287,12 +276,9 @@ .RE .SH USAGE -.sp -.LP See \fBlargefile\fR(5) for the description of the behavior of \fBhead\fR when encountering files greater than or equal to 2 Gbyte ( 2^31 bytes). .SH EXAMPLES -.LP \fBExample 1 \fRWriting the First Ten Lines of All Files .sp .LP @@ -308,14 +294,10 @@ .sp .SH ENVIRONMENT VARIABLES -.sp -.LP See \fBenviron\fR(5) for descriptions of the following environment variables that affect the execution of \fBhead\fR: \fBLANG\fR, \fBLC_ALL\fR, \fBLC_CTYPE\fR, \fBLC_MESSAGES\fR, and \fBNLSPATH\fR. .SH EXIT STATUS -.sp -.LP The following exit values are returned: .sp .ne 2 @@ -336,13 +318,9 @@ .RE .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .SS "/usr/bin/head" -.sp -.sp .TS box; c | c @@ -357,9 +335,7 @@ .TE .SS "ksh93" -.sp -.sp .TS box; c | c @@ -374,7 +350,5 @@ The \fBksh93\fR built-in binding to \fB/bin\fR and \fB/usr/bin\fR is Volatile. The built-in interfaces are Uncommitted. .SH SEE ALSO -.sp -.LP \fBcat\fR(1), \fBksh93\fR(1), \fBmore\fR(1), \fBpg\fR(1), \fBtail\fR(1), \fBattributes\fR(5), \fBenviron\fR(5), \fBlargefile\fR(5), \fBstandards\fR(5)
--- a/usr/src/pkg/manifests/system-test-utiltest.mf Tue Sep 08 09:41:54 2020 +0300 +++ b/usr/src/pkg/manifests/system-test-utiltest.mf Sat Sep 12 15:43:24 2020 -0700 @@ -58,6 +58,7 @@ dir path=opt/util-tests/tests/files/make_a/c dir path=opt/util-tests/tests/files/make_l dir path=opt/util-tests/tests/find +dir path=opt/util-tests/tests/head dir path=opt/util-tests/tests/libcustr dir path=opt/util-tests/tests/libnvpair_json dir path=opt/util-tests/tests/libsff @@ -1519,6 +1520,26 @@ file path=opt/util-tests/tests/files/make_a/make.rules mode=0444 file path=opt/util-tests/tests/find/findtest mode=0555 file path=opt/util-tests/tests/grep_test mode=0555 +file path=opt/util-tests/tests/head/5221.in mode=0444 +file path=opt/util-tests/tests/head/5221.out mode=0444 +file path=opt/util-tests/tests/head/head_test mode=0555 +file path=opt/util-tests/tests/head/multi.1.out mode=0444 +file path=opt/util-tests/tests/head/multi.4.out mode=0444 +file path=opt/util-tests/tests/head/rings.1.out mode=0444 +file path=opt/util-tests/tests/head/rings.2.out mode=0444 +file path=opt/util-tests/tests/head/rings.3.out mode=0444 +file path=opt/util-tests/tests/head/rings.5.out mode=0444 +file path=opt/util-tests/tests/head/rings.in mode=0444 +file path=opt/util-tests/tests/head/stdin-nul.1.out mode=0444 +file path=opt/util-tests/tests/head/stdin-nul.2.out mode=0444 +file path=opt/util-tests/tests/head/stdin-nul.3.out mode=0444 +file path=opt/util-tests/tests/head/stdin.1.out mode=0444 +file path=opt/util-tests/tests/head/stdin.11.out mode=0444 +file path=opt/util-tests/tests/head/stdin.2.out mode=0444 +file path=opt/util-tests/tests/head/stdin.3.out mode=0444 +file path=opt/util-tests/tests/head/stdin.5.out mode=0444 +file path=opt/util-tests/tests/head/stdin.multi.out mode=0444 +file path=opt/util-tests/tests/head/stdin.nonewline.out mode=0444 file path=opt/util-tests/tests/iconv_test mode=0555 file path=opt/util-tests/tests/libcustr/custr_remove mode=0555 file path=opt/util-tests/tests/libcustr/custr_trunc mode=0555
--- a/usr/src/test/util-tests/runfiles/default.run Tue Sep 08 09:41:54 2020 +0300 +++ b/usr/src/test/util-tests/runfiles/default.run Sat Sep 12 15:43:24 2020 -0700 @@ -63,6 +63,7 @@ [/opt/util-tests/tests/date_test] [/opt/util-tests/tests/chown_test] [/opt/util-tests/tests/make_test] +[/opt/util-tests/tests/head/head_test] [/opt/util-tests/tests/demangle] tests = ['afl-fast', 'gcc-libstdc++', 'llvm-stdcxxabi']
--- a/usr/src/test/util-tests/tests/Makefile Tue Sep 08 09:41:54 2020 +0300 +++ b/usr/src/test/util-tests/tests/Makefile Sat Sep 12 15:43:24 2020 -0700 @@ -20,6 +20,6 @@ SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4 SUBDIRS += demangle mergeq workq chown ctf smbios libjedec awk make sleep -SUBDIRS += libcustr find mdb sed +SUBDIRS += libcustr find mdb sed head include $(SRC)/test/Makefile.com
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/5221.in Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,1 @@ +5221 head shouldn't reuse stdin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/5221.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,9 @@ +==> 5221.in <== +5221 head shouldn't reuse stdin + +==> /dev/stdin <== +Old +Bill Joy +Bug + +Lasts Forever
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/head_test.ksh Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,122 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +HEAD=${HEAD:=/usr/bin/head} +TMPFILE=/tmp/head_test.out.$$ +TMPINPUT=/tmp/head_test.in.$$ + +test_fail() { + echo "$*" + ((failures++)) +} + +test_one() { + typeset desc="$1" + shift + typeset input="$1" + shift + typeset output="$1" + shift + + printf "Running %s: " "$desc" + if [[ "$input" == "-" ]]; then + $HEAD $* > $TMPFILE + else + printf "$input" | $HEAD $* > $TMPFILE + fi + + if [[ $? -ne 0 ]]; then + test_fail "head exited non-zero" + return + fi + + if [[ ! -f "$output" ]]; then + test_fail "missing expeced output file $output" + return + fi + + if ! diff $output $TMPFILE >/dev/null 2>/dev/null; then + test_fail "output mismatch" + return + fi + + printf "passed\n" +} + +if ! cd $(dirname $0); then + printf "failed to reach test directory!\n" 1>&2 + exit 1 +fi + +test_one "simple stdin 1" "a\n\n\nb\n" stdin.1.out +test_one "simple stdin 2 -n 1" "a\n\n\nb\n" stdin.2.out "-n 1" +test_one "simple stdin 3 -n 3" "a\n\n\nb\n" stdin.3.out "-n 3" +test_one "simple stdin 4 -n 10000" "a\n\n\nb\n" stdin.1.out "-n 10000" +test_one "simple stdin 5 -c 1" "a\n\n\nb\n" stdin.5.out "-c 1" +test_one "simple stdin 6 -c 230" "a\n\n\nb\n" stdin.1.out "-c 230" +test_one "simple stdin 7 -n 3 -q" "a\n\n\nb\n" stdin.3.out "-n 3" "-q" +test_one "simple stdin 8 -" "a\n\n\nb\n" stdin.2.out "-1" +test_one "simple stdin 9 -23" "a\n\n\nb\n" stdin.1.out "-23" +test_one "simple stdin 10 -q" "a\n\n\nb\n" stdin.1.out "-q" +# +# Note, different implementations have different behaviours when -v is specified +# and there is only standard input. This verifies our current choice. +# +test_one "simple stdin 11 -v" "a\n\n\nb\n" stdin.11.out "-v" +test_one "stdin nul 1" "hello\0regression\n" stdin-nul.1.out +test_one "stdin nul 2 -c 1" "hello\0regression\n" stdin-nul.2.out "-c 1" +test_one "stdin nul 3" "this\0\nwas\0an\0\n\nunfortunate\0buf\0\n" \ + stdin-nul.3.out + +test_one "5221 regression" "Old\nBill Joy\nBug\n\nLasts Forever\n" 5221.out \ + 5221.in /dev/stdin +test_one "/dev/stdin repeated" "Hello\n" stdin.multi.out /dev/stdin /dev/stdin +test_one "no newline -n 3" "Why do you need newlines?" stdin.nonewline.out \ + "-n 3" + +test_one "simple file 1" - rings.1.out rings.in +test_one "simple file 2 -c 30" - rings.2.out "-c 30" rings.in +test_one "simple file 3 -n 7" - rings.3.out "-n 7" rings.in +test_one "simple file 4 -50" - rings.in "-50" rings.in +test_one "simple file 5 -v" - rings.5.out "-v" rings.in +test_one "multi file 1 -n 5 -q" - multi.1.out "-n 5" "-q" rings.in \ + rings.in rings.in +test_one "multi file 2 -n 5 -q -v" - multi.1.out "-n 5" "-q" "-v" "-q" \ + rings.in rings.in rings.in +test_one "multi file 3 -n 5 -q -v -q" - multi.1.out "-n 5" "-q" "-v" "-q" \ + rings.in rings.in rings.in +test_one "multi file 4 -c 100" - multi.4.out "-c 100" rings.in rings.in + +# +# Construct a file larger than 8k in size without a new line to verify that we +# will do multiple reads beyond the first. +# +rm -f $TMPINPUT +for ((i = 0; i < 10000; i++)); do + printf "Lorem ipsum" >> $TMPINPUT +done +test_one "large input" - $TMPINPUT $TMPINPUT + +rm $TMPFILE $TMPINPUT + +if [[ "$failures" -ne 0 ]]; then + printf "%u tests failed\n" "$failures" 2>&1 + exit 1 +fi + +printf "All tests passed successfully\n" +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/multi.1.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,15 @@ + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/multi.4.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,10 @@ +==> rings.in <== + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone +==> rings.in <== + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/rings.1.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,10 @@ + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + One for the Dark Lord on his dark throne, +In the Land of Mordor where the Shadows lie, + One Ring to rule them all, one Ring to find them, + One Ring to bring them all and in the darkness bind them +In the Land of Mordor where the Shadows lie
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/rings.2.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,3 @@ + + +Three Rings for the Elven-ki \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/rings.3.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,7 @@ + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + One for the Dark Lord on his dark throne, +In the Land of Mordor where the Shadows lie,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/rings.5.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,11 @@ +==> rings.in <== + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + One for the Dark Lord on his dark throne, +In the Land of Mordor where the Shadows lie, + One Ring to rule them all, one Ring to find them, + One Ring to bring them all and in the darkness bind them +In the Land of Mordor where the Shadows lie
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/rings.in Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,13 @@ + + +Three Rings for the Elven-kings under the sky, + Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, + One for the Dark Lord on his dark throne, +In the Land of Mordor where the Shadows lie, + One Ring to rule them all, one Ring to find them, + One Ring to bring them all and in the darkness bind them +In the Land of Mordor where the Shadows lie + + +- J.R.R. Tolkien, The Lord of the Rings, Epigraph
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin-nul.2.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,1 @@ +h \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin.1.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,4 @@ +a + + +b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin.11.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,5 @@ +==> standard input <== +a + + +b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin.2.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,1 @@ +a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin.3.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,3 @@ +a + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/util-tests/tests/head/stdin.5.out Sat Sep 12 15:43:24 2020 -0700 @@ -0,0 +1,1 @@ +a \ No newline at end of file