Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Dec 2014 16:26:20 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r275766 - in head/bin/sh: . tests/execution
Message-ID:  <201412141626.sBEGQKHt065965@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Sun Dec 14 16:26:19 2014
New Revision: 275766
URL: https://svnweb.freebsd.org/changeset/base/275766

Log:
  sh: Make sure output suitable as shell input is also printable.
  
  Commands like 'export -p', 'set' and 'trap', and tracing enabled via 'set
  -x' generate output suitable as shell input by adding quotes as necessary.
  
  If there are control characters other than newline or invalid UTF-8
  sequences, use $'...' and \OOO to display them safely.
  
  The resulting output is not parsable by a strict POSIX.1-2008 shell but sh
  from FreeBSD 9.0 and newer and many other shells can parse it.

Added:
  head/bin/sh/tests/execution/set-x4.0   (contents, props changed)
Modified:
  head/bin/sh/output.c
  head/bin/sh/tests/execution/Makefile

Modified: head/bin/sh/output.c
==============================================================================
--- head/bin/sh/output.c	Sun Dec 14 16:17:48 2014	(r275765)
+++ head/bin/sh/output.c	Sun Dec 14 16:26:19 2014	(r275766)
@@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
 
 #include "shell.h"
 #include "syntax.h"
@@ -111,42 +113,86 @@ outstr(const char *p, struct output *fil
 	outbin(p, strlen(p), file);
 }
 
+static void
+byteseq(int ch, struct output *file)
+{
+	char seq[4];
+
+	seq[0] = '\\';
+	seq[1] = (ch >> 6 & 0x3) + '0';
+	seq[2] = (ch >> 3 & 0x7) + '0';
+	seq[3] = (ch & 0x7) + '0';
+	outbin(seq, 4, file);
+}
+
+static void
+outdqstr(const char *p, struct output *file)
+{
+	const char *end;
+	mbstate_t mbs;
+	size_t clen;
+	wchar_t wc;
+
+	memset(&mbs, '\0', sizeof(mbs));
+	end = p + strlen(p);
+	outstr("$'", file);
+	while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) {
+		if (clen == (size_t)-2) {
+			while (p < end)
+				byteseq(*p++, file);
+			break;
+		}
+		if (clen == (size_t)-1) {
+			memset(&mbs, '\0', sizeof(mbs));
+			byteseq(*p++, file);
+			continue;
+		}
+		if (wc == L'\n')
+			outcslow('\n', file), p++;
+		else if (wc == L'\r')
+			outstr("\\r", file), p++;
+		else if (wc == L'\t')
+			outstr("\\t", file), p++;
+		else if (!iswprint(wc)) {
+			for (; clen > 0; clen--)
+				byteseq(*p++, file);
+		} else {
+			if (wc == L'\'' || wc == L'\\')
+				outcslow('\\', file);
+			outbin(p, clen, file);
+			p += clen;
+		}
+	}
+	outcslow('\'', file);
+}
+
 /* Like outstr(), but quote for re-input into the shell. */
 void
 outqstr(const char *p, struct output *file)
 {
-	char ch;
-	int inquotes;
+	int i;
 
 	if (p[0] == '\0') {
 		outstr("''", file);
 		return;
 	}
-	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#=")] == '\0' ||
+	for (i = 0; p[i] != '\0'; i++) {
+		if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') ||
+		    (p[i] & 0x80) != 0 || p[i] == '\'') {
+			outdqstr(p, file);
+			return;
+		}
+	}
+
+	if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
 			strcmp(p, "[") == 0) {
 		outstr(p, file);
 		return;
 	}
 
-	inquotes = 0;
-	while ((ch = *p++) != '\0') {
-		switch (ch) {
-		case '\'':
-			/* Can't quote single quotes inside single quotes. */
-			if (inquotes)
-				outcslow('\'', file);
-			inquotes = 0;
-			outstr("\\'", file);
-			break;
-		default:
-			if (!inquotes)
-				outcslow('\'', file);
-			inquotes = 1;
-			outc(ch, file);
-		}
-	}
-	if (inquotes)
-		outcslow('\'', file);
+	outcslow('\'', file);
+	outstr(p, file);
+	outcslow('\'', file);
 }
 
 void

Modified: head/bin/sh/tests/execution/Makefile
==============================================================================
--- head/bin/sh/tests/execution/Makefile	Sun Dec 14 16:17:48 2014	(r275765)
+++ head/bin/sh/tests/execution/Makefile	Sun Dec 14 16:26:19 2014	(r275766)
@@ -44,6 +44,7 @@ FILES+=		set-n4.0
 FILES+=		set-x1.0
 FILES+=		set-x2.0
 FILES+=		set-x3.0
+FILES+=		set-x4.0
 FILES+=		shellproc1.0
 FILES+=		subshell1.0 subshell1.0.stdout
 FILES+=		subshell2.0

Added: head/bin/sh/tests/execution/set-x4.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/execution/set-x4.0	Sun Dec 14 16:26:19 2014	(r275766)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+key=`printf '\r\t\001\200\300'`
+r=`{ set -x; : "$key"; } 2>&1 >/dev/null`
+case $r in
+*[![:print:]]*) echo fail; exit 3
+esac



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