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
);
64 child_process(pidslot
);
65 output(1, "child %d exiting.\n", pidslot
);
69 output(0, "couldn't create child! (%s)\n", strerror(errno
));
70 shm
->exit_reason
= EXIT_FORK_FAILURE
;
75 shm
->pids
[pidslot
] = pid
;
76 shm
->running_childs
++;
78 debugf("Created child %d in pidslot %d [total:%d/%d]\n",
79 shm
->pids
[pidslot
], pidslot
,
80 shm
->running_childs
, max_children
);
82 if (shm
->exit_reason
!= STILL_RUNNING
)
88 debugf("created enough children\n");
91 void reap_child(pid_t childpid
)
95 lock(&shm
->reaper_lock
);
97 if (childpid
== shm
->last_reaped
) {
98 debugf("already reaped %d!\n", childpid
);
102 i
= find_pid_slot(childpid
);
103 if (i
== PIDSLOT_NOT_FOUND
)
106 debugf("Removing pid %d from pidmap.\n", childpid
);
107 shm
->pids
[i
] = EMPTY_PIDSLOT
;
108 shm
->running_childs
--;
109 shm
->tv
[i
].tv_sec
= 0;
110 shm
->last_reaped
= childpid
;
113 unlock(&shm
->reaper_lock
);
116 static void handle_child(pid_t childpid
, int childstatus
)
120 //debugf("Nothing changed. children:%d\n", shm->running_childs);
124 if (shm
->exit_reason
!= STILL_RUNNING
)
127 if (errno
== ECHILD
) {
131 debugf("All children exited!\n");
133 for_each_pidslot(i
) {
134 if (shm
->pids
[i
] != EMPTY_PIDSLOT
) {
135 if (pid_alive(shm
->pids
[i
]) == -1) {
136 debugf("Removing %d from pidmap\n", shm
->pids
[i
]);
137 shm
->pids
[i
] = EMPTY_PIDSLOT
;
138 shm
->running_childs
--;
140 debugf("%d looks still alive! ignoring.\n", shm
->pids
[i
]);
146 shm
->running_childs
= 0;
149 output(0, "error! (%s)\n", strerror(errno
));
153 debugf("Something happened to pid %d\n", childpid
);
155 if (WIFEXITED(childstatus
)) {
159 slot
= find_pid_slot(childpid
);
160 if (slot
== PIDSLOT_NOT_FOUND
) {
161 /* If we reaped it, it wouldn't show up, so check that. */
162 if (shm
->last_reaped
!= childpid
) {
163 outputerr("## Couldn't find pid slot for %d\n", childpid
);
164 shm
->exit_reason
= EXIT_LOST_PID_SLOT
;
168 debugf("Child %d exited after %ld syscalls.\n", childpid
, shm
->child_syscall_count
[slot
]);
169 reap_child(childpid
);
173 } else if (WIFSIGNALED(childstatus
)) {
175 switch (WTERMSIG(childstatus
)) {
177 debugf("got a alarm signal from pid %d\n", childpid
);
184 debugf("got a signal from pid %d (%s)\n", childpid
, strsignal(WTERMSIG(childstatus
)));
185 reap_child(childpid
);
188 debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus
));
193 } else if (WIFSTOPPED(childstatus
)) {
195 switch (WSTOPSIG(childstatus
)) {
197 debugf("got an alarm signal from pid %d\n", childpid
);
200 debugf("Sending PTRACE_DETACH (and then KILL)\n");
201 ptrace(PTRACE_DETACH
, childpid
, NULL
, NULL
);
202 kill(childpid
, SIGKILL
);
203 reap_child(childpid
);
210 debugf("Child %d was stopped by %s\n", childpid
, strsignal(WTERMSIG(childstatus
)));
211 reap_child(childpid
);
214 debugf("Child %d was stopped by unhandled signal (%s).\n", childpid
, strsignal(WSTOPSIG(childstatus
)));
219 } else if (WIFCONTINUED(childstatus
)) {
222 output(0, "erk, wtf\n");
227 static void handle_children(void)
233 if (shm
->running_childs
== 0)
236 /* First, we wait for *any* child to wake us up. */
237 pid
= waitpid(-1, &childstatus
, WUNTRACED
| WCONTINUED
);
239 /* We were awoken, handle it. */
240 handle_child(pid
, childstatus
);
242 /* While we're awake, let's see if the other children need attention.
243 * We do this instead of just waitpid(-1) again so that there's no way
244 * for any one child to starve the others of attention.
246 for_each_pidslot(i
) {
250 if (pid
== EMPTY_PIDSLOT
)
253 if (pid_is_valid(pid
) == FALSE
)
256 pid
= waitpid(pid
, &childstatus
, WUNTRACED
| WCONTINUED
| WNOHANG
);
258 handle_child(pid
, childstatus
);
262 static const char *reasons
[NUM_EXIT_REASONS
] = {
264 "No more syscalls enabled.",
265 "Reached maximum syscall count.",
266 "No file descriptors open.",
267 "Lost track of a pid slot.",
268 "shm corruption - Found a pid out of range.",
270 "kernel became tainted.",
271 "SHM was corrupted!",
272 "Child reparenting problem",
273 "No files in file list.",
274 "Main process disappeared.",
276 "Something happened during fd init.",
280 static const char * decode_exit(unsigned int reason
)
282 return reasons
[reason
];
287 while (shm
->exit_reason
== STILL_RUNNING
) {
289 if (shm
->spawn_no_more
== FALSE
) {
290 if (shm
->running_childs
< max_children
)
293 /* Periodic regenation of fd's etc. */
294 if (shm
->regenerate
>= REGENERATION_POINT
)
301 /* Wait until all children have exited. */
302 while (pidmap_empty() == FALSE
)
305 outputerr("Bailing main loop. Exit reason: %s\n", decode_exit(shm
->exit_reason
));