From 51375f969fbdb842aca5cc2270c181a68af505c3 Mon Sep 17 00:00:00 2001
From: "Todd C. Miller" <Todd.Miller@courtesan.com>
Date: Mon, 15 Nov 2004 15:53:53 +0000
Subject: [PATCH] Add local error/warning functions like err/warn but that call
 an additional cleanup routine in the error case.  This means we no longer
 need to compile a special version of alloc.o for visudo.

---
 LICENSE        |   4 +-
 Makefile.in    |  35 ++++------
 alloc.c        |  29 ++++----
 check.c        |   9 +--
 config.h.in    |   3 -
 configure      | 159 ------------------------------------------
 configure.in   |   1 -
 defaults.c     |  43 +++++-------
 emul/err.h     |  69 -------------------
 env.c          |   9 +--
 err.c          | 183 -------------------------------------------------
 error.c        | 133 +++++++++++++++++++++++++++++++++++
 error.h        |  44 ++++++++++++
 find_path.c    |   9 +--
 interfaces.c   |   7 +-
 logging.c      |  13 ++--
 mon_systrace.c |  41 +++++------
 sudo.c         |  60 ++++++++--------
 sudo.h         |   2 +
 sudo_edit.c    |  43 +++++-------
 testsudoers.c  |  15 ++--
 visudo.c       | 156 +++++++++++++----------------------------
 22 files changed, 363 insertions(+), 704 deletions(-)
 delete mode 100644 emul/err.h
 delete mode 100644 err.c
 create mode 100644 error.c
 create mode 100644 error.h

diff --git a/LICENSE b/LICENSE
index 5ecdb0ef8..39c0e8abf 100644
--- a/LICENSE
+++ b/LICENSE
@@ -18,8 +18,8 @@ Sudo is distributed under the following ISC-style license:
    Agency (DARPA) and Air Force Research Laboratory, Air Force
    Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-Additionally, err.c, fnmatch.c, getcwd.c, glob.c, snprintf.c, strcasecmp.c,
-fnmatch.h, glob.h err.h, and fnmatch.3 bear the following UCB license:
+Additionally, fnmatch.c, getcwd.c, glob.c, snprintf.c, strcasecmp.c,
+fnmatch.h, glob.h and fnmatch.3 bear the following UCB license:
 
    Copyright (c) 1987, 1989, 1990, 1991, 1993, 1994
 	The Regents of the University of California.  All rights reserved.
diff --git a/Makefile.in b/Makefile.in
index 6c0846acd..42171b011 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -98,37 +98,36 @@ SHELL = /bin/sh
 
 PROGS = @PROGS@
 
-SRCS = alloc.c alloca.c check.c closefrom.c def_data.c defaults.c env.c err.c \
-       fileops.c find_path.c fnmatch.c getcwd.c getprogname.c getspwuid.c \
-       gettime.c goodpath.c gram.c gram.y interfaces.c ldap.c logging.c \
-       match.c mon_systrace.c parse.c set_perms.c sigaction.c snprintf.c \
-       strcasecmp.c strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c \
-       sudo_edit.c testsudoers.c tgetpass.c toke.c toke.l utimes.c visudo.c \
-       zero_bytes.c redblack.c $(AUTH_SRCS)
+SRCS = alloc.c alloca.c check.c closefrom.c def_data.c defaults.c env.c \
+       error.c fileops.c find_path.c fnmatch.c getcwd.c getprogname.c \
+       getspwuid.c gettime.c goodpath.c gram.c gram.y interfaces.c ldap.c \
+       logging.c match.c mon_systrace.c parse.c set_perms.c sigaction.c \
+       snprintf.c strcasecmp.c strerror.c strlcat.c strlcpy.c sudo.c \
+       sudo_noexec.c sudo_edit.c testsudoers.c tgetpass.c toke.c toke.l \
+       utimes.c visudo.c zero_bytes.c redblack.c $(AUTH_SRCS)
 
 AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
 	    auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
 	    auth/secureware.c auth/securid.c auth/securid5.c auth/sia.c \
 	    auth/sudo_auth.c
 
-HDRS = compat.h def_data.h defaults.h ins_2001.h ins_classic.h ins_csops.h \
-       ins_goons.h insults.h interfaces.h logging.h parse.h sudo.h gram.h \
-       version.h auth/sudo_auth.h emul/err.h emul/fnmatch.h emul/utime.h \
+HDRS = compat.h def_data.h defaults.h error.h ins_2001.h ins_classic.h \
+       ins_csops.h ins_goons.h insults.h interfaces.h logging.h parse.h \
+       sudo.h gram.h version.h auth/sudo_auth.h emul/fnmatch.h emul/utime.h \
        redblack.h
 
 AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
 
-PARSEOBJS = gram.o toke.o match.o defaults.o redblack.o
+PARSEOBJS = error.o alloc.o gram.o toke.o match.o defaults.o redblack.o
 
-SUDOBJS = alloc.o check.o env.o getspwuid.o gettime.o goodpath.o fileops.o \
+SUDOBJS = check.o env.o getspwuid.o gettime.o goodpath.o fileops.o \
 	  find_path.o interfaces.o logging.o parse.o set_perms.o sudo.o \
 	  sudo_edit.o tgetpass.o zero_bytes.o @SUDO_OBJS@ $(AUTH_OBJS) \
 	  $(PARSEOBJS)
 
-VISUDOBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o vsalloc.o \
-	    $(PARSEOBJS)
+VISUDOBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o $(PARSEOBJS)
 
-TESTOBJS = alloc.o interfaces.o testsudoers.o $(PARSEOBJS)
+TESTOBJS = interfaces.o testsudoers.o $(PARSEOBJS)
 
 LIBOBJS = @LIBOBJS@ @ALLOCA@
 
@@ -210,7 +209,7 @@ alloc.o: alloc.c $(SUDODEP)
 check.o: check.c $(SUDODEP)
 closefrom.o: closefrom.c config.h
 env.o: env.c $(SUDODEP)
-err.o: err.c config.h compat.h emul/err.h
+error.o: error.c config.h compat.h error.h
 fileops.o: fileops.c $(SUDODEP)
 find_path.o: find_path.c $(SUDODEP)
 getprogname.o: getprogname.c config.h
@@ -239,10 +238,6 @@ utime.o: utime.c config.h pathnames.h compat.h emul/utime.h
 ldap.o: ldap.c $(SUDODEP) parse.h
 mon_systrace.o: mon_systrace.c $(SUDODEP) mon_systrace.h
 
-# Build special copy of alloc.c for visudo that calls Exit()
-vsalloc.o: alloc.c $(SUDODEP)
-	$(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) '-Derr=Err' '-Derrx=Errx' $(srcdir)/alloc.c
-
 # Authentication functions live in "auth" dir and so need extra care
 sudo_auth.o: $(authdir)/sudo_auth.c $(AUTHDEP) $(INSDEP)
 	$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/sudo_auth.c
diff --git a/alloc.c b/alloc.c
index 7a9360469..d103a8c05 100644
--- a/alloc.c
+++ b/alloc.c
@@ -41,11 +41,6 @@
 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
 # include <malloc.h>
 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 
 #include "sudo.h"
 
@@ -78,10 +73,10 @@ emalloc(size)
     VOID *ptr;
 
     if (size == 0)
