(root)/
glibc-2.38/
nptl/
tst-exec5.c
       1  /* Check if posix_spawn does not act as a cancellation entrypoint.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <paths.h>
      21  #include <pthread.h>
      22  #include <signal.h>
      23  #include <spawn.h>
      24  #include <stdbool.h>
      25  #include <stdio.h>
      26  #include <stdlib.h>
      27  #include <unistd.h>
      28  #include <sys/wait.h>
      29  
      30  static int do_test (void);
      31  #define TEST_FUNCTION do_test ()
      32  #include <test-skeleton.c>
      33  
      34  static pthread_barrier_t b;
      35  
      36  static pid_t pid;
      37  static int pipefd[2];
      38  
      39  static void *
      40  tf (void *arg)
      41  {
      42    xpthread_barrier_wait (&b);
      43  
      44    posix_spawn_file_actions_t a;
      45    if (posix_spawn_file_actions_init (&a) != 0)
      46      {
      47        puts ("error: spawn_file_actions_init failed");
      48        exit (1);
      49      }
      50  
      51    if (posix_spawn_file_actions_adddup2 (&a, pipefd[1], STDOUT_FILENO) != 0)
      52      {
      53        puts ("error: spawn_file_actions_adddup2 failed");
      54        exit (1);
      55      }
      56  
      57    if (posix_spawn_file_actions_addclose (&a, pipefd[0]) != 0)
      58      {
      59        puts ("error: spawn_file_actions_addclose");
      60        exit (1);
      61      }
      62  
      63    char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$",
      64  		   NULL };
      65    if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0)
      66      {
      67        puts ("error: spawn failed");
      68        exit (1);
      69      }
      70  
      71    return NULL;
      72  }
      73  
      74  
      75  static int
      76  do_test (void)
      77  {
      78    /* The test basically pipe a 'echo $$' created by a thread with a
      79       cancellation pending.  It then checks if the thread is not cancelled,
      80       the process is created and if the output is the expected one.  */
      81  
      82    if (pipe (pipefd) != 0)
      83      {
      84        puts ("error: pipe failed");
      85        exit (1);
      86      }
      87  
      88    /* Not interested in knowing when the pipe is closed.  */
      89    xsignal (SIGPIPE, SIG_IGN);
      90  
      91    /* To synchronize with the thread.  */
      92    if (pthread_barrier_init (&b, NULL, 2) != 0)
      93      {
      94        puts ("error: pthread_barrier_init failed");
      95        exit (1);
      96      }
      97  
      98    pthread_t th = xpthread_create (NULL, &tf, NULL);
      99  
     100    if (pthread_cancel (th) != 0)
     101      {
     102        puts ("error: pthread_cancel failed");
     103        return 1;
     104      }
     105  
     106    xpthread_barrier_wait (&b);
     107  
     108    if (xpthread_join (th) == PTHREAD_CANCELED)
     109      {
     110        puts ("error: thread cancelled");
     111        exit (1);
     112      }
     113  
     114    close (pipefd[1]);
     115  
     116    /* The global 'pid' should be set by thread posix_spawn calling.  Check
     117       below if it was executed correctly and with expected output.  */
     118  
     119    char buf[64];
     120    ssize_t n;
     121    bool seen_pid = false;
     122    while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0)
     123      {
     124        /* We only expect to read the PID.  */
     125        char *endp;
     126        long int rpid = strtol (buf, &endp, 10);
     127  
     128        if (*endp != '\n')
     129  	{
     130  	  printf ("error: didn't parse whole line: \"%s\"\n", buf);
     131  	  exit (1);
     132  	}
     133        if (endp == buf)
     134  	{
     135  	  puts ("error: read empty line");
     136  	  exit (1);
     137  	}
     138  
     139        if (rpid != pid)
     140  	{
     141  	  printf ("error: found \"%s\", expected PID %ld\n", buf,
     142  		 (long int) pid);
     143  	  exit (1);
     144  	}
     145  
     146        if (seen_pid)
     147  	{
     148  	  puts ("error: found more than one PID line");
     149  	  exit (1);
     150  	}
     151  
     152        seen_pid = true;
     153      }
     154  
     155    close (pipefd[0]);
     156  
     157    int status;
     158    int err = waitpid (pid, &status, 0);
     159    if (err != pid)
     160      {
     161        puts ("errnor: waitpid failed");
     162        exit (1);
     163      }
     164  
     165    if (!seen_pid)
     166      {
     167        puts ("error: didn't get PID");
     168        exit (1);
     169      }
     170  
     171    return 0;
     172  }