diff options
author | Jim Meyering <jim@meyering.net> | 2003-07-11 20:34:29 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2003-07-11 20:34:29 +0000 |
commit | 8db77b89784b5fba5ec5b283eed4bf83ad4f5f28 (patch) | |
tree | 65c63d502a58c5c8e80758e0921486759c92dc25 /src/nohup.c | |
parent | 9c557c0a2782fa557b5b57a4f4420f0a06ffa125 (diff) | |
download | coreutils-8db77b89784b5fba5ec5b283eed4bf83ad4f5f28.tar.gz coreutils-8db77b89784b5fba5ec5b283eed4bf83ad4f5f28.tar.bz2 coreutils-8db77b89784b5fba5ec5b283eed4bf83ad4f5f28.zip |
New file. Rewrite of nohup.sh in C.
This solves a portability problem: on at least Solaris systems,
when nohup.sh used the vendor /bin/sh, it would exit with status
of `1' rather than the required 126 or 127 upon failure to exec
the specified program.
Diffstat (limited to 'src/nohup.c')
-rw-r--r-- | src/nohup.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/nohup.c b/src/nohup.c new file mode 100644 index 000000000..9c7aeff7e --- /dev/null +++ b/src/nohup.c @@ -0,0 +1,183 @@ +/* nohup -- run a command immume to hangups, with output to a non-tty + Copyright (C) 2003 Free Software Foundation, Inc. + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering */ + +#include <config.h> +#include <stdio.h> +#include <sys/types.h> +#include <signal.h> + +#include "system.h" + +#include "closeout.h" +#include "error.h" +#include "long-options.h" +#include "path-concat.h" +#include "quote.h" + +#define PROGRAM_NAME "nohup" + +#define AUTHORS "Jim Meyering" + +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s COMMAND [ARG]...\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + + fputs (_("\ +Run COMMAND, ignoring hangup signals.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int fd; + int saved_stderr_fd = -1; + int stderr_isatty; + + initialize_main (&argc, &argv); + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + /* The above handles --help and --version. + Now, handle `--'. */ + if (argc > 1 && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc <= 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + /* If standard output is a tty, redirect it (appending) to a file. + First try nohup.out, then $HOME/nohup.out. */ + if (isatty (STDOUT_FILENO)) + { + char *in_home = NULL; + char const *file = "nohup.out"; + int flags = O_CREAT | O_WRONLY | O_APPEND; + mode_t mode = S_IRUSR | S_IWUSR; + int saved_errno; + + fd = open (file, flags, mode); + if (fd == -1) + { + saved_errno = errno; + in_home = path_concat (getenv ("HOME"), file, NULL); + fd = open (in_home, flags, mode); + if (fd == -1) + { + int saved_errno2 = errno; + error (0, saved_errno, _("failed to open %s"), quote (file)); + error (0, saved_errno2, _("failed to open %s"), quote (in_home)); + exit (EXIT_FAILURE); + } + file = in_home; + } + + /* Redirect standard output to the file. */ + if (dup2 (fd, STDOUT_FILENO) == -1) + error (EXIT_FAILURE, errno, _("failed to redirect standard output")); + + error (0, 0, _("appending output to %s"), quote (file)); + if (in_home) + free (in_home); + } + else + { + fd = STDOUT_FILENO; + } + + /* If stderr is on a tty, redirect it to stdout. */ + if ((stderr_isatty = isatty (STDERR_FILENO))) + { + /* 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. */ + saved_stderr_fd = dup (STDERR_FILENO); + + if (dup2 (fd, STDERR_FILENO) == -1) + error (EXIT_FAILURE, errno, _("failed to redirect standard error")); + } + + /* Ignore hang-up signals. */ + { +#ifdef _POSIX_SOURCE + struct sigaction sigact; + sigact.sa_handler = SIG_IGN; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (SIGHUP, &sigact, NULL); +#else + signal (SIGHUP, SIG_IGN); +#endif + } + + { + int exit_status; + int saved_errno; + char **cmd = argv + 1; + + execvp (*cmd, cmd); + exit_status = (errno == ENOENT ? 127 : 126); + 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've + just dup2'd it to point back to that same tty. + In other words, output the diagnostic if possible, but not if + it'd go to nohup.out. */ + if ( ! stderr_isatty + || (saved_stderr_fd != -1 + && dup2 (saved_stderr_fd, STDERR_FILENO) != -1)) + error (0, saved_errno, _("cannot run command %s"), quote (*cmd)); + + exit (exit_status); + } +} |