1 /* $Id: fpm_signals.c,v 1.24 2008/08/26 15:09:15 anight Exp $ */
2 /* (c) 2007,2008 Andrei Nigmatulin */
3
4 #include "fpm_config.h"
5
6 #include <signal.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "fpm.h"
17 #include "fpm_signals.h"
18 #include "fpm_sockets.h"
19 #include "fpm_php.h"
20 #include "zlog.h"
21
22 static int sp[2];
23
24 const char *fpm_signal_names[NSIG + 1] = {
25 #ifdef SIGHUP
26 [SIGHUP] = "SIGHUP",
27 #endif
28 #ifdef SIGINT
29 [SIGINT] = "SIGINT",
30 #endif
31 #ifdef SIGQUIT
32 [SIGQUIT] = "SIGQUIT",
33 #endif
34 #ifdef SIGILL
35 [SIGILL] = "SIGILL",
36 #endif
37 #ifdef SIGTRAP
38 [SIGTRAP] = "SIGTRAP",
39 #endif
40 #ifdef SIGABRT
41 [SIGABRT] = "SIGABRT",
42 #endif
43 #ifdef SIGEMT
44 [SIGEMT] = "SIGEMT",
45 #endif
46 #ifdef SIGBUS
47 [SIGBUS] = "SIGBUS",
48 #endif
49 #ifdef SIGFPE
50 [SIGFPE] = "SIGFPE",
51 #endif
52 #ifdef SIGKILL
53 [SIGKILL] = "SIGKILL",
54 #endif
55 #ifdef SIGUSR1
56 [SIGUSR1] = "SIGUSR1",
57 #endif
58 #ifdef SIGSEGV
59 [SIGSEGV] = "SIGSEGV",
60 #endif
61 #ifdef SIGUSR2
62 [SIGUSR2] = "SIGUSR2",
63 #endif
64 #ifdef SIGPIPE
65 [SIGPIPE] = "SIGPIPE",
66 #endif
67 #ifdef SIGALRM
68 [SIGALRM] = "SIGALRM",
69 #endif
70 #ifdef SIGTERM
71 [SIGTERM] = "SIGTERM",
72 #endif
73 #ifdef SIGCHLD
74 [SIGCHLD] = "SIGCHLD",
75 #endif
76 #ifdef SIGCONT
77 [SIGCONT] = "SIGCONT",
78 #endif
79 #ifdef SIGSTOP
80 [SIGSTOP] = "SIGSTOP",
81 #endif
82 #ifdef SIGTSTP
83 [SIGTSTP] = "SIGTSTP",
84 #endif
85 #ifdef SIGTTIN
86 [SIGTTIN] = "SIGTTIN",
87 #endif
88 #ifdef SIGTTOU
89 [SIGTTOU] = "SIGTTOU",
90 #endif
91 #ifdef SIGURG
92 [SIGURG] = "SIGURG",
93 #endif
94 #ifdef SIGXCPU
95 [SIGXCPU] = "SIGXCPU",
96 #endif
97 #ifdef SIGXFSZ
98 [SIGXFSZ] = "SIGXFSZ",
99 #endif
100 #ifdef SIGVTALRM
101 [SIGVTALRM] = "SIGVTALRM",
102 #endif
103 #ifdef SIGPROF
104 [SIGPROF] = "SIGPROF",
105 #endif
106 #ifdef SIGWINCH
107 [SIGWINCH] = "SIGWINCH",
108 #endif
109 #ifdef SIGINFO
110 [SIGINFO] = "SIGINFO",
111 #endif
112 #ifdef SIGIO
113 [SIGIO] = "SIGIO",
114 #endif
115 #ifdef SIGPWR
116 [SIGPWR] = "SIGPWR",
117 #endif
118 #ifdef SIGSYS
119 [SIGSYS] = "SIGSYS",
120 #endif
121 #ifdef SIGWAITING
122 [SIGWAITING] = "SIGWAITING",
123 #endif
124 #ifdef SIGLWP
125 [SIGLWP] = "SIGLWP",
126 #endif
127 #ifdef SIGFREEZE
128 [SIGFREEZE] = "SIGFREEZE",
129 #endif
130 #ifdef SIGTHAW
131 [SIGTHAW] = "SIGTHAW",
132 #endif
133 #ifdef SIGCANCEL
134 [SIGCANCEL] = "SIGCANCEL",
135 #endif
136 #ifdef SIGLOST
137 [SIGLOST] = "SIGLOST",
138 #endif
139 };
140
sig_soft_quit(int signo)141 static void sig_soft_quit(int signo) /* {{{ */
142 {
143 int saved_errno = errno;
144
145 /* closing fastcgi listening socket will force fcgi_accept() exit immediately */
146 close(fpm_globals.listening_socket);
147 if (0 > socket(AF_UNIX, SOCK_STREAM, 0)) {
148 zlog(ZLOG_WARNING, "failed to create a new socket");
149 }
150 fpm_php_soft_quit();
151 errno = saved_errno;
152 }
153 /* }}} */
154
sig_handler(int signo)155 static void sig_handler(int signo) /* {{{ */
156 {
157 static const char sig_chars[NSIG + 1] = {
158 [SIGTERM] = 'T',
159 [SIGINT] = 'I',
160 [SIGUSR1] = '1',
161 [SIGUSR2] = '2',
162 [SIGQUIT] = 'Q',
163 [SIGCHLD] = 'C'
164 };
165 char s;
166 int saved_errno;
167
168 if (fpm_globals.parent_pid != getpid()) {
169 /* prevent a signal race condition when child process
170 have not set up it's own signal handler yet */
171 return;
172 }
173
174 saved_errno = errno;
175 s = sig_chars[signo];
176 zend_quiet_write(sp[1], &s, sizeof(s));
177 errno = saved_errno;
178 }
179 /* }}} */
180
fpm_signals_init_main()181 int fpm_signals_init_main() /* {{{ */
182 {
183 struct sigaction act;
184
185 if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) {
186 zlog(ZLOG_SYSERROR, "failed to init signals: socketpair()");
187 return -1;
188 }
189
190 if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) {
191 zlog(ZLOG_SYSERROR, "failed to init signals: fd_set_blocked()");
192 return -1;
193 }
194
195 if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) {
196 zlog(ZLOG_SYSERROR, "falied to init signals: fcntl(F_SETFD, FD_CLOEXEC)");
197 return -1;
198 }
199
200 memset(&act, 0, sizeof(act));
201 act.sa_handler = sig_handler;
202 sigfillset(&act.sa_mask);
203
204 if (0 > sigaction(SIGTERM, &act, 0) ||
205 0 > sigaction(SIGINT, &act, 0) ||
206 0 > sigaction(SIGUSR1, &act, 0) ||
207 0 > sigaction(SIGUSR2, &act, 0) ||
208 0 > sigaction(SIGCHLD, &act, 0) ||
209 0 > sigaction(SIGQUIT, &act, 0)) {
210
211 zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()");
212 return -1;
213 }
214 return 0;
215 }
216 /* }}} */
217
fpm_signals_init_child()218 int fpm_signals_init_child() /* {{{ */
219 {
220 struct sigaction act, act_dfl;
221
222 memset(&act, 0, sizeof(act));
223 memset(&act_dfl, 0, sizeof(act_dfl));
224
225 act.sa_handler = &sig_soft_quit;
226 act.sa_flags |= SA_RESTART;
227
228 act_dfl.sa_handler = SIG_DFL;
229
230 close(sp[0]);
231 close(sp[1]);
232
233 if (0 > sigaction(SIGTERM, &act_dfl, 0) ||
234 0 > sigaction(SIGINT, &act_dfl, 0) ||
235 0 > sigaction(SIGUSR1, &act_dfl, 0) ||
236 0 > sigaction(SIGUSR2, &act_dfl, 0) ||
237 0 > sigaction(SIGCHLD, &act_dfl, 0) ||
238 0 > sigaction(SIGQUIT, &act, 0)) {
239
240 zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()");
241 return -1;
242 }
243
244 zend_signal_init();
245 return 0;
246 }
247 /* }}} */
248
fpm_signals_get_fd()249 int fpm_signals_get_fd() /* {{{ */
250 {
251 return sp[0];
252 }
253 /* }}} */
254