1 /* nohup -- run a command immune to hangups, with output to a non-tty
2 Copyright (C) 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Written by Jim Meyering */
23 #include <sys/types.h>
30 #include "filenamecat.h"
31 #include "fd-reopen.h"
32 #include "long-options.h"
36 #define PROGRAM_NAME "nohup"
38 #define AUTHORS "Jim Meyering"
43 /* `nohup' itself failed. */
52 if (status
!= EXIT_SUCCESS
)
53 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
58 Usage: %s COMMAND [ARG]...\n\
61 program_name
, program_name
);
64 Run COMMAND, ignoring hangup signals.\n\
67 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
68 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
69 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
70 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
76 main (int argc
, char **argv
)
78 int out_fd
= STDOUT_FILENO
;
79 int saved_stderr_fd
= STDERR_FILENO
;
81 bool redirecting_stdout
;
82 bool stdout_is_closed
;
83 bool redirecting_stderr
;
85 initialize_main (&argc
, &argv
);
86 program_name
= argv
[0];
87 setlocale (LC_ALL
, "");
88 bindtextdomain (PACKAGE
, LOCALEDIR
);
91 initialize_exit_failure (NOHUP_FAILURE
);
92 atexit (close_stdout
);
94 parse_long_options (argc
, argv
, PROGRAM_NAME
, GNU_PACKAGE
, VERSION
,
95 usage
, AUTHORS
, (char const *) NULL
);
96 if (getopt_long (argc
, argv
, "+", NULL
, NULL
) != -1)
97 usage (NOHUP_FAILURE
);
101 error (0, 0, _("missing operand"));
102 usage (NOHUP_FAILURE
);
105 ignoring_input
= isatty (STDIN_FILENO
);
106 redirecting_stdout
= isatty (STDOUT_FILENO
);
107 stdout_is_closed
= (!redirecting_stdout
&& errno
== EBADF
);
108 redirecting_stderr
= isatty (STDERR_FILENO
);
110 /* If standard input is a tty, replace it with /dev/null if possible.
111 Note that it is deliberately opened for *writing*,
112 to ensure any read evokes an error. */
115 fd_reopen (STDIN_FILENO
, "/dev/null", O_WRONLY
, 0);
116 if (!redirecting_stdout
&& !redirecting_stderr
)
117 error (0, 0, _("ignoring input"));
120 /* If standard output is a tty, redirect it (appending) to a file.
121 First try nohup.out, then $HOME/nohup.out. If standard error is
122 a tty and standard output is closed, open nohup.out or
123 $HOME/nohup.out without redirecting anything. */
124 if (redirecting_stdout
|| (redirecting_stderr
&& stdout_is_closed
))
126 char *in_home
= NULL
;
127 char const *file
= "nohup.out";
128 int flags
= O_CREAT
| O_WRONLY
| O_APPEND
;
129 mode_t mode
= S_IRUSR
| S_IWUSR
;
130 mode_t umask_value
= umask (~mode
);
131 out_fd
= (redirecting_stdout
132 ? fd_reopen (STDOUT_FILENO
, file
, flags
, mode
)
133 : open (file
, flags
, mode
));
137 int saved_errno
= errno
;
138 char const *home
= getenv ("HOME");
141 in_home
= file_name_concat (home
, file
, NULL
);
142 out_fd
= (redirecting_stdout
143 ? fd_reopen (STDOUT_FILENO
, in_home
, flags
, mode
)
144 : open (in_home
, flags
, mode
));
148 int saved_errno2
= errno
;
149 error (0, saved_errno
, _("failed to open %s"), quote (file
));
151 error (0, saved_errno2
, _("failed to open %s"),
153 exit (NOHUP_FAILURE
);
161 ? "ignoring input and appending output to %s"
162 : "appending output to %s"),
167 /* If standard error is a tty, redirect it. */
168 if (redirecting_stderr
)
170 /* Save a copy of stderr before redirecting, so we can use the original
171 if execve fails. It's no big deal if this dup fails. It might
172 not change anything, and at worst, it'll lead to suppression of
173 the post-failed-execve diagnostic. */
174 saved_stderr_fd
= dup (STDERR_FILENO
);
176 if (0 <= saved_stderr_fd
177 && set_cloexec_flag (saved_stderr_fd
, true) != 0)
178 error (NOHUP_FAILURE
, errno
,
179 _("failed to set the copy of stderr to close on exec"));
181 if (!redirecting_stdout
)
184 ? "ignoring input and redirecting stderr to stdout"
185 : "redirecting stderr to stdout"));
187 if (dup2 (out_fd
, STDERR_FILENO
) < 0)
188 error (NOHUP_FAILURE
, errno
, _("failed to redirect standard error"));
190 if (stdout_is_closed
)
194 signal (SIGHUP
, SIG_IGN
);
199 char **cmd
= argv
+ optind
;
202 exit_status
= (errno
== ENOENT
? EXIT_ENOENT
: EXIT_CANNOT_INVOKE
);
205 /* The execve failed. Output a diagnostic to stderr only if:
206 - stderr was initially redirected to a non-tty, or
207 - stderr was initially directed to a tty, and we
208 can dup2 it to point back to that same tty.
209 In other words, output the diagnostic if possible, but only if
210 it will go to the original stderr. */
211 if (dup2 (saved_stderr_fd
, STDERR_FILENO
) == STDERR_FILENO
)
212 error (0, saved_errno
, _("cannot run command %s"), quote (*cmd
));