1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify it
5f08c3bdfSopenharmony_ci * under the terms of version 2 of the GNU General Public License as
6f08c3bdfSopenharmony_ci * published by the Free Software Foundation.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, but
9f08c3bdfSopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
10f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * Further, this software is distributed without any warranty that it is
13f08c3bdfSopenharmony_ci * free of the rightful claim of any third person regarding infringement
14f08c3bdfSopenharmony_ci * or the like.  Any license provided herein, whether implied or
15f08c3bdfSopenharmony_ci * otherwise, applies only to this software file.  Patent licenses, if
16f08c3bdfSopenharmony_ci * any, provided herein do not apply to combinations of this program with
17f08c3bdfSopenharmony_ci * other software, or any other product whatsoever.
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License along
20f08c3bdfSopenharmony_ci * with this program; if not, write the Free Software Foundation, Inc.,
21f08c3bdfSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22f08c3bdfSopenharmony_ci *
23f08c3bdfSopenharmony_ci * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24f08c3bdfSopenharmony_ci * Mountain View, CA  94043, or:
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci * http://www.sgi.com
27f08c3bdfSopenharmony_ci *
28f08c3bdfSopenharmony_ci * For further information regarding this notice, see:
29f08c3bdfSopenharmony_ci *
30f08c3bdfSopenharmony_ci * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31f08c3bdfSopenharmony_ci */
32f08c3bdfSopenharmony_ci/**************************************************************
33f08c3bdfSopenharmony_ci *
34f08c3bdfSopenharmony_ci *    OS Testing - Silicon Graphics, Inc.
35f08c3bdfSopenharmony_ci *
36f08c3bdfSopenharmony_ci *    FUNCTION NAME     : forker
37f08c3bdfSopenharmony_ci *			  background
38f08c3bdfSopenharmony_ci *
39f08c3bdfSopenharmony_ci *    FUNCTION TITLE    : fork desired number of copies of the current process
40f08c3bdfSopenharmony_ci *			  fork a process and return control to caller
41f08c3bdfSopenharmony_ci *
42f08c3bdfSopenharmony_ci *    SYNOPSIS:
43f08c3bdfSopenharmony_ci *      int forker(ncopies, mode, prefix)
44f08c3bdfSopenharmony_ci *      int ncopies;
45f08c3bdfSopenharmony_ci *	int mode;
46f08c3bdfSopenharmony_ci *	char *prefix;
47f08c3bdfSopenharmony_ci *
48f08c3bdfSopenharmony_ci *	int background(prefix);
49f08c3bdfSopenharmony_ci *	char *prefix;
50f08c3bdfSopenharmony_ci *
51f08c3bdfSopenharmony_ci *    AUTHOR            : Richard Logan
52f08c3bdfSopenharmony_ci *
53f08c3bdfSopenharmony_ci *    CO-PILOT(s)       : Dean Roehrich
54f08c3bdfSopenharmony_ci *
55f08c3bdfSopenharmony_ci *    INITIAL RELEASE   : UNICOS 8.0
56f08c3bdfSopenharmony_ci *
57f08c3bdfSopenharmony_ci *    DESIGN DESCRIPTION
58f08c3bdfSopenharmony_ci *	The background function will do a fork of the current process.
59f08c3bdfSopenharmony_ci *	The parent process will then exit, thus orphaning the
60f08c3bdfSopenharmony_ci *	child process.  Doing this will not nice the child process
61f08c3bdfSopenharmony_ci *	like executing a cmd in the background using "&" from the shell.
62f08c3bdfSopenharmony_ci *	If the fork fails and prefix is not NULL, a error message is printed
63f08c3bdfSopenharmony_ci *      to stderr and the process will exit with a value of errno.
64f08c3bdfSopenharmony_ci *
65f08c3bdfSopenharmony_ci *	The forker function will fork <ncopies> minus one copies
66f08c3bdfSopenharmony_ci *	of the current process.  There are two modes in how the forks
67f08c3bdfSopenharmony_ci *	will be done.  Mode 0 (default) will have all new processes
68f08c3bdfSopenharmony_ci *	be childern of the parent process.    Using Mode 1,
69f08c3bdfSopenharmony_ci *	the parent process will have one child and that child will
70f08c3bdfSopenharmony_ci *	fork the next process, if necessary, and on and on.
71f08c3bdfSopenharmony_ci *	The forker function will return the number of successful
72f08c3bdfSopenharmony_ci *	forks.  This value will be different for the parent and each child.
73f08c3bdfSopenharmony_ci *	Using mode 0, the parent will get the total number of successful
74f08c3bdfSopenharmony_ci *	forks.  Using mode 1, the newest child will get the total number
75f08c3bdfSopenharmony_ci *	of forks.  The parent will get a return value of 1.
76f08c3bdfSopenharmony_ci *
77f08c3bdfSopenharmony_ci *	The forker function also updates the global variables
78f08c3bdfSopenharmony_ci *	Forker_pids[] and Forker_npids.  The Forker_pids array will
79f08c3bdfSopenharmony_ci *      be updated to contain the pid of each new process.  The
80f08c3bdfSopenharmony_ci *	Forker_npids variable contains the number of entries
81f08c3bdfSopenharmony_ci *	in Forker_pids.  Note, not all processes will have
82f08c3bdfSopenharmony_ci *	access to all pids via Forker_pids.  If using mode 0, only the
83f08c3bdfSopenharmony_ci *	parent process and the last process will have all information.
84f08c3bdfSopenharmony_ci *      If using mode 1, only the last child process will have all information.
85f08c3bdfSopenharmony_ci *
86f08c3bdfSopenharmony_ci *	If the prefix parameter is not NULL and the fork system call fails,
87f08c3bdfSopenharmony_ci *      a error message will be printed to stderr.  The error message
88f08c3bdfSopenharmony_ci *      the be preceeded with prefix string.  If prefix is NULL,
89f08c3bdfSopenharmony_ci *      no error message is printed.
90f08c3bdfSopenharmony_ci *
91f08c3bdfSopenharmony_ci *    SPECIAL REQUIREMENTS
92f08c3bdfSopenharmony_ci *	None.
93f08c3bdfSopenharmony_ci *
94f08c3bdfSopenharmony_ci *    UPDATE HISTORY
95f08c3bdfSopenharmony_ci *      This should contain the description, author, and date of any
96f08c3bdfSopenharmony_ci *      "interesting" modifications (i.e. info should helpful in
97f08c3bdfSopenharmony_ci *      maintaining/enhancing this module).
98f08c3bdfSopenharmony_ci *      username     description
99f08c3bdfSopenharmony_ci *      ----------------------------------------------------------------
100f08c3bdfSopenharmony_ci *	rrl	    This functions will first written during
101f08c3bdfSopenharmony_ci *		the SFS testing days, 1993.
102f08c3bdfSopenharmony_ci *
103f08c3bdfSopenharmony_ci *    BUGS/LIMITATIONS
104f08c3bdfSopenharmony_ci *     The child pids are stored in the fixed array, Forker_pids.
105f08c3bdfSopenharmony_ci *     The array only has space for 4098 pids.  Only the first
106f08c3bdfSopenharmony_ci *     4098 pids will be stored in the array.
107f08c3bdfSopenharmony_ci *
108f08c3bdfSopenharmony_ci **************************************************************/
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci#include <stdio.h>
111f08c3bdfSopenharmony_ci#include <errno.h>
112f08c3bdfSopenharmony_ci#include <unistd.h>		/* fork, getpid, sleep */
113f08c3bdfSopenharmony_ci#include <string.h>
114f08c3bdfSopenharmony_ci#include <stdlib.h>		/* exit */
115f08c3bdfSopenharmony_ci#include "forker.h"
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ciint Forker_pids[FORKER_MAX_PIDS];	/* holds pids of forked processes */
118f08c3bdfSopenharmony_ciint Forker_npids = 0;		/* number of entries in Forker_pids */
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci/***********************************************************************
121f08c3bdfSopenharmony_ci *
122f08c3bdfSopenharmony_ci * This function will fork and the parent will exit zero and
123f08c3bdfSopenharmony_ci * the child will return.  This will orphan the returning process
124f08c3bdfSopenharmony_ci * putting it in the background.
125f08c3bdfSopenharmony_ci *
126f08c3bdfSopenharmony_ci * Return Value
127f08c3bdfSopenharmony_ci *   0 : if fork did not fail
128f08c3bdfSopenharmony_ci *  !0 : if fork failed, the return value will be the errno.
129f08c3bdfSopenharmony_ci ***********************************************************************/
130f08c3bdfSopenharmony_ciint background(char *prefix)
131f08c3bdfSopenharmony_ci{
132f08c3bdfSopenharmony_ci	switch (fork()) {
133f08c3bdfSopenharmony_ci	case -1:
134f08c3bdfSopenharmony_ci		if (prefix != NULL)
135f08c3bdfSopenharmony_ci			fprintf(stderr,
136f08c3bdfSopenharmony_ci				"%s: In %s background(), fork() failed, errno:%d %s\n",
137f08c3bdfSopenharmony_ci				prefix, __FILE__, errno, strerror(errno));
138f08c3bdfSopenharmony_ci		exit(errno);
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	case 0:		/* child process */
141f08c3bdfSopenharmony_ci		break;
142f08c3bdfSopenharmony_ci
143f08c3bdfSopenharmony_ci	default:
144f08c3bdfSopenharmony_ci		exit(0);
145f08c3bdfSopenharmony_ci	}
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	return 0;
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci}				/* end of background */
150f08c3bdfSopenharmony_ci
151f08c3bdfSopenharmony_ci/***********************************************************************
152f08c3bdfSopenharmony_ci * Forker will fork ncopies-1 copies of self.
153f08c3bdfSopenharmony_ci *
154f08c3bdfSopenharmony_ci ***********************************************************************/
155f08c3bdfSopenharmony_ciint forker(int ncopies,
156f08c3bdfSopenharmony_ci	int mode,	/* 0 - all children of parent, 1 - only 1 direct child */
157f08c3bdfSopenharmony_ci	char *prefix)	/* if ! NULL, an message will be printed to stderr */
158f08c3bdfSopenharmony_ci			/* if fork fails. The prefix (program name) will */
159f08c3bdfSopenharmony_ci			/* preceed the message */
160f08c3bdfSopenharmony_ci{
161f08c3bdfSopenharmony_ci	int cnt;
162f08c3bdfSopenharmony_ci	int pid;
163f08c3bdfSopenharmony_ci	static int ind = 0;
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	Forker_pids[ind] = 0;
166f08c3bdfSopenharmony_ci
167f08c3bdfSopenharmony_ci	for (cnt = 1; cnt < ncopies; cnt++) {
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ci		switch (mode) {
170f08c3bdfSopenharmony_ci		case 1:	/* only 1 direct child */
171f08c3bdfSopenharmony_ci			if ((pid = fork()) == -1) {
172f08c3bdfSopenharmony_ci				if (prefix != NULL)
173f08c3bdfSopenharmony_ci					fprintf(stderr,
174f08c3bdfSopenharmony_ci						"%s: %s,forker(): fork() failed, errno:%d %s\n",
175f08c3bdfSopenharmony_ci						prefix, __FILE__, errno,
176f08c3bdfSopenharmony_ci						strerror(errno));
177f08c3bdfSopenharmony_ci				return 0;
178f08c3bdfSopenharmony_ci			}
179f08c3bdfSopenharmony_ci			Forker_npids++;
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci			switch (pid) {
182f08c3bdfSopenharmony_ci			case 0:	/* child - continues the forking */
183f08c3bdfSopenharmony_ci
184f08c3bdfSopenharmony_ci				if (Forker_npids < FORKER_MAX_PIDS)
185f08c3bdfSopenharmony_ci					Forker_pids[Forker_npids - 1] =
186f08c3bdfSopenharmony_ci					    getpid();
187f08c3bdfSopenharmony_ci				break;
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci			default:	/* parent - stop the forking */
190f08c3bdfSopenharmony_ci				if (Forker_npids < FORKER_MAX_PIDS)
191f08c3bdfSopenharmony_ci					Forker_pids[Forker_npids - 1] = pid;
192f08c3bdfSopenharmony_ci				return cnt - 1;
193f08c3bdfSopenharmony_ci			}
194f08c3bdfSopenharmony_ci
195f08c3bdfSopenharmony_ci			break;
196f08c3bdfSopenharmony_ci
197f08c3bdfSopenharmony_ci		default:	/* all new processes are childern of parent */
198f08c3bdfSopenharmony_ci			if ((pid = fork()) == -1) {
199f08c3bdfSopenharmony_ci				if (prefix != NULL)
200f08c3bdfSopenharmony_ci					fprintf(stderr,
201f08c3bdfSopenharmony_ci						"%s: %s,forker(): fork() failed, errno:%d %s\n",
202f08c3bdfSopenharmony_ci						prefix, __FILE__, errno,
203f08c3bdfSopenharmony_ci						strerror(errno));
204f08c3bdfSopenharmony_ci				return cnt - 1;
205f08c3bdfSopenharmony_ci			}
206f08c3bdfSopenharmony_ci			Forker_npids++;
207f08c3bdfSopenharmony_ci
208f08c3bdfSopenharmony_ci			switch (pid) {
209f08c3bdfSopenharmony_ci			case 0:	/* child - stops the forking */
210f08c3bdfSopenharmony_ci				if (Forker_npids < FORKER_MAX_PIDS)
211f08c3bdfSopenharmony_ci					Forker_pids[Forker_npids - 1] =
212f08c3bdfSopenharmony_ci					    getpid();
213f08c3bdfSopenharmony_ci				return cnt;
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_ci			default:	/* parent - continues the forking */
216f08c3bdfSopenharmony_ci				if (Forker_npids < FORKER_MAX_PIDS)
217f08c3bdfSopenharmony_ci					Forker_pids[Forker_npids - 1] = pid;
218f08c3bdfSopenharmony_ci				break;
219f08c3bdfSopenharmony_ci			}
220f08c3bdfSopenharmony_ci			break;
221f08c3bdfSopenharmony_ci		}
222f08c3bdfSopenharmony_ci	}
223f08c3bdfSopenharmony_ci
224f08c3bdfSopenharmony_ci	if (Forker_npids < FORKER_MAX_PIDS)
225f08c3bdfSopenharmony_ci		Forker_pids[Forker_npids] = 0;
226f08c3bdfSopenharmony_ci	return cnt - 1;
227f08c3bdfSopenharmony_ci
228f08c3bdfSopenharmony_ci}				/* end of forker */
229f08c3bdfSopenharmony_ci
230f08c3bdfSopenharmony_ci#if UNIT_TEST
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci/*
233f08c3bdfSopenharmony_ci * The following is a unit test main for the background and forker
234f08c3bdfSopenharmony_ci * functions.
235f08c3bdfSopenharmony_ci */
236f08c3bdfSopenharmony_ci
237f08c3bdfSopenharmony_ciint main(argc, argv)
238f08c3bdfSopenharmony_ciint argc;
239f08c3bdfSopenharmony_cichar **argv;
240f08c3bdfSopenharmony_ci{
241f08c3bdfSopenharmony_ci	int ncopies = 1;
242f08c3bdfSopenharmony_ci	int mode = 0;
243f08c3bdfSopenharmony_ci	int ret;
244f08c3bdfSopenharmony_ci	int ind;
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci	if (argc == 1) {
247f08c3bdfSopenharmony_ci		printf("Usage: %s ncopies [mode]\n", argv[0]);
248f08c3bdfSopenharmony_ci		exit(1);
249f08c3bdfSopenharmony_ci	}
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci	if (sscanf(argv[1], "%i", &ncopies) != 1) {
252f08c3bdfSopenharmony_ci		printf("%s: ncopies argument must be integer\n", argv[0]);
253f08c3bdfSopenharmony_ci		exit(1);
254f08c3bdfSopenharmony_ci	}
255f08c3bdfSopenharmony_ci
256f08c3bdfSopenharmony_ci	if (argc == 3)
257f08c3bdfSopenharmony_ci		if (sscanf(argv[2], "%i", &mode) != 1) {
258f08c3bdfSopenharmony_ci			printf("%s: mode argument must be integer\n", argv[0]);
259f08c3bdfSopenharmony_ci			exit(1);
260f08c3bdfSopenharmony_ci		}
261f08c3bdfSopenharmony_ci
262f08c3bdfSopenharmony_ci	printf("Starting Pid = %d\n", getpid());
263f08c3bdfSopenharmony_ci	ret = background(argv[0]);
264f08c3bdfSopenharmony_ci	printf("After background() ret:%d, pid = %d\n", ret, getpid());
265f08c3bdfSopenharmony_ci
266f08c3bdfSopenharmony_ci	ret = forker(ncopies, mode, argv[0]);
267f08c3bdfSopenharmony_ci
268f08c3bdfSopenharmony_ci	printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n",
269f08c3bdfSopenharmony_ci	       ncopies, mode, argv[0], ret, getpid());
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci	printf("%d My version of Forker_pids[],  Forker_npids = %d\n",
272f08c3bdfSopenharmony_ci	       getpid(), Forker_npids);
273f08c3bdfSopenharmony_ci
274f08c3bdfSopenharmony_ci	for (ind = 0; ind < Forker_npids; ind++) {
275f08c3bdfSopenharmony_ci		printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
276f08c3bdfSopenharmony_ci	}
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_ci	sleep(30);
279f08c3bdfSopenharmony_ci	exit(0);
280f08c3bdfSopenharmony_ci}
281f08c3bdfSopenharmony_ci
282f08c3bdfSopenharmony_ci#endif /* UNIT_TEST */
283