Subject: /bin/sh fixes to make printf a builtin and 'fix' echo
To: <>
From: David Laight <david@l8s.co.uk>
List: current-users
Date: 06/11/2002 14:08:57
--IJpNTDwzlM2Ie8A6
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

> 
> >(fixed a buffer overflow problem in printf at the same time,
> >printf "%1111111111111111111111111111111111111111111111111111111111111111111111111111111111d\n" 42
> >generates a core dump.)
> 
> That's cool that it is fixed.

OK fixes are attached, summary/change comments:

bin/sh/bltin
Makefile: Make printf builtin
builtins.def: Make printf builtin
mkinit.c: Fix delta 1.14
mksyntax.c: Use bounds of CTL chars instead of naming them all
parser.h: Add defns for bounds of CTL chars
error.c: Add warnx (for builtin printf)
error.h: Add warnx (for builtin printf)
options.c: Generic code for mutually exclusive options,
	Support named options with no letter equivalent.
options.h: Make 'V' and 'E' (vi and emacs) mutually exclusive,
	Add new options '-o posix' and '-o SuS'
expand.c: Ignore options that have no single letter form when
	expanding $-

bin/sh/bltin
bltin.h: #undef stdio defs before redefining them,
	Don't define a (broken) macro version of warnx
echo.c: Make output depend on state of '-o posix' and
	'-o SuS' flags

usr.bin/printf
printf.c: Make compile as a builtin for netbsd sh.
	Stop core dump processing (very) long integer
	format strings.

	David

-- 
David Laight: david@l8s.co.uk

--IJpNTDwzlM2Ie8A6
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=sh_diffs

Index: Makefile
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/Makefile,v
retrieving revision 1.57
diff -u -u -r1.57 Makefile
--- Makefile	2002/05/15 20:45:17	1.57
+++ Makefile	2002/06/11 12:36:16
@@ -8,7 +8,7 @@
 SHSRCS=	alias.c cd.c echo.c error.c eval.c exec.c expand.c \
 	histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
 	mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
-	test.c
+	test.c printf.c
 GENSRCS=arith.c arith.h arith_lex.c builtins.c builtins.h init.c nodes.c \
 	nodes.h syntax.c syntax.h token.h
 SRCS=	${SHSRCS} ${GENSRCS}
@@ -25,7 +25,7 @@
 CPPFLAGS+=-DSMALL
 .endif
 
-.PATH:	${.CURDIR}/bltin ${.CURDIR}/../test
+.PATH:	${.CURDIR}/bltin ${.CURDIR}/../test ${.CURDIR}/../../usr.bin/printf
 
 CLEANFILES+= mkinit mknodes mksyntax
 CLEANFILES+= ${GENSRCS} y.tab.h
Index: mkinit.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/mkinit.c,v
retrieving revision 1.20
diff -u -u -r1.20 mkinit.c
--- mkinit.c	2000/07/18 19:13:20	1.20
+++ mkinit.c	2002/06/11 12:36:40
@@ -218,8 +218,6 @@
 			doinclude(line);
 		if (line[0] == 'M' && match("MKINIT", line))
 			dodecl(line, fp);
-		if (line[0] == '#' && gooddefine(line))
-			addstr(line, &defines);
 		if (line[0] == '#' && gooddefine(line)) {
 		        char *cp;
 			char line2[1024];
Index: builtins.def
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/builtins.def,v
retrieving revision 1.15
diff -u -u -r1.15 builtins.def
--- builtins.def	2000/04/09 23:27:03	1.15
+++ builtins.def	2002/06/11 12:36:41
@@ -73,7 +73,7 @@
 #linecmd		line
 localcmd	local
 #nlechocmd	nlecho
-#printfcmd	printf
+printfcmd	printf
 pwdcmd		pwd
 readcmd		read
 returncmd	return
Index: mksyntax.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/mksyntax.c,v
retrieving revision 1.25
diff -u -u -r1.25 mksyntax.c
--- mksyntax.c	2002/05/31 16:18:48	1.25
+++ mksyntax.c	2002/06/11 12:36:43
@@ -296,26 +296,15 @@
 static void
 init()
 {
+	int ctl;
+
 	filltable("CWORD");
 	syntax[0] = "CEOF";
+	for (ctl = CTL_FIRST; ctl <= CTL_LAST; ctl++ )
 #ifdef TARGET_CHAR
-	syntax[base + (TARGET_CHAR)CTLESC] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLVAR] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLENDVAR] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLBACKQ] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLBACKQ + (TARGET_CHAR)CTLQUOTE] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLARI] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLENDARI] = "CCTL";
-	syntax[base + (TARGET_CHAR)CTLQUOTEMARK] = "CCTL";
+		syntax[base + (TARGET_CHAR)ctl ] = "CCTL";
 #else
