Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/nohup.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* nohup -- run a command immune to hangups, with output to a non-tty | - | ||||||||||||||||||
2 | Copyright (C) 2003-2018 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 3 of the License, or | - | ||||||||||||||||||
7 | (at your option) 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, see <https://www.gnu.org/licenses/>. */ | - | ||||||||||||||||||
16 | - | |||||||||||||||||||
17 | /* Written by Jim Meyering */ | - | ||||||||||||||||||
18 | - | |||||||||||||||||||
19 | #include <config.h> | - | ||||||||||||||||||
20 | #include <getopt.h> | - | ||||||||||||||||||
21 | #include <stdio.h> | - | ||||||||||||||||||
22 | #include <sys/types.h> | - | ||||||||||||||||||
23 | #include <signal.h> | - | ||||||||||||||||||
24 | - | |||||||||||||||||||
25 | #include "system.h" | - | ||||||||||||||||||
26 | - | |||||||||||||||||||
27 | #include "error.h" | - | ||||||||||||||||||
28 | #include "filenamecat.h" | - | ||||||||||||||||||
29 | #include "fd-reopen.h" | - | ||||||||||||||||||
30 | #include "long-options.h" | - | ||||||||||||||||||
31 | #include "unistd--.h" | - | ||||||||||||||||||
32 | - | |||||||||||||||||||
33 | #define PROGRAM_NAME "nohup" | - | ||||||||||||||||||
34 | - | |||||||||||||||||||
35 | #define AUTHORS proper_name ("Jim Meyering") | - | ||||||||||||||||||
36 | - | |||||||||||||||||||
37 | static struct option const long_options[] = | - | ||||||||||||||||||
38 | { | - | ||||||||||||||||||
39 | {NULL, 0, NULL, 0} | - | ||||||||||||||||||
40 | }; | - | ||||||||||||||||||
41 | - | |||||||||||||||||||
42 | /* Exit statuses. */ | - | ||||||||||||||||||
43 | enum | - | ||||||||||||||||||
44 | { | - | ||||||||||||||||||
45 | /* 'nohup' itself failed. */ | - | ||||||||||||||||||
46 | POSIX_NOHUP_FAILURE = 127 | - | ||||||||||||||||||
47 | }; | - | ||||||||||||||||||
48 | - | |||||||||||||||||||
49 | void | - | ||||||||||||||||||
50 | usage (int status) | - | ||||||||||||||||||
51 | { | - | ||||||||||||||||||
52 | if (status != EXIT_SUCCESS)
| 3-5 | ||||||||||||||||||
53 | emit_try_help (); executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
54 | else | - | ||||||||||||||||||
55 | { | - | ||||||||||||||||||
56 | printf (_("\ | - | ||||||||||||||||||
57 | Usage: %s COMMAND [ARG]...\n\ | - | ||||||||||||||||||
58 | or: %s OPTION\n\ | - | ||||||||||||||||||
59 | "), | - | ||||||||||||||||||
60 | program_name, program_name); | - | ||||||||||||||||||
61 | - | |||||||||||||||||||
62 | fputs (_("\ | - | ||||||||||||||||||
63 | Run COMMAND, ignoring hangup signals.\n\ | - | ||||||||||||||||||
64 | \n\ | - | ||||||||||||||||||
65 | "), stdout); | - | ||||||||||||||||||
66 | fputs (HELP_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||
67 | fputs (VERSION_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||
68 | printf (_("\n\ | - | ||||||||||||||||||
69 | If standard input is a terminal, redirect it from an unreadable file.\n\ | - | ||||||||||||||||||
70 | If standard output is a terminal, append output to 'nohup.out' if possible,\n\ | - | ||||||||||||||||||
71 | '$HOME/nohup.out' otherwise.\n\ | - | ||||||||||||||||||
72 | If standard error is a terminal, redirect it to standard output.\n\ | - | ||||||||||||||||||
73 | To save output to FILE, use '%s COMMAND > FILE'.\n"), | - | ||||||||||||||||||
74 | program_name); | - | ||||||||||||||||||
75 | printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); | - | ||||||||||||||||||
76 | emit_ancillary_info (PROGRAM_NAME); | - | ||||||||||||||||||
77 | } executed 3 times by 1 test: end of block Executed by:
| 3 | ||||||||||||||||||
78 | exit (status); executed 8 times by 1 test: exit (status); Executed by:
| 8 | ||||||||||||||||||
79 | } | - | ||||||||||||||||||
80 | - | |||||||||||||||||||
81 | int | - | ||||||||||||||||||
82 | main (int argc, char **argv) | - | ||||||||||||||||||
83 | { | - | ||||||||||||||||||
84 | int out_fd = STDOUT_FILENO; | - | ||||||||||||||||||
85 | int saved_stderr_fd = STDERR_FILENO; | - | ||||||||||||||||||
86 | bool ignoring_input; | - | ||||||||||||||||||
87 | bool redirecting_stdout; | - | ||||||||||||||||||
88 | bool stdout_is_closed; | - | ||||||||||||||||||
89 | bool redirecting_stderr; | - | ||||||||||||||||||
90 | int exit_internal_failure; | - | ||||||||||||||||||
91 | - | |||||||||||||||||||
92 | initialize_main (&argc, &argv); | - | ||||||||||||||||||
93 | set_program_name (argv[0]); | - | ||||||||||||||||||
94 | setlocale (LC_ALL, ""); | - | ||||||||||||||||||
95 | bindtextdomain (PACKAGE, LOCALEDIR); | - | ||||||||||||||||||
96 | textdomain (PACKAGE); | - | ||||||||||||||||||
97 | - | |||||||||||||||||||
98 | /* POSIX 2008 requires that internal failure give status 127; unlike | - | ||||||||||||||||||
99 | for env, exec, nice, time, and xargs where it requires internal | - | ||||||||||||||||||
100 | failure give something in the range 1-125. For consistency with | - | ||||||||||||||||||
101 | other tools, fail with EXIT_CANCELED unless POSIXLY_CORRECT. */ | - | ||||||||||||||||||
102 | exit_internal_failure = (getenv ("POSIXLY_CORRECT")
| 1-14 | ||||||||||||||||||
103 | ? POSIX_NOHUP_FAILURE : EXIT_CANCELED); | - | ||||||||||||||||||
104 | initialize_exit_failure (exit_internal_failure); | - | ||||||||||||||||||
105 | atexit (close_stdout); | - | ||||||||||||||||||
106 | - | |||||||||||||||||||
107 | parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, | - | ||||||||||||||||||
108 | usage, AUTHORS, (char const *) NULL); | - | ||||||||||||||||||
109 | if (getopt_long (argc, argv, "+", long_options, NULL) != -1)
| 3-4 | ||||||||||||||||||
110 | usage (exit_internal_failure); executed 3 times by 1 test: usage (exit_internal_failure); Executed by:
| 3 | ||||||||||||||||||
111 | - | |||||||||||||||||||
112 | if (argc <= optind)
| 2 | ||||||||||||||||||
113 | { | - | ||||||||||||||||||
114 | error (0, 0, _("missing operand")); | - | ||||||||||||||||||
115 | usage (exit_internal_failure); | - | ||||||||||||||||||
116 | } never executed: end of block | 0 | ||||||||||||||||||
117 | - | |||||||||||||||||||
118 | ignoring_input = isatty (STDIN_FILENO); | - | ||||||||||||||||||
119 | redirecting_stdout = isatty (STDOUT_FILENO); | - | ||||||||||||||||||
120 | stdout_is_closed = (!redirecting_stdout && errno == EBADF);
| 0-2 | ||||||||||||||||||
121 | redirecting_stderr = isatty (STDERR_FILENO); | - | ||||||||||||||||||
122 | - | |||||||||||||||||||
123 | /* If standard input is a tty, replace it with /dev/null if possible. | - | ||||||||||||||||||
124 | Note that it is deliberately opened for *writing*, | - | ||||||||||||||||||
125 | to ensure any read evokes an error. */ | - | ||||||||||||||||||
126 | if (ignoring_input)
| 0-2 | ||||||||||||||||||
127 | { | - | ||||||||||||||||||
128 | if (fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0) < 0)
| 0 | ||||||||||||||||||
129 | error (exit_internal_failure, errno, never executed: error (exit_internal_failure, (*__errno_location ()) , dcgettext (((void *)0), "failed to render standard input unusable" , 5) ); | 0 | ||||||||||||||||||
130 | _("failed to render standard input unusable")); never executed: error (exit_internal_failure, (*__errno_location ()) , dcgettext (((void *)0), "failed to render standard input unusable" , 5) ); | 0 | ||||||||||||||||||
131 | if (!redirecting_stdout && !redirecting_stderr)
| 0 | ||||||||||||||||||
132 | error (0, 0, _("ignoring input")); never executed: error (0, 0, dcgettext (((void *)0), "ignoring input" , 5) ); | 0 | ||||||||||||||||||
133 | } never executed: end of block | 0 | ||||||||||||||||||
134 | - | |||||||||||||||||||
135 | /* If standard output is a tty, redirect it (appending) to a file. | - | ||||||||||||||||||
136 | First try nohup.out, then $HOME/nohup.out. If standard error is | - | ||||||||||||||||||
137 | a tty and standard output is closed, open nohup.out or | - | ||||||||||||||||||
138 | $HOME/nohup.out without redirecting anything. */ | - | ||||||||||||||||||
139 | if (redirecting_stdout || (redirecting_stderr && stdout_is_closed))
| 0-2 | ||||||||||||||||||
140 | { | - | ||||||||||||||||||
141 | char *in_home = NULL; | - | ||||||||||||||||||
142 | char const *file = "nohup.out"; | - | ||||||||||||||||||
143 | int flags = O_CREAT | O_WRONLY | O_APPEND; | - | ||||||||||||||||||
144 | mode_t mode = S_IRUSR | S_IWUSR; | - | ||||||||||||||||||
145 | mode_t umask_value = umask (~mode); | - | ||||||||||||||||||
146 | out_fd = (redirecting_stdout
| 0 | ||||||||||||||||||
147 | ? fd_reopen (STDOUT_FILENO, file, flags, mode) | - | ||||||||||||||||||
148 | : open (file, flags, mode)); | - | ||||||||||||||||||
149 | - | |||||||||||||||||||
150 | if (out_fd < 0)
| 0 | ||||||||||||||||||
151 | { | - | ||||||||||||||||||
152 | int saved_errno = errno; | - | ||||||||||||||||||
153 | char const *home = getenv ("HOME"); | - | ||||||||||||||||||
154 | if (home)
| 0 | ||||||||||||||||||
155 | { | - | ||||||||||||||||||
156 | in_home = file_name_concat (home, file, NULL); | - | ||||||||||||||||||
157 | out_fd = (redirecting_stdout
| 0 | ||||||||||||||||||
158 | ? fd_reopen (STDOUT_FILENO, in_home, flags, mode) | - | ||||||||||||||||||
159 | : open (in_home, flags, mode)); | - | ||||||||||||||||||
160 | } never executed: end of block | 0 | ||||||||||||||||||
161 | if (out_fd < 0)
| 0 | ||||||||||||||||||
162 | { | - | ||||||||||||||||||
163 | int saved_errno2 = errno; | - | ||||||||||||||||||
164 | error (0, saved_errno, _("failed to open %s"), quoteaf (file)); | - | ||||||||||||||||||
165 | if (in_home)
| 0 | ||||||||||||||||||
166 | error (0, saved_errno2, _("failed to open %s"), never executed: error (0, saved_errno2, dcgettext (((void *)0), "failed to open %s" , 5) , quotearg_style (shell_escape_always_quoting_style, in_home)); | 0 | ||||||||||||||||||
167 | quoteaf (in_home)); never executed: error (0, saved_errno2, dcgettext (((void *)0), "failed to open %s" , 5) , quotearg_style (shell_escape_always_quoting_style, in_home)); | 0 | ||||||||||||||||||
168 | return exit_internal_failure; never executed: return exit_internal_failure; | 0 | ||||||||||||||||||
169 | } | - | ||||||||||||||||||
170 | file = in_home; | - | ||||||||||||||||||
171 | } never executed: end of block | 0 | ||||||||||||||||||
172 | - | |||||||||||||||||||
173 | umask (umask_value); | - | ||||||||||||||||||
174 | error (0, 0, | - | ||||||||||||||||||
175 | _(ignoring_input | - | ||||||||||||||||||
176 | ? N_("ignoring input and appending output to %s") | - | ||||||||||||||||||
177 | : N_("appending output to %s")), | - | ||||||||||||||||||
178 | quoteaf (file)); | - | ||||||||||||||||||
179 | free (in_home); | - | ||||||||||||||||||
180 | } never executed: end of block | 0 | ||||||||||||||||||
181 | - | |||||||||||||||||||
182 | /* If standard error is a tty, redirect it. */ | - | ||||||||||||||||||
183 | if (redirecting_stderr)
| 0-2 | ||||||||||||||||||
184 | { | - | ||||||||||||||||||
185 | /* Save a copy of stderr before redirecting, so we can use the original | - | ||||||||||||||||||
186 | if execve fails. It's no big deal if this dup fails. It might | - | ||||||||||||||||||
187 | not change anything, and at worst, it'll lead to suppression of | - | ||||||||||||||||||
188 | the post-failed-execve diagnostic. */ | - | ||||||||||||||||||
189 | saved_stderr_fd = fcntl (STDERR_FILENO, F_DUPFD_CLOEXEC, | - | ||||||||||||||||||
190 | STDERR_FILENO + 1); | - | ||||||||||||||||||
191 | - | |||||||||||||||||||
192 | if (!redirecting_stdout)
| 0 | ||||||||||||||||||
193 | error (0, 0, never executed: error (0, 0, dcgettext (((void *)0), ignoring_input ? "ignoring input and redirecting stderr to stdout" : "redirecting stderr to stdout" , 5) ); | 0 | ||||||||||||||||||
194 | _(ignoring_input never executed: error (0, 0, dcgettext (((void *)0), ignoring_input ? "ignoring input and redirecting stderr to stdout" : "redirecting stderr to stdout" , 5) ); | 0 | ||||||||||||||||||
195 | ? N_("ignoring input and redirecting stderr to stdout") never executed: error (0, 0, dcgettext (((void *)0), ignoring_input ? "ignoring input and redirecting stderr to stdout" : "redirecting stderr to stdout" , 5) ); | 0 | ||||||||||||||||||
196 | : N_("redirecting stderr to stdout"))); never executed: error (0, 0, dcgettext (((void *)0), ignoring_input ? "ignoring input and redirecting stderr to stdout" : "redirecting stderr to stdout" , 5) ); | 0 | ||||||||||||||||||
197 | - | |||||||||||||||||||
198 | if (dup2 (out_fd, STDERR_FILENO) < 0)
| 0 | ||||||||||||||||||
199 | error (exit_internal_failure, errno, never executed: error (exit_internal_failure, (*__errno_location ()) , dcgettext (((void *)0), "failed to redirect standard error" , 5) ); | 0 | ||||||||||||||||||
200 | _("failed to redirect standard error")); never executed: error (exit_internal_failure, (*__errno_location ()) , dcgettext (((void *)0), "failed to redirect standard error" , 5) ); | 0 | ||||||||||||||||||
201 | - | |||||||||||||||||||
202 | if (stdout_is_closed)
| 0 | ||||||||||||||||||
203 | close (out_fd); never executed: close (out_fd); | 0 | ||||||||||||||||||
204 | } never executed: end of block | 0 | ||||||||||||||||||
205 | - | |||||||||||||||||||
206 | /* error() flushes stderr, but does not check for write failure. | - | ||||||||||||||||||
207 | Normally, we would catch this via our atexit() hook of | - | ||||||||||||||||||
208 | close_stdout, but execvp() gets in the way. If stderr | - | ||||||||||||||||||
209 | encountered a write failure, there is no need to try calling | - | ||||||||||||||||||
210 | error() again, particularly since we may have just changed the | - | ||||||||||||||||||
211 | underlying fd out from under stderr. */ | - | ||||||||||||||||||
212 | if (ferror (stderr))
| 0-2 | ||||||||||||||||||
213 | return exit_internal_failure; never executed: return exit_internal_failure; | 0 | ||||||||||||||||||
214 | - | |||||||||||||||||||
215 | signal (SIGHUP, SIG_IGN); | - | ||||||||||||||||||
216 | - | |||||||||||||||||||
217 | char **cmd = argv + optind; | - | ||||||||||||||||||
218 | execvp (*cmd, cmd); | - | ||||||||||||||||||
219 | int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
| 1 | ||||||||||||||||||
220 | int saved_errno = errno; | - | ||||||||||||||||||
221 | - | |||||||||||||||||||
222 | /* The execve failed. Output a diagnostic to stderr only if: | - | ||||||||||||||||||
223 | - stderr was initially redirected to a non-tty, or | - | ||||||||||||||||||
224 | - stderr was initially directed to a tty, and we | - | ||||||||||||||||||
225 | can dup2 it to point back to that same tty. | - | ||||||||||||||||||
226 | In other words, output the diagnostic if possible, but only if | - | ||||||||||||||||||
227 | it will go to the original stderr. */ | - | ||||||||||||||||||
228 | if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
| 0-2 | ||||||||||||||||||
229 | error (0, saved_errno, _("failed to run command %s"), quoteaf (*cmd)); executed 2 times by 1 test: error (0, saved_errno, dcgettext (((void *)0), "failed to run command %s" , 5) , quotearg_style (shell_escape_always_quoting_style, *cmd)); Executed by:
| 2 | ||||||||||||||||||
230 | - | |||||||||||||||||||
231 | return exit_status; executed 2 times by 1 test: return exit_status; Executed by:
| 2 | ||||||||||||||||||
232 | } | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |