2010-01-23 03:52:57 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd 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 .
systemd 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 systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-24 00:56:47 +03:00
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
2010-01-29 08:45:59 +03:00
# include <sys/epoll.h>
2010-01-26 06:18:44 +03:00
# include <signal.h>
2010-04-15 08:19:54 +04:00
# include <arpa/inet.h>
2010-01-24 00:56:47 +03:00
2010-01-26 23:39:06 +03:00
# include "unit.h"
2010-01-23 03:52:57 +03:00
# include "socket.h"
2010-01-24 00:56:47 +03:00
# include "log.h"
2010-04-06 04:43:58 +04:00
# include "load-dropin.h"
# include "load-fragment.h"
2010-04-15 05:11:11 +04:00
# include "strv.h"
2010-04-15 08:19:54 +04:00
# include "unit-name.h"
2010-04-18 05:08:16 +04:00
# include "dbus-socket.h"
2010-01-24 00:56:47 +03:00
2010-01-27 06:31:52 +03:00
static const UnitActiveState state_translation_table [ _SOCKET_STATE_MAX ] = {
2010-01-26 23:39:06 +03:00
[ SOCKET_DEAD ] = UNIT_INACTIVE ,
[ SOCKET_START_PRE ] = UNIT_ACTIVATING ,
[ SOCKET_START_POST ] = UNIT_ACTIVATING ,
[ SOCKET_LISTENING ] = UNIT_ACTIVE ,
[ SOCKET_RUNNING ] = UNIT_ACTIVE ,
[ SOCKET_STOP_PRE ] = UNIT_DEACTIVATING ,
[ SOCKET_STOP_PRE_SIGTERM ] = UNIT_DEACTIVATING ,
[ SOCKET_STOP_PRE_SIGKILL ] = UNIT_DEACTIVATING ,
[ SOCKET_STOP_POST ] = UNIT_DEACTIVATING ,
2010-04-13 04:06:27 +04:00
[ SOCKET_FINAL_SIGTERM ] = UNIT_DEACTIVATING ,
[ SOCKET_FINAL_SIGKILL ] = UNIT_DEACTIVATING ,
2010-01-26 23:39:06 +03:00
[ SOCKET_MAINTAINANCE ] = UNIT_INACTIVE ,
2010-01-24 00:56:47 +03:00
} ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
static void socket_init ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
s - > timer_watch . type = WATCH_INVALID ;
s - > backlog = SOMAXCONN ;
s - > timeout_usec = DEFAULT_TIMEOUT_USEC ;
s - > directory_mode = 0755 ;
s - > socket_mode = 0666 ;
exec_context_init ( & s - > exec_context ) ;
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
}
2010-01-27 06:31:52 +03:00
2010-04-11 02:22:36 +04:00
static void socket_unwatch_control_pid ( Socket * s ) {
assert ( s ) ;
if ( s - > control_pid < = 0 )
return ;
unit_unwatch_pid ( UNIT ( s ) , s - > control_pid ) ;
s - > control_pid = 0 ;
}
2010-01-26 23:39:06 +03:00
static void socket_done ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
2010-01-26 06:18:44 +03:00
SocketPort * p ;
assert ( s ) ;
while ( ( p = s - > ports ) ) {
LIST_REMOVE ( SocketPort , port , s - > ports , p ) ;
2010-04-21 05:27:44 +04:00
if ( p - > fd > = 0 ) {
unit_unwatch_fd ( UNIT ( s ) , & p - > fd_watch ) ;
close_nointr_nofail ( p - > fd ) ;
}
2010-01-26 06:18:44 +03:00
free ( p - > path ) ;
free ( p ) ;
}
exec_context_done ( & s - > exec_context ) ;
2010-04-10 19:53:17 +04:00
exec_command_free_array ( s - > exec_command , _SOCKET_EXEC_COMMAND_MAX ) ;
2010-01-26 06:18:44 +03:00
s - > control_command = NULL ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 06:18:44 +03:00
s - > service = NULL ;
2010-01-27 06:31:52 +03:00
free ( s - > bind_to_device ) ;
2010-04-10 19:53:17 +04:00
s - > bind_to_device = NULL ;
2010-01-27 06:31:52 +03:00
unit_unwatch_timer ( u , & s - > timer_watch ) ;
2010-01-23 03:52:57 +03:00
}
2010-04-15 08:19:54 +04:00
static bool have_non_accept_socket ( Socket * s ) {
SocketPort * p ;
assert ( s ) ;
if ( ! s - > accept )
return true ;
2010-04-23 23:56:38 +04:00
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > type ! = SOCKET_SOCKET )
return true ;
2010-04-15 08:19:54 +04:00
if ( ! socket_address_can_accept ( & p - > address ) )
return true ;
2010-04-23 23:56:38 +04:00
}
2010-04-15 08:19:54 +04:00
return false ;
}
static int socket_verify ( Socket * s ) {
assert ( s ) ;
if ( UNIT ( s ) - > meta . load_state ! = UNIT_LOADED )
return 0 ;
if ( ! s - > ports ) {
log_error ( " %s lacks Listen setting. Refusing. " , UNIT ( s ) - > meta . id ) ;
return - EINVAL ;
}
return 0 ;
}
2010-04-10 19:53:17 +04:00
static int socket_load ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
int r ;
2010-01-26 09:02:51 +03:00
2010-04-10 19:53:17 +04:00
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
2010-01-26 09:02:51 +03:00
2010-04-10 19:53:17 +04:00
if ( ( r = unit_load_fragment_and_dropin ( u ) ) < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-01-26 09:02:51 +03:00
2010-04-06 04:43:58 +04:00
/* This is a new unit? Then let's add in some extras */
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state = = UNIT_LOADED ) {
2010-01-26 09:02:51 +03:00
2010-04-15 08:19:54 +04:00
if ( have_non_accept_socket ( s ) ) {
if ( ( r = unit_load_related_unit ( u , " .service " , ( Unit * * ) & s - > service ) ) )
return r ;
2010-04-06 04:43:58 +04:00
2010-04-21 08:01:13 +04:00
if ( ( r = unit_add_dependency ( u , UNIT_BEFORE , UNIT ( s - > service ) , true ) ) < 0 )
2010-04-15 08:19:54 +04:00
return r ;
}
2010-01-26 09:02:51 +03:00
2010-04-06 04:43:58 +04:00
if ( ( r = unit_add_exec_dependencies ( u , & s - > exec_context ) ) < 0 )
return r ;
if ( ( r = unit_add_default_cgroup ( u ) ) < 0 )
return r ;
}
2010-04-15 08:19:54 +04:00
return socket_verify ( s ) ;
2010-01-26 09:02:51 +03:00
}
2010-01-23 05:35:54 +03:00
static const char * listen_lookup ( int type ) {
if ( type = = SOCK_STREAM )
return " ListenStream " ;
else if ( type = = SOCK_DGRAM )
return " ListenDatagram " ;
else if ( type = = SOCK_SEQPACKET )
return " ListenSequentialPacket " ;
2010-01-26 06:18:44 +03:00
assert_not_reached ( " Unknown socket type " ) ;
2010-01-23 05:35:54 +03:00
return NULL ;
}
2010-01-26 23:39:06 +03:00
static void socket_dump ( Unit * u , FILE * f , const char * prefix ) {
2010-01-23 03:52:57 +03:00
SocketExecCommand c ;
2010-01-26 23:39:06 +03:00
Socket * s = SOCKET ( u ) ;
2010-01-23 05:35:54 +03:00
SocketPort * p ;
2010-02-03 16:25:50 +03:00
const char * prefix2 ;
char * p2 ;
2010-01-23 03:52:57 +03:00
assert ( s ) ;
2010-01-27 08:33:27 +03:00
assert ( f ) ;
2010-01-23 03:52:57 +03:00
2010-02-03 16:25:50 +03:00
p2 = strappend ( prefix , " \t " ) ;
prefix2 = p2 ? p2 : prefix ;
2010-01-27 04:16:27 +03:00
2010-01-23 03:52:57 +03:00
fprintf ( f ,
" %sSocket State: %s \n "
2010-01-23 05:35:54 +03:00
" %sBindIPv6Only: %s \n "
2010-02-12 04:02:14 +03:00
" %sBacklog: %u \n "
2010-04-08 02:52:14 +04:00
" %sKillMode: %s \n "
2010-02-12 04:02:14 +03:00
" %sSocketMode: %04o \n "
" %sDirectoryMode: %04o \n " ,
2010-04-21 05:27:44 +04:00
prefix , socket_state_to_string ( s - > state ) ,
2010-01-23 05:35:54 +03:00
prefix , yes_no ( s - > bind_ipv6_only ) ,
2010-02-12 04:02:14 +03:00
prefix , s - > backlog ,
2010-04-08 02:52:14 +04:00
prefix , kill_mode_to_string ( s - > kill_mode ) ,
2010-02-12 04:02:14 +03:00
prefix , s - > socket_mode ,
prefix , s - > directory_mode ) ;
2010-01-23 05:35:54 +03:00
2010-04-08 05:48:27 +04:00
if ( s - > control_pid > 0 )
fprintf ( f ,
" %sControl PID: %llu \n " ,
prefix , ( unsigned long long ) s - > control_pid ) ;
2010-01-27 06:31:52 +03:00
if ( s - > bind_to_device )
fprintf ( f ,
" %sBindToDevice: %s \n " ,
prefix , s - > bind_to_device ) ;
2010-04-15 08:19:54 +04:00
if ( s - > accept )
fprintf ( f ,
" %sAccepted: %u \n " ,
prefix , s - > n_accepted ) ;
2010-01-26 06:18:44 +03:00
LIST_FOREACH ( port , p , s - > ports ) {
2010-01-23 03:52:57 +03:00
2010-01-23 05:35:54 +03:00
if ( p - > type = = SOCKET_SOCKET ) {
const char * t ;
int r ;
char * k ;
if ( ( r = socket_address_print ( & p - > address , & k ) ) < 0 )
t = strerror ( - r ) ;
else
t = k ;
fprintf ( f , " %s%s: %s \n " , prefix , listen_lookup ( p - > address . type ) , k ) ;
free ( k ) ;
} else
fprintf ( f , " %sListenFIFO: %s \n " , prefix , p - > path ) ;
}
2010-01-23 03:52:57 +03:00
exec_context_dump ( & s - > exec_context , f , prefix ) ;
2010-04-10 19:53:17 +04:00
for ( c = 0 ; c < _SOCKET_EXEC_COMMAND_MAX ; c + + ) {
2010-01-27 04:16:27 +03:00
if ( ! s - > exec_command [ c ] )
continue ;
2010-01-23 03:52:57 +03:00
2010-04-23 22:25:55 +04:00
fprintf ( f , " %s-> %s: \n " ,
2010-04-21 05:27:44 +04:00
prefix , socket_exec_command_to_string ( c ) ) ;
2010-01-27 04:16:27 +03:00
exec_command_dump_list ( s - > exec_command [ c ] , f , prefix2 ) ;
2010-01-23 03:52:57 +03:00
}
2010-01-27 04:16:27 +03:00
2010-02-03 16:25:50 +03:00
free ( p2 ) ;
2010-01-23 03:52:57 +03:00
}
2010-04-15 08:19:54 +04:00
static int instance_from_socket ( int fd , unsigned nr , char * * instance ) {
socklen_t l ;
char * r ;
union {
struct sockaddr sa ;
struct sockaddr_un un ;
struct sockaddr_in in ;
struct sockaddr_in6 in6 ;
struct sockaddr_storage storage ;
} local , remote ;
assert ( fd > = 0 ) ;
assert ( instance ) ;
l = sizeof ( local ) ;
if ( getsockname ( fd , & local . sa , & l ) < 0 )
return - errno ;
l = sizeof ( remote ) ;
if ( getpeername ( fd , & remote . sa , & l ) < 0 )
return - errno ;
switch ( local . sa . sa_family ) {
case AF_INET : {
uint32_t
a = ntohl ( local . in . sin_addr . s_addr ) ,
b = ntohl ( remote . in . sin_addr . s_addr ) ;
if ( asprintf ( & r ,
2010-04-21 05:27:44 +04:00
" %u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u " ,
2010-04-15 08:19:54 +04:00
nr ,
a > > 24 , ( a > > 16 ) & 0xFF , ( a > > 8 ) & 0xFF , a & 0xFF ,
ntohs ( local . in . sin_port ) ,
b > > 24 , ( b > > 16 ) & 0xFF , ( b > > 8 ) & 0xFF , b & 0xFF ,
ntohs ( remote . in . sin_port ) ) < 0 )
return - ENOMEM ;
break ;
}
case AF_INET6 : {
char a [ INET6_ADDRSTRLEN ] , b [ INET6_ADDRSTRLEN ] ;
if ( asprintf ( & r ,
2010-04-21 05:27:44 +04:00
" %u-%s:%u-%s:%u " ,
2010-04-15 08:19:54 +04:00
nr ,
inet_ntop ( AF_INET6 , & local . in6 . sin6_addr , a , sizeof ( a ) ) ,
ntohs ( local . in6 . sin6_port ) ,
inet_ntop ( AF_INET6 , & remote . in6 . sin6_addr , b , sizeof ( b ) ) ,
ntohs ( remote . in6 . sin6_port ) ) < 0 )
return - ENOMEM ;
break ;
}
case AF_UNIX : {
struct ucred ucred ;
l = sizeof ( ucred ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & ucred , & l ) < 0 )
return - errno ;
if ( asprintf ( & r ,
" %u-%llu-%llu " ,
nr ,
( unsigned long long ) ucred . pid ,
( unsigned long long ) ucred . uid ) < 0 )
return - ENOMEM ;
break ;
}
default :
assert_not_reached ( " Unhandled socket type. " ) ;
}
* instance = r ;
return 0 ;
}
2010-01-26 06:18:44 +03:00
static void socket_close_fds ( Socket * s ) {
2010-01-24 00:56:47 +03:00
SocketPort * p ;
assert ( s ) ;
2010-01-26 06:18:44 +03:00
LIST_FOREACH ( port , p , s - > ports ) {
2010-01-24 00:56:47 +03:00
if ( p - > fd < 0 )
continue ;
2010-01-27 06:31:52 +03:00
unit_unwatch_fd ( UNIT ( s ) , & p - > fd_watch ) ;
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( p - > fd ) ;
/* One little note: we should never delete any sockets
* in the file system here ! After all some other
* process we spawned might still have a reference of
* this fd and wants to continue to use it . Therefore
* we delete sockets in the file system before we
* create a new one , not after we stopped using
* one ! */
2010-01-24 02:39:29 +03:00
2010-01-24 00:56:47 +03:00
p - > fd = - 1 ;
}
}
2010-01-26 06:18:44 +03:00
static int socket_open_fds ( Socket * s ) {
2010-01-24 00:56:47 +03:00
SocketPort * p ;
int r ;
assert ( s ) ;
2010-01-26 06:18:44 +03:00
LIST_FOREACH ( port , p , s - > ports ) {
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
if ( p - > fd > = 0 )
continue ;
2010-01-24 00:56:47 +03:00
if ( p - > type = = SOCKET_SOCKET ) {
2010-02-12 04:02:14 +03:00
if ( ( r = socket_address_listen (
& p - > address ,
s - > backlog ,
s - > bind_ipv6_only ,
s - > bind_to_device ,
s - > directory_mode ,
s - > socket_mode ,
& p - > fd ) ) < 0 )
2010-01-24 00:56:47 +03:00
goto rollback ;
} else {
struct stat st ;
assert ( p - > type = = SOCKET_FIFO ) ;
2010-04-05 00:50:04 +04:00
mkdir_parents ( p - > path , s - > directory_mode ) ;
if ( mkfifo ( p - > path , s - > socket_mode ) < 0 & & errno ! = EEXIST ) {
2010-01-24 00:56:47 +03:00
r = - errno ;
goto rollback ;
}
if ( ( p - > fd = open ( p - > path , O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW ) ) < 0 ) {
r = - errno ;
goto rollback ;
}
if ( fstat ( p - > fd , & st ) < 0 ) {
r = - errno ;
goto rollback ;
}
/* FIXME verify user, access mode */
if ( ! S_ISFIFO ( st . st_mode ) ) {
r = - EEXIST ;
goto rollback ;
}
}
2010-01-26 06:18:44 +03:00
}
return 0 ;
rollback :
socket_close_fds ( s ) ;
return r ;
}
static void socket_unwatch_fds ( Socket * s ) {
SocketPort * p ;
2010-01-24 02:39:29 +03:00
2010-01-26 06:18:44 +03:00
assert ( s ) ;
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > fd < 0 )
continue ;
2010-01-27 06:31:52 +03:00
unit_unwatch_fd ( UNIT ( s ) , & p - > fd_watch ) ;
2010-01-24 00:56:47 +03:00
}
2010-01-26 06:18:44 +03:00
}
static int socket_watch_fds ( Socket * s ) {
SocketPort * p ;
int r ;
assert ( s ) ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > fd < 0 )
continue ;
2010-04-24 00:11:13 +04:00
p - > fd_watch . socket_accept =
2010-04-15 08:19:54 +04:00
s - > accept & &
2010-04-23 23:56:38 +04:00
p - > type = = SOCKET_SOCKET & &
2010-04-15 08:19:54 +04:00
socket_address_can_accept ( & p - > address ) ;
2010-01-29 08:45:59 +03:00
if ( ( r = unit_watch_fd ( UNIT ( s ) , p - > fd , EPOLLIN , & p - > fd_watch ) ) < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
}
2010-01-24 00:56:47 +03:00
2010-01-23 05:35:54 +03:00
return 0 ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
fail :
socket_unwatch_fds ( s ) ;
return r ;
}
static void socket_set_state ( Socket * s , SocketState state ) {
SocketState old_state ;
assert ( s ) ;
old_state = s - > state ;
s - > state = state ;
if ( state ! = SOCKET_START_PRE & &
state ! = SOCKET_START_POST & &
state ! = SOCKET_STOP_PRE & &
state ! = SOCKET_STOP_PRE_SIGTERM & &
state ! = SOCKET_STOP_PRE_SIGKILL & &
state ! = SOCKET_STOP_POST & &
2010-04-13 04:06:27 +04:00
state ! = SOCKET_FINAL_SIGTERM & &
state ! = SOCKET_FINAL_SIGKILL ) {
2010-01-27 06:31:52 +03:00
unit_unwatch_timer ( UNIT ( s ) , & s - > timer_watch ) ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 06:18:44 +03:00
s - > control_command = NULL ;
2010-04-21 05:27:44 +04:00
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
2010-04-10 19:53:17 +04:00
}
2010-01-26 06:18:44 +03:00
2010-04-21 05:27:44 +04:00
if ( state ! = SOCKET_LISTENING )
socket_unwatch_fds ( s ) ;
2010-01-26 06:18:44 +03:00
if ( state ! = SOCKET_START_POST & &
state ! = SOCKET_LISTENING & &
state ! = SOCKET_RUNNING & &
state ! = SOCKET_STOP_PRE & &
state ! = SOCKET_STOP_PRE_SIGTERM & &
state ! = SOCKET_STOP_PRE_SIGKILL )
socket_close_fds ( s ) ;
2010-04-10 19:53:17 +04:00
if ( state ! = old_state )
2010-04-23 22:25:55 +04:00
log_debug ( " %s changed %s -> %s " ,
2010-04-21 05:27:44 +04:00
s - > meta . id ,
socket_state_to_string ( old_state ) ,
socket_state_to_string ( state ) ) ;
2010-01-27 06:31:52 +03:00
unit_notify ( UNIT ( s ) , state_translation_table [ old_state ] , state_translation_table [ state ] ) ;
2010-01-26 06:18:44 +03:00
}
2010-04-21 05:27:44 +04:00
static int socket_coldplug ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
int r ;
assert ( s ) ;
assert ( s - > state = = SOCKET_DEAD ) ;
if ( s - > deserialized_state ! = s - > state ) {
if ( s - > deserialized_state = = SOCKET_START_PRE | |
s - > deserialized_state = = SOCKET_START_POST | |
s - > deserialized_state = = SOCKET_STOP_PRE | |
s - > deserialized_state = = SOCKET_STOP_PRE_SIGTERM | |
s - > deserialized_state = = SOCKET_STOP_PRE_SIGKILL | |
s - > deserialized_state = = SOCKET_STOP_POST | |
s - > deserialized_state = = SOCKET_FINAL_SIGTERM | |
s - > deserialized_state = = SOCKET_FINAL_SIGKILL ) {
if ( s - > control_pid < = 0 )
return - EBADMSG ;
if ( ( r = unit_watch_pid ( UNIT ( s ) , s - > control_pid ) ) < 0 )
return r ;
if ( ( r = unit_watch_timer ( UNIT ( s ) , s - > timeout_usec , & s - > timer_watch ) ) < 0 )
return r ;
}
if ( s - > deserialized_state = = SOCKET_START_POST | |
s - > deserialized_state = = SOCKET_LISTENING | |
s - > deserialized_state = = SOCKET_RUNNING | |
s - > deserialized_state = = SOCKET_STOP_PRE | |
s - > deserialized_state = = SOCKET_STOP_PRE_SIGTERM | |
s - > deserialized_state = = SOCKET_STOP_PRE_SIGKILL )
if ( ( r = socket_open_fds ( s ) ) < 0 )
return r ;
if ( s - > deserialized_state = = SOCKET_LISTENING )
if ( ( r = socket_watch_fds ( s ) ) < 0 )
return r ;
socket_set_state ( s , s - > deserialized_state ) ;
}
return 0 ;
}
2010-04-10 19:53:17 +04:00
static int socket_spawn ( Socket * s , ExecCommand * c , pid_t * _pid ) {
2010-01-26 06:18:44 +03:00
pid_t pid ;
int r ;
2010-04-15 05:11:11 +04:00
char * * argv ;
2010-01-26 06:18:44 +03:00
assert ( s ) ;
assert ( c ) ;
assert ( _pid ) ;
2010-04-10 19:53:17 +04:00
if ( ( r = unit_watch_timer ( UNIT ( s ) , s - > timeout_usec , & s - > timer_watch ) ) < 0 )
goto fail ;
2010-01-26 06:18:44 +03:00
2010-04-15 05:11:11 +04:00
if ( ! ( argv = unit_full_printf_strv ( UNIT ( s ) , c - > argv ) ) ) {
r = - ENOMEM ;
goto fail ;
}
r = exec_spawn ( c ,
argv ,
& s - > exec_context ,
NULL , 0 ,
true ,
true ,
UNIT ( s ) - > meta . manager - > confirm_spawn ,
UNIT ( s ) - > meta . cgroup_bondings ,
& pid ) ;
strv_free ( argv ) ;
if ( r < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
2010-01-26 23:39:06 +03:00
if ( ( r = unit_watch_pid ( UNIT ( s ) , pid ) ) < 0 )
2010-01-26 06:18:44 +03:00
/* FIXME: we need to do something here */
goto fail ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
* _pid = pid ;
return 0 ;
fail :
2010-04-10 19:53:17 +04:00
unit_unwatch_timer ( UNIT ( s ) , & s - > timer_watch ) ;
2010-01-24 00:56:47 +03:00
return r ;
2010-01-23 05:35:54 +03:00
}
2010-01-26 06:18:44 +03:00
static void socket_enter_dead ( Socket * s , bool success ) {
assert ( s ) ;
if ( ! success )
s - > failure = true ;
socket_set_state ( s , s - > failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD ) ;
}
2010-04-13 04:06:27 +04:00
static void socket_enter_signal ( Socket * s , SocketState state , bool success ) ;
2010-01-26 06:18:44 +03:00
static void socket_enter_stop_post ( Socket * s , bool success ) {
int r ;
assert ( s ) ;
if ( ! success )
s - > failure = true ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 05:27:44 +04:00
s - > control_command_id = SOCKET_EXEC_STOP_POST ;
2010-04-13 04:06:27 +04:00
if ( ( s - > control_command = s - > exec_command [ SOCKET_EXEC_STOP_POST ] ) ) {
2010-04-10 19:53:17 +04:00
if ( ( r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ) < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
2010-04-13 04:06:27 +04:00
socket_set_state ( s , SOCKET_STOP_POST ) ;
} else
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , true ) ;
2010-01-26 06:18:44 +03:00
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to run stop-post executable: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , false ) ;
2010-01-26 06:18:44 +03:00
}
static void socket_enter_signal ( Socket * s , SocketState state , bool success ) {
int r ;
2010-04-13 04:06:27 +04:00
bool sent = false ;
2010-01-26 06:18:44 +03:00
assert ( s ) ;
if ( ! success )
s - > failure = true ;
2010-04-13 04:06:27 +04:00
if ( s - > kill_mode ! = KILL_NONE ) {
int sig = ( state = = SOCKET_STOP_PRE_SIGTERM | | state = = SOCKET_FINAL_SIGTERM ) ? SIGTERM : SIGKILL ;
2010-01-26 06:18:44 +03:00
2010-04-08 02:52:14 +04:00
if ( s - > kill_mode = = KILL_CONTROL_GROUP ) {
if ( ( r = cgroup_bonding_kill_list ( UNIT ( s ) - > meta . cgroup_bondings , sig ) ) < 0 ) {
if ( r ! = - EAGAIN & & r ! = - ESRCH )
goto fail ;
} else
sent = true ;
2010-01-26 06:18:44 +03:00
}
2010-04-08 02:52:14 +04:00
2010-04-13 04:06:27 +04:00
if ( ! sent & & s - > control_pid > 0 )
2010-04-08 02:52:14 +04:00
if ( kill ( s - > kill_mode = = KILL_PROCESS ? s - > control_pid : - s - > control_pid , sig ) < 0 & & errno ! = ESRCH ) {
r = - errno ;
goto fail ;
}
2010-01-28 03:59:41 +03:00
}
2010-01-26 06:18:44 +03:00
2010-04-24 04:05:42 +04:00
if ( sent & & s - > control_pid > 0 ) {
2010-04-13 04:06:27 +04:00
if ( ( r = unit_watch_timer ( UNIT ( s ) , s - > timeout_usec , & s - > timer_watch ) ) < 0 )
goto fail ;
2010-01-28 03:59:41 +03:00
2010-04-13 04:06:27 +04:00
socket_set_state ( s , state ) ;
} else if ( state = = SOCKET_STOP_PRE_SIGTERM | | state = = SOCKET_STOP_PRE_SIGKILL )
socket_enter_stop_post ( s , true ) ;
else
2010-01-26 06:18:44 +03:00
socket_enter_dead ( s , true ) ;
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to kill processes: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-26 06:18:44 +03:00
if ( state = = SOCKET_STOP_PRE_SIGTERM | | state = = SOCKET_STOP_PRE_SIGKILL )
socket_enter_stop_post ( s , false ) ;
else
socket_enter_dead ( s , false ) ;
}
static void socket_enter_stop_pre ( Socket * s , bool success ) {
int r ;
assert ( s ) ;
if ( ! success )
s - > failure = true ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 05:27:44 +04:00
s - > control_command_id = SOCKET_EXEC_STOP_PRE ;
2010-04-13 04:06:27 +04:00
if ( ( s - > control_command = s - > exec_command [ SOCKET_EXEC_STOP_PRE ] ) ) {
2010-04-10 19:53:17 +04:00
if ( ( r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ) < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
2010-04-13 04:06:27 +04:00
socket_set_state ( s , SOCKET_STOP_PRE ) ;
} else
2010-01-26 06:18:44 +03:00
socket_enter_stop_post ( s , true ) ;
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to run stop-pre executable: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-26 06:18:44 +03:00
socket_enter_stop_post ( s , false ) ;
}
2010-01-27 07:33:11 +03:00
static void socket_enter_listening ( Socket * s ) {
int r ;
assert ( s ) ;
if ( ( r = socket_watch_fds ( s ) ) < 0 ) {
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to watch sockets: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-27 07:33:11 +03:00
goto fail ;
}
socket_set_state ( s , SOCKET_LISTENING ) ;
return ;
fail :
socket_enter_stop_pre ( s , false ) ;
}
2010-01-26 06:18:44 +03:00
static void socket_enter_start_post ( Socket * s ) {
int r ;
assert ( s ) ;
2010-01-27 07:33:11 +03:00
if ( ( r = socket_open_fds ( s ) ) < 0 ) {
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to listen on sockets: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-26 06:18:44 +03:00
goto fail ;
}
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 05:27:44 +04:00
s - > control_command_id = SOCKET_EXEC_START_POST ;
2010-04-13 04:06:27 +04:00
if ( ( s - > control_command = s - > exec_command [ SOCKET_EXEC_START_POST ] ) ) {
2010-04-10 19:53:17 +04:00
if ( ( r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ) < 0 ) {
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to run start-post executable: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-26 06:18:44 +03:00
goto fail ;
}
2010-04-13 04:06:27 +04:00
socket_set_state ( s , SOCKET_START_POST ) ;
} else
2010-01-27 07:33:11 +03:00
socket_enter_listening ( s ) ;
2010-01-26 06:18:44 +03:00
return ;
fail :
socket_enter_stop_pre ( s , false ) ;
}
static void socket_enter_start_pre ( Socket * s ) {
int r ;
assert ( s ) ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 05:27:44 +04:00
s - > control_command_id = SOCKET_EXEC_START_PRE ;
2010-04-13 04:06:27 +04:00
if ( ( s - > control_command = s - > exec_command [ SOCKET_EXEC_START_PRE ] ) ) {
2010-04-10 19:53:17 +04:00
if ( ( r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ) < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
2010-04-13 04:06:27 +04:00
socket_set_state ( s , SOCKET_START_PRE ) ;
} else
2010-01-26 06:18:44 +03:00
socket_enter_start_post ( s ) ;
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to run start-pre exectuable: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-01-26 06:18:44 +03:00
socket_enter_dead ( s , false ) ;
}
2010-04-15 08:19:54 +04:00
static void socket_enter_running ( Socket * s , int cfd ) {
2010-01-26 06:18:44 +03:00
int r ;
assert ( s ) ;
2010-04-15 08:19:54 +04:00
if ( cfd < 0 ) {
if ( ( r = manager_add_job ( UNIT ( s ) - > meta . manager , JOB_START , UNIT ( s - > service ) , JOB_REPLACE , true , NULL ) ) < 0 )
goto fail ;
socket_set_state ( s , SOCKET_RUNNING ) ;
} else {
Unit * u ;
char * prefix , * instance , * name ;
if ( ( r = instance_from_socket ( cfd , s - > n_accepted + + , & instance ) ) )
goto fail ;
if ( ! ( prefix = unit_name_to_prefix ( UNIT ( s ) - > meta . id ) ) ) {
free ( instance ) ;
r = - ENOMEM ;
goto fail ;
}
name = unit_name_build ( prefix , instance , " .service " ) ;
free ( prefix ) ;
free ( instance ) ;
if ( ! name )
r = - ENOMEM ;
r = manager_load_unit ( UNIT ( s ) - > meta . manager , name , NULL , & u ) ;
free ( name ) ;
if ( r < 0 )
goto fail ;
if ( ( r = service_set_socket_fd ( SERVICE ( u ) , cfd ) < 0 ) )
goto fail ;
cfd = - 1 ;
if ( ( r = manager_add_job ( u - > meta . manager , JOB_START , u , JOB_REPLACE , true , NULL ) ) < 0 )
goto fail ;
}
2010-01-26 06:18:44 +03:00
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to queue socket startup job: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-04-13 04:06:27 +04:00
socket_enter_stop_pre ( s , false ) ;
2010-04-15 08:19:54 +04:00
if ( cfd > = 0 )
close_nointr_nofail ( cfd ) ;
2010-01-26 06:18:44 +03:00
}
static void socket_run_next ( Socket * s , bool success ) {
int r ;
assert ( s ) ;
assert ( s - > control_command ) ;
assert ( s - > control_command - > command_next ) ;
if ( ! success )
s - > failure = true ;
2010-04-11 02:22:36 +04:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 06:18:44 +03:00
s - > control_command = s - > control_command - > command_next ;
2010-04-10 19:53:17 +04:00
if ( ( r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ) < 0 )
2010-01-26 06:18:44 +03:00
goto fail ;
return ;
fail :
2010-04-15 05:11:11 +04:00
log_warning ( " %s failed to run spawn next executable: %s " , s - > meta . id , strerror ( - r ) ) ;
2010-04-13 04:06:27 +04:00
if ( s - > state = = SOCKET_START_POST )
socket_enter_stop_pre ( s , false ) ;
2010-01-26 06:18:44 +03:00
else if ( s - > state = = SOCKET_STOP_POST )
socket_enter_dead ( s , false ) ;
else
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , false ) ;
2010-01-26 06:18:44 +03:00
}
2010-01-26 23:39:06 +03:00
static int socket_start ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
2010-01-24 00:56:47 +03:00
assert ( s ) ;
2010-01-26 06:18:44 +03:00
/* We cannot fulfill this request right now, try again later
* please ! */
if ( s - > state = = SOCKET_STOP_PRE | |
s - > state = = SOCKET_STOP_PRE_SIGKILL | |
s - > state = = SOCKET_STOP_PRE_SIGTERM | |
s - > state = = SOCKET_STOP_POST | |
2010-04-13 04:06:27 +04:00
s - > state = = SOCKET_FINAL_SIGTERM | |
s - > state = = SOCKET_FINAL_SIGKILL )
2010-01-26 06:18:44 +03:00
return - EAGAIN ;
2010-01-24 00:56:47 +03:00
if ( s - > state = = SOCKET_START_PRE | |
s - > state = = SOCKET_START_POST )
2010-01-26 06:18:44 +03:00
return 0 ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
/* Cannot run this without the service being around */
2010-04-15 08:19:54 +04:00
if ( s - > service ) {
if ( s - > service - > meta . load_state ! = UNIT_LOADED )
return - ENOENT ;
/* If the service is alredy actvie we cannot start the
* socket */
if ( s - > service - > state ! = SERVICE_DEAD & &
s - > service - > state ! = SERVICE_MAINTAINANCE & &
s - > service - > state ! = SERVICE_AUTO_RESTART )
return - EBUSY ;
}
2010-04-10 19:53:17 +04:00
2010-01-26 06:18:44 +03:00
assert ( s - > state = = SOCKET_DEAD | | s - > state = = SOCKET_MAINTAINANCE ) ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
s - > failure = false ;
socket_enter_start_pre ( s ) ;
return 0 ;
}
2010-01-24 00:56:47 +03:00
2010-01-26 23:39:06 +03:00
static int socket_stop ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
2010-01-26 06:18:44 +03:00
assert ( s ) ;
/* We cannot fulfill this request right now, try again later
* please ! */
if ( s - > state = = SOCKET_START_PRE | |
s - > state = = SOCKET_START_POST )
return - EAGAIN ;
2010-01-24 00:56:47 +03:00
2010-04-10 19:53:17 +04:00
/* Already on it */
if ( s - > state = = SOCKET_STOP_PRE | |
s - > state = = SOCKET_STOP_PRE_SIGTERM | |
s - > state = = SOCKET_STOP_PRE_SIGKILL | |
s - > state = = SOCKET_STOP_POST | |
2010-04-13 04:06:27 +04:00
s - > state = = SOCKET_FINAL_SIGTERM | |
s - > state = = SOCKET_FINAL_SIGTERM )
2010-04-10 19:53:17 +04:00
return 0 ;
2010-01-26 06:18:44 +03:00
assert ( s - > state = = SOCKET_LISTENING | | s - > state = = SOCKET_RUNNING ) ;
2010-01-24 00:56:47 +03:00
2010-01-26 06:18:44 +03:00
socket_enter_stop_pre ( s , true ) ;
2010-01-23 05:35:54 +03:00
return 0 ;
}
2010-04-21 05:27:44 +04:00
static int socket_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Socket * s = SOCKET ( u ) ;
SocketPort * p ;
int r ;
assert ( u ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , socket_state_to_string ( s - > state ) ) ;
unit_serialize_item ( u , f , " failure " , yes_no ( s - > failure ) ) ;
unit_serialize_item_format ( u , f , " n-accepted " , " %u " , s - > n_accepted ) ;
if ( s - > control_pid > 0 )
unit_serialize_item_format ( u , f , " control-pid " , " %u " , ( unsigned ) s - > control_pid ) ;
if ( s - > control_command_id > = 0 )
unit_serialize_item ( u , f , " control-command " , socket_exec_command_to_string ( s - > control_command_id ) ) ;
LIST_FOREACH ( port , p , s - > ports ) {
int copy ;
if ( p - > fd < 0 )
continue ;
if ( ( copy = fdset_put_dup ( fds , p - > fd ) ) < 0 )
return copy ;
if ( p - > type = = SOCKET_SOCKET ) {
char * t ;
if ( ( r = socket_address_print ( & p - > address , & t ) ) < 0 )
return r ;
unit_serialize_item_format ( u , f , " socket " , " %i %s " , copy , t ) ;
free ( t ) ;
} else {
assert ( p - > type = = SOCKET_FIFO ) ;
unit_serialize_item_format ( u , f , " fifo " , " %i %s " , copy , p - > path ) ;
}
}
return 0 ;
}
static int socket_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Socket * s = SOCKET ( u ) ;
int r ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
SocketState state ;
if ( ( state = socket_state_from_string ( value ) ) < 0 )
log_debug ( " Failed to parse state value %s " , value ) ;
else
s - > deserialized_state = state ;
} else if ( streq ( key , " failure " ) ) {
int b ;
if ( ( b = parse_boolean ( value ) ) < 0 )
log_debug ( " Failed to parse failure value %s " , value ) ;
else
s - > failure = b | | s - > failure ;
} else if ( streq ( key , " n-accepted " ) ) {
unsigned k ;
if ( ( r = safe_atou ( value , & k ) ) < 0 )
log_debug ( " Failed to parse n-accepted value %s " , value ) ;
else
s - > n_accepted + = k ;
} else if ( streq ( key , " control-pid " ) ) {
unsigned pid ;
if ( ( r = safe_atou ( value , & pid ) ) < 0 | | pid < = 0 )
log_debug ( " Failed to parse control-pid value %s " , value ) ;
else
s - > control_pid = ( pid_t ) pid ;
} else if ( streq ( key , " control-command " ) ) {
SocketExecCommand id ;
if ( ( id = socket_exec_command_from_string ( value ) ) < 0 )
log_debug ( " Failed to parse exec-command value %s " , value ) ;
else {
s - > control_command_id = id ;
s - > control_command = s - > exec_command [ id ] ;
}
} else if ( streq ( key , " fifo " ) ) {
int fd , skip = 0 ;
SocketPort * p ;
if ( sscanf ( value , " %i %n " , & fd , & skip ) < 1 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
log_debug ( " Failed to parse fifo value %s " , value ) ;
else {
LIST_FOREACH ( port , p , s - > ports )
if ( streq ( p - > path , value + skip ) )
break ;
if ( p ) {
if ( p - > fd > = 0 )
close_nointr_nofail ( p - > fd ) ;
p - > fd = fdset_remove ( fds , fd ) ;
}
}
} else if ( streq ( key , " socket " ) ) {
int fd , skip = 0 ;
SocketPort * p ;
if ( sscanf ( value , " %i %n " , & fd , & skip ) < 1 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
log_debug ( " Failed to parse socket value %s " , value ) ;
else {
LIST_FOREACH ( port , p , s - > ports )
if ( socket_address_is ( & p - > address , value + skip ) )
break ;
if ( p ) {
if ( p - > fd > = 0 )
close_nointr_nofail ( p - > fd ) ;
p - > fd = fdset_remove ( fds , fd ) ;
}
}
} else
log_debug ( " Unknown serialization key '%s' " , key ) ;
return 0 ;
}
2010-01-26 23:39:06 +03:00
static UnitActiveState socket_active_state ( Unit * u ) {
assert ( u ) ;
2010-01-23 03:52:57 +03:00
2010-01-27 06:31:52 +03:00
return state_translation_table [ SOCKET ( u ) - > state ] ;
2010-01-23 03:52:57 +03:00
}
2010-04-13 22:59:01 +04:00
static const char * socket_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
2010-04-21 05:27:44 +04:00
return socket_state_to_string ( SOCKET ( u ) - > state ) ;
2010-04-13 22:59:01 +04:00
}
2010-01-27 06:31:52 +03:00
static void socket_fd_event ( Unit * u , int fd , uint32_t events , Watch * w ) {
2010-01-26 23:39:06 +03:00
Socket * s = SOCKET ( u ) ;
2010-04-15 08:19:54 +04:00
int cfd = - 1 ;
2010-01-24 02:39:29 +03:00
2010-01-26 06:18:44 +03:00
assert ( s ) ;
2010-04-17 01:24:39 +04:00
assert ( fd > = 0 ) ;
2010-01-24 02:39:29 +03:00
2010-04-15 05:11:11 +04:00
log_debug ( " Incoming traffic on %s " , u - > meta . id ) ;
2010-01-24 02:39:29 +03:00
2010-04-15 08:19:54 +04:00
if ( events ! = EPOLLIN ) {
log_error ( " Got invalid poll event on socket. " ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
2010-04-15 08:19:54 +04:00
}
2010-04-24 00:11:13 +04:00
if ( w - > socket_accept ) {
2010-04-15 08:19:54 +04:00
for ( ; ; ) {
if ( ( cfd = accept4 ( fd , NULL , NULL , SOCK_NONBLOCK ) ) < 0 ) {
if ( errno = = EINTR )
continue ;
log_error ( " Failed to accept socket: %m " ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
2010-04-15 08:19:54 +04:00
}
break ;
}
}
2010-01-24 02:39:29 +03:00
2010-04-15 08:19:54 +04:00
socket_enter_running ( s , cfd ) ;
2010-04-17 01:24:39 +04:00
return ;
fail :
socket_enter_stop_pre ( s , false ) ;
2010-01-24 02:39:29 +03:00
}
2010-01-26 23:39:06 +03:00
static void socket_sigchld_event ( Unit * u , pid_t pid , int code , int status ) {
Socket * s = SOCKET ( u ) ;
2010-01-26 06:18:44 +03:00
bool success ;
2010-01-23 03:52:57 +03:00
assert ( s ) ;
2010-01-26 06:18:44 +03:00
assert ( pid > = 0 ) ;
2010-01-23 03:52:57 +03:00
2010-01-27 07:32:31 +03:00
success = code = = CLD_EXITED & & status = = 0 ;
2010-01-26 06:18:44 +03:00
s - > failure = s - > failure | | ! success ;
2010-01-23 05:35:54 +03:00
2010-01-26 06:18:44 +03:00
assert ( s - > control_pid = = pid ) ;
s - > control_pid = 0 ;
2010-04-21 05:27:44 +04:00
if ( s - > control_command )
exec_status_fill ( & s - > control_command - > exec_status , pid , code , status ) ;
2010-04-15 05:11:11 +04:00
log_debug ( " %s control process exited, code=%s status=%i " , u - > meta . id , sigchld_code_to_string ( code ) , status ) ;
2010-01-26 06:18:44 +03:00
2010-04-21 05:27:44 +04:00
if ( s - > control_command & & s - > control_command - > command_next & & success ) {
log_debug ( " %s running next command for state %s " , u - > meta . id , socket_state_to_string ( s - > state ) ) ;
2010-01-26 06:18:44 +03:00
socket_run_next ( s , success ) ;
2010-01-27 06:31:52 +03:00
} else {
2010-04-21 05:27:44 +04:00
s - > control_command = NULL ;
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
2010-01-26 06:18:44 +03:00
/* No further commands for this step, so let's figure
* out what to do next */
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
log_debug ( " %s got final SIGCHLD for state %s " , u - > meta . id , socket_state_to_string ( s - > state ) ) ;
2010-01-27 06:31:52 +03:00
2010-01-26 06:18:44 +03:00
switch ( s - > state ) {
case SOCKET_START_PRE :
if ( success )
2010-01-27 06:31:52 +03:00
socket_enter_start_post ( s ) ;
2010-01-26 06:18:44 +03:00
else
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , false ) ;
2010-01-26 06:18:44 +03:00
break ;
case SOCKET_START_POST :
if ( success )
2010-01-27 07:33:11 +03:00
socket_enter_listening ( s ) ;
2010-01-26 06:18:44 +03:00
else
socket_enter_stop_pre ( s , false ) ;
break ;
case SOCKET_STOP_PRE :
case SOCKET_STOP_PRE_SIGTERM :
case SOCKET_STOP_PRE_SIGKILL :
socket_enter_stop_post ( s , success ) ;
break ;
case SOCKET_STOP_POST :
2010-04-13 04:06:27 +04:00
case SOCKET_FINAL_SIGTERM :
case SOCKET_FINAL_SIGKILL :
2010-01-26 06:18:44 +03:00
socket_enter_dead ( s , success ) ;
break ;
default :
assert_not_reached ( " Uh, control process died at wrong time. " ) ;
}
}
}
2010-01-23 03:52:57 +03:00
2010-01-27 06:31:52 +03:00
static void socket_timer_event ( Unit * u , uint64_t elapsed , Watch * w ) {
2010-01-26 23:39:06 +03:00
Socket * s = SOCKET ( u ) ;
2010-01-23 03:52:57 +03:00
2010-01-26 06:18:44 +03:00
assert ( s ) ;
assert ( elapsed = = 1 ) ;
2010-01-27 06:31:52 +03:00
assert ( w = = & s - > timer_watch ) ;
2010-01-26 06:18:44 +03:00
switch ( s - > state ) {
case SOCKET_START_PRE :
2010-04-15 05:11:11 +04:00
log_warning ( " %s starting timed out. Terminating. " , u - > meta . id ) ;
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , false ) ;
2010-01-26 06:18:44 +03:00
case SOCKET_START_POST :
2010-04-15 05:11:11 +04:00
log_warning ( " %s starting timed out. Stopping. " , u - > meta . id ) ;
2010-01-26 06:18:44 +03:00
socket_enter_stop_pre ( s , false ) ;
break ;
case SOCKET_STOP_PRE :
2010-04-15 05:11:11 +04:00
log_warning ( " %s stopping timed out. Terminating. " , u - > meta . id ) ;
2010-01-26 06:18:44 +03:00
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGTERM , false ) ;
break ;
case SOCKET_STOP_PRE_SIGTERM :
2010-04-15 05:11:11 +04:00
log_warning ( " %s stopping timed out. Killing. " , u - > meta . id ) ;
2010-01-26 06:18:44 +03:00
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGKILL , false ) ;
break ;
case SOCKET_STOP_PRE_SIGKILL :
2010-04-15 05:11:11 +04:00
log_warning ( " %s still around after SIGKILL. Ignoring. " , u - > meta . id ) ;
2010-01-26 06:18:44 +03:00
socket_enter_stop_post ( s , false ) ;
break ;
case SOCKET_STOP_POST :
2010-04-15 05:11:11 +04:00
log_warning ( " %s stopping timed out (2). Terminating. " , u - > meta . id ) ;
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , false ) ;
2010-01-26 06:18:44 +03:00
break ;
2010-04-13 04:06:27 +04:00
case SOCKET_FINAL_SIGTERM :
2010-04-15 05:11:11 +04:00
log_warning ( " %s stopping timed out (2). Killing. " , u - > meta . id ) ;
2010-04-13 04:06:27 +04:00
socket_enter_signal ( s , SOCKET_FINAL_SIGKILL , false ) ;
2010-01-26 06:18:44 +03:00
break ;
2010-04-13 04:06:27 +04:00
case SOCKET_FINAL_SIGKILL :
2010-04-15 05:11:11 +04:00
log_warning ( " %s still around after SIGKILL (2). Entering maintainance mode. " , u - > meta . id ) ;
2010-01-26 06:18:44 +03:00
socket_enter_dead ( s , false ) ;
break ;
default :
assert_not_reached ( " Timeout at wrong time. " ) ;
}
2010-01-23 03:52:57 +03:00
}
2010-01-26 09:02:51 +03:00
int socket_collect_fds ( Socket * s , int * * fds , unsigned * n_fds ) {
int * rfds ;
unsigned rn_fds , k ;
SocketPort * p ;
assert ( s ) ;
assert ( fds ) ;
assert ( n_fds ) ;
/* Called from the service code for requesting our fds */
rn_fds = 0 ;
LIST_FOREACH ( port , p , s - > ports )
if ( p - > fd > = 0 )
rn_fds + + ;
if ( ! ( rfds = new ( int , rn_fds ) ) < 0 )
return - ENOMEM ;
k = 0 ;
LIST_FOREACH ( port , p , s - > ports )
if ( p - > fd > = 0 )
rfds [ k + + ] = p - > fd ;
assert ( k = = rn_fds ) ;
* fds = rfds ;
* n_fds = rn_fds ;
return 0 ;
}
2010-01-27 08:19:48 +03:00
void socket_notify_service_dead ( Socket * s ) {
assert ( s ) ;
/* The service is dead. Dang. */
if ( s - > state = = SOCKET_RUNNING ) {
2010-04-15 05:11:11 +04:00
log_debug ( " %s got notified about service death. " , s - > meta . id ) ;
2010-01-27 08:19:48 +03:00
socket_enter_listening ( s ) ;
}
}
2010-04-21 05:27:44 +04:00
static const char * const socket_state_table [ _SOCKET_STATE_MAX ] = {
[ SOCKET_DEAD ] = " dead " ,
[ SOCKET_START_PRE ] = " start-pre " ,
[ SOCKET_START_POST ] = " start-post " ,
[ SOCKET_LISTENING ] = " listening " ,
[ SOCKET_RUNNING ] = " running " ,
[ SOCKET_STOP_PRE ] = " stop-pre " ,
[ SOCKET_STOP_PRE_SIGTERM ] = " stop-pre-sigterm " ,
[ SOCKET_STOP_PRE_SIGKILL ] = " stop-pre-sigkill " ,
[ SOCKET_STOP_POST ] = " stop-post " ,
[ SOCKET_FINAL_SIGTERM ] = " final-sigterm " ,
[ SOCKET_FINAL_SIGKILL ] = " final-sigkill " ,
[ SOCKET_MAINTAINANCE ] = " maintainance "
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_state , SocketState ) ;
static const char * const socket_exec_command_table [ _SOCKET_EXEC_COMMAND_MAX ] = {
[ SOCKET_EXEC_START_PRE ] = " StartPre " ,
[ SOCKET_EXEC_START_POST ] = " StartPost " ,
[ SOCKET_EXEC_STOP_PRE ] = " StopPre " ,
[ SOCKET_EXEC_STOP_POST ] = " StopPost "
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_exec_command , SocketExecCommand ) ;
2010-01-26 23:39:06 +03:00
const UnitVTable socket_vtable = {
2010-01-23 03:52:57 +03:00
. suffix = " .socket " ,
2010-01-26 06:18:44 +03:00
. init = socket_init ,
. done = socket_done ,
2010-04-21 05:27:44 +04:00
. load = socket_load ,
. coldplug = socket_coldplug ,
2010-01-26 06:18:44 +03:00
2010-01-23 03:52:57 +03:00
. dump = socket_dump ,
2010-01-23 05:35:54 +03:00
. start = socket_start ,
. stop = socket_stop ,
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
. serialize = socket_serialize ,
. deserialize_item = socket_deserialize_item ,
2010-01-23 03:52:57 +03:00
. active_state = socket_active_state ,
2010-04-13 22:59:01 +04:00
. sub_state_to_string = socket_sub_state_to_string ,
2010-01-23 03:52:57 +03:00
2010-01-24 02:39:29 +03:00
. fd_event = socket_fd_event ,
2010-01-26 06:18:44 +03:00
. sigchld_event = socket_sigchld_event ,
2010-04-18 05:08:16 +04:00
. timer_event = socket_timer_event ,
. bus_message_handler = bus_socket_message_handler
2010-01-23 03:52:57 +03:00
} ;