Subject: bug#18428: Bug#760861: bug#18428: coreutils binary breaks coreutils documentation

From: Paul Eggert <[email-masked]>
Date: Mon, 08 Sep 2014 20:55:23 -0700

Pádraig Brady wrote:
> So we'll stick with the longer form
> (which is likely to be cut n pasted in any case)

While this sounds like a win, I still like the idea of renaming the 
troublesome info node, as there is a lot of advice out there to use the 
old forms for 'info' and it's probably better to support that advice, at 
least for a while, than to make it immediately stop working.

I noticed other problems that are at least somewhat related to the 
recent coreutils multi-binary executable changes, and fixed some of 
these problems with the attached patches.  (I ran out of energy before 
fixing the rest.  :-)  Patch 2 renames the troublesome node.

Come to think of it, how about removing the 'coreutils' command 
entirely?  Why should users invoke 'coreutils' directly?  We could move 
it to libexec and remove it from the documentation.
From 2f40bf03ecb3637625cec578371f23dcae8fc1af Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 8 Sep 2014 11:40:39 -0700
Subject: [PATCH 1/4] doc: mention which commands are optional

* doc/coreutils.texi (coreutils invocation, df invocation)
(stty invocation, whoami invocation, nproc invocation)
(arch invocation, hostname invocation, hostid invocation)
(uptime invocation, chroot invocation, nice invocation)
(stdbuf invocation): Document that the command is installed
optionally.
---
 doc/coreutils.texi | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 0178f60..14ee3b0 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -1516,6 +1516,9 @@ or by explicitly calling @command{coreutils} with the
 coreutils @option{--coreutils-prog=PROGRAM} @dots{}
 @end example
 
+The @command{coreutils} command is not installed by default, so
+portable scripts should not rely on its existence.
+
 @node Output of entire files
 @chapter Output of entire files
 
@@ -11434,6 +11437,9 @@ Ignored; for compatibility with System V versions of @command{df}.
 
 @end table
 
