blob: 573217105d0da2f2ae563f475c445643caea4ecf [file] [log] [blame]
/*
* Copyright (c) International Business Machines Corp., 2001
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* NAME
* fork12.c
*
* DESCRIPTION
* Check that all children inherit parent's file descriptor
*
* ALGORITHM
* Parent forks processes until -1 is returned.$
*
* USAGE
* fork12
* ** CAUTION ** Can hang your machine, esp prior to 2.4.19
*
* HISTORY
* 07/2001 Ported by Wayne Boyer
* 07/2002 Split from fork07 as a test case to exhaust available pids.
*
* RESTRICTIONS
* Should be run as root to avoid resource limits.$
* Should not be run with other test programs because it tries to
* use all available pids.
*/
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include "test.h"
char *TCID = "fork12";
int TST_TOTAL = 1;
static void setup(void);
static void cleanup(void);
static void fork12_sigs(int signum);
int main(int ac, char **av)
{
int forks, pid1, fork_errno, waitstatus;
int ret, status;
int lc;
const char *msg;
msg = parse_opts(ac, av, NULL, NULL);
if (msg != NULL)
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
setup();
for (lc = 0; TEST_LOOPING(lc); lc++) {
tst_count = 0;
tst_resm(TINFO, "Forking as many kids as possible");
forks = 0;
while ((pid1 = fork()) != -1) {
if (pid1 == 0) { /* child */
pause();
exit(0);
}
forks++;
ret = waitpid(-1, &status, WNOHANG);
if (ret < 0)
tst_brkm(TBROK, cleanup,
"waitpid failed %d: %s\n", errno,
strerror(errno));
if (ret > 0) {
/* a child may be killed by OOM killer */
if (WTERMSIG(status) == SIGKILL)
break;
tst_brkm(TBROK, cleanup,
"child exit with error code %d or signal %d",
WEXITSTATUS(status), WTERMSIG(status));
}
}
fork_errno = errno;
/* parent */
tst_resm(TINFO, "Number of processes forked is %d", forks);
tst_resm(TPASS, "fork() eventually failed with %d: %s",
fork_errno, strerror(fork_errno));
/* collect our kids */
/*
* Introducing a sleep(3) to make sure all children are
* at pause() when SIGQUIT is sent to them
*/
sleep(3);
kill(0, SIGQUIT);
while (wait(&waitstatus) > 0) ;
}
cleanup();
tst_exit();
}
static void setup(void)
{
tst_sig(FORK, fork12_sigs, cleanup);
TEST_PAUSE;
}
static void cleanup(void)
{
int waitstatus;
/* collect our kids */
kill(0, SIGQUIT);
while (wait(&waitstatus) > 0) ;
}
static void fork12_sigs(int signum)
{
if (signum == SIGQUIT) {
/* Children will continue, parent will ignore */
} else {
tst_brkm(TBROK, cleanup,
"Unexpected signal %d received.", signum);
}
}