-	errx(1, "internal error, tried to emalloc(0)");
+	errorx(1, "internal error, tried to emalloc(0)");
 
     if ((ptr = (VOID *) malloc(size)) == NULL)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -97,13 +92,13 @@ emalloc2(nmemb, size)
     VOID *ptr;
 
     if (nmemb == 0 || size == 0)
-	errx(1, "internal error, tried to emalloc2(0)");
+	errorx(1, "internal error, tried to emalloc2(0)");
     if (nmemb > SIZE_MAX / size)
-	errx(1, "internal error, emalloc2() overflow");
+	errorx(1, "internal error, emalloc2() overflow");
 
     size *= nmemb;
     if ((ptr = (VOID *) malloc(size)) == NULL)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -119,11 +114,11 @@ erealloc(ptr, size)
 {
 
     if (size == 0)
-	errx(1, "internal error, tried to erealloc(0)");
+	errorx(1, "internal error, tried to erealloc(0)");
 
     ptr = ptr ? (VOID *) realloc(ptr, size) : (VOID *) malloc(size);
     if (ptr == NULL)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -141,14 +136,14 @@ erealloc3(ptr, nmemb, size)
 {
 
     if (nmemb == 0 || size == 0)
-	errx(1, "internal error, tried to erealloc3(0)");
+	errorx(1, "internal error, tried to erealloc3(0)");
     if (nmemb > SIZE_MAX / size)
-	errx(1, "internal error, erealloc3() overflow");
+	errorx(1, "internal error, erealloc3() overflow");
 
     size *= nmemb;
     ptr = ptr ? (VOID *) realloc(ptr, size) : (VOID *) malloc(size);
     if (ptr == NULL)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -199,7 +194,7 @@ easprintf(va_alist)
     va_end(ap);
 
     if (len == -1)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(len);
 }
 
@@ -216,6 +211,6 @@ evasprintf(ret, format, args)
     int len;
 
     if ((len = vasprintf(ret, format, args)) == -1)
-	errx(1, "unable to allocate memory");
+	errorx(1, "unable to allocate memory");
     return(len);
 }
diff --git a/check.c b/check.c
index 83bd15b11..511bec004 100644
--- a/check.c
+++ b/check.c
@@ -45,11 +45,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -273,7 +268,7 @@ expand_prompt(old_prompt, user, host)
 
 oflow:
     /* We pre-allocate enough space, so this should never happen. */
-    errx(1, "internal error, expand_prompt() overflow");
+    errorx(1, "internal error, expand_prompt() overflow");
 }
 
 /*
@@ -552,7 +547,7 @@ remove_timestamp(remove)
 	} else {
 	    timespecclear(&ts);
 	    if (touch(-1, path, &ts) == -1)
-		err(1, "can't reset %s to Epoch", path);
+		error(1, "can't reset %s to Epoch", path);
 	}
     }
 
diff --git a/config.h.in b/config.h.in
index e4ebc772c..7935afdde 100644
--- a/config.h.in
+++ b/config.h.in
@@ -88,9 +88,6 @@
 /* Define to 1 if you have the `dispcrypt' function. */
 #undef HAVE_DISPCRYPT
 
-/* Define to 1 if you have the <err.h> header file. */
-#undef HAVE_ERR_H
-
 /* [Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags. */
 #undef HAVE_EXTENDED_GLOB
 
diff --git a/configure b/configure
index d3df0d854..84a4e4422 100755
--- a/configure
+++ b/configure
@@ -24257,165 +24257,6 @@ fi
 
 done
 
-
-for ac_header in err.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
-  echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-else
-  # Is the header compilable?
-echo "$as_me:$LINENO: checking $ac_header usability" >&5
-echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_header_compiler=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_header_compiler=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6
-
-# Is the header present?
-echo "$as_me:$LINENO: checking $ac_header presence" >&5
-echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
-  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
-  ac_header_preproc=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-    (
-      cat <<\_ASBOX
-## ------------------------------- ##
-## Report this to the sudo lists.  ##
-## ------------------------------- ##
-_ASBOX
-    ) |
-      sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-
-fi
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  case $LIBOBJS in
-    "err.$ac_objext"   | \
-  *" err.$ac_objext"   | \
-    "err.$ac_objext "* | \
-  *" err.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS err.$ac_objext" ;;
-esac
-
-fi
-
-done
-
 if test "$OS" != "ultrix"; then
     echo "$as_me:$LINENO: checking POSIX termios" >&5
 echo $ECHO_N "checking POSIX termios... $ECHO_C" >&6
diff --git a/configure.in b/configure.in
index 03ec6d324..3bdd03cfb 100644
--- a/configure.in
+++ b/configure.in
@@ -1628,7 +1628,6 @@ dnl
 AC_HEADER_STDC
 AC_HEADER_DIRENT
 AC_CHECK_HEADERS(malloc.h paths.h utime.h netgroup.h sys/sockio.h sys/bsdtypes.h sys/select.h)
-AC_CHECK_HEADERS(err.h, , [AC_LIBOBJ(err)])
 dnl ultrix termio/termios are broken
 if test "$OS" != "ultrix"; then
     AC_SYS_POSIX_TERMIOS
diff --git a/defaults.c b/defaults.c
index 68101e108..a081e48b2 100644
--- a/defaults.c
+++ b/defaults.c
@@ -42,11 +42,6 @@
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 
 #include "sudo.h"
@@ -234,7 +229,7 @@ set_default(var, val, op)
 	    break;
     }
     if (!cur->name) {
-	warnx("unknown defaults entry `%s'", var);
+	warningx("unknown defaults entry `%s'", var);
 	return(FALSE);
     }
 
@@ -242,18 +237,18 @@ set_default(var, val, op)
 	case T_LOGFAC:
 	    if (!store_syslogfac(val, cur, op)) {
 		if (val)
-		    warnx("value `%s' is invalid for option `%s'", val, var);
+		    warningx("value `%s' is invalid for option `%s'", val, var);
 		else
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		return(FALSE);
 	    }
 	    break;
 	case T_LOGPRI:
 	    if (!store_syslogpri(val, cur, op)) {
 		if (val)
-		    warnx("value `%s' is invalid for option `%s'", val, var);
+		    warningx("value `%s' is invalid for option `%s'", val, var);
 		else
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		return(FALSE);
 	    }
 	    break;