+@command{df} is installed only on systems that have usable mount tables,
+so portable scripts should not rely on its existence.
+
 @exitstatus
 Failure includes the case where no output is generated, so you can
 inspect the exit status of a command like @samp{df -t ext3 -t reiserfs
@@ -13841,6 +13847,10 @@ systems, those or other settings also may not
 be available, but it's not feasible to document all the variations: just
 try it and see.
 
+@command{stty} is installed only on platforms with the POSIX terminal
+interface, so portable scripts should not rely on its existence on
+non-POSIX platforms.
+
 @exitstatus
 
 @menu
@@ -14760,6 +14770,10 @@ that file instead.  A common choice is @file{/var/log/wtmp}.
 The only options are @option{--help} and @option{--version}.  @xref{Common
 options}.
 
+The @command{users} command is installed only on platforms with the
+POSIX @code{<utmpx.h>} include file or equivalent, so portable scripts
+should not rely on its existence on non-POSIX platforms.
+
 @exitstatus

@@ -14908,6 +14922,10 @@ After each login name print a character indicating the user's message status:
 
 @end table
 
+The @command{who} command is installed only on platforms with the
+POSIX @code{<utmpx.h>} include file or equivalent, so portable scripts
+should not rely on its existence on non-POSIX platforms.
+
 @exitstatus

@@ -15641,6 +15659,9 @@ arch [@var{option}]
 
 The program accepts the @ref{Common options} only.
 
+@command{arch} is not installed by default, so portable scripts should
+not rely on its existence.
+
 @exitstatus

@@ -15832,6 +15853,10 @@ hostname [@var{name}]
 The only options are @option{--help} and @option{--version}.  @xref{Common
 options}.
 
+@command{hostname} is not installed by default, and other packages
+also supply a @command{hostname} command, so portable scripts should
+not rely on its existence or on the exact behavior documented above.
+
 @exitstatus

@@ -15857,6 +15882,10 @@ On that system, the 32-bit quantity happens to be closely
 related to the system's Internet address, but that isn't always
 the case.
 
+@command{hostid} is installed only on systems that have the
+@code{gethostid} function, so portable scripts should not rely on its
+existence.
+
 @exitstatus
 
 @node uptime invocation
@@ -15890,6 +15919,13 @@ also include processes in the uninterruptible sleep state (that is,
 those processes which are waiting for disk I/O).  The Linux kernel
 includes uninterruptible processes.
 
+@command{uptime} is installed only on platforms with infrastructure
+for obtaining the boot time, and other packages also supply an
+@command{uptime} command, so portable scripts should not rely on its
+existence or on the exact behavior documented above.
+
+@exitstatus
+
 @node SELinux context
 @chapter SELinux context
 
@@ -16203,6 +16239,10 @@ files to the required positions under your intended new root directory.
 Finally, if the executable requires any other files (e.g., data, state,
 device files), copy them into place, too.
 
+@command{chroot} is installed only on systems that have the
+@code{chroot} function, so portable scripts should not rely on its
+existence.
+
 @cindex exit status of @command{chroot}
 Exit status:
 
@@ -16431,6 +16471,10 @@ option syntax @option{-@var{adjustment}}.  New scripts should use
 
 @end table
 
+@command{nice} is installed only on systems that have the POSIX
+@code{setpriority} function, so portable scripts should not rely on
+its existence on non-POSIX platforms.
+
 @cindex exit status of @command{nice}
 Exit status:
 
@@ -16642,6 +16686,11 @@ Specify the size of the buffer to use in fully buffered mode.
 
 @end table
 
+@command{stdbuf} is installed only on platforms that use the
+Executable and Linkable Format (ELF) and support the
+@code{constructor} attribute, so portable scripts should not rely on
+its existence.
+
 @cindex exit status of @command{stdbuf}
 Exit status:
 
-- 
1.9.3

From 5c0e59595734fd86a084928efa3713e2e35e072a Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 8 Sep 2014 12:51:14 -0700
Subject: [PATCH 2/4] doc: rename "coreutils invocation" to "Multi-call
 invocation"

This supports longstanding shell commands like
'info coreutils "touch invocation"'.
Problem reported by Vincent Lefevre via Bob Proulx in:
http://bugs.gnu.org/18428
* doc/coreutils.texi (Multi-call invocation):
Rename from "coreutils invocation".
---
 doc/coreutils.texi | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 14ee3b0..fb083f0 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -47,7 +47,7 @@
 * chroot: (coreutils)chroot invocation.         Specify the root directory.
 * cksum: (coreutils)cksum invocation.           Print POSIX CRC checksum.
 * comm: (coreutils)comm invocation.             Compare sorted files by line.
-* coreutils: (coreutils)coreutils invocation.   Multi-call program.
+* coreutils: (coreutils)Multi-call invocation.  Multi-call program.
 * cp: (coreutils)cp invocation.                 Copy files.
 * csplit: (coreutils)csplit invocation.         Split by context.
 * cut: (coreutils)cut invocation.               Print selected parts of lines.
@@ -230,7 +230,7 @@ Common Options
 * Traversing symlinks::          Traversing symlinks to directories
 * Treating / specially::         Treating / specially
 * Standards conformance::        Standards conformance
-* coreutils invocation::         Multi-call binary invocation
+* Multi-call invocation::        Multi-call program invocation
 
 Output of entire files
 
@@ -773,7 +773,7 @@ name.
 * Treating / specially::        --preserve-root and --no-preserve-root.
 * Special built-in utilities::  @command{break}, @command{:}, @dots{}
 * Standards conformance::       Conformance to the POSIX standard.
-* coreutils invocation::        Multi-call binary invocation.
+* Multi-call invocation::       Multi-call program invocation.
 @end menu

@@ -1500,16 +1500,19 @@ that assumes an older version of POSIX and uses @samp{sort +1}
 or @samp{tail +10}, you can work around any compatibility problems by setting
 @samp{_POSIX2_VERSION=199209} in your environment.
 
-@node coreutils invocation
-@section @command{coreutils}: Multi-call binary
+@c This node is named "Multi-call invocation", not the usual
+@c "coreutils invocation", so that shell commands like
+@c 'info coreutils "touch invocation"' work as expected.
+@node Multi-call invocation
+@section @command{coreutils}: Multi-call program
 
 @pindex multicall
 @cindex combined
-@cindex calling combined multi-call binary
+@cindex calling combined multi-call program
 
-@command{coreutils} invokes an individual utility, either
-implicitly selected by the last component of @samp{argv[0]},
-or by explicitly calling @command{coreutils} with the
+The @command{coreutils} command invokes an individual utility, either
+implicitly selected by the last component of the name used to invoke
+@command{coreutils}, or explicitly with the
 @option{--coreutils-prog} option.  Synopsis:
 
 @example
-- 
1.9.3

From ce8d9fe9e325364d5f028931122f294db88aeef0 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 8 Sep 2014 16:31:14 -0700
Subject: [PATCH 3/4] maint: prefer 'return status;' to 'exit (status);' in
 'main'

* build-aux/gen-single-binary.sh: Don't use ATTRIBUTE_NORETURN
for main functions.
* src/base64.c, src/basename.c, src/cat.c, src/chcon.c, src/chgrp.c:
* src/chmod.c, src/chown.c, src/chroot.c, src/cksum.c, src/comm.c:
* src/cp.c, src/csplit.c, src/cut.c, src/date.c, src/dd.c, src/df.c:
* src/dircolors.c, src/dirname.c, src/du.c, src/echo.c, src/env.c:
* src/expand.c, src/expr.c, src/factor.c, src/fmt.c, src/fold.c:
* src/getlimits.c, src/groups.c, src/head.c, src/hostid.c:
* src/hostname.c, src/id.c, src/install.c, src/join.c, src/kill.c:
* src/link.c, src/ln.c, src/logname.c, src/ls.c, src/make-prime-list.c:
* src/md5sum.c, src/mkdir.c, src/mkfifo.c, src/mknod.c, src/mktemp.c:
* src/mv.c, src/nice.c, src/nl.c, src/nohup.c, src/nproc.c:
* src/numfmt.c, src/od.c, src/paste.c, src/pathchk.c, src/pinky.c:
* src/pr.c, src/printenv.c, src/printf.c, src/ptx.c, src/pwd.c:
* src/readlink.c, src/realpath.c, src/rm.c, src/rmdir.c, src/runcon.c:
* src/seq.c, src/shred.c, src/shuf.c, src/sleep.c, src/sort.c:
* src/split.c, src/stat.c, src/stdbuf.c, src/stty.c, src/sum.c:
* src/sync.c, src/tac.c, src/tail.c, src/tee.c, src/timeout.c:
* src/touch.c, src/tr.c, src/true.c, src/truncate.c, src/tsort.c:
* src/tty.c, src/uname.c, src/unexpand.c, src/uniq.c, src/unlink.c:
* src/uptime.c, src/users.c, src/wc.c, src/who.c, src/whoami.c:
In 'main' functions, Prefer 'return status;' to 'exit (status);'.
* src/coreutils-arch.c (_single_binary_main_uname)
(_single_binary_main_arch):
* src/coreutils-dir.c, src/coreutils-vdir.c (_single_binary_main_ls)
(_single_binary_main_dir, _single_binary_main_vdir):
Omit ATTRIBUTE_NORETURN.  Return a value.
* src/coreutils.c (SINGLE_BINARY_PROGRAM): Omit ATTRIBUTE_NORETURN.
(launch_program): Now static.
* src/dd.c (finish_up): New function.
(quit, main): Use it.
* src/getlimits.c (main): Return a proper exit status.
* src/test.c (test_main_return): New macro.
(main): Use it.
* src/logname.c, src/nohup.c, src/whoami.c:
Use 'error' to simplify exit status in 'main' function.
* src/yes.c (main): Use 'return' rather than 'error' to exit,
so that GCC doesn't suggest ATTRIBUTE_NORETURN.
---
 build-aux/gen-single-binary.sh |  4 ++--
 src/base64.c                   |  2 +-
 src/basename.c                 |  2 +-
 src/cat.c                      |  2 +-
 src/chcon.c                    |  2 +-
 src/chgrp.c                    |  2 +-
 src/chmod.c                    |  2 +-
 src/chown.c                    |  2 +-
 src/chroot.c                   | 10 ++++------
 src/cksum.c                    |  4 ++--
 src/comm.c                     |  4 ++--
 src/coreutils-arch.c           |  9 +++++----
 src/coreutils-dir.c            |  9 +++++----
 src/coreutils-vdir.c           |  9 +++++----
 src/coreutils.c                | 13 +++++-------
 src/cp.c                       |  2 +-
 src/csplit.c                   |  2 +-
 src/cut.c                      |  2 +-
 src/date.c                     |  2 +-
 src/dd.c                       | 13 +++++++++---
 src/df.c                       |  4 ++--
 src/dircolors.c                |  2 +-
 src/dirname.c                  |  2 +-
 src/du.c                       |  2 +-
 src/echo.c                     |  6 +++---
 src/env.c                      | 10 ++++------
 src/expand.c                   |  2 +-
 src/expr.c                     |  2 +-
 src/factor.c                   |  2 +-
 src/fmt.c                      |  2 +-
 src/fold.c                     |  2 +-
 src/getlimits.c                |  2 ++
 src/groups.c                   |  2 +-
 src/head.c                     |  2 +-
 src/hostid.c                   |  2 +-
 src/hostname.c                 |  2 +-
 src/id.c                       |  2 +-
 src/install.c                  |  2 +-
 src/join.c                     |  4 ++--
 src/kill.c                     |  6 +++---
 src/link.c                     |  2 +-
 src/ln.c                       |  2 +-
 src/logname.c                  | 15 ++++++--------
 src/ls.c                       |  2 +-
 src/make-prime-list.c          |  2 +-
 src/md5sum.c                   |  2 +-
 src/mkdir.c                    |  4 ++--
 src/mkfifo.c                   |  2 +-
 src/mknod.c                    |  2 +-
 src/mktemp.c                   |  2 +-
 src/mv.c                       |  2 +-
 src/nice.c                     | 12 +++++------
 src/nl.c                       |  2 +-
 src/nohup.c                    | 45 ++++++++++++++++++------------------------
 src/nproc.c                    |  2 +-
 src/numfmt.c                   |  2 +-
 src/od.c                       |  4 ++--
 src/paste.c                    |  2 +-
 src/pathchk.c                  |  2 +-
 src/pinky.c                    |  2 +-
 src/pr.c                       |  4 +---
 src/printenv.c                 |  2 +-
 src/printf.c                   |  4 ++--
 src/ptx.c                      |  2 +-
 src/pwd.c                      |  4 ++--
 src/readlink.c                 |  2 +-
 src/realpath.c                 |  2 +-
 src/rm.c                       |  6 +++---
 src/rmdir.c                    |  2 +-
 src/runcon.c                   | 10 ++++------
 src/seq.c                      |  6 +++---
 src/shred.c                    |  2 +-
 src/shuf.c                     |  2 +-
 src/sleep.c                    |  2 +-
 src/sort.c                     |  4 ++--
 src/split.c                    |  2 +-
 src/stat.c                     |  2 +-
 src/stdbuf.c                   |  8 +++-----
 src/stty.c                     |  4 ++--
 src/sum.c                      |  2 +-
 src/sync.c                     |  2 +-
 src/tac.c                      |  2 +-
 src/tail.c                     |  6 +++---
 src/tee.c                      |  2 +-
 src/test.c                     |  8 +++++---
 src/timeout.c                  | 13 +++++-------
 src/touch.c                    |  2 +-
 src/tr.c                       |  6 +++---
 src/true.c                     |  2 +-
 src/truncate.c                 |  2 +-
 src/tsort.c                    |  2 +-
 src/tty.c                      |  2 +-
 src/uname.c                    |  2 +-
 src/unexpand.c                 |  2 +-
 src/uniq.c                     |  2 +-
 src/unlink.c                   |  2 +-
 src/uptime.c                   |  2 +-
 src/users.c                    |  2 +-
 src/wc.c                       |  2 +-
 src/who.c                      |  2 +-
 src/whoami.c                   | 13 +++++-------
 src/yes.c                      |  5 ++++-
 102 files changed, 204 insertions(+), 218 deletions(-)

diff --git a/build-aux/gen-single-binary.sh b/build-aux/gen-single-binary.sh
index a2423e6..1128f40 100755
--- a/build-aux/gen-single-binary.sh
+++ b/build-aux/gen-single-binary.sh
@@ -91,8 +91,8 @@ for cmd in $ALL_PROGRAMS; do
   # CFLAGS
   # Hack any other program defining a main() replacing its main by
   # _single_binary_main_$PROGRAM_NAME.
-  echo "${base}_CFLAGS = \"-Dmain=_single_binary_main_${cmd}(int, char**) " \
-       "ATTRIBUTE_NORETURN; int _single_binary_main_${cmd}\" " \
+  echo "${base}_CFLAGS = \"-Dmain=_single_binary_main_${cmd} (int, char **);" \
+       " int _single_binary_main_${cmd}\" " \
        "-Dusage=_usage_${cmd} \$(src_coreutils_CFLAGS)"
   var=src_${cmd}_CFLAGS
   eval "value=\$$var"
diff --git a/src/base64.c b/src/base64.c
index b065604..7b4ffda 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -321,5 +321,5 @@ main (int argc, char **argv)
         error (EXIT_FAILURE, errno, "%s", infile);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/basename.c b/src/basename.c
index 9521539..9bd54d5 100644
--- a/src/basename.c
+++ b/src/basename.c
@@ -185,5 +185,5 @@ main (int argc, char **argv)
     perform_basename (argv[optind],
                       optind + 2 == argc ? argv[optind + 1] : NULL, use_nuls);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/cat.c b/src/cat.c
index 8aef79f..026348c 100644
--- a/src/cat.c
+++ b/src/cat.c
@@ -780,5 +780,5 @@ main (int argc, char **argv)
   if (have_read_stdin && close (STDIN_FILENO) < 0)
     error (EXIT_FAILURE, errno, _("closing standard input"));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/chcon.c b/src/chcon.c
index cda0661..21375bc 100644
--- a/src/chcon.c
+++ b/src/chcon.c
@@ -582,5 +582,5 @@ main (int argc, char **argv)
 
   ok = process_files (argv + optind, bit_flags | FTS_NOSTAT);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/chgrp.c b/src/chgrp.c
index c7297c8..8da6a36 100644
--- a/src/chgrp.c
+++ b/src/chgrp.c
@@ -313,5 +313,5 @@ main (int argc, char **argv)
 
   chopt_free (&chopt);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/chmod.c b/src/chmod.c
index 756ec5a..a37075c 100644
--- a/src/chmod.c
+++ b/src/chmod.c
@@ -566,5 +566,5 @@ main (int argc, char **argv)
   ok = process_files (argv + optind,
                       FTS_COMFOLLOW | FTS_PHYSICAL | FTS_DEFER_STAT);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/chown.c b/src/chown.c
index 13a1923..8036d1a 100644
--- a/src/chown.c
+++ b/src/chown.c
@@ -326,5 +326,5 @@ main (int argc, char **argv)
 
   chopt_free (&chopt);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/chroot.c b/src/chroot.c
index 418ea67..757573a 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -388,7 +388,7 @@ main (int argc, char **argv)
       if (parse_additional_groups (groups, &in_gids, &n_gids, !n_gids) != 0)
         {
           if (! n_gids)
-            exit (EXIT_CANCELED);
+            return EXIT_CANCELED;
           /* else look-up outside the chroot worked, then go with those.  */
         }
       else
@@ -428,9 +428,7 @@ main (int argc, char **argv)
   /* Execute the given command.  */
   execvp (argv[0], argv);
 
-  {
-    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    error (0, errno, _("failed to run command %s"), quote (argv[0]));
-    exit (exit_status);
-  }
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  error (0, errno, _("failed to run command %s"), quote (argv[0]));
+  return exit_status;
 }
