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