1 /*	$OpenBSD: sigsuspend.c,v 1.1 2020/09/16 14:04:30 mpi Exp $	*/
2 /*
3  *	Written by Artur Grabowski <art@openbsd.org> 2005, Public domain.
4  */
5 
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <err.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 
14 sig_atomic_t gotusr1;
15 sig_atomic_t gotusr2;
16 
17 void
usr1handler(int signo)18 usr1handler(int signo)
19 {
20 	gotusr1 = 1;
21 }
22 
23 void
usr2handler(int signo)24 usr2handler(int signo)
25 {
26 	gotusr2 = 1;
27 }
28 
29 int
main()30 main()
31 {
32 	sigset_t set, oset;
33 	struct sigaction sa;
34 	pid_t pid, ppid;
35 	int status;
36 
37 	ppid = getpid();
38 
39 	memset(&sa, 0, sizeof(sa));
40 	sigemptyset(&sa.sa_mask);
41 	sa.sa_handler = usr1handler;
42 	if (sigaction(SIGUSR1, &sa, NULL))
43 		err(1, "sigaction(USR1)");
44 
45 	sa.sa_handler = usr2handler;
46 	if (sigaction(SIGUSR2, &sa, NULL))
47 		err(1, "sigaction(USR2)");
48 
49 	/*
50 	 * Set the procmask to mask the early USR1 the child will send us.
51 	 */
52 	sigemptyset(&set);
53 	sigaddset(&set, SIGUSR1);
54 	sigaddset(&set, SIGUSR2);
55 	if (sigprocmask(SIG_BLOCK, &set, &oset))
56 		err(1, "sigprocmask");
57 
58 	switch((pid = fork())) {
59 	case 0:
60 		/*
61 		 * In the child.
62 		 */
63 
64 		kill(ppid, SIGUSR1);	/* Tell the parent we're ready. */
65 
66 		sigemptyset(&set);
67 		sigaddset(&set, SIGUSR2);
68 		sigsuspend(&set);
69 
70 		/*
71 		 * Check that sigsuspend didn't change the signal mask.
72 		 */
73 		if (sigprocmask(SIG_SETMASK, NULL, &oset))
74 			err(1, "sigprocmask");
75 		if (!sigismember(&oset, SIGUSR1) ||
76 		    !sigismember(&oset, SIGUSR2))
77 			errx(1, "sigprocmask is bad");
78 
79 		/* Check that we got the sigusr1 that we expected. */
80 		if (!gotusr1)
81 			errx(1, "didn't get usr1");
82 		if (gotusr2)
83 			errx(1, "got incorrect usr2");
84 
85 		sigemptyset(&set);
86 		sigaddset(&set, SIGUSR1);
87 		sigsuspend(&set);
88 
89 		if (!gotusr2)
90 			errx(1, "didn't get usr2");
91 
92 		_exit(0);
93 	case -1:
94 		err(1, "fork");
95 	default:
96 		/*
97 		 * In the parent.
98 		 * Waiting for the initial USR1 that tells us the child
99 		 * is ready.
100 		 */
101 		while (gotusr1 == 0)
102 			sigsuspend(&oset);
103 
104 		/*
105 		 * Check that sigsuspend didn't change the signal mask.
106 		 */
107 		if (sigprocmask(SIG_SETMASK, NULL, &oset))
108 			err(1, "sigprocmask");
109 		if (!sigismember(&oset, SIGUSR1) ||
110 		    !sigismember(&oset, SIGUSR2))
111 			errx(1, "sigprocmask is bad");
112 
113 		/*
114 		 * Deliberately send USR2 first to confuse.
115 		 */
116 		kill(pid, SIGUSR2);
117 		kill(pid, SIGUSR1);
118 
119 		if (waitpid(pid, &status, 0) != pid)
120 			err(1, "waitpid");
121 
122 		if (WIFEXITED(status))
123 			exit(WEXITSTATUS(status));
124 		exit(1);
125 	}
126 	/* NOTREACHED */
127 }
128 
129 
130