diff --git a/src/cksum.c b/src/cksum.c
index 8db39a4..baae55a 100644
--- a/src/cksum.c
+++ b/src/cksum.c
@@ -102,7 +102,7 @@ main (void)
               crc_remainder (i * 5 + 5));
     }
   printf ("\n};\n");
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
 
 #else /* !CRCTAB */
@@ -312,7 +312,7 @@ main (int argc, char **argv)
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, "-");
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 #endif /* !CRCTAB */
diff --git a/src/comm.c b/src/comm.c
index 5a3eec6..b5c6840 100644
--- a/src/comm.c
+++ b/src/comm.c
@@ -443,7 +443,7 @@ main (int argc, char **argv)
   compare_files (argv + optind);
 
   if (issued_disorder_warning[0] || issued_disorder_warning[1])
-    exit (EXIT_FAILURE);
+    return EXIT_FAILURE;
   else
-    exit (EXIT_SUCCESS);
+    return EXIT_SUCCESS;
 }
diff --git a/src/coreutils-arch.c b/src/coreutils-arch.c
index 899cc93..f55bef9 100644
--- a/src/coreutils-arch.c
+++ b/src/coreutils-arch.c
@@ -22,11 +22,12 @@
 #include "uname.h"
 /* Ensure that the main for uname is declared even if the tool is not being
    built in this single-binary. */
