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