source: trunk/coreutils/src/nohup.c@ 2662

Last change on this file since 2662 was 2554, checked in by bird, 20 years ago

coretuils-5.94

File size: 5.2 KB
Line 
1/* nohup -- run a command immune to hangups, with output to a non-tty
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3
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)
7 any later version.
8
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.
13
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. */
17
18/* Written by Jim Meyering */
19
20#include <config.h>
21#include <getopt.h>
22#include <stdio.h>
23#include <sys/types.h>
24#include <signal.h>
25
26#include "system.h"
27
28#include "cloexec.h"
29#include "error.h"
30#include "filenamecat.h"
31#include "fd-reopen.h"
32#include "long-options.h"
33#include "quote.h"
34#include "unistd--.h"
35
36#define PROGRAM_NAME "nohup"
37
38#define AUTHORS "Jim Meyering"
39
40/* Exit statuses. */
41enum
42 {
43 /* `nohup' itself failed. */
44 NOHUP_FAILURE = 127
45 };
46
47char *program_name;
48
49void
50usage (int status)
51{
52 if (status != EXIT_SUCCESS)
53 fprintf (stderr, _("Try `%s --help' for more information.\n"),
54 program_name);
55 else
56 {
57 printf (_("\
58Usage: %s COMMAND [ARG]...\n\
59 or: %s OPTION\n\
60"),
61 program_name, program_name);
62
63 fputs (_("\
64Run COMMAND, ignoring hangup signals.\n\
65\n\
66"), stdout);
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);
71 }
72 exit (status);
73}
74
75int
76main (int argc, char **argv)
77{
78 int saved_stderr_fd = STDERR_FILENO;
79
80 initialize_main (&argc, &argv);
81 program_name = argv[0];
82 setlocale (LC_ALL, "");
83 bindtextdomain (PACKAGE, LOCALEDIR);
84 textdomain (PACKAGE);
85
86 initialize_exit_failure (NOHUP_FAILURE);
87 atexit (close_stdout);
88
89 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
90 usage, AUTHORS, (char const *) NULL);
91 if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
92 usage (NOHUP_FAILURE);
93
94 if (argc <= optind)
95 {
96 error (0, 0, _("missing operand"));
97 usage (NOHUP_FAILURE);
98 }
99
100 /* If standard input is a tty, replace it with /dev/null.
101 Note that it is deliberately opened for *writing*,
102 to ensure any read evokes an error. */
103 if (isatty (STDIN_FILENO))
104 fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0);
105
106 /* If standard output is a tty, redirect it (appending) to a file.
107 First try nohup.out, then $HOME/nohup.out. */
108 if (isatty (STDOUT_FILENO))
109 {
110 char *in_home = NULL;
111 char const *file = "nohup.out";
112 int flags = O_CREAT | O_WRONLY | O_APPEND;
113 mode_t mode = S_IRUSR | S_IWUSR;
114 mode_t umask_value = umask (~mode);
115 int fd = fd_reopen (STDOUT_FILENO, file, flags, mode);
116
117 if (fd < 0)
118 {
119 int saved_errno = errno;
120 char const *home = getenv ("HOME");
121 if (home)
122 {
123 in_home = file_name_concat (home, file, NULL);
124 fd = fd_reopen (STDOUT_FILENO, in_home, flags, mode);
125 }
126 if (fd < 0)
127 {
128 int saved_errno2 = errno;
129 error (0, saved_errno, _("failed to open %s"), quote (file));
130 if (in_home)
131 error (0, saved_errno2, _("failed to open %s"),
132 quote (in_home));
133 exit (NOHUP_FAILURE);
134 }
135 file = in_home;
136 }
137
138 umask (umask_value);
139 error (0, 0, _("appending output to %s"), quote (file));
140 free (in_home);
141 }
142
143 /* If standard error is a tty, redirect it to stdout. */
144 if (isatty (STDERR_FILENO))
145 {
146 /* Save a copy of stderr before redirecting, so we can use the original
147 if execve fails. It's no big deal if this dup fails. It might
148 not change anything, and at worst, it'll lead to suppression of
149 the post-failed-execve diagnostic. */
150 saved_stderr_fd = dup (STDERR_FILENO);
151
152 if (0 <= saved_stderr_fd
153 && set_cloexec_flag (saved_stderr_fd, true) != 0)
154 error (NOHUP_FAILURE, errno,
155 _("failed to set the copy of stderr to close on exec"));
156
157 if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0)
158 {
159 if (errno != EBADF)
160 error (NOHUP_FAILURE, errno,
161 _("failed to redirect standard error"));
162 close (STDERR_FILENO);
163 }
164 }
165
166 signal (SIGHUP, SIG_IGN);
167
168 {
169 int exit_status;
170 int saved_errno;
171 char **cmd = argv + optind;
172
173 execvp (*cmd, cmd);
174 exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
175 saved_errno = errno;
176
177 /* The execve failed. Output a diagnostic to stderr only if:
178 - stderr was initially redirected to a non-tty, or
179 - stderr was initially directed to a tty, and we
180 can dup2 it to point back to that same tty.
181 In other words, output the diagnostic if possible, but only if
182 it will go to the original stderr. */
183 if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
184 error (0, saved_errno, _("cannot run command %s"), quote (*cmd));
185
186 exit (exit_status);
187 }
188}
Note: See TracBrowser for help on using the repository browser.