aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-05-21 18:28:13 +0000
committerRob Landley <rob@landley.net>2006-05-21 18:28:13 +0000
commitc020f5f518714af603488c7d9e6cc72543fabc49 (patch)
tree1030744a4f3b96c0d3d7498e65635f8ecc898f45
parent4148afe04975c6003bde330db2b074d49f25f5d3 (diff)
downloadbusybox-w32-c020f5f518714af603488c7d9e6cc72543fabc49.tar.gz
busybox-w32-c020f5f518714af603488c7d9e6cc72543fabc49.tar.bz2
busybox-w32-c020f5f518714af603488c7d9e6cc72543fabc49.zip
New version of nohup that's much smaller, less paranoid, consistent,
vaguely portable, and licensed GPLv2 "or later".
-rw-r--r--coreutils/nohup.c202
-rw-r--r--include/platform.h2
-rw-r--r--miscutils/crond.c15
3 files changed, 38 insertions, 181 deletions
diff --git a/coreutils/nohup.c b/coreutils/nohup.c
index febaf547f..ea1c4c55a 100644
--- a/coreutils/nohup.c
+++ b/coreutils/nohup.c
@@ -1,185 +1,55 @@
1/* vi: set sw=4 ts=4: */ 1/* vi:set ts=4: */
2/* nohup -- run a command immune to hangups, with output to a non-tty 2/* nohup - invoke a utility immune to hangups.
3 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 3 *
4 4 * Busybox version based on nohup specification at
5 Licensed under the GPL v2, see the file LICENSE in this tarball. 5 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
6 6 *
7 * Copyright 2006 Rob Landley <rob@landley.net>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */ 10 */
8 11
9/* Written by Jim Meyering */
10/* initial busybox port by Bernhard Fischer */
11
12#include <stdio_ext.h> /* __fpending */
13#include <stdio.h>
14#include <unistd.h>
15#include <fcntl.h> 12#include <fcntl.h>
16#include <sys/types.h> 13#include <unistd.h>
17#include <signal.h>
18#include <errno.h>
19
20#include "busybox.h" 14#include "busybox.h"
21#define EXIT_CANNOT_INVOKE (126)
22#define NOHUP_FAILURE (127)
23#define EXIT_ENOENT NOHUP_FAILURE
24
25 15
26 16int nohup_main(int argc, char *argv[])
27#if defined F_GETFD && defined F_SETFD
28static inline int set_cloexec_flag (int desc)
29{ 17{
30 int flags = fcntl (desc, F_GETFD, 0); 18 int temp, nullfd;
31 if (0 <= flags) { 19 char *nohupout = "nohup.out", *home = NULL;
32 if (flags == (flags |= FD_CLOEXEC) ||
33 fcntl (desc, F_SETFD, flags) != -1) {
34 return 0;
35 }
36 }
37 return -1;
38}
39#else
40#define set_cloexec_flag(desc) (0)
41#endif
42
43static int fd_reopen (int desired_fd, char const *file, int flags)
44{
45 int fd;
46
47 close (desired_fd);
48 fd = open (file, flags | O_WRONLY, S_IRUSR | S_IWUSR);
49 if (fd == desired_fd || fd < 0)
50 return fd;
51 else {
52 int fd2 = fcntl (fd, F_DUPFD, desired_fd);
53 int saved_errno = errno;
54 close (fd);
55 errno = saved_errno;
56 return fd2;
57 }
58}
59
60 20
61/* Close standard output, exiting with status 'exit_failure' on failure. 21 if (argc<2) bb_show_usage();
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.
73 22
74 Besides, it's wasteful to check the return value from every call 23 nullfd = bb_xopen(bb_dev_null, O_WRONLY|O_APPEND);
75 that writes to stdout -- just let the internal stream state record 24 // If stdin is a tty, detach from it.
76 the failure. That's what the ferror test is checking below.
77 25
78 It's important to detect such failures and exit nonzero because many 26 if (isatty(0)) dup2(nullfd, 0);
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. */
81
82static void close_stdout (void)
83{
84 int prev_fail = ferror (stdout);
85 int none_pending = (0 == __fpending (stdout));
86 int fclose_fail = fclose (stdout);
87 27
88 if (prev_fail || fclose_fail) { 28 // Redirect stdout to nohup.out, either in "." or in "$HOME".
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)
96 return;
97 29
98 bb_perror_msg_and_die(bb_msg_write_error); 30 if (isatty(1)) {
99 } 31 close(1);
100} 32 if (open(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR) < 0) {
101 33 home = getenv("HOME");
102 34 if (home) {
103int nohup_main (int argc, char **argv) 35 home = concat_path_file(home, nohupout);
104{ 36 bb_xopen3(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR);
105 int saved_stderr_fd;
106
107 if (argc < 2)
108 bb_show_usage();
109
110 bb_default_error_retval = NOHUP_FAILURE;
111
112 atexit (close_stdout);
113
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, bb_dev_null, 0);
119
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, O_CREAT | O_APPEND);
126
127 if (fd < 0) {
128 if ((in_home = getenv ("HOME")) != NULL) {
129 in_home = concat_path_file(in_home, file);
130 fd = fd_reopen (STDOUT_FILENO, in_home, O_CREAT | O_APPEND);
131 } 37 }
132 if (fd < 0) {
133 bb_perror_msg("failed to open '%s'", file);
134 if (in_home)
135 bb_perror_msg("failed to open '%s'",in_home);
136 return (NOHUP_FAILURE);
137 }
138 file = in_home;
139 }
140
141 umask (~(S_IRUSR | S_IWUSR));
142 bb_error_msg("appending output to '%s'", file);
143 if (ENABLE_FEATURE_CLEAN_UP)
144 free (in_home);
145 }
146
147 /* If standard error is a tty, redirect it to stdout. */
148 if (isatty (STDERR_FILENO)) {
149 /* Save a copy of stderr before redirecting, so we can use the original
150 if execve fails. It's no big deal if this dup fails. It might
151 not change anything, and at worst, it'll lead to suppression of
152 the post-failed-execve diagnostic. */
153 saved_stderr_fd = dup (STDERR_FILENO);
154
155 if (0 <= saved_stderr_fd && set_cloexec_flag (saved_stderr_fd) == -1)
156 bb_perror_msg_and_die("failed to set the copy"
157 "of stderr to close on exec");
158
159 if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0) {
160 if (errno != EBADF)
161 bb_perror_msg_and_die("failed to redirect standard error");
162 close (STDERR_FILENO);
163 } 38 }
164 } else 39 } else dup2(nullfd, 1);
165 saved_stderr_fd = STDERR_FILENO;
166 40
167 signal (SIGHUP, SIG_IGN); 41 // If we have a tty on strderr, announce filename and redirect to stdout.
42 // Else redirect to /dev/null.
168 43
169 { 44 temp = isatty(2);
170 char **cmd = argv + 1; 45 if (temp) fdprintf(2,"Writing to %s\n", home ? home : nohupout);
46 dup2(temp ? 1 : nullfd, 2);
171 47
172 execvp (*cmd, cmd); 48 close(nullfd);
173 49
174 /* The execve failed. Output a diagnostic to stderr only if: 50 // Exec our new program.
175 - stderr was initially redirected to a non-tty, or
176 - stderr was initially directed to a tty, and we
177 can dup2 it to point back to that same tty.
178 In other words, output the diagnostic if possible, but only if
179 it will go to the original stderr. */
180 if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
181 bb_perror_msg("cannot run command '%s'",*cmd);
182 51
183 return (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); 52 execvp(argv[1],argv+1);
184 } 53 if (ENABLE_FEATURE_CLEAN_UP) free(home);
54 bb_error_msg_and_die("exec %s",argv[1]);
185} 55}
diff --git a/include/platform.h b/include/platform.h
index 8bebb234e..62b4efba9 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -105,4 +105,6 @@
105#define _(Text) Text 105#define _(Text) Text
106#define N_(Text) (Text) 106#define N_(Text) (Text)
107 107
108#define fdprintf(...) dprintf(__VA_ARGS__)
109
108#endif /* platform.h */ 110#endif /* platform.h */
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 9b194d13a..030e962f3 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -283,21 +283,6 @@ int crond_main(int ac, char **av)
283 bb_fflush_stdout_and_exit(EXIT_SUCCESS); /* not reached */ 283 bb_fflush_stdout_and_exit(EXIT_SUCCESS); /* not reached */
284} 284}
285 285
286#if ENABLE_DEBUG_CROND_OPTION || ENABLE_FEATURE_CROND_CALL_SENDMAIL
287/*
288 write to temp file..
289*/
290static void fdprintf(int fd, const char *ctl, ...)
291{
292 va_list va;
293
294 va_start(va, ctl);
295 vdprintf(fd, ctl, va);
296 va_end(va);
297}
298#endif
299
300
301static int ChangeUser(const char *user) 286static int ChangeUser(const char *user)
302{ 287{
303 struct passwd *pas; 288 struct passwd *pas;