1/*
2* Copyright (c) 2004, Bull S.A..  All rights reserved.
3* Created by: Sebastien Decugis
4
5* This program is free software; you can redistribute it and/or modify it
6* under the terms of version 2 of the GNU General Public License as
7* published by the Free Software Foundation.
8*
9* This program is distributed in the hope that it would be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program; if not, write the Free Software Foundation, Inc., 59
15* Temple Place - Suite 330, Boston MA 02111-1307, USA.
16
17
18* This sample test aims to check the following assertion:
19*
20* The new process is a copy of the original one -- with few exceptions.
21
22* The steps are:
23* -> set up some data in process memory space
24* -> create a new process
25* -> check in this new process that the memory space was copied.
26*
27* We check that:
28* -> a structure object is copied.
29* -> a malloc'ed memory block is copied and can be freed in child.
30* -> the environment is copied
31* -> signal handlers are copied
32
33
34* The test fails if a difference is detected.
35
36*/
37
38
39/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
40#define _POSIX_C_SOURCE 200112L
41
42/* We can use XSI features in case it is allowed */
43#ifndef WITHOUT_XOPEN
44#define _XOPEN_SOURCE 600
45#endif
46
47/********************************************************************************************/
48/****************************** standard includes *****************************************/
49/********************************************************************************************/
50#include <pthread.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57#include <sys/wait.h>
58 #include <errno.h>
59
60#include <signal.h>
61
62/********************************************************************************************/
63/******************************   Test framework   *****************************************/
64/********************************************************************************************/
65#include "testfrmw.h"
66 #include "testfrmw.c"
67/* This header is responsible for defining the following macros:
68 * UNRESOLVED(ret, descr);
69 *    where descr is a description of the error and ret is an int (error code for example)
70 * FAILED(descr);
71 *    where descr is a short text saying why the test has failed.
72 * PASSED();
73 *    No parameter.
74 *
75 * Both three macros shall terminate the calling process.
76 * The testcase shall not terminate in any other maneer.
77 *
78 * The other file defines the functions
79 * void output_init()
80 * void output(char * string, ...)
81 *
82 * Those may be used to output information.
83 */
84
85/********************************************************************************************/
86/********************************** Configuration ******************************************/
87/********************************************************************************************/
88#ifndef VERBOSE
89#define VERBOSE 1
90#endif
91
92
93/********************************************************************************************/
94/***********************************    Test case   *****************************************/
95/********************************************************************************************/
96
97void handler( int sig )
98{
99	/* this won't be used */
100	output( "Sig %d received\n", sig );
101
102	return ;
103}
104
105
106/* The main test function. */
107int main( int argc, char * argv[] )
108{
109	int ret, status;
110	pid_t child, ctl;
111
112	/* structure for structure test */
113
114	struct _thestruct
115	{
116		char one ;
117		short two;
118		int three;
119		void * four;
120	}
121
122	mystruct = {1, 2, 3, ( void * ) 4};
123
124	/* pointer for malloc'ed memory */
125	void * malloced;
126
127	/* Structure for signal handler test */
128
129	struct sigaction sa_ori, sa_child;
130
131	/* Initialize output */
132	output_init();
133
134	/* Initialize the memory pointer */
135	malloced = ( void * ) malloc( sysconf( _SC_PAGESIZE ) );
136
137	if ( malloced == NULL )
138	{
139		UNRESOLVED( errno, "Unable to alloc memory" );
140	}
141
142	*( double * ) malloced = 2.3;
143
144	/* Initialize an environment variable */
145	ret = setenv( "OPTS_FORK_TC", "2-1.c", 1 );
146
147	if ( ret != 0 )
148	{
149		UNRESOLVED( errno, "Failed to set the environment variable" );
150	}
151
152	/* Initialize the signal handler */
153	sa_ori.sa_handler = handler;
154
155	ret = sigemptyset( &sa_ori.sa_mask );
156
157	if ( ret != 0 )
158	{
159		UNRESOLVED( errno, "sigemptyset failed" );
160	}
161
162	ret = sigaddset( &sa_ori.sa_mask, SIGUSR2 );
163
164	if ( ret != 0 )
165	{
166		UNRESOLVED( errno, "sigaddset failed" );
167	}
168
169	sa_ori.sa_flags = SA_NOCLDSTOP;
170	ret = sigaction( SIGUSR1, &sa_ori, NULL );
171
172	if ( ret != 0 )
173	{
174		UNRESOLVED( errno, "Failed to set the signal handler" );
175	}
176
177	/* Create the child */
178	child = fork();
179
180	if ( child == ( pid_t ) - 1 )
181	{
182		UNRESOLVED( errno, "Failed to fork" );
183	}
184
185	/* child */
186	if ( child == ( pid_t ) 0 )
187	{
188		/* Check the struct was copied */
189
190		if ( ( mystruct.one != 1 ) || ( mystruct.two != 2 ) || ( mystruct.three != 3 ) || ( mystruct.four != ( void * ) 4 ) )
191		{
192			FAILED( "The struct data was not copied to the child process" );
193		}
194
195		/* Check the malloc'ed memory is copied */
196		if ( *( double * ) malloced != 2.3 )
197		{
198			FAILED( "Malloc'd block not copied in child process" );
199		}
200
201		/* Free the memory -- this should suceed */
202		free( malloced );
203
204		/* Check the env variable */
205		if ( strncmp( "2-1.c", getenv( "OPTS_FORK_TC" ), 6 ) != 0 )
206		{
207			FAILED( "The environment is not copied to the child" );
208		}
209
210		/* Check the signal handler stuff */
211		ret = sigaction( SIGUSR1, NULL, &sa_child );
212
213		if ( ret != 0 )
214		{
215			UNRESOLVED( errno, "Failed to read sigaction information in child" );
216		}
217
218		if ( sa_child.sa_handler != handler )
219		{
220			FAILED( "The child signal handler function is different from the parent's" );
221		}
222
223		ret = sigismember( &sa_child.sa_mask, SIGUSR2 );
224
225		if ( ret == 0 )
226		{
227			FAILED( "The child signal handler mask is different from the parent's" );
228		}
229
230		if ( ret != 1 )
231		{
232			UNRESOLVED( errno, "Unexpected return code from sigismember" );
233		}
234
235		if ( ( ( sa_child.sa_flags & SA_NOCLDSTOP ) != SA_NOCLDSTOP )
236#ifndef WITHOUT_XOPEN
237		        || ( ( sa_child.sa_flags & SA_ONSTACK ) != 0 )
238		        || ( ( sa_child.sa_flags & SA_RESETHAND ) != 0 )
239		        || ( ( sa_child.sa_flags & SA_RESTART ) != 0 )
240		        || ( ( sa_child.sa_flags & SA_SIGINFO ) != 0 )
241		        || ( ( sa_child.sa_flags & SA_NOCLDWAIT ) != 0 )
242		        || ( ( sa_child.sa_flags & SA_NODEFER ) != 0 )
243#endif
244		   )
245		{
246			FAILED( "The sigaction flags are different in the child" );
247		}
248
249		/* The child stops here */
250		exit( PTS_PASS );
251	}
252
253	/* Parent joins the child */
254	ctl = waitpid( child, &status, 0 );
255
256	if ( ctl != child )
257	{
258		UNRESOLVED( errno, "Waitpid returned the wrong PID" );
259	}
260
261	if ( !WIFEXITED( status ) )
262	{
263		UNRESOLVED( status, "Child exited abnormally" );
264	}
265
266	if ( WEXITSTATUS( status ) == PTS_PASS )
267	{
268
269		/* Test passed */
270#if VERBOSE > 0
271		output( "Test passed\n" );
272#endif
273
274		PASSED;
275	}
276
277	if ( WEXITSTATUS( status ) == PTS_FAIL )
278	{
279
280		/* Test failed */
281		FAILED( "Test failed in child\n" );
282	}
283
284	/* Otherwise we've an unexpected return code */
285	UNRESOLVED( WEXITSTATUS( status ), "Child returned an unexpected error code" );
286}
287
288
289