7 #include <sys/ptrace.h>
24 /* Generate children*/
25 static void fork_children(void)
27 while (shm
->running_childs
< max_children
) {
31 if (shm
->spawn_no_more
== TRUE
)
34 /* a new child means a new seed, or the new child
35 * will do the same syscalls as the one in the pidslot it's replacing.
36 * (special case startup, or we reseed unnecessarily)
38 if (shm
->ready
== TRUE
)
41 /* Find a space for it in the pid map */
42 pidslot
= find_pid_slot(EMPTY_PIDSLOT
);
43 if (pidslot
== PIDSLOT_NOT_FOUND
) {
44 outputerr("## Pid map was full!\n");
49 if (logging
== TRUE
) {
52 fd
= fileno(shm
->logfiles
[pidslot
]);
53 if (ftruncate(fd
, 0) == 0)
54 lseek(fd
, 0, SEEK_SET
);
66 ret
= child_process(pidslot
);
67 output(1, "child %d exiting.\n", pidslot
);
71 output(0, "couldn't create child! (%s)\n", strerror(errno
));
72 shm
->exit_reason
= EXIT_FORK_FAILURE
;
77 shm
->pids
[pidslot
] = pid
;
78 shm
->running_childs
++;
80 debugf("Created child %d in pidslot %d [total:%d/%d]\n",
81 shm
->pids
[pidslot
], pidslot
,
82 shm
->running_childs
, max_children
);
84 if (shm
->exit_reason
!= STILL_RUNNING
)
90 debugf("created enough children\n");
93 void reap_child(pid_t childpid
)
97 lock(&shm
->reaper_lock
);
99 if (childpid
== shm
->last_reaped
) {
100 debugf("already reaped %d!\n", childpid
);
104 i
= find_pid_slot(childpid
);
105 if (i
== PIDSLOT_NOT_FOUND
)
108 debugf("Removing pid %d from pidmap.\n", childpid
);
109 shm
->pids
[i
] = EMPTY_PIDSLOT
;
110 shm
->running_childs
--;
111 shm
->tv
[i
].tv_sec
= 0;
112 shm
->last_reaped
= childpid
;
115 unlock(&shm
->reaper_lock
);
118 static void handle_child(pid_t childpid
, int childstatus
)
122 //debugf("Nothing changed. children:%d\n", shm->running_childs);
126 if (shm
->exit_reason
!= STILL_RUNNING
)
129 if (errno
== ECHILD
) {
133 debugf("All children exited!\n");
135 for_each_pidslot(i
) {
136 if (shm
->pids
[i
] != EMPTY_PIDSLOT
) {
137 if (pid_alive(shm
->pids
[i
]) == -1) {
138 debugf("Removing %d from pidmap\n", shm
->pids
[i
]);
139 shm
->pids
[i
] = EMPTY_PIDSLOT
;
140 shm
->running_childs
--;
142 debugf("%d looks still alive! ignoring.\n", shm
->pids
[i
]);
148 shm
->running_childs
= 0;
151 output(0, "error! (%s)\n", strerror(errno
));
155 debugf("Something happened to pid %d\n", childpid
);
157 if (WIFEXITED(childstatus
)) {
161 slot
= find_pid_slot(childpid
);
162 if (slot
== PIDSLOT_NOT_FOUND
) {
163 /* If we reaped it, it wouldn't show up, so check that. */
164 if (shm
->last_reaped
!= childpid
) {
165 outputerr("## Couldn't find pid slot for %d\n", childpid
);
166 shm
->exit_reason
= EXIT_LOST_PID_SLOT
;
170 debugf("Child %d exited after %ld syscalls.\n", childpid
, shm
->child_syscall_count
[slot
]);
171 reap_child(childpid
);
175 } else if (WIFSIGNALED(childstatus
)) {
177 switch (WTERMSIG(childstatus
)) {
179 debugf("got a alarm signal from pid %d\n", childpid
);
186 debugf("got a signal from pid %d (%s)\n", childpid
, strsignal(WTERMSIG(childstatus
)));
187 reap_child(childpid
);
190 debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus
));
195 } else if (WIFSTOPPED(childstatus
)) {
197 switch (WSTOPSIG(childstatus
)) {
199 debugf("got an alarm signal from pid %d\n", childpid
);
202 debugf("Sending PTRACE_DETACH (and then KILL)\n");
203 ptrace(PTRACE_DETACH
, childpid
, NULL
, NULL
);
204 kill(childpid
, SIGKILL
);
205 reap_child(childpid
);
212 debugf("Child %d was stopped by %s\n", childpid
, strsignal(WTERMSIG(childstatus
)));
213 reap_child(childpid
);
216 debugf("Child %d was stopped by unhandled signal (%s).\n", childpid
, strsignal(WSTOPSIG(childstatus
)));
221 } else if (WIFCONTINUED(childstatus
)) {
224 output(0, "erk, wtf\n");
229 static void handle_children(void)
235 if (shm
->running_childs
== 0)
238 /* First, we wait for *any* child to wake us up. */
239 pid
= waitpid(-1, &childstatus
, WUNTRACED
| WCONTINUED
);
241 /* We were awoken, handle it. */
242 handle_child(pid
, childstatus
);
244 /* While we're awake, let's see if the other children need attention.
245 * We do this instead of just waitpid(-1) again so that there's no way
246 * for any one child to starve the others of attention.
248 for_each_pidslot(i
) {
252 if (pid
== EMPTY_PIDSLOT
)
255 if (pid_is_valid(pid
) == FALSE
)
258 pid
= waitpid(pid
, &childstatus
, WUNTRACED
| WCONTINUED
| WNOHANG
);
260 handle_child(pid
, childstatus
);
264 static const char *reasons
[NUM_EXIT_REASONS
] = {
266 "No more syscalls enabled.",
267 "Reached maximum syscall count.",
268 "No file descriptors open.",
269 "Lost track of a pid slot.",
270 "shm corruption - Found a pid out of range.",
272 "kernel became tainted.",
273 "SHM was corrupted!",
274 "Child reparenting problem",
275 "No files in file list.",
276 "Main process disappeared.",
278 "Something happened during fd init.",
282 static const char * decode_exit(unsigned int reason
)
284 return reasons
[reason
];
289 while (shm
->exit_reason
== STILL_RUNNING
) {
291 if (shm
->spawn_no_more
== FALSE
) {
292 if (shm
->running_childs
< max_children
)
295 /* Periodic regenation of fd's etc. */
296 if (shm
->regenerate
>= REGENERATION_POINT
)
299 if (shm
->need_reseed
== TRUE
)
306 /* Wait until all children have exited. */
307 while (pidmap_empty() == FALSE
)
310 outputerr("Bailing main loop. Exit reason: %s\n", decode_exit(shm
->exit_reason
));