LCOV - code coverage report
Current view: top level - src - nohup.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 59 76 77.6 %
Date: 2018-01-30 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* nohup -- run a command immune to hangups, with output to a non-tty
       2             :    Copyright (C) 2003, 2004, 2005, 2007 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 <http://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 "cloexec.h"
      28             : #include "error.h"
      29             : #include "filenamecat.h"
      30             : #include "fd-reopen.h"
      31             : #include "long-options.h"
      32             : #include "quote.h"
      33             : #include "unistd--.h"
      34             : 
      35             : #define PROGRAM_NAME "nohup"
      36             : 
      37             : #define AUTHORS "Jim Meyering"
      38             : 
      39             : /* Exit statuses.  */
      40             : enum
      41             :   {
      42             :     /* `nohup' itself failed.  */
      43             :     NOHUP_FAILURE = 127
      44             :   };
      45             : 
      46             : char *program_name;
      47             : 
      48             : void
      49          10 : usage (int status)
      50             : {
      51          10 :   if (status != EXIT_SUCCESS)
      52           8 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      53             :              program_name);
      54             :   else
      55             :     {
      56           2 :       printf (_("\
      57             : Usage: %s COMMAND [ARG]...\n\
      58             :   or:  %s OPTION\n\
      59             : "),
      60             :               program_name, program_name);
      61             : 
      62           2 :       fputs (_("\
      63             : Run COMMAND, ignoring hangup signals.\n\
      64             : \n\
      65             : "), stdout);
      66           2 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
      67           2 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
      68           2 :       printf (_("\n\
      69             : If standard input is a terminal, redirect it from /dev/null.\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           2 :       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
      76           2 :       emit_bug_reporting_address ();
      77             :     }
      78          10 :   exit (status);
      79             : }
      80             : 
      81             : int
      82          19 : main (int argc, char **argv)
      83             : {
      84          19 :   int out_fd = STDOUT_FILENO;
      85          19 :   int saved_stderr_fd = STDERR_FILENO;
      86             :   bool ignoring_input;
      87             :   bool redirecting_stdout;
      88             :   bool stdout_is_closed;
      89             :   bool redirecting_stderr;
      90             : 
      91             :   initialize_main (&argc, &argv);
      92          19 :   program_name = argv[0];
      93          19 :   setlocale (LC_ALL, "");
      94             :   bindtextdomain (PACKAGE, LOCALEDIR);
      95             :   textdomain (PACKAGE);
      96             : 
      97          19 :   initialize_exit_failure (NOHUP_FAILURE);
      98          19 :   atexit (close_stdout);
      99             : 
     100          19 :   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
     101             :                       usage, AUTHORS, (char const *) NULL);
     102          16 :   if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
     103           6 :     usage (NOHUP_FAILURE);
     104             : 
     105          10 :   if (argc <= optind)
     106             :     {
     107           2 :       error (0, 0, _("missing operand"));
     108           2 :       usage (NOHUP_FAILURE);
     109             :     }
     110             : 
     111           8 :   ignoring_input = isatty (STDIN_FILENO);
     112           8 :   redirecting_stdout = isatty (STDOUT_FILENO);
     113           8 :   stdout_is_closed = (!redirecting_stdout && errno == EBADF);
     114           8 :   redirecting_stderr = isatty (STDERR_FILENO);
     115             : 
     116             :   /* If standard input is a tty, replace it with /dev/null if possible.
     117             :      Note that it is deliberately opened for *writing*,
     118             :      to ensure any read evokes an error.  */
     119           8 :   if (ignoring_input)
     120             :     {
     121           6 :       fd_reopen (STDIN_FILENO, "/dev/null", O_WRONLY, 0);
     122           6 :       if (!redirecting_stdout && !redirecting_stderr)
     123           0 :         error (0, 0, _("ignoring input"));
     124             :     }
     125             : 
     126             :   /* If standard output is a tty, redirect it (appending) to a file.
     127             :      First try nohup.out, then $HOME/nohup.out.  If standard error is
     128             :      a tty and standard output is closed, open nohup.out or
     129             :      $HOME/nohup.out without redirecting anything.  */
     130           8 :   if (redirecting_stdout || (redirecting_stderr && stdout_is_closed))
     131             :     {
     132           7 :       char *in_home = NULL;
     133           7 :       char const *file = "nohup.out";
     134           7 :       int flags = O_CREAT | O_WRONLY | O_APPEND;
     135           7 :       mode_t mode = S_IRUSR | S_IWUSR;
     136           7 :       mode_t umask_value = umask (~mode);
     137           7 :       out_fd = (redirecting_stdout
     138             :                 ? fd_reopen (STDOUT_FILENO, file, flags, mode)
     139           7 :                 : open (file, flags, mode));
     140             : 
     141           7 :       if (out_fd < 0)
     142             :         {
     143           0 :           int saved_errno = errno;
     144           0 :           char const *home = getenv ("HOME");
     145           0 :           if (home)
     146             :             {
     147           0 :               in_home = file_name_concat (home, file, NULL);
     148           0 :               out_fd = (redirecting_stdout
     149             :                         ? fd_reopen (STDOUT_FILENO, in_home, flags, mode)
     150           0 :                         : open (in_home, flags, mode));
     151             :             }
     152           0 :           if (out_fd < 0)
     153             :             {
     154           0 :               int saved_errno2 = errno;
     155           0 :               error (0, saved_errno, _("failed to open %s"), quote (file));
     156           0 :               if (in_home)
     157           0 :                 error (0, saved_errno2, _("failed to open %s"),
     158             :                        quote (in_home));
     159           0 :               exit (NOHUP_FAILURE);
     160             :             }
     161           0 :           file = in_home;
     162             :         }
     163             : 
     164           7 :       umask (umask_value);
     165           7 :       error (0, 0,
     166             :              _(ignoring_input
     167             :                ? "ignoring input and appending output to %s"
     168             :                : "appending output to %s"),
     169             :              quote (file));
     170           7 :       free (in_home);
     171             :     }
     172             : 
     173             :   /* If standard error is a tty, redirect it.  */
     174           8 :   if (redirecting_stderr)
     175             :     {
     176             :       /* Save a copy of stderr before redirecting, so we can use the original
     177             :          if execve fails.  It's no big deal if this dup fails.  It might
     178             :          not change anything, and at worst, it'll lead to suppression of
     179             :          the post-failed-execve diagnostic.  */
     180           8 :       saved_stderr_fd = dup (STDERR_FILENO);
     181             : 
     182           8 :       if (0 <= saved_stderr_fd
     183           8 :           && set_cloexec_flag (saved_stderr_fd, true) != 0)
     184           0 :         error (NOHUP_FAILURE, errno,
     185             :                _("failed to set the copy of stderr to close on exec"));
     186             : 
     187           8 :       if (!redirecting_stdout)
     188           1 :         error (0, 0,
     189             :                _(ignoring_input
     190             :                  ? "ignoring input and redirecting stderr to stdout"
     191             :                  : "redirecting stderr to stdout"));
     192             : 
     193           8 :       if (dup2 (out_fd, STDERR_FILENO) < 0)
     194           0 :         error (NOHUP_FAILURE, errno, _("failed to redirect standard error"));
     195             : 
     196           8 :       if (stdout_is_closed)
     197           0 :         close (out_fd);
     198             :     }
     199             : 
     200           8 :   signal (SIGHUP, SIG_IGN);
     201             : 
     202             :   {
     203             :     int exit_status;
     204             :     int saved_errno;
     205           8 :     char **cmd = argv + optind;
     206             : 
     207           8 :     execvp (*cmd, cmd);
     208           8 :     exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
     209           8 :     saved_errno = errno;
     210             : 
     211             :     /* The execve failed.  Output a diagnostic to stderr only if:
     212             :        - stderr was initially redirected to a non-tty, or
     213             :        - stderr was initially directed to a tty, and we
     214             :          can dup2 it to point back to that same tty.
     215             :        In other words, output the diagnostic if possible, but only if
     216             :        it will go to the original stderr.  */
     217           8 :     if (dup2 (saved_stderr_fd, STDERR_FILENO) == STDERR_FILENO)
     218           8 :       error (0, saved_errno, _("cannot run command %s"), quote (*cmd));
     219             : 
     220           8 :     exit (exit_status);
     221             :   }
     222             : }

Generated by: LCOV version 1.10