Compare commits

...
23 Commits
Author SHA1 Message Date
roberto@sirius 63b41856e5 Changelog for 0.9.6 2010-08-28 19:58:55 +02:00
roberto@sirius ed1e668240 NetBSD latest fixes. Ready for 0.9.6 release 2010-08-28 19:36:55 +02:00
roberto@freebsd64 e3a7e70180 fix pidfile on HTTP mode 2010-08-28 13:51:38 +02:00
roberto@freebsd64 9f0b20c8d2 use getsockname() in vacuum() 2010-08-28 13:16:22 +02:00
roberto@freebsd64 68aff372ce HTTP final fixes, better reloading system, better cwd detection, powered up vacuum 2010-08-28 13:00:21 +02:00
roberto@sirius 38cfa72318 close ini file 2010-08-27 11:07:35 +02:00
roberto@sirius 31047e1e10 fixes for --file and shebang support 2010-08-27 07:32:44 +02:00
roberto@sirius bbb90296bb applied Leonid Borisenko patch to allow -O2 and -fno-strict-aliasing CFLAGS 2010-08-27 06:21:43 +02:00
roberto@sirius 00c6aa2f65 0.9.6-rc2 2010-08-26 17:08:15 +02:00
roberto@sirius 720da09631 xmlconf fixes 2010-08-26 15:33:25 +02:00
roberto@fiorenzo 47f7c09b97 add empty QUERY_STRING in http server 2010-08-26 14:55:39 +02:00
roberto@sirius cb5704da10 --callable 2010-08-26 14:09:15 +02:00
roberto@fiorenzo c64356b231 uwsgi packet watermark in HTTP server 2010-08-26 11:38:48 +02:00
roberto@sirius 2acd2f5224 another solaris hack 2010-08-26 11:01:57 +02:00
roberto@sirius ba251f8e3d another solaris fix 2010-08-26 10:09:40 +02:00
roberto@sirius 48019f9044 first round of http fixes 2010-08-26 10:06:17 +02:00
roberto@sunsparc d9a1f2448c solaris fixes 2010-08-26 09:33:23 +02:00
roberto@ubuntu64 553a947c2d fix routing 2010-08-26 08:43:28 +02:00
roberto@sirius 736aedfa89 add --ini-paste commodity and removal of strlc* functions 2010-08-26 08:36:44 +02:00
roberto@sirius 6184acc727 updated --help 2010-08-25 20:00:10 +02:00
roberto@sirius f0d96b03fa added --ping and --ping-timeout 2010-08-25 19:21:31 +02:00
roberto@sirius 14bf840eef fix urack.rb upload 2010-08-24 16:44:32 +02:00
roberto@sirius 7ea08093c7 uWSGI 0.9.6-rc1 2010-08-24 08:41:25 +02:00
18 changed files with 419 additions and 83 deletions
+2
View File
@@ -4,3 +4,5 @@ d3850b52334a91d005b0fe45e1e38ba0997a1fb8 no_server mode
820cc64ab296dc4589ef72a33a6b804c22a0430c 0.9.5rc2
b0db39cfad5ac6d4f00bbb3f9c57cf73206e2afb 0.9.5
9f8b98ad1dfa51b86b13fa624c65f73523075fc4 0.9.5.1
a83e7a482e65befcfbb0e24af8cd5d15190acdd7 0.9.6-rc1
b8f67c6cd0d62f864db9b2b265b4e260ad7d873c 0.9.6-rc2
+26
View File
@@ -1,3 +1,29 @@
*** august 2010 ***
* 0.9.6 [20100829]
- better handling of SCRIPT_NAME
- vacuum option for deleting unix sockets and pidfiles after usage
- advanced XML configuration
- new configuration systems: INI files and LDAP
- embedded HTTP server for development/testing
- better signal handling
- PSGI plugin improved
- usability fixes and new commodities options for root startup
- grunt processes (detached workers)
- preliminary integrated virtualhosting mode
- new option catch-exceptions can redirect python exceptions to your browser
- logging improvements (--logto and --logdate options)
- Full PEP 333 compliant usage of wsgi.file_wrapper
- re-initialize random seed after every fork() [security fix]
- fix Spooler's usage of stdin
- export WSGI environment in uwsgi.env (for doing evil things)
- logsize tracking (uwsgi.logsize) for future embedded log rotation
*** july 2010 ***
* 0.9.5.4 [20100706]
*** june 2010 ***
* 0.9.5.3 [20100628]
+4
View File
@@ -191,6 +191,10 @@ module Rack
buf, sender = client.recvfrom(remains)
end
if buf.length == 0
break
end
rack_input.write( buf )
remains -= buf.length
end
+78 -18
View File
@@ -30,12 +30,23 @@ void http_end() {
exit(0);
}
static char *add_uwsgi_var(char *up, char *key, uint16_t keylen, char *val, uint16_t vallen, int header)
void http_wait_end() {
pid_t wp_p;
int wp_c;
wp_p = waitpid(-1, &wp_c, 0);
uwsgi_log("closing uWSGI embedded HTTP server.\n");
exit(0);
}
static char *add_uwsgi_var(char *up, char *key, uint16_t keylen, char *val, uint16_t vallen, int header, char *watermark)
{
int i;
if (!header) {
if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up ;
*up++ = (unsigned char) (keylen & 0xff);
*up++ = (unsigned char) ((keylen >> 8) & 0xff);
@@ -48,16 +59,18 @@ static char *add_uwsgi_var(char *up, char *key, uint16_t keylen, char *val, uint
if (key[i] == '-') {
key[i] = '_';
} else {
key[i] = toupper(key[i]);
key[i] = toupper( (int) key[i]);
}
}
if (strncmp("CONTENT_TYPE", key, keylen) && strncmp("CONTENT_LENGTH", key, keylen)) {
if ( (up + 2 + keylen + 5 + 2 + vallen) > watermark ) return up ;
*up++ = (unsigned char) (((uint16_t) keylen + 5) & 0xff);
*up++ = (unsigned char) ((((uint16_t) keylen + 5) >> 8) & 0xff);
memcpy(up, "HTTP_", 5);
up += 5;
} else {
if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up ;
*up++ = (unsigned char) (keylen & 0xff);
*up++ = (unsigned char) ((keylen >> 8) & 0xff);
}
@@ -98,10 +111,29 @@ void http_loop(struct uwsgi_server * uwsgi)
exit(1);
}
// ignore broken pipes;
signal(SIGPIPE, SIG_IGN);
if (!uwsgi->http_only) {
signal(SIGCHLD, &http_end);
signal(SIGINT, &http_wait_end);
}
else {
signal(SIGINT, &http_end);
}
uwsgi->http_server_name = malloc(256);
if (!uwsgi->http_server_name) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi->http_server_name, 0, 256);
if (gethostname(uwsgi->http_server_name, 255)) {
uwsgi_error("gethostname()");
memcpy(uwsgi->http_server_name, "localhost", 9);
}
uwsgi_log("starting HTTP loop on %s (pid: %d)\n", uwsgi->http_server_name, (int) getpid());
for(;;) {
if (!uwsgi->http_only) {
@@ -128,6 +160,7 @@ void http_loop(struct uwsgi_server * uwsgi)
if (ret) {
uwsgi_log("pthread_create() = %d\n", ret);
free(ur);
// sleep a bit to allow some resource gaining
sleep(1);
continue;
}
@@ -158,8 +191,7 @@ static void *http_request(void *u_h_r)
size_t len;
int i,
j;
int i, j;
char HTTP_header_key[1024];
@@ -167,8 +199,12 @@ static void *http_request(void *u_h_r)
ptr = tmp_buf;
int qs = 0;
up = uwsgipkt;
char *watermark = up + 4096 ;
char *watermark2 = tmp_buf + 4096 ;
up[0] = 0;
up[3] = 0;
@@ -186,31 +222,37 @@ static void *http_request(void *u_h_r)
if (state == uwsgi_http_method) {
up = add_uwsgi_var(up, "REQUEST_METHOD", 14, tmp_buf, ptr - tmp_buf, 0);
up = add_uwsgi_var(up, "REQUEST_METHOD", 14, tmp_buf, ptr - tmp_buf, 0, watermark);
ptr = tmp_buf;
state = uwsgi_http_uri;
} else if (state == uwsgi_http_uri) {
up = add_uwsgi_var(up, "REQUEST_URI", 11, tmp_buf, ptr - tmp_buf, 0);
up = add_uwsgi_var(up, "REQUEST_URI", 11, tmp_buf, ptr - tmp_buf, 0, watermark);
int path_info_len = ptr - tmp_buf;
for (j = 0; j < ptr - tmp_buf; j++) {
if (tmp_buf[j] == '?') {
path_info_len = j;
if (j + 1 < (ptr - tmp_buf)) {
up = add_uwsgi_var(up, "QUERY_STRING", 12, tmp_buf + j + 1, (ptr - tmp_buf) - (j + 1), 0);
up = add_uwsgi_var(up, "QUERY_STRING", 12, tmp_buf + j + 1, (ptr - tmp_buf) - (j + 1), 0, watermark);
qs = 1 ;
}
break;
}
}
up = add_uwsgi_var(up, "PATH_INFO", 9, tmp_buf, path_info_len, 0);
if (!qs) {
up = add_uwsgi_var(up, "QUERY_STRING", 12, NULL, 0, 0, watermark);
}
up = add_uwsgi_var(up, "PATH_INFO", 9, tmp_buf, path_info_len, 0, watermark);
ptr = tmp_buf;
state = uwsgi_http_protocol;
} else if (state == uwsgi_http_header_key_colon) {
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
*ptr++ = 0;
memset(HTTP_header_key, 0, sizeof(HTTP_header_key));
@@ -219,6 +261,7 @@ static void *http_request(void *u_h_r)
state = uwsgi_http_header_val;
} else {
//check for overflow
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
*ptr++ = buf[i];
}
@@ -236,8 +279,9 @@ static void *http_request(void *u_h_r)
if (state == uwsgi_http_header_val_r) {
up = add_uwsgi_var(up, HTTP_header_key, strlen(HTTP_header_key), tmp_buf, ptr - tmp_buf, 1);
up = add_uwsgi_var(up, HTTP_header_key, strlen(HTTP_header_key), tmp_buf, ptr - tmp_buf, 1, watermark);
if (!strcmp("CONTENT_LENGTH", HTTP_header_key)) {
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
*ptr++ = 0;
http_body_len = atoi(tmp_buf);
}
@@ -245,27 +289,36 @@ static void *http_request(void *u_h_r)
state = uwsgi_http_header_key;
} else if (state == uwsgi_http_protocol_r) {
up = add_uwsgi_var(up, "SERVER_PROTOCOL", 15, tmp_buf, ptr - tmp_buf, 0);
up = add_uwsgi_var(up, "SERVER_PROTOCOL", 15, tmp_buf, ptr - tmp_buf, 0, watermark);
ptr = tmp_buf;
state = uwsgi_http_header_key;
} else if (state == uwsgi_http_end) {
need_to_read = 0;
if (uwsgi.http_server_name) {
up = add_uwsgi_var(up, "SERVER_NAME", 11, uwsgi.http_server_name, strlen(uwsgi.http_server_name), 0);
} else {
up = add_uwsgi_var(up, "SERVER_NAME", 11, "localhost", 9, 0);
}
up = add_uwsgi_var(up, "SERVER_NAME", 11, uwsgi.http_server_name, strlen(uwsgi.http_server_name), 0, watermark);
up = add_uwsgi_var(up, "SERVER_PORT", 11, uwsgi.http_server_port, strlen(uwsgi.http_server_port), 0, watermark);
up = add_uwsgi_var(up, "SERVER_PORT", 11, uwsgi.http_server_port, strlen(uwsgi.http_server_port), 0);
up = add_uwsgi_var(up, "SCRIPT_NAME", 11, "", 0, 0);
up = add_uwsgi_var(up, "SCRIPT_NAME", 11, "", 0, 0, watermark);
char *ip = inet_ntoa(ur->c_addr.sin_addr);
up = add_uwsgi_var(up, "REMOTE_ADDR", 11, ip, strlen(ip), 0);
up = add_uwsgi_var(up, "REMOTE_ADDR", 11, ip, strlen(ip), 0, watermark);
//up = add_uwsgi_var(up, "REMOTE_ADDR", 11, "127.0.0.1", 9, 0, watermark);
//up = add_uwsgi_var(up, "REMOTE_USER", 11, "unknown", 7, 0);
for(j=0;j<uwsgi.http_vars_cnt;j++) {
char *separator;
separator = strchr(uwsgi.http_vars[j], '=');
if (separator) {
up = add_uwsgi_var(up, uwsgi.http_vars[j], separator - uwsgi.http_vars[j], separator + 1, strlen(separator + 1), 0, watermark);
}
else {
up = add_uwsgi_var(up, uwsgi.http_vars[j], strlen(uwsgi.http_vars[j]), NULL, 0, 0, watermark);
}
}
uwsgi_fd = uwsgi_connect(uwsgi.socket_name, 10);
if (uwsgi_fd >= 0) {
ulen = (up - uwsgipkt) - 4;
@@ -298,6 +351,10 @@ static void *http_request(void *u_h_r)
}
close(uwsgi_fd);
}
else {
close(uwsgi_fd);
goto clear;
}
}
} else if (buf[i] == ':') {
@@ -305,11 +362,13 @@ static void *http_request(void *u_h_r)
state = uwsgi_http_header_key_colon;
} else {
//check for overflow
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
*ptr++ = buf[i];
}
} else {
//check for overflow
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
*ptr++ = buf[i];
}
@@ -317,6 +376,7 @@ static void *http_request(void *u_h_r)
}
clear:
close(clientfd);
free(ur);
+6 -2
View File
@@ -83,7 +83,7 @@ void uwsgi_ini_config(char *file, struct option *long_options) {
char *ini_line;
char *section;
char *section = "";
char *key;
char *val;
@@ -96,7 +96,9 @@ void uwsgi_ini_config(char *file, struct option *long_options) {
colon = strchr(file, ':');
if (colon) {
colon[0] = 0;
section_asked = colon+1 ;
if (colon[1] != 0) {
section_asked = colon+1 ;
}
}
fd = open(file, O_RDONLY);
@@ -174,6 +176,8 @@ void uwsgi_ini_config(char *file, struct option *long_options) {
sb.st_size -= (ini_line - ini);
}
close(fd);
}
+7 -7
View File
@@ -11,9 +11,9 @@ void ldap2uwsgi(char *ldapname, char *uwsginame) {
int i;
for(i=0;i<strlen(ldapname);i++) {
if (isupper(ldapname[i])) {
if (isupper( (int)ldapname[i])) {
*ptr++= '-';
*ptr++= tolower(ldapname[i]);
*ptr++= tolower( (int) ldapname[i]);
}
else {
*ptr++= ldapname[i] ;
@@ -29,7 +29,7 @@ int calc_ldap_name(char *name) {
int counter = 0;
for(i=0;i<strlen(name);i++) {
if (isupper(name[i])) {
if (isupper( (int) name[i])) {
counter++;
}
}
@@ -73,7 +73,7 @@ void uwsgi_ldap_schema_dump_ldif(struct option *lo) {
for(i=0;i<strlen(aopt->name);i++) {
if (aopt->name[i] == '-') {
i++;
uwsgi_log("%c", toupper(aopt->name[i]));
uwsgi_log("%c", toupper( (int) aopt->name[i]));
}
else {
uwsgi_log("%c", aopt->name[i]);
@@ -113,7 +113,7 @@ next:
for(i=0;i<strlen(aopt->name);i++) {
if (aopt->name[i] == '-') {
i++;
uwsgi_log("%c", toupper(aopt->name[i]));
uwsgi_log("%c", toupper( (int) aopt->name[i]));
}
else {
uwsgi_log("%c", aopt->name[i]);
@@ -163,7 +163,7 @@ void uwsgi_ldap_schema_dump(struct option *lo) {
for(i=0;i<strlen(aopt->name);i++) {
if (aopt->name[i] == '-') {
i++;
uwsgi_log("%c", toupper(aopt->name[i]));
uwsgi_log("%c", toupper( (int) aopt->name[i]));
}
else {
uwsgi_log("%c", aopt->name[i]);
@@ -203,7 +203,7 @@ next:
for(i=0;i<strlen(aopt->name);i++) {
if (aopt->name[i] == '-') {
i++;
uwsgi_log("%c", toupper(aopt->name[i]));
uwsgi_log("%c", toupper( (int) aopt->name[i]));
}
else {
uwsgi_log("%c", aopt->name[i]);
+1 -1
View File
@@ -84,7 +84,7 @@ void log_request(struct wsgi_request *wsgi_req) {
}
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %ld msecs%s(%.*s %d) %d headers in %d bytes (%d async switches on async core %d)\n",
uwsgi.mypid,
(int) uwsgi.mypid,
wsgi_req->app_id,
app_req,
(unsigned long long ) uwsgi.workers[0].requests,
+4 -4
View File
@@ -30,7 +30,7 @@ int uwsgi_load_plugin(struct uwsgi_server *uwsgi, int modifier, char *plugin, ch
if (absolute) {
plugin_name = malloc(strlen(plugin) + 1);
strlcpy(plugin_name, plugin, strlen(plugin));
memcpy(plugin_name, plugin, strlen(plugin) + 1);
}
else {
plugin_name = malloc(strlen(UWSGI_PLUGIN_DIR) + 1 + strlen(plugin) + 1);
@@ -38,9 +38,9 @@ int uwsgi_load_plugin(struct uwsgi_server *uwsgi, int modifier, char *plugin, ch
uwsgi_error("malloc()");
return -1 ;
}
strlcpy(plugin_name, UWSGI_PLUGIN_DIR, strlen(UWSGI_PLUGIN_DIR));
strlcat(plugin_name, "/", 1);
strlcat(plugin_name, plugin, strlen(plugin));
memcpy(plugin_name, UWSGI_PLUGIN_DIR, strlen(UWSGI_PLUGIN_DIR));
memcpy(plugin_name + strlen(UWSGI_PLUGIN_DIR) , "/", 1);
memcpy(plugin_name + strlen(UWSGI_PLUGIN_DIR) + 1, plugin, strlen(plugin) + 1);
}
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
free(plugin_name);
+3
View File
@@ -1,3 +1,4 @@
#ifdef UWSGI_ROUTING
#include "uwsgi.h"
void routing_setup(struct uwsgi_server *uwsgi) {
@@ -152,3 +153,5 @@ void uwsgi_route_action_uwsgi(struct uwsgi_server *uwsgi, struct wsgi_request *w
}
}
#endif
+1 -1
View File
@@ -34,7 +34,7 @@ class uWSGIDistribution(Distribution):
setup(name='uWSGI',
version='0.9.6-dev',
version='0.9.6',
description='The uWSGI server',
author='Unbit',
author_email='info@unbit.it',
+1 -1
View File
@@ -419,7 +419,7 @@ PyObject *py_snmp_community(PyObject * self, PyObject * args) {
memcpy(uwsgi.shared->snmp_community, snmp_community, 72);
}
else {
strlcpy(uwsgi.shared->snmp_community, snmp_community, 73);
memcpy(uwsgi.shared->snmp_community, snmp_community, strlen(snmp_community) + 1);
}
Py_INCREF(Py_True);
+2 -2
View File
@@ -38,7 +38,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
}
uws_addr->sun_family = AF_UNIX;
strlcpy(uws_addr->sun_path + abstract_socket, socket_name, 102+1);
memcpy(uws_addr->sun_path + abstract_socket, socket_name, 102);
if (bind(serverfd, (struct sockaddr *) uws_addr, strlen(socket_name) + abstract_socket + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) {
uwsgi_error("bind()");
@@ -220,7 +220,7 @@ int connect_to_unix(char *socket_name, int timeout) {
memset(&uws_addr, 0, sizeof(struct sockaddr_un));
uws_addr.sun_family = AF_UNIX;
strlcpy(uws_addr.sun_path, socket_name, 102+1);
memcpy(uws_addr.sun_path, socket_name, 102);
uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (uwsgi_poll.fd < 0) {
+1 -1
View File
@@ -18,7 +18,7 @@ int spool_request(struct uwsgi_server *uwsgi, char *filename, int rn, char *buff
hostname[256] = 0;
if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%llu_%llu", uwsgi->spool_dir, hostname, getpid(), rn, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%llu_%llu", uwsgi->spool_dir, hostname, (int) getpid(), rn, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
return 0;
}
+7 -1
View File
@@ -410,6 +410,12 @@ void sanitize_args(struct uwsgi_server *uwsgi) {
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
}
}
#ifdef UWSGI_HTTP
if (uwsgi->http && !uwsgi->http_only) {
uwsgi->vacuum = 1;
}
#endif
}
void env_to_arg(char *src, char *dst) {
@@ -424,7 +430,7 @@ void env_to_arg(char *src, char *dst) {
dst[i] = src[i];
}
else {
dst[i] = tolower(src[i]);
dst[i] = tolower( (int) src[i]);
if (dst[i] == '_') {
dst[i] = '-';
}
+219 -36
View File
@@ -75,6 +75,8 @@ static struct option long_options[] = {
#endif
{"disable-logging", no_argument, 0, 'L'},
{"callable", required_argument, 0, LONG_ARGS_CALLABLE},
{"pidfile", required_argument, 0, LONG_ARGS_PIDFILE},
{"chroot", required_argument, 0, LONG_ARGS_CHROOT},
{"gid", required_argument, 0, LONG_ARGS_GID},
@@ -84,6 +86,7 @@ static struct option long_options[] = {
{"pyargv", required_argument, 0, LONG_ARGS_PYARGV},
#ifdef UWSGI_INI
{"ini", required_argument, 0, LONG_ARGS_INI},
{"ini-paste", required_argument, 0, LONG_ARGS_INI_PASTE},
#endif
#ifdef UWSGI_PASTE
{"paste", required_argument, 0, LONG_ARGS_PASTE},
@@ -156,15 +159,54 @@ static struct option long_options[] = {
#ifdef UWSGI_HTTP
{"http", required_argument, 0, LONG_ARGS_HTTP},
{"http-only", no_argument, &uwsgi.http_only, 1},
{"http-var", required_argument, 0, LONG_ARGS_HTTP_VAR},
#endif
{"catch-exceptions", no_argument, &uwsgi.catch_exceptions, 1},
{"mode", required_argument, 0, LONG_ARGS_MODE},
{"env", required_argument, 0, LONG_ARGS_ENV},
{"vacuum", no_argument, &uwsgi.vacuum, 1},
{"ping", required_argument, 0, LONG_ARGS_PING},
{"ping-timeout", required_argument, 0, LONG_ARGS_PING_TIMEOUT},
{"version", no_argument, 0, LONG_ARGS_VERSION},
{0, 0, 0, 0}
};
void ping(struct uwsgi_server *uwsgi) {
struct uwsgi_header uh;
struct pollfd uwsgi_poll;
// use a 3 secs timeout by default
if (!uwsgi->ping_timeout) uwsgi->ping_timeout = 3 ;
uwsgi_poll.fd = uwsgi_connect(uwsgi->ping, uwsgi->ping_timeout);
if (uwsgi_poll.fd < 0) {
exit(1);
}
uh.modifier1 = UWSGI_MODIFIER_PING;
uh.pktsize = 0;
uh.modifier2 = 0;
if (write(uwsgi_poll.fd, &uh, 4) != 4) {
uwsgi_error("write()");
exit(2);
}
uwsgi_poll.events = POLLIN;
if (!uwsgi_parse_response(&uwsgi_poll, uwsgi->ping_timeout, &uh, NULL)) {
exit(1);
}
else {
if (uh.pktsize > 0) {
exit(2);
}
else {
exit(0);
}
}
}
int find_worker_id(pid_t pid) {
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
@@ -230,6 +272,7 @@ void grace_them_all() {
void reap_them_all() {
int i;
uwsgi.to_heaven = 1;
uwsgi_log("...brutally killing workers...\n");
for (i = 1; i <= uwsgi.numproc; i++) {
kill(uwsgi.workers[i].pid, SIGTERM);
@@ -310,14 +353,23 @@ static void unconfigured_after_hook(struct uwsgi_server *uwsgi, struct wsgi_requ
static void vacuum(void) {
struct sockaddr_un sa;
socklen_t sa_len = sizeof(struct sockaddr_un);
if (uwsgi.vacuum) {
if (getpid() == masterpid) {
if (uwsgi.socket_name && uwsgi.bind_to_unix) {
if (unlink(uwsgi.socket_name)) {
uwsgi_error("unlink()");
}
else {
uwsgi_log("VACUUM: unix socket removed.\n");
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
}
memset(&sa, 0, sa_len);
if (!getsockname(uwsgi.serverfd, (struct sockaddr*)&sa, &sa_len)) {
if (sa.sun_family == AF_UNIX) {
if (unlink(sa.sun_path)) {
uwsgi_error("unlink()");
}
else {
uwsgi_log("VACUUM: unix socket removed.\n");
}
}
}
if (uwsgi.pidfile && !uwsgi.uid) {
@@ -362,7 +414,6 @@ int main(int argc, char *argv[], char *envp[]) {
int working_workers = 0;
int blocking_workers = 0;
char *cwd = NULL;
int ready_to_reload = 0;
int ready_to_die = 0;
@@ -382,9 +433,13 @@ int main(int argc, char *argv[], char *envp[]) {
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
atexit(vacuum);
// 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
@@ -485,6 +540,11 @@ int main(int argc, char *argv[], char *envp[]) {
if (optind < argc) {
char *lazy = argv[optind];
char *qc = strchr(lazy, ':');
if (qc) {
qc[0] = 0 ;
uwsgi.callable = qc + 1;
}
if (!strcmp(lazy+strlen(lazy)-3, ".py")) {
uwsgi.file_config = lazy;
}
@@ -510,14 +570,17 @@ int main(int argc, char *argv[], char *envp[]) {
parse_sys_envs(environ, long_options);
if (uwsgi.ping) {
ping(&uwsgi);
}
if (uwsgi.binary_path == argv[0]) {
cwd = uwsgi_get_cwd();
uwsgi.binary_path = malloc(strlen(argv[0]) + 1);
if (uwsgi.binary_path == NULL) {
uwsgi_error("malloc()");
exit(1);
}
strlcpy(uwsgi.binary_path, argv[0], strlen(argv[0]) + 1);
memcpy(uwsgi.binary_path, argv[0], strlen(argv[0]) + 1);
}
if (uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] == 0) {
@@ -552,7 +615,7 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_error("fopen");
exit(1);
}
if (fprintf(pidfile, "%d\n", getpid()) < 0) {
if (fprintf(pidfile, "%d\n", (int) getpid()) < 0) {
uwsgi_log( "could not write pidfile.\n");
}
fclose(pidfile);
@@ -603,7 +666,7 @@ int main(int argc, char *argv[], char *envp[]) {
sanitize_args(&uwsgi);
#ifdef UWSGI_HTTP
if (uwsgi.http) {
if (uwsgi.http && !uwsgi.is_a_reload) {
char *tcp_port = strchr(uwsgi.http, ':');
if (tcp_port) {
uwsgi.http_server_port = tcp_port+1;
@@ -636,7 +699,6 @@ int main(int argc, char *argv[], char *envp[]) {
if (uwsgi.http_only) {
signal(SIGINT, (void *) &end_me);
http_loop(&uwsgi);
// never here
exit(1);
@@ -645,7 +707,7 @@ int main(int argc, char *argv[], char *envp[]) {
pid_t http_pid = fork();
if (http_pid > 0) {
signal(SIGINT, (void *) &end_me);
masterpid = http_pid;
http_loop(&uwsgi);
// never here
exit(1);
@@ -654,6 +716,20 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_error("fork()");
exit(1);
}
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
uwsgi_log( "updating pidfile with pid %d\n", (int) getpid());
pidfile = fopen(uwsgi.pidfile, "w");
if (!pidfile) {
uwsgi_error("fopen");
exit(1);
}
if (fprintf(pidfile, "%d\n", (int) getpid()) < 0) {
uwsgi_log( "could not update pidfile.\n");
}
fclose(pidfile);
}
close(uwsgi.http_fd);
}
#endif
@@ -857,7 +933,6 @@ int main(int argc, char *argv[], char *envp[]) {
char *tcp_port = strchr(uwsgi.socket_name, ':');
if (tcp_port == NULL) {
uwsgi.serverfd = bind_to_unix(uwsgi.socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi.bind_to_unix = 1;
}
else {
uwsgi.serverfd = bind_to_tcp(uwsgi.socket_name, uwsgi.listen_queue, tcp_port);
@@ -1022,7 +1097,7 @@ int main(int argc, char *argv[], char *envp[]) {
// parse xml anyway
#ifdef UWSGI_XML
if (uwsgi.xml_config != NULL) {
if (uwsgi.xml_round2 && uwsgi.xml_config != NULL) {
uwsgi_xml_config(uwsgi.wsgi_req, NULL);
}
#endif
@@ -1160,7 +1235,7 @@ int main(int argc, char *argv[], char *envp[]) {
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72);
}
else {
strlcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 73);
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1);
}
}
uwsgi_log( "filling SNMP table...");
@@ -1218,11 +1293,9 @@ int main(int argc, char *argv[], char *envp[]) {
}
#endif
uwsgi_log( "binary reloading uWSGI...\n");
if (cwd) {
if (chdir(cwd)) {
uwsgi_error("chdir()");
exit(1);
}
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
exit(1);
}
/* check fd table (a module can obviosly open some fd on initialization...) */
uwsgi_log( "closing all fds > 2 (_SC_OPEN_MAX = %ld)...\n", sysconf(_SC_OPEN_MAX));
@@ -1430,6 +1503,21 @@ int main(int argc, char *argv[], char *envp[]) {
}
}
}
#endif
// TODO rewrite without using exit code (targeted at 0.9.7)
#ifdef __sun__
/* horrible hack... what the FU*K is doing Solaris ??? */
if (WIFSIGNALED(waitpid_status)) {
if (uwsgi.to_heaven) {
ready_to_reload++;
continue;
}
else if (uwsgi.to_hell) {
ready_to_die++;
continue;
}
}
#endif
/* check for reloading */
if (WIFEXITED(waitpid_status)) {
@@ -2284,7 +2372,7 @@ void uwsgi_wsgi_config(char *filename) {
PyObject *app_list;
int ret;
Py_ssize_t i;
PyObject *app_mnt, *app_app;
PyObject *app_mnt, *app_app = NULL;
FILE *uwsgifile;
char *quick_callable = NULL;
@@ -2292,6 +2380,11 @@ void uwsgi_wsgi_config(char *filename) {
uwsgi.single_interpreter = 1;
if (filename) {
if (uwsgi.callable) {
quick_callable = uwsgi.callable ;
}
uwsgifile = fopen(filename, "r");
if (!uwsgifile) {
uwsgi_error("fopen()");
@@ -2326,10 +2419,15 @@ void uwsgi_wsgi_config(char *filename) {
}
else {
quick_callable = strchr(uwsgi.wsgi_config, ':');
if (quick_callable) {
quick_callable[0] = 0 ;
quick_callable++;
if (uwsgi.callable) {
quick_callable = uwsgi.callable ;
}
else {
quick_callable = strchr(uwsgi.wsgi_config, ':');
if (quick_callable) {
quick_callable[0] = 0 ;
quick_callable++;
}
}
wsgi_module = PyImport_ImportModule(uwsgi.wsgi_config);
@@ -2395,8 +2493,18 @@ void uwsgi_wsgi_config(char *filename) {
}
else {
// quick callable -> thanks gunicorn for the idea
app_app = PyDict_GetItemString(wsgi_dict, quick_callable);
if (app_app) {
// we have extended the concept a bit...
if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') {
quick_callable[strlen(quick_callable) -2 ] = 0 ;
PyObject *tmp_callable = PyDict_GetItemString(wsgi_dict, quick_callable);
if (tmp_callable) {
app_app = python_call(tmp_callable, PyTuple_New(0), 0);
}
}
else {
app_app = PyDict_GetItemString(wsgi_dict, quick_callable);
}
if (app_app) {
applications = PyDict_New();
if (!applications) {
uwsgi_log( "could not initialize applications dictionary\n");
@@ -2407,11 +2515,11 @@ void uwsgi_wsgi_config(char *filename) {
uwsgi_log( "unable to set default application\n");
exit(1);
}
}
else {
}
else {
uwsgi_log( "\"%s\" callable not found.\n", quick_callable);
exit(1);
}
}
}
if (!PyDict_Check(applications)) {
@@ -2694,6 +2802,15 @@ void manage_opt(int i, char *optarg) {
case LONG_ARGS_CHDIR2:
uwsgi.chdir2 = optarg;
break;
case LONG_ARGS_PING:
uwsgi.ping = optarg;
break;
case LONG_ARGS_PING_TIMEOUT:
uwsgi.ping_timeout = atoi(optarg);
break;
case LONG_ARGS_CALLABLE:
uwsgi.callable = optarg;
break;
#ifdef UWSGI_HTTP
case LONG_ARGS_HTTP:
uwsgi.http = optarg;
@@ -2811,6 +2928,17 @@ void manage_opt(int i, char *optarg) {
case LONG_ARGS_ERLANG_COOKIE:
uwsgi.erlang_cookie = optarg;
break;
#endif
#ifdef UWSGI_HTTP
case LONG_ARGS_HTTP_VAR:
if (uwsgi.http_vars_cnt < 63) {
uwsgi.http_vars[uwsgi.http_vars_cnt] = optarg;
uwsgi.http_vars_cnt++;
}
else {
uwsgi_log( "you can specify at most 64 --http-var options\n");
}
break;
#endif
case LONG_ARGS_PYTHONPATH:
if (uwsgi.python_path_cnt < 63) {
@@ -2841,6 +2969,31 @@ void manage_opt(int i, char *optarg) {
case LONG_ARGS_INI:
uwsgi.ini = optarg;
break;
case LONG_ARGS_INI_PASTE:
uwsgi.ini = optarg;
if (uwsgi.ini[0] != '/') {
uwsgi.paste = malloc( 7 + strlen(uwsgi.cwd) + 1 + strlen(uwsgi.ini) + 1);
if (uwsgi.paste == NULL) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.paste, 0, 7 + strlen(uwsgi.cwd) + strlen(uwsgi.ini) + 1);
memcpy(uwsgi.paste, "config:", 7);
memcpy(uwsgi.paste + 7, uwsgi.cwd, strlen(uwsgi.cwd));
uwsgi.paste[7 + strlen(uwsgi.cwd)] = '/';
memcpy(uwsgi.paste + 7 + strlen(uwsgi.cwd) + 1, uwsgi.ini, strlen(uwsgi.ini));
}
else {
uwsgi.paste = malloc( 7 + strlen(uwsgi.ini) + 1);
if (uwsgi.paste == NULL) {
uwsgi_error("malloc()");
exit(1);
}
memset(uwsgi.paste, 0, 7 + strlen(uwsgi.ini) + 1);
memcpy(uwsgi.paste, "config:", 7);
memcpy(uwsgi.paste + 7, uwsgi.ini, strlen(uwsgi.ini));
}
break;
#endif
#ifdef UWSGI_PASTE
case LONG_ARGS_PASTE:
@@ -2989,7 +3142,7 @@ void manage_opt(int i, char *optarg) {
\t-v|--max-vars <n>\t\tset maximum number of vars/headers to <n>\n\
\t-A|--sharedarea <n>\t\tcreate a shared memory area of <n> pages\n\
\t-c|--cgi-mode\t\t\tset cgi mode\n\
\t-C|--chmod-socket\t\tchmod socket to 666\n\
\t-C|--chmod-socket[=NNN]\t\tchmod socket to 666 or NNN\n\
\t-P|--profiler\t\t\tenable profiler\n\
\t-m|--memory-report\t\tenable memory usage report\n\
\t-i|--single-interpreter\t\tsingle interpreter mode\n\
@@ -3002,10 +3155,13 @@ void manage_opt(int i, char *optarg) {
\t-R|--max-requests\t\tmaximum number of requests for each worker\n\
\t-j|--test\t\t\ttest if uWSGI can import a module\n\
\t-Q|--spooler <dir>\t\trun the spooler on directory <dir>\n\
\t--callable <callable>\t\tset the callable (default 'application')\n\
\t--pidfile <file>\t\twrite the masterpid to <file>\n\
\t--chroot <dir>\t\t\tchroot to directory <dir> (only root)\n\
\t--gid <id>\t\t\tsetgid to <id> (only root)\n\
\t--uid <id>\t\t\tsetuid to <id> (only root)\n\
\t--gid <id/groupname>\t\tsetgid to <id/groupname> (only root)\n\
\t--uid <id/username>\t\tsetuid to <id/username> (only root)\n\
\t--chdir <dir>\t\t\tchdir to <dir> before app loading\n\
\t--chdir2 <dir>\t\t\tchdir to <dir> after module loading\n\
\t--no-server\t\t\tinitialize the uWSGI server then exit. Useful for testing and using uwsgi embedded module\n\
\t--no-defer-accept\t\tdisable the no-standard way to defer the accept() call (TCP_DEFER_ACCEPT, SO_ACCEPTFILTER...)\n\
\t--paste <config:/egg:>\t\tload applications using paste.deploy.loadapp()\n\
@@ -3017,8 +3173,11 @@ void manage_opt(int i, char *optarg) {
\t--post-buffering <bytes>\tbuffer HTTP POST request higher than <bytes> to disk\n\
\t--post-buffering-bufsize <b>\tset the buffer size to <b> bytes for post-buffering\n\
\t--prio <N>\t\t\tset process priority/nice to N\n\
\t--no-orphans\t\t\tautomatically kill workers on master's dead\n\
\t--udp <ip:port>\t\t\tbind master process to udp socket on ip:port\n\
\t--multicast <group>\t\tset multicast group\n\
\t--snmp\t\t\t\tenable SNMP support in the UDP server\n\
\t--snmp-community <value>\tset SNMP community code to <value>\n\
\t--erlang <name@ip>\t\tenable the Erlang server with node name <node@ip>\n\
\t--erlang-cookie <cookie>\ttset the erlang cookie to <cookie>\n\
\t--nagios\t\t\tdo a nagios check\n\
@@ -3027,9 +3186,32 @@ void manage_opt(int i, char *optarg) {
\t--proxy-node <socket>\t\tadd the node <socket> to the proxy\n\
\t--proxy-max-connections <n>\tset the max number of concurrent connections mnaged by the proxy\n\
\t--wsgi-file <file>\t\tload the <file> wsgi file\n\
\t--file <file>\t\t\tuse python file instead of python module for configuration\n\
\t--async <n>\t\t\tenable async mode with n core\n\
\t--logto <logfile|addr>\t\tlog to file/udp\n\
\t--logdate\t\t\tadd timestamp to loglines\n\
\t--ignore-script-name\t\tdisable uWSGI management of SCRIPT_NAME\n\
\t--ini <inifile>\t\t\tpath of ini config file\n\
\t--ini-paste <inifile>\t\tpath of ini config file that contains paste configuration\n\
\t--ldap <url>\t\t\turl of LDAP uWSGIConfig resource\n\
\t--ldap-schema\t\t\tdump uWSGIConfig LDAP schema\n\
\t--ldap-schema-ldif\t\tdump uWSGIConfig LDAP schema in LDIF format\n\
\t--grunt\t\t\t\tenable grunt workers\n\
\t--ugreen\t\t\tenable uGreen support\n\
\t--ugreen-stacksize <n>\t\tset uGreen stacksize to <n>\n\
\t--stackless\t\t\tenable usage of tasklet (only on Stackless Python)\n\
\t--no-site\t\t\tdo not import site.py on startup\n\
\t--vhost\t\t\t\tenable virtual hosting\n\
\t--routing\t\t\tenable uWSGI advanced routing\n\
\t--http <addr>\t\t\tstart embedded HTTP server on <addr>\n\
\t--http-only\t\t\tstart only the embedded HTTP server\n\
\t--http-var KEY[=VALUE]\t\tadd var KEY to uwsgi requests made by the embedded HTTP server\n\
\t--catch-exceptions\t\tprint exceptions in the browser\n\
\t--mode\t\t\t\tset configuration mode\n\
\t--env KEY=VALUE\t\t\tset environment variable\n\
\t--vacuum\t\t\tclear the environment on exit (remove UNIX sockets and pidfiles)\n\
\t--ping <addr>\t\t\tping a uWSGI server (returns 1 on failure 0 on success)\n\
\t--ping-timeout <n>\t\tset ping timeout to <n>\n\
\t--version\t\t\tprint server version\n\
\t-d|--daemonize <logfile|addr>\tdaemonize and log into <logfile> or udp <addr>\n", uwsgi.binary_path);
exit(1);
@@ -3065,7 +3247,7 @@ void uwsgi_cluster_add_node(char *nodename, int workers) {
ucn = &uwsgi.shared->nodes[i];
if (ucn->name[0] == 0) {
strlcpy(ucn->name, nodename, 101);
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));
@@ -3086,3 +3268,4 @@ void uwsgi_cluster_add_node(char *nodename, int workers) {
uwsgi_log( "unable to add node %s\n", nodename);
}
+27 -6
View File
@@ -2,7 +2,7 @@
/* indent -i8 -br -brs -brf -l0 -npsl -nip -npcs -npsl -di1 */
#define UWSGI_VERSION "0.9.6-dev"
#define UWSGI_VERSION "0.9.6"
#define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
#define uwsgi_debug(x, ...) uwsgi_log("[uWSGI DEBUG] " x, __VA_ARGS__);
@@ -25,10 +25,7 @@
#include <sys/utsname.h>
// linux has not strlcpy
#ifdef __linux
#define strlcpy(x, y, z) strcpy(x, y)
#define strlcat(x, y, z) strcat(x, y)
#include <sys/prctl.h>
#endif
@@ -101,6 +98,7 @@
#include <sys/sendfile.h>
#include <sys/epoll.h>
#elif defined(__sun__)
#include <sys/sendfile.h>
#include <sys/devpoll.h>
#else
#include <sys/event.h>
@@ -174,6 +172,11 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t);
#define LONG_ARGS_LDAP_SCHEMA 17036
#define LONG_ARGS_LDAP 17037
#define LONG_ARGS_LDAP_SCHEMA_LDIF 17038
#define LONG_ARGS_PING 17039
#define LONG_ARGS_PING_TIMEOUT 17040
#define LONG_ARGS_INI_PASTE 17041
#define LONG_ARGS_CALLABLE 17042
#define LONG_ARGS_HTTP_VAR 17043
@@ -448,11 +451,16 @@ struct uwsgi_server {
uid_t uid;
char *mode;
#ifdef UWSGI_HTTP
char *http;
char *http_server_name;
char *http_server_port;
int http_only;
int http_fd;
char *http_vars[64];
int http_vars_cnt;
#endif
int ignore_script_name;
int logdate;
@@ -656,6 +664,7 @@ struct uwsgi_server {
#ifdef UWSGI_EMBED_PLUGIN_RACK
char *plugin_arg_rack;
char *plugin_arg_rails;
#endif
#endif
@@ -664,12 +673,20 @@ struct uwsgi_server {
int catch_exceptions;
int vacuum;
int bind_to_unix;
int no_server;
#ifdef UWSGI_LDAP
char *ldap;
#endif
char *ping;
int ping_timeout;
char *callable;
int xml_round2;
char *cwd;
};
struct uwsgi_cluster_node {
@@ -1043,11 +1060,15 @@ void embed_plugins(struct uwsgi_server *);
#ifdef UWSGI_EMBED_PLUGIN_RACK
#undef UWSGI_PLUGIN_LONGOPT_RACK
#define UWSGI_PLUGIN_LONGOPT_RACK {"rack", required_argument, 0, 30007},
#define UWSGI_PLUGIN_LONGOPT_RACK {"rack", required_argument, 0, 30007},\
{"rails", required_argument, 0, 30008},
#undef LONG_ARGS_PLUGIN_EMBED_RACK
#define LONG_ARGS_PLUGIN_EMBED_RACK case 30007:\
uwsgi.plugin_arg_rack = optarg;\
break;\
case 30008:\
uwsgi.plugin_arg_rails = optarg;\
break;
#endif
+1 -1
View File
@@ -28,7 +28,7 @@ STACKLESS=False
PLUGINS = []
USWALLOW=False
UNBIT=False
DEBUG=True
DEBUG=False
EMBED_PLUGINS=True
UWSGI_BIN_NAME = 'uwsgi'
UWSGI_PLUGIN_DIR = '.'
+29 -2
View File
@@ -23,6 +23,8 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, struct option *long_options
char *colon ;
char *xml_id ;
colon = strchr(uwsgi.xml_config, ':');
if (colon) {
colon[0] = 0 ;
@@ -54,8 +56,10 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, struct option *long_options
element = NULL ;
if (node->type == XML_ELEMENT_NODE) {
if (!strcmp((char *) node->name, "uwsgi")) {
if (colon) {
if (strcmp(colon, (char *) xmlGetProp(node, (const xmlChar *) "id")) ) {
xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id");
if (colon && xml_id) {
if ( strcmp(colon, xml_id) ) {
continue;
}
}
@@ -76,6 +80,22 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, struct option *long_options
// first check for options
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (!strcmp((char *) node->name, "app")) {
uwsgi.xml_round2 = 1 ;
continue;
}
#ifdef UWSGI_ROUTING
if (!strcmp((char *) node->name, "route")) {
uwsgi.xml_round2 = 1 ;
continue;
}
if (!strcmp((char *) node->name, "routing")) {
uwsgi.xml_round2 = 1 ;
continue;
}
#endif
lopt = long_options;
while ((aopt = lopt)) {
if (!aopt->name)
@@ -100,6 +120,13 @@ void uwsgi_xml_config(struct wsgi_request *wsgi_req, struct option *long_options
}
}
xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id") ;
if (colon && xml_id) {
if (strcmp(colon, xml_id)) {
goto next;
}
}
if (aopt->flag) {
*aopt->flag = aopt->val;
}