1 /* Test for vfork functions.
2    Copyright (C) 2004-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 <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 
30 int raise_fail;
31 
32 static void
alrm(int sig)33 alrm (int sig)
34 {
35   if (raise (SIGUSR1) < 0)
36     raise_fail = 1;
37 }
38 
39 /* This test relies on non-POSIX functionality since the child
40    processes call write, nanosleep and getpid.  */
41 static int
do_test(void)42 do_test (void)
43 {
44   int result = 0;
45   int fd[2];
46 
47   signal (SIGUSR1, SIG_IGN);
48 
49   struct sigaction sa;
50   sa.sa_handler = alrm;
51   sigemptyset (&sa.sa_mask);
52   sa.sa_flags = 0;
53   if (sigaction (SIGALRM, &sa, NULL) < 0)
54     {
55       puts ("couldn't set up SIGALRM handler");
56       return 1;
57     }
58 
59   if (pipe (fd) == -1)
60     {
61       puts ("pipe failed");
62       return 1;
63     }
64 
65   struct itimerval it;
66   it.it_value.tv_sec = 0;
67   it.it_value.tv_usec = 200 * 1000;
68   it.it_interval = it.it_value;
69   if (setitimer (ITIMER_REAL, &it, NULL) < 0)
70     {
71       puts ("couldn't set up timer");
72       return 1;
73     }
74 
75   /* First vfork() without previous getpid().  */
76   pid_t p1;
77   if ((p1 = vfork ()) == 0)
78     {
79       pid_t p = getpid ();
80 
81       struct timespec ts;
82       ts.tv_sec = 1;
83       ts.tv_nsec = 0;
84       TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
85       _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
86     }
87   else if (p1 == -1)
88     {
89       puts ("1st vfork failed");
90       result = 1;
91     }
92 
93   memset (&it, 0, sizeof (it));
94   setitimer (ITIMER_REAL, &it, NULL);
95 
96   pid_t p2 = 0;
97   if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
98     {
99       puts ("1st read failed");
100       result = 1;
101     }
102   int r;
103   if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
104     {
105       puts ("1st waitpid failed");
106       result = 1;
107     }
108   else if (r != 0)
109     {
110       puts ("write in 1st child failed");
111       result = 1;
112     }
113 
114   /* Main process' ID.  */
115   pid_t p0 = getpid ();
116 
117   /* vfork() again, but after a getpid() in the main process.  */
118   pid_t p3;
119   if ((p3 = vfork ()) == 0)
120     {
121       pid_t p = getpid ();
122       _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
123     }
124   else if (p1 == -1)
125     {
126       puts ("2nd vfork failed");
127       result = 1;
128     }
129 
130   pid_t p4;
131   if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
132     {
133       puts ("2nd read failed");
134       result = 1;
135     }
136   if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
137     {
138       puts ("2nd waitpid failed");
139       result = 1;
140     }
141   else if (r != 0)
142     {
143       puts ("write in 2nd child failed");
144       result = 1;
145     }
146 
147   /* And getpid in the main process again.  */
148   pid_t p5 = getpid ();
149 
150   /* Analysis of the results.  */
151   if (p0 != p5)
152     {
153       printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
154       result = 1;
155     }
156 
157   if (p0 == p1)
158     {
159       printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
160       result = 1;
161     }
162 
163   if (p1 != p2)
164     {
165       printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
166       result = 1;
167     }
168 
169   if (p0 == p3)
170     {
171       printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
172       result = 1;
173     }
174 
175   if (p3 != p4)
176     {
177       printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
178       result = 1;
179     }
180 
181   close (fd[0]);
182   close (fd[1]);
183 
184   if (raise_fail)
185     {
186       puts ("raise failed");
187       result = 1;
188     }
189 
190   if (result == 0)
191     puts ("All OK");
192 
193   return result;
194 }
195 
196 #define TEST_FUNCTION do_test ()
197 #include "../test-skeleton.c"
198