summaryrefslogtreecommitdiff
path: root/src/nohup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nohup.c')
-rw-r--r--src/nohup.c182
1 files changed, 99 insertions, 83 deletions
diff --git a/src/nohup.c b/src/nohup.c
index 1f8e62b..11ccf3f 100644
--- a/src/nohup.c
+++ b/src/nohup.c
@@ -1,10 +1,10 @@
/* nohup -- run a command immune to hangups, with output to a non-tty
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003-2016 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,8 +12,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Jim Meyering */
@@ -30,35 +29,31 @@
#include "filenamecat.h"
#include "fd-reopen.h"
#include "long-options.h"
-#include "quote.h"
#include "unistd--.h"
#define PROGRAM_NAME "nohup"
-#define AUTHORS "Jim Meyering"
+#define AUTHORS proper_name ("Jim Meyering")
/* Exit statuses. */
enum
{
- /* `nohup' itself failed. */
- NOHUP_FAILURE = 127
+ /* 'nohup' itself failed. */
+ POSIX_NOHUP_FAILURE = 127
};
-char *program_name;
-
void
usage (int status)
{
if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
+ emit_try_help ();
else
{
printf (_("\
Usage: %s COMMAND [ARG]...\n\
or: %s OPTION\n\
"),
- program_name, program_name);
+ program_name, program_name);
fputs (_("\
Run COMMAND, ignoring hangup signals.\n\
@@ -66,8 +61,15 @@ Run COMMAND, ignoring hangup signals.\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
+ printf (_("\n\
+If standard input is a terminal, redirect it from an unreadable file.\n\
+If standard output is a terminal, append output to 'nohup.out' if possible,\n\
+'$HOME/nohup.out' otherwise.\n\
+If standard error is a terminal, redirect it to standard output.\n\
+To save output to FILE, use '%s COMMAND > FILE'.\n"),
+ program_name);
printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
@@ -81,25 +83,32 @@ main (int argc, char **argv)
bool redirecting_stdout;
bool stdout_is_closed;
bool redirecting_stderr;
+ int exit_internal_failure;
initialize_main (&argc, &argv);
- program_name = argv[0];
+ set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
- initialize_exit_failure (NOHUP_FAILURE);
+ /* POSIX 2008 requires that internal failure give status 127; unlike
+ for env, exec, nice, time, and xargs where it requires internal
+ failure give something in the range 1-125. For consistency with
+ other tools, fail with EXIT_CANCELED unless POSIXLY_CORRECT. */
+ exit_internal_failure = (getenv ("POSIXLY_CORRECT")
+ ? POSIX_NOHUP_FAILURE : EXIT_CANCELED);
+ initialize_exit_failure (exit_internal_failure);
atexit (close_stdout);
- parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
- usage, AUTHORS, (char const *) NULL);
+ parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
+ usage, AUTHORS, (char const *) NULL);
if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
- usage (NOHUP_FAILURE);
+ usage (exit_internal_failure);
if (argc <= optind)
{
error (0, 0, _("missing operand"));
- usage (NOHUP_FAILURE);
+ usage (exit_internal_failure);
}
ignoring_input = isatty (STDIN_FILENO);
@@ -112,9 +121,11 @@ main (int argc, char **argv)
to ensure any read evokes an error. */
if (ignoring_input)
{
- fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0);
+ if (fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0) < 0)
+ error (exit_internal_failure, errno,
+ _("failed to render standard input unusable"));
if (!redirecting_stdout && !redirecting_stderr)
- error (0, 0, _("ignoring input"));
+ error (0, 0, _("ignoring input"));
}
/* If standard output is a tty, redirect it (appending) to a file.
@@ -129,38 +140,38 @@ main (int argc, char **argv)
mode_t mode = S_IRUSR | S_IWUSR;
mode_t umask_value = umask (~mode);
out_fd = (redirecting_stdout
- ? fd_reopen (STDOUT_FILENO, file, flags, mode)
- : open (file, flags, mode));
+ ? fd_reopen (STDOUT_FILENO, file, flags, mode)
+ : open (file, flags, mode));
if (out_fd < 0)
- {
- int saved_errno = errno;
- char const *home = getenv ("HOME");
- if (home)
- {
- in_home = file_name_concat (home, file, NULL);
- out_fd = (redirecting_stdout
- ? fd_reopen (STDOUT_FILENO, in_home, flags, mode)
- : open (in_home, flags, mode));
- }
- if (out_fd < 0)
- {
- int saved_errno2 = errno;
- error (0, saved_errno, _("failed to open %s"), quote (file));
- if (in_home)
- error (0, saved_errno2, _("failed to open %s"),
- quote (in_home));
- exit (NOHUP_FAILURE);
- }
- file = in_home;
- }
+ {
+ int saved_errno = errno;
+ char const *home = getenv ("HOME");
+ if (home)
+ {
+ in_home = file_name_concat (home, file, NULL);
+ out_fd = (redirecting_stdout
+ ? fd_reopen (STDOUT_FILENO, in_home, flags, mode)
+ : open (in_home, flags, mode));
+ }
+ if (out_fd < 0)
+ {
+ int saved_errno2 = errno;
+ error (0, saved_errno, _("failed to open %s"), quoteaf (file));
+ if (in_home)
+ error (0, saved_errno2, _("failed to open %s"),
+ quoteaf (in_home));
+ return exit_internal_failure;
+ }
+ file = in_home;
+ }
umask (umask_value);
error (0, 0,
- _(ignoring_input
- ? "ignoring input and appending output to %s"
- : "appending output to %s"),
- quote (file));
+ _(ignoring_input
+ ? N_("ignoring input and appending output to %s")
+ : N_("appending output to %s")),
+ quoteaf (file));
free (in_home);
}
@@ -168,49 +179,54 @@ main (int argc, char **argv)
if (redirecting_stderr)
{
/* Save a copy of stderr before redirecting, so we can use the original
- if execve fails. It's no big deal if this dup fails. It might
- not change anything, and at worst, it'll lead to suppression of
- the post-failed-execve diagnostic. */
+ if execve fails. It's no big deal if this dup fails. It might
+ not change anything, and at worst, it'll lead to suppression of
+ the post-failed-execve diagnostic. */
saved_stderr_fd = dup (STDERR_FILENO);
if (0 <= saved_stderr_fd
- && set_cloexec_flag (saved_stderr_fd, true) != 0)
- error (NOHUP_FAILURE, errno,
- _("failed to set the copy of stderr to close on exec"));
+ && set_cloexec_flag (saved_stderr_fd, true) != 0)
+ error (exit_internal_failure, errno,
+ _("failed to set the copy of stderr to close on exec"));
if (!redirecting_stdout)
- error (0, 0,
- _(ignoring_input
- ? "ignoring input and redirecting stderr to stdout"
- : "redirecting stderr to stdout"));
+ error (0, 0,
+ _(ignoring_input
+ ? N_("ignoring input and redirecting stderr to stdout")
+ : N_("redirecting stderr to stdout")));
if (dup2 (out_fd, STDERR_FILENO) < 0)
- error (NOHUP_FAILURE, errno, _("failed to redirect standard error"));
+ error (exit_internal_failure, errno,
+ _("failed to redirect standard error"));
if (stdout_is_closed)
- close (out_fd);
+ close (out_fd);
}
+ /* error() flushes stderr, but does not check for write failure.
+ Normally, we would catch this via our atexit() hook of
+ close_stdout, but execvp() gets in the way. If stderr
+ encountered a write failure, there is no need to try calling
+ error() again, particularly since we may have just changed the
+ underlying fd out from under stderr. */
+ if (ferror (stderr))
+ 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, _("cannot 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"), quoteaf (*cmd));
+
+ return exit_status;
}