-int _single_binary_main_uname (int argc, char** argv) ATTRIBUTE_NORETURN;
-int _single_binary_main_arch (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_uname (int argc, char **argv);
+int _single_binary_main_arch (int argc, char **argv);
 
-int _single_binary_main_arch (int argc, char** argv)
+int
+_single_binary_main_arch (int argc, char **argv)
 {
   uname_mode = UNAME_ARCH;
-  _single_binary_main_uname (argc, argv);
+  return _single_binary_main_uname (argc, argv);
 }
diff --git a/src/coreutils-dir.c b/src/coreutils-dir.c
index 4b488f4..afbe39a 100644
--- a/src/coreutils-dir.c
+++ b/src/coreutils-dir.c
@@ -22,11 +22,12 @@
 #include "ls.h"
 /* Ensure that the main for ls is declared even if the tool is not being built
    in this single-binary. */
-int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN;
-int _single_binary_main_dir (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_ls (int argc, char **argv);
+int _single_binary_main_dir (int argc, char **argv);
 
-int _single_binary_main_dir (int argc, char** argv)
+int
+_single_binary_main_dir (int argc, char **argv)
 {
   ls_mode = LS_MULTI_COL;
-  _single_binary_main_ls (argc, argv);
+  return _single_binary_main_ls (argc, argv);
 }
diff --git a/src/coreutils-vdir.c b/src/coreutils-vdir.c
index 036367f..b1b0194 100644
--- a/src/coreutils-vdir.c
+++ b/src/coreutils-vdir.c
@@ -22,11 +22,12 @@
 #include "ls.h"
 /* Ensure that the main for ls is declared even if the tool is not being built
    in this single-binary. */
-int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN;
-int _single_binary_main_vdir (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_ls (int argc, char **argv);
+int _single_binary_main_vdir (int argc, char **argv);
 
-int _single_binary_main_vdir (int argc, char** argv)
+int
+_single_binary_main_vdir (int argc, char** argv)
 {
   ls_mode = LS_LONG_FORMAT;
-  _single_binary_main_ls (argc, argv);
+  return _single_binary_main_ls (argc, argv);
 }
diff --git a/src/coreutils.c b/src/coreutils.c
index c459b1d..898fe84 100644
--- a/src/coreutils.c
+++ b/src/coreutils.c
@@ -35,7 +35,7 @@
    needs to match the one passed as CFLAGS on single-binary.mk (generated
    by gen-single-binary.sh). */
 # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
-  int _single_binary_main_##main_name (int, char**) ATTRIBUTE_NORETURN;
+  int _single_binary_main_##main_name (int, char **);
 # include "coreutils.h"
 # undef SINGLE_BINARY_PROGRAM
 #endif
@@ -46,9 +46,6 @@
 #define AUTHORS \
   proper_name ("Alex Deymo")
 
-void
-launch_program (const char *prog_name, int prog_argc, char **prog_argv);
-
 static struct option const long_options[] =
 {
   {GETOPT_HELP_OPTION_DECL},
@@ -92,10 +89,10 @@ Use: '%s --coreutils-prog=PROGRAM_NAME --help' for individual program help.\n"),
   exit (status);
 }
 
-void
+static void
 launch_program (const char *prog_name, int prog_argc, char **prog_argv)
 {
-  int (*prog_main)(int, char **) = NULL;
+  int (*prog_main) (int, char **) = NULL;
 
   /* Ensure that at least one parameter was passed.  */
   if (!prog_argc || !prog_argv || !prog_argv[0] || !prog_name)
@@ -103,7 +100,7 @@ launch_program (const char *prog_name, int prog_argc, char **prog_argv)
 
 #ifdef SINGLE_BINARY
   if (false);
-  /* Lookup the right main program.  */
+  /* Look up the right main program.  */
 # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
   else if (STREQ (prog_name_str, prog_name)) \
     prog_main = _single_binary_main_##main_name;
@@ -124,7 +121,7 @@ launch_program (const char *prog_name, int prog_argc, char **prog_argv)
   prctl (PR_SET_MM_ARG_START, prog_argv[0]);
 #endif
 
-  exit ((*prog_main) (prog_argc, prog_argv));
+  exit (prog_main (prog_argc, prog_argv));
 }
 
 int
diff --git a/src/cp.c b/src/cp.c
index 6c7231a..60be688 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -1218,5 +1218,5 @@ main (int argc, char **argv)
   forget_all ();
 #endif
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/csplit.c b/src/csplit.c
index a30f09b..f8062ea 100644
--- a/src/csplit.c
+++ b/src/csplit.c
@@ -1466,7 +1466,7 @@ main (int argc, char **argv)
       cleanup_fatal ();
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
 
 void
diff --git a/src/cut.c b/src/cut.c
index 312551f..bdc723b 100644
--- a/src/cut.c
+++ b/src/cut.c
@@ -827,5 +827,5 @@ main (int argc, char **argv)
       ok = false;
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/date.c b/src/date.c
index ef04cb5..ba1918f 100644
--- a/src/date.c
+++ b/src/date.c
@@ -540,7 +540,7 @@ main (int argc, char **argv)
       ok &= show_date (format, when);
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 /* Display the date and/or time in WHEN according to the format specified
diff --git a/src/dd.c b/src/dd.c
index 1e387f3..71c334c 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -917,12 +917,18 @@ process_signals (void)
     }
 }
 
-static void ATTRIBUTE_NORETURN
-quit (int code)
+static void
+finish_up (void)
 {
   cleanup ();
   print_stats ();
   process_signals ();
+}
+
+static void ATTRIBUTE_NORETURN
+quit (int code)
+{
+  finish_up ();
   exit (code);
 }
 
@@ -2340,5 +2346,6 @@ main (int argc, char **argv)
         invalidate_cache (STDOUT_FILENO, 0);
     }
 
-  quit (exit_status);
+  finish_up ();
+  return exit_status;
 }
diff --git a/src/df.c b/src/df.c
index e907b94..a777665 100644
--- a/src/df.c
+++ b/src/df.c
@@ -1620,7 +1620,7 @@ main (int argc, char **argv)
           }
       }
     if (match)
-      exit (EXIT_FAILURE);
+      return EXIT_FAILURE;
   }
 
   if (optind < argc)
@@ -1714,5 +1714,5 @@ main (int argc, char **argv)
 
   IF_LINT (free (columns));
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/dircolors.c b/src/dircolors.c
index 9960536..5544419 100644
--- a/src/dircolors.c
+++ b/src/dircolors.c
@@ -503,5 +503,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/dirname.c b/src/dirname.c
index e0599a3..5a268e1 100644
--- a/src/dirname.c
+++ b/src/dirname.c
@@ -132,5 +132,5 @@ main (int argc, char **argv)
       putchar (use_nuls ? '\0' :'\n');
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/du.c b/src/du.c
index 0966326..5466e17 100644
--- a/src/du.c
+++ b/src/du.c
@@ -1108,5 +1108,5 @@ main (int argc, char **argv)
   if (print_grand_total)
     print_size (&tot_dui, _("total"));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/echo.c b/src/echo.c
index 93f4a82..63b263e 100644
--- a/src/echo.c
+++ b/src/echo.c
@@ -136,7 +136,7 @@ main (int argc, char **argv)
         {
           version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
                        (char *) NULL);
-          exit (EXIT_SUCCESS);
+          return EXIT_SUCCESS;
         }
     }
 
@@ -204,7 +204,7 @@ just_echo:
                     {
                     case 'a': c = '\a'; break;
                     case 'b': c = '\b'; break;
-                    case 'c': exit (EXIT_SUCCESS);
+                    case 'c': return EXIT_SUCCESS;
                     case 'e': c = '\x1B'; break;
                     case 'f': c = '\f'; break;
                     case 'n': c = '\n'; break;
@@ -268,5 +268,5 @@ just_echo:
 
   if (display_return)
     putchar ('\n');
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/env.c b/src/env.c
index 2b37d98..b776052 100644
--- a/src/env.c
+++ b/src/env.c
@@ -144,7 +144,7 @@ main (int argc, char **argv)
       char *const *e = environ;
       while (*e)
         printf ("%s%c", *e++, opt_nul_terminate_output ? '\0' : '\n');
-      exit (EXIT_SUCCESS);
+      return EXIT_SUCCESS;
     }
 
   if (opt_nul_terminate_output)
@@ -155,9 +155,7 @@ main (int argc, char **argv)
 
   execvp (argv[optind], &argv[optind]);
 
-  {
-    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    error (0, errno, "%s", argv[optind]);
-    exit (exit_status);
-  }
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  error (0, errno, "%s", argv[optind]);
+  return exit_status;
 }
diff --git a/src/expand.c b/src/expand.c
index 082b5d4..bbaf0e7 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -426,5 +426,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) != 0)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/expr.c b/src/expr.c
index a97663a..bbf3251 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -326,7 +326,7 @@ main (int argc, char **argv)
     syntax_error ();
   printv (v);
 
-  exit (null (v));
+  return null (v);
 }
 
 /* Return a VALUE for I.  */
diff --git a/src/factor.c b/src/factor.c
index f7beaeb..f636e36 100644
--- a/src/factor.c
+++ b/src/factor.c
@@ -2543,5 +2543,5 @@ main (int argc, char **argv)
     }
 #endif
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/fmt.c b/src/fmt.c
index dbd180b..3ee04d9 100644
--- a/src/fmt.c
+++ b/src/fmt.c
@@ -456,7 +456,7 @@ main (int argc, char **argv)
         }
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 /* Trim space from the front and back of the string P, yielding the prefix,
diff --git a/src/fold.c b/src/fold.c
index 444dc8b..1f03c2e 100644
--- a/src/fold.c
+++ b/src/fold.c
@@ -311,5 +311,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/getlimits.c b/src/getlimits.c
index 597efd8..3a7d7e1 100644
--- a/src/getlimits.c
+++ b/src/getlimits.c
@@ -167,4 +167,6 @@ main (int argc, char **argv)
   print_float (FLT);
   print_float (DBL);
   print_float (LDBL);
+
+  return EXIT_SUCCESS;
 }
diff --git a/src/groups.c b/src/groups.c
index f19ff0a..c904f32 100644
--- a/src/groups.c
+++ b/src/groups.c
@@ -136,5 +136,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/head.c b/src/head.c
index 65bd52a..09bc33d 100644
--- a/src/head.c
+++ b/src/head.c
@@ -1066,5 +1066,5 @@ main (int argc, char **argv)
   if (have_read_stdin && close (STDIN_FILENO) < 0)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/hostid.c b/src/hostid.c
index 5b40eb0..8671812 100644
--- a/src/hostid.c
+++ b/src/hostid.c
@@ -84,5 +84,5 @@ main (int argc, char **argv)
 
   printf ("%08x\n", id);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/hostname.c b/src/hostname.c
index bab51ae..9ef7598 100644
--- a/src/hostname.c
+++ b/src/hostname.c
@@ -112,5 +112,5 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/id.c b/src/id.c
index ccd1e87..33445a0 100644
--- a/src/id.c
+++ b/src/id.c
@@ -314,7 +314,7 @@ main (int argc, char **argv)
   putchar (opt_zero ? '\0' : '\n');
 
   IF_LINT (free (pw_name));
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 /* Convert a gid_t to string.  Do not use this function directly.
diff --git a/src/install.c b/src/install.c
index c342422..db4ee45 100644
--- a/src/install.c
+++ b/src/install.c
@@ -1042,5 +1042,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/join.c b/src/join.c
index 5c26e78..965ab49 100644
--- a/src/join.c
+++ b/src/join.c
@@ -1191,7 +1191,7 @@ main (int argc, char **argv)
     error (EXIT_FAILURE, errno, "%s", g_names[1]);
 
   if (issued_disorder_warning[0] || issued_disorder_warning[1])
-    exit (EXIT_FAILURE);
+    return EXIT_FAILURE;
   else
-    exit (EXIT_SUCCESS);
+    return EXIT_SUCCESS;
 }
diff --git a/src/kill.c b/src/kill.c
index 724667e..4ab86a4 100644
--- a/src/kill.c
+++ b/src/kill.c
@@ -306,7 +306,7 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  exit (list
-        ? list_signals (table, optind < argc ? argv + optind : NULL)
-        : send_signals (signum, argv + optind));
+  return (list
+          ? list_signals (table, optind < argc ? argv + optind : NULL)
+          : send_signals (signum, argv + optind));
 }
diff --git a/src/link.c b/src/link.c
index 9f18fe2..6f3a297 100644
--- a/src/link.c
+++ b/src/link.c
@@ -90,5 +90,5 @@ main (int argc, char **argv)
     error (EXIT_FAILURE, errno, _("cannot create link %s to %s"),
            quote_n (0, argv[optind + 1]), quote_n (1, argv[optind]));
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/ln.c b/src/ln.c
index 42bccfc..5140e92 100644
--- a/src/ln.c
+++ b/src/ln.c
@@ -647,5 +647,5 @@ main (int argc, char **argv)
   else
     ok = do_link (file[0], file[1]);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/logname.c b/src/logname.c
index 6afa1b5..368c4c9 100644
--- a/src/logname.c
+++ b/src/logname.c
@@ -72,15 +72,12 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  /* POSIX requires using getlogin (or equivalent code).  */
+  /* POSIX requires using getlogin (or equivalent code) and prohibits
+     using a fallback technique.  */
   cp = getlogin ();
-  if (cp)
-    {
-      puts (cp);
-      exit (EXIT_SUCCESS);
-    }
-  /* POSIX prohibits using a fallback technique.  */
+  if (! cp)
+    error (EXIT_FAILURE, 0, _("no login name"));
 
-  error (0, 0, _("no login name"));
-  exit (EXIT_FAILURE);
+  puts (cp);
+  return EXIT_SUCCESS;
 }
diff --git a/src/ls.c b/src/ls.c
index a45cfc1..94276b6 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -1513,7 +1513,7 @@ main (int argc, char **argv)
       hash_free (active_dir_set);
     }
 
-  exit (exit_status);
+  return exit_status;
 }
 
 /* Set all the option flags according to the switches specified.
diff --git a/src/make-prime-list.c b/src/make-prime-list.c
index c01b120..5c79ace 100644
--- a/src/make-prime-list.c
+++ b/src/make-prime-list.c
@@ -187,7 +187,7 @@ main (int argc, char **argv)
     }
   limit = atoi (argv[1]);
   if (limit < 3)
-    exit (EXIT_SUCCESS);
+    return EXIT_SUCCESS;
 
   /* Make limit odd */
   if ( !(limit & 1))
