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