implement "-s signal" option for Unix
Igor Sysoev
13 years ago
187 | 187 | static ngx_uint_t ngx_show_configure; |
188 | 188 | static u_char *ngx_conf_file; |
189 | 189 | static u_char *ngx_conf_params; |
190 | #if (NGX_WIN32) | |
191 | 190 | static char *ngx_signal; |
192 | #endif | |
193 | 191 | |
194 | 192 | |
195 | 193 | static char **ngx_os_environ; |
212 | 210 | |
213 | 211 | if (ngx_show_help) { |
214 | 212 | ngx_log_stderr( |
215 | "Usage: nginx [-?hvVt]" | |
216 | #if (NGX_WIN32) | |
217 | " [-s signal]" | |
218 | #endif | |
219 | " [-c filename] [-g directives]" CRLF CRLF | |
213 | "Usage: nginx [-?hvVt] [-s signal] [-c filename] " | |
214 | "[-g directives]" CRLF CRLF | |
220 | 215 | "Options:" CRLF |
221 | 216 | " -?,-h : this help" CRLF |
222 | 217 | " -v : show version and exit" CRLF |
223 | 218 | " -V : show version and configure options then exit" |
224 | 219 | CRLF |
225 | 220 | " -t : test configuration and exit" CRLF |
226 | #if (NGX_WIN32) | |
227 | " -s signal : send signal to a master process" CRLF | |
228 | #endif | |
221 | " -s signal : send signal to a master process: " | |
222 | "stop, quit, reopen, reload" CRLF | |
229 | 223 | " -c filename : set configuration file (default: " |
230 | 224 | NGX_CONF_PATH ")" CRLF |
231 | 225 | " -g directives : set global directives out of configuration " |
336 | 330 | ngx_process = NGX_PROCESS_MASTER; |
337 | 331 | } |
338 | 332 | |
339 | #if (NGX_WIN32) | |
340 | ||
341 | 333 | if (ngx_signal) { |
342 | 334 | return ngx_signal_process(cycle, ngx_signal); |
343 | 335 | } |
344 | 336 | |
345 | #else | |
337 | #if !(NGX_WIN32) | |
346 | 338 | |
347 | 339 | if (ngx_init_signals(cycle->log) != NGX_OK) { |
348 | 340 | return 1; |
684 | 676 | ngx_log_stderr("the option \"-g\" requires parameter"); |
685 | 677 | return NGX_ERROR; |
686 | 678 | |
687 | #if (NGX_WIN32) | |
688 | 679 | case 's': |
689 | 680 | if (*p) { |
690 | 681 | ngx_signal = (char *) p; |
708 | 699 | |
709 | 700 | ngx_log_stderr("invalid option: \"-s %s\"", ngx_signal); |
710 | 701 | return NGX_ERROR; |
711 | #endif | |
712 | 702 | |
713 | 703 | default: |
714 | 704 | ngx_log_stderr("invalid option: \"%c\"", *(p - 1)); |
568 | 568 | } |
569 | 569 | } |
570 | 570 | |
571 | if (ngx_open_listening_sockets(cycle) != NGX_OK) { | |
572 | goto failed; | |
573 | } | |
574 | ||
575 | if (!ngx_test_config) { | |
576 | ngx_configure_listening_socket(cycle); | |
571 | if (ngx_process != NGX_PROCESS_SIGNALLER) { | |
572 | if (ngx_open_listening_sockets(cycle) != NGX_OK) { | |
573 | goto failed; | |
574 | } | |
575 | ||
576 | if (!ngx_test_config) { | |
577 | ngx_configure_listening_socket(cycle); | |
578 | } | |
577 | 579 | } |
578 | 580 | |
579 | 581 | |
982 | 984 | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, |
983 | 985 | ngx_delete_file_n " \"%s\" failed", name); |
984 | 986 | } |
987 | } | |
988 | ||
989 | ||
990 | ngx_int_t | |
991 | ngx_signal_process(ngx_cycle_t *cycle, char *sig) | |
992 | { | |
993 | ssize_t n; | |
994 | ngx_int_t pid; | |
995 | ngx_file_t file; | |
996 | ngx_core_conf_t *ccf; | |
997 | u_char buf[NGX_INT64_LEN + 2]; | |
998 | ||
999 | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started"); | |
1000 | ||
1001 | ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | |
1002 | ||
1003 | file.name = ccf->pid; | |
1004 | file.log = cycle->log; | |
1005 | ||
1006 | file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, | |
1007 | NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); | |
1008 | ||
1009 | if (file.fd == NGX_INVALID_FILE) { | |
1010 | ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, | |
1011 | ngx_open_file_n " \"%s\" failed", file.name.data); | |
1012 | return 1; | |
1013 | } | |
1014 | ||
1015 | n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0); | |
1016 | ||
1017 | if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
1018 | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
1019 | ngx_close_file_n " \"%s\" failed", file.name.data); | |
1020 | } | |
1021 | ||
1022 | if (n == NGX_ERROR) { | |
1023 | return 1; | |
1024 | } | |
1025 | ||
1026 | while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ } | |
1027 | ||
1028 | pid = ngx_atoi(buf, ++n); | |
1029 | ||
1030 | if (pid == NGX_ERROR) { | |
1031 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, | |
1032 | "invalid PID number \"%*s\" in \"%s\"", | |
1033 | n, buf, file.name.data); | |
1034 | return 1; | |
1035 | } | |
1036 | ||
1037 | return ngx_os_signal_process(cycle, sig, pid); | |
1038 | ||
985 | 1039 | } |
986 | 1040 | |
987 | 1041 |
115 | 115 | ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle); |
116 | 116 | ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log); |
117 | 117 | void ngx_delete_pidfile(ngx_cycle_t *cycle); |
118 | ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig); | |
118 | 119 | void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user); |
119 | 120 | char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last); |
120 | 121 | ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv); |
36 | 36 | ngx_int_t ngx_os_specific_init(ngx_log_t *log); |
37 | 37 | void ngx_os_specific_status(ngx_log_t *log); |
38 | 38 | ngx_int_t ngx_daemon(ngx_log_t *log); |
39 | ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid); | |
39 | 40 | |
40 | 41 | |
41 | 42 | ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); |
12 | 12 | typedef struct { |
13 | 13 | int signo; |
14 | 14 | char *signame; |
15 | char *name; | |
15 | 16 | void (*handler)(int signo); |
16 | 17 | } ngx_signal_t; |
17 | 18 | |
35 | 36 | ngx_signal_t signals[] = { |
36 | 37 | { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), |
37 | 38 | "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), |
39 | "reload", | |
38 | 40 | ngx_signal_handler }, |
39 | 41 | |
40 | 42 | { ngx_signal_value(NGX_REOPEN_SIGNAL), |
41 | 43 | "SIG" ngx_value(NGX_REOPEN_SIGNAL), |
44 | "reopen", | |
42 | 45 | ngx_signal_handler }, |
43 | 46 | |
44 | 47 | { ngx_signal_value(NGX_NOACCEPT_SIGNAL), |
45 | 48 | "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), |
49 | "", | |
46 | 50 | ngx_signal_handler }, |
47 | 51 | |
48 | 52 | { ngx_signal_value(NGX_TERMINATE_SIGNAL), |
49 | 53 | "SIG" ngx_value(NGX_TERMINATE_SIGNAL), |
54 | "stop", | |
50 | 55 | ngx_signal_handler }, |
51 | 56 | |
52 | 57 | { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), |
53 | 58 | "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), |
59 | "quit", | |
54 | 60 | ngx_signal_handler }, |
55 | 61 | |
56 | 62 | { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), |
57 | 63 | "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), |
64 | "", | |
58 | 65 | ngx_signal_handler }, |
59 | 66 | |
60 | { SIGALRM, "SIGALRM", ngx_signal_handler }, | |
61 | ||
62 | { SIGINT, "SIGINT", ngx_signal_handler }, | |
63 | ||
64 | { SIGIO, "SIGIO", ngx_signal_handler }, | |
65 | ||
66 | { SIGCHLD, "SIGCHLD", ngx_signal_handler }, | |
67 | ||
68 | { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN }, | |
69 | ||
70 | { 0, NULL, NULL } | |
67 | { SIGALRM, "SIGALRM", "", ngx_signal_handler }, | |
68 | ||
69 | { SIGINT, "SIGINT", "", ngx_signal_handler }, | |
70 | ||
71 | { SIGIO, "SIGIO", "", ngx_signal_handler }, | |
72 | ||
73 | { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, | |
74 | ||
75 | { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN }, | |
76 | ||
77 | { 0, NULL, "", NULL } | |
71 | 78 | }; |
72 | 79 | |
73 | 80 | |
539 | 546 | ngx_abort(); |
540 | 547 | } |
541 | 548 | } |
549 | ||
550 | ||
551 | ngx_int_t | |
552 | ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid) | |
553 | { | |
554 | ngx_signal_t *sig; | |
555 | ||
556 | for (sig = signals; sig->signo != 0; sig++) { | |
557 | if (ngx_strcmp(name, sig->name) == 0) { | |
558 | if (kill(pid, sig->signo) != -1) { | |
559 | return 0; | |
560 | } | |
561 | ||
562 | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
563 | "kill(%P, %d) failed", pid, sig->signo); | |
564 | } | |
565 | } | |
566 | ||
567 | return 1; | |
568 | } |
18 | 18 | #define NGX_CMD_REOPEN 5 |
19 | 19 | |
20 | 20 | |
21 | #define NGX_PROCESS_SINGLE 0 | |
22 | #define NGX_PROCESS_MASTER 1 | |
23 | #define NGX_PROCESS_WORKER 2 | |
21 | #define NGX_PROCESS_SINGLE 0 | |
22 | #define NGX_PROCESS_MASTER 1 | |
23 | #define NGX_PROCESS_WORKER 2 | |
24 | #define NGX_PROCESS_SIGNALLER 3 | |
24 | 25 | |
25 | 26 | |
26 | 27 | void ngx_master_process_cycle(ngx_cycle_t *cycle); |
9 | 9 | |
10 | 10 | #include <ngx_config.h> |
11 | 11 | #include <ngx_core.h> |
12 | ||
12 | 13 | |
13 | 14 | #define NGX_IO_SENDFILE 1 |
14 | 15 | |
31 | 32 | |
32 | 33 | ngx_int_t ngx_os_init(ngx_log_t *log); |
33 | 34 | void ngx_os_status(ngx_log_t *log); |
35 | ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid); | |
34 | 36 | |
35 | 37 | ssize_t ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); |
36 | 38 | ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); |
1005 | 1005 | |
1006 | 1006 | |
1007 | 1007 | ngx_int_t |
1008 | ngx_signal_process(ngx_cycle_t *cycle, char *sig) | |
1009 | { | |
1010 | size_t n; | |
1011 | HANDLE ev; | |
1012 | ngx_int_t rc, pid; | |
1013 | ngx_file_t file; | |
1014 | ngx_core_conf_t *ccf; | |
1015 | u_char buf[NGX_INT64_LEN + 2]; | |
1016 | char evn[NGX_PROCESS_SYNC_NAME]; | |
1017 | ||
1018 | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started"); | |
1019 | ||
1020 | ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | |
1021 | ||
1022 | file.name = ccf->pid; | |
1023 | file.log = cycle->log; | |
1024 | ||
1025 | file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, | |
1026 | NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); | |
1027 | ||
1028 | if (file.fd == NGX_INVALID_FILE) { | |
1029 | ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, | |
1030 | ngx_open_file_n " \"%s\" failed", file.name.data); | |
1031 | return 1; | |
1032 | } | |
1033 | ||
1034 | rc = 1; | |
1035 | ||
1036 | n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0); | |
1037 | ||
1038 | if (n == NGX_ERROR) { | |
1039 | goto failed; | |
1040 | } | |
1041 | ||
1042 | while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ } | |
1043 | ||
1044 | pid = ngx_atoi(buf, ++n); | |
1045 | ||
1046 | if (pid == NGX_ERROR) { | |
1047 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, | |
1048 | "invalid PID number \"%*s\" in \"%s\"", | |
1049 | n, buf, file.name.data); | |
1050 | goto failed; | |
1051 | } | |
1008 | ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid) | |
1009 | { | |
1010 | HANDLE ev; | |
1011 | ngx_int_t rc; | |
1012 | char evn[NGX_PROCESS_SYNC_NAME]; | |
1052 | 1013 | |
1053 | 1014 | ngx_sprintf((u_char *) evn, "ngx_%s_%ul%Z", sig, pid); |
1054 | 1015 | |
1056 | 1017 | if (ev == NULL) { |
1057 | 1018 | ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, |
1058 | 1019 | "OpenEvent(\"%s\") failed", evn); |
1059 | goto failed; | |
1020 | return 1; | |
1060 | 1021 | } |
1061 | 1022 | |
1062 | 1023 | if (SetEvent(ev) == 0) { |
1063 | 1024 | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, |
1064 | 1025 | "SetEvent(\"%s\") failed", evn); |
1026 | rc = 1; | |
1027 | ||
1065 | 1028 | } else { |
1066 | 1029 | rc = 0; |
1067 | 1030 | } |
1068 | 1031 | |
1069 | 1032 | ngx_close_handle(ev); |
1070 | ||
1071 | failed: | |
1072 | ||
1073 | if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
1074 | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
1075 | ngx_close_file_n " \"%s\" failed", file.name.data); | |
1076 | } | |
1077 | 1033 | |
1078 | 1034 | return rc; |
1079 | 1035 | } |