1/*
2 * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like.  Any license provided herein, whether implied or
15 * otherwise, applies only to this software file.  Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA  94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 *
32 */
33/* $Id: kill02.c,v 1.10 2009/08/28 13:20:15 vapier Exp $ */
34/***********************************************************************************
35
36    OS Test -  Silicon Graphics, Inc.
37
38    TEST IDENTIFIER :  kill02  Sending a signal to processes with the same process group ID.
39
40    PARENT DOCUMENT :  kiltds01  Kill System Call.
41
42    AUTHOR          :  Dave Baumgartner
43
44    CO-PILOT        :  Barrie Kletscher
45
46    DATE STARTED    :  12/30/85
47
48    TEST ITEMS
49
50	1. Sending a signal to pid of zero sends to all processes whose process
51	   group ID is equal to the process group ID as the sender.
52
53	2. Sending a signal to pid of zero does not send to processes in another process group.
54
55    OUTPUT SPECIFICATIONS
56
57	PASS :
58		kiltcs02 1 PASS The signal was sent to all processes in the process group.
59		kiltcs02 2 PASS The signal was not sent to selective processes that were not in the process group.
60
61	FAIL :
62		kiltcs02 1 FAIL The signal was not sent to all processes in the process group.
63		kiltcs02 2 FAIL The signal was sent to a process that was not in the process group.
64
65	BROK :
66		kiltcs02 # BROK System call XXX failed. Errno:X, Error message:XXX.
67		kiltcs02 # BROK Setting to catch unexpected signal %d failed. Errno: %d, Error message %s.
68		kiltcs02 # BROK Setting to ignore signal %d failed. Errno: %d, Error message %s.
69
70	WARN :
71		kiltcs02 0 WARN Unexpected signal X was caught.
72
73    SPECIAL PROCEDURAL REQUIREMENTS
74
75	The program must be linked with tst_res.o.
76
77    DETAILED DESCRIPTION
78
79	**Setup**
80	Set up unexpected signal handling.
81	Set up one pipe for each process to be created with no blocking for read.
82
83	**MAIN**
84	If setup fails exit.
85	Fork 2 children(1 & 2).
86	Wait for set up complete messages from the 1st and 2nd child.
87	Send the signal SIGUSR1 with pid equal to zero.
88	Sleep a reasonable amount of time so that each child has been swapped in
89	to process the signal.
90	Now decide the outcome of the test items by reading from each pipe to find
91	out if the child was interrupted by the signal and wrote to it.
92	Remove the second child.
93	Tell the first child it is time to remove it's child B because the decisions have been made.
94	Exit.
95
96	**First Child**
97	Set to catch SIGUSR1 with an int_rout1.
98	Set up to handle the message from the parent to remove child B.
99	Fork two children(A & B).
100	Wait for set up complete messages from child A & child B.
101	Send a set up complete message to the parent.
102	Pause until the signal SIGUSR1 comes in from the parent.
103	Pause until the parent says it is time to remove the child.
104	Exit.
105
106	**Second Child**
107	Set to catch SIGUSR1 with an int_rout2.
108	Set the process group to be something different than the parents.
109	Send a set up complete message to the parent.
110	Pause until killed by parent because this child shouldn't receive signal SIGUSR1.
111
112	**Child A**
113	Set to catch SIGUSR1 with an int_routA.
114	Send a set up complete message to the parent(First Child).
115	Pause until the signal SIGUSR1 comes in from the parent.
116	Exit.
117
118	**Child B**
119	Set to catch SIGUSR1 with an int_routB.
120	Set the process group to be something different than the parents(First Child's).
121	Send a set up complete message to the parent.
122	Pause until killed by parent because this child shouldn't receive signal SIGUSR1.
123
124	**usr1_rout-Used by all children**
125	Write to the appropriate pipe that the signal SIGUSR1 was caught.
126
127	**usr2_rout**
128	Remove child B.
129
130******************************************************************************/
131#include <sys/param.h>
132#include <sys/wait.h>
133#include <errno.h>
134#include <fcntl.h>
135#include <signal.h>
136#include <string.h>
137#include <stdlib.h>
138#include "test.h"
139
140#define CHAR_SET_FAILED	"0"	/*Set up failing status transferred through the pipe.   */
141#define CHAR_SET_PASSED	"1"	/*Set up passing status transferred through the pipe.   */
142#define SIG_CAUGHT	"2"	/*Indicates that the signal SIGUSR1 was caught.         */
143#define SIG_RECEIVED	1	/*Integer value that indicates that the signal SIGUSR1  */
144				/*was caught.                                           */
145#define SIG_NOT_RECD	0	/*Integer value that indicates that the signal SIGUSR1  */
146				/*was caught.                                           */
147#define INT_SET_FAILED	0	/*Set up failing status transferred through the pipe.   */
148#define INT_SET_PASSED	1	/*Set up passing status transferred through the pipe.   */
149#define SLEEP_TIME	10	/*Amount of time the children get to catch the signal   */
150#define TRUE	 	40	/*Child exits with this if execution was as     */
151				/*expected.                                             */
152#define FALSE	 	50	/*Child exits with this if it timed out waiting for the         */
153				/*parents signal.                                       */
154#define TIMEOUT		60	/*Amount of time given in alarm calls.                  */
155#define CHILD_EXIT(VAR) ((VAR >> 8) & 0377)	/*Exit value from the child.               */
156#define CHILD_SIG(VAR) (VAR & 0377)	/*Signal value from the termination of child.       */
157				/*from the parent.                                      */
158
159int pid1;			/*Return value from 1st fork. Global so that it can be  */
160				/*used in interrupt handling routines.                  */
161int pid2;			/*Return value from 2nd fork. Global so that it can be  */
162				/*used in interrupt handling routines.                  */
163int pidA;			/*Return value from 1st fork in child 1. Global so that it      */
164				/*can be used in interrupt handling routines.           */
165int pidB;			/*Return value from 2nd fork in child 1. Global so that it      */
166				/*can be used in interrupt handling routines.           */
167int pipe1_fd[2];		/*Pipe file descriptors used for communication          */
168				/*between child 1 and the 1st parent.                   */
169int pipe2_fd[2];		/*Pipe file descriptors used for communication          */
170				/*between child 2 and the 1st parent.                   */
171int pipeA_fd[2];		/*Pipe file descriptors used for communication          */
172				/*between child A and the 1st parent.                   */
173int pipeB_fd[2];		/*Pipe file descriptors used for communication          */
174				/*between child B and the 1st parent.                   */
175char pipe_buf[10];		/*Pipe buffer.                                          */
176char buf_tmp1[2], buf_tmp2[2];	/*Temp hold for info read into pipe_buf.                */
177int read1_stat = 0;		/*Number of characters read from pipe 1.                */
178int read2_stat = 0;		/*Number of characters read from pipe 2.                */
179int readA_stat = 0;		/*Number of characters read from pipe A.                */
180int readB_stat = 0;		/*Number of characters read from pipe B.                */
181int alarm_flag = FALSE;		/*This flag indicates an alarm time out.                        */
182char who_am_i = '0';		/*This indicates which process is which when using      */
183				/*interrupt routine usr1_rout.                          */
184
185void notify_timeout();		/*Signal handler that the parent enters if it times out */
186				/*waiting for the child to indicate its set up status.  */
187void parent_rout();		/*This is the parents routine.                          */
188void child1_rout();		/*This is child 1's routine.                            */
189void child2_rout();		/*This is child 2's routine.                            */
190void childA_rout();		/*This is child A's routine.                            */
191void childB_rout();		/*This is child B's routine.                            */
192void usr1_rout();		/*This routine is used by all children to indicate that */
193				/*they have caught signal SIGUSR1.                      */
194void par_kill();		/*This routine is called by the original parent to      */
195				/*remove child 2 and to indicate to child 1 to          */
196				/*remove its children.                                  */
197void chld1_kill();		/*This routine is used by child 1 to remove itself and  */
198				/*its children A and B.                                 */
199
200void setup();
201void cleanup();
202
203char *TCID = "kill02";
204int TST_TOTAL = 2;
205
206#ifdef UCLINUX
207static char *argv0;
208void childA_rout_uclinux();
209void childB_rout_uclinux();
210#endif
211
212int main(int ac, char **av)
213{
214	int lc;
215
216	tst_parse_opts(ac, av, NULL, NULL);
217
218#ifdef UCLINUX
219	argv0 = av[0];
220
221	maybe_run_child(&childA_rout_uclinux, "nd", 1, &pipeA_fd[1]);
222	maybe_run_child(&childB_rout_uclinux, "nd", 2, &pipeB_fd[1]);
223	maybe_run_child(&child1_rout, "ndddddd", 3, &pipe1_fd[1], &pipe2_fd[1],
224			&pipeA_fd[0], &pipeA_fd[1], &pipeB_fd[0], &pipeB_fd[1]);
225	maybe_run_child(&child2_rout, "nd", 4, &pipe2_fd[1]);
226#endif
227
228	setup();
229
230	for (lc = 0; TEST_LOOPING(lc); lc++) {
231
232		tst_count = 0;
233
234		if ((pid1 = FORK_OR_VFORK()) > 0) {
235			if ((pid2 = FORK_OR_VFORK()) > 0) {
236				(void)parent_rout();
237			} else if (pid2 == 0) {
238#ifdef UCLINUX
239				if (self_exec(argv0, "nd", 4, pipe2_fd[1]) < 0) {
240					if (kill(pid1, SIGKILL) == -1
241					    && errno != ESRCH) {
242						tst_resm(TWARN,
243							 "Child process may not have been killed.");
244					}
245					tst_brkm(TBROK | TERRNO, cleanup,
246						 "fork failed");
247				}
248#else
249				(void)child2_rout();
250#endif
251			} else {
252				/*
253				 *  The second fork failed kill the first child.
254				 */
255				if (kill(pid1, SIGKILL) == -1 && errno != ESRCH) {
256					tst_resm(TWARN,
257						 "Child process may not have been killed.");
258				}
259				tst_brkm(TBROK | TERRNO, cleanup,
260					 "fork failed");
261			}
262
263		} else if (pid1 == 0) {
264			/*
265			 *  This is child 1.
266			 */
267#ifdef UCLINUX
268			if (self_exec
269			    (argv0, "ndddddd", 3, pipe1_fd[1], pipe2_fd[1],
270			     pipeA_fd[0], pipeA_fd[1], pipeB_fd[0],
271			     pipeB_fd[1]) < 0) {
272				tst_brkm(TBROK | TERRNO, cleanup,
273					 "self_exec() failed");
274			}
275#else
276			(void)child1_rout();
277#endif
278		} else {
279			/*
280			 * Fork failed.
281			 */
282			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
283		}
284	}
285
286	cleanup();
287	tst_exit();
288}				/* END OF MAIN. */
289
290/******************************************************************************
291 *  This is the parents routine.  The parent waits for the children 1 and 2 to
292 *  get set up. Then sends the signal and checks the outcome.
293 *********************************************************************************/
294void parent_rout(void)
295{
296	/*
297	 *  Set to catch the alarm signal SIGALRM.
298	 */
299	if (signal(SIGALRM, notify_timeout) == SIG_ERR) {
300		(void)par_kill();
301		tst_brkm(TBROK, NULL,
302			 "Could not set to catch the parents time out alarm.");
303	}
304
305	/*
306	 *  Setting to catch the timeout alarm worked now let the children start up.
307	 *  Set an alarm which causes a time out on the read pipe loop.
308	 *  The children will notify the parent that set up is complete
309	 *  and the pass/fail status of set up.
310	 */
311	(void)alarm(TIMEOUT);
312
313	while ((read(pipe1_fd[0], pipe_buf, 1) != 1) && (alarm_flag == FALSE))
314		/*EMPTY*/;
315	strncpy(buf_tmp1, pipe_buf, 1);
316	(void)alarm(TIMEOUT);
317
318	while ((read(pipe2_fd[0], pipe_buf, 1) != 1) && (alarm_flag == FALSE))
319		/*EMPTY*/;
320	(void)alarm(0);		/*Reset the alarm clock. */
321	strncpy(buf_tmp2, pipe_buf, 1);
322
323	/*
324	 *  Check the alarm flag.
325	 */
326	if (alarm_flag == TRUE) {
327		tst_brkm(TBROK, NULL,
328			 "The set up of the children failed by timing out.");
329		(void)par_kill();
330		cleanup();
331	}
332
333	/*
334	 *  Check to see if either child failed in the set up.
335	 */
336	if ((strncmp(buf_tmp1, CHAR_SET_FAILED, 1) == 0) ||
337	    (strncmp(buf_tmp2, CHAR_SET_FAILED, 1) == 0)) {
338		/*
339		 * Problems were encountered in the set up of one of the children.
340		 * The error message has been displayed by the child.
341		 */
342		(void)par_kill();
343		cleanup();
344	}
345
346	/*
347	 *  Setup passed, now send SIGUSR1 to process id of zero.
348	 */
349	TEST(kill(0, SIGUSR1));
350
351	if (TEST_RETURN == -1) {
352		tst_brkm(TBROK | TERRNO, NULL, "kill() failed");
353		(void)par_kill();
354		cleanup();
355	}
356
357	/*
358	 *  Sleep for a while to allow the children to get a chance to
359	 *  catch the signal.
360	 */
361	(void)sleep(SLEEP_TIME);
362
363	/*
364	 *  The signal was sent above and time has run out for child response,
365	 *  check the outcomes.
366	 */
367	read1_stat = read(pipe1_fd[0], pipe_buf, 1);
368	if (read1_stat == -1 && errno == EAGAIN)
369		read1_stat = 0;
370	read2_stat = read(pipe2_fd[0], pipe_buf, 1);
371	if (read2_stat == -1 && errno == EAGAIN)
372		read2_stat = 0;
373	readA_stat = read(pipeA_fd[0], pipe_buf, 1);
374	if (readA_stat == -1 && errno == EAGAIN)
375		readA_stat = 0;
376	readB_stat = read(pipeB_fd[0], pipe_buf, 1);
377	if (readB_stat == -1 && errno == EAGAIN)
378		readB_stat = 0;
379
380	if (read1_stat == -1 || read2_stat == -1 ||
381	    readA_stat == -1 || readB_stat == -1) {
382		/*
383		 * The read system call failed.
384		 */
385		tst_brkm(TBROK | TERRNO, NULL, "read() failed");
386		(void)par_kill();
387		cleanup();
388	}
389
390	/*
391	 * Check the processes that were supposed to get the signal.
392	 */
393	if (read1_stat == SIG_RECEIVED) {
394		if (readA_stat == SIG_RECEIVED) {
395			/*
396			 *  Both processes, 1 and A, that were supposed to receive
397			 *  the signal did receive the signal.
398			 */
399			tst_resm(TPASS,
400				 "The signal was sent to all processes in the process group.");
401		} else {	/*Process A didn't receive the signal. */
402			tst_resm(TFAIL,
403				 "Process A did not receive the signal.");
404		}
405
406	} else {		/*Process 1 didn't receive the signal. */
407		tst_resm(TFAIL, "Process 1 did not receive the signal.");
408	}
409
410	/*
411	 * Check the processes that were not supposed to get the signal.
412	 */
413	if (read2_stat == SIG_NOT_RECD) {
414		if (readB_stat == SIG_NOT_RECD) {
415			/*
416			 *  Both processes, 2 and B did not receive the signal.
417			 */
418			tst_resm(TPASS,
419				 "The signal was not sent to selective processes that were not in the process group.");
420		} else {	/*Process B received the signal. */
421			tst_resm(TFAIL, "Process B received the signal.");
422		}
423
424	}
425
426	else {			/*Process 2 received the signal. */
427
428		tst_resm(TFAIL, "Process 2 received the signal.");
429	}
430
431	(void)par_kill();
432
433	(void)alarm(TIMEOUT);
434	while ((read(pipe1_fd[0], pipe_buf, 1) != 1) && (alarm_flag == FALSE))
435		strncpy(buf_tmp1, pipe_buf, 1);
436
437}				/*End of parent_rout */
438
439void child1_rout(void)
440{
441	who_am_i = '1';
442
443	/*
444	 *  Set to catch the SIGUSR1 with int1_rout.
445	 */
446	if (signal(SIGUSR1, usr1_rout) == SIG_ERR) {
447		tst_brkm(TBROK, NULL,
448			 "Could not set to catch the childrens signal.");
449		(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
450		exit(0);
451	}
452	/*
453	 *  Create children A & B.
454	 */
455	if ((pidA = FORK_OR_VFORK()) > 0) {
456		/*
457		 *  This is the parent(child1), fork again to create child B.
458		 */
459		if ((pidB = FORK_OR_VFORK()) == 0) {
460			/* This is child B. */
461#ifdef UCLINUX
462			if (self_exec(argv0, "nd", 2, pipeB_fd[1]) < 0) {
463				tst_brkm(TBROK | TERRNO, NULL,
464					 "self_exec() failed");
465				(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
466				exit(0);
467			}
468#else
469			(void)childB_rout();
470#endif
471		}
472
473		else if (pidB == -1) {
474			/*
475			 *  The fork of child B failed kill child A.
476			 */
477			if (kill(pidA, SIGKILL) == -1)
478				tst_resm(TWARN,
479					 "Child process may not have been killed.");
480			tst_brkm(TBROK | TERRNO, NULL, "fork failed");
481			(void)write(pipe2_fd[1], CHAR_SET_FAILED, 1);
482			exit(0);
483		}
484	}
485
486	else if (pidA == 0) {
487		/* This is child A. */
488#ifdef UCLINUX
489		if (self_exec(argv0, "nd", 1, pipeA_fd[1]) < 0) {
490			tst_brkm(TBROK | TERRNO, NULL, "self_exec() failed");
491			(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
492			exit(0);
493		}
494#else
495		(void)childA_rout();
496#endif
497
498	}
499
500	else if (pidA == -1) {
501		/*
502		 *  The fork of child A failed.
503		 */
504		tst_brkm(TBROK | TERRNO, NULL, "fork failed");
505		(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
506		exit(0);
507	}
508
509	/*
510	 *  Set to catch the SIGUSR2 with chld1_kill.
511	 */
512	if (signal(SIGUSR2, chld1_kill) == SIG_ERR) {
513		tst_brkm(TBROK, NULL,
514			 "Could not set to catch the parents signal.");
515		(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
516		(void)chld1_kill();
517		exit(0);
518	}
519
520	/*
521	 *  Set to catch the alarm signal SIGALRM.
522	 */
523	if (signal(SIGALRM, notify_timeout) == SIG_ERR) {
524		tst_brkm(TBROK, NULL,
525			 "Could not set to catch the childs time out alarm.");
526		(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
527		(void)chld1_kill();
528		exit(0);
529	}
530
531	/*
532	 *  Setting to catch the signals worked now let the children start up.
533	 *  Set an alarm which causes a time out on the pipe read loop.
534	 *  The children A & B will notify the parent(child1) that set up is complete
535	 *  and the pass/fail status of set up.
536	 */
537	(void)alarm(TIMEOUT - 40);
538
539	while ((read(pipeA_fd[0], pipe_buf, 1) != 1) && (alarm_flag == FALSE))
540		/*EMPTY*/;
541	(void)alarm(TIMEOUT - 40);
542
543	while ((read(pipeB_fd[0], pipe_buf, 1) != 1) && (alarm_flag == FALSE))
544		/*EMPTY*/;
545	(void)alarm(0);		/*Reset the alarm clock. */
546
547	/*
548	 *  Check the alarm flag.
549	 */
550	if (alarm_flag == TRUE) {
551		tst_brkm(TBROK, NULL,
552			 "The set up of the children failed by timing out.");
553		(void)chld1_kill();
554		(void)write(pipe1_fd[1], CHAR_SET_FAILED, 1);
555		exit(0);
556	}
557
558	/*
559	 *  Send a set up complete message to the parent.
560	 */
561	(void)write(pipe1_fd[1], CHAR_SET_PASSED, 1);
562
563	/*
564	 *  Pause until the signal SIGUSR1 or SIGUSR2 is sent from the parent.
565	 */
566	(void)pause();
567
568	/*
569	 *  Pause until signal SIGUSR2 is sent from the parent.
570	 *  This pause will only be executed if SIGUSR2 has not been received yet.
571	 */
572	while (1) {
573		sleep(1);
574	}
575
576}				/*End of child1_rout */
577
578/*******************************************************************************
579 *  This is the routine for child 2, which should not receive the parents signal.
580 ******************************************************************************/
581void child2_rout(void)
582{
583	who_am_i = '2';
584
585	/*
586	 * Set the process group of this process to be different
587	 * than the other processes.
588	 */
589	(void)setpgrp();
590
591	/*
592	 *  Set to catch the SIGUSR1 with usr1_rout.
593	 */
594	if (signal(SIGUSR1, usr1_rout) == SIG_ERR) {
595		tst_brkm(TBROK, cleanup,
596			 "Could not set to catch the parents signal.");
597		(void)write(pipe2_fd[1], CHAR_SET_FAILED, 1);
598		exit(0);
599	}
600
601	/* Send a set up complete message to parent. */
602	(void)write(pipe2_fd[1], CHAR_SET_PASSED, 1);
603
604	/*
605	 *  Pause until killed by the parent or SIGUSR1 is received.
606	 */
607	(void)pause();
608}
609
610/*******************************************************************************
611 *  This is the routine for child A, which should receive the parents signal.
612 ******************************************************************************/
613void childA_rout(void)
614{
615	who_am_i = 'A';
616
617	/* Send a set up complete message to parent. */
618	write(pipeA_fd[1], CHAR_SET_PASSED, 1);
619
620	/*
621	 *  Pause until killed by the parent or SIGUSR1 is received.
622	 */
623	(void)pause();
624
625	exit(0);
626}				/*End of childA_rout */
627
628#ifdef UCLINUX
629/*******************************************************************************
630 *  This is the routine for child A after self_exec
631 ******************************************************************************/
632void childA_rout_uclinux(void)
633{
634	/* Setup the signal handler again */
635	if (signal(SIGUSR1, usr1_rout) == SIG_ERR) {
636		tst_brkm(TBROK, NULL,
637			 "Could not set to catch the childrens signal.");
638		(void)write(pipeA_fd[1], CHAR_SET_FAILED, 1);
639		exit(0);
640	}
641
642	childA_rout();
643}
644#endif
645
646/*******************************************************************************
647 *  This is the routine for child B, which should not receive the parents signal.
648 ******************************************************************************/
649void childB_rout(void)
650{
651	who_am_i = 'B';
652
653	/*
654	 * Set the process group of this process to be different
655	 * than the other processes.
656	 */
657	(void)setpgrp();
658
659	/* Send a set up complete message to parent(child 1). */
660	write(pipeB_fd[1], CHAR_SET_PASSED, 1);
661
662	/*
663	 *  Pause until killed by the parent(child 1) or SIGUSR1 is received.
664	 */
665	(void)pause();
666
667	exit(0);
668}
669
670#ifdef UCLINUX
671/*******************************************************************************
672 *  This is the routine for child B after self_exec
673 ******************************************************************************/
674void childB_rout_uclinux(void)
675{
676	/* Setup the signal handler again */
677	if (signal(SIGUSR1, usr1_rout) == SIG_ERR) {
678		tst_brkm(TBROK, NULL,
679			 "Could not set to catch the childrens signal.");
680		(void)write(pipeB_fd[1], CHAR_SET_FAILED, 1);
681		exit(0);
682	}
683
684	childB_rout();
685}
686#endif
687
688/*******************************************************************************
689 *  This routine sets up the interprocess communication pipes, signal handling,
690 *  and process group information.
691 ******************************************************************************/
692void setup(void)
693{
694	int errno_buf;		/*indicates the errno if pipe set up fails.             */
695	int err_flag = FALSE;	/*Indicates if an error has occurred in pipe set up.    */
696
697	/*
698	 *  Set the process group ID to be equal between the parent and children.
699	 */
700	(void)setpgrp();
701
702	/*
703	 *  Set to catch unexpected signals.
704	 *  SIGCLD is set to be ignored because we do not wait for termination status.
705	 *  SIGUSR1 is set to be ignored because this is the signal we are using for
706	 *  the test and we are not concerned with the parent getting it.
707	 */
708
709	tst_sig(FORK, DEF_HANDLER, cleanup);
710
711	if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) {
712		tst_brkm(TBROK | TFAIL, NULL,
713			 "signal(SIGUSR1, SIG_IGN) failed");
714	}
715
716	if (signal(SIGCLD, SIG_IGN) == SIG_ERR) {
717		tst_brkm(TBROK | TERRNO, NULL,
718			 "signal(SIGCLD, SIG_IGN) failed");
719	}
720
721	TEST_PAUSE;
722
723	/*
724	 *  Set up pipe1, pipe2, pipeA, and pipeB.
725	 */
726	if ((pipe(pipe1_fd) == -1)
727	    || (fcntl(pipe1_fd[0], F_SETFL, O_NDELAY) == -1)) {
728		errno_buf = errno;
729		err_flag = TRUE;
730	}
731
732	if ((pipe(pipe2_fd) == -1)
733	    || (fcntl(pipe2_fd[0], F_SETFL, O_NDELAY) == -1)) {
734		errno_buf = errno;
735		err_flag = TRUE;
736	}
737
738	if ((pipe(pipeA_fd) == -1)
739	    || (fcntl(pipeA_fd[0], F_SETFL, O_NDELAY) == -1)) {
740		errno_buf = errno;
741		err_flag = TRUE;
742	}
743
744	if ((pipe(pipeB_fd) == -1)
745	    || (fcntl(pipeB_fd[0], F_SETFL, O_NDELAY) == -1)) {
746		errno_buf = errno;
747		err_flag = TRUE;
748	}
749
750	/*
751	 *  Check for errors.
752	 */
753	if (err_flag == TRUE) {
754		tst_brkm(TBROK | TERRNO, NULL, "pipe() failed");
755	}
756	return;
757
758}
759
760/***********************************************************
761 *  This routine indicates that the process caught SIGUSR1.
762 **********************************************************/
763void usr1_rout(void)
764{
765	switch (who_am_i) {
766	case '1':
767		if (write(pipe1_fd[1], SIG_CAUGHT, 1) == -1)
768			tst_resm(TWARN,
769				 "Writing signal catching status failed in child 1.");
770		break;
771	case '2':
772		if (write(pipe2_fd[1], SIG_CAUGHT, 1) == -1)
773			tst_resm(TWARN,
774				 "Writing signal catching status failed in child 2.");
775		break;
776	case 'A':
777		if (write(pipeA_fd[1], SIG_CAUGHT, 1) == -1)
778			tst_resm(TWARN,
779				 "Writing signal catching status failed in child A.");
780		break;
781	case 'B':
782		if (write(pipeB_fd[1], SIG_CAUGHT, 1) == -1)
783			tst_resm(TWARN,
784				 "Writing signal catching status failed in child B.");
785		break;
786	default:
787		tst_resm(TWARN,
788			 "Unexpected value %d for who_am_i in usr1_rout()",
789			 who_am_i);
790		break;
791	}
792
793}				/*End of usr1_rout */
794
795/***********************************************************
796 *  This routine handles the timeout alarm in the parent,
797 *  which occurs when the child fails to notify the parent
798 *  the status of set up.
799 **********************************************************/
800void notify_timeout(void)
801{
802	alarm_flag = TRUE;
803
804}				/*End of notify_timeout */
805
806/***********************************************************
807 *  This routine handles the procedure for removing the
808 *  children forked off during this test.
809 **********************************************************/
810void par_kill(void)
811{
812	int status;
813
814	/*
815	 *  Indicate to child1 that it can remove it's children and itself now.
816	 */
817	if (kill(pid1, SIGUSR2) == -1 && errno != ESRCH) {
818		tst_resm(TWARN | TERRNO, "kill() failed");
819		tst_resm(TWARN,
820			 "Child 1 and it's children may still be alive.");
821	}
822
823	/*
824	 *  Remove child 2.
825	 */
826	if (kill(pid2, SIGKILL) == -1 && errno != ESRCH)
827		tst_resm(TWARN, "Child2 may still be alive.");
828
829	wait(&status);
830	return;
831
832}				/*End of par_kill */
833
834/*********************************************************************
835 *  This routine is executed by child 1 when the parent tells it to
836 *  remove it's children and itself.
837 ********************************************************************/
838void chld1_kill(void)
839{
840	/*
841	 *  Remove children A & B.
842	 */
843	if (kill(pidA, SIGKILL) == -1 && errno != ESRCH)
844		tst_resm(TWARN | TERRNO,
845			 "kill(%d) failed; child 1's(A) child may still be alive",
846			 pidA);
847
848	(void)write(pipe1_fd[1], CHAR_SET_PASSED, 1);
849
850	if (kill(pidB, SIGKILL) == -1 && errno != ESRCH)
851		tst_resm(TWARN | TERRNO,
852			 "kill(%d) failed; child 1's(B) child may still be alive",
853			 pidB);
854
855	exit(0);
856
857}				/*End of chld1_kill */
858
859/***************************************************************
860 * cleanup() - performs all ONE TIME cleanup for this test at
861 *              completion or premature exit.
862 ***************************************************************/
863void cleanup(void)
864{
865
866}
867