From owner-svn-src-stable@FreeBSD.ORG Fri May 15 08:45:57 2015 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id D5E862F5; Fri, 15 May 2015 08:45:56 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C33301C43; Fri, 15 May 2015 08:45:56 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t4F8juqP002809; Fri, 15 May 2015 08:45:56 GMT (envelope-from bapt@FreeBSD.org) Received: (from bapt@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t4F8juRd002806; Fri, 15 May 2015 08:45:56 GMT (envelope-from bapt@FreeBSD.org) Message-Id: <201505150845.t4F8juRd002806@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: bapt set sender to bapt@FreeBSD.org using -f From: Baptiste Daroussin Date: Fri, 15 May 2015 08:45:56 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r282949 - stable/10/usr.bin/col X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 May 2015 08:45:57 -0000 Author: bapt Date: Fri May 15 08:45:55 2015 New Revision: 282949 URL: https://svnweb.freebsd.org/changeset/base/282949 Log: MFC: r282305, r282309, r282342, r282669, r282722 r282305: col: fixing 25 year old bug Makes col(1) respect POSIX again for escape sequences as decribed in its manpage The bug was introduced in CSRG in 1990 r282309: Use defines to improve clarity r282342: Capsicumize col(1) r282669: Fix about ten integer overflows and underflows and a handful of logic errors in line number handling. Submitted by: schwarze at OpenBSD Discussed with: schwarze at OpenBSD Obtained from: OpenBSD r282722: For half and reverse line feeds, recognize both SUSv2-style escape-digit and BSD-style escape-control-char sequences in the input stream. Submitted by: schwarze at OpenBSD Discussed with: schwarze at OpenBSD Obtained from: OpenBSD Modified: stable/10/usr.bin/col/col.1 stable/10/usr.bin/col/col.c Modified: stable/10/usr.bin/col/col.1 ============================================================================== --- stable/10/usr.bin/col/col.1 Fri May 15 08:40:17 2015 (r282948) +++ stable/10/usr.bin/col/col.1 Fri May 15 08:45:55 2015 (r282949) @@ -31,7 +31,7 @@ .\" @(#)col.1 8.1 (Berkeley) 6/29/93 .\" $FreeBSD$ .\" -.Dd August 4, 2004 +.Dd May 10, 2015 .Dt COL 1 .Os .Sh NAME @@ -82,18 +82,33 @@ recognized and interpreted by itself, wh Output multiple spaces instead of tabs. .El .Pp -The control sequences for carriage motion that +In the input stream, .Nm -understands and their decimal values are listed in the following -table: +understands both the escape sequences of the form escape-digit +mandated by +.St -susv2 +and the traditional +.Bx +format escape-control-character. +The control sequences for carriage motion and their ASCII values +are as follows: .Pp .Bl -tag -width "carriage return" -compact +.It ESC\-BELL +reverse line feed (escape then bell). .It ESC\-7 -reverse line feed (escape then 7) +reverse line feed (escape then 7). +.It ESC\-BACKSPACE +half reverse line feed (escape then backspace). .It ESC\-8 -half reverse line feed (escape then 8) +half reverse line feed (escape then 8). +.It ESC\-TAB +half forward line feed (escape than tab). .It ESC\-9 -half forward line feed (escape then 9) +half forward line feed (escape then 9). +In +.Fl f +mode, this sequence may also occur in the output stream. .It backspace moves back one column (8); ignored in the first column .It carriage return Modified: stable/10/usr.bin/col/col.c ============================================================================== --- stable/10/usr.bin/col/col.c Fri May 15 08:40:17 2015 (r282948) +++ stable/10/usr.bin/col/col.c Fri May 15 08:45:55 2015 (r282949) @@ -45,11 +45,15 @@ static char sccsid[] = "@(#)col.c 8.5 (B #include __FBSDID("$FreeBSD$"); +#include + #include +#include #include #include #include #include +#include #include #include #include @@ -63,9 +67,9 @@ __FBSDID("$FreeBSD$"); #define SI '\017' /* shift in to normal character set */ #define SO '\016' /* shift out to alternate character set */ #define VT '\013' /* vertical tab (aka reverse line feed) */ -#define RLF '\007' /* ESC-07 reverse line feed */ -#define RHLF '\010' /* ESC-010 reverse half-line feed */ -#define FHLF '\011' /* ESC-011 forward half-line feed */ +#define RLF '7' /* ESC-7 reverse line feed */ +#define RHLF '8' /* ESC-8 reverse half-line feed */ +#define FHLF '9' /* ESC-9 forward half-line feed */ /* build up at least this many lines before flushing them out */ #define BUFFER_MARGIN 32 @@ -92,6 +96,7 @@ struct line_str { int l_max_col; /* max column in the line */ }; +static void addto_lineno(int *, int); static LINE *alloc_line(void); static void dowarn(int); static void flush_line(LINE *); @@ -104,7 +109,7 @@ static CSET last_set; /* char_set of la static LINE *lines; static int compress_spaces; /* if doing space -> tab conversion */ static int fine; /* if `fine' resolution (half lines) */ -static int max_bufd_lines; /* max # lines to keep in memory */ +static int max_bufd_lines; /* max # of half lines to keep in memory */ static int nblank_lines; /* # blanks after last flushed line */ static int no_backspaces; /* if not to output any backspaces */ static int pass_unknown_seqs; /* pass unknown control sequences */ @@ -129,10 +134,26 @@ main(int argc, char **argv) int this_line; /* line l points to */ int nflushd_lines; /* number of lines that were flushed */ int adjust, opt, warned, width; + const char *errstr; + cap_rights_t rights; + unsigned long cmd; (void)setlocale(LC_CTYPE, ""); - max_bufd_lines = 128; + cap_rights_init(&rights, CAP_FSTAT, CAP_READ); + if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) + err(1, "unable to limit rights for stdin"); + cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE, CAP_IOCTL); + if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) + err(1, "unable to limit rights for stdout"); + cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ + if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) + err(1, "unable to limit ioctls for stdout"); + + if (cap_enter() < 0 && errno != ENOSYS) + err(1, "unable to enter capability mode"); + + max_bufd_lines = 256; compress_spaces = 1; /* compress spaces into tabs */ while ((opt = getopt(argc, argv, "bfhl:px")) != -1) switch (opt) { @@ -146,8 +167,11 @@ main(int argc, char **argv) compress_spaces = 1; break; case 'l': /* buffered line count */ - if ((max_bufd_lines = atoi(optarg)) <= 0) - errx(1, "bad -l argument %s", optarg); + max_bufd_lines = strtonum(optarg, 1, + (INT_MAX - BUFFER_MARGIN) / 2, &errstr) * 2; + if (errstr != NULL) + errx(1, "bad -l argument, %s: %s", errstr, + optarg); break; case 'p': /* pass unknown control sequences */ pass_unknown_seqs = 1; @@ -163,9 +187,6 @@ main(int argc, char **argv) if (optind != argc) usage(); - /* this value is in half lines */ - max_bufd_lines *= 2; - adjust = cur_col = extra_lines = warned = 0; cur_line = max_line = nflushd_lines = this_line = 0; cur_set = last_set = CS_NORMAL; @@ -184,20 +205,31 @@ main(int argc, char **argv) continue; case ESC: /* just ignore EOF */ switch(getwchar()) { + /* + * In the input stream, accept both the + * XPG5 sequences ESC-digit and the + * traditional BSD sequences ESC-ctrl. + */ + case '\007': + /* FALLTHROUGH */ case RLF: - cur_line -= 2; + addto_lineno(&cur_line, -2); break; + case '\010': + /* FALLTHROUGH */ case RHLF: - cur_line--; + addto_lineno(&cur_line, -1); break; + case '\011': + /* FALLTHROUGH */ case FHLF: - cur_line++; + addto_lineno(&cur_line, 1); if (cur_line > max_line) max_line = cur_line; } continue; case NL: - cur_line += 2; + addto_lineno(&cur_line, 2); if (cur_line > max_line) max_line = cur_line; cur_col = 0; @@ -216,7 +248,7 @@ main(int argc, char **argv) ++cur_col; continue; case VT: - cur_line -= 2; + addto_lineno(&cur_line, -2); continue; } if (iswspace(ch)) { @@ -229,58 +261,61 @@ main(int argc, char **argv) } /* Must stuff ch in a line - are we at the right one? */ - if (cur_line != this_line - adjust) { + if (cur_line + adjust != this_line) { LINE *lnew; - int nmove; - adjust = 0; - nmove = cur_line - this_line; - if (!fine) { - /* round up to next line */ - if (cur_line & 1) { - adjust = 1; - nmove++; - } - } - if (nmove < 0) { - for (; nmove < 0 && l->l_prev; nmove++) + /* round up to next line */ + adjust = !fine && (cur_line & 1); + + if (cur_line + adjust < this_line) { + while (cur_line + adjust < this_line && + l->l_prev != NULL) { l = l->l_prev; - if (nmove) { + this_line--; + } + if (cur_line + adjust < this_line) { if (nflushd_lines == 0) { /* * Allow backup past first * line if nothing has been * flushed yet. */ - for (; nmove < 0; nmove++) { + while (cur_line + adjust + < this_line) { lnew = alloc_line(); l->l_prev = lnew; lnew->l_next = l; l = lines = lnew; extra_lines++; + this_line--; } } else { if (!warned++) dowarn(cur_line); - cur_line -= nmove; + cur_line = this_line - adjust; } } } else { /* may need to allocate here */ - for (; nmove > 0 && l->l_next; nmove--) + while (cur_line + adjust > this_line) { + if (l->l_next == NULL) { + l->l_next = alloc_line(); + l->l_next->l_prev = l; + } l = l->l_next; - for (; nmove > 0; nmove--) { - lnew = alloc_line(); - lnew->l_prev = l; - l->l_next = lnew; - l = lnew; + this_line++; } } - this_line = cur_line + adjust; - nmove = this_line - nflushd_lines; - if (nmove >= max_bufd_lines + BUFFER_MARGIN) { - nflushd_lines += nmove - max_bufd_lines; - flush_lines(nmove - max_bufd_lines); + if (this_line > nflushd_lines && + this_line - nflushd_lines >= + max_bufd_lines + BUFFER_MARGIN) { + if (extra_lines) { + flush_lines(extra_lines); + extra_lines = 0; + } + flush_lines(this_line - nflushd_lines - + max_bufd_lines); + nflushd_lines = this_line - max_bufd_lines; } } /* grow line's buffer? */ @@ -311,25 +346,23 @@ main(int argc, char **argv) } if (ferror(stdin)) err(1, NULL); - if (max_line == 0) - exit(0); /* no lines, so just exit */ + if (extra_lines) + flush_lines(extra_lines); /* goto the last line that had a character on it */ for (; l->l_next; l = l->l_next) this_line++; - flush_lines(this_line - nflushd_lines + extra_lines + 1); + flush_lines(this_line - nflushd_lines + 1); /* make sure we leave things in a sane state */ if (last_set != CS_NORMAL) - PUTC('\017'); + PUTC(SI); /* flush out the last few blank lines */ - nblank_lines = max_line - this_line; + if (max_line > this_line) + nblank_lines = max_line - this_line; if (max_line & 1) nblank_lines++; - else if (!nblank_lines) - /* missing a \n on the last line? */ - nblank_lines = 2; flush_blanks(); exit(0); } @@ -346,7 +379,8 @@ flush_lines(int nflush) flush_blanks(); flush_line(l); } - nblank_lines++; + if (l->l_line || l->l_next) + nblank_lines++; if (l->l_line) (void)free(l->l_line); free_line(l); @@ -377,8 +411,8 @@ flush_blanks(void) for (i = nb; --i >= 0;) PUTC('\n'); if (half) { - PUTC('\033'); - PUTC('9'); + PUTC(ESC); + PUTC(FHLF); if (!nb) PUTC('\r'); } @@ -480,10 +514,10 @@ flush_line(LINE *l) if (c->c_set != last_set) { switch (c->c_set) { case CS_NORMAL: - PUTC('\017'); + PUTC(SI); break; case CS_ALTERNATE: - PUTC('\016'); + PUTC(SO); } last_set = c->c_set; } @@ -498,6 +532,23 @@ flush_line(LINE *l) } } +/* + * Increment or decrement a line number, checking for overflow. + * Stop one below INT_MAX such that the adjust variable is safe. + */ +void +addto_lineno(int *lno, int offset) +{ + if (offset > 0) { + if (*lno >= INT_MAX - offset) + errx(1, "too many lines"); + } else { + if (*lno < INT_MIN - offset) + errx(1, "too many reverse line feeds"); + } + *lno += offset; +} + #define NALLOC 64 static LINE *line_freelist;