diff --git a/src/md5sum.c b/src/md5sum.c
index cc6dd49..cd27e80 100644
--- a/src/md5sum.c
+++ b/src/md5sum.c
@@ -874,5 +874,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/mkdir.c b/src/mkdir.c
index eb9693c..70bca07 100644
--- a/src/mkdir.c
+++ b/src/mkdir.c
@@ -301,6 +301,6 @@ main (int argc, char **argv)
         options.mode = S_IRWXUGO;
     }
 
-  exit (savewd_process_files (argc - optind, argv + optind,
-                              process_dir, &options));
+  return savewd_process_files (argc - optind, argv + optind,
+                               process_dir, &options);
 }
diff --git a/src/mkfifo.c b/src/mkfifo.c
index 415ae56..6324729 100644
--- a/src/mkfifo.c
+++ b/src/mkfifo.c
@@ -177,5 +177,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/mknod.c b/src/mknod.c
index 8f547e9..797e6bb 100644
--- a/src/mknod.c
+++ b/src/mknod.c
@@ -269,5 +269,5 @@ main (int argc, char **argv)
     error (EXIT_FAILURE, errno, _("cannot set permissions of %s"),
            quote (argv[optind]));
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/mktemp.c b/src/mktemp.c
index 2bd80ba..d36e502 100644
--- a/src/mktemp.c
+++ b/src/mktemp.c
@@ -345,5 +345,5 @@ main (int argc, char **argv)
   free (template);
 #endif
 
-  exit (status);
+  return status;
 }
diff --git a/src/mv.c b/src/mv.c
index 1db404f..b71d210 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -508,5 +508,5 @@ main (int argc, char **argv)
   else
     ok = movefile (file[0], file[1], false, &x);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/nice.c b/src/nice.c
index 488ef95..91e8f99 100644
--- a/src/nice.c
+++ b/src/nice.c
@@ -187,7 +187,7 @@ main (int argc, char **argv)
       if (current_niceness == -1 && errno != 0)
         error (EXIT_CANCELED, errno, _("cannot get niceness"));
       printf ("%d\n", current_niceness);
-      exit (EXIT_SUCCESS);
+      return EXIT_SUCCESS;
     }
 
   errno = 0;
@@ -209,14 +209,12 @@ main (int argc, char **argv)
          encountered a write failure, there is no need to try calling
          error() again.  */
       if (ferror (stderr))
-        exit (EXIT_CANCELED);
+        return EXIT_CANCELED;
     }
 
   execvp (argv[i], &argv[i]);
 
-  {
-    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    error (0, errno, "%s", argv[i]);
-    exit (exit_status);
-  }
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  error (0, errno, "%s", argv[i]);
+  return exit_status;
 }
diff --git a/src/nl.c b/src/nl.c
index 982f468..d45dcbd 100644
--- a/src/nl.c
+++ b/src/nl.c
@@ -612,5 +612,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/nohup.c b/src/nohup.c
index eca1f51..13bb045 100644
--- a/src/nohup.c
+++ b/src/nohup.c
@@ -123,10 +123,8 @@ main (int argc, char **argv)
   if (ignoring_input)
     {
       if (fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0) < 0)
-        {
-          error (0, errno, _("failed to render standard input unusable"));
-          exit (exit_internal_failure);
-        }
+        error (exit_internal_failure, errno,
+               _("failed to render standard input unusable"));
       if (!redirecting_stdout && !redirecting_stderr)
         error (0, 0, _("ignoring input"));
     }
@@ -164,7 +162,7 @@ main (int argc, char **argv)
               if (in_home)
                 error (0, saved_errno2, _("failed to open %s"),
                        quote (in_home));
-              exit (exit_internal_failure);
+              return exit_internal_failure;
             }
           file = in_home;
         }
@@ -213,28 +211,23 @@ main (int argc, char **argv)
      error() again, particularly since we may have just changed the
      underlying fd out from under stderr.  */
   if (ferror (stderr))
-    exit (exit_internal_failure);
+    return exit_internal_failure;
 
   signal (SIGHUP, SIG_IGN);
 
-  {
-    int exit_status;
-    int saved_errno;
-    char **cmd = argv + optind;
-
-    execvp (*cmd, cmd);
-    exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    saved_errno = errno;
-
-    /* The execve failed.  Output a diagnostic to stderr only if:
-       - stderr was initially redirected to a non-tty, or
-       - stderr was initially directed to a tty, and we
-         can dup2 it to point back to that same tty.
-       In other words, output the diagnostic if possible, but only if
-       it will go to the original stderr.  */
-    if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
-      error (0, saved_errno, _("failed to run command %s"), quote (*cmd));
-
-    exit (exit_status);
-  }
+  char **cmd = argv + optind;
+  execvp (*cmd, cmd);
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  int saved_errno = errno;
+
+  /* The execve failed.  Output a diagnostic to stderr only if:
+     - stderr was initially redirected to a non-tty, or
+     - stderr was initially directed to a tty, and we
+     can dup2 it to point back to that same tty.
+     In other words, output the diagnostic if possible, but only if
+     it will go to the original stderr.  */
+  if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
+    error (0, saved_errno, _("failed to run command %s"), quote (*cmd));
+
+  return exit_status;
 }
diff --git a/src/nproc.c b/src/nproc.c
index 9bfc8b3..44ee483 100644
--- a/src/nproc.c
+++ b/src/nproc.c
@@ -129,5 +129,5 @@ main (int argc, char **argv)
 
   printf ("%lu\n", nproc);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/numfmt.c b/src/numfmt.c
index b524e65..f111374 100644
--- a/src/numfmt.c
+++ b/src/numfmt.c
@@ -1538,5 +1538,5 @@ main (int argc, char **argv)
   if (!valid_numbers && _invalid != inval_warn && _invalid != inval_ignore)
     exit_status = EXIT_CONVERSION_WARNINGS;
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/od.c b/src/od.c
index 7bc0e2a..c32d785 100644
--- a/src/od.c
+++ b/src/od.c
@@ -1781,7 +1781,7 @@ main (int argc, char **argv)
     }
 
   if (!ok)
-    exit (EXIT_FAILURE);
+    return EXIT_FAILURE;
 
   if (flag_dump_strings && n_specs > 0)
     error (EXIT_FAILURE, 0,
@@ -1972,5 +1972,5 @@ cleanup:
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/paste.c b/src/paste.c
index 3663aaf..8f8f465 100644
--- a/src/paste.c
+++ b/src/paste.c
@@ -518,5 +518,5 @@ main (int argc, char **argv)
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, "-");
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/pathchk.c b/src/pathchk.c
index 4b3884f..3cb8bef 100644
--- a/src/pathchk.c
+++ b/src/pathchk.c
@@ -153,7 +153,7 @@ main (int argc, char **argv)
     ok &= validate_file_name (argv[optind],
                               check_basic_portability, check_extra_portability);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 /* If FILE contains a component with a leading "-", report an error
diff --git a/src/pinky.c b/src/pinky.c
index c48e170..154b6aa 100644
--- a/src/pinky.c
+++ b/src/pinky.c
@@ -604,5 +604,5 @@ main (int argc, char **argv)
   else
     long_pinky (n_users, argv + optind);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/pr.c b/src/pr.c
index 1515b4a..a3dc9bf 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -1170,9 +1170,7 @@ main (int argc, char **argv)
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));
-  if (failed_opens)
-    exit (EXIT_FAILURE);
-  exit (EXIT_SUCCESS);
+  return failed_opens ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 
 /* Parse options of the form -scNNN.
diff --git a/src/printenv.c b/src/printenv.c
index e1faeb5..0646c70 100644
--- a/src/printenv.c
+++ b/src/printenv.c
@@ -150,5 +150,5 @@ main (int argc, char **argv)
       ok = (matches == argc - optind);
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/printf.c b/src/printf.c
index 7d52310..3d303be 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -657,7 +657,7 @@ main (int argc, char **argv)
         {
           version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
                        (char *) NULL);
-          exit (EXIT_SUCCESS);
+          return EXIT_SUCCESS;
         }
     }
 
@@ -692,5 +692,5 @@ main (int argc, char **argv)
            _("warning: ignoring excess arguments, starting with %s"),
            quote (argv[0]));
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/ptx.c b/src/ptx.c
index d165e96..39ac5e4 100644
--- a/src/ptx.c
+++ b/src/ptx.c
@@ -2155,5 +2155,5 @@ main (int argc, char **argv)
 
   /* All done.  */
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/pwd.c b/src/pwd.c
index d126ed7..9bbd787 100644
--- a/src/pwd.c
+++ b/src/pwd.c
@@ -372,7 +372,7 @@ main (int argc, char **argv)
       if (wd)
         {
           puts (wd);
-          exit (EXIT_SUCCESS);
+          return EXIT_SUCCESS;
         }
     }
 
@@ -390,5 +390,5 @@ main (int argc, char **argv)
       file_name_free (file_name);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/readlink.c b/src/readlink.c
