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 *
34 *    OS Testing - Silicon Graphics, Inc.
35 *
36 *    FUNCTION NAME     : forker
37 *			  background
38 *
39 *    FUNCTION TITLE    : fork desired number of copies of the current process
40 *			  fork a process and return control to caller
41 *
42 *    SYNOPSIS:
43 *      int forker(ncopies, mode, prefix)
44 *      int ncopies;
45 *	int mode;
46 *	char *prefix;
47 *
48 *	int background(prefix);
49 *	char *prefix;
50 *
51 *    AUTHOR            : Richard Logan
52 *
53 *    CO-PILOT(s)       : Dean Roehrich
54 *
55 *    INITIAL RELEASE   : UNICOS 8.0
56 *
57 *    DESIGN DESCRIPTION
58 *	The background function will do a fork of the current process.
59 *	The parent process will then exit, thus orphaning the
60 *	child process.  Doing this will not nice the child process
61 *	like executing a cmd in the background using "&" from the shell.
62 *	If the fork fails and prefix is not NULL, a error message is printed
63 *      to stderr and the process will exit with a value of errno.
64 *
65 *	The forker function will fork <ncopies> minus one copies
66 *	of the current process.  There are two modes in how the forks
67 *	will be done.  Mode 0 (default) will have all new processes
68 *	be childern of the parent process.    Using Mode 1,
69 *	the parent process will have one child and that child will
70 *	fork the next process, if necessary, and on and on.
71 *	The forker function will return the number of successful
72 *	forks.  This value will be different for the parent and each child.
73 *	Using mode 0, the parent will get the total number of successful
74 *	forks.  Using mode 1, the newest child will get the total number
75 *	of forks.  The parent will get a return value of 1.
76 *
77 *	The forker function also updates the global variables
78 *	Forker_pids[] and Forker_npids.  The Forker_pids array will
79 *      be updated to contain the pid of each new process.  The
80 *	Forker_npids variable contains the number of entries
81 *	in Forker_pids.  Note, not all processes will have
82 *	access to all pids via Forker_pids.  If using mode 0, only the
83 *	parent process and the last process will have all information.
84 *      If using mode 1, only the last child process will have all information.
85 *
86 *	If the prefix parameter is not NULL and the fork system call fails,
87 *      a error message will be printed to stderr.  The error message
88 *      the be preceeded with prefix string.  If prefix is NULL,
89 *      no error message is printed.
90 *
91 *    SPECIAL REQUIREMENTS
92 *	None.
93 *
94 *    UPDATE HISTORY
95 *      This should contain the description, author, and date of any
96 *      "interesting" modifications (i.e. info should helpful in
97 *      maintaining/enhancing this module).
98 *      username     description
99 *      ----------------------------------------------------------------
100 *	rrl	    This functions will first written during
101 *		the SFS testing days, 1993.
102 *
103 *    BUGS/LIMITATIONS
104 *     The child pids are stored in the fixed array, Forker_pids.
105 *     The array only has space for 4098 pids.  Only the first
106 *     4098 pids will be stored in the array.
107 *
108 **************************************************************/
109
110#include <stdio.h>
111#include <errno.h>
112#include <unistd.h>		/* fork, getpid, sleep */
113#include <string.h>
114#include <stdlib.h>		/* exit */
115#include "forker.h"
116
117int Forker_pids[FORKER_MAX_PIDS];	/* holds pids of forked processes */
118int Forker_npids = 0;		/* number of entries in Forker_pids */
119
120/***********************************************************************
121 *
122 * This function will fork and the parent will exit zero and
123 * the child will return.  This will orphan the returning process
124 * putting it in the background.
125 *
126 * Return Value
127 *   0 : if fork did not fail
128 *  !0 : if fork failed, the return value will be the errno.
129 ***********************************************************************/
130int background(char *prefix)
131{
132	switch (fork()) {
133	case -1:
134		if (prefix != NULL)
135			fprintf(stderr,
136				"%s: In %s background(), fork() failed, errno:%d %s\n",
137				prefix, __FILE__, errno, strerror(errno));
138		exit(errno);
139
140	case 0:		/* child process */
141		break;
142
143	default:
144		exit(0);
145	}
146
147	return 0;
148
149}				/* end of background */
150
151/***********************************************************************
152 * Forker will fork ncopies-1 copies of self.
153 *
154 ***********************************************************************/
155int forker(int ncopies,
156	int mode,	/* 0 - all children of parent, 1 - only 1 direct child */
157	char *prefix)	/* if ! NULL, an message will be printed to stderr */
158			/* if fork fails. The prefix (program name) will */
159			/* preceed the message */
160{
161	int cnt;
162	int pid;
163	static int ind = 0;
164
165	Forker_pids[ind] = 0;
166
167	for (cnt = 1; cnt < ncopies; cnt++) {
168
169		switch (mode) {
170		case 1:	/* only 1 direct child */
171			if ((pid = fork()) == -1) {
172				if (prefix != NULL)
173					fprintf(stderr,
174						"%s: %s,forker(): fork() failed, errno:%d %s\n",
175						prefix, __FILE__, errno,
176						strerror(errno));
177				return 0;
178			}
179			Forker_npids++;
180
181			switch (pid) {
182			case 0:	/* child - continues the forking */
183
184				if (Forker_npids < FORKER_MAX_PIDS)
185					Forker_pids[Forker_npids - 1] =
186					    getpid();
187				break;
188
189			default:	/* parent - stop the forking */
190				if (Forker_npids < FORKER_MAX_PIDS)
191					Forker_pids[Forker_npids - 1] = pid;
192				return cnt - 1;
193			}
194
195			break;
196
197		default:	/* all new processes are childern of parent */
198			if ((pid = fork()) == -1) {
199				if (prefix != NULL)
200					fprintf(stderr,
201						"%s: %s,forker(): fork() failed, errno:%d %s\n",
202						prefix, __FILE__, errno,
203						strerror(errno));
204				return cnt - 1;
205			}
206			Forker_npids++;
207
208			switch (pid) {
209			case 0:	/* child - stops the forking */
210				if (Forker_npids < FORKER_MAX_PIDS)
211					Forker_pids[Forker_npids - 1] =
212					    getpid();
213				return cnt;
214
215			default:	/* parent - continues the forking */
216				if (Forker_npids < FORKER_MAX_PIDS)
217					Forker_pids[Forker_npids - 1] = pid;
218				break;
219			}
220			break;
221		}
222	}
223
224	if (Forker_npids < FORKER_MAX_PIDS)
225		Forker_pids[Forker_npids] = 0;
226	return cnt - 1;
227
228}				/* end of forker */
229
230#if UNIT_TEST
231
232/*
233 * The following is a unit test main for the background and forker
234 * functions.
235 */
236
237int main(argc, argv)
238int argc;
239char **argv;
240{
241	int ncopies = 1;
242	int mode = 0;
243	int ret;
244	int ind;
245
246	if (argc == 1) {
247		printf("Usage: %s ncopies [mode]\n", argv[0]);
248		exit(1);
249	}
250
251	if (sscanf(argv[1], "%i", &ncopies) != 1) {
252		printf("%s: ncopies argument must be integer\n", argv[0]);
253		exit(1);
254	}
255
256	if (argc == 3)
257		if (sscanf(argv[2], "%i", &mode) != 1) {
258			printf("%s: mode argument must be integer\n", argv[0]);
259			exit(1);
260		}
261
262	printf("Starting Pid = %d\n", getpid());
263	ret = background(argv[0]);
264	printf("After background() ret:%d, pid = %d\n", ret, getpid());
265
266	ret = forker(ncopies, mode, argv[0]);
267
268	printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n",
269	       ncopies, mode, argv[0], ret, getpid());
270
271	printf("%d My version of Forker_pids[],  Forker_npids = %d\n",
272	       getpid(), Forker_npids);
273
274	for (ind = 0; ind < Forker_npids; ind++) {
275		printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
276	}
277
278	sleep(30);
279	exit(0);
280}
281
282#endif /* UNIT_TEST */
283