1 /* nohup -- run a command immume to hangups, with output to a non-tty
2 Copyright (C) 2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Jim Meyering */
22 #include <sys/types.h>
28 #include "long-options.h"
29 #include "path-concat.h"
32 #define PROGRAM_NAME "nohup"
34 #define AUTHORS "Jim Meyering"
39 /* `nohup' found the specified command but failed to invoke it. */
40 NOHUP_FOUND_BUT_CANNOT_INVOKE = 126,
42 /* `nohup' itself failed, or did not find the specified command. */
52 fprintf (stderr, _("Try `%s --help' for more information.\n"),
57 Usage: %s COMMAND [ARG]...\n\
60 program_name, program_name);
63 Run COMMAND, ignoring hangup signals.\n\
66 fputs (HELP_OPTION_DESCRIPTION, stdout);
67 fputs (VERSION_OPTION_DESCRIPTION, stdout);
68 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
74 main (int argc, char **argv)
77 int saved_stderr_fd = -1;
80 initialize_main (&argc, &argv);
81 program_name = argv[0];
82 setlocale (LC_ALL, "");
83 bindtextdomain (PACKAGE, LOCALEDIR);
86 atexit (close_stdout);
88 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
89 usage, AUTHORS, NULL);
91 /* The above handles --help and --version.
93 if (argc > 1 && STREQ (argv[1], "--"))
101 error (0, 0, _("too few arguments"));
102 usage (NOHUP_FAILURE);
105 /* If standard output is a tty, redirect it (appending) to a file.
106 First try nohup.out, then $HOME/nohup.out. */
107 if (isatty (STDOUT_FILENO))
109 char *in_home = NULL;
110 char const *file = "nohup.out";
111 int flags = O_CREAT | O_WRONLY | O_APPEND;
112 mode_t mode = S_IRUSR | S_IWUSR;
115 fd = open (file, flags, mode);
119 in_home = path_concat (getenv ("HOME"), file, NULL);
120 fd = open (in_home, flags, mode);
123 int saved_errno2 = errno;
124 error (0, saved_errno, _("failed to open %s"), quote (file));
125 error (0, saved_errno2, _("failed to open %s"), quote (in_home));
126 exit (NOHUP_FAILURE);
131 /* Redirect standard output to the file. */
132 if (dup2 (fd, STDOUT_FILENO) == -1)
133 error (NOHUP_FAILURE, errno, _("failed to redirect standard output"));
135 error (0, 0, _("appending output to %s"), quote (file));
144 /* If stderr is on a tty, redirect it to stdout. */
145 if ((stderr_isatty = isatty (STDERR_FILENO)))
147 /* Save a copy of stderr before redirecting, so we can use the original
148 if execve fails. It's no big deal if this dup fails. It might
149 not change anything, and at worst, it'll lead to suppression of
150 the post-failed-execve diagnostic. */
151 saved_stderr_fd = dup (STDERR_FILENO);
153 if (dup2 (fd, STDERR_FILENO) == -1)
154 error (NOHUP_FAILURE, errno, _("failed to redirect standard error"));
157 /* Ignore hang-up signals. */
160 struct sigaction sigact;
161 sigact.sa_handler = SIG_IGN;
162 sigemptyset (&sigact.sa_mask);
164 sigaction (SIGHUP, &sigact, NULL);
166 signal (SIGHUP, SIG_IGN);
173 char **cmd = argv + 1;
176 exit_status = (errno == ENOENT
178 : NOHUP_FOUND_BUT_CANNOT_INVOKE);
181 /* The execve failed. Output a diagnostic to stderr only if:
182 - stderr was initially redirected to a non-tty, or
183 - stderr was initially directed to a tty, and we've
184 just dup2'd it to point back to that same tty.
185 In other words, output the diagnostic if possible, but not if
186 it'd go to nohup.out. */
188 || (saved_stderr_fd != -1
189 && dup2 (saved_stderr_fd, STDERR_FILENO) != -1))
190 error (0, saved_errno, _("cannot run command %s"), quote (*cmd));