1/*	$OpenBSD: earlysig.c,v 1.2 2014/05/20 01:25:24 guenther Exp $	*/
2
3/*
4 * Public domain.  2005, Otto Moerbeek; 2013, Philip Guenther
5 *
6 * Try to create the case where a signal is delivered to a process before
7 * the pthread fork() wrapper can unlock the ld.so bind lock.
8 */
9
10#include <sys/types.h>
11#include <sys/time.h>
12#include <sys/utsname.h>
13#include <sys/wait.h>
14
15#include <err.h>
16#include <pthread.h>
17#include <signal.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23void dohup(int signo)
24{
25	struct utsname name;
26	uname(&name);			/* anything that'll require binding */
27}
28
29void *tmain(void *arg)
30{
31	return (arg);
32}
33
34int
35main()
36{
37	pthread_t tid;
38	pid_t pid, rpid;
39	int r, status;
40
41	if (signal(SIGHUP, dohup) == SIG_ERR)
42		err(1, "signal");
43
44	/* make sure the thread library is fully active */
45	if ((r = pthread_create(&tid, NULL, tmain, NULL)))
46		errc(1, r, "pthread_create");
47	pthread_join(tid, NULL);
48
49	/* make sure kill() and all the symbols in fork() are bound */
50	kill(0, 0);
51	if ((pid = fork()) <= 0) {
52		if (pid == -1)
53			err(1, "fork");
54		_exit(0);
55	}
56	if (waitpid(pid, &status, 0) == -1)
57		err(1, "waitpid");
58
59
60	switch(pid = fork()) {
61	case -1:
62		err(1, "fork");
63		break;
64	case 0:
65		sleep(2);
66		_exit(0);
67	default:
68		kill(pid, SIGHUP);
69		sleep(3);
70		if ((rpid = waitpid(pid, &status, WNOHANG)) == -1)
71			err(1, "waitpid");
72		if (rpid == 0) {
73			/* took too long */
74			kill(pid, SIGKILL);
75			if (waitpid(pid, &status, 0) == -1)
76				err(1, "waitpid");
77		}
78		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
79			exit(0);
80		else if (WIFEXITED(status))
81			errx(1, "child exited with status %d",
82			    WEXITSTATUS(status));
83		else if (WTERMSIG(status) == SIGKILL)
84			errx(1, "failed: child hung");
85		errx(1, "child killed by signal %d", WTERMSIG(status));
86	}
87}
88