2 * Copyright (c) 2012 David O'Brien
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/types.h>
30 #include <sys/resource.h>
31 #include <sys/sysctl.h>
45 #define SLEEP 20 /* seconds */
53 fprintf(stderr, "usage: %s\n", getprogname());
54 fprintf(stderr, "\t\t-n : length of fork(2) chain\n");
55 fprintf(stderr, "\t\t-t : limit run-time seconds\n");
65 if (getpid() == getpgrp() || verbose) {
67 "pid %d pgroup %d (ppid %d): Received SIGTERM(%d), exiting...\n",
68 getpid(), getpgrp(), getppid(), signum);
73 void angel_of_mercy(int);
75 angel_of_mercy(int sig __unused)
78 signal(SIGALRM, SIG_IGN); /* ignore this signal */
79 printf("Master process: alarmed waking up\n");
84 int bombing_run(unsigned, int);
86 bombing_run(unsigned chainlen, int stime)
93 switch (pid = fork()) {
95 errx(1, "%s: can't fork", __func__);
98 /* This is the code the child runs. */
99 bombing_run(--chainlen, stime);
103 /* This is the code the parent runs. */
104 if (getpid() == getpgrp()) {
105 signal(SIGALRM, angel_of_mercy);
106 alarm(stime); // time for bombing run...
107 cpid = wait4(pid, &status, 0, &ru);
110 "Cleanly shutting down - pid %d pgroup %d (ppid %d)\n",
111 getpid(), getpgrp(), getppid());
113 cpid = wait4(pid, &status, 0, &ru);
122 main(int argc, char *argv[])
124 time_t start /*,tvec*/;
128 int ch, k, maxprocperuid;
130 (void)signal(SIGTERM, term);
137 ctm[24] = '\0'; // see: man 3 ctime
138 fprintf(stderr, "*** fork() generation started on \"%s\" ***\n", ctm);
140 while ((ch = getopt(argc, argv, "n:t:v")) != -1)
143 nflag = strtol(optarg, &endptr, 10);
144 if (nflag <= 0 || *endptr != '\0')
145 errx(1, "illegal number, -n argument -- %s",
149 tflag = strtol(optarg, &endptr, 10);
150 if (tflag <= 0 || *endptr != '\0')
151 errx(1, "illegal number, -t argument -- %s",
163 len = sizeof(maxprocperuid);
164 k = sysctlbyname("kern.maxprocperuid", &maxprocperuid, &len,
167 /* Try to allow a shell to still be started. */
168 nflag = maxprocperuid - 10;
171 // Ensure a unique process group to make killing all children easier.
173 printf(" pid %d pgroup %d (ppid %d), %d fork chain over %d sec\n",
174 getpid(), getpgrp(), getppid(), nflag - 1, tflag);
176 return bombing_run(nflag, tflag);