diff --git a/CMakeLists.txt b/CMakeLists.txt index 076de21..a6be0a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,54 +2,28 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR) cmake_policy(VERSION 2.6.0) +SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + INCLUDE(CheckIncludeFiles) INCLUDE(CheckLibraryExists) INCLUDE(FindPkgConfig) +INCLUDE(AddTargetProperties) -MACRO(ADD_TARGET_PROPERTIES _target _name _properties) - SET(_properties ${ARGV}) - LIST(REMOVE_AT _properties 0) - LIST(REMOVE_AT _properties 0) - GET_TARGET_PROPERTY(_old_properties ${_target} ${_name}) - #MESSAGE("adding property to ${_target} ${_name}: ${_properties}") - IF(NOT _old_properties) - # in case it's NOTFOUND - SET(_old_properties) - ELSE(NOT _old_properties) - SET(_old_properties "${_old_properties} ") - ENDIF(NOT _old_properties) - SET_TARGET_PROPERTIES(${_target} PROPERTIES ${_name} "${_old_properties}${_properties}") -ENDMACRO(ADD_TARGET_PROPERTIES) PROJECT(fcgi-cgi C) -SET(PACKAGE_VERSION 0.2.1) +SET(PACKAGE_VERSION 0.2.2) + IF("${CMAKE_BUILD_TYPE}" STREQUAL "") SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") # libev -CHECK_INCLUDE_FILES(ev.h HAVE_EV_H) -IF(HAVE_EV_H) - CHECK_LIBRARY_EXISTS(ev ev_time "" HAVE_LIBEV) - IF(HAVE_LIBEV) - SET(EV_LIBRARIES ev) - SET(EV_STATIC_LIBRARIES ev;m) - CHECK_LIBRARY_EXISTS(rt clock_gettime "" NEED_RT) - IF(NEED_RT) - SET(EV_STATIC_LIBRARIES ${EV_STATIC_LIBRARIES} rt) - ENDIF(NEED_RT) - ELSE(HAVE_LIBEV) - MESSAGE(FATAL_ERROR "Couldn't find lib ev") - ENDIF(HAVE_LIBEV) -ELSE(HAVE_EV_H) - MESSAGE(FATAL_ERROR "Couldn't find ") -ENDIF(HAVE_EV_H) +FIND_PACKAGE(LibEV REQUIRED) # GLIB 2 pkg_check_modules (GLIB2 REQUIRED glib-2.0) -SET(GLIB_INCLUDES ${GLIB2_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}/glib-2.0/ ${GLIB2_INCLUDE_DIRS}/glib-2.0/include/) -INCLUDE_DIRECTORIES(${GLIB_INCLUDES}) +INCLUDE_DIRECTORIES(${GLIB2_INCLUDES_DIRS}) SET(MAIN_SOURCE fastcgi.c fcgi-cgi.c) @@ -61,15 +35,15 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) add_executable(fcgi-cgi ${MAIN_SOURCE}) -ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC -D_GNU_SOURCE") +ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC") # libev -TARGET_LINK_LIBRARIES(fcgi-cgi "${EV_LIBRARIES}") +TARGET_LINK_LIBRARIES(fcgi-cgi ${LIBEV_LDFLAGS}) +ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS ${LIBEV_CFLAGS}) # GLIB 2 -TARGET_LINK_LIBRARIES(fcgi-cgi "${GLIB2_LIBRARIES}") -ADD_TARGET_PROPERTIES(fcgi-cgi LINK_FLAGS "${GLIB2_LDFLAGS}") -ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "${GLIB2_CFLAGS_OTHER}") +TARGET_LINK_LIBRARIES(fcgi-cgi ${GLIB2_LDFLAGS}) +ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS ${GLIB2_CFLAGS}) INSTALL(TARGETS fcgi-cgi DESTINATION bin) diff --git a/README b/README deleted file mode 100644 index 6919976..0000000 --- a/README +++ /dev/null @@ -1,2 +0,0 @@ - -fcgi-cgi is a FastCGI application to run cgi applications. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..14825f4 --- /dev/null +++ b/README.rst @@ -0,0 +1,54 @@ +Description +----------- + +:Homepage: + http://redmine.lighttpd.net/projects/fcgi-cgi/wiki + +fcgi-cgi is a FastCGI application to run normal cgi applications. It doesn't +make CGI applications faster, but it allows you to run them on a different +host and with different user permissions (without the need for suexec). + +lighttpd2 won't have a mod_cgi, so you need this FastCGI wrapper to be able +to execute standard cgi applications like mailman and cgit. + +fcgi-cgi is released under the `MIT license `_ + +Usage +----- + +Examples for spawning a fcg-cgi instance with daemontools or runit:: + + #!/bin/sh + # run script + + exec spawn-fcgi -n -s /tmp/fastcgi-cgi.sock -u www-default -U www-data -- /usr/bin/fcgi-cgi + + +Build dependencies +------------------ + +* glib >= 2.16.0 (http://www.gtk.org/) +* libev (http://software.schmorp.de/pkg/libev.html) +* cmake or autotools (for snapshots/releases the autotool generated files are included) + + +Build +----- + +* snapshot/release with autotools:: + + ./configure + make + +* build from git: ``git clone git://git.lighttpd.net/fcgi-cgi.git`` + + * with autotools:: + + ./autogen.sh + ./configure + make + + * with cmake (should work with snapshots/releases too):: + + cmake . + make diff --git a/cmake/AddTargetProperties.cmake b/cmake/AddTargetProperties.cmake new file mode 100644 index 0000000..17ee774 --- /dev/null +++ b/cmake/AddTargetProperties.cmake @@ -0,0 +1,13 @@ +MACRO(ADD_TARGET_PROPERTIES _target _name) + SET(_properties) + FOREACH(_prop ${ARGN}) + SET(_properties "${_properties} ${_prop}") + ENDFOREACH(_prop) + GET_TARGET_PROPERTY(_old_properties ${_target} ${_name}) + MESSAGE(STATUS "adding property to ${_target} ${_name}:" ${_properties}) + IF(NOT _old_properties) + # in case it's NOTFOUND + SET(_old_properties) + ENDIF(NOT _old_properties) + SET_TARGET_PROPERTIES(${_target} PROPERTIES ${_name} "${_old_properties} ${_properties}") +ENDMACRO(ADD_TARGET_PROPERTIES) diff --git a/cmake/FindLibEV.cmake b/cmake/FindLibEV.cmake new file mode 100644 index 0000000..29035e3 --- /dev/null +++ b/cmake/FindLibEV.cmake @@ -0,0 +1,71 @@ + +SET(LIBEV_PATH "" CACHE PATH "Base path for include/ev.h and lib/libev*") +SET(LIBEV_INCLUDE_PATH "" CACHE PATH "Include path for ev.h") +SET(LIBEV_LIBDIR "" CACHE PATH "Path containing libev") + +IF(LIBEV_PATH) + SET(LIBEV_INCLUDE_PATH "${LIBEV_PATH}/include" CACHE PATH "Include path for ev.h" FORCE) + SET(LIBEV_LIBDIR "${LIBEV_PATH}/lib" CACHE PATH "Path containing libev" FORCE) +ENDIF(LIBEV_PATH) + +IF(LIBEV_INCLUDE_PATH) + INCLUDE_DIRECTORIES(${LIBEV_INCLUDE_PATH}) +ENDIF(LIBEV_INCLUDE_PATH) + +# Use cached result +IF(NOT LIBEV_FOUND) + UNSET(HAVE_EV_H) + UNSET(HAVE_LIBEV) + UNSET(HAVE_EV_H CACHE) + UNSET(HAVE_LIBEV CACHE) + UNSET(LIBEV_CFLAGS) + UNSET(LIBEV_LDFLAGS) + + IF(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR) + SET(CMAKE_REQUIRED_INCLUDES ${LIBEV_INCLUDE_PATH}) +# MESSAGE(STATUS "Looking for ev.h in ${CMAKE_REQUIRED_INCLUDES}") + CHECK_INCLUDE_FILES(ev.h HAVE_EV_H) + IF(HAVE_EV_H) +# MESSAGE(STATUS "Looking for lib ev in ${LIBEV_LIBDIR}") + CHECK_LIBRARY_EXISTS(ev ev_time "${LIBEV_LIBDIR}" HAVE_LIBEV) + IF(HAVE_LIBEV) + SET(LIBEV_LIBRARIES ev CACHE INTERNAL "") + SET(LIBEV_CFLAGS "" CACHE INTERNAL "") + SET(LIBEV_LDFLAGS "-L${LIBEV_LIBDIR} -lev" CACHE INTERNAL "") + SET(LIBEV_FOUND TRUE CACHE INTERNAL "Found libev" FORCE) + ELSE(HAVE_LIBEV) + MESSAGE(STATUS "Couldn't find lib ev in ${LIBEV_LIBDIR}") + ENDIF(HAVE_LIBEV) + ELSE(HAVE_EV_H) + MESSAGE(STATUS "Couldn't find in ${LIBEV_INCLUDE_PATH}") + ENDIF(HAVE_EV_H) + ELSE(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR) + pkg_check_modules(LIBEV libev) + IF(NOT LIBEV_FOUND) +# MESSAGE(STATUS "Looking for ev.h in ${CMAKE_REQUIRED_INCLUDES}") + CHECK_INCLUDE_FILES(ev.h HAVE_EV_H) + IF(HAVE_EV_H) +# MESSAGE(STATUS "Looking for lib ev") + CHECK_LIBRARY_EXISTS(ev ev_time "" HAVE_LIBEV) + IF(HAVE_LIBEV) + SET(LIBEV_CFLAGS "" CACHE INTERNAL "") + SET(LIBEV_LDFLAGS "-lev" CACHE INTERNAL "") + SET(LIBEV_FOUND TRUE CACHE INTERNAL "Found libev" FORCE) + ELSE(HAVE_LIBEV) + MESSAGE(STATUS "Couldn't find lib ev") + ENDIF(HAVE_LIBEV) + ELSE(HAVE_EV_H) + MESSAGE(STATUS "Couldn't find ") + ENDIF(HAVE_EV_H) + ENDIF(NOT LIBEV_FOUND) + ENDIF(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR) + +ENDIF(NOT LIBEV_FOUND) + +IF(NOT LIBEV_FOUND) + IF(LibEV_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find libev") + ENDIF(LibEV_FIND_REQUIRED) +ENDIF(NOT LIBEV_FOUND) + +MARK_AS_ADVANCED(LIBEV_PATH LIBEV_INCLUDE_PATH LIBEV_LIBDIR) diff --git a/configure.ac b/configure.ac index 17595a0..57a4036 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) -AC_INIT([fcgi-cgi], [0.2.1], [lighttpd@stbuehler.de]) +AC_INIT([fcgi-cgi], [0.2.2], [lighttpd@stbuehler.de]) AC_CONFIG_SRCDIR([fcgi-cgi.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/fastcgi.c b/fastcgi.c index 4091909..f4ad71f 100644 --- a/fastcgi.c +++ b/fastcgi.c @@ -604,7 +604,31 @@ error: static void fastcgi_connection_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { fastcgi_connection *fcon = (fastcgi_connection*) w->data; - UNUSED(loop); + + if (fcon->closing) { + char buf[1024]; + ssize_t r; + + r = read(fcon->fd, buf, sizeof(buf)); + if (r > 0) return; + + if (-1 == r) switch (errno) { + case EINTR: + case EAGAIN: + #if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: + #endif + return; /* try again later */ + default: + break; + } + + ev_io_stop(loop, w); + close(fcon->fd); + fcon->fd = -1; + ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher); + return; + } if (revents & EV_READ) { read_queue(fcon); @@ -637,11 +661,6 @@ static fastcgi_connection *fastcgi_connecion_create(fastcgi_server *fsrv, gint f static void fastcgi_connection_free(fastcgi_connection *fcon) { fcon->fsrv->callbacks->cb_reset_connection(fcon); - if (fcon->fd != -1) { - ev_io_stop(fcon->fsrv->loop, &fcon->fd_watcher); - close(fcon->fd); - fcon->fd = -1; - } fastcgi_queue_clear(&fcon->write_queue); fastcgi_connection_environ_clear(fcon); @@ -655,9 +674,7 @@ static void fastcgi_connection_free(fastcgi_connection *fcon) { void fastcgi_connection_close(fastcgi_connection *fcon) { fcon->closing = TRUE; if (fcon->fd != -1) { - ev_io_stop(fcon->fsrv->loop, &fcon->fd_watcher); - close(fcon->fd); - fcon->fd = -1; + shutdown(fcon->fd, SHUT_WR); } fastcgi_queue_clear(&fcon->write_queue); @@ -666,7 +683,9 @@ void fastcgi_connection_close(fastcgi_connection *fcon) { g_byte_array_set_size(fcon->parambuf, 0); fastcgi_connection_environ_clear(fcon); - ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher); + if (fcon->fd == -1) { + ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher); + } } static void fastcgi_server_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { @@ -723,7 +742,7 @@ static void fastcgi_cleanup_connections(fastcgi_server *fsrv) { for (i = 0; i < fsrv->connections->len; ) { fastcgi_connection *fcon = g_ptr_array_index(fsrv->connections, i); - if (fcon->closing) { + if (fcon->closing && -1 == fcon->fd) { fastcgi_connection *t_fcon; guint l = fsrv->connections->len-1; t_fcon = g_ptr_array_index(fsrv->connections, i) = g_ptr_array_index(fsrv->connections, l); diff --git a/fcgi-cgi.c b/fcgi-cgi.c index b00188b..c85236d 100644 --- a/fcgi-cgi.c +++ b/fcgi-cgi.c @@ -22,7 +22,7 @@ #define __STR(x) #x #define ERROR(...) g_printerr("fcgi-cgi.c:" G_STRINGIFY(__LINE__) ": " __VA_ARGS__) -#define PACKAGE_DESC (PACKAGE_NAME " v" PACKAGE_VERSION " - forks and watches multiple instances of a program in the same environment") +#define PACKAGE_DESC (PACKAGE_NAME " v" PACKAGE_VERSION " - FastCGI application to run normal cgi applications") struct fcgi_cgi_server; typedef struct fcgi_cgi_server fcgi_cgi_server; @@ -311,6 +311,32 @@ static void fcgi_cgi_child_error(fcgi_cgi_child *cld) { } } +static void copy_env_var(GPtrArray *env, const char *name) { + guint i, namelen = strlen(name); + const char *value; + + for (i = 0; i < env->len; ) { + const char *entry = g_ptr_array_index(env, i); + if (0 == strncmp(entry, name, namelen) && entry[namelen] == '=') { + g_ptr_array_remove_index_fast(env, i); + g_free((char*) entry); + } else { + ++i; + } + } + + value = getenv(name); + if (NULL != value) { + guint valuelen = strlen(value); + char *entry = g_malloc(namelen + valuelen + 2); + memcpy(entry, name, namelen); + entry[namelen] = '='; + memcpy(entry + namelen + 1, value, valuelen); + entry[namelen+valuelen+1] = 0; + g_ptr_array_add(env, entry); + } +} + static void fcgi_cgi_child_start(fcgi_cgi_child *cld, const gchar *path) { int pipes_to[2] = {-1, -1}, pipes_from[2] = {-1, -1}, pipes_err[2] = {-1, -1}; pid_t pid; @@ -353,6 +379,7 @@ static void fcgi_cgi_child_start(fcgi_cgi_child *cld, const gchar *path) { } } + copy_env_var(enva, "PATH"); g_ptr_array_add(enva, NULL); newenv = (char**) g_ptr_array_free(enva, FALSE); execve(path, args, newenv);