1 /* Simple exec test, only a thread in the parent.
2    Copyright (C) 2002-2022 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 #include <support/xsignal.h>
30 
31 
32 static void *
tf(void * arg)33 tf (void *arg)
34 {
35   pthread_t th = (pthread_t) arg;
36 
37   if (pthread_join (th, NULL) == 0)
38     {
39       puts ("thread in parent joined!?");
40       exit (1);
41     }
42 
43   puts ("join in thread in parent returned!?");
44   exit (1);
45 }
46 
47 
48 static int
do_test(void)49 do_test (void)
50 {
51   int fd[2];
52   if (pipe (fd) != 0)
53     {
54       puts ("pipe failed");
55       exit (1);
56     }
57 
58   /* Not interested in knowing when the pipe is closed.  */
59   xsignal (SIGPIPE, SIG_IGN);
60 
61   posix_spawn_file_actions_t a;
62   if (posix_spawn_file_actions_init (&a) != 0)
63     {
64       puts ("spawn_file_actions_init failed");
65       exit (1);
66     }
67 
68   if (posix_spawn_file_actions_adddup2 (&a, fd[1], STDOUT_FILENO) != 0)
69     {
70       puts ("spawn_file_actions_adddup2 failed");
71       exit (1);
72     }
73 
74   if (posix_spawn_file_actions_addclose (&a, fd[0]) != 0)
75     {
76       puts ("spawn_file_actions_addclose");
77       exit (1);
78     }
79 
80   pthread_t th;
81   if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
82     {
83       puts ("create failed");
84       exit (1);
85     }
86 
87   pid_t pid;
88   char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$",
89 		   NULL };
90   if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0)
91     {
92       puts ("spawn failed");
93       exit (1);
94     }
95 
96   close (fd[1]);
97 
98   char buf[200];
99   ssize_t n;
100   bool seen_pid = false;
101   while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
102     {
103       /* We only expect to read the PID.  */
104       char *endp;
105       long int rpid = strtol (buf, &endp, 10);
106 
107       if (*endp != '\n')
108 	{
109 	  printf ("didn't parse whole line: \"%s\"\n", buf);
110 	  exit (1);
111 	}
112       if (endp == buf)
113 	{
114 	  puts ("read empty line");
115 	  exit (1);
116 	}
117 
118       if (rpid != pid)
119 	{
120 	  printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
121 	  exit (1);
122 	}
123 
124       if (seen_pid)
125 	{
126 	  puts ("found more than one PID line");
127 	  exit (1);
128 	}
129 
130       seen_pid = true;
131     }
132 
133   close (fd[0]);
134 
135   int status;
136   int err = waitpid (pid, &status, 0);
137   if (err != pid)
138     {
139       puts ("waitpid failed");
140       exit (1);
141     }
142 
143   if (!seen_pid)
144     {
145       puts ("didn't get PID");
146       exit (1);
147     }
148 
149   puts ("read correct PID");
150 
151   return 0;
152 }
153 
154 #define TEST_FUNCTION do_test ()
155 #include "../test-skeleton.c"
156