@@ -261,16 +256,16 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (ISSET(cur->type, T_PATH) && val && *val != '/') {
-		warnx("values for `%s' must start with a '/'", var);
+		warningx("values for `%s' must start with a '/'", var);
 		return(FALSE);
 	    }
 	    if (!store_str(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
@@ -278,12 +273,12 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (!store_int(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
@@ -291,12 +286,12 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (!store_uint(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
@@ -304,18 +299,18 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (!store_mode(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
 	case T_FLAG:
 	    if (val) {
-		warnx("option `%s' does not take a value", var);
+		warningx("option `%s' does not take a value", var);
 		return(FALSE);
 	    }
 	    cur->sd_un.flag = op;
@@ -328,12 +323,12 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (!store_list(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
@@ -341,12 +336,12 @@ set_default(var, val, op)
 	    if (!val) {
 		/* Check for bogus boolean usage or lack of a value. */
 		if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-		    warnx("no value specified for `%s'", var);
+		    warningx("no value specified for `%s'", var);
 		    return(FALSE);
 		}
 	    }
 	    if (!store_tuple(val, cur, op)) {
-		warnx("value `%s' is invalid for option `%s'", val, var);
+		warningx("value `%s' is invalid for option `%s'", val, var);
 		return(FALSE);
 	    }
 	    break;
diff --git a/emul/err.h b/emul/err.h
deleted file mode 100644
index 637740b9f..000000000
--- a/emul/err.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)err.h	8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _ERR_H_
-#define	_ERR_H_
-
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 5
-#define __attribute__(x)
-#endif
-
-#ifdef __STDC__
-void	err(int, const char *, ...) __attribute__((__noreturn__));
-void	verr(int, const char *, va_list) __attribute__((__noreturn__));
-void	errx(int, const char *, ...) __attribute__((__noreturn__));
-void	verrx(int, const char *, va_list) __attribute__((__noreturn__));
-void	warn(const char *, ...);
-void	vwarn(const char *, va_list);
-void	warnx(const char *, ...);
-void	vwarnx(const char *, va_list);
-#else
-void	err() __attribute__((__noreturn__));
-void	verr() __attribute__((__noreturn__));
-void	errx() __attribute__((__noreturn__));
-void	verrx() __attribute__((__noreturn__));
-void	warn();
-void	vwarn();
-void	warnx();
-void	vwarnx();
-#endif /* __STDC__ */
-
-#endif /* !_ERR_H_ */
diff --git a/env.c b/env.c
index 2b58707e3..58f3ded33 100644
--- a/env.c
+++ b/env.c
@@ -42,11 +42,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 #include "sudo.h"
@@ -244,7 +239,7 @@ format_env(var, va_alist)
     if (strlcpy(estring, var, esize) >= esize ||
 	strlcat(estring, "=", esize) >= esize) {
 
-	errx(1, "internal error, format_env() overflow");
+	errorx(1, "internal error, format_env() overflow");
     }
 
     /* Now store the variable's value (if any) */
@@ -255,7 +250,7 @@ format_env(var, va_alist)
 #endif
     while ((val = va_arg(ap, char *)) != NULL) {
 	if (strlcat(estring, val, esize) >= esize)
-	    errx(1, "internal error, format_env() overflow");
+	    errorx(1, "internal error, format_env() overflow");
     }
     va_end(ap);
 
diff --git a/err.c b/err.c
deleted file mode 100644
index e9f37abb4..000000000
--- a/err.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)err.c	8.1 (Berkeley) 6/4/93"
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "config.h"
-#include "compat.h"
-#include "emul/err.h"
-
-#ifndef lint
-static const char rcsid[] = "$Sudo$";
-#endif /* lint */
-
-void
-#ifdef __STDC__
-err(int eval, const char *fmt, ...)
-#else
-err(eval, fmt, va_alist)
-	int eval;
-	const char *fmt;
-	va_dcl
-#endif
-{
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	verr(eval, fmt, ap);
-	va_end(ap);
-}
-
-void
-verr(eval, fmt, ap)
-	int eval;
-	const char *fmt;
-	va_list ap;
-{
-	int sverrno;
-
-	sverrno = errno;
-	(void)fprintf(stderr, "%s: ", getprogname());
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-	(void)fprintf(stderr, "%s\n", strerror(sverrno));
-	exit(eval);
-}
-
-void
-#ifdef __STDC__
-errx(int eval, const char *fmt, ...)
-#else
-errx(eval, fmt, va_alist)
-	int eval;
-	const char *fmt;
-	va_dcl
-#endif
-{
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	verrx(eval, fmt, ap);
-	va_end(ap);
-}
-
-void
-verrx(eval, fmt, ap)
-	int eval;
-	const char *fmt;
-	va_list ap;
-{
-	(void)fprintf(stderr, "%s: ", getprogname());
-	if (fmt != NULL)
-		(void)vfprintf(stderr, fmt, ap);
-	(void)fprintf(stderr, "\n");
-	exit(eval);
-}
-
-void
-#ifdef __STDC__
-warn(const char *fmt, ...)
-#else
-warn(fmt, va_alist)
-	const char *fmt;
-	va_dcl
-#endif
-{
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	vwarn(fmt, ap);
-	va_end(ap);
-}
-
-void
-vwarn(fmt, ap)
-	const char *fmt;
-	va_list ap;
-{
-	int sverrno;
-
-	sverrno = errno;
-	(void)fprintf(stderr, "%s: ", getprogname());
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-	(void)fprintf(stderr, "%s\n", strerror(sverrno));
-}
-
-void
-#ifdef __STDC__
-warnx(const char *fmt, ...)
-#else
-warnx(fmt, va_alist)
-	const char *fmt;
-	va_dcl
-#endif
-{
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	vwarnx(fmt, ap);
-	va_end(ap);
-}
-
-void
-vwarnx(fmt, ap)
-	const char *fmt;
-	va_list ap;
-{
-	(void)fprintf(stderr, "%s: ", getprogname());
-	if (fmt != NULL)
-		(void)vfprintf(stderr, fmt, ap);
-	(void)fprintf(stderr, "\n");
-}
diff --git a/error.c b/error.c
new file mode 100644
index 000000000..e70ded711
--- /dev/null
+++ b/error.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "compat.h"
+#include "error.h"
+
+#ifndef lint
+static const char rcsid[] = "$Sudo$";
+#endif /* lint */
+
+static void _warning	__P((int, const char *, va_list));
+       void cleanup	__P((void));
+
+void
+#ifdef __STDC__
+error(int eval, const char *fmt, ...)
+#else
+error(eval, fmt, va_alist)
+	int eval;
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#ifdef __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	_warning(1, fmt, ap);
+	va_end(ap);
+	cleanup();
+	exit(eval);
+}
+
+void
+#ifdef __STDC__
+errorx(int eval, const char *fmt, ...)
+#else
+error(eval, fmt, va_alist)
+	int eval;
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#ifdef __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	_warning(0, fmt, ap);
+	va_end(ap);
+	cleanup();
+	exit(eval);
+}
+
+void
+#ifdef __STDC__
+warning(const char *fmt, ...)
+#else
+warning(fmt, va_alist)
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#ifdef __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	_warning(1, fmt, ap);
+	va_end(ap);
+}
+
+void
+#ifdef __STDC__
+warningx(const char *fmt, ...)
+#else
+warning(fmt, va_alist)
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#ifdef __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	_warning(0, fmt, ap);
+	va_end(ap);
+}
+
+static void
+_warning(use_errno, fmt, ap)
+	int use_errno;
+	const char *fmt;
+	va_list ap;
+{
+	int serrno = errno;
+
+	fputs(getprogname(), stderr);
+	if (fmt != NULL) {
+		fputs(": ", stderr);
+		vfprintf(stderr, fmt, ap);
+	}
+	if (use_errno) {
+	    fputs(": ", stderr);
+	    fputs(strerror(serrno), stderr);
+	}
+	putc('\n', stderr);
+}
diff --git a/error.h b/error.h
new file mode 100644
index 000000000..b42417941
--- /dev/null
+++ b/error.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo$
+ */
+
+#ifndef _SUDO_ERROR_H_
+#define	_SUDO_ERROR_H_
+
+#ifdef __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 5
+#define __attribute__(x)
+#endif
+
+#ifdef __STDC__
+void	error(int, const char *, ...) __attribute__((__noreturn__));
+void	errorx(int, const char *, ...) __attribute__((__noreturn__));
+void	warning(const char *, ...);
+void	warningx(const char *, ...);
+#else
+void	error() __attribute__((__noreturn__));
+void	errorx() __attribute__((__noreturn__));
+void	warning();
+void	warningx();
+#endif /* __STDC__ */
+
+#endif /* _SUDO_ERROR_H_ */
diff --git a/find_path.c b/find_path.c
index 38916c169..3045fd136 100644
--- a/find_path.c
+++ b/find_path.c
@@ -42,11 +42,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 
 #include "sudo.h"
 
@@ -76,7 +71,7 @@ find_path(infile, outfile, sbp, path)
     int len;			/* length parameter */
 
     if (strlen(infile) >= PATH_MAX)
-	errx(1, "%s: File name too long", infile);
+	errorx(1, "%s: File name too long", infile);
 
     /*
      * If we were given a fully qualified or relative path
@@ -118,7 +113,7 @@ find_path(infile, outfile, sbp, path)
 	 */
 	len = snprintf(command, sizeof(command), "%s/%s", path, infile);
 	if (len <= 0 || len >= sizeof(command))
-	    errx(1, "%s: File name too long", infile);
+	    errorx(1, "%s: File name too long", infile);
 	if ((result = sudo_goodpath(command, sbp)))
 	    break;
 
diff --git a/interfaces.c b/interfaces.c
index 7ee1b7cbd..c2fb8349b 100644
--- a/interfaces.c
+++ b/interfaces.c
@@ -59,11 +59,6 @@ struct rtentry;
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <netdb.h>
 #ifdef _ISC
 # include <sys/stream.h>
@@ -176,7 +171,7 @@ load_interfaces()
 
     sock = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock < 0)
-	err(1, "cannot open socket");
+	error(1, "cannot open socket");
 
     /*
      * Get interface configuration or return (leaving num_interfaces == 0)
diff --git a/logging.c b/logging.c
index b99c95eea..381757f64 100644
--- a/logging.c
+++ b/logging.c
@@ -47,11 +47,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 #include <grp.h>
 #include <signal.h>
@@ -399,9 +394,9 @@ log_error(va_alist)
      */
     if (!ISSET(flags, NO_STDERR)) {
 	if (ISSET(flags, USE_ERRNO))
-	    warn("%s", message);
+	    warning("%s", message);
 	else
-	    warnx("%s", message);
+	    warningx("%s", message);
     }
 
     /*
@@ -459,12 +454,12 @@ send_mail(line)
     (void) sigprocmask(SIG_BLOCK, &set, &oset);
 
     if (pipe(pfd) == -1)
-	err(1, "cannot open pipe");
+	error(1, "cannot open pipe");
 
     switch (pid = fork()) {
 	case -1:
 	    /* Error. */
-	    err(1, "cannot fork");
+	    error(1, "cannot fork");
 	    break;
 	case 0:
 	    {
diff --git a/mon_systrace.c b/mon_systrace.c
index c7f727df9..a1d55fdc1 100644
--- a/mon_systrace.c
+++ b/mon_systrace.c
@@ -27,11 +27,6 @@
 #include <pwd.h>
 #include <signal.h>
 #include <fcntl.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #ifdef HAVE_DEV_SYSTRACE_H
 # include <dev/systrace.h>
 #else
@@ -110,7 +105,7 @@ systrace_attach(pid)
     int fd, cookie;
 
     if ((fd = systrace_open()) == -1)
-	err(1, "unable to open systrace");
+	error(1, "unable to open systrace");
     fflush(stdout);
 
     /*
@@ -119,16 +114,16 @@ systrace_attach(pid)
      */ 
     sigfillset(&set);
     if (sigprocmask(SIG_BLOCK, &set, &oset) != 0)
-	err(1, "sigprocmask");
+	error(1, "sigprocmask");
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     sa.sa_handler = catchsig;
     if (sigaction(SIGUSR1, &sa, &osa) != 0)
-	err(1, "sigaction");
+	error(1, "sigaction");
 
     switch (fork()) {
     case -1:
-	err(1, "can't fork");
+	error(1, "can't fork");
     case 0:
 	/* tracer */
 	break;
@@ -138,7 +133,7 @@ systrace_attach(pid)
 	sigdelset(&set, SIGUSR1);
 	(void) sigsuspend(&set);
 	if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) {
-	    warn("sigprocmask");
+	    warning("sigprocmask");
 	    exit(1);
 	}
 	return;
@@ -154,14 +149,14 @@ systrace_attach(pid)
 	sigaction(SIGINT, &sa, NULL) != 0 ||
 	sigaction(SIGTERM, &sa, NULL) != 0 ||
 	sigprocmask(SIG_SETMASK, &oset, NULL) != 0) {
-	warn("unable to setup signals for %s", user_cmnd);
+	warning("unable to setup signals for %s", user_cmnd);
 	goto fail;
     }
 
     /* become a daemon */
     set_perms(PERM_FULL_ROOT);
     if (setsid() == -1) {
-	warn("setsid");
+	warning("setsid");
 	kill(pid, SIGKILL);
 	_exit(1);
     }
@@ -177,18 +172,18 @@ systrace_attach(pid)
 	    (void) kill(pid, SIGUSR1);
 	    _exit(0);
 	}
-	warn("unable to systrace %s", user_cmnd);
+	warning("unable to systrace %s", user_cmnd);
 	goto fail;
     }
 
     new_child(-1, pid);
     if (set_policy(fd, children.first) != 0) {
-	warn("failed to set policy for %s", user_cmnd);
+	warning("failed to set policy for %s", user_cmnd);
 	goto fail;
     }
 
     if (kill(pid, SIGUSR1) != 0) {
-	warn("unable to wake up sleeping child");
+	warning("unable to wake up sleeping child");
 	_exit(1);
     }
 
