1 /*
2
3 *** uWSGI ***
4
5 Copyright (C) 2009-2017 Unbit S.a.s. <info@unbit.it>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 */
22
23
24 #include "uwsgi.h"
25
26 struct uwsgi_server uwsgi;
27 pid_t masterpid;
28
29 #if defined(__APPLE__) && defined(UWSGI_AS_SHARED_LIBRARY)
30 #include <crt_externs.h>
31 #define UWSGI_ENVIRON (*_NSGetEnviron())
32 #else
33 extern char **environ;
34 #define UWSGI_ENVIRON environ
35 #endif
36
37 UWSGI_DECLARE_EMBEDDED_PLUGINS;
38
39 static struct uwsgi_option uwsgi_base_options[] = {
40 {"socket", required_argument, 's', "bind to the specified UNIX/TCP socket using default protocol", uwsgi_opt_add_socket, NULL, 0},
41 {"uwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol", uwsgi_opt_add_socket, "uwsgi", 0},
42 #ifdef UWSGI_SSL
43 {"suwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
44 {"ssl-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
45 #endif
46
47 {"http-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP protocol", uwsgi_opt_add_socket, "http", 0},
48 {"http-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier1, 0},
49 {"http-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier2, 0},
50
51 {"http11-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP 1.1 (Keep-Alive) protocol", uwsgi_opt_add_socket, "http11", 0},
52
53 #ifdef UWSGI_SSL
54 {"https-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTPS protocol", uwsgi_opt_add_ssl_socket, "https", 0},
55 {"https-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier1, 0},
56 {"https-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier2, 0},
57 #endif
58
59 {"fastcgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol", uwsgi_opt_add_socket, "fastcgi", 0},
60 {"fastcgi-nph-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol (nph mode)", uwsgi_opt_add_socket, "fastcgi-nph", 0},
61 {"fastcgi-modifier1", required_argument, 0, "force the specified modifier1 when using FastCGI protocol", uwsgi_opt_set_64bit, &uwsgi.fastcgi_modifier1, 0},
62 {"fastcgi-modifier2", required_argument, 0, "force the specified modifier2 when using FastCGI protocol", uwsgi_opt_set_64bit, &uwsgi.fastcgi_modifier2, 0},
63
64 {"scgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using SCGI protocol", uwsgi_opt_add_socket, "scgi", 0},
65 {"scgi-nph-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using SCGI protocol (nph mode)", uwsgi_opt_add_socket, "scgi-nph", 0},
66 {"scgi-modifier1", required_argument, 0, "force the specified modifier1 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier1, 0},
67 {"scgi-modifier2", required_argument, 0, "force the specified modifier2 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier2, 0},
68
69 {"raw-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using RAW protocol", uwsgi_opt_add_socket_no_defer, "raw", 0},
70 {"raw-modifier1", required_argument, 0, "force the specified modifier1 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier1, 0},
71 {"raw-modifier2", required_argument, 0, "force the specified modifier2 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier2, 0},
72
73 {"puwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using persistent uwsgi protocol (puwsgi)", uwsgi_opt_add_socket, "puwsgi", 0},
74
75 {"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
76 {"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
77 {"shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
78 {"undeferred-shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
79 {"processes", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
80 {"workers", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
81 {"thunder-lock", no_argument, 0, "serialize accept() usage (if possible)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0},
82 {"harakiri", required_argument, 't', "set harakiri timeout", uwsgi_opt_set_int, &uwsgi.harakiri_options.workers, 0},
83 {"harakiri-verbose", no_argument, 0, "enable verbose mode for harakiri", uwsgi_opt_true, &uwsgi.harakiri_verbose, 0},
84 {"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
85 {"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
86 {"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
87 {"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
88 {"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.mules, 0},
89 #ifdef UWSGI_XML
90 {"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
91 {"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
92 #endif
93 {"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE},
94 {"fallback-config", required_argument, 0, "re-exec uwsgi with the specified config when exit code is 1", uwsgi_opt_set_str, &uwsgi.fallback_config, UWSGI_OPT_IMMEDIATE},
95 {"strict", no_argument, 0, "enable strict mode (placeholder cannot be used)", uwsgi_opt_true, &uwsgi.strict, UWSGI_OPT_IMMEDIATE},
96
97 {"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0},
98 {"skip-atexit", no_argument, 0, "skip atexit hooks (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit, 0},
99 {"skip-atexit-teardown", no_argument, 0, "skip atexit teardown (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit_teardown, 0},
100
101 {"set", required_argument, 'S', "set a placeholder or an option", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE},
102 {"set-placeholder", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE},
103 {"set-ph", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE},
104 {"get", required_argument, 0, "print the specified option value and exit", uwsgi_opt_add_string_list, &uwsgi.get_list, UWSGI_OPT_NO_INITIAL},
105 {"declare-option", required_argument, 0, "declare a new uWSGI custom option", uwsgi_opt_add_custom_option, NULL, UWSGI_OPT_IMMEDIATE},
106 {"declare-option2", required_argument, 0, "declare a new uWSGI custom option (non-immediate)", uwsgi_opt_add_custom_option, NULL, 0},
107
108 {"resolve", required_argument, 0, "place the result of a dns query in the specified placeholder, sytax: placeholder=name (immediate option)", uwsgi_opt_resolve, NULL, UWSGI_OPT_IMMEDIATE},
109
110 {"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
111 {"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
112 {"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
113 {"for-readline", required_argument, 0, "(opt logic) for cycle (expand the specified file to a list of lines)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_readline, UWSGI_OPT_IMMEDIATE},
114 {"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
115 {"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
116
117 {"if-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_opt, UWSGI_OPT_IMMEDIATE},
118 {"if-not-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_opt, UWSGI_OPT_IMMEDIATE},
119
120 {"if-env", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_env, UWSGI_OPT_IMMEDIATE},
121 {"if-not-env", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_env, UWSGI_OPT_IMMEDIATE},
122 {"ifenv", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_env, UWSGI_OPT_IMMEDIATE},
123
124 {"if-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_reload, UWSGI_OPT_IMMEDIATE},
125 {"if-not-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_reload, UWSGI_OPT_IMMEDIATE},
126
127 {"if-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname, UWSGI_OPT_IMMEDIATE},
128 {"if-not-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname, UWSGI_OPT_IMMEDIATE},
129
130 #ifdef UWSGI_PCRE
131 {"if-hostname-match", required_argument, 0, "(opt logic) try to match hostname against a regular expression", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname_match, UWSGI_OPT_IMMEDIATE},
132 {"if-not-hostname-match", required_argument, 0, "(opt logic) try to match hostname against a regular expression", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname_match, UWSGI_OPT_IMMEDIATE},
133 #endif
134
135 {"if-exists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
136 {"if-not-exists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_exists, UWSGI_OPT_IMMEDIATE},
137 {"ifexists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
138
139 {"if-plugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_plugin, UWSGI_OPT_IMMEDIATE},
140 {"if-not-plugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_plugin, UWSGI_OPT_IMMEDIATE},
141 {"ifplugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_plugin, UWSGI_OPT_IMMEDIATE},
142
143 {"if-file", required_argument, 0, "(opt logic) check for file existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_file, UWSGI_OPT_IMMEDIATE},
144 {"if-not-file", required_argument, 0, "(opt logic) check for file existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_file, UWSGI_OPT_IMMEDIATE},
145 {"if-dir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE},
146 {"if-not-dir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_dir, UWSGI_OPT_IMMEDIATE},
147
148 {"ifdir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE},
149 {"if-directory", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE},
150
151 {"endif", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
152 {"end-if", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
153
154 {"blacklist", required_argument, 0, "set options blacklist context", uwsgi_opt_set_str, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
155 {"end-blacklist", no_argument, 0, "clear options blacklist context", uwsgi_opt_set_null, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE},
156
157 {"whitelist", required_argument, 0, "set options whitelist context", uwsgi_opt_set_str, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE},
158 {"end-whitelist", no_argument, 0, "clear options whitelist context", uwsgi_opt_set_null, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE},
159
160 {"ignore-sigpipe", no_argument, 0, "do not report (annoying) SIGPIPE", uwsgi_opt_true, &uwsgi.ignore_sigpipe, 0},
161 {"ignore-write-errors", no_argument, 0, "do not report (annoying) write()/writev() errors", uwsgi_opt_true, &uwsgi.ignore_write_errors, 0},
162 {"write-errors-tolerance", required_argument, 0, "set the maximum number of allowed write errors (default: no tolerance)", uwsgi_opt_set_64bit, &uwsgi.write_errors_tolerance, 0},
163 {"write-errors-exception-only", no_argument, 0, "only raise an exception on write errors giving control to the app itself", uwsgi_opt_true, &uwsgi.write_errors_exception_only, 0},
164 {"disable-write-exception", no_argument, 0, "disable exception generation on write()/writev()", uwsgi_opt_true, &uwsgi.disable_write_exception, 0},
165
166 {"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL, 0},
167 {"include", required_argument, 0, "include the specified file as immediate configuration", uwsgi_opt_load, NULL, UWSGI_OPT_IMMEDIATE},
168 {"inject-before", required_argument, 0, "inject a text file before the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_before, UWSGI_OPT_IMMEDIATE},
169 {"inject-after", required_argument, 0, "inject a text file after the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_after, UWSGI_OPT_IMMEDIATE},
170 {"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0},
171 {"daemonize2", required_argument, 0, "daemonize uWSGI after app loading", uwsgi_opt_set_str, &uwsgi.daemonize2, 0},
172 {"stop", required_argument, 0, "stop an instance", uwsgi_opt_pidfile_signal, (void *) SIGINT, UWSGI_OPT_IMMEDIATE},
173 {"reload", required_argument, 0, "reload an instance", uwsgi_opt_pidfile_signal, (void *) SIGHUP, UWSGI_OPT_IMMEDIATE},
174 {"pause", required_argument, 0, "pause an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE},
175 {"suspend", required_argument, 0, "suspend an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE},
176 {"resume", required_argument, 0, "resume an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE},
177
178 {"connect-and-read", required_argument, 0, "connect to a socket and wait for data from it", uwsgi_opt_connect_and_read, NULL, UWSGI_OPT_IMMEDIATE},
179 {"extract", required_argument, 0, "fetch/dump any supported address to stdout", uwsgi_opt_extract, NULL, UWSGI_OPT_IMMEDIATE},
180
181 {"listen", required_argument, 'l', "set the socket listen queue size", uwsgi_opt_set_int, &uwsgi.listen_queue, UWSGI_OPT_IMMEDIATE},
182 {"max-vars", required_argument, 'v', "set the amount of internal iovec/vars structures", uwsgi_opt_max_vars, NULL, 0},
183 {"max-apps", required_argument, 0, "set the maximum number of per-worker applications", uwsgi_opt_set_int, &uwsgi.max_apps, 0},
184 {"buffer-size", required_argument, 'b', "set internal buffer size", uwsgi_opt_set_16bit, &uwsgi.buffer_size, 0},
185 {"memory-report", no_argument, 'm', "enable memory report", uwsgi_opt_true, &uwsgi.logging_options.memory_report, 0},
186 {"profiler", required_argument, 0, "enable the specified profiler", uwsgi_opt_set_str, &uwsgi.profiler, 0},
187 {"cgi-mode", no_argument, 'c', "force CGI-mode for plugins supporting it", uwsgi_opt_true, &uwsgi.cgi_mode, 0},
188 {"abstract-socket", no_argument, 'a', "force UNIX socket in abstract mode (Linux only)", uwsgi_opt_true, &uwsgi.abstract_socket, 0},
189 {"chmod-socket", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0},
190 {"chmod", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0},
191 {"chown-socket", required_argument, 0, "chown unix sockets", uwsgi_opt_set_str, &uwsgi.chown_socket, 0},
192 {"umask", required_argument, 0, "set umask", uwsgi_opt_set_umask, NULL, UWSGI_OPT_IMMEDIATE},
193 #ifdef __linux__
194 {"freebind", no_argument, 0, "put socket in freebind mode", uwsgi_opt_true, &uwsgi.freebind, 0},
195 #endif
196 {"map-socket", required_argument, 0, "map sockets to specific workers", uwsgi_opt_add_string_list, &uwsgi.map_socket, 0},
197 {"enable-threads", no_argument, 'T', "enable threads", uwsgi_opt_true, &uwsgi.has_threads, 0},
198 {"no-threads-wait", no_argument, 0, "do not wait for threads cancellation on quit/reload", uwsgi_opt_true, &uwsgi.no_threads_wait, 0},
199
200 {"auto-procname", no_argument, 0, "automatically set processes name to something meaningful", uwsgi_opt_true, &uwsgi.auto_procname, 0},
201 {"procname-prefix", required_argument, 0, "add a prefix to the process names", uwsgi_opt_set_str, &uwsgi.procname_prefix, UWSGI_OPT_PROCNAME},
202 {"procname-prefix-spaced", required_argument, 0, "add a spaced prefix to the process names", uwsgi_opt_set_str_spaced, &uwsgi.procname_prefix, UWSGI_OPT_PROCNAME},
203 {"procname-append", required_argument, 0, "append a string to process names", uwsgi_opt_set_str, &uwsgi.procname_append, UWSGI_OPT_PROCNAME},
204 {"procname", required_argument, 0, "set process names", uwsgi_opt_set_str, &uwsgi.procname, UWSGI_OPT_PROCNAME},
205 {"procname-master", required_argument, 0, "set master process name", uwsgi_opt_set_str, &uwsgi.procname_master, UWSGI_OPT_PROCNAME},
206
207 {"single-interpreter", no_argument, 'i', "do not use multiple interpreters (where available)", uwsgi_opt_true, &uwsgi.single_interpreter, 0},
208 {"need-app", no_argument, 0, "exit if no app can be loaded", uwsgi_opt_true, &uwsgi.need_app, 0},
209 {"master", no_argument, 'M', "enable master process", uwsgi_opt_true, &uwsgi.master_process, 0},
210 {"honour-stdin", no_argument, 0, "do not remap stdin to /dev/null", uwsgi_opt_true, &uwsgi.honour_stdin, 0},
211 {"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0},
212 {"emperor-proxy-socket", required_argument, 0, "force the vassal to became an Emperor proxy", uwsgi_opt_set_str, &uwsgi.emperor_proxy, 0},
213 {"emperor-wrapper", required_argument, 0, "set a binary wrapper for vassals", uwsgi_opt_set_str, &uwsgi.emperor_wrapper, 0},
214 {"emperor-wrapper-override", required_argument, 0, "set a binary wrapper for vassals to try before the default one", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_override, 0},
215 {"emperor-wrapper-fallback", required_argument, 0, "set a binary wrapper for vassals to try as a last resort", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_fallback, 0},
216 {"emperor-nofollow", no_argument, 0, "do not follow symlinks when checking for mtime", uwsgi_opt_true, &uwsgi.emperor_nofollow, 0},
217 {"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0},
218 {"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0},
219 {"emperor-required-heartbeat", required_argument, 0, "set the Emperor tolerance about heartbeats", uwsgi_opt_set_int, &uwsgi.emperor_heartbeat, 0},
220 {"emperor-curse-tolerance", required_argument, 0, "set the Emperor tolerance about cursed vassals", uwsgi_opt_set_int, &uwsgi.emperor_curse_tolerance, 0},
221 {"emperor-pidfile", required_argument, 0, "write the Emperor pid in the specified file", uwsgi_opt_set_str, &uwsgi.emperor_pidfile, 0},
222 {"emperor-tyrant", no_argument, 0, "put the Emperor in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant, 0},
223 {"emperor-tyrant-nofollow", no_argument, 0, "do not follow symlinks when checking for uid/gid in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant_nofollow, 0},
224 {"emperor-stats", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
225 {"emperor-stats-server", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0},
226 {"early-emperor", no_argument, 0, "spawn the emperor as soon as possibile", uwsgi_opt_true, &uwsgi.early_emperor, 0},
227 {"emperor-broodlord", required_argument, 0, "run the emperor in BroodLord mode", uwsgi_opt_set_int, &uwsgi.emperor_broodlord, 0},
228 {"emperor-throttle", required_argument, 0, "set throttling level (in milliseconds) for bad behaving vassals (default 1000)", uwsgi_opt_set_int, &uwsgi.emperor_throttle, 0},
229 {"emperor-max-throttle", required_argument, 0, "set max throttling level (in milliseconds) for bad behaving vassals (default 3 minutes)", uwsgi_opt_set_int, &uwsgi.emperor_max_throttle, 0},
230 {"emperor-magic-exec", no_argument, 0, "prefix vassals config files with exec:// if they have the executable bit", uwsgi_opt_true, &uwsgi.emperor_magic_exec, 0},
231 {"emperor-on-demand-extension", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
232 {"emperor-on-demand-ext", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0},
233 {"emperor-on-demand-directory", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
234 {"emperor-on-demand-dir", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0},
235 {"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
236 {"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
237 {"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
238 {"emperor-no-blacklist", no_argument, 0, "disable Emperor blacklisting subsystem", uwsgi_opt_true, &uwsgi.emperor_no_blacklist, 0},
239 #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
240 {"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
241 #endif
242 {"emperor-graceful-shutdown", no_argument, 0, "use vassals graceful shutdown during ragnarok", uwsgi_opt_true, &uwsgi.emperor_graceful_shutdown, 0},
243 #ifdef UWSGI_CAP
244 {"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
245 {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
246 {"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
247 #endif
248 {"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
249 {"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
250 {"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
251 {"vassals-include", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes, 0},
252 {"vassals-inherit-before", required_argument, 0, "add config templates to vassals config (uses --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates_before, 0},
253 {"vassals-include-before", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes_before, 0},
254 {"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0},
255 {"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0},
256 {"vassal-sos", required_argument, 0, "ask emperor for reinforcement when overloaded", uwsgi_opt_set_int, &uwsgi.vassal_sos, 0},
257 {"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0},
258 {"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
259 {"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
260
261 {"heartbeat", required_argument, 0, "announce healthiness to the emperor", uwsgi_opt_set_int, &uwsgi.heartbeat, 0},
262
263 {"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
264 {"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
265 {"mule-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a mule can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.mule_reload_mercy, 0},
266 {"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
267 {"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
268 {"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
269 {"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
270 {"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
271
272 {"print-sym", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
273 {"print-symbol", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
274
275 {"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_true, &uwsgi.reaper, 0},
276 {"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_64bit, &uwsgi.max_requests, 0},
277 {"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_64bit, &uwsgi.min_worker_lifetime, 0},
278 {"max-worker-lifetime", required_argument, 0, "reload workers after the specified amount of seconds (default is disabled)", uwsgi_opt_set_64bit, &uwsgi.max_worker_lifetime, 0},
279 {"max-worker-lifetime-delta", required_argument, 0, "add (worker_id * delta) seconds to the max_worker_lifetime value of each worker", uwsgi_opt_set_int, &uwsgi.max_worker_lifetime_delta, 0},
280
281 {"socket-timeout", required_argument, 'z', "set internal sockets timeout", uwsgi_opt_set_int, &uwsgi.socket_timeout, 0},
282 {"no-fd-passing", no_argument, 0, "disable file descriptor passing", uwsgi_opt_true, &uwsgi.no_fd_passing, 0},
283 {"locks", required_argument, 0, "create the specified number of shared locks", uwsgi_opt_set_int, &uwsgi.locks, 0},
284 {"lock-engine", required_argument, 0, "set the lock engine", uwsgi_opt_set_str, &uwsgi.lock_engine, 0},
285 {"ftok", required_argument, 0, "set the ipcsem key via ftok() for avoiding duplicates", uwsgi_opt_set_str, &uwsgi.ftok, 0},
286 {"persistent-ipcsem", no_argument, 0, "do not remove ipcsem's on shutdown", uwsgi_opt_true, &uwsgi.persistent_ipcsem, 0},
287 {"sharedarea", required_argument, 'A', "create a raw shared memory area of specified pages (note: it supports keyval too)", uwsgi_opt_add_string_list, &uwsgi.sharedareas_list, 0},
288
289 {"safe-fd", required_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0},
290 {"fd-safe", required_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0},
291
292 {"cache", required_argument, 0, "create a shared cache containing given elements", uwsgi_opt_set_64bit, &uwsgi.cache_max_items, 0},
293 {"cache-blocksize", required_argument, 0, "set cache blocksize", uwsgi_opt_set_64bit, &uwsgi.cache_blocksize, 0},
294 {"cache-store", required_argument, 0, "enable persistent cache to disk", uwsgi_opt_set_str, &uwsgi.cache_store, UWSGI_OPT_MASTER},
295 {"cache-store-sync", required_argument, 0, "set frequency of sync for persistent cache", uwsgi_opt_set_int, &uwsgi.cache_store_sync, 0},
296 {"cache-no-expire", no_argument, 0, "disable auto sweep of expired items", uwsgi_opt_true, &uwsgi.cache_no_expire, 0},
297 {"cache-expire-freq", required_argument, 0, "set the frequency of cache sweeper scans (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.cache_expire_freq, 0},
298 {"cache-report-freed-items", no_argument, 0, "constantly report the cache item freed by the sweeper (use only for debug)", uwsgi_opt_true, &uwsgi.cache_report_freed_items, 0},
299 {"cache-udp-server", required_argument, 0, "bind the cache udp server (used only for set/update/delete) to the specified socket", uwsgi_opt_add_string_list, &uwsgi.cache_udp_server, UWSGI_OPT_MASTER},
300 {"cache-udp-node", required_argument, 0, "send cache update/deletion to the specified cache udp server", uwsgi_opt_add_string_list, &uwsgi.cache_udp_node, UWSGI_OPT_MASTER},
301 {"cache-sync", required_argument, 0, "copy the whole content of another uWSGI cache server on server startup", uwsgi_opt_set_str, &uwsgi.cache_sync, 0},
302 {"cache-use-last-modified", no_argument, 0, "update last_modified_at timestamp on every cache item modification (default is disabled)", uwsgi_opt_true, &uwsgi.cache_use_last_modified, 0},
303
304 {"add-cache-item", required_argument, 0, "add an item in the cache", uwsgi_opt_add_string_list, &uwsgi.add_cache_item, 0},
305 {"load-file-in-cache", required_argument, 0, "load a static file in the cache", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache, 0},
306 #ifdef UWSGI_ZLIB
307 {"load-file-in-cache-gzip", required_argument, 0, "load a static file in the cache with gzip compression", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache_gzip, 0},
308 #endif
309
310 {"cache2", required_argument, 0, "create a new generation shared cache (keyval syntax)", uwsgi_opt_add_string_list, &uwsgi.cache2, 0},
311
312
313 {"queue", required_argument, 0, "enable shared queue", uwsgi_opt_set_int, &uwsgi.queue_size, 0},
314 {"queue-blocksize", required_argument, 0, "set queue blocksize", uwsgi_opt_set_int, &uwsgi.queue_blocksize, 0},
315 {"queue-store", required_argument, 0, "enable persistent queue to disk", uwsgi_opt_set_str, &uwsgi.queue_store, UWSGI_OPT_MASTER},
316 {"queue-store-sync", required_argument, 0, "set frequency of sync for persistent queue", uwsgi_opt_set_int, &uwsgi.queue_store_sync, 0},
317
318 {"spooler", required_argument, 'Q', "run a spooler on the specified directory", uwsgi_opt_add_spooler, NULL, UWSGI_OPT_MASTER},
319 {"spooler-external", required_argument, 0, "map spoolers requests to a spooler directory managed by an external instance", uwsgi_opt_add_spooler, (void *) UWSGI_SPOOLER_EXTERNAL, UWSGI_OPT_MASTER},
320 {"spooler-ordered", no_argument, 0, "try to order the execution of spooler tasks", uwsgi_opt_true, &uwsgi.spooler_ordered, 0},
321 {"spooler-chdir", required_argument, 0, "chdir() to specified directory before each spooler task", uwsgi_opt_set_str, &uwsgi.spooler_chdir, 0},
322 {"spooler-processes", required_argument, 0, "set the number of processes for spoolers", uwsgi_opt_set_int, &uwsgi.spooler_numproc, UWSGI_OPT_IMMEDIATE},
323 {"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0},
324 {"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0},
325 {"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.spoolers, 0},
326 {"spooler-frequency", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
327 {"spooler-freq", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
328
329 {"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER},
330 {"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER},
331 {"farm", required_argument, 0, "add a mule farm", uwsgi_opt_add_farm, NULL, UWSGI_OPT_MASTER},
332 {"mule-msg-size", optional_argument, 0, "set mule message buffer size", uwsgi_opt_set_int, &uwsgi.mule_msg_size, UWSGI_OPT_MASTER},
333
334 {"signal", required_argument, 0, "send a uwsgi signal to a server", uwsgi_opt_signal, NULL, UWSGI_OPT_IMMEDIATE},
335 {"signal-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
336 {"signals-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
337
338 {"signal-timer", required_argument, 0, "add a timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER},
339 {"timer", required_argument, 0, "add a timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER},
340
341 {"signal-rbtimer", required_argument, 0, "add a redblack timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER},
342 {"rbtimer", required_argument, 0, "add a redblack timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER},
343
344 {"rpc-max", required_argument, 0, "maximum number of rpc slots (default: 64)", uwsgi_opt_set_64bit, &uwsgi.rpc_max, 0},
345
346 {"disable-logging", no_argument, 'L', "disable request logging", uwsgi_opt_false, &uwsgi.logging_options.enabled, 0},
347
348 {"flock", required_argument, 0, "lock the specified file before starting, exit if locked", uwsgi_opt_flock, NULL, UWSGI_OPT_IMMEDIATE},
349 {"flock-wait", required_argument, 0, "lock the specified file before starting, wait if locked", uwsgi_opt_flock_wait, NULL, UWSGI_OPT_IMMEDIATE},
350
351 {"flock2", required_argument, 0, "lock the specified file after logging/daemon setup, exit if locked", uwsgi_opt_set_str, &uwsgi.flock2, UWSGI_OPT_IMMEDIATE},
352 {"flock-wait2", required_argument, 0, "lock the specified file after logging/daemon setup, wait if locked", uwsgi_opt_set_str, &uwsgi.flock_wait2, UWSGI_OPT_IMMEDIATE},
353
354 {"pidfile", required_argument, 0, "create pidfile (before privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile, 0},
355 {"pidfile2", required_argument, 0, "create pidfile (after privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile2, 0},
356 {"safe-pidfile", required_argument, 0, "create safe pidfile (before privileges drop)", uwsgi_opt_set_str, &uwsgi.safe_pidfile, 0},
357 {"safe-pidfile2", required_argument, 0, "create safe pidfile (after privileges drop)", uwsgi_opt_set_str, &uwsgi.safe_pidfile2, 0},
358 {"chroot", required_argument, 0, "chroot() to the specified directory", uwsgi_opt_set_str, &uwsgi.chroot, 0},
359 #ifdef __linux__
360 {"pivot-root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0},
361 {"pivot_root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0},
362 #endif
363
364 {"uid", required_argument, 0, "setuid to the specified user/uid", uwsgi_opt_set_uid, NULL, 0},
365 {"gid", required_argument, 0, "setgid to the specified group/gid", uwsgi_opt_set_gid, NULL, 0},
366 {"add-gid", required_argument, 0, "add the specified group id to the process credentials", uwsgi_opt_add_string_list, &uwsgi.additional_gids, 0},
367 {"immediate-uid", required_argument, 0, "setuid to the specified user/uid IMMEDIATELY", uwsgi_opt_set_immediate_uid, NULL, UWSGI_OPT_IMMEDIATE},
368 {"immediate-gid", required_argument, 0, "setgid to the specified group/gid IMMEDIATELY", uwsgi_opt_set_immediate_gid, NULL, UWSGI_OPT_IMMEDIATE},
369 {"no-initgroups", no_argument, 0, "disable additional groups set via initgroups()", uwsgi_opt_true, &uwsgi.no_initgroups, 0},
370 #ifdef UWSGI_CAP
371 {"cap", required_argument, 0, "set process capability", uwsgi_opt_set_cap, NULL, 0},
372 #endif
373 #ifdef __linux__
374 {"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, &uwsgi.unshare, 0},
375 {"unshare2", required_argument, 0, "unshare() part of the processes and put it in a new namespace after rootfs change", uwsgi_opt_set_unshare, &uwsgi.unshare2, 0},
376 {"setns-socket", required_argument, 0, "expose a unix socket returning namespace fds from /proc/self/ns", uwsgi_opt_set_str, &uwsgi.setns_socket, UWSGI_OPT_MASTER},
377 {"setns-socket-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0},
378 {"setns-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0},
379 {"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0},
380 {"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0},
381 #endif
382 {"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0},
383 #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
384 {"jail", required_argument, 0, "put the instance in a FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail, 0},
385 {"jail-ip4", required_argument, 0, "add an ipv4 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip4, 0},
386 {"jail-ip6", required_argument, 0, "add an ipv6 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip6, 0},
387 {"jidfile", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0},
388 {"jid-file", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0},
389 #ifdef UWSGI_HAS_FREEBSD_LIBJAIL
390 {"jail2", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0},
391 {"libjail", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0},
392 {"jail-attach", required_argument, 0, "attach to the FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail_attach, 0},
393 #endif
394 #endif
395 {"refork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0},
396 {"re-fork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0},
397 {"refork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0},
398 {"re-fork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0},
399 {"refork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0},
400 {"re-fork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0},
401
402 {"hook-asap", required_argument, 0, "run the specified hook as soon as possible", uwsgi_opt_add_string_list, &uwsgi.hook_asap, 0},
403 {"hook-pre-jail", required_argument, 0, "run the specified hook before jailing", uwsgi_opt_add_string_list, &uwsgi.hook_pre_jail, 0},
404 {"hook-post-jail", required_argument, 0, "run the specified hook after jailing", uwsgi_opt_add_string_list, &uwsgi.hook_post_jail, 0},
405 {"hook-in-jail", required_argument, 0, "run the specified hook in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.hook_in_jail, 0},
406 {"hook-as-root", required_argument, 0, "run the specified hook before privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_root, 0},
407 {"hook-as-user", required_argument, 0, "run the specified hook after privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_user, 0},
408 {"hook-as-user-atexit", required_argument, 0, "run the specified hook before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.hook_as_user_atexit, 0},
409 {"hook-pre-app", required_argument, 0, "run the specified hook before app loading", uwsgi_opt_add_string_list, &uwsgi.hook_pre_app, 0},
410 {"hook-post-app", required_argument, 0, "run the specified hook after app loading", uwsgi_opt_add_string_list, &uwsgi.hook_post_app, 0},
411 {"hook-post-fork", required_argument, 0, "run the specified hook after each fork", uwsgi_opt_add_string_list, &uwsgi.hook_post_fork, 0},
412 {"hook-accepting", required_argument, 0, "run the specified hook after each worker enter the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting, 0},
413 {"hook-accepting1", required_argument, 0, "run the specified hook after the first worker enters the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1, 0},
414 {"hook-accepting-once", required_argument, 0, "run the specified hook after each worker enter the accepting phase (once per-instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting_once, 0},
415 {"hook-accepting1-once", required_argument, 0, "run the specified hook after the first worker enters the accepting phase (once per instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1_once, 0},
416
417 {"hook-master-start", required_argument, 0, "run the specified hook when the Master starts", uwsgi_opt_add_string_list, &uwsgi.hook_master_start, 0},
418
419 {"hook-touch", required_argument, 0, "run the specified hook when the specified file is touched (syntax: <file> <action>)", uwsgi_opt_add_string_list, &uwsgi.hook_touch, 0},
420
421 {"hook-emperor-start", required_argument, 0, "run the specified hook when the Emperor starts", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_start, 0},
422 {"hook-emperor-stop", required_argument, 0, "run the specified hook when the Emperor send a stop message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_stop, 0},
423 {"hook-emperor-reload", required_argument, 0, "run the specified hook when the Emperor send a reload message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_reload, 0},
424 {"hook-emperor-lost", required_argument, 0, "run the specified hook when the Emperor connection is lost", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_lost, 0},
425
426 {"hook-as-vassal", required_argument, 0, "run the specified hook before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0},
427 {"hook-as-emperor", required_argument, 0, "run the specified hook in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0},
428
429 {"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0},
430
431 {"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0},
432
433 {"after-request-hook", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
434 {"after-request-call", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
435
436 {"exec-asap", required_argument, 0, "run the specified command as soon as possible", uwsgi_opt_add_string_list, &uwsgi.exec_asap, 0},
437 {"exec-pre-jail", required_argument, 0, "run the specified command before jailing", uwsgi_opt_add_string_list, &uwsgi.exec_pre_jail, 0},
438 {"exec-post-jail", required_argument, 0, "run the specified command after jailing", uwsgi_opt_add_string_list, &uwsgi.exec_post_jail, 0},
439 {"exec-in-jail", required_argument, 0, "run the specified command in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.exec_in_jail, 0},
440 {"exec-as-root", required_argument, 0, "run the specified command before privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_root, 0},
441 {"exec-as-user", required_argument, 0, "run the specified command after privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_user, 0},
442 {"exec-as-user-atexit", required_argument, 0, "run the specified command before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.exec_as_user_atexit, 0},
443 {"exec-pre-app", required_argument, 0, "run the specified command before app loading", uwsgi_opt_add_string_list, &uwsgi.exec_pre_app, 0},
444 {"exec-post-app", required_argument, 0, "run the specified command after app loading", uwsgi_opt_add_string_list, &uwsgi.exec_post_app, 0},
445
446 {"exec-as-vassal", required_argument, 0, "run the specified command before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.exec_as_vassal, 0},
447 {"exec-as-emperor", required_argument, 0, "run the specified command in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.exec_as_emperor, 0},
448
449 {"mount-asap", required_argument, 0, "mount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.mount_asap, 0},
450 {"mount-pre-jail", required_argument, 0, "mount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.mount_pre_jail, 0},
451 {"mount-post-jail", required_argument, 0, "mount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.mount_post_jail, 0},
452 {"mount-in-jail", required_argument, 0, "mount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.mount_in_jail, 0},
453 {"mount-as-root", required_argument, 0, "mount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.mount_as_root, 0},
454
455 {"mount-as-vassal", required_argument, 0, "mount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.mount_as_vassal, 0},
456 {"mount-as-emperor", required_argument, 0, "mount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.mount_as_emperor, 0},
457
458 {"umount-asap", required_argument, 0, "unmount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.umount_asap, 0},
459 {"umount-pre-jail", required_argument, 0, "unmount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.umount_pre_jail, 0},
460 {"umount-post-jail", required_argument, 0, "unmount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.umount_post_jail, 0},
461 {"umount-in-jail", required_argument, 0, "unmount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.umount_in_jail, 0},
462 {"umount-as-root", required_argument, 0, "unmount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.umount_as_root, 0},
463
464 {"umount-as-vassal", required_argument, 0, "unmount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.umount_as_vassal, 0},
465 {"umount-as-emperor", required_argument, 0, "unmount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.umount_as_emperor, 0},
466
467 {"wait-for-interface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
468 {"wait-for-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
469
470 {"wait-interface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
471 {"wait-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
472
473 {"wait-for-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
474 {"wait-for-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
475
476 {"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
477 {"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
478
479 {"wait-for-fs", required_argument, 0, "wait for the specified filesystem item to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
480 {"wait-for-file", required_argument, 0, "wait for the specified file to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
481 {"wait-for-dir", required_argument, 0, "wait for the specified directory to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
482 {"wait-for-mountpoint", required_argument, 0, "wait for the specified mountpoint to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_mountpoint, 0},
483 {"wait-for-fs-timeout", required_argument, 0, "set the timeout for wait-for-fs/file/dir", uwsgi_opt_set_int, &uwsgi.wait_for_fs_timeout, 0},
484
485 {"wait-for-socket", required_argument, 0, "wait for the specified socket to be ready before loading apps", uwsgi_opt_add_string_list, &uwsgi.wait_for_socket, 0},
486 {"wait-for-socket-timeout", required_argument, 0, "set the timeout for wait-for-socket", uwsgi_opt_set_int, &uwsgi.wait_for_socket_timeout, 0},
487
488 {"call-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0},
489 {"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
490 {"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
491 {"call-in-jail", required_argument, 0, "call the specified function in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.call_in_jail, 0},
492 {"call-as-root", required_argument, 0, "call the specified function before privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_root, 0},
493 {"call-as-user", required_argument, 0, "call the specified function after privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_user, 0},
494 {"call-as-user-atexit", required_argument, 0, "call the specified function before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.call_as_user_atexit, 0},
495 {"call-pre-app", required_argument, 0, "call the specified function before app loading", uwsgi_opt_add_string_list, &uwsgi.call_pre_app, 0},
496 {"call-post-app", required_argument, 0, "call the specified function after app loading", uwsgi_opt_add_string_list, &uwsgi.call_post_app, 0},
497
498 {"call-as-vassal", required_argument, 0, "call the specified function() before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal, 0},
499 {"call-as-vassal1", required_argument, 0, "call the specified function(char *) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal1, 0},
500 {"call-as-vassal3", required_argument, 0, "call the specified function(char *, uid_t, gid_t) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal3, 0},
501
502 {"call-as-emperor", required_argument, 0, "call the specified function() in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor, 0},
503 {"call-as-emperor1", required_argument, 0, "call the specified function(char *) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor1, 0},
504 {"call-as-emperor2", required_argument, 0, "call the specified function(char *, pid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor2, 0},
505 {"call-as-emperor4", required_argument, 0, "call the specified function(char *, pid_t, uid_t, gid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor4, 0},
506
507
508
509 {"ini", required_argument, 0, "load config from ini file", uwsgi_opt_load_ini, NULL, UWSGI_OPT_IMMEDIATE},
510 #ifdef UWSGI_YAML
511 {"yaml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
512 {"yml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
513 #endif
514 #ifdef UWSGI_JSON
515 {"json", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE},
516 {"js", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE},
517 #endif
518 {"weight", required_argument, 0, "weight of the instance (used by clustering/lb/subscriptions)", uwsgi_opt_set_64bit, &uwsgi.weight, 0},
519 {"auto-weight", required_argument, 0, "set weight of the instance (used by clustering/lb/subscriptions) automatically", uwsgi_opt_true, &uwsgi.auto_weight, 0},
520 {"no-server", no_argument, 0, "force no-server mode", uwsgi_opt_true, &uwsgi.no_server, 0},
521 {"command-mode", no_argument, 0, "force command mode", uwsgi_opt_true, &uwsgi.command_mode, UWSGI_OPT_IMMEDIATE},
522 {"no-defer-accept", no_argument, 0, "disable deferred-accept on sockets", uwsgi_opt_true, &uwsgi.no_defer_accept, 0},
523 {"tcp-nodelay", no_argument, 0, "enable TCP NODELAY on each request", uwsgi_opt_true, &uwsgi.tcp_nodelay, 0},
524 {"so-keepalive", no_argument, 0, "enable TCP KEEPALIVEs", uwsgi_opt_true, &uwsgi.so_keepalive, 0},
525 {"so-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
526 {"socket-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
527 {"so-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
528 {"socket-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
529 {"socket-sndbuf", required_argument, 0, "set SO_SNDBUF", uwsgi_opt_set_64bit, &uwsgi.so_sndbuf, 0},
530 {"socket-rcvbuf", required_argument, 0, "set SO_RCVBUF", uwsgi_opt_set_64bit, &uwsgi.so_rcvbuf, 0},
531 {"shutdown-sockets", no_argument, 0, "force calling shutdown() in addition to close() when sockets are destroyed", uwsgi_opt_true, &uwsgi.shutdown_sockets, 0},
532 {"limit-as", required_argument, 0, "limit processes address space/vsz", uwsgi_opt_set_megabytes, &uwsgi.rl.rlim_max, 0},
533 {"limit-nproc", required_argument, 0, "limit the number of spawnable processes", uwsgi_opt_set_int, &uwsgi.rl_nproc.rlim_max, 0},
534 {"reload-on-as", required_argument, 0, "reload if address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_as, UWSGI_OPT_MEMORY},
535 {"reload-on-rss", required_argument, 0, "reload if rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_rss, UWSGI_OPT_MEMORY},
536 {"evil-reload-on-as", required_argument, 0, "force the master to reload a worker if its address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_as, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
537 {"evil-reload-on-rss", required_argument, 0, "force the master to reload a worker if its rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_rss, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
538 {"mem-collector-freq", required_argument, 0, "set the memory collector frequency when evil reloads are in place", uwsgi_opt_set_int, &uwsgi.mem_collector_freq, 0},
539
540 {"reload-on-fd", required_argument, 0, "reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.reload_on_fd, UWSGI_OPT_MASTER},
541 {"brutal-reload-on-fd", required_argument, 0, "brutal reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.brutal_reload_on_fd, UWSGI_OPT_MASTER},
542
543 #ifdef __linux__
544 #ifdef MADV_MERGEABLE
545 {"ksm", optional_argument, 0, "enable Linux KSM", uwsgi_opt_set_int, &uwsgi.linux_ksm, 0},
546 #endif
547 #endif
548 #ifdef UWSGI_PCRE
549 {"pcre-jit", no_argument, 0, "enable pcre jit (if available)", uwsgi_opt_pcre_jit, NULL, UWSGI_OPT_IMMEDIATE},
550 #endif
551 {"never-swap", no_argument, 0, "lock all memory pages avoiding swapping", uwsgi_opt_true, &uwsgi.never_swap, 0},
552 {"touch-reload", required_argument, 0, "reload uWSGI if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_reload, UWSGI_OPT_MASTER},
553 {"touch-workers-reload", required_argument, 0, "trigger reload of (only) workers if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_workers_reload, UWSGI_OPT_MASTER},
554 {"touch-mules-reload", required_argument, 0, "reload mules if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_mules_reload, UWSGI_OPT_MASTER},
555 {"touch-spoolers-reload", required_argument, 0, "reload spoolers if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_spoolers_reload, UWSGI_OPT_MASTER},
556 {"touch-chain-reload", required_argument, 0, "trigger chain reload if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_chain_reload, UWSGI_OPT_MASTER},
557 {"touch-logrotate", required_argument, 0, "trigger logrotation if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logrotate, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
558 {"touch-logreopen", required_argument, 0, "trigger log reopen if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logreopen, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
559 {"touch-exec", required_argument, 0, "run command when the specified file is modified/touched (syntax: file command)", uwsgi_opt_add_string_list, &uwsgi.touch_exec, UWSGI_OPT_MASTER},
560 {"touch-signal", required_argument, 0, "signal when the specified file is modified/touched (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.touch_signal, UWSGI_OPT_MASTER},
561
562 {"fs-reload", required_argument, 0, "graceful reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_reload, UWSGI_OPT_MASTER},
563 {"fs-brutal-reload", required_argument, 0, "brutal reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_brutal_reload, UWSGI_OPT_MASTER},
564 {"fs-signal", required_argument, 0, "raise a uwsgi signal when the specified filesystem object is modified (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.fs_signal, UWSGI_OPT_MASTER},
565
566 {"check-mountpoint", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
567 {"mountpoint-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
568 {"check-mount", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
569 {"mount-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
570
571 {"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal management", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
572 {"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0},
573 {"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0},
574 {"prio", required_argument, 0, "set processes/threads priority", uwsgi_opt_set_rawint, &uwsgi.prio, 0},
575 {"cpu-affinity", required_argument, 0, "set cpu affinity", uwsgi_opt_set_int, &uwsgi.cpu_affinity, 0},
576 {"post-buffering", required_argument, 0, "set size in bytes after which will buffer to disk instead of memory", uwsgi_opt_set_64bit, &uwsgi.post_buffering, 0},
577 {"post-buffering-bufsize", required_argument, 0, "set buffer size for read() in post buffering mode", uwsgi_opt_set_64bit, &uwsgi.post_buffering_bufsize, 0},
578 {"body-read-warning", required_argument, 0, "set the amount of allowed memory allocation (in megabytes) for request body before starting printing a warning", uwsgi_opt_set_64bit, &uwsgi.body_read_warning, 0},
579 {"upload-progress", required_argument, 0, "enable creation of .json files in the specified directory during a file upload", uwsgi_opt_set_str, &uwsgi.upload_progress, 0},
580 {"no-default-app", no_argument, 0, "do not fallback to default app", uwsgi_opt_true, &uwsgi.no_default_app, 0},
581 {"manage-script-name", no_argument, 0, "automatically rewrite SCRIPT_NAME and PATH_INFO", uwsgi_opt_true, &uwsgi.manage_script_name, 0},
582 {"ignore-script-name", no_argument, 0, "ignore SCRIPT_NAME", uwsgi_opt_true, &uwsgi.ignore_script_name, 0},
583
584 {"catch-exceptions", no_argument, 0, "report exception as http output (discouraged, use only for testing)", uwsgi_opt_true, &uwsgi.catch_exceptions, 0},
585 {"reload-on-exception", no_argument, 0, "reload a worker when an exception is raised", uwsgi_opt_true, &uwsgi.reload_on_exception, 0},
586 {"reload-on-exception-type", required_argument, 0, "reload a worker when a specific exception type is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_type, 0},
587 {"reload-on-exception-value", required_argument, 0, "reload a worker when a specific exception value is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_value, 0},
588 {"reload-on-exception-repr", required_argument, 0, "reload a worker when a specific exception type+value (language-specific) is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_repr, 0},
589 {"exception-handler", required_argument, 0, "add an exception handler", uwsgi_opt_add_string_list, &uwsgi.exception_handlers_instance, UWSGI_OPT_MASTER},
590
591 {"enable-metrics", no_argument, 0, "enable metrics subsystem", uwsgi_opt_true, &uwsgi.has_metrics, UWSGI_OPT_MASTER},
592 {"metric", required_argument, 0, "add a custom metric", uwsgi_opt_add_string_list, &uwsgi.additional_metrics, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
593 {"metric-threshold", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
594 {"metric-alarm", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
595 {"alarm-metric", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
596 {"metrics-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
597 {"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
598 {"metric-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
599 {"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
600 {"metrics-no-cores", no_argument, 0, "disable generation of cores-related metrics", uwsgi_opt_true, &uwsgi.metrics_no_cores, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
601
602 {"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
603 {"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
604 {"stats-server", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
605 {"stats-http", no_argument, 0, "prefix stats server json output with http headers", uwsgi_opt_true, &uwsgi.stats_http, UWSGI_OPT_MASTER},
606 {"stats-minified", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
607 {"stats-min", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
608 {"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
609 {"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
610 {"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
611 {"stats-no-cores", no_argument, 0, "disable generation of cores-related stats", uwsgi_opt_true, &uwsgi.stats_no_cores, UWSGI_OPT_MASTER},
612 {"stats-no-metrics", no_argument, 0, "do not include metrics in stats output", uwsgi_opt_true, &uwsgi.stats_no_metrics, UWSGI_OPT_MASTER},
613 {"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
614 {"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
615 {"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0},
616
617 {"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER},
618
619 {"notify-socket", required_argument, 0, "enable the notification socket", uwsgi_opt_set_str, &uwsgi.notify_socket, UWSGI_OPT_MASTER},
620 {"subscription-notify-socket", required_argument, 0, "set the notification socket for subscriptions", uwsgi_opt_set_str, &uwsgi.subscription_notify_socket, UWSGI_OPT_MASTER},
621
622 #ifdef UWSGI_SSL
623 {"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
624 {"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER},
625 {"legion-node", required_argument, 0, "add a node to a legion", uwsgi_opt_legion_node, NULL, UWSGI_OPT_MASTER},
626 {"legion-freq", required_argument, 0, "set the frequency of legion packets", uwsgi_opt_set_int, &uwsgi.legion_freq, UWSGI_OPT_MASTER},
627 {"legion-tolerance", required_argument, 0, "set the tolerance of legion subsystem", uwsgi_opt_set_int, &uwsgi.legion_tolerance, UWSGI_OPT_MASTER},
628 {"legion-death-on-lord-error", required_argument, 0, "declare itself as a dead node for the specified amount of seconds if one of the lord hooks fails", uwsgi_opt_set_int, &uwsgi.legion_death_on_lord_error, UWSGI_OPT_MASTER},
629 {"legion-skew-tolerance", required_argument, 0, "set the clock skew tolerance of legion subsystem (default 30 seconds)", uwsgi_opt_set_int, &uwsgi.legion_skew_tolerance, UWSGI_OPT_MASTER},
630 {"legion-lord", required_argument, 0, "action to call on Lord election", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
631 {"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
632 {"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
633 {"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
634 {"legion-join", required_argument, 0, "action to call on legion join (first time quorum is reached)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
635 {"legion-node-joined", required_argument, 0, "action to call on new node joining legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
636 {"legion-node-left", required_argument, 0, "action to call node leaving legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
637 {"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER},
638 {"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER},
639 {"legion-scroll-max-size", required_argument, 0, "set max size of legion scroll buffer", uwsgi_opt_set_16bit, &uwsgi.legion_scroll_max_size, 0},
640 {"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0},
641 {"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
642 {"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
643 {"subscriptions-sign-skip-uid", required_argument, 0, "skip signature check for the specified uid when using unix sockets credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_sign_skip_uid, UWSGI_OPT_MASTER},
644 #endif
645 {"subscriptions-credentials-check", required_argument, 0, "add a directory to search for subscriptions key credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_credentials_check_dir, UWSGI_OPT_MASTER},
646 {"subscriptions-use-credentials", no_argument, 0, "enable management of SCM_CREDENTIALS in subscriptions UNIX sockets", uwsgi_opt_true, &uwsgi.subscriptions_use_credentials, 0},
647 {"subscription-algo", required_argument, 0, "set load balancing algorithm for the subscription system", uwsgi_opt_ssa, NULL, 0},
648 {"subscription-dotsplit", no_argument, 0, "try to fallback to the next part (dot based) in subscription key", uwsgi_opt_true, &uwsgi.subscription_dotsplit, 0},
649 {"subscribe-to", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
650 {"st", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
651 {"subscribe", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
652 {"subscribe2", required_argument, 0, "subscribe to the specified subscription server using advanced keyval syntax", uwsgi_opt_add_string_list, &uwsgi.subscriptions2, UWSGI_OPT_MASTER},
653 {"subscribe-freq", required_argument, 0, "send subscription announce at the specified interval", uwsgi_opt_set_int, &uwsgi.subscribe_freq, 0},
654 {"subscription-tolerance", required_argument, 0, "set tolerance for subscription servers", uwsgi_opt_set_int, &uwsgi.subscription_tolerance, 0},
655 {"unsubscribe-on-graceful-reload", no_argument, 0, "force unsubscribe request even during graceful reload", uwsgi_opt_true, &uwsgi.unsubscribe_on_graceful_reload, 0},
656 {"start-unsubscribed", no_argument, 0, "configure subscriptions but do not send them (useful with master fifo)", uwsgi_opt_true, &uwsgi.subscriptions_blocked, 0},
657
658 {"subscribe-with-modifier1", required_argument, 0, "force the specififed modifier1 when subscribing", uwsgi_opt_set_str, &uwsgi.subscribe_with_modifier1, UWSGI_OPT_MASTER},
659
660 {"snmp", optional_argument, 0, "enable the embedded snmp server", uwsgi_opt_snmp, NULL, 0},
661 {"snmp-community", required_argument, 0, "set the snmp community string", uwsgi_opt_snmp_community, NULL, 0},
662 #ifdef UWSGI_SSL
663 {"ssl-verbose", no_argument, 0, "be verbose about SSL errors", uwsgi_opt_true, &uwsgi.ssl_verbose, 0},
664 {"ssl-verify-depth", optional_argument, 0, "set maximum certificate verification depth", uwsgi_opt_set_int, &uwsgi.ssl_verify_depth, 0},
665 #ifdef UWSGI_SSL_SESSION_CACHE
666 // force master, as ssl sessions caching initialize locking early
667 {"ssl-sessions-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
668 {"ssl-session-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
669 {"ssl-sessions-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
670 {"ssl-session-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
671 #endif
672 {"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0},
673 {"sni-dir", required_argument, 0, "check for cert/key/client_ca file in the specified directory and create a sni/ssl context on demand", uwsgi_opt_set_str, &uwsgi.sni_dir, 0},
674 {"sni-dir-ciphers", required_argument, 0, "set ssl ciphers for sni-dir option", uwsgi_opt_set_str, &uwsgi.sni_dir_ciphers, 0},
675 {"ssl-enable3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0},
676 {"ssl-enable-sslv3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0},
677 {"ssl-enable-tlsv1", no_argument, 0, "enable TLSv1 (insecure)", uwsgi_opt_true, &uwsgi.tlsv1, 0},
678 {"ssl-option", no_argument, 0, "set a raw ssl option (numeric value)", uwsgi_opt_add_string_list, &uwsgi.ssl_options, 0},
679 #ifdef UWSGI_PCRE
680 {"sni-regexp", required_argument, 0, "add an SNI-governed SSL context (the key is a regexp)", uwsgi_opt_sni, NULL, 0},
681 #endif
682 {"ssl-tmp-dir", required_argument, 0, "store ssl-related temp files in the specified directory", uwsgi_opt_set_str, &uwsgi.ssl_tmp_dir, 0},
683 #endif
684 {"check-interval", required_argument, 0, "set the interval (in seconds) of master checks", uwsgi_opt_set_int, &uwsgi.master_interval, UWSGI_OPT_MASTER},
685 {"forkbomb-delay", required_argument, 0, "sleep for the specified number of seconds when a forkbomb is detected", uwsgi_opt_set_int, &uwsgi.forkbomb_delay, UWSGI_OPT_MASTER},
686 {"binary-path", required_argument, 0, "force binary path", uwsgi_opt_set_str, &uwsgi.binary_path, 0},
687 {"privileged-binary-patch", required_argument, 0, "patch the uwsgi binary with a new command (before privileges drop)", uwsgi_opt_set_str, &uwsgi.privileged_binary_patch, 0},
688 {"unprivileged-binary-patch", required_argument, 0, "patch the uwsgi binary with a new command (after privileges drop)", uwsgi_opt_set_str, &uwsgi.unprivileged_binary_patch, 0},
689 {"privileged-binary-patch-arg", required_argument, 0, "patch the uwsgi binary with a new command and arguments (before privileges drop)", uwsgi_opt_set_str, &uwsgi.privileged_binary_patch_arg, 0},
690 {"unprivileged-binary-patch-arg", required_argument, 0, "patch the uwsgi binary with a new command and arguments (after privileges drop)", uwsgi_opt_set_str, &uwsgi.unprivileged_binary_patch_arg, 0},
691 {"async", required_argument, 0, "enable async mode with specified cores", uwsgi_opt_set_int, &uwsgi.async, 0},
692 {"max-fd", required_argument, 0, "set maximum number of file descriptors (requires root privileges)", uwsgi_opt_set_int, &uwsgi.requested_max_fd, 0},
693 {"logto", required_argument, 0, "set logfile/udp address", uwsgi_opt_set_str, &uwsgi.logfile, 0},
694 {"logto2", required_argument, 0, "log to specified file or udp address after privileges drop", uwsgi_opt_set_str, &uwsgi.logto2, 0},
695 {"log-format", required_argument, 0, "set advanced format for request logging", uwsgi_opt_set_str, &uwsgi.logformat, 0},
696 {"logformat", required_argument, 0, "set advanced format for request logging", uwsgi_opt_set_str, &uwsgi.logformat, 0},
697 {"logformat-strftime", no_argument, 0, "apply strftime to logformat output", uwsgi_opt_true, &uwsgi.logformat_strftime, 0},
698 {"log-format-strftime", no_argument, 0, "apply strftime to logformat output", uwsgi_opt_true, &uwsgi.logformat_strftime, 0},
699 {"logfile-chown", no_argument, 0, "chown logfiles", uwsgi_opt_true, &uwsgi.logfile_chown, 0},
700 {"logfile-chmod", required_argument, 0, "chmod logfiles", uwsgi_opt_logfile_chmod, NULL, 0},
701 {"log-syslog", optional_argument, 0, "log to syslog", uwsgi_opt_set_logger, "syslog", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
702 {"log-socket", required_argument, 0, "send logs to the specified socket", uwsgi_opt_set_logger, "socket", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
703 {"req-logger", required_argument, 0, "set/append a request logger", uwsgi_opt_set_req_logger, NULL, UWSGI_OPT_REQ_LOG_MASTER},
704 {"logger-req", required_argument, 0, "set/append a request logger", uwsgi_opt_set_req_logger, NULL, UWSGI_OPT_REQ_LOG_MASTER},
705 {"logger", required_argument, 0, "set/append a logger", uwsgi_opt_set_logger, NULL, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
706 {"logger-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
707 {"loggers-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
708 {"threaded-logger", no_argument, 0, "offload log writing to a thread", uwsgi_opt_true, &uwsgi.threaded_logger, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
709
710
711 {"log-encoder", required_argument, 0, "add an item in the log encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
712 {"log-req-encoder", required_argument, 0, "add an item in the log req encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_req_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
713
714
715 #ifdef UWSGI_PCRE
716 {"log-drain", required_argument, 0, "drain (do not show) log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_drain_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
717 {"log-filter", required_argument, 0, "show only log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_filter_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
718 {"log-route", required_argument, 0, "log to the specified named logger if regexp applied on logline matches", uwsgi_opt_add_regexp_custom_list, &uwsgi.log_route, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
719 {"log-req-route", required_argument, 0, "log requests to the specified named logger if regexp applied on logline matches", uwsgi_opt_add_regexp_custom_list, &uwsgi.log_req_route, UWSGI_OPT_REQ_LOG_MASTER},
720 #endif
721
722 {"use-abort", no_argument, 0, "call abort() on segfault/fpe, could be useful for generating a core dump", uwsgi_opt_true, &uwsgi.use_abort, 0},
723
724 {"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
725 {"alarm-cheap", required_argument, 0, "use main alarm thread rather than create dedicated threads for curl-based alarms", uwsgi_opt_true, &uwsgi.alarm_cheap, 0},
726 {"alarm-freq", required_argument, 0, "tune the anti-loop alarm system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
727 {"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
728 {"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
729 {"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
730 {"alarm-backlog", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
731 {"backlog-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
732 {"lq-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
733 {"alarm-lq", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
734 {"alarm-listen-queue", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
735 {"listen-queue-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
736 #ifdef UWSGI_PCRE
737 {"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
738 {"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
739 {"not-log-alarm", required_argument, 0, "skip the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list_custom, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
740 {"not-alarm-log", required_argument, 0, "skip the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list_custom, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
741 #endif
742 {"alarm-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
743 {"alarms-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
744 {"alarm-msg-size", required_argument, 0, "set the max size of an alarm message (default 8192)", uwsgi_opt_set_64bit, &uwsgi.alarm_msg_size, 0},
745 {"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
746 {"log-master-bufsize", required_argument, 0, "set the buffer size for the master logger. bigger log messages will be truncated", uwsgi_opt_set_64bit, &uwsgi.log_master_bufsize, 0},
747 {"log-master-stream", no_argument, 0, "create the master logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_stream, 0},
748 {"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0},
749 {"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0},
750 {"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0},
751 {"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
752 {"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0},
753
754 {"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
755 {"log-date", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
756 {"log-prefix", optional_argument, 0, "prefix logs with a string", uwsgi_opt_log_date, NULL, 0},
757
758 {"log-zero", no_argument, 0, "log responses without body", uwsgi_opt_true, &uwsgi.logging_options.zero, 0},
759 {"log-slow", required_argument, 0, "log requests slower than the specified number of milliseconds", uwsgi_opt_set_int, &uwsgi.logging_options.slow, 0},
760 {"log-4xx", no_argument, 0, "log requests with a 4xx response", uwsgi_opt_true, &uwsgi.logging_options._4xx, 0},
761 {"log-5xx", no_argument, 0, "log requests with a 5xx response", uwsgi_opt_true, &uwsgi.logging_options._5xx, 0},
762 {"log-big", required_argument, 0, "log requestes bigger than the specified size", uwsgi_opt_set_64bit, &uwsgi.logging_options.big, 0},
763 {"log-sendfile", required_argument, 0, "log sendfile requests", uwsgi_opt_true, &uwsgi.logging_options.sendfile, 0},
764 {"log-ioerror", required_argument, 0, "log requests with io errors", uwsgi_opt_true, &uwsgi.logging_options.ioerror, 0},
765 {"log-micros", no_argument, 0, "report response time in microseconds instead of milliseconds", uwsgi_opt_true, &uwsgi.log_micros, 0},
766 {"log-x-forwarded-for", no_argument, 0, "use the ip from X-Forwarded-For header instead of REMOTE_ADDR", uwsgi_opt_true, &uwsgi.logging_options.log_x_forwarded_for, 0},
767 {"master-as-root", no_argument, 0, "leave master process running as root", uwsgi_opt_true, &uwsgi.master_as_root, 0},
768
769 {"drop-after-init", no_argument, 0, "run privileges drop after plugin initialization, superseded by drop-after-apps", uwsgi_opt_true, &uwsgi.drop_after_init, 0},
770 {"drop-after-apps", no_argument, 0, "run privileges drop after apps loading, superseded by master-as-root", uwsgi_opt_true, &uwsgi.drop_after_apps, 0},
771
772 {"force-cwd", required_argument, 0, "force the initial working directory to the specified value", uwsgi_opt_set_str, &uwsgi.force_cwd, 0},
773 {"binsh", required_argument, 0, "override /bin/sh (used by exec hooks, it always fallback to /bin/sh)", uwsgi_opt_add_string_list, &uwsgi.binsh, 0},
774 {"chdir", required_argument, 0, "chdir to specified directory before apps loading", uwsgi_opt_set_str, &uwsgi.chdir, 0},
775 {"chdir2", required_argument, 0, "chdir to specified directory after apps loading", uwsgi_opt_set_str, &uwsgi.chdir2, 0},
776 {"lazy", no_argument, 0, "set lazy mode (load apps in workers instead of master)", uwsgi_opt_true, &uwsgi.lazy, 0},
777 {"lazy-apps", no_argument, 0, "load apps in each worker instead of the master", uwsgi_opt_true, &uwsgi.lazy_apps, 0},
778 {"cheap", no_argument, 0, "set cheap mode (spawn workers only after the first request)", uwsgi_opt_true, &uwsgi.status.is_cheap, UWSGI_OPT_MASTER},
779 {"cheaper", required_argument, 0, "set cheaper mode (adaptive process spawning)", uwsgi_opt_set_int, &uwsgi.cheaper_count, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
780 {"cheaper-initial", required_argument, 0, "set the initial number of processes to spawn in cheaper mode", uwsgi_opt_set_int, &uwsgi.cheaper_initial, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
781 {"cheaper-algo", required_argument, 0, "choose to algorithm used for adaptive process spawning", uwsgi_opt_set_str, &uwsgi.requested_cheaper_algo, UWSGI_OPT_MASTER},
782 {"cheaper-step", required_argument, 0, "number of additional processes to spawn at each overload", uwsgi_opt_set_int, &uwsgi.cheaper_step, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
783 {"cheaper-overload", required_argument, 0, "increase workers after specified overload", uwsgi_opt_set_64bit, &uwsgi.cheaper_overload, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
784 {"cheaper-algo-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
785 {"cheaper-algos-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
786 {"cheaper-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
787 {"cheaper-rss-limit-soft", required_argument, 0, "don't spawn new workers if total resident memory usage of all workers is higher than this limit", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_soft, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
788 {"cheaper-rss-limit-hard", required_argument, 0, "if total workers resident memory usage is higher try to stop workers", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_hard, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
789 {"idle", required_argument, 0, "set idle mode (put uWSGI in cheap mode after inactivity)", uwsgi_opt_set_int, &uwsgi.idle, UWSGI_OPT_MASTER},
790 {"die-on-idle", no_argument, 0, "shutdown uWSGI when idle", uwsgi_opt_true, &uwsgi.die_on_idle, 0},
791 {"mount", required_argument, 0, "load application under mountpoint", uwsgi_opt_add_string_list, &uwsgi.mounts, 0},
792 {"worker-mount", required_argument, 0, "load application under mountpoint in the specified worker or after workers spawn", uwsgi_opt_add_string_list, &uwsgi.mounts, 0},
793
794 {"threads", required_argument, 0, "run each worker in prethreaded mode with the specified number of threads", uwsgi_opt_set_int, &uwsgi.threads, UWSGI_OPT_THREADS},
795 {"thread-stacksize", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS},
796 {"threads-stacksize", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS},
797 {"thread-stack-size", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS},
798 {"threads-stack-size", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS},
799
800 {"vhost", no_argument, 0, "enable virtualhosting mode (based on SERVER_NAME variable)", uwsgi_opt_true, &uwsgi.vhost, 0},
801 {"vhost-host", no_argument, 0, "enable virtualhosting mode (based on HTTP_HOST variable)", uwsgi_opt_true, &uwsgi.vhost_host, UWSGI_OPT_VHOST},
802 #ifdef UWSGI_ROUTING
803 {"route", required_argument, 0, "add a route", uwsgi_opt_add_route, "path_info", 0},
804 {"route-host", required_argument, 0, "add a route based on Host header", uwsgi_opt_add_route, "http_host", 0},
805 {"route-uri", required_argument, 0, "add a route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
806 {"route-qs", required_argument, 0, "add a route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
807 {"route-remote-addr", required_argument, 0, "add a route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
808 {"route-user-agent", required_argument, 0, "add a route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
809 {"route-remote-user", required_argument, 0, "add a route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
810 {"route-referer", required_argument, 0, "add a route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
811 {"route-label", required_argument, 0, "add a routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
812 {"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
813 {"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
814 {"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
815
816
817
818 {"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0},
819 {"final-route-status", required_argument, 0, "add a final route for the specified status", uwsgi_opt_add_route, "status", 0},
820 {"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0},
821 {"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
822 {"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
823 {"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
824 {"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
825 {"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
826 {"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
827 {"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
828 {"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0},
829 {"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
830 {"final-route-run", required_argument, 0, "always run the specified final route action", uwsgi_opt_add_route, "run", 0},
831
832 {"error-route", required_argument, 0, "add an error route", uwsgi_opt_add_route, "path_info", 0},
833 {"error-route-status", required_argument, 0, "add an error route for the specified status", uwsgi_opt_add_route, "status", 0},
834 {"error-route-host", required_argument, 0, "add an error route based on Host header", uwsgi_opt_add_route, "http_host", 0},
835 {"error-route-uri", required_argument, 0, "add an error route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
836 {"error-route-qs", required_argument, 0, "add an error route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
837 {"error-route-remote-addr", required_argument, 0, "add an error route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
838 {"error-route-user-agent", required_argument, 0, "add an error route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
839 {"error-route-remote-user", required_argument, 0, "add an error route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
840 {"error-route-referer", required_argument, 0, "add an error route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
841 {"error-route-label", required_argument, 0, "add an error routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
842 {"error-route-if", required_argument, 0, "add an error route based on condition", uwsgi_opt_add_route, "if", 0},
843 {"error-route-if-not", required_argument, 0, "add an error route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
844 {"error-route-run", required_argument, 0, "always run the specified error route action", uwsgi_opt_add_route, "run", 0},
845
846 {"response-route", required_argument, 0, "add a response route", uwsgi_opt_add_route, "path_info", 0},
847 {"response-route-status", required_argument, 0, "add a response route for the specified status", uwsgi_opt_add_route, "status", 0},
848 {"response-route-host", required_argument, 0, "add a response route based on Host header", uwsgi_opt_add_route, "http_host", 0},
849 {"response-route-uri", required_argument, 0, "add a response route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
850 {"response-route-qs", required_argument, 0, "add a response route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
851 {"response-route-remote-addr", required_argument, 0, "add a response route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
852 {"response-route-user-agent", required_argument, 0, "add a response route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
853 {"response-route-remote-user", required_argument, 0, "add a response route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
854 {"response-route-referer", required_argument, 0, "add a response route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
855 {"response-route-label", required_argument, 0, "add a response routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
856 {"response-route-if", required_argument, 0, "add a response route based on condition", uwsgi_opt_add_route, "if", 0},
857 {"response-route-if-not", required_argument, 0, "add a response route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
858 {"response-route-run", required_argument, 0, "always run the specified response route action", uwsgi_opt_add_route, "run", 0},
859
860 {"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
861 {"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
862 #endif
863
864
865 {"error-page-403", required_argument, 0, "add an error page (html) for managed 403 response", uwsgi_opt_add_string_list, &uwsgi.error_page_403, 0},
866 {"error-page-404", required_argument, 0, "add an error page (html) for managed 404 response", uwsgi_opt_add_string_list, &uwsgi.error_page_404, 0},
867 {"error-page-500", required_argument, 0, "add an error page (html) for managed 500 response", uwsgi_opt_add_string_list, &uwsgi.error_page_500, 0},
868
869 {"websockets-ping-freq", required_argument, 0, "set the frequency (in seconds) of websockets automatic ping packets", uwsgi_opt_set_int, &uwsgi.websockets_ping_freq, 0},
870 {"websocket-ping-freq", required_argument, 0, "set the frequency (in seconds) of websockets automatic ping packets", uwsgi_opt_set_int, &uwsgi.websockets_ping_freq, 0},
871
872 {"websockets-pong-tolerance", required_argument, 0, "set the tolerance (in seconds) of websockets ping/pong subsystem", uwsgi_opt_set_int, &uwsgi.websockets_pong_tolerance, 0},
873 {"websocket-pong-tolerance", required_argument, 0, "set the tolerance (in seconds) of websockets ping/pong subsystem", uwsgi_opt_set_int, &uwsgi.websockets_pong_tolerance, 0},
874
875 {"websockets-max-size", required_argument, 0, "set the max allowed size of websocket messages (in Kbytes, default 1024)", uwsgi_opt_set_64bit, &uwsgi.websockets_max_size, 0},
876 {"websocket-max-size", required_argument, 0, "set the max allowed size of websocket messages (in Kbytes, default 1024)", uwsgi_opt_set_64bit, &uwsgi.websockets_max_size, 0},
877
878 {"chunked-input-limit", required_argument, 0, "set the max size of a chunked input part (default 1MB, in bytes)", uwsgi_opt_set_64bit, &uwsgi.chunked_input_limit, 0},
879 {"chunked-input-timeout", required_argument, 0, "set default timeout for chunked input", uwsgi_opt_set_int, &uwsgi.chunked_input_timeout, 0},
880
881 {"clock", required_argument, 0, "set a clock source", uwsgi_opt_set_str, &uwsgi.requested_clock, 0},
882
883 {"clock-list", no_argument, 0, "list enabled clocks", uwsgi_opt_true, &uwsgi.clock_list, 0},
884 {"clocks-list", no_argument, 0, "list enabled clocks", uwsgi_opt_true, &uwsgi.clock_list, 0},
885
886 {"add-header", required_argument, 0, "automatically add HTTP headers to response", uwsgi_opt_add_string_list, &uwsgi.additional_headers, 0},
887 {"rem-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0},
888 {"del-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0},
889 {"collect-header", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
890 {"response-header-collect", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
891
892 {"pull-header", required_argument, 0, "store the specified response header in a request var and remove it from the response (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.pull_headers, 0},
893
894 {"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
895 {"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
896 {"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
897 {"static-map", required_argument, 0, "map mountpoint to static directory (or file)", uwsgi_opt_static_map, &uwsgi.static_maps, UWSGI_OPT_MIME},
898 {"static-map2", required_argument, 0, "like static-map but completely appending the requested resource to the docroot", uwsgi_opt_static_map, &uwsgi.static_maps2, UWSGI_OPT_MIME},
899 {"static-skip-ext", required_argument, 0, "skip specified extension from staticfile checks", uwsgi_opt_add_string_list, &uwsgi.static_skip_ext, UWSGI_OPT_MIME},
900 {"static-index", required_argument, 0, "search for specified file if a directory is requested", uwsgi_opt_add_string_list, &uwsgi.static_index, UWSGI_OPT_MIME},
901 {"static-safe", required_argument, 0, "skip security checks if the file is under the specified path", uwsgi_opt_add_string_list, &uwsgi.static_safe, UWSGI_OPT_MIME},
902 {"static-cache-paths", required_argument, 0, "put resolved paths in the uWSGI cache for the specified amount of seconds", uwsgi_opt_set_int, &uwsgi.use_static_cache_paths, UWSGI_OPT_MIME|UWSGI_OPT_MASTER},
903 {"static-cache-paths-name", required_argument, 0, "use the specified cache for static paths", uwsgi_opt_set_str, &uwsgi.static_cache_paths_name, UWSGI_OPT_MIME|UWSGI_OPT_MASTER},
904 #ifdef __APPLE__
905 {"mimefile", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
906 {"mime-file", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
907 #else
908 {"mimefile", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
909 {"mime-file", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
910 #endif
911
912 {"static-expires-type", required_argument, 0, "set the Expires header based on content type", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type, UWSGI_OPT_MIME},
913 {"static-expires-type-mtime", required_argument, 0, "set the Expires header based on content type and file mtime", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type_mtime, UWSGI_OPT_MIME},
914
915 #ifdef UWSGI_PCRE
916 {"static-expires", required_argument, 0, "set the Expires header based on filename regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires, UWSGI_OPT_MIME},
917 {"static-expires-mtime", required_argument, 0, "set the Expires header based on filename regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_mtime, UWSGI_OPT_MIME},
918
919 {"static-expires-uri", required_argument, 0, "set the Expires header based on REQUEST_URI regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_uri, UWSGI_OPT_MIME},
920 {"static-expires-uri-mtime", required_argument, 0, "set the Expires header based on REQUEST_URI regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_uri_mtime, UWSGI_OPT_MIME},
921
922 {"static-expires-path-info", required_argument, 0, "set the Expires header based on PATH_INFO regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_path_info, UWSGI_OPT_MIME},
923 {"static-expires-path-info-mtime", required_argument, 0, "set the Expires header based on PATH_INFO regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_path_info_mtime, UWSGI_OPT_MIME},
924 {"static-gzip", required_argument, 0, "if the supplied regexp matches the static file translation it will search for a gzip version", uwsgi_opt_add_regexp_list, &uwsgi.static_gzip, UWSGI_OPT_MIME},
925 #endif
926 {"static-gzip-all", no_argument, 0, "check for a gzip version of all requested static files", uwsgi_opt_true, &uwsgi.static_gzip_all, UWSGI_OPT_MIME},
927 {"static-gzip-dir", required_argument, 0, "check for a gzip version of all requested static files in the specified dir/prefix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_dir, UWSGI_OPT_MIME},
928 {"static-gzip-prefix", required_argument, 0, "check for a gzip version of all requested static files in the specified dir/prefix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_dir, UWSGI_OPT_MIME},
929 {"static-gzip-ext", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
930 {"static-gzip-suffix", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
931
932 {"honour-range", no_argument, 0, "enable support for the HTTP Range header", uwsgi_opt_true, &uwsgi.honour_range, 0},
933
934 {"offload-threads", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
935 {"offload-thread", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
936
937 {"file-serve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
938 {"fileserve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
939
940 {"disable-sendfile", no_argument, 0, "disable sendfile() and rely on boring read()/write()", uwsgi_opt_true, &uwsgi.disable_sendfile, 0},
941
942 {"check-cache", optional_argument, 0, "check for response data in the specified cache (empty for default cache)", uwsgi_opt_set_str, &uwsgi.use_check_cache, 0},
943 {"close-on-exec", no_argument, 0, "set close-on-exec on connection sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
944 {"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0},
945 {"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0},
946 {"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0},
947 {"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0},
948 {"early-envdir", required_argument, 0, "load a daemontools compatible envdir ASAP", uwsgi_opt_envdir, NULL, UWSGI_OPT_IMMEDIATE},
949 {"unenv", required_argument, 0, "unset environment variable", uwsgi_opt_unset_env, NULL, 0},
950 {"vacuum", no_argument, 0, "try to remove all of the generated file/sockets", uwsgi_opt_true, &uwsgi.vacuum, 0},
951 {"file-write", required_argument, 0, "write the specified content to the specified file (syntax: file=value) before privileges drop", uwsgi_opt_add_string_list, &uwsgi.file_write_list, 0},
952 #ifdef __linux__
953 {"cgroup", required_argument, 0, "put the processes in the specified cgroup", uwsgi_opt_add_string_list, &uwsgi.cgroup, 0},
954 {"cgroup-opt", required_argument, 0, "set value in specified cgroup option", uwsgi_opt_add_string_list, &uwsgi.cgroup_opt, 0},
955 {"cgroup-dir-mode", required_argument, 0, "set permission for cgroup directory (default is 700)", uwsgi_opt_set_str, &uwsgi.cgroup_dir_mode, 0},
956 {"namespace", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
957 {"namespace-keep-mount", required_argument, 0, "keep the specified mountpoint in your namespace", uwsgi_opt_add_string_list, &uwsgi.ns_keep_mount, 0},
958 {"ns", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
959 {"namespace-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0},
960 {"ns-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0},
961 #endif
962 {"enable-proxy-protocol", no_argument, 0, "enable PROXY1 protocol support (only for http parsers)", uwsgi_opt_true, &uwsgi.enable_proxy_protocol, 0},
963 {"reuse-port", no_argument, 0, "enable REUSE_PORT flag on socket (BSD only)", uwsgi_opt_true, &uwsgi.reuse_port, 0},
964 {"tcp-fast-open", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0},
965 {"tcp-fastopen", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0},
966 {"tcp-fast-open-client", no_argument, 0, "use sendto(..., MSG_FASTOPEN, ...) instead of connect() if supported", uwsgi_opt_true, &uwsgi.tcp_fast_open_client, 0},
967 {"tcp-fastopen-client", no_argument, 0, "use sendto(..., MSG_FASTOPEN, ...) instead of connect() if supported", uwsgi_opt_true, &uwsgi.tcp_fast_open_client, 0},
968 {"zerg", required_argument, 0, "attach to a zerg server", uwsgi_opt_add_string_list, &uwsgi.zerg_node, 0},
969 {"zerg-fallback", no_argument, 0, "fallback to normal sockets if the zerg server is not available", uwsgi_opt_true, &uwsgi.zerg_fallback, 0},
970 {"zerg-server", required_argument, 0, "enable the zerg server on the specified UNIX socket", uwsgi_opt_set_str, &uwsgi.zerg_server, UWSGI_OPT_MASTER},
971
972 {"cron", required_argument, 0, "add a cron task", uwsgi_opt_add_cron, NULL, UWSGI_OPT_MASTER},
973 {"cron2", required_argument, 0, "add a cron task (key=val syntax)", uwsgi_opt_add_cron2, NULL, UWSGI_OPT_MASTER},
974 {"unique-cron", required_argument, 0, "add a unique cron task", uwsgi_opt_add_unique_cron, NULL, UWSGI_OPT_MASTER},
975 {"cron-harakiri", required_argument, 0, "set the maximum time (in seconds) we wait for cron command to complete", uwsgi_opt_set_int, &uwsgi.cron_harakiri, 0},
976 #ifdef UWSGI_SSL
977 {"legion-cron", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
978 {"cron-legion", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
979 {"unique-legion-cron", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER},
980 {"unique-cron-legion", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER},
981 #endif
982 {"loop", required_argument, 0, "select the uWSGI loop engine", uwsgi_opt_set_str, &uwsgi.loop, 0},
983 {"loop-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
984 {"loops-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
985 {"worker-exec", required_argument, 0, "run the specified command as worker", uwsgi_opt_set_str, &uwsgi.worker_exec, 0},
986 {"worker-exec2", required_argument, 0, "run the specified command as worker (after post_fork hook)", uwsgi_opt_set_str, &uwsgi.worker_exec2, 0},
987 {"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
988 {"attach-control-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background), when the daemon dies, the master dies too", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
989 {"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
990 {"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
991 #ifdef UWSGI_SSL
992 {"legion-attach-daemon", required_argument, 0, "same as --attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
993 {"legion-smart-attach-daemon", required_argument, 0, "same as --smart-attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
994 {"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
995 #endif
996 {"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
997 {"attach-daemon2", required_argument, 0, "attach-daemon keyval variant (supports smart modes too)", uwsgi_opt_add_daemon2, NULL, UWSGI_OPT_MASTER},
998 {"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
999 {"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
1000 {"need-plugins", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
1001 {"need-plugin", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
1002 {"plugins-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
1003 {"plugin-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
1004 {"plugins-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0},
1005 {"plugin-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0},
1006 {"autoload", no_argument, 0, "try to automatically load plugins when unknown options are found", uwsgi_opt_true, &uwsgi.autoload, UWSGI_OPT_IMMEDIATE},
1007 {"dlopen", required_argument, 0, "blindly load a shared library", uwsgi_opt_load_dl, NULL, UWSGI_OPT_IMMEDIATE},
1008 {"allowed-modifiers", required_argument, 0, "comma separated list of allowed modifiers", uwsgi_opt_set_str, &uwsgi.allowed_modifiers, 0},
1009 {"remap-modifier", required_argument, 0, "remap request modifier from one id to another", uwsgi_opt_set_str, &uwsgi.remap_modifier, 0},
1010
1011 {"dump-options", no_argument, 0, "dump the full list of available options", uwsgi_opt_true, &uwsgi.dump_options, 0},
1012 {"show-config", no_argument, 0, "show the current config reformatted as ini", uwsgi_opt_true, &uwsgi.show_config, 0},
1013 {"binary-append-data", required_argument, 0, "return the content of a resource to stdout for appending to a uwsgi binary (for data:// usage)", uwsgi_opt_binary_append_data, NULL, UWSGI_OPT_IMMEDIATE},
1014 {"print", required_argument, 0, "simple print", uwsgi_opt_print, NULL, 0},
1015 {"iprint", required_argument, 0, "simple print (immediate version)", uwsgi_opt_print, NULL, UWSGI_OPT_IMMEDIATE},
1016 {"exit", optional_argument, 0, "force exit() of the instance", uwsgi_opt_exit, NULL, UWSGI_OPT_IMMEDIATE},
1017 {"cflags", no_argument, 0, "report uWSGI CFLAGS (useful for building external plugins)", uwsgi_opt_cflags, NULL, UWSGI_OPT_IMMEDIATE},
1018 {"dot-h", no_argument, 0, "dump the uwsgi.h used for building the core (useful for building external plugins)", uwsgi_opt_dot_h, NULL, UWSGI_OPT_IMMEDIATE},
1019 {"config-py", no_argument, 0, "dump the uwsgiconfig.py used for building the core (useful for building external plugins)", uwsgi_opt_config_py, NULL, UWSGI_OPT_IMMEDIATE},
1020 {"build-plugin", required_argument, 0, "build a uWSGI plugin for the current binary", uwsgi_opt_build_plugin, NULL, UWSGI_OPT_IMMEDIATE},
1021 {"version", no_argument, 0, "print uWSGI version", uwsgi_opt_print, UWSGI_VERSION, 0},
1022 {"response-headers-limit", required_argument, 0, "set response header maximum size (default: 64k)", uwsgi_opt_set_int, &uwsgi.response_header_limit, 0},
1023 {0, 0, 0, 0, 0, 0, 0}
1024 };
1025
show_config(void)1026 void show_config(void) {
1027 int i;
1028 uwsgi_log("\n;uWSGI instance configuration\n[uwsgi]\n");
1029 for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
1030 if (uwsgi.exported_opts[i]->value) {
1031 uwsgi_log("%s = %s\n", uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
1032 }
1033 else {
1034 uwsgi_log("%s = true\n", uwsgi.exported_opts[i]->key);
1035 }
1036 }
1037 uwsgi_log(";end of configuration\n\n");
1038
1039 }
1040
config_magic_table_fill(char * filename,char ** magic_table)1041 void config_magic_table_fill(char *filename, char **magic_table) {
1042
1043 char *tmp = NULL;
1044 char *fullname = filename;
1045
1046 magic_table['o'] = filename;
1047
1048 if (uwsgi_check_scheme(filename) || !strcmp(filename, "-")) {
1049 return;
1050 }
1051
1052 char *section = uwsgi_get_last_char(filename, ':');
1053 if (section) {
1054 *section = 0;
1055 if (section == filename) {
1056 goto reuse;
1057 }
1058 }
1059
1060
1061 // we have a special case for symlinks
1062 if (uwsgi_is_link(filename)) {
1063 if (filename[0] != '/') {
1064 fullname = uwsgi_concat3(uwsgi.cwd, "/", filename);
1065 }
1066 }
1067 else {
1068
1069 fullname = uwsgi_expand_path(filename, strlen(filename), NULL);
1070 if (!fullname) {
1071 exit(1);
1072 }
1073 char *minimal_name = uwsgi_malloc(strlen(fullname) + 1);
1074 memcpy(minimal_name, fullname, strlen(fullname));
1075 minimal_name[strlen(fullname)] = 0;
1076 free(fullname);
1077 fullname = minimal_name;
1078 }
1079
1080 magic_table['b'] = uwsgi.binary_path;
1081 magic_table['p'] = fullname;
1082
1083 // compute filename hash
1084 uint32_t hash = djb33x_hash(magic_table['p'], strlen(magic_table['p']));
1085 char *hex = uwsgi_str_to_hex((char *)&hash, 4);
1086 magic_table['j'] = uwsgi_concat2n(hex, 8, "", 0);
1087 free(hex);
1088
1089 struct stat st;
1090 if (!lstat(fullname, &st)) {
1091 magic_table['i'] = uwsgi_num2str(st.st_ino);
1092 }
1093
1094 magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1;
1095
1096 magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0);
1097 if (magic_table['d'][strlen(magic_table['d']) - 1] == '/') {
1098 tmp = magic_table['d'] + (strlen(magic_table['d']) - 1);
1099 #ifdef UWSGI_DEBUG
1100 uwsgi_log("tmp = %c\n", *tmp);
1101 #endif
1102 *tmp = 0;
1103 }
1104
1105 // clear optional vars
1106 magic_table['c'] = "";
1107 magic_table['e'] = "";
1108 magic_table['n'] = magic_table['s'];
1109
1110 magic_table['0'] = "";
1111 magic_table['1'] = "";
1112 magic_table['2'] = "";
1113 magic_table['3'] = "";
1114 magic_table['4'] = "";
1115 magic_table['5'] = "";
1116 magic_table['6'] = "";
1117 magic_table['7'] = "";
1118 magic_table['8'] = "";
1119 magic_table['9'] = "";
1120
1121 if (uwsgi_get_last_char(magic_table['d'], '/')) {
1122 magic_table['c'] = uwsgi_str(uwsgi_get_last_char(magic_table['d'], '/') + 1);
1123 if (magic_table['c'][strlen(magic_table['c']) - 1] == '/') {
1124 magic_table['c'][strlen(magic_table['c']) - 1] = 0;
1125 }
1126 }
1127
1128 int base = '0';
1129 char *to_split = uwsgi_str(magic_table['d']);
1130 char *p, *ctx = NULL;
1131 uwsgi_foreach_token(to_split, "/", p, ctx) {
1132 if (base <= '9') {
1133 magic_table[base] = p;
1134 base++;
1135 }
1136 else {
1137 break;
1138 }
1139 }
1140
1141 if (tmp)
1142 *tmp = '/';
1143
1144 if (uwsgi_get_last_char(magic_table['s'], '.'))
1145 magic_table['e'] = uwsgi_get_last_char(magic_table['s'], '.') + 1;
1146 if (uwsgi_get_last_char(magic_table['s'], '.'))
1147 magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.') - magic_table['s'], "", 0);
1148
1149 reuse:
1150 magic_table['x'] = "";
1151 if (section) {
1152 magic_table['x'] = section+1;
1153 *section = ':';
1154 }
1155
1156 // first round ?
1157 if (!uwsgi.magic_table_first_round) {
1158 magic_table['O'] = magic_table['o'];
1159 magic_table['D'] = magic_table['d'];
1160 magic_table['S'] = magic_table['s'];
1161 magic_table['P'] = magic_table['p'];
1162 magic_table['C'] = magic_table['c'];
1163 magic_table['E'] = magic_table['e'];
1164 magic_table['N'] = magic_table['n'];
1165 magic_table['X'] = magic_table['x'];
1166 magic_table['I'] = magic_table['i'];
1167 magic_table['J'] = magic_table['j'];
1168 uwsgi.magic_table_first_round = 1;
1169 }
1170
1171 }
1172
find_worker_id(pid_t pid)1173 int find_worker_id(pid_t pid) {
1174 int i;
1175 for (i = 1; i <= uwsgi.numproc; i++) {
1176 if (uwsgi.workers[i].pid == pid)
1177 return i;
1178 }
1179
1180 return -1;
1181 }
1182
1183
warn_pipe()1184 void warn_pipe() {
1185 struct wsgi_request *wsgi_req = current_wsgi_req();
1186
1187 if (uwsgi.threads < 2 && wsgi_req->uri_len > 0) {
1188 uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request %.*s (ip %.*s) !!!\n", wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr);
1189 }
1190 else {
1191 uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n");
1192 }
1193 }
1194
1195 // in threading mode we need to use the cancel pthread subsystem
wait_for_threads()1196 void wait_for_threads() {
1197 int i, ret;
1198
1199 // on some platform thread cancellation is REALLY flaky
1200 if (uwsgi.no_threads_wait) return;
1201
1202 int sudden_death = 0;
1203
1204 pthread_mutex_lock(&uwsgi.six_feet_under_lock);
1205 for (i = 1; i < uwsgi.threads; i++) {
1206 if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
1207 if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[i].thread_id)) {
1208 uwsgi_error("pthread_cancel()\n");
1209 sudden_death = 1;
1210 }
1211 }
1212 }
1213
1214 if (sudden_death)
1215 goto end;
1216
1217 // wait for thread termination
1218 for (i = 1; i < uwsgi.threads; i++) {
1219 if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
1220 ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, NULL);
1221 if (ret) {
1222 uwsgi_log("pthread_join() = %d\n", ret);
1223 }
1224 }
1225 }
1226
1227 // cancel inital thread last since after pthread_cancel() and
1228 // pthread_join() is called on it, the whole process will appear to be
1229 // a zombie. although it won't eliminate process zombie time, but it
1230 // should minimize it.
1231 if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, pthread_self())) {
1232 if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[0].thread_id)) {
1233 uwsgi_error("pthread_cancel() on initial thread\n");
1234 goto end;
1235 }
1236
1237 ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, NULL);
1238 if (ret) {
1239 uwsgi_log("pthread_join() = %d on initial thread\n", ret);
1240 }
1241 }
1242
1243 end:
1244
1245 pthread_mutex_unlock(&uwsgi.six_feet_under_lock);
1246 }
1247
1248
gracefully_kill(int signum)1249 void gracefully_kill(int signum) {
1250
1251 uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
1252 uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
1253 if (uwsgi.threads > 1) {
1254 struct wsgi_request *wsgi_req = current_wsgi_req();
1255 wait_for_threads();
1256 if (!uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request) {
1257 if (uwsgi.workers[uwsgi.mywid].shutdown_sockets)
1258 uwsgi_shutdown_all_sockets();
1259 exit(UWSGI_RELOAD_CODE);
1260 }
1261 return;
1262 // never here
1263 }
1264
1265 // still not found a way to gracefully reload in async mode
1266 if (uwsgi.async > 1) {
1267 if (uwsgi.workers[uwsgi.mywid].shutdown_sockets)
1268 uwsgi_shutdown_all_sockets();
1269 exit(UWSGI_RELOAD_CODE);
1270 }
1271
1272 if (!uwsgi.workers[uwsgi.mywid].cores[0].in_request) {
1273 if (uwsgi.workers[uwsgi.mywid].shutdown_sockets)
1274 uwsgi_shutdown_all_sockets();
1275 exit(UWSGI_RELOAD_CODE);
1276 }
1277 }
1278
end_me(int signum)1279 void end_me(int signum) {
1280 if (getpid() != masterpid && uwsgi.skip_atexit) {
1281 _exit(UWSGI_END_CODE);
1282 // never here
1283 }
1284 exit(UWSGI_END_CODE);
1285 }
1286
simple_goodbye_cruel_world()1287 void simple_goodbye_cruel_world() {
1288
1289 if (uwsgi.threads > 1 && !uwsgi_instance_is_dying) {
1290 wait_for_threads();
1291 }
1292
1293 uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
1294 uwsgi_log("...The work of process %d is done. Seeya!\n", getpid());
1295 exit(0);
1296 }
1297
goodbye_cruel_world()1298 void goodbye_cruel_world() {
1299 uwsgi_curse(uwsgi.mywid, 0);
1300
1301 if (!uwsgi.gbcw_hook) {
1302 simple_goodbye_cruel_world();
1303 }
1304 else {
1305 uwsgi.gbcw_hook();
1306 }
1307 }
1308
1309 // brutally destroy
kill_them_all(int signum)1310 void kill_them_all(int signum) {
1311
1312 if (uwsgi_instance_is_dying) return;
1313 uwsgi.status.brutally_destroying = 1;
1314
1315 // unsubscribe if needed
1316 uwsgi_unsubscribe_all();
1317
1318 uwsgi_log("SIGINT/SIGTERM received...killing workers...\n");
1319
1320 int i;
1321 for (i = 1; i <= uwsgi.numproc; i++) {
1322 if (uwsgi.workers[i].pid > 0) {
1323 uwsgi_curse(i, SIGINT);
1324 }
1325 }
1326 for (i = 0; i < uwsgi.mules_cnt; i++) {
1327 if (uwsgi.mules[i].pid > 0) {
1328 uwsgi_curse_mule(i, SIGINT);
1329 }
1330 }
1331
1332 uwsgi_destroy_processes();
1333 }
1334
1335 // gracefully destroy
gracefully_kill_them_all(int signum)1336 void gracefully_kill_them_all(int signum) {
1337
1338 if (uwsgi_instance_is_dying) return;
1339 uwsgi.status.gracefully_destroying = 1;
1340
1341 // unsubscribe if needed
1342 uwsgi_unsubscribe_all();
1343
1344 uwsgi_log_verbose("graceful shutdown triggered...\n");
1345
1346 int i;
1347 for (i = 1; i <= uwsgi.numproc; i++) {
1348 if (uwsgi.workers[i].pid > 0) {
1349 if (uwsgi.shutdown_sockets)
1350 uwsgi.workers[i].shutdown_sockets = 1;
1351 uwsgi_curse(i, SIGHUP);
1352 }
1353 }
1354 for (i = 0; i < uwsgi.mules_cnt; i++) {
1355 if (uwsgi.mules[i].pid > 0) {
1356 uwsgi_curse_mule(i, SIGHUP);
1357 }
1358 }
1359
1360 uwsgi_destroy_processes();
1361 }
1362
1363
1364 // graceful reload
grace_them_all(int signum)1365 void grace_them_all(int signum) {
1366 if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying)
1367 return;
1368
1369 int i;
1370
1371 if (uwsgi.lazy) {
1372 for (i = 1; i <= uwsgi.numproc; i++) {
1373 if (uwsgi.workers[i].pid > 0) {
1374 uwsgi_curse(i, SIGHUP);
1375 }
1376 }
1377 return;
1378 }
1379
1380
1381 uwsgi.status.gracefully_reloading = 1;
1382
1383 uwsgi_destroy_processes();
1384
1385 uwsgi_log("...gracefully killing workers...\n");
1386
1387 #ifdef UWSGI_SSL
1388 uwsgi_legion_announce_death();
1389 #endif
1390
1391 if (uwsgi.unsubscribe_on_graceful_reload) {
1392 uwsgi_unsubscribe_all();
1393 }
1394
1395 for (i = 1; i <= uwsgi.numproc; i++) {
1396 if (uwsgi.workers[i].pid > 0) {
1397 uwsgi_curse(i, SIGHUP);
1398 }
1399 }
1400
1401 for (i = 0; i < uwsgi.mules_cnt; i++) {
1402 if (uwsgi.mules[i].pid > 0) {
1403 uwsgi_curse_mule(i, SIGHUP);
1404 }
1405 }
1406 }
1407
uwsgi_nuclear_blast()1408 void uwsgi_nuclear_blast() {
1409
1410 // the Emperor (as an example) cannot nuke itself
1411 if (uwsgi.disable_nuclear_blast) return;
1412
1413 if (!uwsgi.workers) {
1414 reap_them_all(0);
1415 }
1416 else if (uwsgi.master_process) {
1417 if (getpid() == uwsgi.workers[0].pid) {
1418 reap_them_all(0);
1419 }
1420 }
1421
1422 exit(1);
1423 }
1424
1425 // brutally reload
reap_them_all(int signum)1426 void reap_them_all(int signum) {
1427
1428 // avoid reace condition in lazy mode
1429 if (uwsgi_instance_is_reloading)
1430 return;
1431
1432 uwsgi.status.brutally_reloading = 1;
1433
1434 if (!uwsgi.workers) return;
1435
1436 uwsgi_destroy_processes();
1437
1438 uwsgi_log("...brutally killing workers...\n");
1439
1440 #ifdef UWSGI_SSL
1441 uwsgi_legion_announce_death();
1442 #endif
1443
1444 // unsubscribe if needed
1445 uwsgi_unsubscribe_all();
1446
1447 int i;
1448 for (i = 1; i <= uwsgi.numproc; i++) {
1449 if (uwsgi.workers[i].pid > 0)
1450 uwsgi_curse(i, SIGTERM);
1451 }
1452 for (i = 0; i < uwsgi.mules_cnt; i++) {
1453 if (uwsgi.mules[i].pid > 0) {
1454 uwsgi_curse_mule(i, SIGTERM);
1455 }
1456 }
1457 }
1458
harakiri()1459 void harakiri() {
1460
1461 uwsgi_log("\nF*CK !!! i must kill myself (pid: %d app_id: %d)...\n", uwsgi.mypid, uwsgi.wsgi_req->app_id);
1462
1463 if (!uwsgi.master_process) {
1464 uwsgi_log("*** if you want your workers to be automatically respawned consider enabling the uWSGI master process ***\n");
1465 }
1466 exit(0);
1467 }
1468
stats(int signum)1469 void stats(int signum) {
1470 //fix this for better logging(this cause races)
1471 struct uwsgi_app *ua = NULL;
1472 int i, j;
1473
1474 if (uwsgi.mywid == 0) {
1475 show_config();
1476 uwsgi_log("\tworkers total requests: %lu\n", uwsgi.workers[0].requests);
1477 uwsgi_log("-----------------\n");
1478 for (j = 1; j <= uwsgi.numproc; j++) {
1479 for (i = 0; i < uwsgi.workers[j].apps_cnt; i++) {
1480 ua = &uwsgi.workers[j].apps[i];
1481 if (ua) {
1482 uwsgi_log("\tworker %d app %d [%.*s] requests: %lu exceptions: %lu\n", j, i, ua->mountpoint_len, ua->mountpoint, ua->requests, ua->exceptions);
1483 }
1484 }
1485 uwsgi_log("-----------------\n");
1486 }
1487 }
1488 else {
1489 uwsgi_log("worker %d total requests: %lu\n", uwsgi.mywid, uwsgi.workers[0].requests);
1490 for (i = 0; i < uwsgi.workers[uwsgi.mywid].apps_cnt; i++) {
1491 ua = &uwsgi.workers[uwsgi.mywid].apps[i];
1492 if (ua) {
1493 uwsgi_log("\tapp %d [%.*s] requests: %lu exceptions: %lu\n", i, ua->mountpoint_len, ua->mountpoint, ua->requests, ua->exceptions);
1494 }
1495 }
1496 uwsgi_log("-----------------\n");
1497 }
1498 uwsgi_log("\n");
1499 }
1500
what_i_am_doing()1501 void what_i_am_doing() {
1502
1503 struct wsgi_request *wsgi_req;
1504 int i;
1505 char ctime_storage[26];
1506
1507 uwsgi_backtrace(uwsgi.backtrace_depth);
1508
1509 if (uwsgi.cores > 1) {
1510 for (i = 0; i < uwsgi.cores; i++) {
1511 wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[i].req;
1512 if (wsgi_req->uri_len > 0) {
1513 #if defined(__sun__) && !defined(__clang__)
1514 ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26);
1515 #else
1516 ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
1517 #endif
1518 if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
1519 uwsgi_log("HARAKIRI: --- uWSGI worker %d core %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
1520 }
1521 else {
1522 uwsgi_log("SIGUSR2: --- uWSGI worker %d core %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
1523 }
1524 }
1525 }
1526 }
1527 else {
1528 wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req;
1529 if (wsgi_req->uri_len > 0) {
1530 #if defined(__sun__) && !defined(__clang__)
1531 ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26);
1532 #else
1533 ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
1534 #endif
1535 if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
1536 uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
1537 }
1538 else {
1539 uwsgi_log("SIGUSR2: --- uWSGI worker %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
1540 }
1541 }
1542 else if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) {
1543 uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS handling signal %d ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, uwsgi.workers[uwsgi.mywid].signum);
1544 }
1545 }
1546 }
1547
1548
1549
unconfigured_hook(struct wsgi_request * wsgi_req)1550 int unconfigured_hook(struct wsgi_request *wsgi_req) {
1551 if (wsgi_req->uh->modifier1 == 0 && !uwsgi.no_default_app) {
1552 if (uwsgi_apps_cnt > 0 && uwsgi.default_app > -1) {
1553 struct uwsgi_app *ua = &uwsgi_apps[uwsgi.default_app];
1554 if (uwsgi.p[ua->modifier1]->request != unconfigured_hook) {
1555 wsgi_req->uh->modifier1 = ua->modifier1;
1556 return uwsgi.p[ua->modifier1]->request(wsgi_req);
1557 }
1558 }
1559 }
1560 uwsgi_log("-- unavailable modifier requested: %d --\n", wsgi_req->uh->modifier1);
1561 return -1;
1562 }
1563
unconfigured_after_hook(struct wsgi_request * wsgi_req)1564 static void unconfigured_after_hook(struct wsgi_request *wsgi_req) {
1565 return;
1566 }
1567
1568 struct uwsgi_plugin unconfigured_plugin = {
1569
1570 .name = "unconfigured",
1571 .request = unconfigured_hook,
1572 .after_request = unconfigured_after_hook,
1573 };
1574
uwsgi_exec_atexit(void)1575 void uwsgi_exec_atexit(void) {
1576 if (getpid() == masterpid) {
1577
1578 uwsgi_hooks_run(uwsgi.hook_as_user_atexit, "atexit", 0);
1579 // now run exit scripts needed by the user
1580 struct uwsgi_string_list *usl;
1581
1582 uwsgi_foreach(usl, uwsgi.exec_as_user_atexit) {
1583 uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid());
1584 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
1585 if (ret != 0) {
1586 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
1587 }
1588 }
1589
1590 uwsgi_foreach(usl, uwsgi.call_as_user_atexit) {
1591 if (uwsgi_call_symbol(usl->value)) {
1592 uwsgi_log("unable to call function \"%s\"\n", usl->value);
1593 }
1594 }
1595 }
1596 }
1597
vacuum(void)1598 static void vacuum(void) {
1599
1600 struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
1601
1602 if (uwsgi.restore_tc) {
1603 if (getpid() == masterpid) {
1604 if (tcsetattr(0, TCSANOW, &uwsgi.termios)) {
1605 uwsgi_error("vacuum()/tcsetattr()");
1606 }
1607 }
1608 }
1609
1610 if (uwsgi.vacuum) {
1611 if (getpid() == masterpid) {
1612 if (chdir(uwsgi.cwd)) {
1613 uwsgi_error("chdir()");
1614 }
1615 if (uwsgi.pidfile && !uwsgi.uid) {
1616 if (unlink(uwsgi.pidfile)) {
1617 uwsgi_error("unlink()");
1618 }
1619 else {
1620 uwsgi_log("VACUUM: pidfile removed.\n");
1621 }
1622 }
1623 if (uwsgi.pidfile2) {
1624 if (unlink(uwsgi.pidfile2)) {
1625 uwsgi_error("unlink()");
1626 }
1627 else {
1628 uwsgi_log("VACUUM: pidfile2 removed.\n");
1629 }
1630 }
1631 if (uwsgi.safe_pidfile && !uwsgi.uid) {
1632 if (unlink(uwsgi.safe_pidfile)) {
1633 uwsgi_error("unlink()");
1634 }
1635 else {
1636 uwsgi_log("VACUUM: safe pidfile removed.\n");
1637 }
1638 }
1639 if (uwsgi.safe_pidfile2) {
1640 if (unlink(uwsgi.safe_pidfile2)) {
1641 uwsgi_error("unlink()");
1642 }
1643 else {
1644 uwsgi_log("VACUUM: safe pidfile2 removed.\n");
1645 }
1646 }
1647 if (uwsgi.chdir) {
1648 if (chdir(uwsgi.chdir)) {
1649 uwsgi_error("chdir()");
1650 }
1651 }
1652 while (uwsgi_sock) {
1653 if (uwsgi_sock->family == AF_UNIX && uwsgi_sock->name[0] != '@') {
1654 struct stat st;
1655 if (!stat(uwsgi_sock->name, &st)) {
1656 if (st.st_ino != uwsgi_sock->inode) {
1657 uwsgi_log("VACUUM WARNING: unix socket %s changed inode. Skip removal\n", uwsgi_sock->name);
1658 goto next;
1659 }
1660 }
1661 if (unlink(uwsgi_sock->name)) {
1662 uwsgi_error("unlink()");
1663 }
1664 else {
1665 uwsgi_log("VACUUM: unix socket %s removed.\n", uwsgi_sock->name);
1666 }
1667 }
1668 next:
1669 uwsgi_sock = uwsgi_sock->next;
1670 }
1671 if (uwsgi.stats) {
1672 // is a unix socket ?
1673 if (!strchr(uwsgi.stats, ':') && uwsgi.stats[0] != '@') {
1674 if (unlink(uwsgi.stats)) {
1675 uwsgi_error("unlink()");
1676 }
1677 else {
1678 uwsgi_log("VACUUM: unix socket %s (stats) removed.\n", uwsgi.stats);
1679 }
1680 }
1681 }
1682 }
1683 }
1684 }
1685
signal_pidfile(int sig,char * filename)1686 int signal_pidfile(int sig, char *filename) {
1687
1688 int ret = 0;
1689 size_t size = 0;
1690
1691 char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
1692
1693 if (size > 0) {
1694 if (kill((pid_t) atoi(buffer), sig)) {
1695 uwsgi_error("signal_pidfile()/kill()");
1696 ret = -1;
1697 }
1698 }
1699 else {
1700 uwsgi_log("error: invalid pidfile\n");
1701 ret = -1;
1702 }
1703 free(buffer);
1704 return ret;
1705 }
1706
uwsgi_command_signal(char * opt)1707 /*static*/ void uwsgi_command_signal(char *opt) {
1708
1709 int tmp_signal;
1710 char *colon = strchr(opt, ',');
1711 if (!colon) {
1712 uwsgi_log("invalid syntax for signal, must be addr,signal\n");
1713 exit(1);
1714 }
1715
1716 colon[0] = 0;
1717 tmp_signal = atoi(colon + 1);
1718
1719 if (tmp_signal < 0 || tmp_signal > 255) {
1720 uwsgi_log("invalid signal number\n");
1721 exit(3);
1722 }
1723
1724 uint8_t uwsgi_signal = tmp_signal;
1725 int ret = uwsgi_remote_signal_send(opt, uwsgi_signal);
1726
1727 if (ret < 0) {
1728 uwsgi_log("unable to deliver signal %d to node %s\n", uwsgi_signal, opt);
1729 exit(1);
1730 }
1731
1732 if (ret == 0) {
1733 uwsgi_log("node %s rejected signal %d\n", opt, uwsgi_signal);
1734 exit(2);
1735 }
1736
1737 uwsgi_log("signal %d delivered to node %s\n", uwsgi_signal, opt);
1738 exit(0);
1739 }
1740
fixup_argv_and_environ(int argc,char ** argv,char ** environ,char ** envp)1741 static void fixup_argv_and_environ(int argc, char **argv, char **environ, char **envp) {
1742
1743 uwsgi.orig_argv = argv;
1744 uwsgi.argv = argv;
1745 uwsgi.argc = argc;
1746 uwsgi.environ = UWSGI_ENVIRON;
1747
1748 // avoid messing with fake environ
1749 if (envp && *environ != *envp) return;
1750
1751
1752 #if defined(__linux__) || defined(__sun__)
1753
1754 int i;
1755 int env_count = 0;
1756
1757 uwsgi.argv = uwsgi_malloc(sizeof(char *) * (argc + 1));
1758
1759 for (i = 0; i < argc; i++) {
1760 if (i == 0 || argv[0] + uwsgi.max_procname + 1 == argv[i]) {
1761 uwsgi.max_procname += strlen(argv[i]) + 1;
1762 }
1763 uwsgi.argv[i] = strdup(argv[i]);
1764 }
1765
1766 // required by execve
1767 uwsgi.argv[i] = NULL;
1768
1769 uwsgi.max_procname++;
1770
1771 for (i = 0; environ[i] != NULL; i++) {
1772 // useless
1773 //if ((environ[0] + uwsgi.max_procname + 1) == environ[i]) {
1774 uwsgi.max_procname += strlen(environ[i]) + 1;
1775 //}
1776 env_count++;
1777 }
1778
1779 uwsgi.environ = uwsgi_malloc(sizeof(char *) * (env_count+1));
1780 for (i = 0; i < env_count; i++) {
1781 uwsgi.environ[i] = strdup(environ[i]);
1782 #ifdef UWSGI_DEBUG
1783 uwsgi_log("ENVIRON: %s\n", uwsgi.environ[i]);
1784 #endif
1785 environ[i] = uwsgi.environ[i];
1786 }
1787 uwsgi.environ[env_count] = NULL;
1788
1789 #ifdef UWSGI_DEBUG
1790 uwsgi_log("max space for custom process name = %d\n", uwsgi.max_procname);
1791 #endif
1792 //environ = uwsgi.environ;
1793
1794 #endif
1795 }
1796
1797
uwsgi_plugins_atexit(void)1798 void uwsgi_plugins_atexit(void) {
1799
1800 int j;
1801
1802 if (!uwsgi.workers)
1803 return;
1804
1805 // the master cannot run atexit handlers...
1806 if (uwsgi.master_process && uwsgi.workers[0].pid == getpid())
1807 return;
1808
1809 for (j = 0; j < uwsgi.gp_cnt; j++) {
1810 if (uwsgi.gp[j]->atexit) {
1811 uwsgi.gp[j]->atexit();
1812 }
1813 }
1814
1815 for (j = 0; j < 256; j++) {
1816 if (uwsgi.p[j]->atexit) {
1817 uwsgi.p[j]->atexit();
1818 }
1819 }
1820
1821 }
1822
uwsgi_backtrace(int depth)1823 void uwsgi_backtrace(int depth) {
1824
1825 #if defined(__GLIBC__) || (defined(__APPLE__) && !defined(NO_EXECINFO)) || defined(UWSGI_HAS_EXECINFO)
1826
1827 #include <execinfo.h>
1828
1829 void **btrace = uwsgi_malloc(sizeof(void *) * depth);
1830 size_t bt_size, i;
1831 char **bt_strings;
1832
1833 bt_size = backtrace(btrace, depth);
1834
1835 bt_strings = backtrace_symbols(btrace, bt_size);
1836
1837 struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
1838 uwsgi_buffer_append(ub, "*** backtrace of ",17);
1839 uwsgi_buffer_num64(ub, (int64_t) getpid());
1840 uwsgi_buffer_append(ub, " ***\n", 5);
1841 for (i = 0; i < bt_size; i++) {
1842 uwsgi_buffer_append(ub, bt_strings[i], strlen(bt_strings[i]));
1843 uwsgi_buffer_append(ub, "\n", 1);
1844 }
1845
1846 free(btrace);
1847
1848 uwsgi_buffer_append(ub, "*** end of backtrace ***\n", 25);
1849
1850 uwsgi_log("%.*s", ub->pos, ub->buf);
1851
1852 struct uwsgi_string_list *usl = uwsgi.alarm_segfault;
1853 while(usl) {
1854 uwsgi_alarm_trigger(usl->value, ub->buf, ub->pos);
1855 usl = usl->next;
1856 }
1857
1858 uwsgi_buffer_destroy(ub);
1859 #endif
1860
1861 }
1862
uwsgi_segfault(int signum)1863 void uwsgi_segfault(int signum) {
1864
1865 uwsgi_log("!!! uWSGI process %d got Segmentation Fault !!!\n", (int) getpid());
1866 uwsgi_backtrace(uwsgi.backtrace_depth);
1867
1868 if (uwsgi.use_abort) abort();
1869
1870 // restore default handler to generate core
1871 signal(signum, SIG_DFL);
1872 kill(getpid(), signum);
1873
1874 // never here...
1875 exit(1);
1876 }
1877
uwsgi_fpe(int signum)1878 void uwsgi_fpe(int signum) {
1879
1880 uwsgi_log("!!! uWSGI process %d got Floating Point Exception !!!\n", (int) getpid());
1881 uwsgi_backtrace(uwsgi.backtrace_depth);
1882
1883 if (uwsgi.use_abort) abort();
1884
1885 // restore default handler to generate core
1886 signal(signum, SIG_DFL);
1887 kill(getpid(), signum);
1888
1889 // never here...
1890 exit(1);
1891 }
1892
uwsgi_flush_logs()1893 void uwsgi_flush_logs() {
1894
1895 struct pollfd pfd;
1896
1897 if (!uwsgi.master_process)
1898 return;
1899 if (!uwsgi.log_master)
1900 return;
1901
1902 if (uwsgi.workers) {
1903 if (uwsgi.workers[0].pid == getpid()) {
1904 goto check;
1905 }
1906 }
1907
1908
1909 if (uwsgi.mywid == 0)
1910 goto check;
1911
1912 return;
1913
1914 check:
1915 // this buffer could not be initialized !!!
1916 if (uwsgi.log_master) {
1917 uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize);
1918 }
1919
1920 // check for data in logpipe
1921 pfd.events = POLLIN;
1922 pfd.fd = uwsgi.shared->worker_log_pipe[0];
1923 if (pfd.fd == -1)
1924 pfd.fd = 2;
1925
1926 while (poll(&pfd, 1, 0) > 0) {
1927 if (uwsgi_master_log()) {
1928 break;
1929 }
1930 }
1931 }
1932
plugins_list(void)1933 static void plugins_list(void) {
1934 int i;
1935 uwsgi_log("\n*** uWSGI loaded generic plugins ***\n");
1936 for (i = 0; i < uwsgi.gp_cnt; i++) {
1937 uwsgi_log("%s\n", uwsgi.gp[i]->name);
1938 }
1939
1940 uwsgi_log("\n*** uWSGI loaded request plugins ***\n");
1941 for (i = 0; i < 256; i++) {
1942 if (uwsgi.p[i] == &unconfigured_plugin)
1943 continue;
1944 uwsgi_log("%d: %s\n", i, uwsgi.p[i]->name);
1945 }
1946
1947 uwsgi_log("--- end of plugins list ---\n\n");
1948 }
1949
loggers_list(void)1950 static void loggers_list(void) {
1951 struct uwsgi_logger *ul = uwsgi.loggers;
1952 uwsgi_log("\n*** uWSGI loaded loggers ***\n");
1953 while (ul) {
1954 uwsgi_log("%s\n", ul->name);
1955 ul = ul->next;
1956 }
1957 uwsgi_log("--- end of loggers list ---\n\n");
1958 }
1959
cheaper_algo_list(void)1960 static void cheaper_algo_list(void) {
1961 struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos;
1962 uwsgi_log("\n*** uWSGI loaded cheaper algorithms ***\n");
1963 while (uca) {
1964 uwsgi_log("%s\n", uca->name);
1965 uca = uca->next;
1966 }
1967 uwsgi_log("--- end of cheaper algorithms list ---\n\n");
1968 }
1969
1970 #ifdef UWSGI_ROUTING
router_list(void)1971 static void router_list(void) {
1972 struct uwsgi_router *ur = uwsgi.routers;
1973 uwsgi_log("\n*** uWSGI loaded routers ***\n");
1974 while (ur) {
1975 uwsgi_log("%s\n", ur->name);
1976 ur = ur->next;
1977 }
1978 uwsgi_log("--- end of routers list ---\n\n");
1979 }
1980 #endif
1981
loop_list(void)1982 static void loop_list(void) {
1983 struct uwsgi_loop *loop = uwsgi.loops;
1984 uwsgi_log("\n*** uWSGI loaded loop engines ***\n");
1985 while (loop) {
1986 uwsgi_log("%s\n", loop->name);
1987 loop = loop->next;
1988 }
1989 uwsgi_log("--- end of loop engines list ---\n\n");
1990 }
1991
imperial_monitor_list(void)1992 static void imperial_monitor_list(void) {
1993 struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors;
1994 uwsgi_log("\n*** uWSGI loaded imperial monitors ***\n");
1995 while (uim) {
1996 uwsgi_log("%s\n", uim->scheme);
1997 uim = uim->next;
1998 }
1999 uwsgi_log("--- end of imperial monitors list ---\n\n");
2000 }
2001
clocks_list(void)2002 static void clocks_list(void) {
2003 struct uwsgi_clock *clocks = uwsgi.clocks;
2004 uwsgi_log("\n*** uWSGI loaded clocks ***\n");
2005 while (clocks) {
2006 uwsgi_log("%s\n", clocks->name);
2007 clocks = clocks->next;
2008 }
2009 uwsgi_log("--- end of clocks list ---\n\n");
2010 }
2011
alarms_list(void)2012 static void alarms_list(void) {
2013 struct uwsgi_alarm *alarms = uwsgi.alarms;
2014 uwsgi_log("\n*** uWSGI loaded alarms ***\n");
2015 while (alarms) {
2016 uwsgi_log("%s\n", alarms->name);
2017 alarms = alarms->next;
2018 }
2019 uwsgi_log("--- end of alarms list ---\n\n");
2020 }
2021
uwsgi_unix_seconds()2022 static time_t uwsgi_unix_seconds() {
2023 return time(NULL);
2024 }
2025
uwsgi_unix_microseconds()2026 static uint64_t uwsgi_unix_microseconds() {
2027 struct timeval tv;
2028 gettimeofday(&tv, NULL);
2029 return ((uint64_t) tv.tv_sec * 1000000) + tv.tv_usec;
2030 }
2031
2032 static struct uwsgi_clock uwsgi_unix_clock = {
2033 .name = "unix",
2034 .seconds = uwsgi_unix_seconds,
2035 .microseconds = uwsgi_unix_microseconds,
2036 };
2037
uwsgi_init_random()2038 void uwsgi_init_random() {
2039 srand((unsigned int) (uwsgi.start_tv.tv_usec * uwsgi.start_tv.tv_sec));
2040 }
2041
2042 #ifdef UWSGI_AS_SHARED_LIBRARY
uwsgi_init(int argc,char * argv[],char * envp[])2043 int uwsgi_init(int argc, char *argv[], char *envp[]) {
2044 #else
2045 int main(int argc, char *argv[], char *envp[]) {
2046 #endif
2047 uwsgi_setup(argc, argv, envp);
2048 return uwsgi_run();
2049 }
2050
2051 static char *uwsgi_at_file_read(char *filename) {
2052 size_t size = 0;
2053 char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
2054 if (size > 1) {
2055 if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
2056 buffer[size-2] = 0;
2057 }
2058 }
2059 return buffer;
2060 }
2061
2062 void uwsgi_setup(int argc, char *argv[], char *envp[]) {
2063 int i;
2064
2065 struct utsname uuts;
2066
2067 // signal mask is inherited, and sme process manager could make a real mess...
2068 sigset_t smask;
2069 sigfillset(&smask);
2070 if (sigprocmask(SIG_UNBLOCK, &smask, NULL)) {
2071 uwsgi_error("sigprocmask()");
2072 }
2073
2074 signal(SIGCHLD, SIG_DFL);
2075 signal(SIGSEGV, uwsgi_segfault);
2076 signal(SIGFPE, uwsgi_fpe);
2077 signal(SIGHUP, SIG_IGN);
2078 signal(SIGTERM, SIG_IGN);
2079 signal(SIGPIPE, SIG_IGN);
2080
2081 //initialize masterpid with a default value
2082 masterpid = getpid();
2083
2084 memset(&uwsgi, 0, sizeof(struct uwsgi_server));
2085 uwsgi_proto_hooks_setup();
2086 uwsgi.cwd = uwsgi_get_cwd();
2087
2088 init_magic_table(uwsgi.magic_table);
2089
2090 // initialize schemes
2091 uwsgi_setup_schemes();
2092
2093 // initialize the clock
2094 uwsgi_register_clock(&uwsgi_unix_clock);
2095 uwsgi_set_clock("unix");
2096
2097 // fallback config
2098 atexit(uwsgi_fallback_config);
2099 // manage/flush logs
2100 atexit(uwsgi_flush_logs);
2101 // clear sockets, pidfiles...
2102 atexit(vacuum);
2103 // call user scripts
2104 atexit(uwsgi_exec_atexit);
2105 #ifdef UWSGI_SSL
2106 // call legions death hooks
2107 atexit(uwsgi_legion_atexit);
2108 #endif
2109
2110 // allocate main shared memory
2111 uwsgi.shared = (struct uwsgi_shared *) uwsgi_calloc_shared(sizeof(struct uwsgi_shared));
2112
2113 // initialize request plugin to void
2114 for (i = 0; i < 256; i++) {
2115 uwsgi.p[i] = &unconfigured_plugin;
2116 }
2117
2118 // set default values
2119 uwsgi_init_default();
2120
2121 // detect cpu cores
2122 #if defined(_SC_NPROCESSORS_ONLN)
2123 uwsgi.cpus = sysconf(_SC_NPROCESSORS_ONLN);
2124 #elif defined(_SC_NPROCESSORS_CONF)
2125 uwsgi.cpus = sysconf(_SC_NPROCESSORS_CONF);
2126 #endif
2127 // set default logit hook
2128 uwsgi.logit = uwsgi_logit_simple;
2129
2130 #ifdef UWSGI_BLACKLIST
2131 if (!uwsgi_file_to_string_list(UWSGI_BLACKLIST, &uwsgi.blacklist)) {
2132 uwsgi_log("you cannot run this build of uWSGI without a blacklist file\n");
2133 exit(1);
2134 }
2135 #endif
2136
2137 #ifdef UWSGI_WHITELIST
2138 if (!uwsgi_file_to_string_list(UWSGI_WHITELIST, &uwsgi.whitelist)) {
2139 uwsgi_log("you cannot run this build of uWSGI without a whitelist file\n");
2140 exit(1);
2141 }
2142 #endif
2143
2144 // get startup time
2145 gettimeofday(&uwsgi.start_tv, NULL);
2146
2147 // initialize random engine
2148 uwsgi_init_random();
2149
2150 setlinebuf(stdout);
2151
2152 uwsgi.rl.rlim_cur = 0;
2153 uwsgi.rl.rlim_max = 0;
2154
2155 // are we under systemd ?
2156 char *notify_socket = getenv("NOTIFY_SOCKET");
2157 if (notify_socket) {
2158 uwsgi_systemd_init(notify_socket);
2159 }
2160
2161 uwsgi_notify("initializing uWSGI");
2162
2163 // check if we are under the Emperor
2164 uwsgi_check_emperor();
2165
2166 char *screen_env = getenv("TERM");
2167 if (screen_env) {
2168 if (!strcmp(screen_env, "screen")) {
2169 uwsgi.screen_session = getenv("STY");
2170 }
2171 }
2172
2173
2174 // count/set the current reload status
2175 uwsgi_setup_reload();
2176
2177 #ifdef __CYGWIN__
2178 SYSTEM_INFO si;
2179 GetSystemInfo(&si);
2180 uwsgi.page_size = si.dwPageSize;
2181 #else
2182 uwsgi.page_size = getpagesize();
2183 #endif
2184 uwsgi.binary_path = uwsgi_get_binary_path(argv[0]);
2185
2186 if(uwsgi.response_header_limit == 0)
2187 uwsgi.response_header_limit = UMAX16;
2188
2189 // ok we can now safely play with argv and environ
2190 fixup_argv_and_environ(argc, argv, UWSGI_ENVIRON, envp);
2191
2192 if (gethostname(uwsgi.hostname, 255)) {
2193 uwsgi_error("gethostname()");
2194 }
2195 uwsgi.hostname_len = strlen(uwsgi.hostname);
2196
2197 #ifdef UWSGI_ROUTING
2198 uwsgi_register_embedded_routers();
2199 #endif
2200
2201 // call here to allows plugin to override hooks
2202 uwsgi_register_base_hooks();
2203 uwsgi_register_logchunks();
2204 uwsgi_log_encoders_register_embedded();
2205
2206 // register base metrics (so plugins can override them)
2207 uwsgi_metrics_collectors_setup();
2208
2209 //initialize embedded plugins
2210 UWSGI_LOAD_EMBEDDED_PLUGINS
2211 // now a bit of magic, if the executable basename contains a 'uwsgi_' string,
2212 // try to automatically load a plugin
2213 #ifdef UWSGI_DEBUG
2214 uwsgi_log("executable name: %s\n", uwsgi.binary_path);
2215 #endif
2216 uwsgi_autoload_plugins_by_name(argv[0]);
2217
2218
2219 // build the options structure
2220 build_options();
2221
2222 // set a couple of 'static' magic vars
2223 uwsgi.magic_table['v'] = uwsgi.cwd;
2224 uwsgi.magic_table['h'] = uwsgi.hostname;
2225 uwsgi.magic_table['t'] = uwsgi_64bit2str(uwsgi_now());
2226 uwsgi.magic_table['T'] = uwsgi_64bit2str(uwsgi_micros());
2227 uwsgi.magic_table['V'] = UWSGI_VERSION;
2228 uwsgi.magic_table['k'] = uwsgi_num2str(uwsgi.cpus);
2229 uwsgi.magic_table['['] = "\033";
2230 uwsgi.magic_table['u'] = uwsgi_num2str((int)getuid());
2231 struct passwd *pw = getpwuid(getuid());
2232 uwsgi.magic_table['U'] = pw ? pw->pw_name : uwsgi.magic_table['u'];
2233 uwsgi.magic_table['g'] = uwsgi_num2str((int)getgid());
2234 struct group *gr = getgrgid(getgid());
2235 uwsgi.magic_table['G'] = gr ? gr->gr_name : uwsgi.magic_table['g'];
2236
2237 // you can embed a ini file in the uWSGi binary with default options
2238 #ifdef UWSGI_EMBED_CONFIG
2239 uwsgi_ini_config("", uwsgi.magic_table);
2240 // rebuild options if a custom ini is set
2241 build_options();
2242 #endif
2243 //parse environ
2244 parse_sys_envs(UWSGI_ENVIRON);
2245
2246 // parse commandline options
2247 uwsgi_commandline_config();
2248
2249 // second pass: ENVs
2250 uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
2251
2252 // third pass: FILEs
2253 uwsgi_apply_config_pass('@', uwsgi_at_file_read);
2254
2255 // last pass: REFERENCEs
2256 uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
2257
2258 // ok, the options dictionary is available, lets manage it
2259 uwsgi_configure();
2260
2261 // fixup cwd
2262 if (uwsgi.force_cwd) uwsgi.cwd = uwsgi.force_cwd;
2263
2264 // run "asap" hooks
2265 uwsgi_hooks_run(uwsgi.hook_asap, "asap", 1);
2266 struct uwsgi_string_list *usl = NULL;
2267 uwsgi_foreach(usl, uwsgi.mount_asap) {
2268 uwsgi_log("mounting \"%s\" (asap)...\n", usl->value);
2269 if (uwsgi_mount_hook(usl->value)) exit(1);
2270 }
2271 uwsgi_foreach(usl, uwsgi.umount_asap) {
2272 uwsgi_log("un-mounting \"%s\" (asap)...\n", usl->value);
2273 if (uwsgi_umount_hook(usl->value)) exit(1);
2274 }
2275 uwsgi_foreach(usl, uwsgi.exec_asap) {
2276 uwsgi_log("running \"%s\" (asap)...\n", usl->value);
2277 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
2278 if (ret != 0) {
2279 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
2280 exit(1);
2281 }
2282 }
2283 uwsgi_foreach(usl, uwsgi.call_asap) {
2284 if (uwsgi_call_symbol(usl->value)) {
2285 uwsgi_log("unable to call function \"%s\"\n", usl->value);
2286 exit(1);
2287 }
2288 }
2289
2290 // manage envdirs ASAP
2291 uwsgi_envdirs(uwsgi.envdirs);
2292
2293 // --get management
2294 struct uwsgi_string_list *get_list = uwsgi.get_list;
2295 while(get_list) {
2296 char *v = uwsgi_get_exported_opt(get_list->value);
2297 if (v) {
2298 fprintf(stdout, "%s\n", v);
2299 }
2300 get_list = get_list->next;
2301 }
2302
2303 if (uwsgi.get_list) {
2304 exit(0);
2305 }
2306
2307
2308 // initial log setup (files and daemonization)
2309 uwsgi_setup_log();
2310
2311 #ifndef __CYGWIN__
2312 // enable never-swap mode
2313 if (uwsgi.never_swap) {
2314 if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
2315 uwsgi_error("mlockall()");
2316 }
2317 }
2318 #endif
2319
2320 if (uwsgi.flock2)
2321 uwsgi_opt_flock(NULL, uwsgi.flock2, NULL);
2322
2323 if (uwsgi.flock_wait2)
2324 uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
2325
2326 // setup master logging
2327 if (uwsgi.log_master && !uwsgi.daemonize2)
2328 uwsgi_setup_log_master();
2329
2330 // setup offload engines
2331 uwsgi_offload_engines_register_all();
2332
2333 // setup main loops
2334 uwsgi_register_loop("simple", simple_loop);
2335 uwsgi_register_loop("async", async_loop);
2336
2337 // setup cheaper algos
2338 uwsgi_register_cheaper_algo("spare", uwsgi_cheaper_algo_spare);
2339 uwsgi_register_cheaper_algo("backlog", uwsgi_cheaper_algo_backlog);
2340 uwsgi_register_cheaper_algo("manual", uwsgi_cheaper_algo_manual);
2341
2342 // setup imperial monitors
2343 uwsgi_register_imperial_monitor("dir", uwsgi_imperial_monitor_directory_init, uwsgi_imperial_monitor_directory);
2344 uwsgi_register_imperial_monitor("glob", uwsgi_imperial_monitor_glob_init, uwsgi_imperial_monitor_glob);
2345
2346 // setup stats pushers
2347 uwsgi_stats_pusher_setup();
2348
2349 // register embedded alarms
2350 uwsgi_register_embedded_alarms();
2351
2352 /* uWSGI IS CONFIGURED !!! */
2353
2354 if (uwsgi.dump_options) {
2355 struct option *lopt = uwsgi.long_options;
2356 while (lopt && lopt->name) {
2357 fprintf(stdout, "%s\n", lopt->name);
2358 lopt++;
2359 }
2360 exit(0);
2361 }
2362
2363 if (uwsgi.show_config)
2364 show_config();
2365
2366 if (uwsgi.plugins_list)
2367 plugins_list();
2368
2369 if (uwsgi.loggers_list)
2370 loggers_list();
2371
2372 if (uwsgi.cheaper_algo_list)
2373 cheaper_algo_list();
2374
2375
2376 #ifdef UWSGI_ROUTING
2377 if (uwsgi.router_list)
2378 router_list();
2379 #endif
2380
2381
2382 if (uwsgi.loop_list)
2383 loop_list();
2384
2385 if (uwsgi.imperial_monitor_list)
2386 imperial_monitor_list();
2387
2388 if (uwsgi.clock_list)
2389 clocks_list();
2390
2391 if (uwsgi.alarms_list)
2392 alarms_list();
2393
2394 // set the clock
2395 if (uwsgi.requested_clock)
2396 uwsgi_set_clock(uwsgi.requested_clock);
2397
2398 if (uwsgi.binary_path == uwsgi.argv[0]) {
2399 uwsgi.binary_path = uwsgi_str(uwsgi.argv[0]);
2400 }
2401
2402 uwsgi_log_initial("*** Starting uWSGI %s (%dbit) on [%.*s] ***\n", UWSGI_VERSION, (int) (sizeof(void *)) * 8, 24, ctime((const time_t *) &uwsgi.start_tv.tv_sec));
2403
2404 #ifdef UWSGI_DEBUG
2405 uwsgi_log("***\n*** You are running a DEBUG version of uWSGI, please disable debug in your build profile and recompile it ***\n***\n");
2406 #endif
2407
2408 uwsgi_log_initial("compiled with version: %s on %s\n", __VERSION__, UWSGI_BUILD_DATE);
2409
2410 #ifdef __sun__
2411 if (uname(&uuts) < 0) {
2412 #else
2413 if (uname(&uuts)) {
2414 #endif
2415 uwsgi_error("uname()");
2416 }
2417 else {
2418 uwsgi_log_initial("os: %s-%s %s\n", uuts.sysname, uuts.release, uuts.version);
2419 uwsgi_log_initial("nodename: %s\n", uuts.nodename);
2420 uwsgi_log_initial("machine: %s\n", uuts.machine);
2421 }
2422
2423 uwsgi_log_initial("clock source: %s\n", uwsgi.clock->name);
2424 #ifdef UWSGI_PCRE
2425 if (uwsgi.pcre_jit) {
2426 uwsgi_log_initial("pcre jit enabled\n");
2427 }
2428 else {
2429 uwsgi_log_initial("pcre jit disabled\n");
2430 }
2431 #endif
2432
2433 #ifdef __BIG_ENDIAN__
2434 uwsgi_log_initial("*** big endian arch detected ***\n");
2435 #endif
2436
2437 uwsgi_log_initial("detected number of CPU cores: %d\n", uwsgi.cpus);
2438
2439
2440 uwsgi_log_initial("current working directory: %s\n", uwsgi.cwd);
2441
2442 if (uwsgi.screen_session) {
2443 uwsgi_log("*** running under screen session %s ***\n", uwsgi.screen_session);
2444 }
2445
2446 if (uwsgi.pidfile && !uwsgi.is_a_reload) {
2447 uwsgi_write_pidfile(uwsgi.pidfile);
2448 }
2449
2450 uwsgi_log_initial("detected binary path: %s\n", uwsgi.binary_path);
2451
2452 if (uwsgi.is_a_reload) {
2453 struct rlimit rl;
2454 if (!getrlimit(RLIMIT_NOFILE, &rl)) {
2455 uwsgi.max_fd = rl.rlim_cur;
2456 }
2457 }
2458
2459 #ifdef UWSGI_ROUTING
2460 uwsgi_routing_dump();
2461 #else
2462 uwsgi_log("!!! no internal routing support, rebuild with pcre support !!!\n");
2463 #endif
2464
2465 // initialize shared sockets
2466 uwsgi_setup_shared_sockets();
2467
2468 #ifdef __linux__
2469 if (uwsgi.setns_preopen) {
2470 uwsgi_setns_preopen();
2471 }
2472 // eventually join a linux namespace
2473 if (uwsgi.setns) {
2474 uwsgi_setns(uwsgi.setns);
2475 }
2476 #endif
2477
2478 // start the Emperor if needed
2479 if (uwsgi.early_emperor && uwsgi.emperor) {
2480 uwsgi_emperor_start();
2481 }
2482
2483 if (!uwsgi.reloads) {
2484 uwsgi_hooks_run(uwsgi.hook_pre_jail, "pre-jail", 1);
2485 struct uwsgi_string_list *usl = NULL;
2486 uwsgi_foreach(usl, uwsgi.mount_pre_jail) {
2487 uwsgi_log("mounting \"%s\" (pre-jail)...\n", usl->value);
2488 if (uwsgi_mount_hook(usl->value)) {
2489 exit(1);
2490 }
2491 }
2492
2493 uwsgi_foreach(usl, uwsgi.umount_pre_jail) {
2494 uwsgi_log("un-mounting \"%s\" (pre-jail)...\n", usl->value);
2495 if (uwsgi_umount_hook(usl->value)) {
2496 exit(1);
2497 }
2498 }
2499 // run the pre-jail scripts
2500 uwsgi_foreach(usl, uwsgi.exec_pre_jail) {
2501 uwsgi_log("running \"%s\" (pre-jail)...\n", usl->value);
2502 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
2503 if (ret != 0) {
2504 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
2505 exit(1);
2506 }
2507 }
2508
2509 uwsgi_foreach(usl, uwsgi.call_pre_jail) {
2510 if (uwsgi_call_symbol(usl->value)) {
2511 uwsgi_log("unable to call function \"%s\"\n", usl->value);
2512 exit(1);
2513 }
2514 }
2515 }
2516
2517 // we could now patch the binary
2518 if (uwsgi.privileged_binary_patch) {
2519 uwsgi.argv[0] = uwsgi.privileged_binary_patch;
2520 execvp(uwsgi.privileged_binary_patch, uwsgi.argv);
2521 uwsgi_error("execvp()");
2522 exit(1);
2523 }
2524
2525 if (uwsgi.privileged_binary_patch_arg) {
2526 uwsgi_exec_command_with_args(uwsgi.privileged_binary_patch_arg);
2527 }
2528
2529
2530 // call jail systems
2531 for (i = 0; i < uwsgi.gp_cnt; i++) {
2532 if (uwsgi.gp[i]->jail) {
2533 uwsgi.gp[i]->jail(uwsgi_start, uwsgi.argv);
2534 }
2535 }
2536
2537 // TODO pluginize basic Linux namespace support
2538 #if defined(__linux__) && !defined(__ia64__)
2539 if (uwsgi.ns) {
2540 linux_namespace_start((void *) uwsgi.argv);
2541 // never here
2542 }
2543 else {
2544 #endif
2545 uwsgi_start((void *) uwsgi.argv);
2546 #if defined(__linux__) && !defined(__ia64__)
2547 }
2548 #endif
2549
2550 if (uwsgi.safe_pidfile && !uwsgi.is_a_reload) {
2551 uwsgi_write_pidfile_explicit(uwsgi.safe_pidfile, masterpid);
2552 }
2553 }
2554
2555
2556 int uwsgi_start(void *v_argv) {
2557
2558 int i, j;
2559
2560 #ifdef __linux__
2561 uwsgi_set_cgroup();
2562
2563 #if !defined(__ia64__)
2564 if (uwsgi.ns) {
2565 linux_namespace_jail();
2566 }
2567 #endif
2568 #endif
2569
2570 uwsgi_hooks_run(uwsgi.hook_in_jail, "in-jail", 1);
2571
2572 struct uwsgi_string_list *usl;
2573
2574 uwsgi_foreach(usl, uwsgi.mount_in_jail) {
2575 uwsgi_log("mounting \"%s\" (in-jail)...\n", usl->value);
2576 if (uwsgi_mount_hook(usl->value)) {
2577 exit(1);
2578 }
2579 }
2580
2581 uwsgi_foreach(usl, uwsgi.umount_in_jail) {
2582 uwsgi_log("un-mounting \"%s\" (in-jail)...\n", usl->value);
2583 if (uwsgi_umount_hook(usl->value)) {
2584 exit(1);
2585 }
2586 }
2587
2588 uwsgi_foreach(usl, uwsgi.exec_in_jail) {
2589 uwsgi_log("running \"%s\" (in-jail)...\n", usl->value);
2590 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
2591 if (ret != 0) {
2592 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
2593 exit(1);
2594 }
2595 }
2596
2597 uwsgi_foreach(usl, uwsgi.call_in_jail) {
2598 if (uwsgi_call_symbol(usl->value)) {
2599 uwsgi_log("unable to call function \"%s\"\n", usl->value);
2600 exit(1);
2601 }
2602 }
2603
2604
2605 uwsgi_file_write_do(uwsgi.file_write_list);
2606
2607 if (!uwsgi.master_as_root && !uwsgi.chown_socket && !uwsgi.drop_after_init && !uwsgi.drop_after_apps) {
2608 uwsgi_as_root();
2609 }
2610
2611 // wait for socket
2612 uwsgi_foreach(usl, uwsgi.wait_for_socket) {
2613 if (uwsgi_wait_for_socket(usl->value)) exit(1);
2614 }
2615
2616 if (uwsgi.logto2) {
2617 if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
2618 logto(uwsgi.logto2);
2619 }
2620 }
2621
2622 if (uwsgi.chdir) {
2623 uwsgi_log("chdir() to %s\n", uwsgi.chdir);
2624 if (chdir(uwsgi.chdir)) {
2625 uwsgi_error("chdir()");
2626 exit(1);
2627 }
2628 }
2629
2630 if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
2631 uwsgi_write_pidfile(uwsgi.pidfile2);
2632 }
2633
2634 if (!uwsgi.master_process && !uwsgi.command_mode) {
2635 uwsgi_log_initial("*** WARNING: you are running uWSGI without its master process manager ***\n");
2636 }
2637
2638 #ifdef RLIMIT_NPROC
2639 if (uwsgi.rl_nproc.rlim_max > 0) {
2640 uwsgi.rl_nproc.rlim_cur = uwsgi.rl_nproc.rlim_max;
2641 uwsgi_log_initial("limiting number of processes to %d...\n", (int) uwsgi.rl_nproc.rlim_max);
2642 if (setrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) {
2643 uwsgi_error("setrlimit()");
2644 }
2645 }
2646
2647 if (!getrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) {
2648 if (uwsgi.rl_nproc.rlim_cur != RLIM_INFINITY) {
2649 uwsgi_log_initial("your processes number limit is %d\n", (int) uwsgi.rl_nproc.rlim_cur);
2650 if ((int) uwsgi.rl_nproc.rlim_cur < uwsgi.numproc + uwsgi.master_process) {
2651 uwsgi.numproc = uwsgi.rl_nproc.rlim_cur - 1;
2652 uwsgi_log_initial("!!! number of workers adjusted to %d due to system limits !!!\n", uwsgi.numproc);
2653 }
2654 }
2655 }
2656 #endif
2657 #ifndef __OpenBSD__
2658
2659 if (uwsgi.rl.rlim_max > 0) {
2660 uwsgi.rl.rlim_cur = uwsgi.rl.rlim_max;
2661 uwsgi_log_initial("limiting address space of processes...\n");
2662 if (setrlimit(RLIMIT_AS, &uwsgi.rl)) {
2663 uwsgi_error("setrlimit()");
2664 }
2665 }
2666 if (uwsgi.prio != 0) {
2667 #ifdef __HAIKU__
2668 if (set_thread_priority(find_thread(NULL), uwsgi.prio) == B_BAD_THREAD_ID) {
2669 uwsgi_error("set_thread_priority()");
2670 #else
2671 if (setpriority(PRIO_PROCESS, 0, uwsgi.prio)) {
2672 uwsgi_error("setpriority()");
2673 #endif
2674
2675 }
2676 else {
2677 uwsgi_log_initial("scheduler priority set to %d\n", uwsgi.prio);
2678 }
2679 }
2680 if (!getrlimit(RLIMIT_AS, &uwsgi.rl)) {
2681 //check for overflow
2682 if (uwsgi.rl.rlim_max != (rlim_t) RLIM_INFINITY) {
2683 uwsgi_log_initial("your process address space limit is %lld bytes (%lld MB)\n", (long long) uwsgi.rl.rlim_max, (long long) uwsgi.rl.rlim_max / 1024 / 1024);
2684 }
2685 }
2686 #endif
2687
2688 uwsgi_log_initial("your memory page size is %d bytes\n", uwsgi.page_size);
2689
2690 // automatically fix options
2691 sanitize_args();
2692
2693
2694 if (uwsgi.requested_max_fd) {
2695 uwsgi.rl.rlim_cur = uwsgi.requested_max_fd;
2696 uwsgi.rl.rlim_max = uwsgi.requested_max_fd;
2697 if (setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
2698 uwsgi_error("setrlimit()");
2699 }
2700 }
2701
2702 if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
2703 uwsgi.max_fd = uwsgi.rl.rlim_cur;
2704 uwsgi_log_initial("detected max file descriptor number: %lu\n", (unsigned long) uwsgi.max_fd);
2705 }
2706
2707 // start the Emperor if needed
2708 if (!uwsgi.early_emperor && uwsgi.emperor) {
2709 uwsgi_emperor_start();
2710 }
2711
2712 // end of generic initialization
2713
2714
2715 // build mime.types dictionary
2716 if (uwsgi.build_mime_dict) {
2717 if (!uwsgi.mime_file)
2718 #ifdef __APPLE__
2719 uwsgi_string_new_list(&uwsgi.mime_file, "/etc/apache2/mime.types");
2720 #else
2721 uwsgi_string_new_list(&uwsgi.mime_file, "/etc/mime.types");
2722 #endif
2723 struct uwsgi_string_list *umd = uwsgi.mime_file;
2724 while (umd) {
2725 if (!access(umd->value, R_OK)) {
2726 uwsgi_build_mime_dict(umd->value);
2727 }
2728 else {
2729 uwsgi_log("!!! no %s file found !!!\n", umd->value);
2730 }
2731 umd = umd->next;
2732 }
2733 }
2734
2735 if (uwsgi.async > 1) {
2736 if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) {
2737 uwsgi_log_initial("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
2738 uwsgi.rl.rlim_cur = uwsgi.async;
2739 uwsgi.rl.rlim_max = uwsgi.async;
2740 if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
2741 uwsgi_log("max open files limit raised to %lu\n", (unsigned long) uwsgi.rl.rlim_cur);
2742 uwsgi.async = uwsgi.rl.rlim_cur;
2743 uwsgi.max_fd = uwsgi.rl.rlim_cur;
2744 }
2745 else {
2746 uwsgi.async = (int) uwsgi.max_fd;
2747 }
2748 }
2749 uwsgi_log_initial("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
2750 }
2751
2752 #ifdef UWSGI_DEBUG
2753 uwsgi_log("cores allocated...\n");
2754 #endif
2755
2756 if (uwsgi.vhost) {
2757 uwsgi_log_initial("VirtualHosting mode enabled.\n");
2758 }
2759
2760 // setup locking
2761 uwsgi_setup_locking();
2762 if (uwsgi.use_thunder_lock) {
2763 uwsgi_log_initial("thunder lock: enabled\n");
2764 }
2765 else {
2766 uwsgi_log_initial("thunder lock: disabled (you can enable it with --thunder-lock)\n");
2767 }
2768
2769 // allocate rpc structures
2770 uwsgi_rpc_init();
2771
2772 // initialize sharedareas
2773 uwsgi_sharedareas_init();
2774
2775 uwsgi.snmp_lock = uwsgi_lock_init("snmp");
2776
2777 // setup queue
2778 if (uwsgi.queue_size > 0) {
2779 uwsgi_init_queue();
2780 }
2781
2782 uwsgi_cache_create_all();
2783
2784 if (uwsgi.use_check_cache) {
2785 uwsgi.check_cache = uwsgi_cache_by_name(uwsgi.use_check_cache);
2786 if (!uwsgi.check_cache) {
2787 uwsgi_log("unable to find cache \"%s\"\n", uwsgi.use_check_cache);
2788 exit(1);
2789 }
2790 }
2791
2792 if (uwsgi.use_static_cache_paths) {
2793 if (uwsgi.static_cache_paths_name) {
2794 uwsgi.static_cache_paths = uwsgi_cache_by_name(uwsgi.static_cache_paths_name);
2795 if (!uwsgi.static_cache_paths) {
2796 uwsgi_log("unable to find cache \"%s\"\n", uwsgi.static_cache_paths_name);
2797 exit(1);
2798 }
2799 }
2800 else {
2801 if (!uwsgi.caches) {
2802 uwsgi_log("caching of static paths requires uWSGI caching !!!\n");
2803 exit(1);
2804 }
2805 uwsgi.static_cache_paths = uwsgi.caches;
2806 }
2807 }
2808
2809 // initialize the alarm subsystem
2810 uwsgi_alarms_init();
2811
2812 // initialize the exception handlers
2813 uwsgi_exception_setup_handlers();
2814
2815 // initialize socket protocols (do it after caching !!!)
2816 uwsgi_protocols_register();
2817
2818 /* plugin initialization */
2819 for (i = 0; i < uwsgi.gp_cnt; i++) {
2820 if (uwsgi.gp[i]->init) {
2821 uwsgi.gp[i]->init();
2822 }
2823 }
2824
2825 if (!uwsgi.no_server) {
2826
2827 // systemd/upstart/zerg socket activation
2828 if (!uwsgi.is_a_reload) {
2829 uwsgi_setup_systemd();
2830 uwsgi_setup_upstart();
2831 uwsgi_setup_zerg();
2832 uwsgi_setup_emperor();
2833 }
2834
2835
2836 //check for inherited sockets
2837 if (uwsgi.is_a_reload) {
2838 uwsgi_setup_inherited_sockets();
2839 }
2840
2841
2842 //now bind all the unbound sockets
2843 uwsgi_bind_sockets();
2844
2845 if (!uwsgi.master_as_root && !uwsgi.drop_after_init && !uwsgi.drop_after_apps) {
2846 uwsgi_as_root();
2847 }
2848
2849 // put listening socket in non-blocking state and set the protocol
2850 uwsgi_set_sockets_protocols();
2851
2852 }
2853
2854
2855 // initialize request plugin only if workers or master are available
2856 if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
2857 for (i = 0; i < 256; i++) {
2858 if (uwsgi.p[i]->init) {
2859 uwsgi.p[i]->init();
2860 }
2861 }
2862 }
2863
2864 if (!uwsgi.master_as_root && !uwsgi.drop_after_apps) {
2865 uwsgi_as_root();
2866 }
2867
2868
2869 /* gp/plugin initialization */
2870 for (i = 0; i < uwsgi.gp_cnt; i++) {
2871 if (uwsgi.gp[i]->post_init) {
2872 uwsgi.gp[i]->post_init();
2873 }
2874 }
2875
2876 // again check for workers/sockets...
2877 if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
2878 for (i = 0; i < 256; i++) {
2879 if (uwsgi.p[i]->post_init) {
2880 uwsgi.p[i]->post_init();
2881 }
2882 }
2883 }
2884
2885 uwsgi.current_wsgi_req = simple_current_wsgi_req;
2886
2887
2888 if (uwsgi.has_threads) {
2889 if (uwsgi.threads > 1)
2890 uwsgi.current_wsgi_req = threaded_current_wsgi_req;
2891 (void) pthread_attr_init(&uwsgi.threads_attr);
2892 if (uwsgi.threads_stacksize) {
2893 if (pthread_attr_setstacksize(&uwsgi.threads_attr, uwsgi.threads_stacksize * 1024) == 0) {
2894 uwsgi_log("threads stack size set to %luk\n", (unsigned long) uwsgi.threads_stacksize);
2895 }
2896 else {
2897 uwsgi_log("!!! unable to set requested threads stacksize !!!\n");
2898 }
2899 }
2900
2901 pthread_mutex_init(&uwsgi.lock_static, NULL);
2902
2903 // again check for workers/sockets...
2904 if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
2905 for (i = 0; i < 256; i++) {
2906 if (uwsgi.p[i]->enable_threads)
2907 uwsgi.p[i]->enable_threads();
2908 }
2909 }
2910 }
2911
2912 // users of the --loop option should know what they are doing... really...
2913 #ifndef UWSGI_DEBUG
2914 if (uwsgi.loop)
2915 goto unsafe;
2916 #endif
2917
2918 if (!uwsgi.sockets &&
2919 !ushared->gateways_cnt &&
2920 !uwsgi.no_server &&
2921 !uwsgi.udp_socket &&
2922 !uwsgi.emperor &&
2923 !uwsgi.command_mode &&
2924 !uwsgi.daemons_cnt &&
2925 !uwsgi.crons &&
2926 !uwsgi.spoolers &&
2927 !uwsgi.emperor_proxy
2928 #ifdef __linux__
2929 && !uwsgi.setns_socket
2930 #endif
2931 #ifdef UWSGI_SSL
2932 && !uwsgi.legions
2933 #endif
2934 ) {
2935 uwsgi_log("The -s/--socket option is missing and stdin is not a socket.\n");
2936 exit(1);
2937 }
2938 else if (!uwsgi.sockets && ushared->gateways_cnt && !uwsgi.no_server && !uwsgi.master_process) {
2939 // here we will have a zombie... sorry
2940 uwsgi_log("...you should enable the master process... really...\n");
2941 if (uwsgi.force_gateway) {
2942 struct uwsgi_gateway *ug = &ushared->gateways[0];
2943 ug->loop(0, ug->data);
2944 // when we are here the gateway is dead :(
2945 }
2946 exit(0);
2947 }
2948
2949 if (!uwsgi.sockets)
2950 uwsgi.numproc = 0;
2951
2952 if (uwsgi.command_mode) {
2953 uwsgi.sockets = NULL;
2954 uwsgi.numproc = 1;
2955 // hack to destroy the instance after command exit
2956 uwsgi.status.brutally_destroying = 1;
2957 }
2958
2959 #ifndef UWSGI_DEBUG
2960 unsafe:
2961 #endif
2962
2963 #ifdef UWSGI_DEBUG
2964 struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
2965 int so_bufsize;
2966 socklen_t so_bufsize_len;
2967 while (uwsgi_sock) {
2968 so_bufsize_len = sizeof(int);
2969 if (getsockopt(uwsgi_sock->fd, SOL_SOCKET, SO_RCVBUF, &so_bufsize, &so_bufsize_len)) {
2970 uwsgi_error("getsockopt()");
2971 }
2972 else {
2973 uwsgi_debug("uwsgi socket %d SO_RCVBUF size: %d\n", i, so_bufsize);
2974 }
2975
2976 so_bufsize_len = sizeof(int);
2977 if (getsockopt(uwsgi_sock->fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
2978 uwsgi_error("getsockopt()");
2979 }
2980 else {
2981 uwsgi_debug("uwsgi socket %d SO_SNDBUF size: %d\n", i, so_bufsize);
2982 }
2983 uwsgi_sock = uwsgi_sock->next;
2984 }
2985 #endif
2986
2987
2988 #ifndef UNBIT
2989 if (uwsgi.sockets)
2990 uwsgi_log("your server socket listen backlog is limited to %d connections\n", uwsgi.listen_queue);
2991 #endif
2992
2993 uwsgi_log("your mercy for graceful operations on workers is %d seconds\n", uwsgi.worker_reload_mercy);
2994
2995 if (uwsgi.crons) {
2996 struct uwsgi_cron *ucron = uwsgi.crons;
2997 while (ucron) {
2998 #ifdef UWSGI_SSL
2999 if (ucron->legion) {
3000 uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task for legion \"%s\"\n", ucron->command, ucron->legion);
3001 ucron = ucron->next;
3002 continue;
3003 }
3004 #endif
3005 uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task\n", ucron->command);
3006 ucron = ucron->next;
3007 }
3008 }
3009
3010
3011 // initialize post buffering values
3012 if (uwsgi.post_buffering > 0)
3013 uwsgi_setup_post_buffering();
3014
3015 // initialize workers/master shared memory segments
3016 uwsgi_setup_workers();
3017
3018 // create signal pipes if master is enabled
3019 if (uwsgi.master_process) {
3020 for (i = 1; i <= uwsgi.numproc; i++) {
3021 create_signal_pipe(uwsgi.workers[i].signal_pipe);
3022 }
3023 }
3024
3025 // set masterpid
3026 uwsgi.mypid = getpid();
3027 masterpid = uwsgi.mypid;
3028 uwsgi.workers[0].pid = masterpid;
3029
3030 // initialize mules and farms
3031 uwsgi_setup_mules_and_farms();
3032
3033 if (uwsgi.command_mode) {
3034 uwsgi_log("*** Operational MODE: command ***\n");
3035 }
3036 else if (!uwsgi.numproc) {
3037 uwsgi_log("*** Operational MODE: no-workers ***\n");
3038 }
3039 else if (uwsgi.threads > 1) {
3040 if (uwsgi.numproc > 1) {
3041 uwsgi_log("*** Operational MODE: preforking+threaded ***\n");
3042 }
3043 else {
3044 uwsgi_log("*** Operational MODE: threaded ***\n");
3045 }
3046 }
3047 else if (uwsgi.async > 1) {
3048 if (uwsgi.numproc > 1) {
3049 uwsgi_log("*** Operational MODE: preforking+async ***\n");
3050 }
3051 else {
3052 uwsgi_log("*** Operational MODE: async ***\n");
3053 }
3054 }
3055 else if (uwsgi.numproc > 1) {
3056 uwsgi_log("*** Operational MODE: preforking ***\n");
3057 }
3058 else {
3059 uwsgi_log("*** Operational MODE: single process ***\n");
3060 }
3061
3062 // set a default request structure (for loading apps...)
3063 uwsgi.wsgi_req = &uwsgi.workers[0].cores[0].req;
3064
3065 // ok, let's initialize the metrics subsystem
3066 uwsgi_setup_metrics();
3067
3068 // cores are allocated, lets allocate logformat (if required)
3069 if (uwsgi.logformat) {
3070 uwsgi_build_log_format(uwsgi.logformat);
3071 uwsgi.logit = uwsgi_logit_lf;
3072 // TODO check it
3073 //if (uwsgi.logformat_strftime) {
3074 //uwsgi.logit = uwsgi_logit_lf_strftime;
3075 //}
3076 uwsgi.logvectors = uwsgi_malloc(sizeof(struct iovec *) * uwsgi.cores);
3077 for (j = 0; j < uwsgi.cores; j++) {
3078 uwsgi.logvectors[j] = uwsgi_malloc(sizeof(struct iovec) * uwsgi.logformat_vectors);
3079 uwsgi.logvectors[j][uwsgi.logformat_vectors - 1].iov_base = "\n";
3080 uwsgi.logvectors[j][uwsgi.logformat_vectors - 1].iov_len = 1;
3081 }
3082 }
3083
3084 // initialize locks and socket as soon as possible, as the master could enqueue tasks
3085 if (uwsgi.spoolers != NULL) {
3086 create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
3087 struct uwsgi_spooler *uspool = uwsgi.spoolers;
3088 while (uspool) {
3089 // lock is required even in EXTERNAL mode
3090 uspool->lock = uwsgi_lock_init(uwsgi_concat2("spooler on ", uspool->dir));
3091 if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
3092 goto next;
3093 create_signal_pipe(uspool->signal_pipe);
3094 next:
3095 uspool = uspool->next;
3096 }
3097 }
3098
3099 // preinit apps (create the language environment)
3100 for (i = 0; i < 256; i++) {
3101 if (uwsgi.p[i]->preinit_apps) {
3102 uwsgi.p[i]->preinit_apps();
3103 }
3104 }
3105
3106 for (i = 0; i < uwsgi.gp_cnt; i++) {
3107 if (uwsgi.gp[i]->preinit_apps) {
3108 uwsgi.gp[i]->preinit_apps();
3109 }
3110 }
3111
3112 //init apps hook (if not lazy)
3113 if (!uwsgi.lazy && !uwsgi.lazy_apps) {
3114 uwsgi_init_all_apps();
3115 }
3116
3117 // Register uwsgi atexit plugin callbacks after all applications have
3118 // been loaded. This ensures plugin atexit callbacks are called prior
3119 // to application registered atexit callbacks.
3120 atexit(uwsgi_plugins_atexit);
3121
3122 if (!uwsgi.master_as_root) {
3123 uwsgi_as_root();
3124 }
3125
3126 // postinit apps (setup specific features after app initialization)
3127 for (i = 0; i < 256; i++) {
3128 if (uwsgi.p[i]->postinit_apps) {
3129 uwsgi.p[i]->postinit_apps();
3130 }
3131 }
3132
3133 for (i = 0; i < uwsgi.gp_cnt; i++) {
3134 if (uwsgi.gp[i]->postinit_apps) {
3135 uwsgi.gp[i]->postinit_apps();
3136 }
3137 }
3138
3139 // initialize after_request hooks
3140 uwsgi_foreach(usl, uwsgi.after_request_hooks) {
3141 usl->custom_ptr = dlsym(RTLD_DEFAULT, usl->value);
3142 if (!usl->custom_ptr) {
3143 uwsgi_log("unable to find symbol/function \"%s\"\n", usl->value);
3144 exit(1);
3145 }
3146 uwsgi_log("added \"%s(struct wsgi_request *)\" to the after-request chain\n", usl->value);
3147 }
3148
3149 if (uwsgi.daemonize2) {
3150 masterpid = uwsgi_daemonize2();
3151 }
3152
3153 if (uwsgi.no_server) {
3154 uwsgi_log("no-server mode requested. Goodbye.\n");
3155 exit(0);
3156 }
3157
3158
3159 if (!uwsgi.master_process && uwsgi.numproc == 0) {
3160 exit(0);
3161 }
3162
3163 if (!uwsgi.single_interpreter && uwsgi.numproc > 0) {
3164 uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n");
3165 }
3166
3167 // check for request plugins, and eventually print a warning
3168 int rp_available = 0;
3169 for (i = 0; i < 256; i++) {
3170 if (uwsgi.p[i] != &unconfigured_plugin) {
3171 rp_available = 1;
3172 break;
3173 }
3174 }
3175 if (!rp_available && !ushared->gateways_cnt) {
3176 uwsgi_log("!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!\n");
3177 uwsgi_log("no request plugin is loaded, you will not be able to manage requests.\n");
3178 uwsgi_log("you may need to install the package for your language of choice, or simply load it with --plugin.\n");
3179 uwsgi_log("!!!!!!!!!!! END OF WARNING !!!!!!!!!!\n");
3180 }
3181
3182 #ifdef __linux__
3183 #ifdef MADV_MERGEABLE
3184 if (uwsgi.linux_ksm > 0) {
3185 uwsgi_log("[uwsgi-KSM] enabled with frequency: %d\n", uwsgi.linux_ksm);
3186 }
3187 #endif
3188 #endif
3189
3190 if (uwsgi.master_process) {
3191 // initialize threads with shared state
3192 uwsgi_alarm_thread_start();
3193 uwsgi_exceptions_handler_thread_start();
3194 // initialize a mutex to avoid glibc problem with pthread+fork()
3195 if (uwsgi.threaded_logger) {
3196 pthread_mutex_init(&uwsgi.threaded_logger_lock, NULL);
3197 }
3198
3199 if (uwsgi.is_a_reload) {
3200 uwsgi_log("gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
3201 }
3202 else {
3203 uwsgi_log("spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
3204 }
3205 }
3206
3207
3208
3209 // security in multiuser environment: allow only a subset of modifiers
3210 if (uwsgi.allowed_modifiers) {
3211 for (i = 0; i < 256; i++) {
3212 if (!uwsgi_list_has_num(uwsgi.allowed_modifiers, i)) {
3213 uwsgi.p[i]->request = unconfigured_hook;
3214 uwsgi.p[i]->after_request = unconfigured_after_hook;
3215 }
3216 }
3217 }
3218
3219 // master fixup
3220 for (i = 0; i < 256; i++) {
3221 if (uwsgi.p[i]->master_fixup) {
3222 uwsgi.p[i]->master_fixup(0);
3223 }
3224 }
3225
3226
3227
3228 struct uwsgi_spooler *uspool = uwsgi.spoolers;
3229 while (uspool) {
3230 if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
3231 goto next2;
3232 uspool->pid = spooler_start(uspool);
3233 next2:
3234 uspool = uspool->next;
3235 }
3236
3237 if (!uwsgi.master_process) {
3238 if (uwsgi.numproc == 1) {
3239 uwsgi_log("spawned uWSGI worker 1 (and the only) (pid: %d, cores: %d)\n", masterpid, uwsgi.cores);
3240 }
3241 else {
3242 uwsgi_log("spawned uWSGI worker 1 (pid: %d, cores: %d)\n", masterpid, uwsgi.cores);
3243 }
3244 uwsgi.workers[1].pid = masterpid;
3245 uwsgi.workers[1].id = 1;
3246 uwsgi.workers[1].last_spawn = uwsgi_now();
3247 uwsgi.workers[1].manage_next_request = 1;
3248 uwsgi.mywid = 1;
3249 uwsgi.respawn_delta = uwsgi_now();
3250 }
3251 else {
3252 // setup internal signalling system
3253 create_signal_pipe(uwsgi.shared->worker_signal_pipe);
3254 uwsgi.signal_socket = uwsgi.shared->worker_signal_pipe[1];
3255 }
3256
3257 // uWSGI is ready
3258 uwsgi_notify_ready();
3259 uwsgi.current_time = uwsgi_now();
3260
3261 // here we spawn the workers...
3262 if (!uwsgi.status.is_cheap) {
3263 if (uwsgi.cheaper && uwsgi.cheaper_count) {
3264 int nproc = uwsgi.cheaper_initial;
3265 if (!nproc)
3266 nproc = uwsgi.cheaper_count;
3267 for (i = 1; i <= uwsgi.numproc; i++) {
3268 if (i <= nproc) {
3269 if (uwsgi_respawn_worker(i))
3270 break;
3271 uwsgi.respawn_delta = uwsgi_now();
3272 }
3273 else {
3274 uwsgi.workers[i].cheaped = 1;
3275 }
3276 }
3277 }
3278 else {
3279 for (i = 2 - uwsgi.master_process; i < uwsgi.numproc + 1; i++) {
3280 if (uwsgi_respawn_worker(i))
3281 break;
3282 uwsgi.respawn_delta = uwsgi_now();
3283 }
3284 }
3285 }
3286
3287 if (uwsgi.safe_pidfile2 && !uwsgi.is_a_reload) {
3288 uwsgi_write_pidfile_explicit(uwsgi.safe_pidfile2, masterpid);
3289 }
3290
3291 // END OF INITIALIZATION
3292 return 0;
3293
3294 }
3295
3296 // this lives in a worker thread and periodically scans for memory usage
3297 // when evil reloaders are in place
3298 void *mem_collector(void *foobar) {
3299 // block all signals
3300 sigset_t smask;
3301 sigfillset(&smask);
3302 pthread_sigmask(SIG_BLOCK, &smask, NULL);
3303 uwsgi_log_verbose("mem-collector thread started for worker %d\n", uwsgi.mywid);
3304 for(;;) {
3305 sleep(uwsgi.mem_collector_freq);
3306 uint64_t rss = 0, vsz = 0;
3307 get_memusage(&rss, &vsz);
3308 uwsgi.workers[uwsgi.mywid].rss_size = rss;
3309 uwsgi.workers[uwsgi.mywid].vsz_size = vsz;
3310 }
3311 return NULL;
3312 }
3313
3314 int uwsgi_run() {
3315
3316 // !!! from now on, we could be in the master or in a worker !!!
3317 int i;
3318
3319 if (getpid() == masterpid && uwsgi.master_process == 1) {
3320 #ifdef UWSGI_AS_SHARED_LIBRARY
3321 int ml_ret = master_loop(uwsgi.argv, uwsgi.environ);
3322 if (ml_ret == -1) {
3323 return 0;
3324 }
3325 #else
3326 (void) master_loop(uwsgi.argv, uwsgi.environ);
3327 #endif
3328 //from now on the process is a real worker
3329 }
3330
3331 #if defined(__linux__) && defined(PR_SET_PDEATHSIG)
3332 // avoid workers running without master at all costs !!! (dangerous)
3333 if (uwsgi.master_process && uwsgi.no_orphans) {
3334 if (prctl(PR_SET_PDEATHSIG, SIGKILL)) {
3335 uwsgi_error("uwsgi_run()/prctl()");
3336 }
3337 }
3338 #endif
3339
3340 if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
3341 pthread_t t;
3342 pthread_create(&t, NULL, mem_collector, NULL);
3343 }
3344
3345
3346 // eventually maps (or disable) sockets for the worker
3347 uwsgi_map_sockets();
3348
3349 // eventually set cpu affinity poilicies (OS-dependent)
3350 uwsgi_set_cpu_affinity();
3351
3352 if (uwsgi.worker_exec) {
3353 char *w_argv[2];
3354 w_argv[0] = uwsgi.worker_exec;
3355 w_argv[1] = NULL;
3356
3357 uwsgi.sockets->arg &= (~O_NONBLOCK);
3358 if (fcntl(uwsgi.sockets->fd, F_SETFL, uwsgi.sockets->arg) < 0) {
3359 uwsgi_error("fcntl()");
3360 exit(1);
3361 }
3362
3363 if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) {
3364 if (dup2(uwsgi.sockets->fd, 0) < 0) {
3365 uwsgi_error("dup2()");
3366 }
3367 }
3368 execvp(w_argv[0], w_argv);
3369 // never here
3370 uwsgi_error("execvp()");
3371 exit(1);
3372 }
3373
3374 if (uwsgi.master_as_root) {
3375 uwsgi_as_root();
3376 }
3377
3378 // set default wsgi_req (for loading apps);
3379 uwsgi.wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req;
3380
3381 if (uwsgi.offload_threads > 0) {
3382 uwsgi.offload_thread = uwsgi_malloc(sizeof(struct uwsgi_thread *) * uwsgi.offload_threads);
3383 for(i=0;i<uwsgi.offload_threads;i++) {
3384 uwsgi.offload_thread[i] = uwsgi_offload_thread_start();
3385 if (!uwsgi.offload_thread[i]) {
3386 uwsgi_log("unable to start offload thread %d for worker %d !!!\n", i, uwsgi.mywid);
3387 uwsgi.offload_threads = i;
3388 break;
3389 }
3390 }
3391 uwsgi_log("spawned %d offload threads for uWSGI worker %d\n", uwsgi.offload_threads, uwsgi.mywid);
3392 }
3393
3394 // must be run before running apps
3395 for (i = 0; i < 256; i++) {
3396 if (uwsgi.p[i]->post_fork) {
3397 uwsgi.p[i]->post_fork();
3398 }
3399 }
3400
3401 for (i = 0; i < uwsgi.gp_cnt; i++) {
3402 if (uwsgi.gp[i]->post_fork) {
3403 uwsgi.gp[i]->post_fork();
3404 }
3405 }
3406
3407 uwsgi_hooks_run(uwsgi.hook_post_fork, "post-fork", 1);
3408
3409 if (uwsgi.worker_exec2) {
3410 char *w_argv[2];
3411 w_argv[0] = uwsgi.worker_exec2;
3412 w_argv[1] = NULL;
3413
3414 uwsgi.sockets->arg &= (~O_NONBLOCK);
3415 if (fcntl(uwsgi.sockets->fd, F_SETFL, uwsgi.sockets->arg) < 0) {
3416 uwsgi_error("fcntl()");
3417 exit(1);
3418 }
3419
3420 if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) {
3421 if (dup2(uwsgi.sockets->fd, 0) < 0) {
3422 uwsgi_error("dup2()");
3423 }
3424 }
3425 execvp(w_argv[0], w_argv);
3426 // never here
3427 uwsgi_error("execvp()");
3428 exit(1);
3429 }
3430
3431 // must be run before running apps
3432
3433 // check for worker override
3434 for (i = 0; i < 256; i++) {
3435 if (uwsgi.p[i]->worker) {
3436 if (uwsgi.p[i]->worker()) {
3437 _exit(0);
3438 }
3439 }
3440 }
3441
3442 for (i = 0; i < uwsgi.gp_cnt; i++) {
3443 if (uwsgi.gp[i]->worker) {
3444 if (uwsgi.gp[i]->worker()) {
3445 _exit(0);
3446 }
3447 }
3448 }
3449
3450 uwsgi_worker_run();
3451 // never here
3452 _exit(0);
3453
3454 }
3455
3456 void uwsgi_worker_run() {
3457
3458 int i;
3459
3460 if (uwsgi.lazy || uwsgi.lazy_apps) {
3461 uwsgi_init_all_apps();
3462 }
3463
3464 // some apps could be mounted only on specific workers
3465 uwsgi_init_worker_mount_apps();
3466
3467 if (uwsgi.async > 1) {
3468 // a stack of unused cores
3469 uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
3470
3471 // fill it with default values
3472 for (i = 0; i < uwsgi.async; i++) {
3473 uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
3474 }
3475
3476 // the first available core is the last one
3477 uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
3478 }
3479
3480 // setup UNIX signals for the worker
3481 if (uwsgi.harakiri_options.workers > 0 && !uwsgi.master_process) {
3482 signal(SIGALRM, (void *) &harakiri);
3483 }
3484 uwsgi_unix_signal(SIGHUP, gracefully_kill);
3485 uwsgi_unix_signal(SIGINT, end_me);
3486 uwsgi_unix_signal(SIGTERM, end_me);
3487
3488 uwsgi_unix_signal(SIGUSR1, stats);
3489 signal(SIGUSR2, (void *) &what_i_am_doing);
3490 if (!uwsgi.ignore_sigpipe) {
3491 signal(SIGPIPE, (void *) &warn_pipe);
3492 }
3493
3494 // worker initialization done
3495
3496 // run fixup handler
3497 for (i = 0; i < 256; i++) {
3498 if (uwsgi.p[i]->fixup) {
3499 uwsgi.p[i]->fixup();
3500 }
3501 }
3502
3503 if (uwsgi.chdir2) {
3504 uwsgi_log("chdir() to %s\n", uwsgi.chdir2);
3505 if (chdir(uwsgi.chdir2)) {
3506 uwsgi_error("chdir()");
3507 exit(1);
3508 }
3509 }
3510
3511
3512 //re - initialize wsgi_req(can be full of init_uwsgi_app data)
3513 for (i = 0; i < uwsgi.cores; i++) {
3514 memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
3515 uwsgi.workers[uwsgi.mywid].cores[i].req.async_id = i;
3516 }
3517
3518
3519 // eventually remap plugins
3520 if (uwsgi.remap_modifier) {
3521 char *map, *ctx = NULL;
3522 uwsgi_foreach_token(uwsgi.remap_modifier, ",", map, ctx) {
3523 char *colon = strchr(map, ':');
3524 if (colon) {
3525 colon[0] = 0;
3526 int rm_src = atoi(map);
3527 int rm_dst = atoi(colon + 1);
3528 uwsgi.p[rm_dst]->request = uwsgi.p[rm_src]->request;
3529 uwsgi.p[rm_dst]->after_request = uwsgi.p[rm_src]->after_request;
3530 }
3531 }
3532 }
3533
3534
3535 if (uwsgi.cores > 1) {
3536 uwsgi.workers[uwsgi.mywid].cores[0].thread_id = pthread_self();
3537 pthread_mutex_init(&uwsgi.six_feet_under_lock, NULL);
3538 }
3539
3540 uwsgi_ignition();
3541
3542 // never here
3543 exit(0);
3544
3545 }
3546
3547
3548 void uwsgi_ignition() {
3549
3550 int i;
3551
3552 for (i = 0; i < 256; i++) {
3553 if (uwsgi.p[i]->hijack_worker) {
3554 uwsgi.p[i]->hijack_worker();
3555 }
3556 }
3557
3558 for (i = 0; i < uwsgi.gp_cnt; i++) {
3559 if (uwsgi.gp[i]->hijack_worker) {
3560 uwsgi.gp[i]->hijack_worker();
3561 }
3562 }
3563
3564 // create a pthread key, storing per-thread wsgi_request structure
3565 if (uwsgi.threads > 1) {
3566 if (pthread_key_create(&uwsgi.tur_key, NULL)) {
3567 uwsgi_error("pthread_key_create()");
3568 exit(1);
3569 }
3570 }
3571
3572 // mark the worker as "accepting" (this is a mark used by chain reloading)
3573 uwsgi.workers[uwsgi.mywid].accepting = 1;
3574 // ready to accept request, if i am a vassal signal Emperor about it
3575 if (uwsgi.has_emperor && uwsgi.mywid == 1) {
3576 char byte = 5;
3577 if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
3578 uwsgi_error("emperor-i-am-ready-to-accept/write()");
3579 uwsgi_log_verbose("lost communication with the Emperor, goodbye...\n");
3580 gracefully_kill_them_all(0);
3581 exit(1);
3582 }
3583 }
3584
3585 // run accepting hooks
3586 uwsgi_hooks_run(uwsgi.hook_accepting, "accepting", 1);
3587 if (uwsgi.workers[uwsgi.mywid].respawn_count == 1) {
3588 uwsgi_hooks_run(uwsgi.hook_accepting_once, "accepting-once", 1);
3589 }
3590
3591 if (uwsgi.mywid == 1) {
3592 uwsgi_hooks_run(uwsgi.hook_accepting1, "accepting1", 1);
3593 if (uwsgi.workers[uwsgi.mywid].respawn_count == 1) {
3594 uwsgi_hooks_run(uwsgi.hook_accepting1_once, "accepting1-once", 1);
3595 }
3596 }
3597
3598 if (uwsgi.loop) {
3599 void (*u_loop) (void) = uwsgi_get_loop(uwsgi.loop);
3600 if (!u_loop) {
3601 uwsgi_log("unavailable loop engine !!!\n");
3602 exit(1);
3603 }
3604 if (uwsgi.mywid == 1) {
3605 uwsgi_log("*** running %s loop engine [addr:%p] ***\n", uwsgi.loop, u_loop);
3606 }
3607 u_loop();
3608 uwsgi_log("your loop engine died. R.I.P.\n");
3609 }
3610 else {
3611 if (uwsgi.async < 2) {
3612 simple_loop();
3613 }
3614 else {
3615 async_loop();
3616 }
3617 }
3618
3619 // end of the process...
3620 end_me(0);
3621 }
3622
3623 /*
3624
3625 what happens here ?
3626
3627 we transform the uwsgi_option structure to a struct option
3628 for passing it to getopt_long
3629 A short options string is built.
3630
3631 This function could be called multiple times, so it will free previous areas
3632
3633 */
3634
3635 void build_options() {
3636
3637 int options_count = 0;
3638 int pos = 0;
3639 int i;
3640 // first count the base options
3641
3642 struct uwsgi_option *op = uwsgi_base_options;
3643 while (op->name) {
3644 options_count++;
3645 op++;
3646 }
3647
3648 for (i = 0; i < 256; i++) {
3649 if (uwsgi.p[i]->options) {
3650 options_count += uwsgi_count_options(uwsgi.p[i]->options);
3651 }
3652 }
3653
3654 for (i = 0; i < uwsgi.gp_cnt; i++) {
3655 if (uwsgi.gp[i]->options) {
3656 options_count += uwsgi_count_options(uwsgi.gp[i]->options);
3657 }
3658 }
3659
3660 // add custom options
3661 struct uwsgi_custom_option *uco = uwsgi.custom_options;
3662 while (uco) {
3663 options_count++;
3664 uco = uco->next;
3665 }
3666
3667 if (uwsgi.options)
3668 free(uwsgi.options);
3669
3670
3671 // rebuild uwsgi.options area
3672 uwsgi.options = uwsgi_calloc(sizeof(struct uwsgi_option) * (options_count + 1));
3673
3674 op = uwsgi_base_options;
3675 while (op->name) {
3676 memcpy(&uwsgi.options[pos], op, sizeof(struct uwsgi_option));
3677 pos++;
3678 op++;
3679 }
3680
3681 for (i = 0; i < 256; i++) {
3682 if (uwsgi.p[i]->options) {
3683 int c = uwsgi_count_options(uwsgi.p[i]->options);
3684 memcpy(&uwsgi.options[pos], uwsgi.p[i]->options, sizeof(struct uwsgi_option) * c);
3685 pos += c;
3686 }
3687 }
3688
3689 for (i = 0; i < uwsgi.gp_cnt; i++) {
3690 if (uwsgi.gp[i]->options) {
3691 int c = uwsgi_count_options(uwsgi.gp[i]->options);
3692 memcpy(&uwsgi.options[pos], uwsgi.gp[i]->options, sizeof(struct uwsgi_option) * c);
3693 pos += c;
3694 }
3695 }
3696
3697 uco = uwsgi.custom_options;
3698 while (uco) {
3699 uwsgi.options[pos].name = uco->name;
3700 if (uco->has_args) {
3701 uwsgi.options[pos].type = required_argument;
3702 }
3703 else {
3704 uwsgi.options[pos].type = no_argument;
3705 }
3706 // custom options should be immediate
3707 uwsgi.options[pos].flags = UWSGI_OPT_IMMEDIATE;
3708 // help shows the option definition
3709 uwsgi.options[pos].help = uco->value;
3710 uwsgi.options[pos].data = uco;
3711 uwsgi.options[pos].func = uwsgi_opt_custom;
3712
3713 pos++;
3714 uco = uco->next;
3715 }
3716
3717
3718 pos = 0;
3719
3720 if (uwsgi.long_options)
3721 free(uwsgi.long_options);
3722
3723 uwsgi.long_options = uwsgi_calloc(sizeof(struct option) * (options_count + 1));
3724
3725 if (uwsgi.short_options)
3726 free(uwsgi.short_options);
3727
3728 uwsgi.short_options = uwsgi_calloc((options_count * 3) + 1);
3729
3730 // build long_options (this time with custom_options)
3731 op = uwsgi.options;
3732 while (op->name) {
3733 uwsgi.long_options[pos].name = op->name;
3734 uwsgi.long_options[pos].has_arg = op->type;
3735 uwsgi.long_options[pos].flag = 0;
3736 // add 1000 to avoid short_options collision
3737 uwsgi.long_options[pos].val = 1000 + pos;
3738 if (op->shortcut) {
3739 char shortcut = (char) op->shortcut;
3740 // avoid duplicates in short_options
3741 if (!strchr(uwsgi.short_options, shortcut)) {
3742 strncat(uwsgi.short_options, &shortcut, 1);
3743 if (op->type == optional_argument) {
3744 strcat(uwsgi.short_options, "::");
3745 }
3746 else if (op->type == required_argument) {
3747 strcat(uwsgi.short_options, ":");
3748 }
3749 }
3750 }
3751 op++;
3752 pos++;
3753 }
3754 }
3755
3756 /*
3757
3758 this function builds the help output from the uwsgi.options structure
3759
3760 */
3761 void uwsgi_help(char *opt, char *val, void *none) {
3762
3763 size_t max_size = 0;
3764
3765 fprintf(stdout, "Usage: %s [options...]\n", uwsgi.binary_path);
3766
3767 struct uwsgi_option *op = uwsgi.options;
3768 while (op && op->name) {
3769 if (strlen(op->name) > max_size) {
3770 max_size = strlen(op->name);
3771 }
3772 op++;
3773 }
3774
3775 max_size++;
3776
3777 op = uwsgi.options;
3778 while (op && op->name) {
3779 if (op->shortcut) {
3780 fprintf(stdout, " -%c|--%-*s %s\n", op->shortcut, (int) max_size - 3, op->name, op->help);
3781 }
3782 else {
3783 fprintf(stdout, " --%-*s %s\n", (int) max_size, op->name, op->help);
3784 }
3785 op++;
3786 }
3787
3788 exit(0);
3789 }
3790
3791 /*
3792
3793 initialize all apps
3794
3795 */
3796 void uwsgi_init_all_apps() {
3797
3798 int i, j;
3799
3800 uwsgi_hooks_run(uwsgi.hook_pre_app, "pre app", 1);
3801
3802 // now run the pre-app scripts
3803 struct uwsgi_string_list *usl = uwsgi.exec_pre_app;
3804 while (usl) {
3805 uwsgi_log("running \"%s\" (pre app)...\n", usl->value);
3806 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
3807 if (ret != 0) {
3808 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
3809 exit(1);
3810 }
3811 usl = usl->next;
3812 }
3813
3814 uwsgi_foreach(usl, uwsgi.call_pre_app) {
3815 if (uwsgi_call_symbol(usl->value)) {
3816 uwsgi_log("unable to call function \"%s\"\n", usl->value);
3817 exit(1);
3818 }
3819 }
3820
3821
3822 for (i = 0; i < 256; i++) {
3823 if (uwsgi.p[i]->init_apps) {
3824 uwsgi.p[i]->init_apps();
3825 }
3826 }
3827
3828 for (i = 0; i < uwsgi.gp_cnt; i++) {
3829 if (uwsgi.gp[i]->init_apps) {
3830 uwsgi.gp[i]->init_apps();
3831 }
3832 }
3833
3834 struct uwsgi_string_list *app_mps = uwsgi.mounts;
3835 while (app_mps) {
3836 char *what = strchr(app_mps->value, '=');
3837 if (what) {
3838 what[0] = 0;
3839 what++;
3840 for (j = 0; j < 256; j++) {
3841 if (uwsgi.p[j]->mount_app) {
3842 uwsgi_log("mounting %s on %s\n", what, app_mps->value);
3843 if (uwsgi.p[j]->mount_app(app_mps->value, what) != -1)
3844 break;
3845 }
3846 }
3847 what--;
3848 what[0] = '=';
3849 }
3850 else {
3851 uwsgi_log("invalid mountpoint: %s\n", app_mps->value);
3852 exit(1);
3853 }
3854 app_mps = app_mps->next;
3855 }
3856
3857 // no app initialized and virtualhosting enabled
3858 if (uwsgi_apps_cnt == 0 && uwsgi.numproc > 0 && !uwsgi.command_mode) {
3859 if (uwsgi.need_app) {
3860 if (!uwsgi.lazy)
3861 uwsgi_log("*** no app loaded. GAME OVER ***\n");
3862 if (uwsgi.lazy_apps) {
3863 if (uwsgi.master_process) {
3864 if (kill(uwsgi.workers[0].pid, SIGINT)) {
3865 uwsgi_error("kill()");
3866 }
3867 }
3868 }
3869 exit(UWSGI_FAILED_APP_CODE);
3870 }
3871 else {
3872 uwsgi_log("*** no app loaded. going in full dynamic mode ***\n");
3873 }
3874 }
3875
3876 uwsgi_hooks_run(uwsgi.hook_post_app, "post app", 1);
3877
3878 usl = uwsgi.exec_post_app;
3879 while (usl) {
3880 uwsgi_log("running \"%s\" (post app)...\n", usl->value);
3881 int ret = uwsgi_run_command_and_wait(NULL, usl->value);
3882 if (ret != 0) {
3883 uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
3884 exit(1);
3885 }
3886 usl = usl->next;
3887 }
3888
3889 uwsgi_foreach(usl, uwsgi.call_post_app) {
3890 if (uwsgi_call_symbol(usl->value)) {
3891 uwsgi_log("unable to call function \"%s\"\n", usl->value);
3892 }
3893 }
3894
3895 }
3896
3897 void uwsgi_init_worker_mount_apps() {
3898 /*
3899 int i,j;
3900 for (i = 0; i < uwsgi.mounts_cnt; i++) {
3901 char *what = strchr(uwsgi.mounts[i], '=');
3902 if (what) {
3903 what[0] = 0;
3904 what++;
3905 for (j = 0; j < 256; j++) {
3906 if (uwsgi.p[j]->mount_app) {
3907 if (!uwsgi_startswith(uwsgi.mounts[i], "worker://", 9)) {
3908 uwsgi_log("mounting %s on %s\n", what, uwsgi.mounts[i]+9);
3909 if (uwsgi.p[j]->mount_app(uwsgi.mounts[i] + 9, what, 1) != -1)
3910 break;
3911 }
3912 }
3913 }
3914 what--;
3915 what[0] = '=';
3916 }
3917 else {
3918 uwsgi_log("invalid mountpoint: %s\n", uwsgi.mounts[i]);
3919 exit(1);
3920 }
3921 }
3922 */
3923
3924 }
3925
3926 void uwsgi_opt_true(char *opt, char *value, void *key) {
3927
3928 int *ptr = (int *) key;
3929 *ptr = 1;
3930 if (value) {
3931 if (!strcasecmp("false", value) || !strcasecmp("off", value) || !strcasecmp("no", value) || !strcmp("0", value)) {
3932 *ptr = 0;
3933 }
3934 }
3935 }
3936
3937 void uwsgi_opt_false(char *opt, char *value, void *key) {
3938
3939 int *ptr = (int *) key;
3940 *ptr = 0;
3941 if (value) {
3942 if (!strcasecmp("false", value) || !strcasecmp("off", value) || !strcasecmp("no", value) || !strcmp("0", value)) {
3943 *ptr = 1;
3944 }
3945 }
3946 }
3947
3948 void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
3949 gid_t gid = 0;
3950 if (is_a_number(value)) gid = atoi(value);
3951 if (gid == 0) {
3952 struct group *ugroup = getgrnam(value);
3953 if (ugroup)
3954 gid = ugroup->gr_gid;
3955 }
3956 if (gid <= 0) {
3957 uwsgi_log("uwsgi_opt_set_immediate_gid(): invalid gid %d\n", (int) gid);
3958 exit(1);
3959 }
3960 if (setgid(gid)) {
3961 uwsgi_error("uwsgi_opt_set_immediate_gid()/setgid()");
3962 exit(1);
3963 }
3964
3965 if (setgroups(0, NULL)) {
3966 uwsgi_error("uwsgi_opt_set_immediate_gid()/setgroups()");
3967 exit(1);
3968 }
3969
3970 gid = getgid();
3971 if (!gid) {
3972 exit(1);
3973 }
3974 uwsgi_log("immediate gid: %d\n", (int) gid);
3975 }
3976
3977
3978 void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
3979 uid_t uid = 0;
3980 if (is_a_number(value)) uid = atoi(value);
3981 if (uid == 0) {
3982 struct passwd *upasswd = getpwnam(value);
3983 if (upasswd)
3984 uid = upasswd->pw_uid;
3985 }
3986 if (uid <= 0) {
3987 uwsgi_log("uwsgi_opt_set_immediate_uid(): invalid uid %d\n", uid);
3988 exit(1);
3989 }
3990 if (setuid(uid)) {
3991 uwsgi_error("uwsgi_opt_set_immediate_uid()/setuid()");
3992 exit(1);
3993 }
3994
3995 uid = getuid();
3996 if (!uid) {
3997 exit(1);
3998 }
3999 uwsgi_log("immediate uid: %d\n", (int) uid);
4000 }
4001
4002 void uwsgi_opt_safe_fd(char *opt, char *value, void *foobar) {
4003 int fd = atoi(value);
4004 if (fd < 0) {
4005 uwsgi_log("invalid file descriptor: %d\n", fd);
4006 exit(1);
4007 }
4008 uwsgi_add_safe_fd(fd);
4009 }
4010
4011 void uwsgi_opt_set_int(char *opt, char *value, void *key) {
4012 int *ptr = (int *) key;
4013 if (value) {
4014 *ptr = atoi((char *) value);
4015 }
4016 else {
4017 *ptr = 1;
4018 }
4019
4020 if (*ptr < 0) {
4021 uwsgi_log("invalid value for option \"%s\": must be > 0\n", opt);
4022 exit(1);
4023 }
4024 }
4025
4026 void uwsgi_opt_uid(char *opt, char *value, void *key) {
4027 uid_t uid = 0;
4028 if (is_a_number(value)) uid = atoi(value);
4029 if (!uid) {
4030 struct passwd *p = getpwnam(value);
4031 if (p) {
4032 uid = p->pw_uid;
4033 }
4034 else {
4035 uwsgi_log("unable to find user %s\n", value);
4036 exit(1);
4037 }
4038 }
4039 if (key) {
4040 uid_t *ptr = (uid_t *) key;
4041 *ptr = uid;
4042 }
4043 }
4044
4045 void uwsgi_opt_gid(char *opt, char *value, void *key) {
4046 gid_t gid = 0;
4047 if (is_a_number(value)) gid = atoi(value);
4048 if (!gid) {
4049 struct group *g = getgrnam(value);
4050 if (g) {
4051 gid = g->gr_gid;
4052 }
4053 else {
4054 uwsgi_log("unable to find group %s\n", value);
4055 exit(1);
4056 }
4057 }
4058 if (key) {
4059 gid_t *ptr = (gid_t *) key;
4060 *ptr = gid;
4061 }
4062 }
4063
4064 void uwsgi_opt_set_rawint(char *opt, char *value, void *key) {
4065 int *ptr = (int *) key;
4066 if (value) {
4067 *ptr = atoi((char *) value);
4068 }
4069 else {
4070 *ptr = 1;
4071 }
4072 }
4073
4074
4075 void uwsgi_opt_set_64bit(char *opt, char *value, void *key) {
4076 uint64_t *ptr = (uint64_t *) key;
4077
4078 if (value) {
4079 *ptr = (strtoul(value, NULL, 10));
4080 }
4081 else {
4082 *ptr = 1;
4083 }
4084 }
4085
4086 void uwsgi_opt_set_16bit(char *opt, char *value, void *key) {
4087 uint16_t *ptr = (uint16_t *) key;
4088
4089 if (value) {
4090 unsigned long n = strtoul(value, NULL, 10);
4091 if (n > 65535) n = 65535;
4092 *ptr = n;
4093 }
4094 else {
4095 *ptr = 1;
4096 }
4097 }
4098
4099
4100 void uwsgi_opt_set_megabytes(char *opt, char *value, void *key) {
4101 uint64_t *ptr = (uint64_t *) key;
4102 *ptr = (uint64_t)strtoul(value, NULL, 10) * 1024 * 1024;
4103 }
4104
4105 void uwsgi_opt_set_str(char *opt, char *value, void *key) {
4106 char **ptr = (char **) key;
4107 if (!value) {
4108 *ptr = "";
4109 return;
4110 }
4111 *ptr = (char *) value;
4112 }
4113
4114 void uwsgi_opt_set_null(char *opt, char *value, void *key) {
4115 char **ptr = (char **) key;
4116 *ptr = NULL;
4117 }
4118
4119
4120 void uwsgi_opt_set_logger(char *opt, char *value, void *prefix) {
4121
4122 if (!value)
4123 value = "";
4124
4125 if (prefix) {
4126 uwsgi_string_new_list(&uwsgi.requested_logger, uwsgi_concat3((char *) prefix, ":", value));
4127 }
4128 else {
4129 uwsgi_string_new_list(&uwsgi.requested_logger, uwsgi_str(value));
4130 }
4131 }
4132
4133 void uwsgi_opt_set_req_logger(char *opt, char *value, void *prefix) {
4134
4135 if (!value)
4136 value = "";
4137
4138 if (prefix) {
4139 uwsgi_string_new_list(&uwsgi.requested_req_logger, uwsgi_concat3((char *) prefix, ":", value));
4140 }
4141 else {
4142 uwsgi_string_new_list(&uwsgi.requested_req_logger, uwsgi_str(value));
4143 }
4144 }
4145
4146 void uwsgi_opt_set_str_spaced(char *opt, char *value, void *key) {
4147 char **ptr = (char **) key;
4148 *ptr = uwsgi_concat2((char *) value, " ");
4149 }
4150
4151 void uwsgi_opt_add_string_list(char *opt, char *value, void *list) {
4152 struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list;
4153 uwsgi_string_new_list(ptr, value);
4154 }
4155
4156 void uwsgi_opt_add_addr_list(char *opt, char *value, void *list) {
4157 struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list;
4158 int af = AF_INET;
4159 #ifdef AF_INET6
4160 void *ip = uwsgi_malloc(16);
4161 if (strchr(value, ':')) {
4162 af = AF_INET6;
4163 }
4164 #else
4165 void *ip = uwsgi_malloc(4);
4166 #endif
4167
4168 if (inet_pton(af, value, ip) <= 0) {
4169 uwsgi_log("%s: invalid address\n", opt);
4170 uwsgi_error("uwsgi_opt_add_addr_list()");
4171 exit(1);
4172 }
4173
4174 struct uwsgi_string_list *usl = uwsgi_string_new_list(ptr, ip);
4175 usl->custom = af;
4176 usl->custom_ptr = value;
4177 }
4178
4179
4180 void uwsgi_opt_add_string_list_custom(char *opt, char *value, void *list) {
4181 struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list;
4182 struct uwsgi_string_list *usl = uwsgi_string_new_list(ptr, value);
4183 usl->custom = 1;
4184 }
4185
4186 #ifdef UWSGI_PCRE
4187 void uwsgi_opt_add_regexp_list(char *opt, char *value, void *list) {
4188 struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list;
4189 uwsgi_regexp_new_list(ptr, value);
4190 }
4191
4192 void uwsgi_opt_add_regexp_custom_list(char *opt, char *value, void *list) {
4193 char *space = strchr(value, ' ');
4194 if (!space) {
4195 uwsgi_log("invalid custom regexp syntax: must be <custom> <regexp>\n");
4196 exit(1);
4197 }
4198 char *custom = uwsgi_concat2n(value, space - value, "", 0);
4199 struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list;
4200 uwsgi_regexp_custom_new_list(ptr, space + 1, custom);
4201 }
4202 #endif
4203
4204 void uwsgi_opt_add_shared_socket(char *opt, char *value, void *protocol) {
4205 struct uwsgi_socket *us = uwsgi_new_shared_socket(generate_socket_name(value));
4206 if (!strcmp(opt, "undeferred-shared-socket")) {
4207 us->no_defer = 1;
4208 }
4209 }
4210
4211 void uwsgi_opt_add_socket(char *opt, char *value, void *protocol) {
4212 struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
4213 uwsgi_sock->name_len = strlen(uwsgi_sock->name);
4214 uwsgi_sock->proto_name = protocol;
4215 }
4216
4217 #ifdef UWSGI_SSL
4218 void uwsgi_opt_add_ssl_socket(char *opt, char *value, void *protocol) {
4219 char *client_ca = NULL;
4220
4221 // build socket, certificate and key file
4222 char *sock = uwsgi_str(value);
4223 char *crt = strchr(sock, ',');
4224 if (!crt) {
4225 uwsgi_log("invalid https-socket syntax must be socket,crt,key\n");
4226 exit(1);
4227 }
4228 *crt = '\0'; crt++;
4229 char *key = strchr(crt, ',');
4230 if (!key) {
4231 uwsgi_log("invalid https-socket syntax must be socket,crt,key\n");
4232 exit(1);
4233 }
4234 *key = '\0'; key++;
4235
4236 char *ciphers = strchr(key, ',');
4237 if (ciphers) {
4238 *ciphers = '\0'; ciphers++;
4239 client_ca = strchr(ciphers, ',');
4240 if (client_ca) {
4241 *client_ca = '\0'; client_ca++;
4242 }
4243 }
4244
4245 struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(sock));
4246 uwsgi_sock->name_len = strlen(uwsgi_sock->name);
4247 uwsgi_sock->proto_name = protocol;
4248
4249 // ok we have the socket, initialize ssl if required
4250 if (!uwsgi.ssl_initialized) {
4251 uwsgi_ssl_init();
4252 }
4253
4254 // initialize ssl context
4255 uwsgi_sock->ssl_ctx = uwsgi_ssl_new_server_context(uwsgi_sock->name, crt, key, ciphers, client_ca);
4256 if (!uwsgi_sock->ssl_ctx) {
4257 exit(1);
4258 }
4259 }
4260 #endif
4261
4262 void uwsgi_opt_add_socket_no_defer(char *opt, char *value, void *protocol) {
4263 struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
4264 uwsgi_sock->name_len = strlen(uwsgi_sock->name);
4265 uwsgi_sock->proto_name = protocol;
4266 uwsgi_sock->no_defer = 1;
4267 }
4268
4269 void uwsgi_opt_add_lazy_socket(char *opt, char *value, void *protocol) {
4270 struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
4271 uwsgi_sock->proto_name = protocol;
4272 uwsgi_sock->bound = 1;
4273 uwsgi_sock->lazy = 1;
4274 }
4275
4276
4277 void uwsgi_opt_set_placeholder(char *opt, char *value, void *ph) {
4278
4279 char *p = strchr(value, '=');
4280 if (!p) {
4281 uwsgi_log("invalid placeholder/--set value\n");
4282 exit(1);
4283 }
4284
4285 p[0] = 0;
4286 add_exported_option_do(uwsgi_str(value), p + 1, 0, ph ? 1 : 0);
4287 p[0] = '=';
4288
4289 }
4290
4291 void uwsgi_opt_ssa(char *opt, char *value, void *foobar) {
4292 uwsgi_subscription_set_algo(value);
4293 }
4294
4295 #ifdef UWSGI_SSL
4296 void uwsgi_opt_scd(char *opt, char *value, void *foobar) {
4297 // openssl could not be initialized
4298 if (!uwsgi.ssl_initialized) {
4299 uwsgi_ssl_init();
4300 }
4301
4302 char *colon = strchr(value, ':');
4303 if (!colon) {
4304 uwsgi_log("invalid syntax for '%s', must be: <digest>:<directory>\n", opt);
4305 exit(1);
4306 }
4307
4308 char *algo = uwsgi_concat2n(value, (colon - value), "", 0);
4309 uwsgi.subscriptions_sign_check_md = EVP_get_digestbyname(algo);
4310 if (!uwsgi.subscriptions_sign_check_md) {
4311 uwsgi_log("unable to find digest algorithm: %s\n", algo);
4312 exit(1);
4313 }
4314 free(algo);
4315
4316 uwsgi.subscriptions_sign_check_dir = colon + 1;
4317 }
4318 #endif
4319
4320 void uwsgi_opt_set_umask(char *opt, char *value, void *mode) {
4321 int error = 0;
4322 mode_t mask = uwsgi_mode_t(value, &error);
4323 if (error) {
4324 uwsgi_log("invalid umask: %s\n", value);
4325 }
4326 umask(mask);
4327
4328 uwsgi.do_not_change_umask = 1;
4329 }
4330
4331 void uwsgi_opt_exit(char *opt, char *value, void *none) {
4332 int exit_code = 1;
4333 if (value) {
4334 exit_code = atoi(value);
4335 }
4336 exit(exit_code);
4337 }
4338
4339 void uwsgi_opt_print(char *opt, char *value, void *str) {
4340 if (str) {
4341 fprintf(stdout, "%s\n", (char *) str);
4342 exit(0);
4343 }
4344 fprintf(stdout, "%s\n", value);
4345 }
4346
4347 void uwsgi_opt_set_uid(char *opt, char *value, void *none) {
4348 if (is_a_number(value)) uwsgi.uid = atoi(value);
4349 if (!uwsgi.uid)
4350 uwsgi.uidname = value;
4351 }
4352
4353 void uwsgi_opt_set_gid(char *opt, char *value, void *none) {
4354 if (is_a_number(value)) uwsgi.gid = atoi(value);
4355 if (!uwsgi.gid)
4356 uwsgi.gidname = value;
4357 }
4358
4359 #ifdef UWSGI_CAP
4360 void uwsgi_opt_set_cap(char *opt, char *value, void *none) {
4361 uwsgi.cap_count = uwsgi_build_cap(value, &uwsgi.cap);
4362 if (uwsgi.cap_count == 0) {
4363 uwsgi_log("[security] empty capabilities mask !!!\n");
4364 exit(1);
4365 }
4366 }
4367 void uwsgi_opt_set_emperor_cap(char *opt, char *value, void *none) {
4368 uwsgi.emperor_cap_count = uwsgi_build_cap(value, &uwsgi.emperor_cap);
4369 if (uwsgi.emperor_cap_count == 0) {
4370 uwsgi_log("[security] empty capabilities mask !!!\n");
4371 exit(1);
4372 }
4373 }
4374 #endif
4375 #ifdef __linux__
4376 void uwsgi_opt_set_unshare(char *opt, char *value, void *mask) {
4377 uwsgi_build_unshare(value, (int *) mask);
4378 }
4379 #endif
4380
4381 void uwsgi_opt_set_env(char *opt, char *value, void *none) {
4382 if (putenv(value)) {
4383 uwsgi_error("putenv()");
4384 }
4385 }
4386
4387 void uwsgi_opt_unset_env(char *opt, char *value, void *none) {
4388 #ifdef UNSETENV_VOID
4389 unsetenv(value);
4390 #else
4391 if (unsetenv(value)) {
4392 uwsgi_error("unsetenv()");
4393 }
4394 #endif
4395 }
4396
4397 void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) {
4398
4399 long *signum_fake_ptr = (long *) sig;
4400 int signum = (long) signum_fake_ptr;
4401 exit(signal_pidfile(signum, pidfile));
4402 }
4403
4404 void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
4405 if (!dlopen(value, RTLD_NOW | RTLD_GLOBAL)) {
4406 uwsgi_log("%s\n", dlerror());
4407 }
4408 }
4409
4410 void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
4411
4412 char *plugins_list = uwsgi_concat2(value, "");
4413 char *p, *ctx = NULL;
4414 uwsgi_foreach_token(plugins_list, ",", p, ctx) {
4415 #ifdef UWSGI_DEBUG
4416 uwsgi_debug("loading plugin %s\n", p);
4417 #endif
4418 if (uwsgi_load_plugin(-1, p, NULL)) {
4419 build_options();
4420 }
4421 else if (!uwsgi_startswith(opt, "need-", 5)) {
4422 uwsgi_log("unable to load plugin \"%s\"\n", p);
4423 exit(1);
4424 }
4425 }
4426 free(p);
4427 free(plugins_list);
4428 }
4429
4430 void uwsgi_opt_check_static(char *opt, char *value, void *foobar) {
4431
4432 uwsgi_dyn_dict_new(&uwsgi.check_static, value, strlen(value), NULL, 0);
4433 uwsgi_log("[uwsgi-static] added check for %s\n", value);
4434 uwsgi.build_mime_dict = 1;
4435
4436 }
4437
4438 void uwsgi_opt_add_dyn_dict(char *opt, char *value, void *dict) {
4439
4440 char *equal = strchr(value, '=');
4441 if (!equal) {
4442 uwsgi_log("invalid dictionary syntax for %s\n", opt);
4443 exit(1);
4444 }
4445
4446 struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict;
4447
4448 uwsgi_dyn_dict_new(udd, value, equal - value, equal + 1, strlen(equal + 1));
4449
4450 }
4451
4452 #ifdef UWSGI_PCRE
4453 void uwsgi_opt_add_regexp_dyn_dict(char *opt, char *value, void *dict) {
4454
4455 char *space = strchr(value, ' ');
4456 if (!space) {
4457 uwsgi_log("invalid dictionary syntax for %s\n", opt);
4458 exit(1);
4459 }
4460
4461 struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict;
4462
4463 struct uwsgi_dyn_dict *new_udd = uwsgi_dyn_dict_new(udd, value, space - value, space + 1, strlen(space + 1));
4464
4465 char *regexp = uwsgi_concat2n(value, space - value, "", 0);
4466
4467 if (uwsgi_regexp_build(regexp, &new_udd->pattern, &new_udd->pattern_extra)) {
4468 exit(1);
4469 }
4470
4471 free(regexp);
4472 }
4473 #endif
4474
4475
4476 void uwsgi_opt_fileserve_mode(char *opt, char *value, void *foobar) {
4477
4478 if (!strcasecmp("x-sendfile", value)) {
4479 uwsgi.file_serve_mode = 2;
4480 }
4481 else if (!strcasecmp("xsendfile", value)) {
4482 uwsgi.file_serve_mode = 2;
4483 }
4484 else if (!strcasecmp("x-accel-redirect", value)) {
4485 uwsgi.file_serve_mode = 1;
4486 }
4487 else if (!strcasecmp("xaccelredirect", value)) {
4488 uwsgi.file_serve_mode = 1;
4489 }
4490 else if (!strcasecmp("nginx", value)) {
4491 uwsgi.file_serve_mode = 1;
4492 }
4493
4494 }
4495
4496 void uwsgi_opt_static_map(char *opt, char *value, void *static_maps) {
4497
4498 struct uwsgi_dyn_dict **maps = (struct uwsgi_dyn_dict **) static_maps;
4499 char *mountpoint = uwsgi_str(value);
4500
4501 char *docroot = strchr(mountpoint, '=');
4502
4503 if (!docroot) {
4504 uwsgi_log("invalid document root in static map, syntax mountpoint=docroot\n");
4505 exit(1);
4506 }
4507 docroot[0] = 0;
4508 docroot++;
4509 uwsgi_dyn_dict_new(maps, mountpoint, strlen(mountpoint), docroot, strlen(docroot));
4510 uwsgi_log_initial("[uwsgi-static] added mapping for %s => %s\n", mountpoint, docroot);
4511 uwsgi.build_mime_dict = 1;
4512 }
4513
4514
4515 int uwsgi_zerg_attach(char *value) {
4516
4517 int count = 8;
4518 int zerg_fd = uwsgi_connect(value, 30, 0);
4519 if (zerg_fd < 0) {
4520 uwsgi_log("--- unable to connect to zerg server %s ---\n", value);
4521 return -1;
4522 }
4523
4524 int last_count = count;
4525
4526 int *zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10);
4527 if (zerg == NULL) {
4528 if (last_count != count) {
4529 close(zerg_fd);
4530 zerg_fd = uwsgi_connect(value, 30, 0);
4531 if (zerg_fd < 0) {
4532 uwsgi_log("--- unable to connect to zerg server %s ---\n", value);
4533 return -1;
4534 }
4535 zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10);
4536 }
4537 }
4538
4539 if (zerg == NULL) {
4540 uwsgi_log("--- invalid data received from zerg-server ---\n");
4541 close(zerg_fd);
4542 return -1;
4543 }
4544
4545 if (!uwsgi.zerg) {
4546 uwsgi.zerg = zerg;
4547 }
4548 else {
4549 int pos = 0;
4550 for (;;) {
4551 if (uwsgi.zerg[pos] == -1) {
4552 uwsgi.zerg = realloc(uwsgi.zerg, (sizeof(int) * (pos)) + (sizeof(int) * count + 1));
4553 if (!uwsgi.zerg) {
4554 uwsgi_error("realloc()");
4555 exit(1);
4556 }
4557 memcpy(&uwsgi.zerg[pos], zerg, (sizeof(int) * count + 1));
4558 break;
4559 }
4560 pos++;
4561 }
4562 free(zerg);
4563 }
4564
4565 close(zerg_fd);
4566 return 0;
4567 }
4568
4569 void uwsgi_opt_signal(char *opt, char *value, void *foobar) {
4570 uwsgi_command_signal(value);
4571 }
4572
4573 void uwsgi_opt_log_date(char *opt, char *value, void *foobar) {
4574
4575 uwsgi.logdate = 1;
4576 if (value) {
4577 if (strcasecmp("true", value) && strcasecmp("1", value) && strcasecmp("on", value) && strcasecmp("yes", value)) {
4578 uwsgi.log_strftime = value;
4579 }
4580 }
4581 }
4582
4583 void uwsgi_opt_chmod_socket(char *opt, char *value, void *foobar) {
4584
4585 int i;
4586
4587 uwsgi.chmod_socket = 1;
4588 if (value) {
4589 if (strlen(value) == 1 && *value == '1') {
4590 return;
4591 }
4592 if (strlen(value) != 3) {
4593 uwsgi_log("invalid chmod value: %s\n", value);
4594 exit(1);
4595 }
4596 for (i = 0; i < 3; i++) {
4597 if (value[i] < '0' || value[i] > '7') {
4598 uwsgi_log("invalid chmod value: %s\n", value);
4599 exit(1);
4600 }
4601 }
4602
4603 uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[0] - '0');
4604 uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[1] - '0');
4605 uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[2] - '0');
4606 }
4607
4608 }
4609
4610 void uwsgi_opt_logfile_chmod(char *opt, char *value, void *foobar) {
4611
4612 int i;
4613
4614 if (strlen(value) != 3) {
4615 uwsgi_log("invalid chmod value: %s\n", value);
4616 exit(1);
4617 }
4618 for (i = 0; i < 3; i++) {
4619 if (value[i] < '0' || value[i] > '7') {
4620 uwsgi_log("invalid chmod value: %s\n", value);
4621 exit(1);
4622 }
4623 }
4624
4625 uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[0] - '0');
4626 uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[1] - '0');
4627 uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[2] - '0');
4628
4629 }
4630
4631 void uwsgi_opt_max_vars(char *opt, char *value, void *foobar) {
4632
4633 uwsgi.max_vars = atoi(value);
4634 uwsgi.vec_size = 4 + 1 + (4 * uwsgi.max_vars);
4635 }
4636
4637 void uwsgi_opt_deprecated(char *opt, char *value, void *message) {
4638 uwsgi_log("[WARNING] option \"%s\" is deprecated: %s\n", opt, (char *) message);
4639 }
4640
4641 void uwsgi_opt_load(char *opt, char *filename, void *none) {
4642
4643 // here we need to avoid setting upper magic vars
4644 int orig_magic = uwsgi.magic_table_first_round;
4645 uwsgi.magic_table_first_round = 1;
4646
4647 if (uwsgi_endswith(filename, ".ini")) {
4648 uwsgi_opt_load_ini(opt, filename, none);
4649 goto end;
4650 }
4651 #ifdef UWSGI_XML
4652 if (uwsgi_endswith(filename, ".xml")) {
4653 uwsgi_opt_load_xml(opt, filename, none);
4654 goto end;
4655 }
4656 #endif
4657 #ifdef UWSGI_YAML
4658 if (uwsgi_endswith(filename, ".yaml")) {
4659 uwsgi_opt_load_yml(opt, filename, none);
4660 goto end;
4661 }
4662 if (uwsgi_endswith(filename, ".yml")) {
4663 uwsgi_opt_load_yml(opt, filename, none);
4664 goto end;
4665 }
4666 #endif
4667 #ifdef UWSGI_JSON
4668 if (uwsgi_endswith(filename, ".json")) {
4669 uwsgi_opt_load_json(opt, filename, none);
4670 goto end;
4671 }
4672 if (uwsgi_endswith(filename, ".js")) {
4673 uwsgi_opt_load_json(opt, filename, none);
4674 goto end;
4675 }
4676 #endif
4677
4678 // fallback to pluggable system
4679 uwsgi_opt_load_config(opt, filename, none);
4680 end:
4681 uwsgi.magic_table_first_round = orig_magic;
4682 }
4683
4684 void uwsgi_opt_logic(char *opt, char *arg, void *func) {
4685
4686 if (uwsgi.logic_opt) {
4687 uwsgi_log("recursive logic in options is not supported (option = %s)\n", opt);
4688 exit(1);
4689 }
4690 uwsgi.logic_opt = (int (*)(char *, char *)) func;
4691 uwsgi.logic_opt_cycles = 0;
4692 if (arg) {
4693 uwsgi.logic_opt_arg = uwsgi_str(arg);
4694 }
4695 else {
4696 uwsgi.logic_opt_arg = NULL;
4697 }
4698 }
4699
4700 void uwsgi_opt_noop(char *opt, char *foo, void *bar) {
4701 }
4702
4703 void uwsgi_opt_load_ini(char *opt, char *filename, void *none) {
4704 config_magic_table_fill(filename, uwsgi.magic_table);
4705 uwsgi_ini_config(filename, uwsgi.magic_table);
4706 }
4707
4708 void uwsgi_opt_load_config(char *opt, char *filename, void *none) {
4709 struct uwsgi_configurator *uc = uwsgi.configurators;
4710 while(uc) {
4711 if (uwsgi_endswith(filename, uc->name)) {
4712 config_magic_table_fill(filename, uwsgi.magic_table);
4713 uc->func(filename, uwsgi.magic_table);
4714 return;
4715 }
4716 uc = uc->next;
4717 }
4718
4719 uwsgi_log("unable to load configuration from %s\n", filename);
4720 exit(1);
4721 }
4722
4723 #ifdef UWSGI_XML
4724 void uwsgi_opt_load_xml(char *opt, char *filename, void *none) {
4725 config_magic_table_fill(filename, uwsgi.magic_table);
4726 uwsgi_xml_config(filename, uwsgi.wsgi_req, uwsgi.magic_table);
4727 }
4728 #endif
4729
4730 #ifdef UWSGI_YAML
4731 void uwsgi_opt_load_yml(char *opt, char *filename, void *none) {
4732 config_magic_table_fill(filename, uwsgi.magic_table);
4733 uwsgi_yaml_config(filename, uwsgi.magic_table);
4734 }
4735 #endif
4736
4737 #ifdef UWSGI_JSON
4738 void uwsgi_opt_load_json(char *opt, char *filename, void *none) {
4739 config_magic_table_fill(filename, uwsgi.magic_table);
4740 uwsgi_json_config(filename, uwsgi.magic_table);
4741 }
4742 #endif
4743
4744 void uwsgi_opt_add_custom_option(char *opt, char *value, void *none) {
4745
4746 struct uwsgi_custom_option *uco = uwsgi.custom_options, *old_uco;
4747
4748 if (!uco) {
4749 uwsgi.custom_options = uwsgi_malloc(sizeof(struct uwsgi_custom_option));
4750 uco = uwsgi.custom_options;
4751 }
4752 else {
4753 while (uco) {
4754 old_uco = uco;
4755 uco = uco->next;
4756 }
4757
4758 uco = uwsgi_malloc(sizeof(struct uwsgi_custom_option));
4759 old_uco->next = uco;
4760 }
4761
4762 char *copy = uwsgi_str(value);
4763 char *equal = strchr(copy, '=');
4764 if (!equal) {
4765 uwsgi_log("invalid %s syntax, must be newoption=template\n", value);
4766 exit(1);
4767 }
4768 *equal = 0;
4769
4770 uco->name = copy;
4771 uco->value = equal + 1;
4772 uco->has_args = 0;
4773 // a little hack, we allow the user to skip the first 2 arguments (yes.. it is silly...but users tend to make silly things...)
4774 if (strstr(uco->value, "$1") || strstr(uco->value, "$2") || strstr(uco->value, "$3")) {
4775 uco->has_args = 1;
4776 }
4777 uco->next = NULL;
4778 build_options();
4779 }
4780
4781
4782 void uwsgi_opt_flock(char *opt, char *filename, void *none) {
4783
4784 int fd = open(filename, O_RDWR);
4785 if (fd < 0) {
4786 uwsgi_error_open(filename);
4787 exit(1);
4788 }
4789
4790 if (uwsgi_fcntl_is_locked(fd)) {
4791 uwsgi_log("uWSGI ERROR: %s is locked by another instance\n", filename);
4792 exit(1);
4793 }
4794 }
4795
4796 void uwsgi_opt_flock_wait(char *opt, char *filename, void *none) {
4797
4798 int fd = open(filename, O_RDWR);
4799 if (fd < 0) {
4800 uwsgi_error_open(filename);
4801 exit(1);
4802 }
4803
4804 if (uwsgi_fcntl_lock(fd)) {
4805 exit(1);
4806 }
4807 }
4808
4809 // report CFLAGS used for compiling the server
4810 // use that values to build external plugins
4811 void uwsgi_opt_cflags(char *opt, char *filename, void *foobar) {
4812 fprintf(stdout, "%s\n", uwsgi_get_cflags());
4813 exit(0);
4814 }
4815
4816 char *uwsgi_get_cflags() {
4817 size_t len = sizeof(UWSGI_CFLAGS) -1;
4818 char *src = UWSGI_CFLAGS;
4819 char *ptr = uwsgi_malloc((len / 2) + 1);
4820 char *base = ptr;
4821 size_t i;
4822 unsigned int u;
4823 for (i = 0; i < len; i += 2) {
4824 sscanf(src + i, "%2x", &u);
4825 *ptr++ = (char) u;
4826 }
4827 *ptr ++= 0;
4828 return base;
4829 }
4830
4831 // report uwsgi.h used for compiling the server
4832 // use that values to build external plugins
4833 extern char *uwsgi_dot_h;
4834 char *uwsgi_get_dot_h() {
4835 char *src = uwsgi_dot_h;
4836 size_t len = strlen(src);
4837 char *ptr = uwsgi_malloc((len / 2) + 1);
4838 char *base = ptr;
4839 size_t i;
4840 unsigned int u;
4841 for (i = 0; i < len; i += 2) {
4842 sscanf(src + i, "%2x", &u);
4843 *ptr++ = (char) u;
4844 }
4845 #ifdef UWSGI_ZLIB
4846 struct uwsgi_buffer *ub = uwsgi_zlib_decompress(base, ptr-base);
4847 if (!ub) {
4848 free(base);
4849 return "";
4850 }
4851 // add final null byte
4852 uwsgi_buffer_append(ub, "\0", 1);
4853 free(base);
4854 // base is the final blob
4855 base = ub->buf;
4856 ub->buf = NULL;
4857 uwsgi_buffer_destroy(ub);
4858 #else
4859 // add final null byte
4860 *ptr = '\0';
4861 #endif
4862 return base;
4863 }
4864 void uwsgi_opt_dot_h(char *opt, char *filename, void *foobar) {
4865 fprintf(stdout, "%s\n", uwsgi_get_dot_h());
4866 exit(0);
4867 }
4868
4869 extern char *uwsgi_config_py;
4870 char *uwsgi_get_config_py() {
4871 char *src = uwsgi_config_py;
4872 size_t len = strlen(src);
4873 char *ptr = uwsgi_malloc((len / 2) + 1);
4874 char *base = ptr;
4875 size_t i;
4876 unsigned int u;
4877 for (i = 0; i < len; i += 2) {
4878 sscanf(src + i, "%2x", &u);
4879 *ptr++ = (char) u;
4880 }
4881 #ifdef UWSGI_ZLIB
4882 struct uwsgi_buffer *ub = uwsgi_zlib_decompress(base, ptr-base);
4883 if (!ub) {
4884 free(base);
4885 return "";
4886 }
4887 // add final null byte
4888 uwsgi_buffer_append(ub, "\0", 1);
4889 free(base);
4890 // base is the final blob
4891 base = ub->buf;
4892 ub->buf = NULL;
4893 uwsgi_buffer_destroy(ub);
4894 #else
4895 // add final null byte
4896 *ptr = '\0';
4897 #endif
4898 return base;
4899 }
4900
4901 void uwsgi_opt_config_py(char *opt, char *filename, void *foobar) {
4902 fprintf(stdout, "%s\n", uwsgi_get_config_py());
4903 exit(0);
4904 }
4905
4906
4907 void uwsgi_opt_build_plugin(char *opt, char *directory, void *foobar) {
4908 uwsgi_build_plugin(directory);
4909 exit(1);
4910 }
4911
4912 void uwsgi_opt_connect_and_read(char *opt, char *address, void *foobar) {
4913
4914 char buf[8192];
4915
4916 int fd = uwsgi_connect(address, -1, 0);
4917 while (fd >= 0) {
4918 int ret = uwsgi_waitfd(fd, -1);
4919 if (ret <= 0) {
4920 exit(0);
4921 }
4922 ssize_t len = read(fd, buf, 8192);
4923 if (len <= 0) {
4924 exit(0);
4925 }
4926 uwsgi_log("%.*s", (int) len, buf);
4927 }
4928 uwsgi_error("uwsgi_connect()");
4929 exit(1);
4930 }
4931
4932 void uwsgi_opt_extract(char *opt, char *address, void *foobar) {
4933
4934 size_t len = 0;
4935 char *buf;
4936
4937 buf = uwsgi_open_and_read(address, &len, 0, NULL);
4938 if (len > 0) {
4939 if (write(1, buf, len) != (ssize_t) len) {
4940 uwsgi_error("write()");
4941 exit(1);
4942 };
4943 };
4944 exit(0);
4945 }
4946
4947 void uwsgi_print_sym(char *opt, char *symbol, void *foobar) {
4948 char **sym = dlsym(RTLD_DEFAULT, symbol);
4949 if (sym) {
4950 uwsgi_log("%s", *sym);
4951 exit(0);
4952 }
4953
4954 char *symbol_start = uwsgi_concat2(symbol, "_start");
4955 char *symbol_end = uwsgi_concat2(symbol, "_end");
4956
4957 char *sym_s = dlsym(RTLD_DEFAULT, symbol_start);
4958 char *sym_e = dlsym(RTLD_DEFAULT, symbol_end);
4959
4960 if (sym_s && sym_e) {
4961 uwsgi_log("%.*s", sym_e - sym_s, sym_s);
4962 }
4963
4964 exit(0);
4965 }
4966
4967 void uwsgi_update_pidfiles() {
4968 if (uwsgi.pidfile) {
4969 uwsgi_write_pidfile(uwsgi.pidfile);
4970 }
4971 if (uwsgi.pidfile2) {
4972 uwsgi_write_pidfile(uwsgi.pidfile2);
4973 }
4974 if (uwsgi.safe_pidfile) {
4975 uwsgi_write_pidfile(uwsgi.safe_pidfile);
4976 }
4977 if (uwsgi.safe_pidfile2) {
4978 uwsgi_write_pidfile(uwsgi.safe_pidfile2);
4979 }
4980 }
4981
4982 void uwsgi_opt_binary_append_data(char *opt, char *value, void *none) {
4983
4984 size_t size;
4985 char *buf = uwsgi_open_and_read(value, &size, 0, NULL);
4986
4987 uint64_t file_len = size;
4988
4989 if (write(1, buf, size) != (ssize_t) size) {
4990 uwsgi_error("uwsgi_opt_binary_append_data()/write()");
4991 exit(1);
4992 }
4993
4994 if (write(1, &file_len, 8) != 8) {
4995 uwsgi_error("uwsgi_opt_binary_append_data()/write()");
4996 exit(1);
4997 }
4998
4999 exit(0);
5000 }
5001