index f46d948..d63f07b 100644
--- a/src/readlink.c
+++ b/src/readlink.c
@@ -174,5 +174,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (status);
+  return status;
 }
diff --git a/src/realpath.c b/src/realpath.c
index 0c55327..930530c 100644
--- a/src/realpath.c
+++ b/src/realpath.c
@@ -273,5 +273,5 @@ main (int argc, char **argv)
   for (; optind < argc; ++optind)
     ok &= process_path (argv[optind], can_mode);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/rm.c b/src/rm.c
index 708d85d..7ab1c07 100644
--- a/src/rm.c
+++ b/src/rm.c
@@ -315,7 +315,7 @@ main (int argc, char **argv)
   if (argc <= optind)
     {
       if (x.ignore_missing_files)
-        exit (EXIT_SUCCESS);
+        return EXIT_SUCCESS;
       else
         {
           error (0, 0, _("missing operand"));
@@ -347,10 +347,10 @@ main (int argc, char **argv)
                             select_plural (n_files))),
                program_name, n_files);
       if (!yesno ())
-        exit (EXIT_SUCCESS);
+        return EXIT_SUCCESS;
     }
 
   enum RM_status status = rm (file, &x);
   assert (VALID_STATUS (status));
-  exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);
+  return status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/rmdir.c b/src/rmdir.c
index e67d3b0..6bdfb0f 100644
--- a/src/rmdir.c
+++ b/src/rmdir.c
@@ -248,5 +248,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/runcon.c b/src/runcon.c
index 14ccc3d..efe83f2 100644
--- a/src/runcon.c
+++ b/src/runcon.c
@@ -177,7 +177,7 @@ main (int argc, char **argv)
         error (EXIT_FAILURE, errno, _("failed to get current context"));
       fputs (cur_context, stdout);
       fputc ('\n', stdout);
-      exit (EXIT_SUCCESS);
+      return EXIT_SUCCESS;
     }
 
   if (!(user || role || type || range || compute_trans))
@@ -258,9 +258,7 @@ main (int argc, char **argv)
 
   execvp (argv[optind], argv + optind);
 
-  {
-    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    error (0, errno, "%s", argv[optind]);
-    exit (exit_status);
-  }
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  error (0, errno, "%s", argv[optind]);
+  return exit_status;
 }
diff --git a/src/seq.c b/src/seq.c
index 1124358..7943824 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -574,7 +574,7 @@ main (int argc, char **argv)
       char const *s1 = n_args == 1 ? "1" : argv[optind];
       char const *s2 = argv[optind + (n_args - 1)];
       if (seq_fast (s1, s2))
-        exit (EXIT_SUCCESS);
+        return EXIT_SUCCESS;
 
       /* Upon any failure, let the more general code deal with it.  */
     }
@@ -608,7 +608,7 @@ main (int argc, char **argv)
         {
           IF_LINT (free (s1));
           IF_LINT (free (s2));
-          exit (EXIT_SUCCESS);
+          return EXIT_SUCCESS;
         }
 
       free (s1);
@@ -621,5 +621,5 @@ main (int argc, char **argv)
 
   print_numbers (format_str, layout, first.value, step.value, last.value);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/shred.c b/src/shred.c
index bd88e38..d17c870 100644
--- a/src/shred.c
+++ b/src/shred.c
@@ -1318,7 +1318,7 @@ main (int argc, char **argv)
       free (qname);
     }
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 /*
  * vim:sw=2:sts=2:
diff --git a/src/shuf.c b/src/shuf.c
index 2505be6..915f7b7 100644
--- a/src/shuf.c
+++ b/src/shuf.c
@@ -622,5 +622,5 @@ main (int argc, char **argv)
     }
 #endif
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/sleep.c b/src/sleep.c
index e24c251..10fd989 100644
--- a/src/sleep.c
+++ b/src/sleep.c
@@ -145,5 +145,5 @@ main (int argc, char **argv)
   if (xnanosleep (seconds))
     error (EXIT_FAILURE, errno, _("cannot read realtime clock"));
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/sort.c b/src/sort.c
index c249319..deb7c3a 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -4708,7 +4708,7 @@ main (int argc, char **argv)
 
       /* POSIX requires that sort return 1 IFF invoked with -c or -C and the
          input is not properly sorted.  */
-      exit (check (files[0], checkonly) ? EXIT_SUCCESS : SORT_OUT_OF_ORDER);
+      return check (files[0], checkonly) ? EXIT_SUCCESS : SORT_OUT_OF_ORDER;
     }
 
   /* Check all inputs are accessible, or exit immediately.  */
@@ -4746,5 +4746,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) == EOF)
     die (_("close failed"), "-");
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/split.c b/src/split.c
index dacacaa..36295c4 100644
--- a/src/split.c
+++ b/src/split.c
@@ -1488,5 +1488,5 @@ main (int argc, char **argv)
     error (EXIT_FAILURE, errno, "%s", infile);
   closeout (NULL, output_desc, filter_pid, outfile);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/stat.c b/src/stat.c
index b65dbe5..c78ab70 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -1575,5 +1575,5 @@ main (int argc, char *argv[])
            ? do_statfs (argv[i], format)
            : do_stat (argv[i], format, format2));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/stdbuf.c b/src/stdbuf.c
index 92ee282..c8398ab 100644
--- a/src/stdbuf.c
+++ b/src/stdbuf.c
@@ -387,9 +387,7 @@ main (int argc, char **argv)
 
   execvp (*argv, argv);
 
-  {
-    int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-    error (0, errno, _("failed to run command %s"), quote (argv[0]));
-    exit (exit_status);
-  }
+  int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+  error (0, errno, _("failed to run command %s"), quote (argv[0]));
+  return exit_status;
 }
diff --git a/src/stty.c b/src/stty.c
index 3c48578..4843b9b 100644
--- a/src/stty.c
+++ b/src/stty.c
@@ -862,7 +862,7 @@ main (int argc, char **argv)
       max_col = screen_columns ();
       current_col = 0;
       display_settings (output_type, &mode, device_name);
-      exit (EXIT_SUCCESS);
+      return EXIT_SUCCESS;
     }
 
   speed_was_set = false;
@@ -1070,7 +1070,7 @@ main (int argc, char **argv)
         }
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
 
 /* Return false if not applied because not reversible; otherwise
diff --git a/src/sum.c b/src/sum.c
index 442b7ad..5c502ce 100644
--- a/src/sum.c
+++ b/src/sum.c
@@ -270,5 +270,5 @@ main (int argc, char **argv)
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, "-");
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/sync.c b/src/sync.c
index 8c89043..b706fbe 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -69,5 +69,5 @@ main (int argc, char **argv)
     error (0, 0, _("ignoring all arguments"));
 
   sync ();
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/tac.c b/src/tac.c
index c76afc7..ba055a0 100644
--- a/src/tac.c
+++ b/src/tac.c
@@ -699,5 +699,5 @@ main (int argc, char **argv)
   free (G_buffer - offset);
 #endif
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/tail.c b/src/tail.c
index 5ff738d..7dd3f4a 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -2218,7 +2218,7 @@ main (int argc, char **argv)
 
   /* Don't read anything if we'll never output anything.  */
   if (! n_units && ! forever && ! from_start)
-    exit (EXIT_SUCCESS);
+    return EXIT_SUCCESS;
 
   F = xnmalloc (n_files, sizeof *F);
   for (i = 0; i < n_files; i++)
@@ -2286,7 +2286,7 @@ main (int argc, char **argv)
                 error (EXIT_FAILURE, errno, _("write error"));
 
               if (!tail_forever_inotify (wd, F, n_files, sleep_interval))
-                exit (EXIT_FAILURE);
+                return EXIT_FAILURE;
             }
           error (0, errno, _("inotify cannot be used, reverting to polling"));
         }
@@ -2297,5 +2297,5 @@ main (int argc, char **argv)
 
   if (have_read_stdin && close (STDIN_FILENO) < 0)
     error (EXIT_FAILURE, errno, "-");
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/tee.c b/src/tee.c
index be36560..821d825 100644
--- a/src/tee.c
+++ b/src/tee.c
@@ -125,7 +125,7 @@ main (int argc, char **argv)
   if (close (STDIN_FILENO) != 0)
     error (EXIT_FAILURE, errno, _("standard input"));
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 /* Copy the standard input into each of the NFILES files in FILES
diff --git a/src/test.c b/src/test.c
index 7596879..24bcb93 100644
--- a/src/test.c
+++ b/src/test.c
@@ -57,10 +57,12 @@ enum { TEST_TRUE, TEST_FALSE, TEST_FAILURE };
 
 #if defined TEST_STANDALONE
 # define test_exit(val) exit (val)
+# define test_main_return(val) return val
 #else
    static jmp_buf test_exit_buf;
    static int test_error_return = 0;
 # define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
+# define test_main_return(val) test_exit (val)
 #endif /* !TEST_STANDALONE */
 
 static int pos;		/* The offset of the current argument in ARGV. */
@@ -851,7 +853,7 @@ main (int margc, char **margv)
             {
               version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
                            (char *) NULL);
