Files
uwsgi/uwsgi.c
T

3502 lines
98 KiB
C

/*
*** uWSGI ***
Copyright (C) 2009-2011 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "uwsgi.h"
struct uwsgi_server uwsgi;
extern char **environ;
static char *short_options = NULL;
static char *base_short_options = "s:p:t:x:d:l:v:b:mcaCTiMhrR:z:A:Q:Ly:";
extern struct uwsgi_plugin uwsgi_cache_plugin;
UWSGI_DECLARE_EMBEDDED_PLUGINS
static struct option long_base_options[] = {
{"socket", required_argument, 0, 's'},
{"shared-socket", required_argument, 0, LONG_ARGS_SHARED_SOCKET},
{"processes", required_argument, 0, 'p'},
{"workers", required_argument, 0, 'p'},
{"harakiri", required_argument, 0, 't'},
{"harakiri-verbose", no_argument, &uwsgi.harakiri_verbose, 1},
#ifdef UWSGI_XML
{"xmlconfig", required_argument, 0, 'x'},
{"xml", required_argument, 0, 'x'},
#endif
{"daemonize", required_argument, 0, 'd'},
{"listen", required_argument, 0, 'l'},
{"max-vars", required_argument, 0, 'v'},
{"buffer-size", required_argument, 0, 'b'},
{"memory-report", no_argument, 0, 'm'},
{"cgi-mode", no_argument, 0, 'c'},
{"abstract-socket", no_argument, 0, 'a'},
{"chmod-socket", optional_argument, 0, 'C'},
{"map-socket", required_argument, 0, LONG_ARGS_MAP_SOCKET},
{"chmod", optional_argument, 0, 'C'},
#ifdef UWSGI_THREADING
{"enable-threads", no_argument, 0, 'T'},
#endif
{"single-interpreter", no_argument, 0, 'i'},
{"master", no_argument, 0, 'M'},
{"emperor", required_argument, 0, LONG_ARGS_EMPEROR},
{"reload-mercy", required_argument, 0, LONG_ARGS_RELOAD_MERCY},
{"exit-on-reload", no_argument, &uwsgi.exit_on_reload, 1},
{"help", no_argument, 0, 'h'},
{"reaper", no_argument, 0, 'r'},
{"max-requests", required_argument, 0, 'R'},
{"socket-timeout", required_argument, 0, 'z'},
{"sharedarea", required_argument, 0, 'A'},
{"cache", required_argument, 0, LONG_ARGS_CACHE},
{"cache-blocksize", required_argument, 0, LONG_ARGS_CACHE_BLOCKSIZE},
{"cache-store", required_argument, 0, LONG_ARGS_CACHE_STORE},
{"cache-store-sync", required_argument, 0, LONG_ARGS_CACHE_STORE_SYNC},
{"queue", required_argument, 0, LONG_ARGS_QUEUE},
{"queue-blocksize", required_argument, 0, LONG_ARGS_QUEUE_BLOCKSIZE},
{"queue-store", required_argument, 0, LONG_ARGS_QUEUE_STORE},
{"queue-store-sync", required_argument, 0, LONG_ARGS_QUEUE_STORE_SYNC},
#ifdef UWSGI_SPOOLER
{"spooler", required_argument, 0, 'Q'},
#endif
{"disable-logging", no_argument, 0, 'L'},
{"pidfile", required_argument, 0, LONG_ARGS_PIDFILE},
{"pidfile2", required_argument, 0, LONG_ARGS_PIDFILE2},
{"chroot", required_argument, 0, LONG_ARGS_CHROOT},
{"gid", required_argument, 0, LONG_ARGS_GID},
{"uid", required_argument, 0, LONG_ARGS_UID},
#ifdef UWSGI_INI
{"ini", required_argument, 0, LONG_ARGS_INI},
#endif
#ifdef UWSGI_YAML
{"yaml", required_argument, 0, 'y'},
{"yml", required_argument, 0, 'y'},
#endif
#ifdef UWSGI_LDAP
{"ldap", required_argument, 0, LONG_ARGS_LDAP},
{"ldap-schema", no_argument, 0, LONG_ARGS_LDAP_SCHEMA},
{"ldap-schema-ldif", no_argument, 0, LONG_ARGS_LDAP_SCHEMA_LDIF},
#endif
{"no-server", no_argument, &uwsgi.no_server, 1},
{"no-defer-accept", no_argument, &uwsgi.no_defer_accept, 1},
{"limit-as", required_argument, 0, LONG_ARGS_LIMIT_AS},
{"reload-on-as", required_argument, 0, LONG_ARGS_RELOAD_ON_AS},
{"reload-on-rss", required_argument, 0, LONG_ARGS_RELOAD_ON_RSS},
{"touch-reload", required_argument, 0, LONG_ARGS_TOUCH_RELOAD},
{"limit-post", required_argument, 0, LONG_ARGS_LIMIT_POST},
{"no-orphans", no_argument, &uwsgi.no_orphans, 1},
{"prio", required_argument, 0, LONG_ARGS_PRIO},
{"cpu-affinity", required_argument, 0, LONG_ARGS_CPU_AFFINITY},
{"post-buffering", required_argument, 0, LONG_ARGS_POST_BUFFERING},
{"post-buffering-bufsize", required_argument, 0, LONG_ARGS_POST_BUFFERING_SIZE},
{"upload-progress", required_argument, 0, LONG_ARGS_UPLOAD_PROGRESS},
{"no-default-app", no_argument, &uwsgi.no_default_app, 1},
{"manage-script-name", no_argument, &uwsgi.manage_script_name, 1},
#ifdef UWSGI_UDP
{"udp", required_argument, 0, LONG_ARGS_UDP},
#endif
#ifdef UWSGI_MULTICAST
{"multicast", required_argument, 0, LONG_ARGS_MULTICAST},
{"cluster", required_argument, 0, LONG_ARGS_CLUSTER},
{"cluster-nodes", required_argument, 0, LONG_ARGS_CLUSTER_NODES},
#endif
{"cluster-reload", required_argument, 0, LONG_ARGS_CLUSTER_RELOAD},
{"cluster-log", required_argument, 0, LONG_ARGS_CLUSTER_LOG},
{"subscribe-to", required_argument, 0, LONG_ARGS_SUBSCRIBE_TO},
#ifdef UWSGI_SNMP
{"snmp", optional_argument, 0, LONG_ARGS_SNMP},
{"snmp-community", required_argument, 0, LONG_ARGS_SNMP_COMMUNITY},
#endif
{"check-interval", required_argument, 0, LONG_ARGS_CHECK_INTERVAL},
{"binary-path", required_argument, 0, LONG_ARGS_BINARY_PATH},
#ifdef UWSGI_ASYNC
{"async", required_argument, 0, LONG_ARGS_ASYNC},
#endif
{"logto", required_argument, 0, LONG_ARGS_LOGTO},
{"logfile-chown", no_argument, &uwsgi.logfile_chown, 1},
{"log-syslog", optional_argument, 0, LONG_ARGS_LOG_SYSLOG},
{"log-master", no_argument, 0, LONG_ARGS_LOG_MASTER},
{"logdate", optional_argument, 0, LONG_ARGS_LOG_DATE},
{"log-zero", no_argument, 0, LONG_ARGS_LOG_ZERO},
{"log-slow", required_argument, 0, LONG_ARGS_LOG_SLOW},
{"log-4xx", no_argument, 0, LONG_ARGS_LOG_4xx},
{"log-5xx", no_argument, 0, LONG_ARGS_LOG_5xx},
{"log-big", required_argument, 0, LONG_ARGS_LOG_BIG},
{"log-sendfile", required_argument, 0, LONG_ARGS_LOG_SENDFILE},
{"log-micros", no_argument, &uwsgi.log_micros, 1},
{"master-as-root", no_argument, &uwsgi.master_as_root, 1},
{"chdir", required_argument, 0, LONG_ARGS_CHDIR},
{"chdir2", required_argument, 0, LONG_ARGS_CHDIR2},
{"mount", required_argument, 0, LONG_ARGS_MOUNT},
{"grunt", no_argument, &uwsgi.grunt, 1},
{"threads", required_argument, 0, LONG_ARGS_THREADS},
{"vhost", no_argument, &uwsgi.vhost, 1},
{"vhost-host", no_argument, 0, LONG_ARGS_VHOSTHOST},
#ifdef UWSGI_ROUTING
{"routing", no_argument, &uwsgi.routing, 1},
#endif
{"check-static", required_argument, 0, LONG_ARGS_CHECK_STATIC},
{"static-map", required_argument, 0, LONG_ARGS_STATIC_MAP},
{"file-serve-mode", required_argument, 0, LONG_ARGS_FILE_SERVE_MODE},
{"check-cache", no_argument, &uwsgi.check_cache, 1},
{"close-on-exec", no_argument, &uwsgi.close_on_exec, 1},
{"mode", required_argument, 0, LONG_ARGS_MODE},
{"env", required_argument, 0, LONG_ARGS_ENV},
{"vacuum", no_argument, &uwsgi.vacuum, 1},
#ifdef __linux__
{"cgroup", required_argument, 0, LONG_ARGS_CGROUP},
{"cgroup-opt", required_argument, 0, LONG_ARGS_CGROUP_OPT},
{"namespace", required_argument, 0, LONG_ARGS_LINUX_NS},
{"ns", required_argument, 0, LONG_ARGS_LINUX_NS},
{"namespace-net", required_argument, 0, LONG_ARGS_LINUX_NS_NET},
{"ns-net", required_argument, 0, LONG_ARGS_LINUX_NS_NET},
#endif
{"loop", required_argument, 0, LONG_ARGS_LOOP},
{"worker-exec", required_argument, 0, LONG_ARGS_WORKER_EXEC},
{"attach-daemon", required_argument, 0, LONG_ARGS_ATTACH_DAEMON},
{"plugins", required_argument, 0, LONG_ARGS_PLUGINS},
{"allowed-modifiers", required_argument, 0, LONG_ARGS_ALLOWED_MODIFIERS},
{"remap-modifier", required_argument, 0, LONG_ARGS_REMAP_MODIFIER},
{"dump-options", no_argument, &uwsgi.dump_options, 1},
{"show-config", no_argument, &uwsgi.show_config, 1},
{"print", required_argument, 0, LONG_ARGS_PRINT},
{"version", no_argument, 0, LONG_ARGS_VERSION},
{0, 0, 0, 0}
};
int find_worker_id(pid_t pid)
{
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid == pid)
return i;
}
return -1;
}
void warn_pipe()
{
struct wsgi_request *wsgi_req = current_wsgi_req();
if (uwsgi.threads < 2 && wsgi_req->uri_len > 0) {
uwsgi_log("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);
} else {
uwsgi_log("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n");
}
}
void gracefully_kill(int signum)
{
uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
if (UWSGI_IS_IN_REQUEST) {
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
} else {
reload_me(0);
}
}
void reload_me(int signum)
{
exit(UWSGI_RELOAD_CODE);
}
void end_me(int signum)
{
exit(UWSGI_END_CODE);
}
void goodbye_cruel_world()
{
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log("...The work of process %d is done. Seeya!\n", getpid());
exit(0);
}
void kill_them_all(int signum)
{
int i;
uwsgi.to_hell = 1;
uwsgi_log("SIGINT/SIGQUIT received...killing workers...\n");
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0)
kill(uwsgi.workers[i].pid, SIGINT);
}
for (i = 0; i < uwsgi.shared->daemons_cnt; i++) {
if (uwsgi.shared->daemons[i].pid > 0)
kill(uwsgi.shared->daemons[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.gateways_cnt; i++) {
if (uwsgi.gateways[i].pid > 0)
kill(uwsgi.gateways[i].pid, SIGKILL);
}
}
void grace_them_all(int signum)
{
int i;
uwsgi.to_heaven = 1;
if (uwsgi.reload_mercy > 0) {
uwsgi.master_mercy = time(NULL) + uwsgi.reload_mercy;
}
for (i = 0; i < uwsgi.shared->daemons_cnt; i++) {
if (uwsgi.shared->daemons[i].pid > 0)
kill(uwsgi.shared->daemons[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.gateways_cnt; i++) {
if (uwsgi.gateways[i].pid > 0)
kill(uwsgi.gateways[i].pid, SIGKILL);
}
uwsgi_log("...gracefully killing workers...\n");
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0)
kill(uwsgi.workers[i].pid, SIGHUP);
}
}
void uwsgi_nuclear_blast() {
if (!uwsgi.workers) {
reap_them_all(0);
}
else if (uwsgi.master_process) {
if (getpid() == uwsgi.workers[0].pid) {
reap_them_all(0);
}
}
exit(1);
}
void reap_them_all(int signum)
{
int i;
uwsgi.to_heaven = 1;
for (i = 0; i < uwsgi.shared->daemons_cnt; i++) {
if (uwsgi.shared->daemons[i].pid > 0)
kill(uwsgi.shared->daemons[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.gateways_cnt; i++) {
if (uwsgi.gateways[i].pid > 0)
kill(uwsgi.gateways[i].pid, SIGKILL);
}
if (!uwsgi.workers) return;
uwsgi_log("...brutally killing workers...\n");
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0)
kill(uwsgi.workers[i].pid, SIGTERM);
}
}
void harakiri()
{
uwsgi_log("\nF*CK !!! i must kill myself (pid: %d app_id: %d)...\n", uwsgi.mypid, uwsgi.wsgi_req->app_id);
if (!uwsgi.master_process) {
uwsgi_log("*** if you want your workers to be automatically respawned consider enabling the uWSGI master process ***\n");
}
exit(0);
}
void stats(int signum)
{
//fix this for better logging(this cause races)
struct uwsgi_app *ua = NULL;
int i;
uwsgi_log("*** pid %d stats ***\n", getpid());
uwsgi_log("\ttotal requests: %llu\n", uwsgi.workers[0].requests);
for (i = 0; i < uwsgi.apps_cnt; i++) {
ua = &uwsgi.apps[i];
if (ua) {
uwsgi_log("\tapp %d requests: %d\n", i, ua->requests);
}
}
uwsgi_log("\n");
}
void what_i_am_doing()
{
struct wsgi_request *wsgi_req;
int i;
if (uwsgi.cores > 1) {
for(i=0;i<uwsgi.cores;i++) {
wsgi_req = uwsgi.wsgi_requests[i];
if (wsgi_req->uri_len > 0) {
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && uwsgi.workers[uwsgi.mywid].harakiri < time(NULL)) {
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((const time_t *) & wsgi_req->start_of_request.tv_sec));
}
else {
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((const time_t *) & wsgi_req->start_of_request.tv_sec));
}
}
}
}
else {
wsgi_req = uwsgi.wsgi_requests[0];
if (wsgi_req->uri_len > 0) {
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && uwsgi.workers[uwsgi.mywid].harakiri < time(NULL)) {
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((const time_t *) & wsgi_req->start_of_request.tv_sec));
} else {
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((const time_t *) & wsgi_req->start_of_request.tv_sec));
}
}
}
}
pid_t masterpid;
struct timeval last_respawn;
int unconfigured_hook(struct wsgi_request * wsgi_req)
{
uwsgi_log("-- unavailable modifier requested: %d --\n", wsgi_req->uh.modifier1);
return -1;
}
static void unconfigured_after_hook(struct wsgi_request * wsgi_req)
{
return;
}
struct uwsgi_plugin unconfigured_plugin = {
.name = "unconfigured",
.request = unconfigured_hook,
.after_request = unconfigured_after_hook,
};
static void vacuum(void)
{
int i;
if (uwsgi.vacuum) {
if (getpid() == masterpid) {
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
}
if (uwsgi.pidfile && !uwsgi.uid) {
if (unlink(uwsgi.pidfile)) {
uwsgi_error("unlink()");
} else {
uwsgi_log("VACUUM: pidfile removed.\n");
}
}
if (uwsgi.pidfile2) {
if (unlink(uwsgi.pidfile2)) {
uwsgi_error("unlink()");
} else {
uwsgi_log("VACUUM: pidfile2 removed.\n");
}
}
if (uwsgi.chdir) {
if (chdir(uwsgi.chdir)) {
uwsgi_error("chdir()");
}
}
for (i = 0; i < uwsgi.sockets_cnt; i++) {
if (uwsgi.sockets[i].family == AF_UNIX) {
if (unlink(uwsgi.sockets[i].name)) {
uwsgi_error("unlink()");
} else {
uwsgi_log("VACUUM: unix socket %s removed.\n", uwsgi.sockets[i].name);
}
}
}
}
}
}
int main(int argc, char *argv[], char *envp[])
{
int i, j;
int rlen;
FILE *pidfile;
char *env_reloads;
char env_reload_buf[11];
char *plugins_requested;
#ifdef UNBIT
//struct uidsec_struct us;
#endif
#ifdef UWSGI_DEBUG
struct utsname uuts;
#endif
char *emperor_env;
char *magic_table[0xff];
char *optname;
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
init_magic_table(magic_table);
//initialize masterpid with a default value
masterpid = getpid();
memset(&uwsgi, 0, sizeof(struct uwsgi_server));
uwsgi.cwd = uwsgi_get_cwd();
atexit(vacuum);
#ifdef UWSGI_DEBUG
#ifdef __sun__
if (uname(&uuts) < 0) {
#else
if (uname(&uuts)) {
#endif
uwsgi_error("uname()");
} else {
uwsgi_log("SYSNAME: %s\nNODENAME: %s\nRELEASE: %s\nVERSION: %s\nMACHINE: %s\n",
uuts.sysname,
uuts.nodename,
uuts.release,
uuts.version,
uuts.machine);
}
#endif
uwsgi.shared = (struct uwsgi_shared *) mmap(NULL, sizeof(struct uwsgi_shared), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.shared) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.shared, 0, sizeof(struct uwsgi_shared));
#ifdef UWSGI_SPOOLER
//set the spooler frequency to 30 seconds by default
uwsgi.shared->spooler_frequency = 30;
#endif
for (i = 0; i < 0xFF; i++) {
uwsgi.p[i] = &unconfigured_plugin;
}
uwsgi.master_queue = -1;
uwsgi.emperor_fd_config = -1;
uwsgi.cluster_fd = -1;
uwsgi.cores = 1;
uwsgi.apps_cnt = 0;
uwsgi.default_app = -1;
uwsgi.buffer_size = 4096;
uwsgi.numproc = 1;
uwsgi.async = 1;
uwsgi.listen_queue = 100;
uwsgi.max_vars = MAX_VARS;
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
gettimeofday(&uwsgi.start_tv, NULL);
setlinebuf(stdout);
uwsgi.rl.rlim_cur = 0;
uwsgi.rl.rlim_max = 0;
emperor_env = getenv("UWSGI_EMPEROR_FD");
if (emperor_env) {
uwsgi.has_emperor = 1;
uwsgi.emperor_fd = atoi(emperor_env);
uwsgi.master_process = 1;
uwsgi.no_orphans = 1;
uwsgi_log("*** has_emperor mode detected (fd: %d) ***\n", uwsgi.emperor_fd);
if (getenv("UWSGI_EMPEROR_FD_CONFIG")) {
uwsgi.emperor_fd_config = atoi(getenv("UWSGI_EMPEROR_FD_CONFIG"));
}
}
env_reloads = getenv("UWSGI_RELOADS");
if (env_reloads) {
//convert env value to int
uwsgi.reloads = atoi(env_reloads);
uwsgi.reloads++;
//convert reloads to string
rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
if (rlen > 0) {
env_reload_buf[rlen] = 0;
if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
uwsgi_error("setenv()");
}
}
uwsgi.is_a_reload = 1;
} else {
if (setenv("UWSGI_RELOADS", "0", 1)) {
uwsgi_error("setenv()");
}
}
uwsgi.binary_path = argv[0];
//initialize embedded plugins
UWSGI_LOAD_EMBEDDED_PLUGINS
// now a bit of magic, if the argv[0] contains a _ try to automatically load a plugin
//uwsgi_log("executable name: %s\n", argv[0]);
char *p = strtok(argv[0], "_");
plugins_requested = NULL;
while (p != NULL) {
p = strtok(NULL, "_");
if (p) plugins_requested = p;
}
if (plugins_requested) {
uwsgi_log("plugin = %s\n", plugins_requested);
uwsgi_load_plugin(0, plugins_requested, NULL, 0);
}
plugins_requested = getenv("UWSGI_PLUGINS");
if (plugins_requested) {
char *p = strtok(plugins_requested, ",");
while (p != NULL) {
uwsgi_load_plugin(-1, p, NULL, 0);
p = strtok(NULL, ",");
}
}
build_options();
uwsgi.option_index = -1;
while ((i = getopt_long(argc, argv, short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
if (uwsgi.option_index > -1) {
optname = (char *)uwsgi.long_options[uwsgi.option_index].name;
}
else {
optname = uwsgi_get_optname_by_index(i);
}
// is this a flagged option ?
if (i == 0) {
add_exported_option(optname, "1", 0);
}
else {
add_exported_option(optname, optarg, 1);
manage_opt(i, optarg);
}
uwsgi.option_index = -1;
}
if (optind < argc) {
char *lazy = argv[optind];
if (lazy[0] != '[') {
if (0) {}
#ifdef UWSGI_XML
else if (!strcmp(lazy+strlen(lazy)-4, ".xml")) {
uwsgi.xml_config = lazy;
}
#endif
#ifdef UWSGI_INI
else if (!strcmp(lazy+strlen(lazy)-4, ".ini")) {
uwsgi.ini = lazy;
}
#endif
#ifdef UWSGI_YAML
else if (!strcmp(lazy+strlen(lazy)-4, ".yml")) {
uwsgi.yaml = lazy;
}
#endif
// manage magic mountpoint
else if ( (lazy[0] == '/' || strchr(lazy, '|')) && strchr(lazy,'=')) {
}
else {
int magic = 0;
for(i =0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->magic) {
if (uwsgi.gp[i]->magic(NULL, lazy)) {
magic = 1;
break;
}
}
}
if (!magic) {
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->magic) {
if (uwsgi.p[i]->magic(NULL, lazy)) {
magic = 1;
break;
}
}
}
}
}
}
}
if (gethostname(uwsgi.hostname, 255)) {
uwsgi_error("gethostname()");
}
uwsgi.hostname_len = strlen(uwsgi.hostname);
magic_table['v'] = uwsgi.cwd;
magic_table['h'] = uwsgi.hostname;
#ifdef UWSGI_XML
if (uwsgi.xml_config != NULL) {
magic_table['o'] = uwsgi.xml_config;
if (uwsgi.xml_config[0] == '/') {
magic_table['p'] = uwsgi.xml_config;
}
else {
magic_table['p'] = uwsgi_concat3(uwsgi.cwd,"/",uwsgi.xml_config);
}
magic_table['s'] = uwsgi_get_last_char(magic_table['p'], '/')+1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s']-magic_table['p'], "", 0);
if (uwsgi_get_last_char(uwsgi.xml_config, '.')) magic_table['e'] = uwsgi_get_last_char(uwsgi.xml_config, '.')+1;
if (uwsgi_get_last_char(magic_table['s'], '.')) magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.')-magic_table['s'], "", 0) ;
uwsgi_xml_config(uwsgi.wsgi_req, 0, magic_table);
uwsgi.xml_config = magic_table['p'];
}
#endif
#ifdef UWSGI_INI
if (uwsgi.ini != NULL) {
magic_table['o'] = uwsgi.ini;
if (uwsgi.ini[0] == '/') {
magic_table['p'] = uwsgi.ini;
}
else {
magic_table['p'] = uwsgi_concat3(uwsgi.cwd,"/",uwsgi.ini);
}
magic_table['s'] = uwsgi_get_last_char(magic_table['p'], '/')+1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s']-magic_table['p'], "", 0);
if (uwsgi_get_last_char(uwsgi.ini, '.')) magic_table['e'] = uwsgi_get_last_char(uwsgi.ini, '.')+1;
if (uwsgi_get_last_char(magic_table['s'], '.')) magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.')-magic_table['s'], "", 0) ;
uwsgi_ini_config(uwsgi.ini, magic_table);
}
#endif
#ifdef UWSGI_YAML
if (uwsgi.yaml != NULL) {
magic_table['o'] = uwsgi.yaml;
if (uwsgi.yaml[0] == '/') {
magic_table['p'] = uwsgi.yaml;
}
else {
magic_table['p'] = uwsgi_concat3(uwsgi.cwd,"/",uwsgi.yaml);
}
magic_table['s'] = uwsgi_get_last_char(magic_table['p'], '/')+1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s']-magic_table['p'], "", 0);
if (uwsgi_get_last_char(uwsgi.yaml, '.')) magic_table['e'] = uwsgi_get_last_char(uwsgi.yaml, '.')+1;
if (uwsgi_get_last_char(magic_table['s'], '.')) magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.')-magic_table['s'], "", 0) ;
uwsgi_yaml_config(uwsgi.yaml, magic_table);
}
#endif
#ifdef UWSGI_LDAP
if (uwsgi.ldap != NULL) {
uwsgi_ldap_config();
}
#endif
//parse environ
parse_sys_envs(environ);
// second pass
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
int has_percent = 0;
char *magic_key = NULL;
char *magic_val = NULL;
if (uwsgi.exported_opts[i]->value && !uwsgi.exported_opts[i]->configured) {
for(j=0;j<(int)strlen(uwsgi.exported_opts[i]->value);j++) {
if (uwsgi.exported_opts[i]->value[j] == '%') {
has_percent = 1;
}
else if (uwsgi.exported_opts[i]->value[j] == '(' && has_percent == 1) {
has_percent = 2;
magic_key = uwsgi.exported_opts[i]->value + j + 1;
}
else if (has_percent > 1) {
if (uwsgi.exported_opts[i]->value[j] == ')') {
if (has_percent <= 2) {
magic_key = NULL;
has_percent = 0;
continue;
}
#ifdef UWSGI_DEBUG
uwsgi_log("need to interpret the %.*s tag\n", has_percent-2, magic_key);
#endif
char *tmp_magic_key = uwsgi_concat2n(magic_key, has_percent-2, "", 0);
magic_val = uwsgi_get_exported_opt(tmp_magic_key);
free(tmp_magic_key);
if (!magic_val) {
magic_key = NULL;
has_percent = 0;
continue;
}
uwsgi.exported_opts[i]->value = uwsgi_concat4n(
uwsgi.exported_opts[i]->value, (magic_key-2) - uwsgi.exported_opts[i]->value,
magic_val, strlen(magic_val),
magic_key + (has_percent-1),
strlen(magic_key + (has_percent-1)), "", 0);
#ifdef UWSGI_DEBUG
uwsgi_log("computed new value = %s\n", uwsgi.exported_opts[i]->value);
#endif
magic_key = NULL;
has_percent = 0;
j = 0;
}
else {
has_percent++;
}
}
else {
has_percent = 0;
}
}
}
}
// ok, the options dictionary is available, lets manage it
struct option *lopt = uwsgi.long_options;
struct option *aopt;
char *val;
for(i=0;i<uwsgi.exported_opts_cnt;i++) {
if (uwsgi.exported_opts[i]->configured) continue;
lopt = uwsgi.long_options;;
while ((aopt = lopt)) {
if (!aopt->name) break;
if (!strcmp(aopt->name, uwsgi.exported_opts[i]->key)) {
val = uwsgi.exported_opts[i]->value;
if (aopt->flag) *aopt->flag = aopt->val;
else if (val) {
if (aopt->has_arg == optional_argument) {
if (!strcasecmp("true", val)) {
val = NULL;
}
}
if (aopt->has_arg == no_argument) {
if (!strcasecmp("false", val) || val[0] == '0') {
lopt++;
continue;
}
}
manage_opt(aopt->val, val);
}
}
lopt++;
}
}
/* uWSGI IS CONFIGURED !!! */
if (uwsgi.dump_options) {
struct option *lopt = uwsgi.long_options;
while(lopt->name) {
fprintf(stdout, "%s\n", lopt->name);
lopt++;
}
exit(0);
}
if (uwsgi.show_config) {
fprintf(stdout, "\n;uWSGI instance configuration\n[uwsgi]\n");
for(i=0;i<uwsgi.exported_opts_cnt;i++) {
if (uwsgi.exported_opts[i]->value) {
fprintf(stdout,"%s = %s\n", uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
}
else {
fprintf(stdout,"%s = true\n", uwsgi.exported_opts[i]->key);
}
}
fprintf(stdout, ";end of configuration\n\n");
}
#ifdef UWSGI_UDP
// get cluster configuration
if (uwsgi.cluster != NULL) {
// get multicast socket
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
// ask for cluster options only if bot pre-existent options are set
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
// now wait max 60 seconds and resend multicast request every 10 seconds
for(;;) {
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
continue;
}
waitfd:
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
if (rlen < 0) {
break;
}
else if (rlen > 0) {
// receive the packet
char clusterbuf[4096];
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, manage_string_opt, NULL)) {
goto options_parsed;
}
else {
goto waitfd;
}
}
}
}
options_parsed:
if (!uwsgi.cluster_nodes) uwsgi_cluster_add_me();
}
#endif
//call after_opt hooks
if (uwsgi.binary_path == argv[0]) {
uwsgi.binary_path = uwsgi_malloc(strlen(argv[0]) + 1);
memcpy(uwsgi.binary_path, argv[0], strlen(argv[0]) + 1);
}
if (!uwsgi.no_initial_output) {
if (uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] == 0) {
uwsgi_log("*** Starting uWSGI %s (%dbit) on [%.*s] ***\n", UWSGI_VERSION, (int) (sizeof(void *)) * 8, 24, ctime((const time_t *) &uwsgi.start_tv.tv_sec));
} else {
uwsgi_log("*** Starting uWSGI %s (CGI mode) (%dbit) on [%.*s] ***\n", UWSGI_VERSION, (int) (sizeof(void *)) * 8, 24, ctime((const time_t *) &uwsgi.start_tv.tv_sec));
}
#ifdef UWSGI_DEBUG
uwsgi_log("***\n*** You are running a DEBUG version of uWSGI, please disable debug in your build profile and recompile it ***\n***\n");
#endif
uwsgi_log("compiled with version: %s on %s\n", __VERSION__, UWSGI_BUILD_DATE);
#ifdef __BIG_ENDIAN__
uwsgi_log("*** big endian arch detected ***\n");
#endif
}
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
uwsgi_log("writing pidfile to %s\n", uwsgi.pidfile);
pidfile = fopen(uwsgi.pidfile, "w");
if (!pidfile) {
uwsgi_error_open(uwsgi.pidfile);
exit(1);
}
if (fprintf(pidfile, "%d\n", (int) getpid()) < 0) {
uwsgi_log("could not write pidfile.\n");
}
fclose(pidfile);
}
for (i = 0; i < uwsgi.shared_sockets_cnt; i++) {
char *tcp_port = strchr(uwsgi.shared_sockets[i].name, ':');
if (tcp_port == NULL) {
uwsgi.shared_sockets[i].fd = bind_to_unix(uwsgi.shared_sockets[i].name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi.shared_sockets[i].family = AF_UNIX;
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", i, uwsgi.shared_sockets[i].name, uwsgi.shared_sockets[i].fd);
} else {
uwsgi.shared_sockets[i].fd = bind_to_tcp(uwsgi.shared_sockets[i].name, uwsgi.listen_queue, tcp_port);
uwsgi.shared_sockets[i].family = AF_INET;
uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", i, uwsgi.shared_sockets[i].name, uwsgi.shared_sockets[i].fd);
}
if (uwsgi.shared_sockets[i].fd < 0) {
uwsgi_log("unable to create shared socket on: %s\n", uwsgi.shared_sockets[i].name);
exit(1);
}
uwsgi.shared_sockets[i].bound = 1;
}
// call jail systems
for(i =0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->jail) {
uwsgi.gp[i]->jail(uwsgi_start, argv);
}
}
#ifdef __linux__
#ifndef CLONE_NEWUTS
#define CLONE_NEWUTS 0x04000000
#endif
#ifndef CLONE_NEWPID
#define CLONE_NEWPID 0x20000000
#endif
#ifndef CLONE_NEWIPC
#define CLONE_NEWIPC 0x08000000
#endif
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif
if (uwsgi.ns) {
for(;;) {
char stack[PTHREAD_STACK_MIN];
int waitpid_status;
uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns);
int clone_flags = SIGCHLD|CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
if (uwsgi.ns_net) {
clone_flags |= CLONE_NEWNET;
}
pid_t pid = clone(uwsgi_start, stack+PTHREAD_STACK_MIN, clone_flags, (void *)argv);
if (pid == -1) {
uwsgi_error("clone()");
exit(1);
}
uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid);
pid = waitpid(pid, &waitpid_status, 0);
if (pid < 0) {
uwsgi_error("waitpid()");
exit(1);
}
// in Linux this is reliable
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 1) {
exit(1);
}
uwsgi_log("pid %d ended. Respawning...\n", (int) pid);
}
}
else {
#endif
uwsgi_start((void *)argv);
#ifdef __linux__
}
#endif
// never here
return 0;
}
int uwsgi_start(void *v_argv) {
char **argv = v_argv;
#ifdef UWSGI_DEBUG
int so_bufsize;
socklen_t so_bufsize_len;
#endif
pid_t pid;
int i, j;
union uwsgi_sockaddr usa;
union uwsgi_sockaddr_ptr gsa, isa;
socklen_t socket_type_len;
int emperor_pipe[2];
#ifdef __linux__
char *ns_tmp_mountpoint=NULL, *ns_tmp_mountpoint2=NULL;
if (uwsgi.ns) {
if (getpid() != 1) {
uwsgi_log("your kernel does not support linux pid namespace\n");
exit(1);
}
char *ns_hostname = strchr(uwsgi.ns, ':');
if (ns_hostname) {
ns_hostname[0] = 0;
ns_hostname++;
if (sethostname(ns_hostname, strlen(ns_hostname))) {
uwsgi_error("sethostname()");
}
}
FILE *procmounts;
char line[1024];
int unmounted = 1;
char *delim0, *delim1;
if (chdir(uwsgi.ns)) {
uwsgi_error("chdir()");
exit(1);
}
if (strcmp(uwsgi.ns, "/")) {
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint, S_IRWXU);
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint2, S_IRWXU);
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
uwsgi_error("mount()");
}
if (chdir(ns_tmp_mountpoint)) {
uwsgi_error("chdir()");
}
if (pivot_root(".", ns_tmp_mountpoint2)) {
uwsgi_error("pivot_root()");
exit(1);
}
if (chdir("/")) {
uwsgi_error("chdir()");
exit(1);
}
}
uwsgi_log("remounting /proc\n");
if (mount("proc","/proc", "proc", 0, NULL)) {
uwsgi_error("mount()");
}
while(unmounted) {
unmounted = 0;
procmounts = fopen("/proc/self/mounts", "r");
while(fgets(line,1024,procmounts) != NULL) {
delim0 = strchr(line, ' ');
delim0++;
delim1 = strchr(delim0, ' ');
*delim1 = 0;
if (!strcmp(delim0,"/") || !strcmp(delim0,"/proc")) continue;
if (!umount(delim0)) {
unmounted++;
}
}
fclose(procmounts);
}
if (rmdir("/.uwsgi_ns_tmp_mountpoint/.uwsgi_ns_tmp_mountpoint")) {
uwsgi_error("rmdir()");
}
if (rmdir("/.uwsgi_ns_tmp_mountpoint")) {
uwsgi_error("rmdir()");
}
if (strcmp(uwsgi.ns, "/")) {
free(ns_tmp_mountpoint2);
free(ns_tmp_mountpoint);
}
}
#endif
if (!uwsgi.master_as_root) {
uwsgi_as_root();
}
if (uwsgi.chdir) {
if (chdir(uwsgi.chdir)) {
uwsgi_error("chdir()");
exit(1);
}
}
if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
uwsgi_log("writing pidfile2 to %s\n", uwsgi.pidfile2);
FILE *pidfile2 = fopen(uwsgi.pidfile2, "w");
if (!pidfile2) {
uwsgi_error_open(uwsgi.pidfile2);
exit(1);
}
if (fprintf(pidfile2, "%d\n", (int) getpid()) < 0) {
uwsgi_log("could not write pidfile2.\n");
}
fclose(pidfile2);
}
if (!uwsgi.no_initial_output) {
if (!uwsgi.master_process) {
uwsgi_log(" *** WARNING: you are running uWSGI without its master process manager ***\n");
}
}
#ifndef __OpenBSD__
if (uwsgi.rl.rlim_max > 0) {
uwsgi_log("limiting address space of processes...\n");
if (setrlimit(RLIMIT_AS, &uwsgi.rl)) {
uwsgi_error("setrlimit()");
}
}
if (uwsgi.prio != 0) {
#ifdef __HAIKU__
if (set_thread_priority(find_thread(NULL), uwsgi.prio) == B_BAD_THREAD_ID) {
uwsgi_error("set_thread_priority()");
#else
if (setpriority(PRIO_PROCESS, 0, uwsgi.prio)) {
uwsgi_error("setpriority()");
#endif
} else {
uwsgi_log("scheduler priority set to %d\n", uwsgi.prio);
}
}
if (!getrlimit(RLIMIT_AS, &uwsgi.rl)) {
//check for overflow
if (uwsgi.rl.rlim_max != RLIM_INFINITY && !uwsgi.no_initial_output) {
uwsgi_log("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);
}
}
#endif
uwsgi.page_size = getpagesize();
if (!uwsgi.no_initial_output) {
uwsgi_log("your memory page size is %d bytes\n", uwsgi.page_size);
}
if (uwsgi.buffer_size > 65536) {
uwsgi_log("invalid buffer size.\n");
exit(1);
}
sanitize_args();
// end of generic initialization
// start the Emperor if needed
if (uwsgi.emperor_dir) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, emperor_pipe)) {
uwsgi_error("socketpair()");
exit(1);
}
uwsgi.emperor_pid = fork();
if (uwsgi.emperor_pid < 0) {
uwsgi_error("pid()");
exit(1);
}
else if (uwsgi.emperor_pid > 0) {
close(emperor_pipe[1]);
emperor_loop();
// never here
exit(1);
}
// do not go on if no socket or gateway is defined
if (!uwsgi.sockets_cnt && !uwsgi.gateways_cnt) {
exit(0);
}
close(emperor_pipe[0]);
uwsgi.has_emperor = 1;
uwsgi.emperor_fd = emperor_pipe[1];
uwsgi.master_process = 1;
uwsgi.no_orphans = 1;
}
uwsgi_register_loop("simple", simple_loop);
uwsgi_register_loop("async", async_loop);
// TODO rewrite to use uwsgi.max_fd
if (uwsgi.async > 1) {
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
if ((unsigned long) uwsgi.rl.rlim_cur < (unsigned long) uwsgi.async) {
uwsgi_log("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.rl.rlim_cur);
if (uwsgi.rl.rlim_cur < uwsgi.rl.rlim_max && (unsigned long) uwsgi.rl.rlim_max > (unsigned long) uwsgi.async) {
unsigned long tmp_nofile = (unsigned long) uwsgi.rl.rlim_cur;
uwsgi.rl.rlim_cur = uwsgi.async;
if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi_log("max open files limit reset to %lu\n", (unsigned long) uwsgi.rl.rlim_cur);
uwsgi.async = uwsgi.rl.rlim_cur;
} else {
uwsgi.async = (int) tmp_nofile;
}
} else {
uwsgi.async = uwsgi.rl.rlim_cur;
}
uwsgi_log("- async cores set to %d -\n", uwsgi.async);
}
}
}
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi.max_fd = uwsgi.rl.rlim_cur;
}
uwsgi.wsgi_requests = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.cores);
for (i = 0; i < uwsgi.cores; i++) {
uwsgi.wsgi_requests[i] = uwsgi_malloc(sizeof(struct wsgi_request));
memset(uwsgi.wsgi_requests[i], 0, sizeof(struct wsgi_request));
}
uwsgi.async_buf = uwsgi_malloc(sizeof(char *) * uwsgi.cores);
if (uwsgi.async > 1) {
uwsgi_log("async fd table size: %d\n", uwsgi.max_fd);
uwsgi.async_waiting_fd_table = malloc( sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_waiting_fd_table) {
uwsgi_error("malloc()");
exit(1);
}
}
if (uwsgi.post_buffering > 0) {
uwsgi.async_post_buf = uwsgi_malloc(sizeof(char *) * uwsgi.cores);
if (!uwsgi.post_buffering_bufsize) {
uwsgi.post_buffering_bufsize = 8192;
}
}
for (i = 0; i < uwsgi.cores; i++) {
uwsgi.async_buf[i] = uwsgi_malloc(uwsgi.buffer_size);
if (uwsgi.post_buffering > 0) {
uwsgi.async_post_buf[i] = uwsgi_malloc(uwsgi.post_buffering_bufsize);
}
}
//by default set wsgi_req to the first slot
uwsgi.wsgi_req = uwsgi.wsgi_requests[0];
if (uwsgi.cores > 1) {
uwsgi_log("allocated %llu bytes (%llu KB) for %d cores per worker.\n", (uint64_t) (sizeof(struct wsgi_request) * uwsgi.cores),
(uint64_t) ((sizeof(struct wsgi_request) * uwsgi.cores) / 1024),
uwsgi.cores);
}
if (uwsgi.vhost) {
uwsgi_log("VirtualHosting mode enabled.\n");
uwsgi.apps_cnt = 0;
}
// application generic lock
uwsgi.user_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.user_lock);
if (uwsgi.master_process) {
// signal table lock
uwsgi.signal_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.signal_table_lock);
// fmon table lock
uwsgi.fmon_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.fmon_table_lock);
// timer table lock
uwsgi.timer_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.timer_table_lock);
// rb_timer table lock
uwsgi.rb_timer_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.rb_timer_table_lock);
// daemons table lock
uwsgi.daemon_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.daemon_table_lock);
// cron table lock
uwsgi.cron_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.cron_table_lock);
}
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir) {
// spooler lock
uwsgi.spooler_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.spooler_lock);
}
#endif
uwsgi.rpc_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.rpc_table_lock);
if (uwsgi.sharedareasize > 0) {
uwsgi.sharedareamutex = uwsgi_mmap_shared_lock();
uwsgi.sharedarea = mmap(NULL, uwsgi.page_size * uwsgi.sharedareasize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (uwsgi.sharedarea) {
uwsgi_log("shared area mapped at %p, you can access it with uwsgi.sharedarea* functions.\n", uwsgi.sharedarea);
uwsgi_lock_init(uwsgi.sharedareamutex);
} else {
uwsgi_error("mmap()");
exit(1);
}
}
if (uwsgi.queue_size > 0) {
if (!uwsgi.queue_blocksize) uwsgi.queue_blocksize = 8192;
if (uwsgi.queue_blocksize % uwsgi.page_size != 0) {
uwsgi_log("invalid queue blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size);
exit(1);
}
uwsgi.shared->queue_pos = 0;
uwsgi.shared->queue_pull_pos = 0;
if (uwsgi.queue_store) {
uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size;
int queue_fd;
struct stat qst;
if (stat(uwsgi.queue_store, &qst)) {
uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store);
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
if (queue_fd >= 0) {
// fill the queue store
if (ftruncate(queue_fd, uwsgi.queue_filesize)) {
uwsgi_log("ftruncate()");
exit(1);
}
}
}
else {
if ((size_t)qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) {
uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n");
exit(1);
}
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store);
}
if (queue_fd < 0) {
uwsgi_error_open(uwsgi.queue_store);
exit(1);
}
uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
uwsgi_queue_fix();
}
else {
uwsgi.queue = mmap(NULL, uwsgi.queue_blocksize * uwsgi.queue_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
}
if (!uwsgi.queue) {
uwsgi_error("mmap()");
exit(1);
}
uwsgi.queue_lock = uwsgi_mmap_shared_rwlock();
uwsgi_rwlock_init(uwsgi.queue_lock);
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024*1024));
}
if (uwsgi.cache_max_items > 0) {
if (!uwsgi.cache_blocksize) uwsgi.cache_blocksize = UMAX16;
if (uwsgi.cache_blocksize % uwsgi.page_size != 0) {
uwsgi_log("invalid cache blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.cache_blocksize, uwsgi.page_size);
exit(1);
}
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache_hashtable) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache_unused_stack) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
// the first cache item is always zero
uwsgi.shared->cache_first_available_item = 1;
uwsgi.shared->cache_unused_stack_ptr = 0;
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (uwsgi.cache_store) {
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
int cache_fd;
struct stat cst;
if (stat(uwsgi.cache_store, &cst)) {
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
if (cache_fd >= 0) {
// fill the caching store
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
uwsgi_log("ftruncate()");
exit(1);
}
}
}
else {
if ((size_t)cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
exit(1);
}
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
}
if (cache_fd < 0) {
uwsgi_error_open(uwsgi.cache_store);
exit(1);
}
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
uwsgi_cache_fix();
}
else {
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
for(i=0;i< (int) uwsgi.cache_max_items;i++) {
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
}
}
if (!uwsgi.cache_items) {
uwsgi_error("mmap()");
exit(1);
}
/*
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.cache) {
uwsgi_error("mmap()");
exit(1);
}
*/
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) ;
uwsgi.cache_lock = uwsgi_mmap_shared_rwlock();
uwsgi_rwlock_init(uwsgi.cache_lock);
uwsgi.p[111] = &uwsgi_cache_plugin;
uwsgi_log("*** Cache subsystem initialized: %dMB preallocated ***\n", ((sizeof(uint64_t) * UMAX16) + (sizeof(uint64_t) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024*1024));
}
// attach startup daemons
if (uwsgi.master_process) {
for(i=0;i<uwsgi.startup_daemons_cnt;i++) {
if (uwsgi_attach_daemon(uwsgi.startup_daemons[i])) {
uwsgi_log("!!! unable to attach daemon %s !!!\n", uwsgi.startup_daemons[i]);
}
}
}
/* plugin initialization */
for(i =0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->init) {
uwsgi.gp[i]->init();
}
}
if (!uwsgi.no_server) {
//check for inherited sockets
if (uwsgi.is_a_reload) {
for (i = 0; i < uwsgi.sockets_cnt; i++) {
//a bit overengineering
if (uwsgi.sockets[i].name != NULL) {
for (j = 3; j < sysconf(_SC_OPEN_MAX); j++) {
socket_type_len = sizeof(struct sockaddr_un);
gsa.sa = &usa.sa;
if (!getsockname(j, gsa.sa, &socket_type_len)) {
if (socket_type_len <= 2) {
// unbound socket
continue;
}
if (gsa.sa->sa_family == AF_UNIX) {
if (!strcmp(usa.sa_un.sun_path, uwsgi.sockets[i].name)) {
uwsgi.sockets[i].fd = j;
uwsgi.sockets[i].family = AF_UNIX;
uwsgi.sockets[i].bound = 1;
uwsgi.sockets_poll[i].fd = uwsgi.sockets[i].fd;
uwsgi.sockets_poll[i].events = POLLIN;
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd %d\n", i, uwsgi.sockets[i].name, uwsgi.sockets[i].fd);
}
} else if (gsa.sa->sa_family == AF_INET) {
char *computed_addr;
char computed_port[6];
isa.sa_in = (struct sockaddr_in *) &usa;
char ipv4a[INET_ADDRSTRLEN + 1];
memset(ipv4a, 0, INET_ADDRSTRLEN + 1);
memset(computed_port, 0, 6);
if (snprintf(computed_port, 6, "%d", ntohs(isa.sa_in->sin_port)) > 0) {
if (inet_ntop(AF_INET, (const void *) &isa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) {
if (!strcmp("0.0.0.0", ipv4a)) {
computed_addr = uwsgi_concat2(":", computed_port);
} else {
computed_addr = uwsgi_concat3(ipv4a, ":", computed_port);
}
char *asterisk = strchr(uwsgi.sockets[i].name, '*');
int match = 1;
if (asterisk) {
asterisk[0] = 0;
match = strncmp(computed_addr, uwsgi.sockets[i].name, strlen(uwsgi.sockets[i].name));
asterisk[0] = '*';
}
else {
match = strcmp(computed_addr, uwsgi.sockets[i].name);
}
if (!match) {
uwsgi.sockets[i].fd = j;
uwsgi.sockets[i].family = AF_INET;
uwsgi.sockets[i].bound = 1;
uwsgi.sockets_poll[i].fd = uwsgi.sockets[i].fd;
uwsgi.sockets_poll[i].events = POLLIN;
uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", i, uwsgi.sockets[i].name, uwsgi.sockets[i].fd);
}
free(computed_addr);
}
}
}
}
}
}
}
//now close all the unbound fd
for (j = 3; j < sysconf(_SC_OPEN_MAX); j++) {
int useless = 1;
#ifdef UWSGI_MULTICAST
if (j == uwsgi.cluster_fd) continue;
#endif
if (uwsgi.has_emperor) { if (j == uwsgi.emperor_fd) continue; }
socket_type_len = sizeof(struct sockaddr_un);
gsa.sa = (struct sockaddr *) & usa;
if (!getsockname(j, gsa.sa, &socket_type_len)) {
for (i = 0; i < uwsgi.sockets_cnt; i++) {
if (uwsgi.sockets[i].fd == j && uwsgi.sockets[i].bound) {
useless = 0;
break;
}
}
}
if (useless)
close(j);
}
}
//now bind all the unbound sockets
for (i = 0; i < uwsgi.sockets_cnt; i++) {
if (!uwsgi.sockets[i].bound) {
char *tcp_port = strchr(uwsgi.sockets[i].name, ':');
if (tcp_port == NULL) {
uwsgi.sockets[i].fd = bind_to_unix(uwsgi.sockets[i].name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi.sockets[i].family = AF_UNIX;
uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", i, uwsgi.sockets[i].name, uwsgi.sockets[i].fd);
} else {
uwsgi.sockets[i].fd = bind_to_tcp(uwsgi.sockets[i].name, uwsgi.listen_queue, tcp_port);
uwsgi.sockets[i].family = AF_INET;
uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", i, uwsgi.sockets[i].name, uwsgi.sockets[i].fd);
}
if (uwsgi.sockets[i].fd < 0) {
uwsgi_log("unable to create server socket on: %s\n", uwsgi.sockets[i].name);
exit(1);
}
}
uwsgi.sockets[i].bound = 1;
uwsgi.sockets_poll[i].fd = uwsgi.sockets[i].fd;
uwsgi.sockets_poll[i].events = POLLIN;
}
int zero_used = 0;
for (i = 0; i < uwsgi.sockets_cnt; i++) {
if (uwsgi.sockets[i].bound && uwsgi.sockets[i].fd == 0) {
zero_used = 1;
break;
}
}
if (!zero_used) {
socket_type_len = sizeof(struct sockaddr_un);
gsa.sa = (struct sockaddr *) & usa;
if (!getsockname(0, gsa.sa, &socket_type_len)) {
if (uwsgi.sockets_cnt < 8) {
uwsgi.sockets_cnt++;
uwsgi.sockets[uwsgi.sockets_cnt - 1].fd = 0;
uwsgi.sockets[uwsgi.sockets_cnt - 1].bound = 1;
uwsgi.sockets[uwsgi.sockets_cnt - 1].family = gsa.sa->sa_family;
if (uwsgi.sockets[uwsgi.sockets_cnt - 1].family == AF_UNIX) {
uwsgi.sockets[uwsgi.sockets_cnt - 1].name = usa.sa_un.sun_path;
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi.sockets_cnt - 1, uwsgi.sockets[uwsgi.sockets_cnt - 1].name);
}
else {
uwsgi_log("uwsgi socket %d inherited INET address %s fd 0\n", uwsgi.sockets_cnt - 1, uwsgi.sockets[uwsgi.sockets_cnt - 1].name);
}
uwsgi.sockets_poll[uwsgi.sockets_cnt - 1].fd = 0;
uwsgi.sockets_poll[uwsgi.sockets_cnt - 1].events = POLLIN;
} else {
uwsgi_log("too many socket defined, i cannot map fd 0\n");
}
} else {
int fd = open("/dev/null", O_RDONLY);
if (fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
if (fd != 0) {
if (dup2(fd, 0)) {
uwsgi_error("dup2()");
exit(1);
}
}
}
}
// put listening socket in non-blocking state
for (i = 0; i < uwsgi.sockets_cnt; i++) {
uwsgi.sockets[i].arg = fcntl(uwsgi.sockets[i].fd, F_GETFL, NULL);
if (uwsgi.sockets[i].arg < 0) {
uwsgi_error("fcntl()");
exit(1);
}
uwsgi.sockets[i].arg |= O_NONBLOCK;
if (fcntl(uwsgi.sockets[i].fd, F_SETFL, uwsgi.sockets[i].arg) < 0) {
uwsgi_error("fcntl()");
exit(1);
}
}
}
// initialize request plugin only if workers or master are available
if (uwsgi.sockets_cnt || uwsgi.master_process) {
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init) {
uwsgi.p[i]->init();
}
}
}
/* gp/plugin initialization */
for(i =0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->post_init) {
uwsgi.gp[i]->post_init();
}
}
for(i =0; i < 0xff; i++) {
if (uwsgi.p[i]->post_init) {
uwsgi.p[i]->post_init();
}
}
uwsgi.current_wsgi_req = simple_current_wsgi_req;
#ifdef UWSGI_THREADING
if (uwsgi.sockets_cnt) {
if (uwsgi.has_threads) {
if (uwsgi.threads > 1)
uwsgi.current_wsgi_req = threaded_current_wsgi_req;
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->enable_threads)
uwsgi.p[i]->enable_threads();
}
}
}
#endif
if (!uwsgi.sockets_cnt && !uwsgi.gateways_cnt && !uwsgi.no_server) {
uwsgi_log("The -s/--socket option is missing and stdin is not a socket.\n");
exit(1);
}
else if (!uwsgi.sockets_cnt && uwsgi.gateways_cnt && !uwsgi.no_server && !uwsgi.master_process) {
exit(0);
}
if (!uwsgi.sockets_cnt) uwsgi.numproc = 0;
#ifdef UWSGI_DEBUG
for (i = 0; i < uwsgi.sockets_cnt; i++) {
so_bufsize_len = sizeof(int);
if (getsockopt(uwsgi.sockets[i].fd, SOL_SOCKET, SO_RCVBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("getsockopt()");
} else {
uwsgi_debug("uwsgi socket %d SO_RCVBUF size: %d\n", i, so_bufsize);
}
so_bufsize_len = sizeof(int);
if (getsockopt(uwsgi.sockets[i].fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("getsockopt()");
} else {
uwsgi_debug("uwsgi socket %d SO_SNDBUF size: %d\n", i, so_bufsize);
}
}
#endif
#ifndef UNBIT
uwsgi_log("your server socket listen backlog is limited to %d connections\n", uwsgi.listen_queue);
#endif
memset(uwsgi.apps, 0, sizeof(uwsgi.apps));
uwsgi.workers = (struct uwsgi_worker *) mmap(NULL, sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1 + uwsgi.grunt), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.workers) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.workers, 0, sizeof(struct uwsgi_worker) * uwsgi.numproc + 1);
for(i=0;i<MAX_SOCKETS;i++) {
if (!uwsgi.map_socket[i]) continue;
char *p = strtok(uwsgi.map_socket[i], ",");
while (p != NULL) {
int w = atoi(p);
if (w < 1 || w > uwsgi.numproc) {
uwsgi_log("invalid worker num: %d\n", w);
exit(1);
}
uwsgi.workers[w].sockets_mask[i] = 1;
uwsgi_log("mapped socket %d (%s) to worker %d\n", i, uwsgi.sockets[i].name, w);
p = strtok(NULL, ",");
}
}
uwsgi.mypid = getpid();
masterpid = uwsgi.mypid;
if (uwsgi.cores > 1) {
for (i = 0; i < uwsgi.numproc+1; i++) {
uwsgi.core = (struct uwsgi_core **) mmap(NULL, sizeof(struct uwsgi_core *) * uwsgi.cores, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.core) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.core, 0, sizeof(struct uwsgi_core *) * uwsgi.cores);
for (j = 0; j < uwsgi.cores; j++) {
uwsgi.core[j] = (struct uwsgi_core *) mmap(NULL, sizeof(struct uwsgi_core), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uwsgi.core[j]) {
uwsgi_error("mmap()");
exit(1);
}
memset(uwsgi.core[j], 0, sizeof(struct uwsgi_core));
}
}
}
uwsgi.workers[0].pid = masterpid;
/*
uwsgi.shared->hooks[0] = uwsgi_request_wsgi;
uwsgi.shared->after_hooks[0] = uwsgi_after_request_wsgi;
uwsgi.shared->hooks[UWSGI_MODIFIER_ADMIN_REQUEST] = uwsgi_request_admin; //10
#ifdef UWSGI_SPOOLER
uwsgi.shared->hooks[UWSGI_MODIFIER_SPOOL_REQUEST] = uwsgi_request_spooler; //17
#endif
uwsgi.shared->hooks[UWSGI_MODIFIER_EVAL] = uwsgi_request_eval; //22
uwsgi.shared->hooks[UWSGI_MODIFIER_FASTFUNC] = uwsgi_request_fastfunc; //26
uwsgi.shared->hooks[UWSGI_MODIFIER_MANAGE_PATH_INFO] = uwsgi_request_wsgi; // 30
uwsgi.shared->after_hooks[UWSGI_MODIFIER_MANAGE_PATH_INFO] = uwsgi_after_request_wsgi; // 30
uwsgi.shared->hooks[UWSGI_MODIFIER_MESSAGE_MARSHAL] = uwsgi_request_marshal; //33
uwsgi.shared->hooks[UWSGI_MODIFIER_PING] = uwsgi_request_ping; //100
*/
uwsgi_log("*** Operational MODE: ");
if (!uwsgi.numproc) {
uwsgi_rawlog("no-workers");
}
else if (uwsgi.threads > 1) {
if (uwsgi.numproc > 1) {
uwsgi_rawlog("preforking+threaded");
} else {
uwsgi_rawlog("threaded");
}
}
#ifdef UWSGI_ASYNC
else if (uwsgi.async > 1) {
if (uwsgi.numproc > 1) {
uwsgi_rawlog("preforking+async");
} else {
uwsgi_rawlog("async");
}
}
#endif
else if (uwsgi.numproc > 1) {
uwsgi_rawlog("preforking");
} else {
uwsgi_rawlog("single process");
}
uwsgi_rawlog(" ***\n");
//init apps hook
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init_apps) {
uwsgi.p[i]->init_apps();
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->init_apps) {
uwsgi.gp[i]->init_apps();
}
}
/*parse xml for <app> tags */
#ifdef UWSGI_XML
if (uwsgi.xml_round2 && uwsgi.xml_config != NULL) {
uwsgi_xml_config(uwsgi.wsgi_req, 1, NULL);
}
#endif
for (i = 0; i < uwsgi.mounts_cnt; i++) {
char *what = strchr(uwsgi.mounts[i], '=');
if (what) {
what[0] = 0;
what++;
uwsgi_log("mounting %s on %s\n", what, uwsgi.mounts[i]);
for (j = 0; j < 0xFF; j++) {
if (uwsgi.p[j]->mount_app) {
if (uwsgi.p[j]->mount_app(uwsgi.mounts[i], what) != -1) break;
}
}
what--; what[0] = '=';
} else {
uwsgi_log("invalid mountpoint: %s\n", uwsgi.mounts[i]);
exit(1);
}
}
if (uwsgi.no_server) {
uwsgi_log("no-server mode requested. Goodbye.\n");
exit(0);
}
//is this a proxy only worker ?
if (!uwsgi.master_process && uwsgi.numproc == 0) {
exit(0);
}
if (!uwsgi.single_interpreter) {
uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n");
}
if (uwsgi.master_process) {
if (uwsgi.is_a_reload) {
uwsgi_log("gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
} else {
uwsgi_log("spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
}
}
// security in multiuser environment: allow only a subset of modifiers
if (uwsgi.allowed_modifiers) {
for (i = 0; i < 0xFF; i++) {
if (!uwsgi_list_has_num(uwsgi.allowed_modifiers, i)) {
uwsgi.p[i]->request = unconfigured_hook;
uwsgi.p[i]->after_request = unconfigured_after_hook;
}
}
}
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir != NULL && uwsgi.sockets_cnt > 0) {
uwsgi.shared->spooler_pid = spooler_start();
}
#endif
#ifdef UWSGI_ROUTING
routing_setup();
#endif
if (!uwsgi.master_process) {
if (uwsgi.numproc == 1) {
uwsgi_log("spawned uWSGI worker 1 (and the only) (pid: %d, cores: %d)\n", masterpid, uwsgi.cores);
} else {
uwsgi_log("spawned uWSGI worker 1 (pid: %d, cores: %d)\n", masterpid, uwsgi.cores);
}
uwsgi.workers[1].pid = masterpid;
uwsgi.workers[1].id = 1;
uwsgi.workers[1].last_spawn = time(NULL);
uwsgi.workers[1].manage_next_request = 1;
uwsgi.mywid = 1;
gettimeofday(&last_respawn, NULL);
uwsgi.respawn_delta = last_respawn.tv_sec;
}
else {
// setup internal signalling system
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_signal_pipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
}
for (i = 2 - uwsgi.master_process; i < uwsgi.numproc + 1; i++) {
pid = fork();
if (pid == 0) {
close(uwsgi.shared->worker_signal_pipe[0]);
uwsgi.mypid = getpid();
uwsgi.workers[i].pid = uwsgi.mypid;
uwsgi.workers[i].id = i;
uwsgi.workers[i].last_spawn = time(NULL);
uwsgi.workers[i].manage_next_request = 1;
uwsgi.mywid = i;
break;
} else if (pid < 1) {
uwsgi_error("fork()");
exit(1);
} else {
uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", i, pid, uwsgi.cores);
//close(uwsgi.workers[i].pipe[1]);
gettimeofday(&last_respawn, NULL);
uwsgi.respawn_delta = last_respawn.tv_sec;
}
}
if (getpid() == masterpid && uwsgi.master_process == 1) {
master_loop(argv, environ);
//from now on the process is a real worker
}
for(i=0;i<uwsgi.sockets_cnt;i++) {
if (uwsgi.workers[uwsgi.mywid].sockets_mask[i]) {
// disable the socket for this worker
#ifdef UWSGI_DEBUG
uwsgi_log("switching off socket %d (%d) on worker %d\n", i, uwsgi.sockets[i].fd, uwsgi.mywid);
#endif
int fd = uwsgi.sockets[i].fd;
close(fd);
fd = open("/dev/null", O_RDONLY);
if (fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
if (fd != uwsgi.sockets[i].fd) {
if (dup2(fd, uwsgi.sockets[i].fd)) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
uwsgi.sockets_poll[i].fd = -1;
uwsgi.sockets_poll[i].events = 0;
}
}
if (uwsgi.cpu_affinity) {
#ifdef __linux__
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
int ncpu = sysconf(_SC_NPROCESSORS_ONLN);
int base_cpu = (uwsgi.mywid-1)*uwsgi.cpu_affinity;
if (base_cpu >= ncpu) {
base_cpu = base_cpu % ncpu;
}
uwsgi_log("set cpu affinity for worker %d to", uwsgi.mywid);
for(i=0;i<uwsgi.cpu_affinity;i++) {
if (base_cpu >= ncpu) base_cpu = 0 ;
CPU_SET(base_cpu, &cpuset);
uwsgi_log(" %d", base_cpu);
base_cpu++;
}
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset)) {
uwsgi_error("sched_setaffinity()");
}
uwsgi_log("\n");
#endif
}
if (uwsgi.worker_exec) {
char *w_argv[2];
w_argv[0] = uwsgi.worker_exec;
w_argv[1] = NULL;
uwsgi.sockets[0].arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.sockets[i].fd, F_SETFL, uwsgi.sockets[i].arg) < 0) {
uwsgi_error("fcntl()");
exit(1);
}
if (uwsgi.sockets[0].fd != 0) {
if (dup2(uwsgi.sockets[0].fd, 0)) {
uwsgi_error("dup2()");
}
}
execvp(w_argv[0], w_argv);
// never here
uwsgi_error("execvp()");
exit(1);
}
if (uwsgi.master_as_root) {
uwsgi_as_root();
}
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->post_fork) {
uwsgi.p[i]->post_fork();
}
}
//postpone the queue initialization as kevent
//do not pass kfd after fork()
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
uwsgi.async_queue = event_queue_init();
if (uwsgi.async_queue < 0) {
exit(1);
}
for(i=0;i<uwsgi.sockets_cnt;i++) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.sockets[i].fd);
}
}
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request*) * uwsgi.async);
for(i=0;i<uwsgi.async;i++) {
uwsgi.async_queue_unused[i] = uwsgi.wsgi_requests[i];
}
uwsgi.async_queue_unused_ptr = uwsgi.async-1;
#endif
uwsgi.async_hvec = uwsgi_malloc(sizeof(struct iovec *) * uwsgi.cores);
for (i = 0; i < uwsgi.cores; i++) {
uwsgi.async_hvec[i] = uwsgi_malloc(sizeof(struct iovec) * uwsgi.vec_size);
}
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && !uwsgi.master_process) {
signal(SIGALRM, (void *) &harakiri);
}
uwsgi_unix_signal(SIGHUP, gracefully_kill);
uwsgi_unix_signal(SIGINT, end_me);
uwsgi_unix_signal(SIGTERM, reload_me);
uwsgi_unix_signal(SIGUSR1, stats);
signal(SIGUSR2, (void *) &what_i_am_doing);
signal(SIGPIPE, (void *) &warn_pipe);
//initialization done
if (uwsgi.chdir2) {
if (chdir(uwsgi.chdir2)) {
uwsgi_error("chdir()");
exit(1);
}
}
//re - initialize wsgi_req(can be full of init_uwsgi_app data)
for (i = 0; i < uwsgi.cores; i++) {
memset(uwsgi.wsgi_requests[i], 0, sizeof(struct wsgi_request));
uwsgi.wsgi_requests[i]->async_id = i;
}
// eventually remap plugins
if (uwsgi.remap_modifier) {
char *map = strtok(uwsgi.remap_modifier, ",");
struct uwsgi_plugin *up_tmp;
while (map != NULL) {
char *colon = strchr(map, ':');
if (colon) {
colon[0] = 0;
int rm_src = atoi(map);
int rm_dst = atoi(colon+1);
up_tmp = uwsgi.p[rm_dst] ;
uwsgi.p[rm_dst] = uwsgi.p[rm_src];
uwsgi.p[rm_src] = up_tmp ;
// fix rpc
for(i=0;i<uwsgi.shared->rpc_count;i++) {
if (uwsgi.shared->rpc_table[i].modifier1 == rm_src) uwsgi.shared->rpc_table[i].modifier1 = rm_dst;
else if (uwsgi.shared->rpc_table[i].modifier1 == rm_dst) uwsgi.shared->rpc_table[i].modifier1 = rm_src;
}
}
map = strtok(NULL, ",");
}
}
if (uwsgi.master_process) {
uwsgi.sockets_poll[uwsgi.sockets_cnt].fd = uwsgi.shared->worker_signal_pipe[1];
uwsgi.sockets_poll[uwsgi.sockets_cnt].events = POLLIN;
#ifdef UWSGI_ASYNC
// add uwsgi signal fd to async queue
if (uwsgi.async > 1) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.sockets_poll[uwsgi.sockets_cnt].fd);
}
#endif
}
if (uwsgi.loop) {
void (*u_loop) (void) = uwsgi_get_loop(uwsgi.loop);
uwsgi_log("running %s loop %p\n", uwsgi.loop, u_loop);
u_loop();
uwsgi_log("done\n");
goto end;
} else {
if (uwsgi.threads > 1) {
pthread_attr_t pa;
pthread_t *a_thread;
int ret;
ret = pthread_attr_init(&pa);
if (ret) {
uwsgi_log("pthread_attr_init() = %d\n", ret);
exit(1);
}
ret = pthread_attr_setdetachstate(&pa, PTHREAD_CREATE_DETACHED);
if (ret) {
uwsgi_log("pthread_attr_setdetachstate() = %d\n", ret);
exit(1);
}
if (pthread_key_create(&uwsgi.tur_key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
for (i = 1; i < uwsgi.threads; i++) {
long j = i;
a_thread = uwsgi_malloc(sizeof(pthread_t));
pthread_create(a_thread, &pa, simple_loop, (void *) j);
}
}
if (uwsgi.async < 2) {
long y = 0;
simple_loop((void *) y);
} else {
async_loop(NULL);
}
}
end:
if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) {
reload_me(0);
} else {
goodbye_cruel_world();
}
// never here
return 0;
}
static int manage_base_opt(int i, char *optarg) {
char *p;
struct uwsgi_static_map *usm;
switch (i) {
case 0:
return 1;
#ifdef UWSGI_UDP
case LONG_ARGS_CLUSTER_RELOAD:
send_udp_message(98, optarg, "", 0);
break;
case LONG_ARGS_CLUSTER_LOG:
uwsgi_stdin_sendto(optarg, 96, 0);
break;
#endif
case LONG_ARGS_VHOSTHOST:
uwsgi.vhost = 1;
uwsgi.vhost_host = 1;
return 1;
case LONG_ARGS_LOOP:
uwsgi.loop = optarg;
return 1;
case LONG_ARGS_WORKER_EXEC:
uwsgi.worker_exec = optarg;
return 1;
case LONG_ARGS_REMAP_MODIFIER:
uwsgi.remap_modifier = optarg;
return 1;
case LONG_ARGS_ALLOWED_MODIFIERS:
uwsgi.allowed_modifiers = optarg;
return 1;
case LONG_ARGS_PLUGINS:
p = strtok(optarg, ",");
while (p != NULL) {
#ifdef UWSGI_DEBUG
uwsgi_debug("loading plugin %s\n", p);
#endif
uwsgi_load_plugin(-1, p, NULL, 0);
p = strtok(NULL, ",");
}
build_options();
return 1;
case LONG_ARGS_CHDIR:
uwsgi.chdir = optarg;
return 1;
case LONG_ARGS_CHDIR2:
uwsgi.chdir2 = optarg;
return 1;
#ifdef UWSGI_LDAP
case LONG_ARGS_LDAP:
uwsgi.ldap = optarg;
return 1;
case LONG_ARGS_LDAP_SCHEMA:
uwsgi_ldap_schema_dump();
return 1;
case LONG_ARGS_LDAP_SCHEMA_LDIF:
uwsgi_ldap_schema_dump_ldif();
return 1;
#endif
case LONG_ARGS_MODE:
uwsgi.mode = optarg;
return 1;
case LONG_ARGS_ENV:
if (putenv(optarg)) {
uwsgi_error("putenv()");
}
return 1;
#ifdef UWSGI_THREADING
case LONG_ARGS_THREADS:
uwsgi.threads = atoi(optarg);
return 1;
#endif
#ifdef UWSGI_ASYNC
case LONG_ARGS_ASYNC:
uwsgi.async = atoi(optarg);
return 1;
#endif
case LONG_ARGS_LOGTO:
logto(optarg);
return 1;
case LONG_ARGS_EMPEROR:
uwsgi.emperor_dir = optarg;
return 1;
case LONG_ARGS_RELOAD_MERCY:
uwsgi.reload_mercy = atoi(optarg);
return 1;
case LONG_ARGS_LOG_MASTER:
uwsgi.log_master = 1;
return 1;
case LONG_ARGS_LOG_SYSLOG:
log_syslog(optarg);
uwsgi.log_syslog = 1;
uwsgi.log_master = 1;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_PRINT:
uwsgi_log("%s\n", optarg);
return 1;
case LONG_ARGS_VERSION:
fprintf(stdout, "uWSGI %s\n", UWSGI_VERSION);
exit(0);
#ifdef UWSGI_SNMP
case LONG_ARGS_SNMP:
uwsgi.snmp = 1;
if (optarg) {
uwsgi.snmp_addr = optarg;
uwsgi.master_process = 1;
}
return 1;
case LONG_ARGS_SNMP_COMMUNITY:
uwsgi.snmp = 1;
uwsgi.snmp_community = optarg;
return 1;
#endif
case LONG_ARGS_PIDFILE:
uwsgi.pidfile = optarg;
return 1;
case LONG_ARGS_PIDFILE2:
uwsgi.pidfile2 = optarg;
return 1;
#ifdef UWSGI_UDP
case LONG_ARGS_UDP:
uwsgi.udp_socket = optarg;
uwsgi.master_process = 1;
return 1;
#endif
#ifdef UWSGI_MULTICAST
case LONG_ARGS_MULTICAST:
uwsgi.multicast_group = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_CLUSTER:
uwsgi.cluster = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_CLUSTER_NODES:
uwsgi.cluster = optarg;
uwsgi.cluster_nodes = 1;
uwsgi.master_process = 1;
return 1;
#endif
case LONG_ARGS_CHROOT:
uwsgi.chroot = optarg;
return 1;
case LONG_ARGS_GID:
uwsgi.gid = atoi(optarg);
if (!uwsgi.gid) {
uwsgi.gidname = optarg;
}
return 1;
case LONG_ARGS_UID:
uwsgi.uid = atoi(optarg);
if (!uwsgi.uid) {
uwsgi.uidname = optarg;
}
return 1;
case LONG_ARGS_BINARY_PATH:
uwsgi.binary_path = optarg;
return 1;
#ifdef UWSGI_ERLANG
case LONG_ARGS_ERLANG:
uwsgi.erlang_node = optarg;
return 1;
case LONG_ARGS_ERLANG_COOKIE:
uwsgi.erlang_cookie = optarg;
return 1;
#endif
case LONG_ARGS_CHECK_STATIC:
uwsgi.check_static = optarg;
uwsgi.check_static_len = strlen(uwsgi.check_static);
return 1;
case LONG_ARGS_FILE_SERVE_MODE:
if (!strcasecmp("x-sendfile", optarg)) {
uwsgi.file_serve_mode = 2;
}
else if (!strcasecmp("xsendfile", optarg)) {
uwsgi.file_serve_mode = 2;
}
else if (!strcasecmp("x-accel-redirect", optarg)) {
uwsgi.file_serve_mode = 1;
}
else if (!strcasecmp("xaccelredirect", optarg)) {
uwsgi.file_serve_mode = 1;
}
else if (!strcasecmp("nginx", optarg)) {
uwsgi.file_serve_mode = 1;
}
return 1;
case LONG_ARGS_STATIC_MAP:
usm = uwsgi.static_maps;
if (!usm) {
usm = uwsgi_malloc(sizeof(struct uwsgi_static_map));
uwsgi.static_maps = usm;
}
else {
while(usm->next) {
if (!usm->next) {
usm->next = uwsgi_malloc(sizeof(struct uwsgi_static_map));
usm = usm->next;
break;
}
}
}
char *docroot = strchr(optarg, '=');
if (!docroot) {
uwsgi_log("invalid document root in static map\n");
exit(1);
}
usm->mountpoint = optarg;
usm->mountpoint_len = docroot-usm->mountpoint;
usm->document_root = realpath(docroot+1, NULL);
usm->document_root_len = strlen(usm->document_root);
uwsgi_log("static-mapped %.*s to %.*s\n", usm->mountpoint_len, usm->mountpoint, usm->document_root_len, usm->document_root);
usm->next = NULL;
return 1;
case LONG_ARGS_ATTACH_DAEMON:
if (uwsgi.startup_daemons_cnt < MAX_DAEMONS) {
uwsgi.startup_daemons[uwsgi.startup_daemons_cnt] = optarg;
uwsgi.startup_daemons_cnt++;
} else {
uwsgi_log("you can specify at most %d --attach-daemons options\n", MAX_DAEMONS);
}
return 1;
case LONG_ARGS_SUBSCRIBE_TO:
if (uwsgi.subscriptions_cnt < MAX_SUBSCRIPTIONS) {
uwsgi.subscriptions[uwsgi.subscriptions_cnt] = optarg;
uwsgi.subscriptions_cnt++;
} else {
uwsgi_log("you can specify at most %d --attach-daemons options\n", MAX_SUBSCRIPTIONS);
}
return 1;
#ifdef __linux__
case LONG_ARGS_CGROUP:
uwsgi.cgroup = optarg;
return 1;
case LONG_ARGS_CGROUP_OPT:
if (uwsgi.cgroup_opt_cnt < 63) {
uwsgi.cgroup_opt[uwsgi.cgroup_opt_cnt] = optarg;
uwsgi.cgroup_opt_cnt++;
} else {
uwsgi_log("you can specify at most 64 --cgroup_opt options\n");
}
return 1;
case LONG_ARGS_LINUX_NS:
uwsgi.ns = optarg;
return 1;
case LONG_ARGS_LINUX_NS_NET:
uwsgi.ns_net = optarg;
return 1;
#endif
case LONG_ARGS_LIMIT_AS:
uwsgi.rl.rlim_cur = (atoi(optarg)) * 1024 * 1024;
uwsgi.rl.rlim_max = uwsgi.rl.rlim_cur;
return 1;
case LONG_ARGS_LIMIT_POST:
uwsgi.limit_post = (int) strtol(optarg, NULL, 10);
return 1;
case LONG_ARGS_RELOAD_ON_AS:
uwsgi.reload_on_as = atoi(optarg);
return 1;
case LONG_ARGS_RELOAD_ON_RSS:
uwsgi.reload_on_rss = atoi(optarg);
return 1;
case LONG_ARGS_TOUCH_RELOAD:
uwsgi.touch_reload = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_PRIO:
uwsgi.prio = (int) strtol(optarg, NULL, 10);
return 1;
case LONG_ARGS_CPU_AFFINITY:
uwsgi.cpu_affinity = (int) strtol(optarg, NULL, 10);
return 1;
case LONG_ARGS_POST_BUFFERING:
uwsgi.post_buffering = atoi(optarg);
return 1;
case LONG_ARGS_POST_BUFFERING_SIZE:
uwsgi.post_buffering_bufsize = atoi(optarg);
return 1;
case LONG_ARGS_UPLOAD_PROGRESS:
uwsgi.upload_progress = optarg;
return 1;
#ifdef UWSGI_YAML
case 'y':
uwsgi.yaml = optarg;
return 1;
#endif
#ifdef UWSGI_INI
case LONG_ARGS_INI:
uwsgi.ini = optarg;
return 1;
#endif
case LONG_ARGS_MAP_SOCKET:
p = strchr(optarg, ':');
if (!p) {
uwsgi_log("invalid map-socket syntax, must be socketnum:workerN[,workerN...]\n");
exit(1);
}
p[0] = 0;
int sn = atoi(optarg);
if (sn < 0 || sn >= MAX_SOCKETS) {
uwsgi_log("invalid socket number in map-socket\n");
exit(1);
}
uwsgi.map_socket[sn] = p+1;
p[0] = ':';
return 1;
case LONG_ARGS_CHECK_INTERVAL:
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = atoi(optarg);
return 1;
case LONG_ARGS_CACHE:
uwsgi.cache_max_items = atoi(optarg);
return 1;
case LONG_ARGS_CACHE_STORE:
uwsgi.cache_store = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_CACHE_STORE_SYNC:
uwsgi.cache_store_sync = atoi(optarg);
return 1;
case LONG_ARGS_CACHE_BLOCKSIZE:
uwsgi.cache_blocksize = atoi(optarg);
return 1;
case LONG_ARGS_QUEUE_STORE:
uwsgi.queue_store = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_QUEUE_STORE_SYNC:
uwsgi.queue_store_sync = atoi(optarg);
return 1;
case LONG_ARGS_QUEUE:
uwsgi.queue_size = atoi(optarg);
return 1;
case LONG_ARGS_QUEUE_BLOCKSIZE:
uwsgi.queue_blocksize = atoi(optarg);
return 1;
case 'A':
uwsgi.sharedareasize = atoi(optarg);
return 1;
case 'L':
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 0;
return 1;
case LONG_ARGS_LOG_ZERO:
uwsgi.shared->options[UWSGI_OPTION_LOG_ZERO] = 1;
return 1;
case LONG_ARGS_LOG_SLOW:
uwsgi.shared->options[UWSGI_OPTION_LOG_SLOW] = atoi(optarg);
return 1;
case LONG_ARGS_LOG_4xx:
uwsgi.shared->options[UWSGI_OPTION_LOG_4xx] = 1;
return 1;
case LONG_ARGS_LOG_5xx:
uwsgi.shared->options[UWSGI_OPTION_LOG_5xx] = 1;
return 1;
case LONG_ARGS_LOG_BIG:
uwsgi.shared->options[UWSGI_OPTION_LOG_BIG] = atoi(optarg);
return 1;
case LONG_ARGS_LOG_SENDFILE:
uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] = 1;
return 1;
case LONG_ARGS_MOUNT:
if (uwsgi.mounts_cnt < MAX_APPS) {
uwsgi.mounts[uwsgi.mounts_cnt] = optarg;
uwsgi.mounts_cnt++;
} else {
uwsgi_log("you can specify at most %d --mount options\n", MAX_APPS);
}
return 1;
#ifdef UWSGI_SPOOLER
case 'Q':
uwsgi.spool_dir = uwsgi_malloc(PATH_MAX);
if (access(optarg, R_OK | W_OK | X_OK)) {
uwsgi_error("[spooler directory] access()");
exit(1);
}
if (!realpath(optarg, uwsgi.spool_dir)) {
uwsgi_error("realpath()");
exit(1);
}
uwsgi.master_process = 1;
return 1;
#endif
case 'd':
if (!uwsgi.is_a_reload) {
daemonize(optarg);
}
return 1;
case 's':
if (uwsgi.sockets_cnt < 8) {
uwsgi.sockets[uwsgi.sockets_cnt].name = generate_socket_name(optarg);
uwsgi.sockets_cnt++;
} else {
uwsgi_log("you can specify at most 8 --socket options\n");
}
return 1;
case LONG_ARGS_SHARED_SOCKET:
if (uwsgi.shared_sockets_cnt < MAX_SOCKETS) {
uwsgi.shared_sockets[uwsgi.shared_sockets_cnt].name = generate_socket_name(optarg);
uwsgi.shared_sockets_cnt++;
} else {
uwsgi_log("you can specify at most 8 --socket options\n");
}
return 1;
#ifdef UWSGI_XML
case 'x':
uwsgi.xml_config = optarg;
return 1;
#endif
case 'l':
uwsgi.listen_queue = atoi(optarg);
return 1;
case 'v':
uwsgi.max_vars = atoi(optarg);
uwsgi.vec_size = 4 + 1 + (4 * uwsgi.max_vars);
return 1;
case 'p':
if (!strcmp(optarg, "auto")) {
#ifndef __sun__
struct rlimit rl;
if (getrlimit(RLIMIT_NPROC, &rl)) {
uwsgi_error("getrlimit()");
uwsgi.numproc = 1;
}
else {
if (rl.rlim_cur == RLIM_INFINITY || rl.rlim_cur > 64) {
if (rl.rlim_max != RLIM_INFINITY && rl.rlim_max < 64) {
uwsgi.numproc = rl.rlim_max;
}
else {
#ifdef _SC_NPROCESSORS_ONLN
uwsgi.numproc = (sysconf(_SC_NPROCESSORS_ONLN))*2;
#else
uwsgi.numproc = 1;
#endif
}
}
else {
uwsgi.numproc = rl.rlim_cur;
}
if (uwsgi.numproc > 1) {
uwsgi.numproc--;
uwsgi.master_process = 1;
}
}
#else
uwsgi.numproc = 4;
#endif
}
else {
uwsgi.numproc = atoi(optarg);
}
return 1;
case 'r':
uwsgi.shared->options[UWSGI_OPTION_REAPER] = 1;
return 1;
case 'm':
uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] = 1;
return 1;
case 't':
uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] = atoi(optarg);
return 1;
case 'b':
uwsgi.buffer_size = atoi(optarg);
return 1;
case 'c':
uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1;
return 1;
case 'a':
uwsgi.abstract_socket = 1;
return 1;
case LONG_ARGS_LOG_DATE:
uwsgi.logdate = 1;
if (optarg) {
uwsgi.log_strftime = optarg;
}
return 1;
case 'C':
uwsgi.chmod_socket = 1;
if (optarg) {
if (strlen(optarg) != 3) {
uwsgi_log("invalid chmod value: %s\n", optarg);
exit(1);
}
for (i = 0; i < 3; i++) {
if (optarg[i] < '0' || optarg[i] > '7') {
uwsgi_log("invalid chmod value: %s\n", optarg);
exit(1);
}
}
uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (optarg[0] - '0');
uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (optarg[1] - '0');
uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (optarg[2] - '0');
}
return 1;
case 'M':
uwsgi.master_process = 1;
return 1;
case 'R':
uwsgi.shared->options[UWSGI_OPTION_MAX_REQUESTS] = atoi(optarg);
return 1;
case 'z':
if (atoi(optarg) > 0) {
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = atoi(optarg);
}
return 1;
case 'T':
uwsgi.has_threads = 1;
uwsgi.shared->options[UWSGI_OPTION_THREADS] = 1;
return 1;
case 'i':
uwsgi.single_interpreter = 1;
return 1;
case 'h':
uwsgi_help();
/*
fprintf(stdout, "Usage: %s [options...]\n\
\t-d|--daemonize <logfile|addr>\tdaemonize and log into <logfile> or udp <addr>\n", uwsgi.binary_path);
*/
return 0;
}
return 0;
}
void manage_opt(int i, char *optarg) {
int j;
if (manage_base_opt(i, optarg)) {
return;
}
for (j = 0; j < 0xFF; j++) {
if (uwsgi.p[j]->manage_opt) {
if (uwsgi.p[j]->manage_opt(i, optarg)) {
return;
}
}
}
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->manage_opt) {
if (uwsgi.gp[j]->manage_opt(i, optarg)) {
return;
}
}
}
//never here
exit(1);
}
void uwsgi_cluster_simple_add_node(char *nodename, int workers, int type) {
int i;
struct uwsgi_cluster_node *ucn;
char *tcp_port;
if (strlen(nodename) > 100) {
uwsgi_log("invalid cluster node name %s\n", nodename);
return;
}
tcp_port = strchr(nodename, ':');
if (tcp_port == NULL) {
fprintf(stdout, "invalid cluster node name %s\n", nodename);
return;
}
// first check for already present node
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0) {
if (!strcmp(ucn->name, nodename)) {
ucn->status = UWSGI_NODE_OK;
ucn->last_seen = time(NULL);
return;
}
}
}
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] == 0) {
memcpy(ucn->name, nodename, strlen(nodename) + 1);
ucn->workers = workers;
ucn->ucn_addr.sin_family = AF_INET;
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
tcp_port[0] = 0;
if (nodename[0] == 0) {
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
} else {
uwsgi_log("%s\n", nodename);
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nodename);
}
ucn->type = type;
// here memory can be freed, as it is allocated by uwsgi_concat2n
if (type == CLUSTER_NODE_DYNAMIC) {
free(nodename);
}
else {
tcp_port[0] = ':';
}
ucn->last_seen = time(NULL);
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
return;
}
}
uwsgi_log("unable to add node %s\n", nodename);
}
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
int i;
struct uwsgi_cluster_node *ucn;
char *tcp_port;
uwsgi_log("adding node\n");
tcp_port = strchr(nucn->name, ':');
if (tcp_port == NULL) {
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
return;
}
// first check for already present node
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0) {
if (!strcmp(ucn->name, nucn->name)) {
ucn->status = UWSGI_NODE_OK;
ucn->last_seen = time(NULL);
// update requests
ucn->requests = nucn->requests;
return;
}
}
}
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] == 0) {
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
ucn->workers = nucn->workers;
ucn->ucn_addr.sin_family = AF_INET;
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
tcp_port[0] = 0;
if (nucn->name[0] == 0) {
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
} else {
uwsgi_log("%s\n", nucn->name);
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
}
ucn->type = type;
// here memory can be freed, as it is allocated by uwsgi_concat2n
if (type != CLUSTER_NODE_DYNAMIC) {
tcp_port[0] = ':';
}
ucn->last_seen = time(NULL);
ucn->requests = nucn->requests;
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
return;
}
}
uwsgi_log("unable to add node %s\n", nucn->name);
}
void build_options() {
int i;
struct option *lopt,
*aopt;
int opt_count = count_options(long_base_options);
int short_opt_size = strlen(base_short_options);
char *so_ptr;
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->short_options) {
short_opt_size += strlen(uwsgi.p[i]->short_options);
}
}
for(i=0;i<uwsgi.gp_cnt;i++) {
if (uwsgi.gp[i]->short_options) {
short_opt_size += strlen(uwsgi.gp[i]->short_options);
}
}
if (short_options) {
free(short_options);
}
short_options = uwsgi_malloc(short_opt_size + 1);
memcpy(short_options, base_short_options, strlen(base_short_options));
so_ptr = short_options + strlen(base_short_options);
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->short_options) {
memcpy(so_ptr, uwsgi.p[i]->short_options, strlen(uwsgi.p[i]->short_options));
so_ptr += strlen(uwsgi.p[i]->short_options);
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->short_options) {
memcpy(so_ptr, uwsgi.gp[i]->short_options, strlen(uwsgi.gp[i]->short_options));
so_ptr += strlen(uwsgi.gp[i]->short_options);
}
}
*so_ptr = 0;
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->options) {
opt_count += count_options(uwsgi.p[i]->options);
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->options) {
opt_count += count_options(uwsgi.gp[i]->options);
}
}
if (uwsgi.long_options) {
free(uwsgi.long_options);
}
uwsgi.long_options = uwsgi_malloc(sizeof(struct option) * (opt_count + 1));
opt_count = 0;
lopt = long_base_options;
while ((aopt = lopt)) {
if (!aopt->name)
break;
uwsgi.long_options[opt_count].name = aopt->name;
uwsgi.long_options[opt_count].has_arg = aopt->has_arg;
uwsgi.long_options[opt_count].flag = aopt->flag;
uwsgi.long_options[opt_count].val = aopt->val;
opt_count++;
lopt++;
}
for (i = 0; i < 0xFF; i++) {
lopt = uwsgi.p[i]->options;
if (!lopt)
continue;
while ((aopt = lopt)) {
if (!aopt->name)
break;
uwsgi.long_options[opt_count].name = aopt->name;
uwsgi.long_options[opt_count].has_arg = aopt->has_arg;
uwsgi.long_options[opt_count].flag = aopt->flag;
uwsgi.long_options[opt_count].val = aopt->val;
opt_count++;
lopt++;
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
lopt = uwsgi.gp[i]->options;
if (!lopt)
continue;
while ((aopt = lopt)) {
if (!aopt->name)
break;
uwsgi.long_options[opt_count].name = aopt->name;
uwsgi.long_options[opt_count].has_arg = aopt->has_arg;
uwsgi.long_options[opt_count].flag = aopt->flag;
uwsgi.long_options[opt_count].val = aopt->val;
opt_count++;
lopt++;
}
}
uwsgi.long_options[opt_count].name = 0;
uwsgi.long_options[opt_count].has_arg = 0;
uwsgi.long_options[opt_count].flag = 0;
uwsgi.long_options[opt_count].val = 0;
}
void manage_string_opt(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
// never free this value
char *key2 = uwsgi_concat2n(key, keylen, "", 0);
char *val2 = uwsgi_concat2n(val, vallen, "", 0);
uwsgi_log("%s = %s\n", key2, val2);
add_exported_option(key2, val2, 0);
}
#ifdef UWSGI_UDP
int uwsgi_cluster_add_me() {
const char *key1 = "hostname";
const char *key2 = "address";
const char *key3 = "workers";
const char *key4 = "requests";
char *ptrbuf ;
uint16_t ustrlen;
char numproc[6];
if (!uwsgi.sockets[0].name) {
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
exit(1);
}
snprintf(numproc, 6, "%d", uwsgi.numproc);
size_t len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets[0].name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
char *buf = uwsgi_malloc( len );
ptrbuf = buf;
ustrlen = strlen(key1);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, key1, strlen(key1)); ptrbuf+=strlen(key1);
ustrlen = strlen(uwsgi.hostname);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname)); ptrbuf+=strlen(uwsgi.hostname);
ustrlen = strlen(key2);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, key2, strlen(key2)); ptrbuf+=strlen(key2);
ustrlen = strlen(uwsgi.sockets[0].name);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, uwsgi.sockets[0].name, strlen(uwsgi.sockets[0].name)); ptrbuf+=strlen(uwsgi.sockets[0].name);
ustrlen = strlen(key3);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, key3, strlen(key3)); ptrbuf+=strlen(key3);
ustrlen = strlen(numproc);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, numproc, strlen(numproc)); ptrbuf+=strlen(numproc);
ustrlen = strlen(key4);
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, key4, strlen(key4)); ptrbuf+=strlen(key4);
ustrlen = 1;
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
*ptrbuf++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ptrbuf, "0", 1); ptrbuf+=1;
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
free(buf);
uwsgi_log("add_me() successfull\n");
return 0;
}
int uwsgi_cluster_join(char *name) {
int fd ;
char *cp;
int broadcast = 0;
if (name[0] == ':') {
fd = bind_to_udp(name, 0, 1);
broadcast = 1;
}
else {
fd = bind_to_udp(name, 1, 0);
}
if (fd >= 0) {
cp = strchr(name,':');
cp[0] = 0;
uwsgi.mc_cluster_addr.sin_family=AF_INET;
if (broadcast) {
uwsgi.mc_cluster_addr.sin_addr.s_addr=INADDR_BROADCAST;
}
else {
uwsgi.mc_cluster_addr.sin_addr.s_addr=inet_addr(name);
}
uwsgi.mc_cluster_addr.sin_port=htons(atoi(cp+1));
cp[0] = ':';
// announce my presence to all the nodes
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
}
else {
exit(1);
}
return fd;
}
void uwsgi_stdin_sendto(char *socket_name, uint8_t modifier1, uint8_t modifier2) {
char buf[4096];
ssize_t rlen ;
size_t delta = 4096;
char *ptr = buf;
rlen = read(0, ptr, delta);
while(rlen > 0) {
uwsgi_log("%.*s\n", rlen, ptr);
ptr += rlen;
delta-=rlen;
if (delta <= 0) break;
rlen = read(0, ptr, delta);
}
if (ptr > buf) {
send_udp_message(modifier1, socket_name, buf, ptr-buf);
uwsgi_log("sent string \"%.*s\" to cluster node %s", ptr-buf, buf, socket_name);
}
}
#endif
char *uwsgi_cluster_best_node() {
int i;
int best_node = -1;
struct uwsgi_cluster_node *ucn;
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
if (best_node == -1) {
best_node = i;
}
else {
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
best_node = i;
}
}
}
}
if (best_node == -1) {
return NULL;
}
uwsgi.shared->nodes[best_node].last_choosen = time(NULL);
return uwsgi.shared->nodes[best_node].name;
}
struct uwsgi_help_item main_help[] = {
{"socket <name>", "path (or name) of UNIX/TCP socket to bind to"},
{"listen <num>", "set socket listen queue to <n> (default 100, maximum is system dependent)"},
{"socket-timeout <sec>", "set socket timeout to <sec> seconds (default 4 seconds)"},
{"buffer-size <n>", "set buffer size to <n> bytes"},
{"disable-logging", "disable request logging (only errors or server messages will be logged)"},
{"xmlconfig <path>", "path of xml config file"},
{"harakiri <sec>", "set harakiri timeout to <sec> seconds"},
{"harakiri-verbose", "report additional info during harakiri"},
{"processes <n>", "spawn <n> uwsgi worker processes"},
{"workers <n>", "spawn <n> uwsgi worker processes"},
{"max-vars <n>", "set maximum number of vars/headers to <n>"},
{"sharedarea <n>", "create a shared memory area of <n> pages"},
{"cgi-mode", "set cgi mode"},
{"chmod-socket[=NNN]", "chmod socket to 666 or NNN"},
{"chmod[=NNN]", "chmod socket to 666 or NNN"},
{"memory-report", "enable memory usage report"},
{"single-interpreter", "single interpreter mode"},
{"abstract-socket", "set socket in the abstract namespace (Linux only)"},
{"enable-threads", "enable threads support"},
{"master", "enable master process manager"},
{"help", "this help"},
{"reaper", "process reaper (call waitpid(-1,...) after each request)"},
{"max-requests", "maximum number of requests for each worker"},
{"test", "test if uWSGI can import a module"},
{"spooler <dir>", "run the spooler on directory <dir>"},
{"pidfile <file>", "write the masterpid to <file>"},
{"chroot <dir>", "chroot to directory <dir> (only root)"},
{"gid <id/groupname>", "setgid to <id/groupname> (only root)"},
{"uid <id/username>", "setuid to <id/username> (only root)"},
{"chdir <dir>", "chdir to <dir> before app loading"},
{"chdir2 <dir>", "chdir to <dir> after module loading"},
{"no-server", "initialize the uWSGI server then exit. Useful for testing and using uwsgi embedded module"},
{"no-defer-accept", "disable the no-standard way to defer the accept() call (TCP_DEFER_ACCEPT, SO_ACCEPTFILTER...)"},
{"check-interval <sec>", "set the check interval (in seconds) of the master process"},
{"limit-as <MB>", "limit the address space of processes to MB megabytes"},
{"limit-post <bytes>", "limit HTTP content_length size to <bytes>"},
{"post-buffering <bytes>", "buffer HTTP POST request higher than <bytes> to disk"},
{"post-buffering-bufsize <b>", "set the buffer size to <b> bytes for post-buffering"},
{"prio <N>", "set process priority/nice to N"},
{"no-orphans", "automatically kill workers on master's dead"},
{"udp <ip:port>", "bind master process to udp socket on ip:port"},
{"multicast <group>", "set multicast group"},
{"snmp[=<addr>]", "enable SNMP support in the UDP server or bind it to <addr>"},
{"snmp-community <value>", "set SNMP community code to <value>"},
{"erlang <name|address>", "enable the Erlang server with node name <name@address>"},
{"erlang-cookie <cookie>", "set the erlang cookie to <cookie>"},
{"nagios", "do a nagios check"},
{"binary-path <bin-path>", "set the path for the next reload of uWSGI (needed for chroot environments)"},
{"proxy <socket>", "run the uwsgi proxy on socket <socket>"},
{"proxy-node <socket>", "add the node <socket> to the proxy"},
{"proxy-max-connections <n>", "set the max number of concurrent connections mnaged by the proxy"},
{"async <n>", "enable async mode with n core"},
{"threads <n>", "spawn <n> threads core"},
{"logto <logfile|addr>", "log to file/udp"},
{"logdate", "add timestamp to loglines"},
{"log-zero", "log requests with 0 response size"},
{"log-slow <t>", "log requests slower than <t> milliseconds"},
{"log-4xx", "log requests with status code 4xx"},
{"log-5xx", "log requests with status code 5xx"},
{"log-big <n>", "log requests bigger than <n> bytes"},
{"log-sendfile", "log sendfile() requests"},
{"ignore-script-name", "disable uWSGI management of SCRIPT_NAME"},
{"no-default-app", "do not fallback unknown SCRIPT_NAME requests"},
{"ini <inifile>", "path of ini config file"},
{"ldap <url>", "url of LDAP uWSGIConfig resource"},
{"ldap-schema", "dump uWSGIConfig LDAP schema"},
{"ldap-schema-ldif", "dump uWSGIConfig LDAP schema in LDIF format"},
{"grunt", "enable grunt workers"},
{"ugreen", "enable uGreen support"},
{"ugreen-stacksize <n>", "set uGreen stacksize to <n>"},
{"no-site", "do not import site.py on startup"},
{"vhost", "enable virtual hosting"},
{"vhost-host", "use the Host header as the key for virtual hosting"},
{"mount MOUNTPOINT=app", "add a new app under MOUNTPOINT"},
{"routing", "enable uWSGI advanced routing"},
{"http <addr>", "start embedded HTTP server on <addr>"},
{"http-only", "start only the embedded HTTP server"},
{"http-var KEY[=VALUE]", "add var KEY to uwsgi requests made by the embedded HTTP server"},
{"catch-exceptions", "print exceptions in the browser"},
{"mode", "set configuration mode"},
{"env KEY=VALUE", "set environment variable"},
{"vacuum", "clear the environment on exit (remove UNIX sockets and pidfiles)"},
{"ping <addr>", "ping a uWSGI server (returns 1 on failure 0 on success)"},
{"ping-timeout <n>", "set ping timeout to <n>"},
{"cgroup <group>", "run the server in <group> cgroup (Linux only)"},
{"cgroup-opt KEY=VAL", "set cgroup option (Linux only)"},
{"version", "print server version"},
{"attach-daemon <command>", "run <command> under the control of master process"},
{"daemonize <logfile|addr>", "daemonize and log into <logfile> or udp <addr>"},
{ 0, 0 },
};
void uwsgi_help(void) {
struct uwsgi_help_item *uhi, *all_help;
int max_size = 0;
struct option *lopt;
int found;
char *space;
char *tmp_option = NULL;
int i;
all_help = main_help;
build_options();
while( (uhi = all_help) ) {
if (uhi->key == 0)
break;
if ((int)strlen(uhi->key) > max_size) {
max_size = (int)strlen(uhi->key);
}
all_help++;
}
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->help) {
all_help = uwsgi.p[i]->help;
while( (uhi = all_help) ) {
if (uhi->key == 0) break;
if ((int)strlen(uhi->key) > max_size)
max_size = (int)strlen(uhi->key);
all_help++;
}
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->help) {
all_help = uwsgi.gp[i]->help ;
while( (uhi = all_help) ) {
if (uhi->key == 0) break;
if ((int)strlen(uhi->key) > max_size)
max_size = (int)strlen(uhi->key);
all_help++;
}
}
}
fprintf(stdout, "Usage: %s [options...]\n", uwsgi.binary_path);
lopt = uwsgi.long_options;
max_size+=4;
while(lopt->name) {
found = 0;
all_help = main_help;
while( (uhi = all_help) ) {
if (uhi->key == 0) break;
tmp_option = uwsgi_concat2(uhi->key, "");
space = strchr(tmp_option, ' ');
if (!space) space = strstr(tmp_option, "[=");
if (space) space[0] = 0;
if (!strcmp(tmp_option, lopt->name)) {
found = 1;
break;
}
free(tmp_option);
all_help++;
}
if (!found) {
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->help) {
all_help = uwsgi.p[i]->help;
while( (uhi = all_help) ) {
if (uhi->key == 0) break;
tmp_option = uwsgi_concat2(uhi->key, "");
space = strchr(tmp_option, ' ');
if (!space) space = strstr(tmp_option, "[=");
if (space) space[0] = 0;
if (!strcmp(tmp_option, lopt->name)) {
found = 1;
break;
}
free(tmp_option);
all_help++;
}
}
if (found) break;
}
}
if (!found) {
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->help) {
all_help = uwsgi.gp[i]->help;
while( (uhi = all_help) ) {
if (uhi->key == 0) break;
tmp_option = uwsgi_concat2(uhi->key, "");
space = strchr(tmp_option, ' ');
if (!space) space = strstr(tmp_option, "[=");
if (space) space[0] = 0;
if (!strcmp(tmp_option, lopt->name)) {
found = 1;
break;
}
free(tmp_option);
all_help++;
}
}
if (found) break;
}
}
if (found) {
if (!lopt->flag && ( (lopt->val >= 'a' && lopt->val <= 'z') || (lopt->val >= 'A' && lopt->val <= 'Z'))) {
fprintf(stdout, " -%c|--%-*s %s\n", lopt->val, max_size-3, uhi->key, uhi->value);
}
else {
fprintf(stdout, " --%-*s %s\n", max_size, uhi->key, uhi->value);
}
if (tmp_option) free(tmp_option);
}
else {
fprintf(stdout, " --%-*s *** UNDOCUMENTED OPTION ***\n", max_size, lopt->name);
}
lopt++;
}
exit(0);
}