@@ -259,7 +254,7 @@ systrace_attach(pid)
 		if (switch_emulation(fd, &msg) == 0)
 		    ans.stra_policy = SYSTR_POLICY_PERMIT;
 		else {
-		    warnx("unsupported emulation \"%s\"",
+		    warningx("unsupported emulation \"%s\"",
 			msg.msg_data.msg_emul.emul);
 		    ans.stra_policy = SYSTR_POLICY_NEVER;
 		}
@@ -273,7 +268,7 @@ systrace_attach(pid)
 
 	    default:
 #ifdef SUDO_DEVEL
-		warnx("unexpected message type %d", msg.msg_type);
+		warningx("unexpected message type %d", msg.msg_type);
 #endif
 		memset(&ans, 0, sizeof(ans));
 		ans.stra_pid = msg.msg_pid;
@@ -314,7 +309,7 @@ new_child(ppid, pid)
 		break;
 	    }
 	if (emul == NULL)
-	    errx(1, "unable to find native emulation!");
+	    errorx(1, "unable to find native emulation!");
     }
     entry = (struct childinfo *) emalloc(sizeof(*entry));
     entry->pid = pid;
@@ -507,7 +502,7 @@ find_handler(pid, code)
     struct childinfo *child;
 
     if ((child = find_child(pid)) == NULL) {
-	warnx("unable to find child with pid %d", pid);
+	warningx("unable to find child with pid %d", pid);
 	return(NULL);
     }
     for (sca = child->action; sca->code != -1; sca++) {
@@ -572,7 +567,7 @@ update_env(fd, pid, seqnr, askp)
     envep = envbuf + (sizeof(envbuf) / sizeof(char *));
     for (envp = envbuf; envp < envep; envp++, off += sizeof(char *)) {
 	if (systrace_read(fd, pid, off, &ap, sizeof(ap)) != 0) {
-	    warn("STRIOCIO");
+	    warning("STRIOCIO");
 	    return(-1);
 	}
 	if ((*envp = ap) == NULL)
@@ -703,7 +698,7 @@ update_env(fd, pid, seqnr, askp)
 		    continue;
 		ap = inject.stri_addr + (replace[n] - buf);
 		if (systrace_write(fd, pid, offsets[n], &ap, sizeof(ap)) != 0) {
-		    warn("STRIOCIO");
+		    warning("STRIOCIO");
 		    return(-1);
 		}
 	    }
@@ -782,7 +777,7 @@ decode_args(fd, pid, askp)
     off = (char *)askp->args[1];
     for (cp = abuf, ep = abuf + sizeof(abuf); cp < ep; off += sizeof(char *)) {
 	if (systrace_read(fd, pid, off, &ap, sizeof(ap)) != 0) {
-	    warn("STRIOCIO");
+	    warning("STRIOCIO");
 	    return(-1);
 	}
 	if (ap == NULL) {
@@ -848,7 +843,7 @@ check_execv(fd, pid, seqnr, askp, cookie, policyp, errorp)
     /* Get processes's cwd. */
     error = ioctl(fd, STRIOCGETCWD, &pid);
     if (error == -1 || !getcwd(user_cwd, sizeof(user_cwd))) {
-	warnx("cannot get working directory");
+	warningx("cannot get working directory");
 	(void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
     }
 
diff --git a/sudo.c b/sudo.c
index b4d6f8d21..5c8438dba 100644
--- a/sudo.c
+++ b/sudo.c
@@ -59,11 +59,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -177,7 +172,7 @@ main(argc, argv, envp)
     environ = zero_env(envp);
 
     if (geteuid() != 0)
-	errx(1, "must be setuid root");
+	errorx(1, "must be setuid root");
 
     /*
      * Signal setup:
@@ -356,10 +351,10 @@ main(argc, argv, envp)
     if (ISSET(validated, VALIDATE_OK)) {
 	/* Finally tell the user if the command did not exist. */
 	if (cmnd_status == NOT_FOUND_DOT) {
-	    warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
+	    warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
 	    exit(1);
 	} else if (cmnd_status == NOT_FOUND) {
-	    warnx("%s: command not found", user_cmnd);
+	    warningx("%s: command not found", user_cmnd);
 	    exit(1);
 	}
 
@@ -418,7 +413,7 @@ main(argc, argv, envp)
 
 	    /* Change to target user's homedir. */
 	    if (chdir(runas_pw->pw_dir) == -1)
-		warn("unable to change directory to %s", runas_pw->pw_dir);
+		warning("unable to change directory to %s", runas_pw->pw_dir);
 	}
 
 	if (ISSET(sudo_mode, MODE_EDIT))
@@ -441,7 +436,7 @@ main(argc, argv, envp)
 	/*
 	 * If we got here then the exec() failed...
 	 */
-	warn("unable to execute %s", safe_cmnd);
+	warning("unable to execute %s", safe_cmnd);
 	exit(127);
     } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
 	log_auth(validated, 1);
@@ -458,9 +453,9 @@ main(argc, argv, envp)
 	    log_auth(validated,
 		!(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
 	    if (cmnd_status == NOT_FOUND)
-		warnx("%s: command not found", user_cmnd);
+		warningx("%s: command not found", user_cmnd);
 	    else if (cmnd_status == NOT_FOUND_DOT)
-		warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
+		warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
 	} else {
 	    /* Just tell the user they are not allowed to run foo. */
 	    log_auth(validated, 1);
@@ -487,7 +482,7 @@ init_vars(sudo_mode)
 
     /* Sanity check command from user. */
     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
-	errx(1, "%s: File name too long", NewArgv[0]);
+	errorx(1, "%s: File name too long", NewArgv[0]);
 
 #ifdef HAVE_TZSET
     (void) tzset();		/* set the timezone if applicable */
@@ -552,7 +547,7 @@ init_vars(sudo_mode)
 	 * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
 	 */
 	if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
-	    errx(1, "uid %s does not exist in the passwd file!", pw_name);
+	    errorx(1, "uid %s does not exist in the passwd file!", pw_name);
 	log_error(0, "uid %s does not exist in the passwd file!", pw_name);
     }
     if (user_shell == NULL || *user_shell == '\0')
@@ -577,7 +572,7 @@ init_vars(sudo_mode)
     if (!getcwd(user_cwd, sizeof(user_cwd))) {
 	set_perms(PERM_ROOT);
 	if (!getcwd(user_cwd, sizeof(user_cwd))) {
-	    warnx("cannot get working directory");
+	    warningx("cannot get working directory");
 	    (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
 	}
     } else
@@ -598,7 +593,7 @@ init_vars(sudo_mode)
 	else if (user_shell && *user_shell)
 	    NewArgv[0] = user_shell;
 	else
-	    errx(1, "unable to determine shell");
+	    errorx(1, "unable to determine shell");
 
 	/* copy the args from NewArgv */
 	for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
@@ -653,7 +648,7 @@ set_cmnd(sudo_mode)
 	    for (to = user_args, from = NewArgv + 1; *from; from++) {
 		n = strlcpy(to, *from, size - (to - user_args));
 		if (n >= size - (to - user_args))
-		    errx(1, "internal error, init_vars() overflow");
+		    errorx(1, "internal error, init_vars() overflow");
 		to += n;
 		*to++ = ' ';
 	    }
@@ -696,7 +691,7 @@ parse_args(argc, argv)
 
     while (NewArgc > 0 && NewArgv[0][0] == '-') {
 	if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
-	    warnx("please use single character options");
+	    warningx("please use single character options");
 
 	switch (NewArgv[0][1]) {
 	    case 'p':
@@ -824,10 +819,10 @@ parse_args(argc, argv)
 		    SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
 		return(rval);
 	    case '\0':
-		warnx("'-' requires an argument");
+		warningx("'-' requires an argument");
 		usage(1);
 	    default:
-		warnx("illegal option `%s'", NewArgv[0]);
+		warningx("illegal option `%s'", NewArgv[0]);
 		usage(1);
 	}
 	NewArgc--;
@@ -837,10 +832,10 @@ parse_args(argc, argv)
     if (user_runas != NULL) {
 	if (rval == MODE_LIST) {
 	    if ((list_pw = sudo_getpwnam(*user_runas)) == NULL)
-		errx(1, "unknown user %s", *user_runas);
+		errorx(1, "unknown user %s", *user_runas);
 	    user_runas = NULL;
 	} else if (!ISSET(rval, (MODE_EDIT|MODE_RUN))) {
-	    warnx("the `-u' and '-%c' options may not be used together", excl);
+	    warningx("the `-u' and '-%c' options may not be used together", excl);
 	    usage(1);
 	}
     }
@@ -874,17 +869,17 @@ open_sudoers(sudoers, keepopen)
 	(statbuf.st_mode & 0007777) == 0400) {
 
 	if (chmod(sudoers, SUDOERS_MODE) == 0) {
-	    warnx("fixed mode on %s", sudoers);
+	    warningx("fixed mode on %s", sudoers);
 	    SET(statbuf.st_mode, SUDOERS_MODE);
 	    if (statbuf.st_gid != SUDOERS_GID) {
 		if (!chown(sudoers, (uid_t) -1, SUDOERS_GID)) {
-		    warnx("set group on %s", sudoers);
+		    warningx("set group on %s", sudoers);
 		    statbuf.st_gid = SUDOERS_GID;
 		} else
-		    warn("unable to set group on %s", sudoers);
+		    warning("unable to set group on %s", sudoers);
 	    }
 	} else
-	    warn("unable to fix mode on %s", sudoers);
+	    warning("unable to fix mode on %s", sudoers);
     }
 
     /*
@@ -973,7 +968,7 @@ set_loginclass(pw)
 
     if (login_class && strcmp(login_class, "-") != 0) {
 	if (strcmp(*user_runas, "root") != 0 && user_uid != 0)
-	    errx(1, "only root can use -c %s", login_class);
+	    errorx(1, "only root can use -c %s", login_class);
     } else {
 	login_class = pw->pw_class;
 	if (!login_class || !*login_class)
@@ -1073,6 +1068,15 @@ get_authpw()
     return(pw);
 }
 
+/*
+ * Stub for error()/errorx()
+ */
+void
+cleanup()
+{
+    return;
+}
+
 /*
  * Tell which options are mutually exclusive and exit.
  */
@@ -1080,7 +1084,7 @@ static void
 usage_excl(exit_val)
     int exit_val;
 {
-    warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
+    warningx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
     usage(exit_val);
 }
 
diff --git a/sudo.h b/sudo.h
index d06c42f39..5f5c0c70c 100644
--- a/sudo.h
+++ b/sudo.h
@@ -26,6 +26,7 @@
 #include <pathnames.h>
 #include <limits.h>
 #include "compat.h"
+#include "error.h"
 #include "defaults.h"
 #include "logging.h"
 
@@ -239,6 +240,7 @@ FILE *open_sudoers	__P((const char *, int *));
 void display_privs      __P((struct passwd *));
 void sudo_setpwent	__P((void));
 void sudo_endpwent	__P((void));
+void cleanup		__P((void));
 #ifdef HAVE_SYSTRACE
 void systrace_attach	__P((pid_t));
 #endif
diff --git a/sudo_edit.c b/sudo_edit.c
index f335d2105..d8d136e49 100644
--- a/sudo_edit.c
+++ b/sudo_edit.c
@@ -41,11 +41,6 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
 #include <signal.h>
@@ -122,9 +117,9 @@ int sudo_edit(argc, argv)
 	set_perms(PERM_ROOT);
 	if (error || !S_ISREG(sb.st_mode)) {
 	    if (error)
-		warn("%s", *ap);
+		warning("%s", *ap);
 	    else
-		warnx("%s: not a regular file", *ap);
+		warningx("%s: not a regular file", *ap);
 	    if (ofd != -1)
 		close(ofd);
 	    argc--;
@@ -144,16 +139,16 @@ int sudo_edit(argc, argv)
 	tfd = mkstemp(tf[i].tfile);
 	set_perms(PERM_ROOT);
 	if (tfd == -1) {
-	    warn("mkstemp");
+	    warning("mkstemp");
 	    goto cleanup;
 	}
 	if (ofd != -1) {
 	    while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
 		if ((nwritten = write(tfd, buf, nread)) != nread) {
 		    if (nwritten == -1)
-			warn("%s", tf[i].tfile);
+			warning("%s", tf[i].tfile);
 		    else
-			warnx("%s: short write", tf[i].tfile);
+			warningx("%s: short write", tf[i].tfile);
 		    goto cleanup;
 		}
 	    }
@@ -225,7 +220,7 @@ int sudo_edit(argc, argv)
     gettime(&ts1);
     kidpid = fork();
     if (kidpid == -1) {
-	warn("fork");
+	warning("fork");
 	goto cleanup;
     } else if (kidpid == 0) {
 	/* child */
@@ -234,7 +229,7 @@ int sudo_edit(argc, argv)
 	(void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
 	set_perms(PERM_FULL_USER);
 	execvp(nargv[0], nargv);
-	warn("unable to execute %s", nargv[0]);
+	warning("unable to execute %s", nargv[0]);
 	_exit(127);
     }
 
@@ -278,10 +273,10 @@ int sudo_edit(argc, argv)
 	set_perms(PERM_ROOT);
 	if (error || !S_ISREG(sb.st_mode)) {
 	    if (error)
-		warn("%s", tf[i].tfile);
+		warning("%s", tf[i].tfile);
 	    else
-		warnx("%s: not a regular file", tf[i].tfile);
-	    warnx("%s left unmodified", tf[i].ofile);
+		warningx("%s: not a regular file", tf[i].tfile);
+	    warningx("%s left unmodified", tf[i].ofile);
 	    if (tfd != -1)
 		close(tfd);
 	    continue;
@@ -294,7 +289,7 @@ int sudo_edit(argc, argv)
 	     */
 	    timespecsub(&ts1, &ts2, &ts2);
 	    if (timespecisset(&ts2)) {
-		warnx("%s unchanged", tf[i].ofile);
+		warningx("%s unchanged", tf[i].ofile);
 		unlink(tf[i].tfile);
 		close(tfd);
 		continue;
@@ -304,17 +299,17 @@ int sudo_edit(argc, argv)
 	ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
 	set_perms(PERM_ROOT);
 	if (ofd == -1) {
-	    warn("unable to write to %s", tf[i].ofile);
-	    warnx("contents of edit session left in %s", tf[i].tfile);
+	    warning("unable to write to %s", tf[i].ofile);
+	    warningx("contents of edit session left in %s", tf[i].tfile);
 	    close(tfd);
 	    continue;
 	}
 	while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
 	    if ((nwritten = write(ofd, buf, nread)) != nread) {
 		if (nwritten == -1)
-		    warn("%s", tf[i].ofile);
+		    warning("%s", tf[i].ofile);
 		else
-		    warnx("%s: short write", tf[i].ofile);
+		    warningx("%s: short write", tf[i].ofile);
 		break;
 	    }
 	}
@@ -322,11 +317,11 @@ int sudo_edit(argc, argv)
 	    /* success, got EOF */
 	    unlink(tf[i].tfile);
 	} else if (nread < 0) {
-	    warn("unable to read temporary file");
-	    warnx("contents of edit session left in %s", tf[i].tfile);
+	    warning("unable to read temporary file");
+	    warningx("contents of edit session left in %s", tf[i].tfile);
 	} else {
-	    warn("unable to write to %s", tf[i].ofile);
-	    warnx("contents of edit session left in %s", tf[i].tfile);
+	    warning("unable to write to %s", tf[i].ofile);
+	    warningx("contents of edit session left in %s", tf[i].tfile);
 	}
 	close(ofd);
     }
diff --git a/testsudoers.c b/testsudoers.c
index a12df6121..055fa2bbd 100644
--- a/testsudoers.c
+++ b/testsudoers.c
@@ -53,11 +53,6 @@
 #ifdef HAVE_NETGROUP_H
 # include <netgroup.h>
 #endif /* HAVE_NETGROUP_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
@@ -161,7 +156,7 @@ main(argc, argv)
 
     if (user_host == NULL) {
 	if (gethostname(hbuf, sizeof(hbuf)) != 0)
-	    err(1, "gethostname");
+	    error(1, "gethostname");
 	user_host = hbuf;
     }
     if ((p = strchr(user_host, '.'))) {
@@ -183,7 +178,7 @@ main(argc, argv)
 	for (to = user_args, from = NewArgv + 1; *from; from++) {
 	    n = strlcpy(to, *from, size - (to - user_args));
 	    if (n >= size - (to - user_args))
-		    errx(1, "internal error, init_vars() overflow");
+		    errorx(1, "internal error, init_vars() overflow");
 	    to += n;
 	    *to++ = ' ';
 	}
@@ -280,6 +275,12 @@ set_perms(perm)
     return;
 }
 
+void
+cleanup()
+{
+    return;
+}
+
 void
 print_member(m)    
     struct member *m;
diff --git a/visudo.c b/visudo.c
index c6533f165..cb4248df1 100644
--- a/visudo.c
+++ b/visudo.c
@@ -58,11 +58,6 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
 #include <time.h>
@@ -100,7 +95,7 @@ struct sudoersfile {
 /*
  * Function prototypes
  */
-static RETSIGTYPE Exit		__P((int)) __attribute__((__noreturn__));
+static RETSIGTYPE quit		__P((int)) __attribute__((__noreturn__));
 static char *get_editor		__P((void));
 static char whatnow		__P((void));
 static int check_aliases	__P((int));
@@ -116,10 +111,6 @@ static void usage		__P((void)) __attribute__((__noreturn__));
 
 void yyerror			__P((const char *));
 void yyrestart			__P((FILE *));
-void Err			__P((int, const char *, ...))
-				    __attribute__((__noreturn__));
-void Errx			__P((int, const char *, ...))
-				    __attribute__((__noreturn__));
 
 /*
  * External globals exported by the parser
@@ -193,7 +184,7 @@ main(argc, argv)
     /* Mock up a fake sudo_user struct. */
     user_host = user_shost = user_cmnd = "";
     if ((sudo_user.pw = getpwuid(getuid())) == NULL)
-	Errx(1, "you don't exist in the passwd database");
+	errorx(1, "you don't exist in the passwd database");
 
     /* Setup defaults data structures. */
     init_defaults();
@@ -206,9 +197,9 @@ main(argc, argv)
      * existing errors and to pull in editor and env_editor conf values.
      */
     if ((yyin = open_sudoers(sudoers_path, NULL)) == NULL)
-	Err(1, "%s", sudoers_path);
+	error(1, "%s", sudoers_path);
     if (!lock_file(fileno(yyin), SUDO_TLOCK))
-	Errx(1, "%s busy, try again later", sudoers_path);
+	errorx(1, "%s busy, try again later", sudoers_path);
     init_parser(sudoers_path, 0);
     yyparse();
     (void) update_defaults();
@@ -268,7 +259,7 @@ edit_sudoers(sp, editor, lineno)
 #else
     if (stat(sp->path, &sb) == -1)
 #endif
-	Err(1, "can't stat %s", sp->path);
+	error(1, "can't stat %s", sp->path);
     orig_size = sb.st_size;
     orig_mtim.tv_sec = mtim_getsec(sb);
     orig_mtim.tv_nsec = mtim_getnsec(sb);
@@ -278,14 +269,14 @@ edit_sudoers(sp, editor, lineno)
 	easprintf(&sp->tpath, "%s.tmp", sp->path);
 	tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 	if (tfd < 0)
-	    Err(1, "%s", sp->tpath);
+	    error(1, "%s", sp->tpath);
 
 	/* Copy sp->path -> sp->tpath and reset the mtime. */
 	if (orig_size != 0) {
 	    (void) lseek(sp->fd, (off_t)0, SEEK_SET);
 	    while ((n = read(sp->fd, buf, sizeof(buf))) > 0)
 		if (write(tfd, buf, n) != n)
-		    Err(1, "write error");
+		    error(1, "write error");
 
 	    /* Add missing newline at EOF if needed. */
 	    if (n > 0 && buf[n - 1] != '\n') {
@@ -323,18 +314,18 @@ edit_sudoers(sp, editor, lineno)
 	 * Sanity checks.
 	 */
 	if (stat(sp->tpath, &sb) < 0) {
-	    warnx("cannot stat temporary file (%s), %s unchanged",
+	    warningx("cannot stat temporary file (%s), %s unchanged",
 		sp->tpath, sp->path);
 	    return(FALSE);
 	}
 	if (sb.st_size == 0 && orig_size != 0) {
-	    warnx("zero length temporary file (%s), %s unchanged",
+	    warningx("zero length temporary file (%s), %s unchanged",
 		sp->tpath, sp->path);
 	    sp->modified = TRUE;
 	    return(FALSE);
 	}
     } else {
-	warnx("editor (%s) failed, %s unchanged", editor, sp->path);
+	warningx("editor (%s) failed, %s unchanged", editor, sp->path);
 	return(FALSE);
     }
 
@@ -358,7 +349,7 @@ edit_sudoers(sp, editor, lineno)
     if (modified)
 	sp->modified = modified;
     else
-	warnx("%s unchanged", sp->tpath);
+	warningx("%s unchanged", sp->tpath);
 
     return(TRUE);
 }
@@ -383,11 +374,9 @@ reparse_sudoers(editor, strict, quiet)
 	sp = sudoerslist.first;
 	last = sudoerslist.last;
 	fp = fopen(sp->tpath, "r+");
-	if (fp == NULL) {
-	    warnx("can't re-open temporary file (%s), %s unchanged.",
+	if (fp == NULL)
+	    errorx(1, "can't re-open temporary file (%s), %s unchanged.",
 		sp->tpath, sp->path);
-	    Exit(-1);
-	}
 
 	/* Clean slate for each parse */
 	user_runas = NULL;
@@ -397,7 +386,7 @@ reparse_sudoers(editor, strict, quiet)
 	/* Parse the sudoers temp file */
 	yyrestart(fp);
 	if (yyparse() && parse_error != TRUE) {
-	    warnx("unabled to parse temporary file (%s), unknown error",
+	    warningx("unabled to parse temporary file (%s), unknown error",
 		sp->tpath);
 	    parse_error = TRUE;
 	}
@@ -412,7 +401,8 @@ reparse_sudoers(editor, strict, quiet)
 	    switch (whatnow()) {
 		case 'Q' :	parse_error = FALSE;	/* ignore parse error */
 				break;
-		case 'x' :	Exit(0);
+		case 'x' :	cleanup();
+				exit(0);
 				break;
 	    }
 	}
@@ -425,7 +415,7 @@ reparse_sudoers(editor, strict, quiet)
 		}
 	    }
 	    if (sp == NULL)
-		Errx(1, "internal error, can't find %s in list!", sudoers);
+		errorx(1, "internal error, can't find %s in list!", sudoers);
 	}
 
 	/* If any new #include directives were added, edit them too. */
@@ -453,12 +443,12 @@ install_sudoers(sp)
      * we move it to sp->path things are kosher.
      */
     if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) {
-	warn("unable to set (uid, gid) of %s to (%d, %d)",
+	warning("unable to set (uid, gid) of %s to (%d, %d)",
 	    sp->tpath, SUDOERS_UID, SUDOERS_GID);
 	return(FALSE);
     }
     if (chmod(sp->tpath, SUDOERS_MODE) != 0) {
-	warn("unable to change mode of %s to 0%o", sp->tpath, SUDOERS_MODE);
+	warning("unable to change mode of %s to 0%o", sp->tpath, SUDOERS_MODE);
 	return(FALSE);
     }
 
@@ -473,7 +463,7 @@ install_sudoers(sp)
     } else {
 	if (errno == EXDEV) {
 	    char *av[4];
-	    warnx("%s and %s not on the same file system, using mv to rename",
+	    warningx("%s and %s not on the same file system, using mv to rename",
 	      sp->tpath, sp->path);
 
 	    /* Build up argument vector for the command */
@@ -487,7 +477,7 @@ install_sudoers(sp)
 
 	    /* And run it... */
 	    if (run_command(_PATH_MV, av)) {
-		warnx("command failed: '%s %s %s', %s unchanged",
+		warningx("command failed: '%s %s %s', %s unchanged",
 		    _PATH_MV, sp->tpath, sp->path, sp->path);
 		(void) unlink(sp->tpath);
 		free(sp->tpath);
@@ -497,7 +487,7 @@ install_sudoers(sp)
 	    free(sp->tpath);
 	    sp->tpath = NULL;
 	} else {
-	    warn("error renaming %s, %s unchanged", sp->tpath, sp->path);
+	    warning("error renaming %s, %s unchanged", sp->tpath, sp->path);
 	    (void) unlink(sp->tpath);
 	    return(FALSE);
 	}
@@ -579,7 +569,7 @@ setup_signals()
 	 */
 	sigemptyset(&sa.sa_mask);
 	sa.sa_flags = SA_RESTART;
-	sa.sa_handler = Exit;
+	sa.sa_handler = quit;
 	(void) sigaction(SIGTERM, &sa, NULL);
 	(void) sigaction(SIGHUP, &sa, NULL);
 	(void) sigaction(SIGINT, &sa, NULL);
@@ -601,13 +591,12 @@ run_command(path, argv)
 
     switch (pid = fork()) {
 	case -1:
-	    warn("unable to run %s", path);
-	    Exit(-1);
+	    error(1, "unable to run %s", path);
 	    break;	/* NOTREACHED */
 	case 0:
 	    (void) sigprocmask(SIG_SETMASK, &oset, NULL);
 	    execv(path, argv);
-	    warn("unable to run %s", path);
+	    warning("unable to run %s", path);
 	    _exit(127);
 	    break;	/* NOTREACHED */
     }
@@ -633,13 +622,13 @@ check_syntax(sudoers_path, quiet)
 
     if ((yyin = fopen(sudoers_path, "r")) == NULL) {
 	if (!quiet)
-	    warn("unable to open %s", sudoers_path);
+	    warning("unable to open %s", sudoers_path);
 	exit(1);
     }
     init_parser(sudoers_path, quiet);
     if (yyparse() && parse_error != TRUE) {
 	if (!quiet)
-	    warnx("failed to parse %s file, unknown error", sudoers_path);
+	    warningx("failed to parse %s file, unknown error", sudoers_path);
 	parse_error = TRUE;
     }
     if (!quiet){
@@ -674,14 +663,14 @@ open_sudoers(path, keepopen)
 	entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE);
 	entry->tpath = NULL;
 	if (entry->fd == -1) {
-	    warn("%s", entry->path);
+	    warning("%s", entry->path);
 	    free(entry);
 	    return(NULL);
 	}
 	if (!lock_file(entry->fd, SUDO_TLOCK))
-	    Errx(1, "%s busy, try again later", entry->path);
+	    errorx(1, "%s busy, try again later", entry->path);
 	if ((fp = fdopen(entry->fd, "r")) == NULL)
-	    Err(1, "%s", entry->path);
+	    error(1, "%s", entry->path);
 	if (sudoerslist.last == NULL)
 	    sudoerslist.first = sudoerslist.last = entry;
 	else {
@@ -694,10 +683,10 @@ open_sudoers(path, keepopen)
 	/* Already exists, open .tmp version if there is one. */
 	if (entry->tpath != NULL) {
 	    if ((fp = fopen(entry->tpath, "r")) == NULL)
-		Err(1, "%s", entry->tpath);
+		error(1, "%s", entry->tpath);
 	} else {
 	    if ((fp = fdopen(entry->fd, "r")) == NULL)
-		Err(1, "%s", entry->path);
+		error(1, "%s", entry->path);
 	}
     }
     return(fp);
@@ -724,8 +713,7 @@ get_editor()
 	} else {
 	    if (def_env_editor) {
 		/* If we are honoring $EDITOR this is a fatal error. */
-		warnx("specified editor (%s) doesn't exist!", UserEditor);
-		Exit(-1);
+		errorx(1, "specified editor (%s) doesn't exist!", UserEditor);
 	    } else {
 		/* Otherwise, just ignore $EDITOR. */
 		UserEditor = NULL;
@@ -747,8 +735,7 @@ get_editor()
 
 	if (stat(UserEditor, &user_editor_sb) != 0) {
 	    /* Should never happen since we already checked above. */
-	    warn("unable to stat editor (%s)", UserEditor);
-	    Exit(-1);
+	    error(1, "unable to stat editor (%s)", UserEditor);
 	}
 	EditorPath = estrdup(def_editor);
 	Editor = strtok(EditorPath, ":");
@@ -794,10 +781,8 @@ get_editor()
 	} while ((Editor = strtok(NULL, ":")));
 
 	/* Bleah, none of the editors existed! */
-	if (Editor == NULL || *Editor == '\0') {
-	    warnx("no editor found (editor path = %s)", def_editor);
-	    Exit(-1);
-	}
+	if (Editor == NULL || *Editor == '\0')
+	    errorx(1, "no editor found (editor path = %s)", def_editor);
     }
     return(Editor);
 }
@@ -906,13 +891,10 @@ print_unused(v1, v2)
 }
 
 /*
- * Unlink the sudoers temp file (if it exists) and exit.
- * Used in place of a normal exit() and as a signal handler.
- * A positive parameter indicates we were called as a signal handler.
+ * Unlink any sudoers temp files that remain.
  */
-static RETSIGTYPE
-Exit(sig)
-    int sig;
+void
+cleanup()
 {
     struct sudoersfile *sp;
 
@@ -920,62 +902,20 @@ Exit(sig)
 	if (sp->tpath != NULL)
 	    (void) unlink(sp->tpath);
     }
-
-#define	emsg	 " exiting due to signal.\n"
-    if (sig > 0) {
-	write(STDERR_FILENO, getprogname(), strlen(getprogname()));
-	write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
-	_exit(sig);
-    }
-    exit(-sig);
 }
 
 /*
- * Like err() but calls Exit()
+ * Unlink sudoers temp files (if any) and exit.
  */
-void
-#ifdef __STDC__
-Err(int eval, const char *fmt, ...)
-#else
-Err(eval, fmt, va_alist)
-	int eval;
-	const char *fmt;
-	va_dcl
-#endif
-{
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	vwarn(fmt, ap);
-	va_end(ap);
-	Exit(-eval);
-}
-
-/*
- * Like errx() but calls Exit()
- */
-void
-#ifdef __STDC__
-Errx(int eval, const char *fmt, ...)
-#else
-Errx(eval, fmt, va_alist)
-	int eval;
-	const char *fmt;
-	va_dcl
-#endif
+static RETSIGTYPE
+quit(signo)
+    int signo;
 {
-	va_list ap;
-#ifdef __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
-	vwarnx(fmt, ap);
-	va_end(ap);
-	Exit(-eval);
+    cleanup();
+#define	emsg	 " exiting due to signal.\n"
+    write(STDERR_FILENO, getprogname(), strlen(getprogname()));
+    write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
+    _exit(signo);
 }
 
 static void
-- 
2.40.0