2011-11-01 04:24:38 +04:00
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright ( C ) 2011 Colin Walters < walters @ verbum . org >
*
* 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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
* Author : Colin Walters < walters @ verbum . org >
*/
# include <gio/gio.h>
# include <sys/types.h>
# include <unistd.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <errno.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <sys/stat.h>
/* Taken from gnome-user-share src/httpd.c under the GPLv2 */
static int
get_port ( void )
{
int sock ;
int saved_errno ;
struct sockaddr_in addr ;
int reuse ;
socklen_t len ;
sock = socket ( PF_INET , SOCK_STREAM , 0 ) ;
if ( sock < 0 )
{
return - 1 ;
}
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = 0 ;
addr . sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
reuse = 1 ;
setsockopt ( sock , SOL_SOCKET , SO_REUSEADDR , & reuse , sizeof ( reuse ) ) ;
if ( bind ( sock , ( struct sockaddr * ) & addr , sizeof ( addr ) ) = = - 1 )
{
saved_errno = errno ;
close ( sock ) ;
errno = saved_errno ;
return - 1 ;
}
len = sizeof ( addr ) ;
if ( getsockname ( sock , ( struct sockaddr * ) & addr , & len ) = = - 1 )
{
saved_errno = errno ;
close ( sock ) ;
errno = saved_errno ;
return - 1 ;
}
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
/* XXX This exposes a potential race condition, but without this,
* httpd will not start on the above listed platforms due to the fact
* that SO_REUSEADDR is also needed when Apache binds to the listening
* socket . At this time , Apache does not support that socket option .
*/
close ( sock ) ;
# endif
return ntohs ( addr . sin_port ) ;
}
static const char * known_httpd_modules_locations [ ] = {
" /usr/libexec/apache2 " ,
" /usr/lib/apache2/modules " ,
" /usr/lib64/httpd/modules " ,
" /usr/lib/httpd/modules " ,
NULL
} ;
static gchar *
get_httpd_modules_path ( )
{
int i ;
for ( i = 0 ; known_httpd_modules_locations [ i ] ; i + + )
{
if ( g_file_test ( known_httpd_modules_locations [ i ] , G_FILE_TEST_IS_EXECUTABLE )
& & g_file_test ( known_httpd_modules_locations [ i ] , G_FILE_TEST_IS_DIR ) )
{
return g_strdup ( known_httpd_modules_locations [ i ] ) ;
}
}
return NULL ;
}
int
main ( int argc ,
char * * argv )
{
int port ;
char * listen ;
char * address_string ;
GError * error = NULL ;
GPtrArray * httpd_argv ;
char * modules ;
if ( argc ! = 3 )
{
fprintf ( stderr , " usage: run-apache CONF PORTFILE " ) ;
return 1 ;
}
g_type_init ( ) ;
port = get_port ( ) ;
if ( port = = - 1 )
{
perror ( " Failed to bind port " ) ;
return 1 ;
}
httpd_argv = g_ptr_array_new ( ) ;
g_ptr_array_add ( httpd_argv , " httpd " ) ;
2011-11-01 20:35:50 +04:00
g_ptr_array_add ( httpd_argv , " -X " ) ;
2011-11-01 04:24:38 +04:00
g_ptr_array_add ( httpd_argv , " -f " ) ;
g_ptr_array_add ( httpd_argv , argv [ 1 ] ) ;
g_ptr_array_add ( httpd_argv , " -C " ) ;
listen = g_strdup_printf ( " Listen 127.0.0.1:%d " , port ) ;
g_ptr_array_add ( httpd_argv , listen ) ;
g_ptr_array_add ( httpd_argv , NULL ) ;
address_string = g_strdup_printf ( " http://127.0.0.1:%d \n " , port ) ;
if ( ! g_file_set_contents ( argv [ 2 ] , address_string , - 1 , & error ) )
{
g_printerr ( " %s \n " , error - > message ) ;
return 1 ;
}
setenv ( " LANG " , " C " , 1 ) ;
modules = get_httpd_modules_path ( ) ;
if ( modules = = NULL )
{
g_printerr ( " Failed to find httpd modules \n " ) ;
return 1 ;
}
if ( symlink ( modules , " modules " ) < 0 )
{
perror ( " failed to make modules symlink " ) ;
return 1 ;
}
execvp ( " httpd " , ( char * * ) httpd_argv - > pdata ) ;
perror ( " Failed to run httpd " ) ;
return 1 ;
}