-              test_exit (EXIT_SUCCESS);
+              test_main_return (EXIT_SUCCESS);
             }
         }
       if (margc < 2 || !STREQ (margv[margc - 1], "]"))
@@ -864,12 +866,12 @@ main (int margc, char **margv)
   pos = 1;
 
   if (pos >= argc)
-    test_exit (TEST_FALSE);
+    test_main_return (TEST_FALSE);
 
   value = posixtest (argc - 1);
 
   if (pos != argc)
     test_syntax_error (_("extra argument %s"), quote (argv[pos]));
 
-  test_exit (value ? TEST_TRUE : TEST_FALSE);
+  test_main_return (value ? TEST_TRUE : TEST_FALSE);
 }
diff --git a/src/timeout.c b/src/timeout.c
index 68baa23..c4cc074 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -440,12 +440,10 @@ main (int argc, char **argv)
   if (monitored_pid == -1)
     {
       error (0, errno, _("fork system call failed"));
-      exit (EXIT_CANCELED);
+      return EXIT_CANCELED;
     }
   else if (monitored_pid == 0)
     {                           /* child */
-      int exit_status;
-
       /* exec doesn't reset SIG_IGN -> SIG_DFL.  */
       signal (SIGTTIN, SIG_DFL);
       signal (SIGTTOU, SIG_DFL);
@@ -453,9 +451,9 @@ main (int argc, char **argv)
       execvp (argv[0], argv);   /* FIXME: should we use "sh -c" ... here?  */
 
       /* exit like sh, env, nohup, ...  */
-      exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+      int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
       error (0, errno, _("failed to run command %s"), quote (argv[0]));
-      exit (exit_status);
+      return exit_status;
     }
   else
     {
@@ -500,8 +498,7 @@ main (int argc, char **argv)
         }
 
       if (timed_out && !preserve_status)
-        exit (EXIT_TIMEDOUT);
-      else
-        exit (status);
+        status = EXIT_TIMEDOUT;
+      return status;
     }
 }
diff --git a/src/touch.c b/src/touch.c
index 1ba2426..b128e88 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -433,5 +433,5 @@ main (int argc, char **argv)
   for (; optind < argc; ++optind)
     ok &= touch (argv[optind]);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/tr.c b/src/tr.c
index 06858f9..5905a63 100644
--- a/src/tr.c
+++ b/src/tr.c
@@ -1804,13 +1804,13 @@ main (int argc, char **argv)
 
   spec_init (s1);
   if (!parse_str (argv[optind], s1))
-    exit (EXIT_FAILURE);
+    return EXIT_FAILURE;
 
   if (non_option_args == 2)
     {
       spec_init (s2);
       if (!parse_str (argv[optind + 1], s2))
-        exit (EXIT_FAILURE);
+        return EXIT_FAILURE;
     }
   else
     s2 = NULL;
@@ -1944,5 +1944,5 @@ main (int argc, char **argv)
   if (close (STDIN_FILENO) != 0)
     error (EXIT_FAILURE, errno, _("standard input"));
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/true.c b/src/true.c
index 8a1c4f9..ea4833a 100644
--- a/src/true.c
+++ b/src/true.c
@@ -76,5 +76,5 @@ main (int argc, char **argv)
                      (char *) NULL);
     }
 
-  exit (EXIT_STATUS);
+  return EXIT_STATUS;
 }
diff --git a/src/truncate.c b/src/truncate.c
index f312509..44d0b96 100644
--- a/src/truncate.c
+++ b/src/truncate.c
@@ -420,5 +420,5 @@ main (int argc, char **argv)
         }
     }
 
-  exit (errors ? EXIT_FAILURE : EXIT_SUCCESS);
+  return errors ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/tsort.c b/src/tsort.c
index 661c717..8380ce8 100644
--- a/src/tsort.c
+++ b/src/tsort.c
@@ -557,5 +557,5 @@ main (int argc, char **argv)
 
   ok = tsort (optind == argc ? "-" : argv[optind]);
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/tty.c b/src/tty.c
index 16301e1..f8c2554 100644
--- a/src/tty.c
+++ b/src/tty.c
@@ -120,5 +120,5 @@ main (int argc, char **argv)
         puts (_("not a tty"));
     }
 
-  exit (isatty (STDIN_FILENO) ? EXIT_SUCCESS : EXIT_FAILURE);
+  return isatty (STDIN_FILENO) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/uname.c b/src/uname.c
index e3bed48..3cc3cba 100644
--- a/src/uname.c
+++ b/src/uname.c
@@ -371,5 +371,5 @@ main (int argc, char **argv)
 
   putchar ('\n');
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/unexpand.c b/src/unexpand.c
index 505e223..03c9a2e 100644
--- a/src/unexpand.c
+++ b/src/unexpand.c
@@ -528,5 +528,5 @@ main (int argc, char **argv)
   if (have_read_stdin && fclose (stdin) != 0)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (exit_status);
+  return exit_status;
 }
diff --git a/src/uniq.c b/src/uniq.c
index 54200ff..358d06c 100644
--- a/src/uniq.c
+++ b/src/uniq.c
@@ -662,5 +662,5 @@ main (int argc, char **argv)
 
   check_file (file[0], file[1], delimiter);
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/unlink.c b/src/unlink.c
index 260a530..a05aa32 100644
--- a/src/unlink.c
+++ b/src/unlink.c
@@ -85,5 +85,5 @@ main (int argc, char **argv)
   if (unlink (argv[optind]) != 0)
     error (EXIT_FAILURE, errno, _("cannot unlink %s"), quote (argv[optind]));
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/uptime.c b/src/uptime.c
index 4ab914f..93931d2 100644
--- a/src/uptime.c
+++ b/src/uptime.c
@@ -253,5 +253,5 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/users.c b/src/users.c
index ee44c81..a0dce19 100644
--- a/src/users.c
+++ b/src/users.c
@@ -147,5 +147,5 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/wc.c b/src/wc.c
index 4909d9f..2048025 100644
--- a/src/wc.c
+++ b/src/wc.c
@@ -797,5 +797,5 @@ main (int argc, char **argv)
   if (have_read_stdin && close (STDIN_FILENO) != 0)
     error (EXIT_FAILURE, errno, "-");
 
-  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/src/who.c b/src/who.c
index f07cee6..23e2511 100644
--- a/src/who.c
+++ b/src/who.c
@@ -828,5 +828,5 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  exit (EXIT_SUCCESS);
+  return EXIT_SUCCESS;
 }
diff --git a/src/whoami.c b/src/whoami.c
index 7301abb..545e521 100644
--- a/src/whoami.c
+++ b/src/whoami.c
@@ -83,12 +83,9 @@ main (int argc, char **argv)
   errno = 0;
   uid = geteuid ();
   pw = (uid == NO_UID && errno ? NULL : getpwuid (uid));
-  if (pw)
-    {
-      puts (pw->pw_name);
-      exit (EXIT_SUCCESS);
-    }
-  fprintf (stderr, _("%s: cannot find name for user ID %lu\n"),
-           program_name, (unsigned long int) uid);
-  exit (EXIT_FAILURE);
+  if (!pw)
+    error (EXIT_FAILURE, errno, "cannot find name for user ID %lu",
+           (unsigned long int) uid);
+  puts (pw->pw_name);
+  return EXIT_SUCCESS;
 }
diff --git a/src/yes.c b/src/yes.c
index 9721312..e5957b9 100644
--- a/src/yes.c
+++ b/src/yes.c
@@ -83,6 +83,9 @@ main (int argc, char **argv)
       for (i = optind; i < argc; i++)
         if (fputs (argv[i], stdout) == EOF
             || putchar (i == argc - 1 ? '\n' : ' ') == EOF)
-          error (EXIT_FAILURE, errno, _("standard output"));
+          {
+            error (0, errno, _("standard output"));
+            return EXIT_FAILURE;
+          }
     }
 }
-- 
1.9.3

From a1c1914969972a5190c42a97b49d9e6686721684 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 8 Sep 2014 20:41:44 -0700
Subject: [PATCH 4/4] maint: avoid file-scope names of the form _[a-z]*

The C standard says this isn't portable, if you include
standard include files.
* build-aux/gen-single-binary.sh:
* src/coreutils-arch.c (single_binary_main_arch)
(single_binary_main_uname):
* src/coreutils-dir.c (single_binary_main_ls)
(_single_binary_main_dir):
* src/coreutils-vdir.c (single_binary_main_ls)
(_single_binary_main_vdir):
* src/coreutils.c (SINGLE_BINARY_PROGRAM):
Remove leading _ from single_binary prefix.
* src/numfmt.c (round_style): Rename from _round.  All uses changed.
(inval_style): Rename from _invalid.  All uses changed.
---
 build-aux/gen-single-binary.sh |  6 +++---
 src/coreutils-arch.c           |  8 ++++----
 src/coreutils-dir.c            |  8 ++++----
 src/coreutils-vdir.c           |  8 ++++----
 src/coreutils.c                |  4 ++--
 src/numfmt.c                   | 26 ++++++++++++++------------
 6 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/build-aux/gen-single-binary.sh b/build-aux/gen-single-binary.sh
