Latest patch from vodz.  Adds a check for divide by zero in the posix
math suport, cleaner math syntax error checking, moves redundant signal
string tables (from kill and ash) into libbb and provides a few
cleanups elsewhere.
diff --git a/Makefile b/Makefile
index 287c3c8..bde9704 100644
--- a/Makefile
+++ b/Makefile
@@ -247,7 +247,7 @@
 trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
 xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
 copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
-dirname.c make_directory.c create_icmp_socket.c arith.c
+dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c
 LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
 LIBBB_CFLAGS = -I$(LIBBB)
 ifneq ($(strip $(BB_SRC_DIR)),)
diff --git a/ash.c b/ash.c
index b1aec62..bcd12f1 100644
--- a/ash.c
+++ b/ash.c
@@ -52,6 +52,7 @@
 
 /* If you need ash to act as a full Posix shell, with full math
  * support, enable this.   This adds a bit over 2k an x86 system. */
+//#undef ASH_MATH_SUPPORT
 #define ASH_MATH_SUPPORT
 
 /* Getopts is used by shell procedures to parse positional parameters.
@@ -78,8 +79,6 @@
 /* These are here to work with glibc -- Don't change these... */
 #undef FNMATCH_BROKEN
 #undef GLOB_BROKEN
-#undef _GNU_SOURCE
-#undef __USE_GNU
 
 #include <assert.h>
 #include <ctype.h>
