| 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 blockExecuted 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 blockExecuted 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 |