1 /* vi: set sw=4 ts=4: */
2 /* nohup -- run a command immune to hangups, with output to a non-tty
3 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
5 Licensed under the GPL v2, see the file LICENSE in this tarball.
9 /* Written by Jim Meyering */
10 /* initial busybox port by Bernhard Fischer */
12 #include <stdio_ext.h> /* __fpending */
16 #include <sys/types.h>
21 #define EXIT_CANNOT_INVOKE (126)
22 #define NOHUP_FAILURE (127)
23 #define EXIT_ENOENT NOHUP_FAILURE
27 #if defined F_GETFD && defined F_SETFD
28 static inline int set_cloexec_flag (int desc)
30 int flags = fcntl (desc, F_GETFD, 0);
32 if (flags == (flags |= FD_CLOEXEC) ||
33 fcntl (desc, F_SETFD, flags) != -1) {
40 #define set_cloexec_flag(desc) (0)
43 static int fd_reopen (int desired_fd, char const *file, int flags, mode_t mode)
48 fd = open (file, flags, mode);
49 if (fd == desired_fd || fd < 0)
52 int fd2 = fcntl (fd, F_DUPFD, desired_fd);
53 int saved_errno = errno;
61 /* Close standard output, exiting with status 'exit_failure' on failure.
62 If a program writes *anything* to stdout, that program should close
63 stdout and make sure that it succeeds before exiting. Otherwise,
64 suppose that you go to the extreme of checking the return status
65 of every function that does an explicit write to stdout. The last
66 printf can succeed in writing to the internal stream buffer, and yet
67 the fclose(stdout) could still fail (due e.g., to a disk full error)
68 when it tries to write out that buffered data. Thus, you would be
69 left with an incomplete output file and the offending program would
70 exit successfully. Even calling fflush is not always sufficient,
71 since some file systems (NFS and CODA) buffer written/flushed data
72 until an actual close call.
74 Besides, it's wasteful to check the return value from every call
75 that writes to stdout -- just let the internal stream state record
76 the failure. That's what the ferror test is checking below.
78 It's important to detect such failures and exit nonzero because many
79 tools (most notably `make' and other build-management systems) depend
80 on being able to detect failure in other tools via their exit status. */
82 static void close_stdout (void)
84 int prev_fail = ferror (stdout);
85 int none_pending = (0 == __fpending (stdout));
86 int fclose_fail = fclose (stdout);
88 if (prev_fail || fclose_fail) {
89 /* If ferror returned zero, no data remains to be flushed, and we'd
90 otherwise fail with EBADF due to a failed fclose, then assume that
91 it's ok to ignore the fclose failure. That can happen when a
92 program like cp is invoked like this `cp a b >&-' (i.e., with
93 stdout closed) and doesn't generate any output (hence no previous
94 error and nothing to be flushed). */
95 if ((fclose_fail ? errno : 0) == EBADF && !prev_fail && none_pending)
98 bb_perror_msg_and_die(bb_msg_write_error);
103 int nohup_main (int argc, char **argv)
110 bb_default_error_retval = NOHUP_FAILURE;
112 atexit (close_stdout);
114 /* If standard input is a tty, replace it with /dev/null.
115 Note that it is deliberately opened for *writing*,
116 to ensure any read evokes an error. */
117 if (isatty (STDIN_FILENO))
118 fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0);
120 /* If standard output is a tty, redirect it (appending) to a file.
121 First try nohup.out, then $HOME/nohup.out. */
122 if (isatty (STDOUT_FILENO)) {
123 char *in_home = NULL;
124 char const *file = "nohup.out";
125 int fd = fd_reopen (STDOUT_FILENO, file,
126 O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
129 if ((in_home = getenv ("HOME")) != NULL) {
130 in_home = concat_path_file(in_home, file);
131 fd = fd_reopen (STDOUT_FILENO, in_home,
132 O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
135 bb_perror_msg("failed to open '%s'", file);
137 bb_perror_msg("failed to open '%s'",in_home);
138 exit (NOHUP_FAILURE);
143 umask (~(S_IRUSR | S_IWUSR));
144 bb_error_msg("appending output to '%s'", file);
145 if (ENABLE_FEATURE_CLEAN_UP)
149 /* If standard error is a tty, redirect it to stdout. */
150 if (isatty (STDERR_FILENO)) {
151 /* Save a copy of stderr before redirecting, so we can use the original
152 if execve fails. It's no big deal if this dup fails. It might
153 not change anything, and at worst, it'll lead to suppression of
154 the post-failed-execve diagnostic. */
155 saved_stderr_fd = dup (STDERR_FILENO);
157 if (0 <= saved_stderr_fd && set_cloexec_flag (saved_stderr_fd) == -1)
158 bb_perror_msg_and_die("failed to set the copy"
159 "of stderr to close on exec");
161 if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0) {
163 bb_perror_msg_and_die("failed to redirect standard error");
164 close (STDERR_FILENO);
167 saved_stderr_fd = STDERR_FILENO;
169 signal (SIGHUP, SIG_IGN);
172 char **cmd = argv + 1;
176 /* The execve failed. Output a diagnostic to stderr only if:
177 - stderr was initially redirected to a non-tty, or
178 - stderr was initially directed to a tty, and we
179 can dup2 it to point back to that same tty.
180 In other words, output the diagnostic if possible, but only if
181 it will go to the original stderr. */
182 if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
183 bb_perror_msg("cannot run command '%s'",*cmd);
185 return (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);