index 1128f40..4e07cfd 100755
--- a/build-aux/gen-single-binary.sh
+++ b/build-aux/gen-single-binary.sh
@@ -90,9 +90,9 @@ for cmd in $ALL_PROGRAMS; do
 
   # CFLAGS
   # Hack any other program defining a main() replacing its main by
-  # _single_binary_main_$PROGRAM_NAME.
-  echo "${base}_CFLAGS = \"-Dmain=_single_binary_main_${cmd} (int, char **);" \
-       " int _single_binary_main_${cmd}\" " \
+  # single_binary_main_$PROGRAM_NAME.
+  echo "${base}_CFLAGS = \"-Dmain=single_binary_main_${cmd} (int, char **);" \
+       " int single_binary_main_${cmd}\" " \
        "-Dusage=_usage_${cmd} \$(src_coreutils_CFLAGS)"
   var=src_${cmd}_CFLAGS
   eval "value=\$$var"
diff --git a/src/coreutils-arch.c b/src/coreutils-arch.c
index f55bef9..66e4990 100644
--- a/src/coreutils-arch.c
+++ b/src/coreutils-arch.c
@@ -22,12 +22,12 @@
 #include "uname.h"
 /* Ensure that the main for uname is declared even if the tool is not being
    built in this single-binary. */
-int _single_binary_main_uname (int argc, char **argv);
-int _single_binary_main_arch (int argc, char **argv);
+int single_binary_main_uname (int argc, char **argv);
+int single_binary_main_arch (int argc, char **argv);
 
 int
-_single_binary_main_arch (int argc, char **argv)
+single_binary_main_arch (int argc, char **argv)
 {
   uname_mode = UNAME_ARCH;
-  return _single_binary_main_uname (argc, argv);
+  return single_binary_main_uname (argc, argv);
 }
diff --git a/src/coreutils-dir.c b/src/coreutils-dir.c
index afbe39a..4543cb4 100644
--- a/src/coreutils-dir.c
+++ b/src/coreutils-dir.c
@@ -22,12 +22,12 @@
 #include "ls.h"
 /* Ensure that the main for ls is declared even if the tool is not being built
    in this single-binary. */
-int _single_binary_main_ls (int argc, char **argv);
-int _single_binary_main_dir (int argc, char **argv);
+int single_binary_main_ls (int argc, char **argv);
+int single_binary_main_dir (int argc, char **argv);
 
 int
-_single_binary_main_dir (int argc, char **argv)
+single_binary_main_dir (int argc, char **argv)
 {
   ls_mode = LS_MULTI_COL;
-  return _single_binary_main_ls (argc, argv);
+  return single_binary_main_ls (argc, argv);
 }
diff --git a/src/coreutils-vdir.c b/src/coreutils-vdir.c
index b1b0194..223f70c 100644
--- a/src/coreutils-vdir.c
+++ b/src/coreutils-vdir.c
@@ -22,12 +22,12 @@
 #include "ls.h"
 /* Ensure that the main for ls is declared even if the tool is not being built
    in this single-binary. */
-int _single_binary_main_ls (int argc, char **argv);
-int _single_binary_main_vdir (int argc, char **argv);
+int single_binary_main_ls (int argc, char **argv);
+int single_binary_main_vdir (int argc, char **argv);
 
 int
-_single_binary_main_vdir (int argc, char** argv)
+single_binary_main_vdir (int argc, char** argv)
 {
   ls_mode = LS_LONG_FORMAT;
-  return _single_binary_main_ls (argc, argv);
+  return single_binary_main_ls (argc, argv);
 }
diff --git a/src/coreutils.c b/src/coreutils.c
index 898fe84..57dc784 100644
--- a/src/coreutils.c
+++ b/src/coreutils.c
@@ -35,7 +35,7 @@
    needs to match the one passed as CFLAGS on single-binary.mk (generated
    by gen-single-binary.sh). */
 # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
-  int _single_binary_main_##main_name (int, char **);
+  int single_binary_main_##main_name (int, char **);
 # include "coreutils.h"
 # undef SINGLE_BINARY_PROGRAM
 #endif
@@ -103,7 +103,7 @@ launch_program (const char *prog_name, int prog_argc, char **prog_argv)
   /* Look up the right main program.  */
 # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
   else if (STREQ (prog_name_str, prog_name)) \
-    prog_main = _single_binary_main_##main_name;
+    prog_main = single_binary_main_##main_name;
 # include "coreutils.h"
 # undef SINGLE_BINARY_PROGRAM
 #endif
diff --git a/src/numfmt.c b/src/numfmt.c
index f111374..ff2e41d 100644
--- a/src/numfmt.c
+++ b/src/numfmt.c
@@ -161,8 +161,8 @@ enum { MAX_ACCEPTABLE_DIGITS = 27 };
 
 static enum scale_type scale_from = scale_none;
 static enum scale_type scale_to = scale_none;
-static enum round_type _round = round_from_zero;
-static enum inval_type _invalid = inval_abort;
+static enum round_type round_style = round_from_zero;
+static enum inval_type inval_style = inval_abort;
 static const char *suffix = NULL;
 static uintmax_t from_unit_size = 1;
 static uintmax_t to_unit_size = 1;
@@ -677,7 +677,7 @@ simple_strtod_fatal (enum simple_strtod_error err, char const *input_str)
 
     }
 
-  if (_invalid != inval_ignore)
+  if (inval_style != inval_ignore)
     error (conv_exit_code, 0, gettext (msgid), quote (input_str));
 }
 
@@ -1077,7 +1077,7 @@ parse_human_number (const char *str, long double /*output */ *value,
 
   if (ptr && *ptr != '\0')
     {
-      if (_invalid != inval_ignore)
+      if (inval_style != inval_ignore)
         error (conv_exit_code, 0, _("invalid suffix in input %s: %s"),
                quote_n (0, str), quote_n (1, ptr));
       e = SSE_INVALID_SUFFIX;
@@ -1099,7 +1099,7 @@ prepare_padded_number (const long double val, size_t precision)
   expld (val, 10, &x);
   if (scale_to == scale_none && x > MAX_UNSCALED_DIGITS)
     {
-      if (_invalid != inval_ignore)
+      if (inval_style != inval_ignore)
         error (conv_exit_code, 0, _("value too large to be printed: '%Lg'"
                                     " (consider using --to)"), val);
       return 0;
@@ -1107,14 +1107,14 @@ prepare_padded_number (const long double val, size_t precision)
 
   if (x > MAX_ACCEPTABLE_DIGITS - 1)
     {
-      if (_invalid != inval_ignore)
+      if (inval_style != inval_ignore)
         error (conv_exit_code, 0, _("value too large to be printed: '%Lg'"
                                     " (cannot handle values > 999Y)"), val);
       return 0;
     }
 
   double_to_human (val, precision, buf, sizeof (buf), scale_to, grouping,
-                   _round);
+                   round_style);
   if (suffix)
     strncat (buf, suffix, sizeof (buf) - strlen (buf) -1);
 
@@ -1304,7 +1304,7 @@ process_line (char *line, bool newline)
 
   extract_fields (line, field, &pre, &num, &suf);
   if (!num)
-    if (_invalid != inval_ignore)
+    if (inval_style != inval_ignore)
       error (conv_exit_code, 0, _("input line is too short, "
                                   "no numbers found to convert in field %ld"),
            field);
@@ -1390,7 +1390,7 @@ main (int argc, char **argv)
           break;
 
         case ROUND_OPTION:
-          _round = XARGMATCH ("--round", optarg, round_args, round_types);
+          round_style = XARGMATCH ("--round", optarg, round_args, round_types);
           break;
 
         case GROUPING_OPTION:
@@ -1458,7 +1458,8 @@ main (int argc, char **argv)
           break;
 
         case INVALID_OPTION:
-          _invalid = XARGMATCH ("--invalid", optarg, inval_args, inval_types);
+          inval_style = XARGMATCH ("--invalid", optarg,
+                                   inval_args, inval_types);
           break;
 
           case_GETOPT_HELP_CHAR;
@@ -1492,7 +1493,7 @@ main (int argc, char **argv)
   setup_padding_buffer (padding_width);
   auto_padding = (padding_width == 0 && delimiter == DELIMITER_DEFAULT);
 
-  if (_invalid != inval_abort)
+  if (inval_style != inval_abort)
     conv_exit_code = 0;
 
   if (argc > optind)
@@ -1535,7 +1536,8 @@ main (int argc, char **argv)
     error (0, 0, _("failed to convert some of the input numbers"));
 
   int exit_status = EXIT_SUCCESS;
-  if (!valid_numbers && _invalid != inval_warn && _invalid != inval_ignore)
+  if (!valid_numbers
+      && inval_style != inval_warn && inval_style != inval_ignore)
     exit_status = EXIT_CONVERSION_WARNINGS;
 
   return exit_status;
-- 
1.9.3