-	syntax[base + CTLESC] = "CCTL";
-	syntax[base + CTLVAR] = "CCTL";
-	syntax[base + CTLENDVAR] = "CCTL";
-	syntax[base + CTLBACKQ] = "CCTL";
-	syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
-	syntax[base + CTLARI] = "CCTL";
-	syntax[base + CTLENDARI] = "CCTL";
-	syntax[base + CTLQUOTEMARK] = "CCTL";
+		syntax[base + ctl] = "CCTL";
 #endif /* TARGET_CHAR */
 }
 
@@ -374,9 +363,9 @@
 
 static char *macro[] = {
 	"#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
-	"#define is_alpha(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))",
-	"#define is_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))",
-	"#define is_in_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))",
+	"#define is_alpha(c)\t((c) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char) (c)))",
+	"#define is_name(c)\t((c) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char) (c))))",
+	"#define is_in_name(c)\t((c) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char) (c))))",
 	"#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
 	NULL
 };
Index: parser.h
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/parser.h,v
retrieving revision 1.14
diff -u -u -r1.14 parser.h
--- parser.h	2000/07/27 04:09:28	1.14
+++ parser.h	2002/06/11 12:36:44
@@ -39,15 +39,17 @@
  */
 
 /* control characters in argument strings */
-#define CTLESC '\201'
-#define CTLVAR '\202'
+#define CTL_FIRST '\201'	/* first 'special' character */
+#define CTLESC '\201'		/* escape next character */
+#define CTLVAR '\202'		/* variable defn */
 #define CTLENDVAR '\203'
 #define CTLBACKQ '\204'
 #define CTLQUOTE 01		/* ored with CTLBACKQ code if in quotes */
 /*	CTLBACKQ | CTLQUOTE == '\205' */
-#define	CTLARI	'\206'
+#define	CTLARI	'\206'		/* arithmetic expression */
 #define	CTLENDARI '\207'
 #define	CTLQUOTEMARK '\210'
+#define	CTL_LAST '\210'		/* last 'special' character */
 
 /* variable substitution byte (follows CTLVAR) */
 #define VSTYPE	0x0f		/* type of variable substitution */
Index: error.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/error.c,v
retrieving revision 1.25
diff -u -u -r1.25 error.c
--- error.c	2002/05/25 23:09:06	1.25
+++ error.c	2002/06/11 12:42:29
@@ -123,9 +123,17 @@
 	/* NOTREACHED */
 }
 
+static void
+exvwarning( const char *msg, va_list ap )
+{
+	if (commandname)
+		outfmt(&errout, "%s: ", commandname);
+	doformat(&errout, msg, ap);
+	out2c('\n');
+}
 
 /*
- * Exverror is called to raise the error exception.  If the first argument
+ * Exverror is called to raise the error exception.  If the second argument
  * is not NULL then error prints an error message using printf style
  * formatting.  It then raises the error exception.
  */
@@ -144,12 +152,9 @@
 	else
 		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
 #endif
-	if (msg) {
-		if (commandname)
-			outfmt(&errout, "%s: ", commandname);
-		doformat(&errout, msg, ap);
-		out2c('\n');
-	}
+	if (msg)
+		exvwarning( msg, ap );
+
 	flushall();
 	exraise(cond);
 	/* NOTREACHED */
@@ -176,6 +181,16 @@
 	va_start(ap, msg);
 	exverror(cond, msg, ap);
 	/* NOTREACHED */
+	va_end(ap);
+}
+
+void
+warnx(const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	exvwarning( msg, ap);
 	va_end(ap);
 }
 
