(root)/
findutils-4.9.0/
find/
exec.c
       1  /* exec.c -- Implementation of -exec, -execdir, -ok, -okdir.
       2     Copyright (C) 1990-2022 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  
      18  /* config.h must be included first. */
      19  #include <config.h>
      20  
      21  /* system headers. */
      22  #include <assert.h>
      23  #include <errno.h>
      24  #include <fcntl.h>
      25  #include <signal.h>
      26  #include <sys/wait.h>
      27  
      28  
      29  /* gnulib headers */
      30  #include "cloexec.h"
      31  #include "dirname.h"
      32  #include "error.h"
      33  #include "fcntl--.h"
      34  #include "save-cwd.h"
      35  #include "xalloc.h"
      36  
      37  /* findutils headers */
      38  #include "buildcmd.h"
      39  #include "defs.h"
      40  #include "die.h"
      41  #include "fdleak.h"
      42  #include "system.h"
      43  
      44  
      45  /* Initialize exec->wd_for_exec.
      46  
      47     We save in exec->wd_for_exec the directory whose path relative to
      48     cwd_df is dir.
      49   */
      50  static bool
      51  initialize_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
      52  {
      53    execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
      54    execp->wd_for_exec->name = NULL;
      55    execp->wd_for_exec->desc = openat (cwd_fd, dir, O_RDONLY);
      56    if (execp->wd_for_exec->desc < 0)
      57      return false;
      58    set_cloexec_flag (execp->wd_for_exec->desc, true);
      59    return true;
      60  }
      61  
      62  
      63  static bool
      64  record_exec_dir (struct exec_val *execp)
      65  {
      66    if (!execp->state.todo)
      67      {
      68        /* working directory not already known, so must be a *dir variant,
      69  	 and this must be the first arg we added.   However, this may
      70  	 be -execdir foo {} \; (i.e. not multiple).  */
      71        assert (!execp->state.todo);
      72  
      73        /* Record the WD. If we're using -L or fts chooses to do so for
      74  	 any other reason, state.cwd_dir_fd may in fact not be the
      75  	 directory containing the target file.  When this happens,
      76  	 rel_path will contain directory components (since it is the
      77  	 path from state.cwd_dir_fd to the target file).
      78  
      79  	 We deal with this by extracting any directory part and using
      80  	 that to adjust what goes into execp->wd_for_exec.
      81        */
      82        if (strchr (state.rel_pathname, '/'))
      83  	{
      84  	  char *dir = mdir_name (state.rel_pathname);
      85  	  bool result = initialize_wd_for_exec (execp, state.cwd_dir_fd, dir);
      86  	  free (dir);
      87  	  return result;
      88  	}
      89        else
      90  	{
      91  	  return initialize_wd_for_exec (execp, state.cwd_dir_fd, ".");
      92  	}
      93      }
      94    return true;
      95  }
      96  
      97  
      98  
      99  
     100  bool
     101  impl_pred_exec (const char *pathname,
     102                  struct stat *stat_buf,
     103                  struct predicate *pred_ptr)
     104  {
     105    struct exec_val *execp = &pred_ptr->args.exec_vec;
     106    char *buf = NULL;
     107    const char *target;
     108    bool result;
     109    const bool local = is_exec_in_local_dir (pred_ptr->pred_func);
     110    const char *prefix;
     111    size_t pfxlen;
     112  
     113    (void) stat_buf;
     114    if (local)
     115      {
     116        /* For -execdir/-okdir predicates, the parser did not fill in
     117           the wd_for_exec member of struct exec_val.  So for those
     118           predicates, we do so now.
     119        */
     120        if (!record_exec_dir (execp))
     121          {
     122            die (EXIT_FAILURE, errno,
     123                 _("Failed to save working directory in order to "
     124                   "run a command on %s"),
     125                   safely_quote_err_filename (0, pathname));
     126            /*NOTREACHED*/
     127          }
     128        target = buf = base_name (state.rel_pathname);
     129        if ('/' == target[0])
     130          {
     131            /* find / execdir ls -d {} \; */
     132            prefix = NULL;
     133            pfxlen = 0;
     134          }
     135        else
     136          {
     137            prefix = "./";
     138            pfxlen = 2u;
     139          }
     140      }
     141    else
     142      {
     143        /* For the others (-exec, -ok), the parser should
     144           have set wd_for_exec to initial_wd, indicating
     145           that the exec should take place from find's initial
     146           working directory.
     147        */
     148        assert (execp->wd_for_exec == initial_wd);
     149        target = pathname;
     150        prefix = NULL;
     151        pfxlen = 0u;
     152      }
     153  
     154    if (execp->multiple)
     155      {
     156        /* Push the argument onto the current list.
     157         * The command may or may not be run at this point,
     158         * depending on the command line length limits.
     159         */
     160        bc_push_arg (&execp->ctl,
     161                     &execp->state,
     162                     target, strlen (target)+1,
     163                     prefix, pfxlen,
     164                     0);
     165  
     166        /* remember that there are pending execdirs. */
     167        if (execp->state.todo)
     168          state.execdirs_outstanding = true;
     169  
     170        /* POSIX: If the primary expression is punctuated by a plus
     171         * sign, the primary shall always evaluate as true
     172         */
     173        result = true;
     174      }
     175    else
     176      {
     177        int i;
     178  
     179        for (i=0; i<execp->num_args; ++i)
     180          {
     181            bc_do_insert (&execp->ctl,
     182                          &execp->state,
     183                          execp->replace_vec[i],
     184                          strlen (execp->replace_vec[i]),
     185                          prefix, pfxlen,
     186                          target, strlen (target),
     187                          0);
     188          }
     189  
     190        /* Actually invoke the command. */
     191        bc_do_exec (&execp->ctl, &execp->state);
     192        if (WIFEXITED(execp->last_child_status))
     193          {
     194            if (0 == WEXITSTATUS(execp->last_child_status))
     195              result = true;        /* The child succeeded. */
     196            else
     197              result = false;
     198          }
     199        else
     200          {
     201            result = false;
     202          }
     203        if (local)
     204          free_cwd (execp->wd_for_exec);
     205      }
     206    if (buf)
     207      {
     208        assert (local);
     209        free (buf);
     210      }
     211    return result;
     212  }
     213  
     214  
     215  
     216  /*  1) fork to get a child; parent remembers the child pid
     217      2) child execs the command requested
     218      3) parent waits for child; checks for proper pid of child
     219  
     220      Possible returns:
     221  
     222      ret		errno	status(h)   status(l)
     223  
     224      pid		x	signal#	    0177	stopped
     225      pid		x	exit arg    0		term by _exit
     226      pid		x	0	    signal #	term by signal
     227      -1		EINTR				parent got signal
     228      -1		other				some other kind of error
     229  
     230      Return true only if the pid matches, status(l) is
     231      zero, and the exit arg (status high) is 0.
     232      Otherwise return false, possibly printing an error message. */
     233  static bool
     234  prep_child_for_exec (bool close_stdin, const struct saved_cwd *wd)
     235  {
     236    bool ok = true;
     237    if (close_stdin)
     238      {
     239        const char inputfile[] = "/dev/null";
     240  
     241        if (close (0) < 0)
     242  	{
     243  	  error (0, errno, _("Cannot close standard input"));
     244  	  ok = false;
     245  	}
     246        else
     247  	{
     248  	  if (open (inputfile, O_RDONLY
     249  #if defined O_LARGEFILE
     250  		   |O_LARGEFILE
     251  #endif
     252  		   ) < 0)
     253  	    {
     254  	      /* This is not entirely fatal, since
     255  	       * executing the child with a closed
     256  	       * stdin is almost as good as executing it
     257  	       * with its stdin attached to /dev/null.
     258  	       */
     259  	      error (0, errno, "%s", safely_quote_err_filename (0, inputfile));
     260  	      /* do not set ok=false, it is OK to continue anyway. */
     261  	    }
     262  	}
     263      }
     264  
     265    /* Even if DebugSearch is set, don't announce our change of
     266     * directory, since we're not going to emit a subsequent
     267     * announcement of a call to stat() anyway, as we're about to exec
     268     * something.
     269     */
     270    if (0 != restore_cwd (wd))
     271      {
     272        error (0, errno, _("Failed to change directory%s%s"),
     273  	     (wd->desc < 0 && wd->name) ? ": " : "",
     274  	     (wd->desc < 0 && wd->name) ? wd->name : "");
     275        ok = false;
     276      }
     277    return ok;
     278  }
     279  
     280  
     281  int
     282  launch (struct buildcmd_control *ctl, void *usercontext, int argc, char **argv)
     283  {
     284    pid_t child_pid;
     285    static int first_time = 1;
     286    struct exec_val *execp = usercontext;
     287  
     288    (void) ctl;			/* silence compiler warning */
     289    (void) argc;			/* silence compiler warning */
     290  
     291    if (options.debug_options & DebugExec)
     292      {
     293        int i;
     294        fprintf (stderr, "DebugExec: launching process (argc=%" PRIuMAX "):",
     295                 (uintmax_t) execp->state.cmd_argc - 1);
     296        for (i=0; i<execp->state.cmd_argc -1; ++i)
     297  	{
     298  	  fprintf (stderr, " %s",
     299  	           safely_quote_err_filename (0, execp->state.cmd_argv[i]));
     300  	}
     301        fprintf (stderr, "\n");
     302      }
     303  
     304    /* Make sure output of command doesn't get mixed with find output. */
     305    fflush (stdout);
     306    fflush (stderr);
     307  
     308    /* Make sure to listen for the kids.  */
     309    if (first_time)
     310      {
     311        first_time = 0;
     312        signal (SIGCHLD, SIG_DFL);
     313      }
     314  
     315    child_pid = fork ();
     316    if (child_pid == -1)
     317      die (EXIT_FAILURE, errno, _("cannot fork"));
     318    if (child_pid == 0)
     319      {
     320        /* We are the child. */
     321        assert (NULL != execp->wd_for_exec);
     322        if (!prep_child_for_exec (execp->close_stdin, execp->wd_for_exec))
     323  	{
     324  	  _exit (1);
     325  	}
     326        else
     327  	{
     328  	  if (fd_leak_check_is_enabled ())
     329  	    {
     330  	      complain_about_leaky_fds ();
     331  	    }
     332  	}
     333  
     334        if (bc_args_exceed_testing_limit (argv))
     335  	errno = E2BIG;
     336        else
     337  	execvp (argv[0], argv);
     338        /* TODO: use a pipe to pass back the errno value, like xargs does */
     339        error (0, errno, "%s",
     340  	     safely_quote_err_filename (0, argv[0]));
     341        _exit (1);
     342      }
     343  
     344    while (waitpid (child_pid, &(execp->last_child_status), 0) == (pid_t) -1)
     345      {
     346        if (errno != EINTR)
     347  	{
     348  	  error (0, errno, _("error waiting for %s"),
     349  		 safely_quote_err_filename (0, argv[0]));
     350  	  state.exit_status = EXIT_FAILURE;
     351  	  return 0;		/* FAIL */
     352  	}
     353      }
     354  
     355    if (WIFSIGNALED (execp->last_child_status))
     356      {
     357        error (0, 0, _("%s terminated by signal %d"),
     358  	     quotearg_n_style (0, options.err_quoting_style, argv[0]),
     359  	     WTERMSIG (execp->last_child_status));
     360  
     361        if (execp->multiple)
     362  	{
     363  	  /* -exec   \; just returns false if the invoked command fails.
     364  	   * -exec {} + returns true if the invoked command fails, but
     365  	   *            sets the program exit status.
     366  	   */
     367  	  state.exit_status = EXIT_FAILURE;
     368  	}
     369  
     370        return 1;			/* OK */
     371      }
     372  
     373    int ex = WEXITSTATUS (execp->last_child_status);
     374    if (options.debug_options & DebugExec)
     375      {
     376        /* pid_t is of type long on Solaris 11.  Cast CHILD_PID for use with
     377         * %ld as long as gnulib doesn't provide portable PRIdPID. */
     378        fprintf (stderr,
     379                 "DebugExec: process (PID=%ld) terminated with exit status: %d\n",
     380                 (long) child_pid, ex);
     381      }
     382  
     383    if (0 == ex)
     384      {
     385        return 1;			/* OK */
     386      }
     387    else
     388      {
     389        if (execp->multiple)
     390  	{
     391  	  /* -exec   \; just returns false if the invoked command fails.
     392  	   * -exec {} + returns true if the invoked command fails, but
     393  	   *            sets the program exit status.
     394  	   */
     395  	  state.exit_status = EXIT_FAILURE;
     396  	}
     397        /* The child failed, but this is the exec callback.  We
     398         * don't want to run the child again in this case anwyay.
     399         */
     400        return 1;			/* FAIL (but don't try again) */
     401      }
     402  
     403  }