Browse Source

- merge spawn-fcgi changes from trunk (from @2191)

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2192 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.20
Elan Ruusamäe 14 years ago
parent
commit
ef95813dea
  1. 1
      NEWS
  2. 160
      src/server.c
  3. 276
      src/spawn-fcgi.c

1
NEWS

@ -25,6 +25,7 @@ NEWS
* Do not rely on PATH_MAX (POSIX does not require it) (#580)
* Disable logging to access.log if filename is an empty string
* Implement a clean way to open /dev/null and use it to close stdin/out/err in the needed places (#624)
* merge spawn-fcgi changes from trunk (from @2191)
- 1.4.19 - 2008-03-10

160
src/server.c

@ -865,34 +865,9 @@ int main (int argc, char **argv) {
return -1;
}
#ifdef HAVE_FORK
/* network is up, let's deamonize ourself */
if (srv->srvconf.dont_daemonize == 0) daemonize();
#endif
srv->gid = getgid();
srv->uid = getuid();
/* write pid file */
if (pid_fd != -1) {
buffer_copy_long(srv->tmp_buf, getpid());
buffer_append_string(srv->tmp_buf, "\n");
write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
close(pid_fd);
pid_fd = -1;
}
/* Close stderr ASAP in the child process to make sure that nothing
* is being written to that fd which may not be valid anymore. */
if (-1 == log_error_open(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");
plugins_free(srv);
network_close(srv);
server_free(srv);
return -1;
}
if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
@ -943,7 +918,86 @@ int main (int argc, char **argv) {
return -1;
}
if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
log_error_write(srv, __FILE__, __LINE__,
"s", "fdevent_init failed");
return -1;
}
/*
* kqueue() is called here, select resets its internals,
* all server sockets get their handlers
*
* */
if (0 != network_register_fdevents(srv)) {
plugins_free(srv);
network_close(srv);
server_free(srv);
return -1;
}
/* might fail if user is using fam (not gamin) and famd isn't running */
if (NULL == (srv->stat_cache = stat_cache_init())) {
log_error_write(srv, __FILE__, __LINE__, "s",
"stat-cache could not be setup, dieing.");
return -1;
}
#ifdef HAVE_FAM_H
/* setup FAM */
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
log_error_write(srv, __FILE__, __LINE__, "s",
"could not open a fam connection, dieing.");
return -1;
}
#ifdef HAVE_FAMNOEXISTS
FAMNoExists(srv->stat_cache->fam);
#endif
srv->stat_cache->fam_fcce_ndx = -1;
fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
}
#endif
/* get the current number of FDs */
srv->cur_fds = open("/dev/null", O_RDONLY);
close(srv->cur_fds);
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
return -1;
}
}
/* Close stderr ASAP to make sure that nothing is being written to
* that fd which may not be valid anymore after forking. */
if (-1 == log_error_open(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");
plugins_free(srv);
network_close(srv);
server_free(srv);
return -1;
}
#ifdef HAVE_FORK
/* network is up, let's deamonize ourself */
if (srv->srvconf.dont_daemonize == 0) daemonize();
#endif
/* write pid file */
if (pid_fd != -1) {
buffer_copy_long(srv->tmp_buf, getpid());
buffer_append_string(srv->tmp_buf, "\n");
write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
close(pid_fd);
pid_fd = -1;
}
#ifdef HAVE_SIGACTION
@ -1067,62 +1121,6 @@ int main (int argc, char **argv) {
}
#endif
if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
log_error_write(srv, __FILE__, __LINE__,
"s", "fdevent_init failed");
return -1;
}
/*
* kqueue() is called here, select resets its internals,
* all server sockets get their handlers
*
* */
if (0 != network_register_fdevents(srv)) {
plugins_free(srv);
network_close(srv);
server_free(srv);
return -1;
}
/* might fail if user is using fam (not gamin) and famd isn't running */
if (NULL == (srv->stat_cache = stat_cache_init())) {
log_error_write(srv, __FILE__, __LINE__, "s",
"stat-cache could not be setup, dieing.");
return -1;
}
#ifdef HAVE_FAM_H
/* setup FAM */
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
log_error_write(srv, __FILE__, __LINE__, "s",
"could not open a fam connection, dieing.");
return -1;
}
#ifdef HAVE_FAMNOEXISTS
FAMNoExists(srv->stat_cache->fam);
#endif
srv->stat_cache->fam_fcce_ndx = -1;
fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
}
#endif
/* get the current number of FDs */
srv->cur_fds = open("/dev/null", O_RDONLY);
close(srv->cur_fds);
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
return -1;
}
}
/* main-loop */
while (!srv_shutdown) {
int n;

276
src/spawn-fcgi.c

@ -37,7 +37,7 @@ typedef int socklen_t;
#endif
#ifdef HAVE_SYS_UN_H
int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) {
int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned short port, const char *unixsocket, int fork_count, int child_count, int pid_fd, int nofork) {
int fcgi_fd;
int socket_type, status;
struct timeval tv = { 0, 100 * 1000 };
@ -48,9 +48,6 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
socklen_t servlen;
pid_t child;
int val;
if (child_count < 2) {
child_count = 5;
}
@ -74,25 +71,6 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
#endif
socket_type = AF_UNIX;
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
/* check if some backend is listening on the socket
* as if we delete the socket-file and rebind there will be no "socket already in use" error
*/
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
__FILE__, __LINE__);
return -1;
}
/* cleanup previous socket if it exists */
unlink(unixsocket);
close(fcgi_fd);
} else {
fcgi_addr_in.sin_family = AF_INET;
if (addr != NULL) {
@ -107,128 +85,169 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
}
/* open socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
val = 1;
if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: bind failed: %s\n",
__FILE__, __LINE__,
strerror(errno));
return -1;
}
if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
/* server is not up, spawn in */
pid_t child;
int val;
if (-1 == listen(fcgi_fd, 1024)) {
fprintf(stderr, "%s.%d: fd = -1\n",
__FILE__, __LINE__);
return -1;
}
if (unixsocket) unlink(unixsocket);
if (!nofork) {
child = fork();
} else {
child = 0;
}
switch (child) {
case 0: {
char cgi_childs[64];
close(fcgi_fd);
int i = 0;
/* reopen socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
/* is safe as we limit to 256 childs */
sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
val = 1;
if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
close(FCGI_LISTENSOCK_FILENO);
dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
close(fcgi_fd);
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: bind failed: %s\n",
__FILE__, __LINE__,
strerror(errno));
return -1;
}
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
if (-1 == listen(fcgi_fd, 1024)) {
fprintf(stderr, "%s.%d: fd = -1\n",
__FILE__, __LINE__);
return -1;
}
/* create environment */
while (fork_count-- > 0) {
putenv(cgi_childs);
if (!nofork) {
child = fork();
} else {
child = 0;
}
/* fork and replace shell */
if (appArgv) {
execv(appArgv[0], appArgv);
switch (child) {
case 0: {
char cgi_childs[64];
int max_fd = 0;
} else {
char *b = malloc(strlen("exec ") + strlen(appPath) + 1);
strcpy(b, "exec ");
strcat(b, appPath);
int i = 0;
/* exec the cgi */
execl("/bin/sh", "sh", "-c", b, (char *)NULL);
}
/* loose control terminal */
setsid();
exit(errno);
/* is safe as we limit to 256 childs */
sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
break;
}
case -1:
/* error */
break;
default:
/* father */
/* wait */
select(0, NULL, NULL, NULL, &tv);
switch (waitpid(child, &status, WNOHANG)) {
case 0:
fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
__FILE__, __LINE__,
child);
if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
close(FCGI_LISTENSOCK_FILENO);
dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
close(fcgi_fd);
}
/* write pid file */
if (pid_fd != -1) {
/* assume a 32bit pid_t */
char pidbuf[12];
max_fd = open("/dev/null", O_RDWR);
close(STDERR_FILENO);
dup2(max_fd, STDERR_FILENO);
close(max_fd);
snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
max_fd = open("/dev/null", O_RDWR);
close(STDOUT_FILENO);
dup2(max_fd, STDOUT_FILENO);
close(max_fd);
write(pid_fd, pidbuf, strlen(pidbuf));
close(pid_fd);
pid_fd = -1;
}
/* we don't need the client socket */
for (i = 3; i < max_fd; i++) {
if (i != FCGI_LISTENSOCK_FILENO) close(i);
}
break;
case -1:
break;
default:
if (WIFEXITED(status)) {
fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
__FILE__, __LINE__,
WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s.%d: child signaled: %d\n",
__FILE__, __LINE__,
WTERMSIG(status));
} else {
fprintf(stderr, "%s.%d: child died somehow: %d\n",
__FILE__, __LINE__,
status);
/* create environment */
putenv(cgi_childs);
/* fork and replace shell */
if (appArgv) {
execv(appArgv[0], appArgv);
} else {
char *b = malloc(strlen("exec ") + strlen(appPath) + 1);
strcpy(b, "exec ");
strcat(b, appPath);
/* exec the cgi */
execl("/bin/sh", "sh", "-c", b, (char *)NULL);
}
exit(errno);
break;
}
case -1:
/* error */
break;
default:
/* father */
/* wait */
select(0, NULL, NULL, NULL, &tv);
switch (waitpid(child, &status, WNOHANG)) {
case 0:
fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
__FILE__, __LINE__,
child);
/* write pid file */
if (pid_fd != -1) {
/* assume a 32bit pid_t */
char pidbuf[12];
snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
write(pid_fd, pidbuf, strlen(pidbuf));
/* avoid eol for the last one */
if (fork_count != 0) {
write(pid_fd, "\n", 1);
}
}
break;
case -1:
break;
default:
if (WIFEXITED(status)) {
fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
__FILE__, __LINE__,
WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s.%d: child signaled: %d\n",
__FILE__, __LINE__,
WTERMSIG(status));
} else {
fprintf(stderr, "%s.%d: child died somehow: %d\n",
__FILE__, __LINE__,
status);
}
}
break;
}
}
break;
close(pid_fd);
pid_fd = -1;
} else {
fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
__FILE__, __LINE__);
return -1;
}
close(fcgi_fd);
@ -256,6 +275,7 @@ void show_help () {
" -p <port> bind to tcp-port\n" \
" -s <path> bind to unix-domain socket\n" \
" -C <childs> (PHP only) numbers of childs to spawn (default 5)\n" \
" -F <childs> numbers of childs to fork (default 1)\n" \
" -P <path> name of PID-file for spawed process\n" \
" -n no fork (for daemontools)\n" \
" -v show version\n" \
@ -276,20 +296,21 @@ int main(int argc, char **argv) {
char **fcgi_app_argv = { NULL };
unsigned short port = 0;
int child_count = 5;
int fork_count = 1;
int i_am_root, o;
int pid_fd = -1;
int nofork = 0;
struct sockaddr_un un;
const size_t sun_path_len = sizeof(un.sun_path);
i_am_root = (getuid() == 0);
while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
while (-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:F:s:P:"))) {
switch(o) {
case 'f': fcgi_app = optarg; break;
case 'a': addr = optarg;/* ip addr */ break;
case 'p': port = strtol(optarg, NULL, 10);/* port */ break;
case 'C': child_count = strtol(optarg, NULL, 10);/* */ break;
case 'F': fork_count = strtol(optarg, NULL, 10);/* */ break;
case 's': unixsocket = optarg; /* unix-domain socket */ break;
case 'c': if (i_am_root) { changeroot = optarg; }/* chroot() */ break;
case 'u': if (i_am_root) { username = optarg; } /* set user */ break;
@ -321,7 +342,7 @@ int main(int argc, char **argv) {
return -1;
}
if (unixsocket && strlen(unixsocket) > sun_path_len - 1) {
if (unixsocket && strlen(unixsocket) > sizeof(un.sun_path) - 1) {
fprintf(stderr, "%s.%d: %s\n",
__FILE__, __LINE__,
"path of the unix socket is too long\n");
@ -416,18 +437,15 @@ int main(int argc, char **argv) {
"I will not set gid to 0\n");
return -1;
}
}
/*
* Change group before chroot, when we have access
* to /etc/group
*/
if (groupname) {
/* do the change before we do the chroot() */
setgid(grp->gr_gid);
setgroups(0, NULL);
setgroups(0, NULL);
if (username) {
initgroups(username, grp->gr_gid);
}
}
if (changeroot) {
@ -451,7 +469,7 @@ int main(int argc, char **argv) {
}
}
return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, child_count, pid_fd, nofork);
return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, fork_count, child_count, pid_fd, nofork);
}
#else
int main() {

Loading…
Cancel
Save