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