Index: error.h
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/error.h,v
retrieving revision 1.14
diff -u -u -r1.14 error.h
--- error.h	2001/02/04 19:52:06	1.14
+++ error.h	2002/06/11 12:36:46
@@ -93,6 +93,7 @@
 void onint __P((void));
 void error __P((const char *, ...)) __attribute__((__noreturn__));
 void exerror __P((int, const char *, ...)) __attribute__((__noreturn__));
+void warnx __P((const char *, ...));
 const char *errmsg __P((int, int));
 
 
Index: options.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/options.c,v
retrieving revision 1.31
diff -u -u -r1.31 options.c
--- options.c	2001/02/26 13:06:43	1.31
+++ options.c	2002/06/11 12:36:48
@@ -200,6 +200,21 @@
 	}
 }
 
+static void
+set_opt_val( int i, int val )
+{
+	int j;
+	int flag;
+
+	if (val && (flag = optlist[i].opt_set)) {
+		/* some options (eg vi/emacs) are mutually exclusive */
+		for (j = 0; j < NOPTS; j++)
+		    if (optlist[j].opt_set == flag)
+			optlist[j].val = 0;
+	}
+	optlist[i].val = val;
+}
+
 STATIC void
 minus_o(name, val)
 	char *name;
@@ -215,7 +230,7 @@
 	} else {
 		for (i = 0; i < NOPTS; i++)
 			if (equal(name, optlist[i].name)) {
-				setoption(optlist[i].letter, val);
+				set_opt_val(i, val);
 				return;
 			}
 		error("Illegal option -o %s", name);
@@ -227,19 +242,12 @@
 setoption(flag, val)
 	char flag;
 	int val;
-	{
+{
 	int i;
 
 	for (i = 0; i < NOPTS; i++)
 		if (optlist[i].letter == flag) {
-			optlist[i].val = val;
-			if (val) {
-				/* #%$ hack for ksh semantics */
-				if (flag == 'V')
-					Eflag = 0;
-				else if (flag == 'E')
-					Vflag = 0;
-			}
+			set_opt_val( i, val );
 			return;
 		}
 	error("Illegal option -%c", flag);
@@ -269,7 +277,7 @@
 void
 setparam(argv)
 	char **argv;
-	{
+{
 	char **newparam;
 	char **ap;
 	int nparam;
@@ -295,7 +303,7 @@
 void
 freeparam(param)
 	volatile struct shparam *param;
-	{
+{
 	char **ap;
 
 	if (param->malloc) {
@@ -514,7 +522,7 @@
 int
 nextopt(optstring)
 	const char *optstring;
-	{
+{
 	char *p;
 	const char *q;
 	char c;
Index: options.h
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/options.h,v
retrieving revision 1.14
diff -u -u -r1.14 options.h
--- options.h	2001/02/04 19:52:06	1.14
+++ options.h	2002/06/11 12:36:49
@@ -65,13 +65,16 @@
 #define	bflag optlist[13].val
 #define	uflag optlist[14].val
 #define	qflag optlist[15].val
+#define	posix_flag optlist[16].val	/* posix variants */
+#define	SuS_flag optlist[17].val	/* Single Unix Spec variants */
 
-#define NOPTS	16
+#define NOPTS	18
 
 struct optent {
-	const char *name;
-	const char letter;
-	char val;
+	const char *name;		/* for set -o <name> */
+	const char letter;		/* set [+/-]<letter> */
+	char val;			/* value of <letter>flag */
+	const char opt_set;		/* only one of each set may be non zero */
 };
 
 #ifdef DEFINE_OPTIONS
@@ -85,13 +88,15 @@
 	{ "stdin",	's',	0 },
 	{ "xtrace",	'x',	0 },
 	{ "verbose",	'v',	0 },
-	{ "vi",		'V',	0 },
-	{ "emacs",	'E',	0 },
+	{ "vi",		'V',	0,	'V' },
+	{ "emacs",	'E',	0,	'V' },
 	{ "noclobber",	'C',	0 },
 	{ "allexport",	'a',	0 },
 	{ "notify",	'b',	0 },
 	{ "nounset",	'u',	0 },
 	{ "quietprofile", 'q',	0 },
+	{ "posix",	0,	0,	1 },
+	{ "SuS",	0,	0,	1 },
 };
 #else
 extern struct optent optlist[NOPTS];
Index: expand.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/expand.c,v
retrieving revision 1.53
diff -u -u -r1.53 expand.c
--- expand.c	2002/05/15 14:59:21	1.53
+++ expand.c	2002/06/11 12:36:54
@@ -883,7 +883,7 @@
 		break;
 	case '-':
 		for (i = 0 ; i < NOPTS ; i++) {
-			if (optlist[i].val)
+			if (optlist[i].val && optlist[i].letter)
 				STPUTC(optlist[i].letter, expdest);
 		}
 		break;
Index: bltin.h
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/bltin/bltin.h,v
retrieving revision 1.9
diff -u -u -r1.9 bltin.h
--- bltin.h	1997/07/04 21:02:29	1.9
+++ bltin.h	2002/06/11 12:37:22
@@ -48,6 +48,10 @@
 #include "../mystring.h"
 #ifdef SHELL
 #include "../output.h"
+#undef stdout
+#undef stderr
+#undef putc
+#undef putchar
 #define stdout out1
 #define stderr out2
 #define printf out1fmt
@@ -57,11 +61,6 @@
 #define fputs outstr
 #define fflush flushout
 #define INITARGS(argv)
-#define warnx(a, b, c) {				\
-	char buf[64];					\
-	(void)snprintf(buf, sizeof(buf), a, b, c);	\
-	error("%s", buf);				\
-}
 
 #else
 #undef NULL
@@ -71,7 +70,8 @@
 #endif
 
 pointer stalloc __P((int));
-void error __P((char *, ...));
+void error __P((const char *, ...));
+void warnx __P((const char *, ...));
 int	echocmd __P((int, char **));
 
 
Index: echo.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/bltin/echo.c,v
retrieving revision 1.8
diff -u -u -r1.8 echo.c
--- echo.c	1996/11/02 18:26:06	1.8
+++ echo.c	2002/06/11 12:37:23
@@ -40,13 +40,24 @@
 
 /*
  * Echo command.
+ *
+ * echo is steeped in tradition - several of them!
+ * netbsd has supported 'echo [-n | -e] args' in spite of -e not being
+ * documented anywhere.
+ * Posix requires that -n be supported, output from strings containing
+ * \ is implementation defined
+ * The Single Unix Spec requires that \ escapes be treated (as below)
+ * but that -n not be treated as an argument.
+ * (ksh supports 'echo [-eEn] args')
  */
 
 #define main echocmd
 
 #include "bltin.h"
+#include "options.h"
 
-/* #define eflag 1 */
+#undef nflag
+#undef eflag
 
 int
 main(argc, argv)  char **argv; {
@@ -55,28 +66,31 @@
 	register char c;
 	int count;
 	int nflag = 0;
-#ifndef eflag
 	int eflag = 0;
-#endif
 
 	ap = argv;
 	if (argc)
 		ap++;
-	if ((p = *ap) != NULL) {
-		if (equal(p, "-n")) {
-			nflag++;
-			ap++;
-		} else if (equal(p, "-e")) {
-#ifndef eflag
-			eflag++;
-#endif
-			ap++;
-		}
+
+	if (SuS_flag) {
+	    eflag = 1;
+	} else {
+	    if ((p = *ap) != NULL) {
+		    if (equal(p, "-n")) {
+			    nflag = 1;
+			    ap++;
+		    } else if (!posix_flag && equal(p, "-e")) {
+			    eflag = 1;
+			    ap++;
+		    }
+	    }
 	}
+
 	while ((p = *ap++) != NULL) {
 		while ((c = *p++) != '\0') {
 			if (c == '\\' && eflag) {
 				switch (*p++) {
+				case 'a':  c = '\a';  break;
 				case 'b':  c = '\b';  break;
 				case 'c':  return 0;		/* exit */
 				case 'f':  c = '\f';  break;
Index: printf.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/printf/printf.c,v
retrieving revision 1.22
diff -u -r1.22 printf.c
--- printf.c	2001/05/05 17:29:39	1.22
+++ printf.c	2002/06/11 12:49:22
@@ -72,7 +72,6 @@
 static intmax_t	 getintmax __P((void));
 static uintmax_t getuintmax __P ((void));
 static char	*getstr __P((void));
-static char	*mklong __P((const char *, int)); 
 static void      check_conversion __P((const char *, const char *));
 static void	 usage __P((void)); 
      
@@ -80,9 +79,7 @@
 static char  **gargv;
 
 #ifdef BUILTIN
-int progprintf __P((int, char **));
-#else
-int main __P((int, char **));
+#define main progprintf
 #endif
 
 #define isodigit(c)	((c) >= '0' && (c) <= '7')
@@ -92,38 +89,6 @@
 #ifdef SHELL
 #define main printfcmd
 #include "../../bin/sh/bltin/bltin.h"
-
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <vararg.h>
-#endif
-
-static void warnx __P((const char *fmt, ...));
-
-static void 
-#ifdef __STDC__
-warnx(const char *fmt, ...)
-#else
-warnx(fmt, va_alist)
-	const char *fmt;
-	va_dcl
-#endif
-{
-	
-	char buf[64];
-	va_list ap;
-
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	vsprintf(buf, fmt, ap);
-	va_end(ap);
-
-	error(buf);
-}
 #endif /* SHELL */
 
 #define PF(f, func) { \
@@ -138,19 +103,13 @@
 		(void)printf(f, func); \
 }
 
-int
-#ifdef BUILTIN
-progprintf(argc, argv)
-#else
-main(argc, argv)
-#endif
-	int argc;
-	char *argv[];
+int main __P((int, char **));
+int main(int argc, char *argv[])
 {
 	char *fmt, *start;
 	int fieldwidth, precision;
-	char convch, nextch;
-	char *format;
+	char convch, nextch, next2ch;
+	static char *format = 0;
 	int ch;
 
 #if !defined(SHELL) && !defined(BUILTIN)
@@ -173,7 +132,13 @@
 		return (1);
 	}
 
-	format = *argv;
+	/* we might need to overwrite the byte after the null.... */
+	if (format)
+	    free( format );
+	format = malloc( strlen( *argv ) + 2 );
+	if (!format)
+		return 2;
+	strcpy( format, *argv );
 	gargv = ++argv;
 
 #define SKIP1	"#-+ 0"
@@ -223,6 +188,7 @@
 
 				convch = *fmt;
 				nextch = *(fmt + 1);
+				next2ch = *(fmt + 2);
 				*(fmt + 1) = '\0';
 				switch(convch) {
 				case 'c': {
@@ -237,18 +203,24 @@
 				}
 				case 'd':
 				case 'i': {
-					char *f = mklong(start, convch);
 					intmax_t p = getintmax();
-					PF(f, p);
+					fmt[0] = 'j';
+					fmt[1] = convch;
+					fmt[2] = 0;
+					PF(start, p);
+					fmt[0] = convch;
 					break;
 				}
 				case 'o':
 				case 'u':
 				case 'x':
 				case 'X': {
-					char *f = mklong(start, convch);
 					uintmax_t p = getuintmax();
-					PF(f, p);
+					fmt[0] = 'j';
+					fmt[1] = convch;
+					fmt[2] = 0;
+					PF(start, p);
+					fmt[0] = convch;
 					break;
 				}
 				case 'e':
@@ -265,6 +237,7 @@
 					return(1);
 				}
 				*(fmt + 1) = nextch;
+				*(fmt + 2) = next2ch;
 				break;
 
 			case '\\':
@@ -422,22 +395,6 @@
 	}
 
 	return 1;
-}
-
-static char *
-mklong(str, ch)
-	const char *str;
-	char ch;
-{
-	static char copy[64];
-	size_t len;	
-
-	len = strlen(str) + 2;
-	(void)memmove(copy, str, len - 3);
-	copy[len - 3] = 'j';
-	copy[len - 2] = ch;
-	copy[len - 1] = '\0';
-	return (copy);	
 }
 
 static int

--IJpNTDwzlM2Ie8A6--