Index: head/etc/mtree/BSD.tests.dist =================================================================== --- head/etc/mtree/BSD.tests.dist (revision 311894) +++ head/etc/mtree/BSD.tests.dist (revision 311895) @@ -1,696 +1,698 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin cat .. date .. dd .. expr .. ls .. mv .. pax .. pkill .. sh builtins .. errors .. execution .. expansion .. parameters .. parser .. set-e .. .. sleep .. test .. .. cddl lib .. sbin .. usr.bin .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. .. zfsd .. .. .. etc rc.d .. .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. libarchive .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libmp .. libnv .. libpam .. libproc .. librt .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-sh .. .. rtld-elf .. .. sbin dhclient .. devd .. growfs .. ifconfig .. mdconfig .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. plain .. .. .. .. sys acl .. aio .. fifo .. file .. fs tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. nop .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. portacl .. .. mqueue .. netinet .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. .. posixshm .. sys .. vfs .. vm .. .. usr.bin apply .. basename .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. cpio .. col .. comm .. cut .. dirname .. file2c .. grep .. gzip .. ident .. join .. jot .. lastcomm .. limits .. m4 .. mkimg .. ncal .. opensm .. printf .. sdiff .. sed regress.multitest.out .. .. soelim .. + tail + .. tar .. timeout .. tr .. truncate .. units .. uudecode .. uuencode .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. etcupdate .. extattr .. fstyp .. makefs .. newsyslog .. nmtree .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: Index: head/usr.bin/tail/Makefile =================================================================== --- head/usr.bin/tail/Makefile (revision 311894) +++ head/usr.bin/tail/Makefile (revision 311895) @@ -1,7 +1,13 @@ # $FreeBSD$ # @(#)Makefile 8.1 (Berkeley) 6/6/93 +.include + PROG= tail SRCS= forward.c misc.c read.c reverse.c tail.c + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif .include Index: head/usr.bin/tail/reverse.c =================================================================== --- head/usr.bin/tail/reverse.c (revision 311894) +++ head/usr.bin/tail/reverse.c (revision 311895) @@ -1,291 +1,277 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Edward Sze-Tyan Wang. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include +#include #include #include #include #include #include #include #include #include #include #include #include "extern.h" static void r_buf(FILE *, const char *); static void r_reg(FILE *, const char *, enum STYLE, off_t, struct stat *); /* * reverse -- display input in reverse order by line. * * There are six separate cases for this -- regular and non-regular * files by bytes, lines or the whole file. * * BYTES display N bytes * REG mmap the file and display the lines * NOREG cyclically read characters into a wrap-around buffer * * LINES display N lines * REG mmap the file and display the lines * NOREG cyclically read lines into a wrap-around array of buffers * * FILE display the entire file * REG mmap the file and display the lines * NOREG cyclically read input into a linked list of buffers */ void reverse(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp) { if (style != REVERSE && off == 0) return; if (S_ISREG(sbp->st_mode)) r_reg(fp, fn, style, off, sbp); else switch(style) { case FBYTES: case RBYTES: bytes(fp, fn, off); break; case FLINES: case RLINES: lines(fp, fn, off); break; case REVERSE: r_buf(fp, fn); break; default: break; } } /* * r_reg -- display a regular file in reverse order by line. */ static void r_reg(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp) { struct mapinfo map; off_t curoff, size, lineend; int i; if (!(size = sbp->st_size)) return; map.start = NULL; map.mapoff = map.maxoff = size; map.fd = fileno(fp); map.maplen = 0; /* * Last char is special, ignore whether newline or not. Note that * size == 0 is dealt with above, and size == 1 sets curoff to -1. */ curoff = size - 2; lineend = size; while (curoff >= 0) { if (curoff < map.mapoff || curoff >= map.mapoff + (off_t)map.maplen) { if (maparound(&map, curoff) != 0) { ierr(fn); return; } } for (i = curoff - map.mapoff; i >= 0; i--) { if (style == RBYTES && --off == 0) break; if (map.start[i] == '\n') break; } /* `i' is either the map offset of a '\n', or -1. */ curoff = map.mapoff + i; if (i < 0) continue; /* Print the line and update offsets. */ if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) { ierr(fn); return; } lineend = curoff + 1; curoff--; if (style == RLINES) off--; if (off == 0 && style != REVERSE) { /* Avoid printing anything below. */ curoff = 0; break; } } if (curoff < 0 && mapprint(&map, 0, lineend) != 0) { ierr(fn); return; } if (map.start != NULL && munmap(map.start, map.maplen)) ierr(fn); } -typedef struct bf { - struct bf *next; - struct bf *prev; - int len; - char *l; -} BF; +static const size_t bsz = 128 * 1024; +typedef struct bfelem { + TAILQ_ENTRY(bfelem) entries; + size_t len; + char l[bsz]; +} bfelem_t; /* * r_buf -- display a non-regular file in reverse order by line. * * This is the function that saves the entire input, storing the data in a * doubly linked list of buffers and then displays them in reverse order. * It has the usual nastiness of trying to find the newlines, as there's no * guarantee that a newline occurs anywhere in the file, let alone in any * particular buffer. If we run out of memory, input is discarded (and the * user warned). */ static void r_buf(FILE *fp, const char *fn) { - BF *mark, *tl, *tr; - int ch, len, llen; + struct bfelem *tl, *temp, *first = NULL; + size_t len, llen; char *p; - off_t enomem; + off_t enomem = 0; + TAILQ_HEAD(bfhead, bfelem) head; - tl = NULL; -#define BSZ (128 * 1024) - for (mark = NULL, enomem = 0;;) { + TAILQ_INIT(&head); + + while (!feof(fp)) { /* * Allocate a new block and link it into place in a doubly * linked list. If out of memory, toss the LRU block and * keep going. */ - if (enomem || (tl = malloc(sizeof(BF))) == NULL || - (tl->l = malloc(BSZ)) == NULL) { - if (!mark) + while ((tl = malloc(sizeof(bfelem_t))) == NULL) { + first = TAILQ_FIRST(&head); + if (TAILQ_EMPTY(&head)) err(1, "malloc"); - if (enomem) - tl = tl->next; - else { - if (tl) - free(tl); - tl = mark; - } - enomem += tl->len; - } else if (mark) { - tl->next = mark; - tl->prev = mark->prev; - mark->prev->next = tl; - mark->prev = tl; - } else { - mark = tl; - mark->next = mark->prev = mark; + enomem += first->len; + TAILQ_REMOVE(&head, first, entries); + free(first); } + TAILQ_INSERT_TAIL(&head, tl, entries); /* Fill the block with input data. */ - for (p = tl->l, len = 0; - len < BSZ && (ch = getc(fp)) != EOF; ++len) - *p++ = ch; - - if (ferror(fp)) { - ierr(fn); - return; + len = 0; + while ((!feof(fp)) && len < bsz) { + p = tl->l + len; + len += fread(p, 1, bsz - len, fp); + if (ferror(fp)) { + ierr(fn); + return; + } } - /* - * If no input data for this block and we tossed some data, - * recover it. - */ - if (!len && enomem) { - enomem -= tl->len; - tl = tl->prev; - break; - } - tl->len = len; - if (ch == EOF) - break; } if (enomem) { warnx("warning: %jd bytes discarded", (intmax_t)enomem); rval = 1; } /* - * Step through the blocks in the reverse order read. The last char - * is special, ignore whether newline or not. + * Now print the lines in reverse order + * Outline: + * Scan backward for "\n", + * print forward to the end of the buffers + * free any buffers that start after the "\n" just found + * Loop */ - for (mark = tl;;) { - for (p = tl->l + (len = tl->len) - 1, llen = 0; len--; - --p, ++llen) - if (*p == '\n') { - if (llen) { + tl = TAILQ_LAST(&head, bfhead); + first = TAILQ_FIRST(&head); + while (tl != NULL) { + for (p = tl->l + tl->len - 1, llen = 0; p >= tl->l; + --p, ++llen) { + int start = (tl == first && p == tl->l); + + if ((*p == '\n') || start) { + struct bfelem *tr; + + if (start && len) + WR(p, llen + 1); + else if (llen) WR(p + 1, llen); - llen = 0; + tr = TAILQ_NEXT(tl, entries); + llen = 0; + if (tr != NULL) { + TAILQ_FOREACH_FROM_SAFE(tr, &head, + entries, temp) { + if (tr->len) + WR(&tr->l, tr->len); + TAILQ_REMOVE(&head, tr, + entries); + free(tr); + } } - if (tl == mark) - continue; - for (tr = tl->next; tr->len; tr = tr->next) { - WR(tr->l, tr->len); - tr->len = 0; - if (tr == mark) - break; - } } + } tl->len = llen; - if ((tl = tl->prev) == mark) - break; + tl = TAILQ_PREV(tl, bfhead, entries); } - tl = tl->next; - if (tl->len) { - WR(tl->l, tl->len); - tl->len = 0; - } - while ((tl = tl->next)->len) { - WR(tl->l, tl->len); - tl->len = 0; - } + TAILQ_REMOVE(&head, first, entries); + free(first); } Index: head/usr.bin/tail/tests/Makefile =================================================================== --- head/usr.bin/tail/tests/Makefile (nonexistent) +++ head/usr.bin/tail/tests/Makefile (revision 311895) @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PACKAGE= tests + +ATF_TESTS_SH= tail_test + +.include Property changes on: head/usr.bin/tail/tests/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/tail/tests/tail_test.sh =================================================================== --- head/usr.bin/tail/tests/tail_test.sh (nonexistent) +++ head/usr.bin/tail/tests/tail_test.sh (revision 311895) @@ -0,0 +1,233 @@ +# Copyright (c) 2016 Alan Somers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +atf_test_case empty_r +empty_r_head() +{ + atf_set "descr" "Reverse an empty file" +} +empty_r_body() +{ + touch infile expectfile + tail -r infile > outfile + tail -r < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case file_r +file_r_head() +{ + atf_set "descr" "Reverse a file" +} +file_r_body() +{ + cat > infile < expectfile << HERE +This is the third line +This is the second line +This is the first line +HERE + tail -r infile > outfile + tail -r < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case file_rn2 +file_rn2_head() +{ + atf_set "descr" "Reverse the last two lines of a file" +} +file_rn2_body() +{ + cat > infile < expectfile << HERE +This is the third line +This is the second line +HERE + tail -rn2 infile > outfile + tail -rn2 < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case file_rc28 +file_rc28_head() +{ + atf_set "descr" "Reverse a file and display the last 28 characters" +} +file_rc28_body() +{ + cat > infile < expectfile << HERE +This is the third line +line +HERE + tail -rc28 infile > outfile + tail -rc28 < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case longfile_r +longfile_r_head() +{ + atf_set "descr" "Reverse a long file" +} +longfile_r_body() +{ + jot -w "%0511d" 1030 0 > infile + jot -w "%0511d" 1030 1029 0 -1 > expectfile + tail -r infile > outfile + tail -r < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case longfile_r_enomem +longfile_r_enomem_head() +{ + atf_set "descr" "Reverse a file that's too long to store in RAM" +} +longfile_r_enomem_body() +{ + # When we reverse a file that's too long for RAM, tail should drop the + # first part and just print what it can. We'll check that the last + # part is ok + { + ulimit -v 32768 || atf_skip "Can't adjust ulimit" + jot -w "%01023d" 32768 0 | tail -r > outfile ; + } + if [ "$?" -ne 1 ]; then + atf_skip "Didn't get ENOMEM. Adjust test parameters" + fi + # We don't know how much of the input we dropped. So just check that + # the first ten lines of tail's output are the same as the last ten of + # the input + jot -w "%01023d" 10 32767 0 -1 > expectfile + head -n 10 outfile > outtrunc + diff expectfile outtrunc + atf_check cmp expectfile outtrunc +} + +atf_test_case longfile_r_longlines +longfile_r_longlines_head() +{ + atf_set "descr" "Reverse a long file with extremely long lines" +} +longfile_r_longlines_body() +{ + jot -s " " -w "%07d" 18000 0 > infile + jot -s " " -w "%07d" 18000 18000 >> infile + jot -s " " -w "%07d" 18000 36000 >> infile + jot -s " " -w "%07d" 18000 36000 > expectfile + jot -s " " -w "%07d" 18000 18000 >> expectfile + jot -s " " -w "%07d" 18000 0 >> expectfile + tail -r infile > outfile + tail -r < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case longfile_rc135782 +longfile_rc135782_head() +{ + atf_set "descr" "Reverse a long file and print the last 135,782 bytes" +} +longfile_rc135782_body() +{ + jot -w "%063d" 9000 0 > infile + jot -w "%063d" 2121 8999 0 -1 > expectfile + echo "0000000000000000000000000000000006878" >> expectfile + tail -rc135782 infile > outfile + tail -rc135782 < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case longfile_rc145782_longlines +longfile_rc145782_longlines_head() +{ + atf_set "descr" "Reverse a long file with extremely long lines and print the last 145,782 bytes" +} +longfile_rc145782_longlines_body() +{ + jot -s " " -w "%07d" 18000 0 > infile + jot -s " " -w "%07d" 18000 18000 >> infile + jot -s " " -w "%07d" 18000 36000 >> infile + jot -s " " -w "%07d" 18000 36000 > expectfile + echo -n "35777 " >> expectfile + jot -s " " -w "%07d" 222 35778 >> expectfile + tail -rc145782 infile > outfile + tail -rc145782 < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + +atf_test_case longfile_rn2500 +longfile_rn2500_head() +{ + atf_set "descr" "Reverse a long file and print the last 2,500 lines" +} +longfile_rn2500_body() +{ + jot -w "%063d" 9000 0 > infile + jot -w "%063d" 2500 8999 0 -1 > expectfile + tail -rn2500 infile > outfile + tail -rn2500 < infile > outpipe + atf_check cmp expectfile outfile + atf_check cmp expectfile outpipe +} + + +atf_init_test_cases() +{ + atf_add_test_case empty_r + atf_add_test_case file_r + atf_add_test_case file_rc28 + atf_add_test_case file_rn2 + # The longfile tests are designed to exercise behavior in r_buf(), + # which operates on 128KB blocks + atf_add_test_case longfile_r + atf_add_test_case longfile_r_enomem + atf_add_test_case longfile_r_longlines + atf_add_test_case longfile_rc135782 + atf_add_test_case longfile_rc145782_longlines + atf_add_test_case longfile_rn2500 +} Property changes on: head/usr.bin/tail/tests/tail_test.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property