1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_channel.h>
12
13
14 typedef struct {
15 int signo;
16 char *signame;
17 char *name;
18 void (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
19 } ngx_signal_t;
20
21
22
23 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
24 static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext);
25 static void ngx_process_get_status(void);
26 static void ngx_unlock_mutexes(ngx_pid_t pid);
27
28
29 int ngx_argc;
30 char **ngx_argv;
31 char **ngx_os_argv;
32
33 ngx_int_t ngx_process_slot;
34 ngx_socket_t ngx_channel;
35 ngx_int_t ngx_last_process;
36 ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
37
38
39 ngx_signal_t signals[] = {
40 { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
41 "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
42 "reload",
43 ngx_signal_handler },
44
45 { ngx_signal_value(NGX_REOPEN_SIGNAL),
46 "SIG" ngx_value(NGX_REOPEN_SIGNAL),
47 "reopen",
48 ngx_signal_handler },
49
50 { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
51 "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
52 "",
53 ngx_signal_handler },
54
55 { ngx_signal_value(NGX_TERMINATE_SIGNAL),
56 "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
57 "stop",
58 ngx_signal_handler },
59
60 { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
61 "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
62 "quit",
63 ngx_signal_handler },
64
65 { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
66 "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
67 "",
68 ngx_signal_handler },
69
70 { SIGALRM, "SIGALRM", "", ngx_signal_handler },
71
72 { SIGINT, "SIGINT", "", ngx_signal_handler },
73
74 { SIGIO, "SIGIO", "", ngx_signal_handler },
75
76 { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
77
78 { SIGSYS, "SIGSYS, SIG_IGN", "", NULL },
79
80 { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },
81
82 { 0, NULL, "", NULL }
83 };
84
85
86 ngx_pid_t
ngx_spawn_process(ngx_cycle_t * cycle,ngx_spawn_proc_pt proc,void * data,char * name,ngx_int_t respawn)87 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
88 char *name, ngx_int_t respawn)
89 {
90 u_long on;
91 ngx_pid_t pid;
92 ngx_int_t s;
93
94 if (respawn >= 0) {
95 s = respawn;
96
97 } else {
98 for (s = 0; s < ngx_last_process; s++) {
99 if (ngx_processes[s].pid == -1) {
100 break;
101 }
102 }
103
104 if (s == NGX_MAX_PROCESSES) {
105 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
106 "no more than %d processes can be spawned",
107 NGX_MAX_PROCESSES);
108 return NGX_INVALID_PID;
109 }
110 }
111
112
113 if (respawn != NGX_PROCESS_DETACHED) {
114
115 /* Solaris 9 still has no AF_LOCAL */
116
117 if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
118 {
119 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
120 "socketpair() failed while spawning \"%s\"", name);
121 return NGX_INVALID_PID;
122 }
123
124 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
125 "channel %d:%d",
126 ngx_processes[s].channel[0],
127 ngx_processes[s].channel[1]);
128
129 if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
130 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
131 ngx_nonblocking_n " failed while spawning \"%s\"",
132 name);
133 ngx_close_channel(ngx_processes[s].channel, cycle->log);
134 return NGX_INVALID_PID;
135 }
136
137 if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
138 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
139 ngx_nonblocking_n " failed while spawning \"%s\"",
140 name);
141 ngx_close_channel(ngx_processes[s].channel, cycle->log);
142 return NGX_INVALID_PID;
143 }
144
145 on = 1;
146 if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
147 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
148 "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
149 ngx_close_channel(ngx_processes[s].channel, cycle->log);
150 return NGX_INVALID_PID;
151 }
152
153 if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
154 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
155 "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
156 ngx_close_channel(ngx_processes[s].channel, cycle->log);
157 return NGX_INVALID_PID;
158 }
159
160 if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
161 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
162 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
163 name);
164 ngx_close_channel(ngx_processes[s].channel, cycle->log);
165 return NGX_INVALID_PID;
166 }
167
168 if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
169 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
170 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
171 name);
172 ngx_close_channel(ngx_processes[s].channel, cycle->log);
173 return NGX_INVALID_PID;
174 }
175
176 ngx_channel = ngx_processes[s].channel[1];
177
178 } else {
179 ngx_processes[s].channel[0] = -1;
180 ngx_processes[s].channel[1] = -1;
181 }
182
183 ngx_process_slot = s;
184
185
186 pid = fork();
187
188 switch (pid) {
189
190 case -1:
191 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
192 "fork() failed while spawning \"%s\"", name);
193 ngx_close_channel(ngx_processes[s].channel, cycle->log);
194 return NGX_INVALID_PID;
195
196 case 0:
197 ngx_parent = ngx_pid;
198 ngx_pid = ngx_getpid();
199 proc(cycle, data);
200 break;
201
202 default:
203 break;
204 }
205
206 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
207
208 ngx_processes[s].pid = pid;
209 ngx_processes[s].exited = 0;
210
211 if (respawn >= 0) {
212 return pid;
213 }
214
215 ngx_processes[s].proc = proc;
216 ngx_processes[s].data = data;
217 ngx_processes[s].name = name;
218 ngx_processes[s].exiting = 0;
219
220 switch (respawn) {
221
222 case NGX_PROCESS_NORESPAWN:
223 ngx_processes[s].respawn = 0;
224 ngx_processes[s].just_spawn = 0;
225 ngx_processes[s].detached = 0;
226 break;
227
228 case NGX_PROCESS_JUST_SPAWN:
229 ngx_processes[s].respawn = 0;
230 ngx_processes[s].just_spawn = 1;
231 ngx_processes[s].detached = 0;
232 break;
233
234 case NGX_PROCESS_RESPAWN:
235 ngx_processes[s].respawn = 1;
236 ngx_processes[s].just_spawn = 0;
237 ngx_processes[s].detached = 0;
238 break;
239
240 case NGX_PROCESS_JUST_RESPAWN:
241 ngx_processes[s].respawn = 1;
242 ngx_processes[s].just_spawn = 1;
243 ngx_processes[s].detached = 0;
244 break;
245
246 case NGX_PROCESS_DETACHED:
247 ngx_processes[s].respawn = 0;
248 ngx_processes[s].just_spawn = 0;
249 ngx_processes[s].detached = 1;
250 break;
251 }
252
253 if (s == ngx_last_process) {
254 ngx_last_process++;
255 }
256
257 return pid;
258 }
259
260
261 ngx_pid_t
ngx_execute(ngx_cycle_t * cycle,ngx_exec_ctx_t * ctx)262 ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
263 {
264 return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
265 NGX_PROCESS_DETACHED);
266 }
267
268
269 static void
ngx_execute_proc(ngx_cycle_t * cycle,void * data)270 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
271 {
272 ngx_exec_ctx_t *ctx = data;
273
274 if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
275 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
276 "execve() failed while executing %s \"%s\"",
277 ctx->name, ctx->path);
278 }
279
280 exit(1);
281 }
282
283
284 ngx_int_t
ngx_init_signals(ngx_log_t * log)285 ngx_init_signals(ngx_log_t *log)
286 {
287 ngx_signal_t *sig;
288 struct sigaction sa;
289
290 for (sig = signals; sig->signo != 0; sig++) {
291 ngx_memzero(&sa, sizeof(struct sigaction));
292
293 if (sig->handler) {
294 sa.sa_sigaction = sig->handler;
295 sa.sa_flags = SA_SIGINFO;
296
297 } else {
298 sa.sa_handler = SIG_IGN;
299 }
300
301 sigemptyset(&sa.sa_mask);
302 if (sigaction(sig->signo, &sa, NULL) == -1) {
303 #if (NGX_VALGRIND)
304 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
305 "sigaction(%s) failed, ignored", sig->signame);
306 #else
307 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
308 "sigaction(%s) failed", sig->signame);
309 return NGX_ERROR;
310 #endif
311 }
312 }
313
314 return NGX_OK;
315 }
316
317
318 static void
ngx_signal_handler(int signo,siginfo_t * siginfo,void * ucontext)319 ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
320 {
321 char *action;
322 ngx_int_t ignore;
323 ngx_err_t err;
324 ngx_signal_t *sig;
325
326 ignore = 0;
327
328 err = ngx_errno;
329
330 for (sig = signals; sig->signo != 0; sig++) {
331 if (sig->signo == signo) {
332 break;
333 }
334 }
335
336 ngx_time_sigsafe_update();
337
338 action = "";
339
340 switch (ngx_process) {
341
342 case NGX_PROCESS_MASTER:
343 case NGX_PROCESS_SINGLE:
344 switch (signo) {
345
346 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
347 ngx_quit = 1;
348 action = ", shutting down";
349 break;
350
351 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
352 case SIGINT:
353 ngx_terminate = 1;
354 action = ", exiting";
355 break;
356
357 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
358 if (ngx_daemonized) {
359 ngx_noaccept = 1;
360 action = ", stop accepting connections";
361 }
362 break;
363
364 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
365 ngx_reconfigure = 1;
366 action = ", reconfiguring";
367 break;
368
369 case ngx_signal_value(NGX_REOPEN_SIGNAL):
370 ngx_reopen = 1;
371 action = ", reopening logs";
372 break;
373
374 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
375 if (ngx_getppid() == ngx_parent || ngx_new_binary > 0) {
376
377 /*
378 * Ignore the signal in the new binary if its parent is
379 * not changed, i.e. the old binary's process is still
380 * running. Or ignore the signal in the old binary's
381 * process if the new binary's process is already running.
382 */
383
384 action = ", ignoring";
385 ignore = 1;
386 break;
387 }
388
389 ngx_change_binary = 1;
390 action = ", changing binary";
391 break;
392
393 case SIGALRM:
394 ngx_sigalrm = 1;
395 break;
396
397 case SIGIO:
398 ngx_sigio = 1;
399 break;
400
401 case SIGCHLD:
402 ngx_reap = 1;
403 break;
404 }
405
406 break;
407
408 case NGX_PROCESS_WORKER:
409 case NGX_PROCESS_HELPER:
410 switch (signo) {
411
412 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
413 if (!ngx_daemonized) {
414 break;
415 }
416 ngx_debug_quit = 1;
417 /* fall through */
418 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
419 ngx_quit = 1;
420 action = ", shutting down";
421 break;
422
423 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
424 case SIGINT:
425 ngx_terminate = 1;
426 action = ", exiting";
427 break;
428
429 case ngx_signal_value(NGX_REOPEN_SIGNAL):
430 ngx_reopen = 1;
431 action = ", reopening logs";
432 break;
433
434 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
435 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
436 case SIGIO:
437 action = ", ignoring";
438 break;
439 }
440
441 break;
442 }
443
444 if (siginfo && siginfo->si_pid) {
445 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
446 "signal %d (%s) received from %P%s",
447 signo, sig->signame, siginfo->si_pid, action);
448
449 } else {
450 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
451 "signal %d (%s) received%s",
452 signo, sig->signame, action);
453 }
454
455 if (ignore) {
456 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
457 "the changing binary signal is ignored: "
458 "you should shutdown or terminate "
459 "before either old or new binary's process");
460 }
461
462 if (signo == SIGCHLD) {
463 ngx_process_get_status();
464 }
465
466 ngx_set_errno(err);
467 }
468
469
470 static void
ngx_process_get_status(void)471 ngx_process_get_status(void)
472 {
473 int status;
474 char *process;
475 ngx_pid_t pid;
476 ngx_err_t err;
477 ngx_int_t i;
478 ngx_uint_t one;
479
480 one = 0;
481
482 for ( ;; ) {
483 pid = waitpid(-1, &status, WNOHANG);
484
485 if (pid == 0) {
486 return;
487 }
488
489 if (pid == -1) {
490 err = ngx_errno;
491
492 if (err == NGX_EINTR) {
493 continue;
494 }
495
496 if (err == NGX_ECHILD && one) {
497 return;
498 }
499
500 /*
501 * Solaris always calls the signal handler for each exited process
502 * despite waitpid() may be already called for this process.
503 *
504 * When several processes exit at the same time FreeBSD may
505 * erroneously call the signal handler for exited process
506 * despite waitpid() may be already called for this process.
507 */
508
509 if (err == NGX_ECHILD) {
510 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
511 "waitpid() failed");
512 return;
513 }
514
515 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
516 "waitpid() failed");
517 return;
518 }
519
520
521 one = 1;
522 process = "unknown process";
523
524 for (i = 0; i < ngx_last_process; i++) {
525 if (ngx_processes[i].pid == pid) {
526 ngx_processes[i].status = status;
527 ngx_processes[i].exited = 1;
528 process = ngx_processes[i].name;
529 break;
530 }
531 }
532
533 if (WTERMSIG(status)) {
534 #ifdef WCOREDUMP
535 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
536 "%s %P exited on signal %d%s",
537 process, pid, WTERMSIG(status),
538 WCOREDUMP(status) ? " (core dumped)" : "");
539 #else
540 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
541 "%s %P exited on signal %d",
542 process, pid, WTERMSIG(status));
543 #endif
544
545 } else {
546 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
547 "%s %P exited with code %d",
548 process, pid, WEXITSTATUS(status));
549 }
550
551 if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
552 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
553 "%s %P exited with fatal code %d "
554 "and cannot be respawned",
555 process, pid, WEXITSTATUS(status));
556 ngx_processes[i].respawn = 0;
557 }
558
559 ngx_unlock_mutexes(pid);
560 }
561 }
562
563
564 static void
ngx_unlock_mutexes(ngx_pid_t pid)565 ngx_unlock_mutexes(ngx_pid_t pid)
566 {
567 ngx_uint_t i;
568 ngx_shm_zone_t *shm_zone;
569 ngx_list_part_t *part;
570 ngx_slab_pool_t *sp;
571
572 /*
573 * unlock the accept mutex if the abnormally exited process
574 * held it
575 */
576
577 if (ngx_accept_mutex_ptr) {
578 (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
579 }
580
581 /*
582 * unlock shared memory mutexes if held by the abnormally exited
583 * process
584 */
585
586 part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
587 shm_zone = part->elts;
588
589 for (i = 0; /* void */ ; i++) {
590
591 if (i >= part->nelts) {
592 if (part->next == NULL) {
593 break;
594 }
595 part = part->next;
596 shm_zone = part->elts;
597 i = 0;
598 }
599
600 sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
601
602 if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
603 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
604 "shared memory zone \"%V\" was locked by %P",
605 &shm_zone[i].shm.name, pid);
606 }
607 }
608 }
609
610
611 void
ngx_debug_point(void)612 ngx_debug_point(void)
613 {
614 ngx_core_conf_t *ccf;
615
616 ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
617 ngx_core_module);
618
619 switch (ccf->debug_points) {
620
621 case NGX_DEBUG_POINTS_STOP:
622 raise(SIGSTOP);
623 break;
624
625 case NGX_DEBUG_POINTS_ABORT:
626 ngx_abort();
627 }
628 }
629
630
631 ngx_int_t
ngx_os_signal_process(ngx_cycle_t * cycle,char * name,ngx_pid_t pid)632 ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid)
633 {
634 ngx_signal_t *sig;
635
636 for (sig = signals; sig->signo != 0; sig++) {
637 if (ngx_strcmp(name, sig->name) == 0) {
638 if (kill(pid, sig->signo) != -1) {
639 return 0;
640 }
641
642 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
643 "kill(%P, %d) failed", pid, sig->signo);
644 }
645 }
646
647 return 1;
648 }
649