Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 May 2015 08:45:56 +0000 (UTC)
From:      Baptiste Daroussin <bapt@FreeBSD.org>
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
Message-ID:  <201505150845.t4F8juRd002806@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/capability.h>
+
 #include <err.h>
+#include <errno.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <termios.h>
 #include <unistd.h>
 #include <wchar.h>
 #include <wctype.h>
@@ -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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505150845.t4F8juRd002806>