@@ -4839,6 +4838,7 @@
 expari(int flag)
 {
 	char *p, *start;
+	int errcode;
 	int result;
 	int begoff;
 	int quotes = flag & (EXP_FULL | EXP_CASE);
@@ -4877,9 +4877,13 @@
 	removerecordregions(begoff);
 	if (quotes)
 		rmescapes(p+2);
-	result = arith(p+2);
-	if (result < 0)
-	    error("arith: syntax error: \"%s\"\n", p+2);
+	result = arith(p+2, &errcode);
+	if (errcode < 0) {
+		if(errcode == -2)
+			error("divide by zero");
+		else
+			error("syntax error: \"%s\"\n", p+2);
+	}
 	snprintf(p, 12, "%d", result);
 
 	while (*p++)
@@ -5429,9 +5433,9 @@
 			goto nometa;
 		p = preglob(str->text);
 		INTOFF;
-		switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
+		switch (glob(p, 0, 0, &pglob)) {
 		case 0:
-			if (!(pglob.gl_flags & GLOB_MAGCHAR))
+			if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
 				goto nometa2;
 			addglob(&pglob);
 			globfree(&pglob);
@@ -6006,7 +6010,7 @@
 struct redirtab {
 	struct redirtab *next;
 	short renamed[10]; /* Current ash support only 0-9 descriptors */
-	/* char renamed[10]; */ /* char on arm (and others) can't be negative */
+	/* char on arm (and others) can't be negative */
 };
 
 static struct redirtab *redirlist;
@@ -6166,7 +6170,7 @@
 retry:
 #ifdef BB_FEATURE_COMMAND_EDITING
 	{
-	    if (parsefile->fd)
+	    if (!iflag || parsefile->fd)
 		    nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
 	    else {
 		    nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
@@ -6468,80 +6472,6 @@
 #endif
 
 
-/* A translation list so we can be polite to our users. */
-static char *signal_names[NSIG + 2] = {
-    "EXIT",
-    "SIGHUP",
-    "SIGINT",
-    "SIGQUIT",
-    "SIGILL",
-    "SIGTRAP",
-    "SIGABRT",
-    "SIGBUS",
-    "SIGFPE",
-    "SIGKILL",
-    "SIGUSR1",
-    "SIGSEGV",
-    "SIGUSR2",
-    "SIGPIPE",
-    "SIGALRM",
-    "SIGTERM",
-    "SIGJUNK(16)",
-    "SIGCHLD",
-    "SIGCONT",
-    "SIGSTOP",
-    "SIGTSTP",
-    "SIGTTIN",
-    "SIGTTOU",
-    "SIGURG",
-    "SIGXCPU",
-    "SIGXFSZ",
-    "SIGVTALRM",
-    "SIGPROF",
-    "SIGWINCH",
-    "SIGIO",
-    "SIGPWR",
-    "SIGSYS",
-#ifdef SIGRTMIN
-    "SIGRTMIN",
-    "SIGRTMIN+1",
-    "SIGRTMIN+2",
-    "SIGRTMIN+3",
-    "SIGRTMIN+4",
-    "SIGRTMIN+5",
-    "SIGRTMIN+6",
-    "SIGRTMIN+7",
-    "SIGRTMIN+8",
-    "SIGRTMIN+9",
-    "SIGRTMIN+10",
-    "SIGRTMIN+11",
-    "SIGRTMIN+12",
-    "SIGRTMIN+13",
-    "SIGRTMIN+14",
-    "SIGRTMIN+15",
-    "SIGRTMAX-15",
-    "SIGRTMAX-14",
-    "SIGRTMAX-13",
-    "SIGRTMAX-12",
-    "SIGRTMAX-11",
-    "SIGRTMAX-10",
-    "SIGRTMAX-9",
-    "SIGRTMAX-8",
-    "SIGRTMAX-7",
-    "SIGRTMAX-6",
-    "SIGRTMAX-5",
-    "SIGRTMAX-4",
-    "SIGRTMAX-3",
-    "SIGRTMAX-2",
-    "SIGRTMAX-1",
-    "SIGRTMAX",
-#endif
-    "DEBUG",
-    (char *)0x0,
-};
-
-
-
 #ifdef JOBS
 static int
 killcmd(argc, argv)
@@ -6599,18 +6529,20 @@
 	}
 
 	if (list) {
+		const char *name;
+
 		if (!*argptr) {
 			out1str("0\n");
 			for (i = 1; i < NSIG; i++) {
-				printf(snlfmt, signal_names[i] + 3);
+				name = u_signal_names(0, &i, 1);
+				if(name)
+					printf(snlfmt, name);
 			}
 			return 0;
 		}
-		signo = atoi(*argptr);
-		if (signo > 128)
-			signo -= 128;
-		if (0 < signo && signo < NSIG)
-				printf(snlfmt, signal_names[signo] + 3);
+		name = u_signal_names(*argptr, &signo, -1);
+		if (name)
+			printf(snlfmt, name);
 		else
 			error("invalid signal number or exit status: %s",
 			      *argptr);
@@ -8834,12 +8766,6 @@
 static char *
 nodesavestr(const char *s)
 {
-#ifdef _GNU_SOURCE
-	char   *rtn = funcstring;
-
-	funcstring = stpcpy(funcstring, s) + 1;
-	return rtn;
-#else
 	const char *p = s;
 	char *q = funcstring;
 	char   *rtn = funcstring;
@@ -8848,7 +8774,6 @@
 		continue;
 	funcstring = q;
 	return rtn;
-#endif
 }
 
 #ifdef ASH_GETOPTS
@@ -12052,11 +11977,15 @@
 		for (signo = 0 ; signo < NSIG ; signo++) {
 			if (trap[signo] != NULL) {
 				char *p;
+				const char *sn;
 
 				p = single_quote(trap[signo]);
-				printf("trap -- %s %s\n", p,
-					signal_names[signo] + (signo ? 3 : 0)
-				);
+				sn = sys_siglist[signo];
+				if(sn==NULL)
+					sn = u_signal_names(0, &signo, 0);
+				if(sn==NULL)
+					sn = "???";
+				printf("trap -- %s %s\n", p, sn);
 				stunalloc(p);
 			}
 		}
@@ -12273,30 +12202,11 @@
 static int decode_signal(const char *string, int minsig)
 {
 	int signo;
+	const char *name = u_signal_names(string, &signo, minsig);
 
-	if (is_number(string, &signo)) {
-		if (signo >= NSIG) {
-			return -1;
-		}
-		return signo;
-	}
-
-	signo = minsig;
-	if (!signo) {
-		goto zero;
-	}
-	for (; signo < NSIG; signo++) {
-		if (!strcasecmp(string, &(signal_names[signo])[3])) {
-			return signo;
-		}
-zero:
-		if (!strcasecmp(string, signal_names[signo])) {
-			return signo;
-		}
-	}
-
-	return -1;
+	return name ? signo : -1;
 }
+
 static struct var **hashvar (const char *);
 static void showvars (const char *, int, int);
 static struct var **findvar (struct var **, const char *);
@@ -12616,6 +12526,7 @@
 	return 0;
 }
 
+
 /*
  * The "local" command.
  */
@@ -12874,7 +12785,7 @@
 /*
  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
  * This file contains code for the times builtin.
- * $Id: ash.c,v 1.16 2001/08/01 17:21:33 kraai Exp $
+ * $Id: ash.c,v 1.17 2001/08/02 05:02:45 andersen Exp $
  */
 static int timescmd (int argc, char **argv)
 {
@@ -12894,24 +12805,32 @@
 	return 0;
 }
 
-
 #ifdef ASH_MATH_SUPPORT
 /* The let builtin.  */
 int letcmd(int argc, char **argv)
 {
+	int errcode;
 	long result=0;
 	if (argc == 2) {
 		char *tmp, *expression, p[13];
 		expression = strchr(argv[1], '=');
 		if (!expression) {
+			/* Cannot use 'error()' here, or the return code
+			 * will be incorrect */
 			out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
 			return 0;
 		}
 		*expression = '\0';
 		tmp = ++expression;
-		result = arith(tmp);
-		if (result < 0) {
-			out2fmt("sh: let: syntax error: \"%s=%s\"\n", argv[1], expression);
+		result = arith(tmp, &errcode);
+		if (errcode < 0) {
+			/* Cannot use 'error()' here, or the return code
+			 * will be incorrect */
+			out2fmt("sh: let: ");
+			if(errcode == -2)
+				out2fmt("divide by zero");
+			else
+				out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
 			return 0;
 		}
 		snprintf(p, 12, "%ld", result);
diff --git a/cmdedit.c b/cmdedit.c
index 3b47504..2ec8154 100644
--- a/cmdedit.c
+++ b/cmdedit.c
@@ -1167,25 +1167,21 @@
 	len = 0;
 	command_ps = command;
 
-	if (new_settings.c_cc[VERASE] == 0) {     /* first call */
-
-		getTermSettings(0, (void *) &initial_settings);
-		memcpy(&new_settings, &initial_settings, sizeof(struct termios));
-		new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
-		/* Turn off echoing and CTRL-C, so we can trap it */
-		new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
+	getTermSettings(0, (void *) &initial_settings);
+	memcpy(&new_settings, &initial_settings, sizeof(struct termios));
+	new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
+	/* Turn off echoing and CTRL-C, so we can trap it */
+	new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
 #ifndef linux
-		/* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-		new_settings.c_cc[VMIN] = 1;
-		new_settings.c_cc[VTIME] = 0;
-		/* Turn off CTRL-C, so we can trap it */
+	/* Hmm, in linux c_cc[] not parsed if set ~ICANON */
+	new_settings.c_cc[VMIN] = 1;
+	new_settings.c_cc[VTIME] = 0;
+	/* Turn off CTRL-C, so we can trap it */
 #       ifndef _POSIX_VDISABLE
 #               define _POSIX_VDISABLE '\0'
 #       endif
-		new_settings.c_cc[VINTR] = _POSIX_VDISABLE;	
+	new_settings.c_cc[VINTR] = _POSIX_VDISABLE;	
 #endif
-	}
-
 	command[0] = 0;
 
 	setTermSettings(0, (void *) &new_settings);
diff --git a/coreutils/cut.c b/coreutils/cut.c
index abe0572..3ed2648 100644
--- a/coreutils/cut.c
+++ b/coreutils/cut.c
@@ -344,10 +344,8 @@
 		int i;
 		FILE *file;
 		for (i = optind; i < argc; i++) {
-			file = fopen(argv[i], "r");
-			if (file == NULL) {
-				perror_msg("%s", argv[i]);
-			} else {
+			file = wfopen(argv[i], "r");
+			if(file) {
 				cut_file(file);
 				fclose(file);
 			}
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 6ac9f1b..a4059dd 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -201,9 +201,8 @@
                    const char *forced_outname)
 {
   struct passwd *pw;
-  register int n;
   register char *p;
-  int mode, n1;
+  int mode;
   char buf[2 * BUFSIZ];
   char *outname;
   int do_base64 = 0;
@@ -249,12 +248,7 @@
         error_msg("%s: No user `%s'", inname, buf + 1);
         return FALSE;
       }
-      n = strlen (pw->pw_dir);
-      n1 = strlen (p);
-      outname = (char *) xmalloc ((size_t) (n + n1 + 2));
-      memcpy (outname + n + 1, p, (size_t) (n1 + 1));
-      memcpy (outname, pw->pw_dir, (size_t) n);
-      outname[n] = '/';
+      outname = concat_path_file(pw->pw_dir, p);
       dofre = TRUE;
     }
   }
diff --git a/cut.c b/cut.c
index abe0572..3ed2648 100644
--- a/cut.c
+++ b/cut.c
@@ -344,10 +344,8 @@
 		int i;
 		FILE *file;
 		for (i = optind; i < argc; i++) {
-			file = fopen(argv[i], "r");
-			if (file == NULL) {
-				perror_msg("%s", argv[i]);
-			} else {
+			file = wfopen(argv[i], "r");
+			if(file) {
 				cut_file(file);
 				fclose(file);
 			}
diff --git a/include/libbb.h b/include/libbb.h
index 66acc22..df52027 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -212,7 +212,7 @@
 char *concat_path_file(const char *path, const char *filename);
 char *last_char_is(const char *s, int c);
 
-extern long arith (const char *startbuf);
+extern long arith (const char *startbuf, int *errcode);
 
 typedef struct file_headers_s {
 	char *name;
@@ -261,6 +261,8 @@
 
 int make_directory (char *path, mode_t mode, int flags);
 
+const char *u_signal_names(const char *str_sig, int *signo, int startnum);
+
 #define CT_AUTO	0
 #define CT_UNIX2DOS	1
 #define CT_DOS2UNIX	2
diff --git a/kill.c b/kill.c
index 34cbc4d..3884ebd 100644
--- a/kill.c
+++ b/kill.c
@@ -34,96 +34,11 @@
 static const int KILL = 0;
 static const int KILLALL = 1;
 
-struct signal_name {
-	const char *name;
-	int number;
-};
-
-static const struct signal_name signames[] = {
-	/* POSIX signals */
-	{ "HUP",	SIGHUP },	/* 1 */
-	{ "INT",	SIGINT }, 	/* 2 */
-	{ "QUIT",	SIGQUIT }, 	/* 3 */
-	{ "ILL",	SIGILL }, 	/* 4 */
-	{ "ABRT",	SIGABRT }, 	/* 6 */
-	{ "FPE",	SIGFPE }, 	/* 8 */
-	{ "KILL",	SIGKILL }, 	/* 9 */
-	{ "SEGV",	SIGSEGV }, 	/* 11 */
-	{ "PIPE",	SIGPIPE }, 	/* 13 */
-	{ "ALRM",	SIGALRM }, 	/* 14 */
-	{ "TERM",	SIGTERM }, 	/* 15 */
-	{ "USR1",	SIGUSR1 }, 	/* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
-	{ "USR2",	SIGUSR2 }, 	/* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
-	{ "CHLD",	SIGCHLD }, 	/* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
-	{ "CONT",	SIGCONT }, 	/* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
-	{ "STOP",	SIGSTOP },	/* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
-	{ "TSTP",	SIGTSTP },	/* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
-	{ "TTIN",	SIGTTIN },	/* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
-	{ "TTOU",	SIGTTOU },	/* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
-	/* Miscellaneous other signals */
-#ifdef SIGTRAP
-	{ "TRAP",	SIGTRAP },	/* 5 */
-#endif
-#ifdef SIGIOT
-	{ "IOT",	SIGIOT }, 	/* 6, same as SIGABRT */
-#endif
-#ifdef SIGEMT
-	{ "EMT",	SIGEMT }, 	/* 7 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGBUS
-	{ "BUS",	SIGBUS },	/* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSYS
-	{ "SYS",	SIGSYS }, 	/* 12 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSTKFLT
-	{ "STKFLT",	SIGSTKFLT },	/* 16 (arm,i386,m68k,ppc) */
-#endif
-#ifdef SIGURG
-	{ "URG",	SIGURG },	/* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
-#endif
-#ifdef SIGIO
-	{ "IO",		SIGIO },	/* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
-#endif
-#ifdef SIGPOLL
-	{ "POLL",	SIGPOLL },	/* same as SIGIO */
-#endif
-#ifdef SIGCLD
-	{ "CLD",	SIGCLD },	/* same as SIGCHLD (mips) */
-#endif
-#ifdef SIGXCPU
-	{ "XCPU",	SIGXCPU },	/* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
-#endif
-#ifdef SIGXFSZ
-	{ "XFSZ",	SIGXFSZ },	/* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
-#endif
-#ifdef SIGVTALRM
-	{ "VTALRM",	SIGVTALRM },	/* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
-#endif
-#ifdef SIGPROF
-	{ "PROF",	SIGPROF },	/* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
-#endif
-#ifdef SIGPWR
-	{ "PWR",	SIGPWR },	/* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
-#endif
-#ifdef SIGINFO
-	{ "INFO",	SIGINFO },	/* 29 (alpha) */
-#endif
-#ifdef SIGLOST
-	{ "LOST",	SIGLOST }, 	/* 29 (arm,i386,m68k,ppc,sparc*) */
-#endif
-#ifdef SIGWINCH
-	{ "WINCH",	SIGWINCH },	/* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
-#endif
-#ifdef SIGUNUSED
-	{ "UNUSED",	SIGUNUSED },	/* 31 (arm,i386,m68k,ppc) */
-#endif
-	{0, 0}
-};
 
 extern int kill_main(int argc, char **argv)
 {
 	int whichApp, sig = SIGTERM;
+	const char *name;
 
 #ifdef BB_KILLALL
 	/* Figure out what we are trying to do here */
@@ -142,52 +57,37 @@
 		while (*++(*argv)) {
 			switch (**argv) {
 			case 'l':
-				{
+				if(argc>1) {
+					for(argv++; *argv; argv++) {
+						name = u_signal_names(*argv, &sig, -1);
+						if(name!=NULL)
+							printf("%s\n", name);
+					}
+				} else {
 					int col = 0;
-					const struct signal_name *s = signames;
-
-					while (s->name != 0) {
-						col += fprintf(stderr, "%2d) %-8s", s->number, s->name);
-						s++;
+					for(sig=1; sig < NSIG; sig++) {
+						name = u_signal_names(0, &sig, 1);
+						if(name==NULL)  /* unnamed */
+							continue;
+						col += printf("%2d) %-16s", sig, name);
 						if (col > 60) {
-							fprintf(stderr, "\n");
+							printf("\n");
 							col = 0;
 						}
 					}
-					fprintf(stderr, "\n\n");
-					return EXIT_SUCCESS;
+					printf("\n");
 				}
-				break;
+				return EXIT_SUCCESS;
 			case '-':
 				show_usage();
 			default:
-				{
-					if (isdigit(**argv)) {
-						sig = atoi(*argv);
-						if (sig < 0 || sig >= NSIG)
-							goto end;
-						else {
-							argc--;
-							argv++;
-							goto do_it_now;
-						}
-					} else {
-						const struct signal_name *s = signames;
-
-						while (s->name != 0) {
-							if (strcasecmp(s->name, *argv) == 0) {
-								sig = s->number;
+				name = u_signal_names(*argv, &sig, 0);
+				if(name==NULL)
+					error_msg_and_die( "bad signal name: %s", *argv);
 								argc--;
 								argv++;
 								goto do_it_now;
 							}
-							s++;
-						}
-						if (s->name == 0)
-							goto end;
-					}
-				}
-			}
 			argc--;
 			argv++;
 		}
@@ -239,8 +139,4 @@
 #endif
 
 	return EXIT_SUCCESS;
-
-
-  end:
-	error_msg_and_die( "bad signal name: %s", *argv);
 }
diff --git a/libbb/arith.c b/libbb/arith.c
index c7a3cf9..04c45ec 100644
--- a/libbb/arith.c
+++ b/libbb/arith.c
@@ -119,20 +119,26 @@
 		NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR);
 	else if (op == TOK_MUL)
 		NUMPTR[-1] *= *NUMPTR;
-	else if (op == TOK_DIV)
+	else if (op == TOK_DIV) {
+		if(*NUMPTR==0)
+			return -2;
 		NUMPTR[-1] /= *NUMPTR;
-	else if (op == TOK_REM)
+		}
+	else if (op == TOK_REM) {
+		if(*NUMPTR==0)
+			return -2;
 		NUMPTR[-1] %= *NUMPTR;
+		}
 	else if (op == TOK_ADD)
 		NUMPTR[-1] += *NUMPTR;
 	else if (op == TOK_SUB)
 		NUMPTR[-1] -= *NUMPTR;
 	}
 	return 0;
-err: return(1);
+err: return(-1);
 }
 
-extern long arith (const char *startbuf)
+extern long arith (const char *startbuf, int *errcode)
 {
 	register char arithval;
 	const char *expr = startbuf;
@@ -142,8 +148,9 @@
 	unsigned char prec;
 
 	long *numstack, *numstackptr;
-
 	operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack;
+
+	*errcode = 0;
 	numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack;
 
 	while ((arithval = *expr)) {
@@ -163,7 +170,8 @@
 				op = *--stackptr;
 				if (op == TOK_LPAREN)
 					goto prologue;
-				if(ARITH_APPLY(op)) goto err;
+				*errcode = ARITH_APPLY(op);
+				if(*errcode) return *errcode;
 			}
 			goto err; /* Mismatched parens */
 		} if (arithval == '|') {
@@ -231,17 +239,22 @@
 
 		prec = PREC(op);
 		if (prec != UNARYPREC)
-			while (stackptr != stack && PREC(stackptr[-1]) >= prec)
-				if(ARITH_APPLY(*--stackptr)) goto err;
+			while (stackptr != stack && PREC(stackptr[-1]) >= prec) {
+				*errcode = ARITH_APPLY(*--stackptr);
+				if(*errcode) return *errcode;
+			}
 		*stackptr++ = op;
 		lasttok = op;
 prologue: ++expr;
 	} /* yay */
 
-	while (stackptr != stack)
-		if(ARITH_APPLY(*--stackptr)) goto err;
+	while (stackptr != stack) {
+		*errcode = ARITH_APPLY(*--stackptr);
+		if(*errcode) return *errcode;
+	}
 	if (numstackptr != numstack+1) {
 err: 
+	    *errcode = -1;
 	    return -1;
 	 /* NOTREACHED */
 	}
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index c699a84..86dd2fb 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -17,7 +17,7 @@
 	if (!path)
 	    path="";
 	lc = last_char_is(path, '/');
-	if (filename[0] == '/')
+	while (*filename == '/')
 		filename++;
 	outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
 	sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
diff --git a/libbb/libbb.h b/libbb/libbb.h
index 66acc22..df52027 100644
--- a/libbb/libbb.h
+++ b/libbb/libbb.h
@@ -212,7 +212,7 @@
 char *concat_path_file(const char *path, const char *filename);
 char *last_char_is(const char *s, int c);
 
-extern long arith (const char *startbuf);
+extern long arith (const char *startbuf, int *errcode);
 
 typedef struct file_headers_s {
 	char *name;
@@ -261,6 +261,8 @@
 
 int make_directory (char *path, mode_t mode, int flags);
 
+const char *u_signal_names(const char *str_sig, int *signo, int startnum);
+
 #define CT_AUTO	0
 #define CT_UNIX2DOS	1
 #define CT_DOS2UNIX	2
diff --git a/miscutils/update.c b/miscutils/update.c
index 603740e..27a04dd 100644
--- a/miscutils/update.c
+++ b/miscutils/update.c
@@ -69,9 +69,6 @@
 	if (daemon(0, 1) < 0)
 		perror_msg_and_die("daemon");
 
-	/* Become a proper daemon */
-	setsid();
-	chdir("/");
 #ifdef OPEN_MAX
 	for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
 #else
diff --git a/procps/kill.c b/procps/kill.c
index 34cbc4d..3884ebd 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -34,96 +34,11 @@
 static const int KILL = 0;
 static const int KILLALL = 1;
 
-struct signal_name {
-	const char *name;
-	int number;
-};
-
-static const struct signal_name signames[] = {
-	/* POSIX signals */
-	{ "HUP",	SIGHUP },	/* 1 */
-	{ "INT",	SIGINT }, 	/* 2 */
-	{ "QUIT",	SIGQUIT }, 	/* 3 */
-	{ "ILL",	SIGILL }, 	/* 4 */
-	{ "ABRT",	SIGABRT }, 	/* 6 */
-	{ "FPE",	SIGFPE }, 	/* 8 */
-	{ "KILL",	SIGKILL }, 	/* 9 */
-	{ "SEGV",	SIGSEGV }, 	/* 11 */
-	{ "PIPE",	SIGPIPE }, 	/* 13 */
-	{ "ALRM",	SIGALRM }, 	/* 14 */
-	{ "TERM",	SIGTERM }, 	/* 15 */
-	{ "USR1",	SIGUSR1 }, 	/* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
-	{ "USR2",	SIGUSR2 }, 	/* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
-	{ "CHLD",	SIGCHLD }, 	/* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
-	{ "CONT",	SIGCONT }, 	/* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
-	{ "STOP",	SIGSTOP },	/* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
-	{ "TSTP",	SIGTSTP },	/* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
-	{ "TTIN",	SIGTTIN },	/* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
-	{ "TTOU",	SIGTTOU },	/* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
-	/* Miscellaneous other signals */
-#ifdef SIGTRAP
-	{ "TRAP",	SIGTRAP },	/* 5 */
-#endif
-#ifdef SIGIOT
-	{ "IOT",	SIGIOT }, 	/* 6, same as SIGABRT */
-#endif
-#ifdef SIGEMT
-	{ "EMT",	SIGEMT }, 	/* 7 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGBUS
-	{ "BUS",	SIGBUS },	/* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSYS
-	{ "SYS",	SIGSYS }, 	/* 12 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSTKFLT
-	{ "STKFLT",	SIGSTKFLT },	/* 16 (arm,i386,m68k,ppc) */
-#endif
-#ifdef SIGURG
-	{ "URG",	SIGURG },	/* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
-#endif
-#ifdef SIGIO
-	{ "IO",		SIGIO },	/* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
-#endif
-#ifdef SIGPOLL
-	{ "POLL",	SIGPOLL },	/* same as SIGIO */
-#endif
-#ifdef SIGCLD
-	{ "CLD",	SIGCLD },	/* same as SIGCHLD (mips) */
-#endif
-#ifdef SIGXCPU
-	{ "XCPU",	SIGXCPU },	/* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
-#endif
-#ifdef SIGXFSZ
-	{ "XFSZ",	SIGXFSZ },	/* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
-#endif
-#ifdef SIGVTALRM
-	{ "VTALRM",	SIGVTALRM },	/* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
-#endif
-#ifdef SIGPROF
-	{ "PROF",	SIGPROF },	/* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
-#endif
-#ifdef SIGPWR
-	{ "PWR",	SIGPWR },	/* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
-#endif
-#ifdef SIGINFO
-	{ "INFO",	SIGINFO },	/* 29 (alpha) */
-#endif
-#ifdef SIGLOST
-	{ "LOST",	SIGLOST }, 	/* 29 (arm,i386,m68k,ppc,sparc*) */
-#endif
-#ifdef SIGWINCH
-	{ "WINCH",	SIGWINCH },	/* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
-#endif
-#ifdef SIGUNUSED
-	{ "UNUSED",	SIGUNUSED },	/* 31 (arm,i386,m68k,ppc) */
-#endif
-	{0, 0}
-};
 
 extern int kill_main(int argc, char **argv)
 {
 	int whichApp, sig = SIGTERM;
+	const char *name;
 
 #ifdef BB_KILLALL
 	/* Figure out what we are trying to do here */
@@ -142,52 +57,37 @@
 		while (*++(*argv)) {
 			switch (**argv) {
 			case 'l':
-				{
+				if(argc>1) {
+					for(argv++; *argv; argv++) {
+						name = u_signal_names(*argv, &sig, -1);
+						if(name!=NULL)
+							printf("%s\n", name);
+					}
+				} else {
 					int col = 0;
-					const struct signal_name *s = signames;
-
-					while (s->name != 0) {
-						col += fprintf(stderr, "%2d) %-8s", s->number, s->name);
-						s++;
+					for(sig=1; sig < NSIG; sig++) {
+						name = u_signal_names(0, &sig, 1);
+						if(name==NULL)  /* unnamed */
+							continue;
+						col += printf("%2d) %-16s", sig, name);
 						if (col > 60) {
-							fprintf(stderr, "\n");
+							printf("\n");
 							col = 0;
 						}
 					}
-					fprintf(stderr, "\n\n");
-					return EXIT_SUCCESS;
+					printf("\n");
 				}
-				break;
+				return EXIT_SUCCESS;
 			case '-':
 				show_usage();
 			default:
-				{
-					if (isdigit(**argv)) {
-						sig = atoi(*argv);
-						if (sig < 0 || sig >= NSIG)
-							goto end;
-						else {
-							argc--;
-							argv++;
-							goto do_it_now;
-						}
-					} else {
-						const struct signal_name *s = signames;
-
-						while (s->name != 0) {
-							if (strcasecmp(s->name, *argv) == 0) {
-								sig = s->number;
+				name = u_signal_names(*argv, &sig, 0);
+				if(name==NULL)
+					error_msg_and_die( "bad signal name: %s", *argv);
 								argc--;
 								argv++;
 								goto do_it_now;
 							}
-							s++;
-						}
-						if (s->name == 0)
-							goto end;
-					}
-				}
-			}
 			argc--;
 			argv++;
 		}
@@ -239,8 +139,4 @@
 #endif
 
 	return EXIT_SUCCESS;
-
-
-  end:
-	error_msg_and_die( "bad signal name: %s", *argv);
 }
diff --git a/shell/ash.c b/shell/ash.c
index b1aec62..bcd12f1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -52,6 +52,7 @@
 
 /* If you need ash to act as a full Posix shell, with full math
  * support, enable this.   This adds a bit over 2k an x86 system. */
+//#undef ASH_MATH_SUPPORT
 #define ASH_MATH_SUPPORT
 
 /* Getopts is used by shell procedures to parse positional parameters.
@@ -78,8 +79,6 @@
 /* These are here to work with glibc -- Don't change these... */
 #undef FNMATCH_BROKEN
 #undef GLOB_BROKEN
-#undef _GNU_SOURCE
-#undef __USE_GNU
 
 #include <assert.h>
 #include <ctype.h>
@@ -4839,6 +4838,7 @@
 expari(int flag)
 {
 	char *p, *start;
+	int errcode;
 	int result;
 	int begoff;
 	int quotes = flag & (EXP_FULL | EXP_CASE);
@@ -4877,9 +4877,13 @@
 	removerecordregions(begoff);
 	if (quotes)
 		rmescapes(p+2);
-	result = arith(p+2);
-	if (result < 0)
-	    error("arith: syntax error: \"%s\"\n", p+2);
+	result = arith(p+2, &errcode);
+	if (errcode < 0) {
+		if(errcode == -2)
+			error("divide by zero");
+		else
+			error("syntax error: \"%s\"\n", p+2);
+	}
 	snprintf(p, 12, "%d", result);
 
 	while (*p++)
@@ -5429,9 +5433,9 @@
 			goto nometa;
 		p = preglob(str->text);
 		INTOFF;
-		switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
+		switch (glob(p, 0, 0, &pglob)) {
 		case 0:
-			if (!(pglob.gl_flags & GLOB_MAGCHAR))
+			if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
 				goto nometa2;
 			addglob(&pglob);
 			globfree(&pglob);
@@ -6006,7 +6010,7 @@
 struct redirtab {
 	struct redirtab *next;
 	short renamed[10]; /* Current ash support only 0-9 descriptors */
-	/* char renamed[10]; */ /* char on arm (and others) can't be negative */
+	/* char on arm (and others) can't be negative */
 };
 
 static struct redirtab *redirlist;
@@ -6166,7 +6170,7 @@
 retry:
 #ifdef BB_FEATURE_COMMAND_EDITING
 	{
-	    if (parsefile->fd)
+	    if (!iflag || parsefile->fd)
 		    nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
 	    else {
 		    nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
@@ -6468,80 +6472,6 @@
 #endif
 
 
-/* A translation list so we can be polite to our users. */
-static char *signal_names[NSIG + 2] = {
-    "EXIT",
-    "SIGHUP",
-    "SIGINT",
-    "SIGQUIT",
-    "SIGILL",
-    "SIGTRAP",
-    "SIGABRT",
-    "SIGBUS",
-    "SIGFPE",
-    "SIGKILL",
-    "SIGUSR1",
-    "SIGSEGV",
-    "SIGUSR2",
-    "SIGPIPE",
-    "SIGALRM",
-    "SIGTERM",
-    "SIGJUNK(16)",
-    "SIGCHLD",
-    "SIGCONT",
-    "SIGSTOP",
-    "SIGTSTP",
-    "SIGTTIN",
-    "SIGTTOU",
-    "SIGURG",
-    "SIGXCPU",
-    "SIGXFSZ",
-    "SIGVTALRM",
-    "SIGPROF",
-    "SIGWINCH",
-    "SIGIO",
-    "SIGPWR",
-    "SIGSYS",
-#ifdef SIGRTMIN
-    "SIGRTMIN",
-    "SIGRTMIN+1",
-    "SIGRTMIN+2",
-    "SIGRTMIN+3",
-    "SIGRTMIN+4",
-    "SIGRTMIN+5",
-    "SIGRTMIN+6",
-    "SIGRTMIN+7",
-    "SIGRTMIN+8",
-    "SIGRTMIN+9",
-    "SIGRTMIN+10",
-    "SIGRTMIN+11",
-    "SIGRTMIN+12",
-    "SIGRTMIN+13",
-    "SIGRTMIN+14",
-    "SIGRTMIN+15",
-    "SIGRTMAX-15",
-    "SIGRTMAX-14",
-    "SIGRTMAX-13",
-    "SIGRTMAX-12",
-    "SIGRTMAX-11",
-    "SIGRTMAX-10",
-    "SIGRTMAX-9",
-    "SIGRTMAX-8",
-    "SIGRTMAX-7",
-    "SIGRTMAX-6",
-    "SIGRTMAX-5",
-    "SIGRTMAX-4",
-    "SIGRTMAX-3",
-    "SIGRTMAX-2",
-    "SIGRTMAX-1",
-    "SIGRTMAX",
-#endif
-    "DEBUG",
-    (char *)0x0,
-};
-
-
-
 #ifdef JOBS
 static int
 killcmd(argc, argv)
@@ -6599,18 +6529,20 @@
 	}
 
 	if (list) {
+		const char *name;
+
 		if (!*argptr) {
 			out1str("0\n");
 			for (i = 1; i < NSIG; i++) {
-				printf(snlfmt, signal_names[i] + 3);
+				name = u_signal_names(0, &i, 1);
+				if(name)
+					printf(snlfmt, name);
 			}
 			return 0;
 		}
-		signo = atoi(*argptr);
-		if (signo > 128)
-			signo -= 128;
-		if (0 < signo && signo < NSIG)
-				printf(snlfmt, signal_names[signo] + 3);
+		name = u_signal_names(*argptr, &signo, -1);
+		if (name)
+			printf(snlfmt, name);
 		else
 			error("invalid signal number or exit status: %s",
 			      *argptr);
@@ -8834,12 +8766,6 @@
 static char *
 nodesavestr(const char *s)
 {
-#ifdef _GNU_SOURCE
-	char   *rtn = funcstring;
-
-	funcstring = stpcpy(funcstring, s) + 1;
-	return rtn;
-#else
 	const char *p = s;
 	char *q = funcstring;
 	char   *rtn = funcstring;
@@ -8848,7 +8774,6 @@
 		continue;
 	funcstring = q;
 	return rtn;
-#endif
 }
 
 #ifdef ASH_GETOPTS
@@ -12052,11 +11977,15 @@
 		for (signo = 0 ; signo < NSIG ; signo++) {
 			if (trap[signo] != NULL) {
 				char *p;
+				const char *sn;
 
 				p = single_quote(trap[signo]);
-				printf("trap -- %s %s\n", p,
-					signal_names[signo] + (signo ? 3 : 0)
-				);
+				sn = sys_siglist[signo];
+				if(sn==NULL)
+					sn = u_signal_names(0, &signo, 0);
+				if(sn==NULL)
+					sn = "???";
+				printf("trap -- %s %s\n", p, sn);
 				stunalloc(p);
 			}
 		}
@@ -12273,30 +12202,11 @@
 static int decode_signal(const char *string, int minsig)
 {
 	int signo;
+	const char *name = u_signal_names(string, &signo, minsig);
 
-	if (is_number(string, &signo)) {
-		if (signo >= NSIG) {
-			return -1;
-		}
-		return signo;
-	}
-
-	signo = minsig;
-	if (!signo) {
-		goto zero;
-	}
-	for (; signo < NSIG; signo++) {
-		if (!strcasecmp(string, &(signal_names[signo])[3])) {
-			return signo;
-		}
-zero:
-		if (!strcasecmp(string, signal_names[signo])) {
-			return signo;
-		}
-	}
-
-	return -1;
+	return name ? signo : -1;
 }
+
 static struct var **hashvar (const char *);
 static void showvars (const char *, int, int);
 static struct var **findvar (struct var **, const char *);
@@ -12616,6 +12526,7 @@
 	return 0;
 }
 
+
 /*
  * The "local" command.
  */
@@ -12874,7 +12785,7 @@
 /*
  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
  * This file contains code for the times builtin.
- * $Id: ash.c,v 1.16 2001/08/01 17:21:33 kraai Exp $
+ * $Id: ash.c,v 1.17 2001/08/02 05:02:45 andersen Exp $
  */
 static int timescmd (int argc, char **argv)
 {
@@ -12894,24 +12805,32 @@
 	return 0;
 }
 
-
 #ifdef ASH_MATH_SUPPORT
 /* The let builtin.  */
 int letcmd(int argc, char **argv)
 {
+	int errcode;
 	long result=0;
 	if (argc == 2) {
 		char *tmp, *expression, p[13];
 		expression = strchr(argv[1], '=');
 		if (!expression) {
+			/* Cannot use 'error()' here, or the return code
+			 * will be incorrect */
 			out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
 			return 0;
 		}
 		*expression = '\0';
 		tmp = ++expression;
-		result = arith(tmp);
-		if (result < 0) {
-			out2fmt("sh: let: syntax error: \"%s=%s\"\n", argv[1], expression);
+		result = arith(tmp, &errcode);
+		if (errcode < 0) {
+			/* Cannot use 'error()' here, or the return code
+			 * will be incorrect */
+			out2fmt("sh: let: ");
+			if(errcode == -2)
+				out2fmt("divide by zero");
+			else
+				out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
 			return 0;
 		}
 		snprintf(p, 12, "%ld", result);
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index 3b47504..2ec8154 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -1167,25 +1167,21 @@
 	len = 0;
 	command_ps = command;
 
-	if (new_settings.c_cc[VERASE] == 0) {     /* first call */
-
-		getTermSettings(0, (void *) &initial_settings);
-		memcpy(&new_settings, &initial_settings, sizeof(struct termios));
-		new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
-		/* Turn off echoing and CTRL-C, so we can trap it */
-		new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
+	getTermSettings(0, (void *) &initial_settings);
+	memcpy(&new_settings, &initial_settings, sizeof(struct termios));
+	new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
+	/* Turn off echoing and CTRL-C, so we can trap it */
+	new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
 #ifndef linux
-		/* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-		new_settings.c_cc[VMIN] = 1;
-		new_settings.c_cc[VTIME] = 0;
-		/* Turn off CTRL-C, so we can trap it */
+	/* Hmm, in linux c_cc[] not parsed if set ~ICANON */
+	new_settings.c_cc[VMIN] = 1;
+	new_settings.c_cc[VTIME] = 0;
+	/* Turn off CTRL-C, so we can trap it */
 #       ifndef _POSIX_VDISABLE
 #               define _POSIX_VDISABLE '\0'
 #       endif
-		new_settings.c_cc[VINTR] = _POSIX_VDISABLE;	
+	new_settings.c_cc[VINTR] = _POSIX_VDISABLE;	
 #endif
-	}
-
 	command[0] = 0;
 
 	setTermSettings(0, (void *) &new_settings);
diff --git a/update.c b/update.c
index 603740e..27a04dd 100644
--- a/update.c
+++ b/update.c
@@ -69,9 +69,6 @@
 	if (daemon(0, 1) < 0)
 		perror_msg_and_die("daemon");
 
-	/* Become a proper daemon */
-	setsid();
-	chdir("/");
 #ifdef OPEN_MAX
 	for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
 #else
diff --git a/uudecode.c b/uudecode.c
index 6ac9f1b..a4059dd 100644
--- a/uudecode.c
+++ b/uudecode.c
@@ -201,9 +201,8 @@
                    const char *forced_outname)
 {
   struct passwd *pw;
-  register int n;
   register char *p;
-  int mode, n1;
+  int mode;
   char buf[2 * BUFSIZ];
   char *outname;
   int do_base64 = 0;
@@ -249,12 +248,7 @@
         error_msg("%s: No user `%s'", inname, buf + 1);
         return FALSE;
       }
-      n = strlen (pw->pw_dir);
-      n1 = strlen (p);
-      outname = (char *) xmalloc ((size_t) (n + n1 + 2));
-      memcpy (outname + n + 1, p, (size_t) (n1 + 1));
-      memcpy (outname, pw->pw_dir, (size_t) n);
-      outname[n] = '/';
+      outname = concat_path_file(pw->pw_dir, p);
       dofre = TRUE;
     }
   }