2010-08-14 19:59:25 +02:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-23 01:52:57 +01:00
2010-02-03 13:03:47 +01:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 00:20:58 +02:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-02-03 13:03:47 +01:00
( 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
2012-04-12 00:20:58 +02:00
Lesser General Public License for more details .
2010-02-03 13:03:47 +01:00
2012-04-12 00:20:58 +02:00
You should have received a copy of the GNU Lesser General Public License
2010-02-03 13:03:47 +01:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-23 22:56:47 +01:00
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
2010-01-29 06:45:59 +01:00
# include <sys/epoll.h>
2010-01-26 04:18:44 +01:00
# include <signal.h>
2010-04-15 06:19:54 +02:00
# include <arpa/inet.h>
2013-11-19 21:12:59 +01:00
# include <netinet/tcp.h>
2011-05-17 19:37:03 +02:00
# include <mqueue.h>
2014-05-28 11:36:40 +02:00
# include <sys/xattr.h>
2010-01-23 22:56:47 +01:00
2013-11-19 21:12:59 +01:00
# include "sd-event.h"
2010-01-23 22:56:47 +01:00
# include "log.h"
2010-04-06 02:43:58 +02:00
# include "load-dropin.h"
# include "load-fragment.h"
2010-04-15 03:11:11 +02:00
# include "strv.h"
2012-04-10 21:54:31 +02:00
# include "mkdir.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2010-04-15 06:19:54 +02:00
# include "unit-name.h"
2012-09-18 11:27:56 +02:00
# include "unit-printf.h"
2010-07-01 00:29:17 +02:00
# include "missing.h"
2010-07-03 19:48:33 +02:00
# include "special.h"
2010-08-11 22:58:34 +02:00
# include "label.h"
2011-01-20 18:22:03 +01:00
# include "exit-status.h"
2011-03-17 04:02:35 +01:00
# include "def.h"
2013-10-10 21:13:31 +02:00
# include "smack-util.h"
2013-11-19 21:12:59 +01:00
# include "bus-util.h"
# include "bus-error.h"
2013-12-02 23:30:19 +01:00
# include "dbus-socket.h"
# include "unit.h"
# include "socket.h"
2010-01-23 22:56:47 +01:00
2010-01-27 04:31:52 +01:00
static const UnitActiveState state_translation_table [ _SOCKET_STATE_MAX ] = {
2010-01-26 21:39:06 +01:00
[ SOCKET_DEAD ] = UNIT_INACTIVE ,
[ SOCKET_START_PRE ] = UNIT_ACTIVATING ,
2014-06-05 09:55:53 +02:00
[ SOCKET_START_CHOWN ] = UNIT_ACTIVATING ,
2010-01-26 21:39:06 +01:00
[ 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 02:06:27 +02:00
[ SOCKET_FINAL_SIGTERM ] = UNIT_DEACTIVATING ,
[ SOCKET_FINAL_SIGKILL ] = UNIT_DEACTIVATING ,
2010-08-31 00:23:34 +02:00
[ SOCKET_FAILED ] = UNIT_FAILED
2010-01-23 22:56:47 +01:00
} ;
2010-01-23 01:52:57 +01:00
2013-11-19 21:12:59 +01:00
static int socket_dispatch_io ( sd_event_source * source , int fd , uint32_t revents , void * userdata ) ;
static int socket_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) ;
2010-04-21 03:27:44 +02:00
static void socket_init ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
assert ( u ) ;
2012-01-15 12:04:08 +01:00
assert ( u - > load_state = = UNIT_STUB ) ;
2010-04-21 03:27:44 +02:00
s - > backlog = SOMAXCONN ;
2013-11-04 17:47:43 +01:00
s - > timeout_usec = u - > manager - > default_timeout_start_usec ;
2010-04-21 03:27:44 +02:00
s - > directory_mode = 0755 ;
2011-05-17 19:37:23 +02:00
s - > socket_mode = 0666 ;
2010-04-21 03:27:44 +02:00
2010-06-19 04:25:28 +02:00
s - > max_connections = 64 ;
2010-07-01 00:29:17 +02:00
s - > priority = - 1 ;
s - > ip_tos = - 1 ;
s - > ip_ttl = - 1 ;
s - > mark = - 1 ;
2012-01-15 12:04:08 +01:00
s - > exec_context . std_output = u - > manager - > default_std_output ;
s - > exec_context . std_error = u - > manager - > default_std_error ;
2014-02-24 23:50:10 +01:00
2010-04-21 03:27:44 +02:00
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
}
2010-01-27 04:31:52 +01:00
2010-04-11 00:22:36 +02: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 ;
}
2013-01-17 02:27:06 +01:00
void socket_free_ports ( Socket * s ) {
2010-01-26 04:18:44 +01:00
SocketPort * p ;
assert ( s ) ;
while ( ( p = s - > ports ) ) {
2013-10-14 06:10:14 +02:00
LIST_REMOVE ( port , s - > ports , p ) ;
2010-01-26 04:18:44 +01:00
2013-11-19 21:12:59 +01:00
sd_event_source_unref ( p - > event_source ) ;
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2010-01-26 04:18:44 +01:00
free ( p - > path ) ;
free ( p ) ;
}
2013-01-17 02:27:06 +01:00
}
static void socket_done ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
assert ( s ) ;
socket_free_ports ( s ) ;
2010-01-26 04:18:44 +01:00
2013-11-27 20:23:18 +01:00
s - > exec_runtime = exec_runtime_unref ( s - > exec_runtime ) ;
2010-04-10 17:53:17 +02:00
exec_command_free_array ( s - > exec_command , _SOCKET_EXEC_COMMAND_MAX ) ;
2010-01-26 04:18:44 +01:00
s - > control_command = NULL ;
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 04:18:44 +01:00
2012-01-06 23:08:54 +01:00
unit_ref_unset ( & s - > service ) ;
2010-01-26 04:18:44 +01:00
2010-08-03 13:33:40 +02:00
free ( s - > tcp_congestion ) ;
s - > tcp_congestion = NULL ;
2010-01-27 04:31:52 +01:00
free ( s - > bind_to_device ) ;
2010-04-10 17:53:17 +02:00
s - > bind_to_device = NULL ;
2010-01-27 04:31:52 +01:00
2012-10-29 23:30:05 +01:00
free ( s - > smack ) ;
free ( s - > smack_ip_in ) ;
free ( s - > smack_ip_out ) ;
2014-06-04 16:19:00 +02:00
strv_free ( s - > symlinks ) ;
2014-06-05 09:55:53 +02:00
free ( s - > user ) ;
free ( s - > group ) ;
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
}
static int socket_arm_timer ( Socket * s ) {
int r ;
assert ( s ) ;
if ( s - > timeout_usec < = 0 ) {
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
return 0 ;
}
if ( s - > timer_event_source ) {
r = sd_event_source_set_time ( s - > timer_event_source , now ( CLOCK_MONOTONIC ) + s - > timeout_usec ) ;
if ( r < 0 )
return r ;
return sd_event_source_set_enabled ( s - > timer_event_source , SD_EVENT_ONESHOT ) ;
}
2014-03-24 02:49:09 +01:00
return sd_event_add_time (
UNIT ( s ) - > manager - > event ,
& s - > timer_event_source ,
CLOCK_MONOTONIC ,
now ( CLOCK_MONOTONIC ) + s - > timeout_usec , 0 ,
socket_dispatch_timer , s ) ;
2010-01-23 01:52:57 +01:00
}
2014-07-20 23:58:35 +02:00
int socket_instantiate_service ( Socket * s ) {
_cleanup_free_ char * prefix = NULL , * name = NULL ;
2010-07-16 19:42:27 +02:00
int r ;
Unit * u ;
assert ( s ) ;
/* This fills in s->service if it isn't filled in yet. For
* Accept = yes sockets we create the next connection service
* here . For Accept = no this is mostly a NOP since the service
* is figured out at load time anyway . */
2014-07-20 23:58:35 +02:00
if ( UNIT_DEREF ( s - > service ) | | ! s - > accept )
2010-07-16 19:42:27 +02:00
return 0 ;
2014-03-14 14:05:56 +01:00
prefix = unit_name_to_prefix ( UNIT ( s ) - > id ) ;
if ( ! prefix )
2010-07-16 19:42:27 +02:00
return - ENOMEM ;
2014-03-14 14:05:56 +01:00
if ( asprintf ( & name , " %s@%u.service " , prefix , s - > n_accepted ) < 0 )
2010-07-16 19:42:27 +02:00
return - ENOMEM ;
2012-01-15 12:25:20 +01:00
r = manager_load_unit ( UNIT ( s ) - > manager , name , NULL , NULL , & u ) ;
2010-07-16 19:42:27 +02:00
if ( r < 0 )
return r ;
2012-01-15 12:04:08 +01:00
u - > no_gc = true ;
2012-01-06 23:08:54 +01:00
unit_ref_set ( & s - > service , u ) ;
return unit_add_two_dependencies ( UNIT ( s ) , UNIT_BEFORE , UNIT_TRIGGERS , u , false ) ;
2010-07-16 19:42:27 +02:00
}
2010-04-15 06:19:54 +02:00
static bool have_non_accept_socket ( Socket * s ) {
SocketPort * p ;
assert ( s ) ;
if ( ! s - > accept )
return true ;
2010-04-23 21:56:38 +02:00
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > type ! = SOCKET_SOCKET )
return true ;
2010-04-15 06:19:54 +02:00
if ( ! socket_address_can_accept ( & p - > address ) )
return true ;
2010-04-23 21:56:38 +02:00
}
2010-04-15 06:19:54 +02:00
return false ;
}
2013-09-26 20:14:24 +02:00
static int socket_add_mount_links ( Socket * s ) {
2010-05-13 03:07:16 +02:00
SocketPort * p ;
int r ;
assert ( s ) ;
2013-09-26 20:14:24 +02:00
LIST_FOREACH ( port , p , s - > ports ) {
const char * path = NULL ;
2010-05-13 03:07:16 +02:00
2013-09-26 20:14:24 +02:00
if ( p - > type = = SOCKET_SOCKET )
path = socket_address_get_path ( & p - > address ) ;
else if ( p - > type = = SOCKET_FIFO | | p - > type = = SOCKET_SPECIAL )
path = p - > path ;
2010-05-13 03:07:16 +02:00
2013-09-26 20:14:24 +02:00
if ( ! path )
continue ;
2010-05-13 03:07:16 +02:00
2013-09-26 20:14:24 +02:00
r = unit_require_mounts_for ( UNIT ( s ) , path ) ;
2012-10-16 19:50:26 +02:00
if ( r < 0 )
2010-05-13 03:07:16 +02:00
return r ;
2012-10-16 19:50:26 +02:00
}
2010-05-13 03:07:16 +02:00
return 0 ;
}
static int socket_add_device_link ( Socket * s ) {
char * t ;
assert ( s ) ;
2013-01-12 23:05:52 +01:00
if ( ! s - > bind_to_device | | streq ( s - > bind_to_device , " lo " ) )
2010-05-13 03:07:16 +02:00
return 0 ;
2013-12-02 23:30:19 +01:00
t = strappenda ( " /sys/subsystem/net/devices/ " , s - > bind_to_device ) ;
return unit_add_node_link ( UNIT ( s ) , t , false ) ;
2010-05-13 03:07:16 +02:00
}
2010-07-03 19:48:33 +02:00
static int socket_add_default_dependencies ( Socket * s ) {
int r ;
assert ( s ) ;
2013-03-25 21:20:08 +01:00
r = unit_add_dependency_by_name ( UNIT ( s ) , UNIT_BEFORE , SPECIAL_SOCKETS_TARGET , NULL , true ) ;
if ( r < 0 )
return r ;
2010-10-29 06:04:03 +02:00
2013-03-25 21:20:08 +01:00
if ( UNIT ( s ) - > manager - > running_as = = SYSTEMD_SYSTEM ) {
r = unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_AFTER , UNIT_REQUIRES , SPECIAL_SYSINIT_TARGET , NULL , true ) ;
if ( r < 0 )
2010-07-03 19:48:33 +02:00
return r ;
2010-10-29 06:04:03 +02:00
}
2010-07-03 19:48:33 +02:00
2010-10-29 01:15:18 +02:00
return unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_BEFORE , UNIT_CONFLICTS , SPECIAL_SHUTDOWN_TARGET , NULL , true ) ;
2010-07-03 19:48:33 +02:00
}
2013-05-03 04:51:50 +02:00
_pure_ static bool socket_has_exec ( Socket * s ) {
2012-01-03 20:33:28 +01:00
unsigned i ;
assert ( s ) ;
for ( i = 0 ; i < _SOCKET_EXEC_COMMAND_MAX ; i + + )
if ( s - > exec_command [ i ] )
return true ;
return false ;
}
2013-12-02 23:30:19 +01:00
static int socket_add_extras ( Socket * s ) {
Unit * u = UNIT ( s ) ;
2010-04-10 17:53:17 +02:00
int r ;
2010-01-26 07:02:51 +01:00
2013-12-02 23:30:19 +01:00
assert ( s ) ;
2012-01-06 23:08:54 +01:00
2013-12-02 23:30:19 +01:00
if ( have_non_accept_socket ( s ) ) {
2010-04-06 02:43:58 +02:00
2013-12-02 23:30:19 +01:00
if ( ! UNIT_DEREF ( s - > service ) ) {
Unit * x ;
2012-01-06 23:08:54 +01:00
2013-12-02 23:30:19 +01:00
r = unit_load_related_unit ( u , " .service " , & x ) ;
2012-01-06 23:08:54 +01:00
if ( r < 0 )
2010-04-15 06:19:54 +02:00
return r ;
2013-12-02 23:30:19 +01:00
unit_ref_set ( & s - > service , x ) ;
2010-04-15 06:19:54 +02:00
}
2010-01-26 07:02:51 +01:00
2013-12-02 23:30:19 +01:00
r = unit_add_two_dependencies ( u , UNIT_BEFORE , UNIT_TRIGGERS , UNIT_DEREF ( s - > service ) , true ) ;
if ( r < 0 )
2010-05-13 03:07:16 +02:00
return r ;
2013-12-02 23:30:19 +01:00
}
2010-05-13 03:07:16 +02:00
2013-12-02 23:30:19 +01:00
r = socket_add_mount_links ( s ) ;
if ( r < 0 )
return r ;
2010-05-13 03:07:16 +02:00
2013-12-02 23:30:19 +01:00
r = socket_add_device_link ( s ) ;
if ( r < 0 )
return r ;
2014-03-19 20:40:05 +01:00
r = unit_patch_contexts ( u ) ;
2013-12-02 23:30:19 +01:00
if ( r < 0 )
return r ;
if ( socket_has_exec ( s ) ) {
r = unit_add_exec_dependencies ( u , & s - > exec_context ) ;
if ( r < 0 )
return r ;
2010-04-06 02:43:58 +02:00
2014-03-19 20:40:05 +01:00
r = unit_add_default_slice ( u , & s - > cgroup_context ) ;
2013-06-17 21:33:26 +02:00
if ( r < 0 )
return r ;
2013-12-02 23:30:19 +01:00
}
2013-06-17 21:33:26 +02:00
2013-12-02 23:30:19 +01:00
if ( u - > default_dependencies ) {
r = socket_add_default_dependencies ( s ) ;
if ( r < 0 )
return r ;
}
return 0 ;
}
2014-06-04 16:19:00 +02:00
static const char * socket_find_symlink_target ( Socket * s ) {
const char * found = NULL ;
SocketPort * p ;
LIST_FOREACH ( port , p , s - > ports ) {
const char * f = NULL ;
switch ( p - > type ) {
case SOCKET_FIFO :
f = p - > path ;
break ;
case SOCKET_SOCKET :
if ( p - > address . sockaddr . un . sun_path [ 0 ] ! = 0 )
f = p - > address . sockaddr . un . sun_path ;
break ;
default :
break ;
}
if ( f ) {
if ( found )
return NULL ;
found = f ;
}
}
return found ;
}
2013-12-02 23:30:19 +01:00
static int socket_verify ( Socket * s ) {
assert ( s ) ;
if ( UNIT ( s ) - > load_state ! = UNIT_LOADED )
return 0 ;
if ( ! s - > ports ) {
log_error_unit ( UNIT ( s ) - > id , " %s lacks Listen setting. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
}
if ( s - > accept & & have_non_accept_socket ( s ) ) {
log_error_unit ( UNIT ( s ) - > id , " %s configured for accepting sockets, but sockets are non-accepting. Refusing. " ,
UNIT ( s ) - > id ) ;
return - EINVAL ;
}
if ( s - > accept & & s - > max_connections < = 0 ) {
log_error_unit ( UNIT ( s ) - > id , " %s's MaxConnection setting too small. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
}
2012-07-16 12:44:42 +02:00
2013-12-02 23:30:19 +01:00
if ( s - > accept & & UNIT_DEREF ( s - > service ) ) {
log_error_unit ( UNIT ( s ) - > id , " Explicit service configuration for accepting sockets not supported on %s. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
}
if ( s - > exec_context . pam_name & & s - > kill_context . kill_mode ! = KILL_CONTROL_GROUP ) {
log_error_unit ( UNIT ( s ) - > id , " %s has PAM enabled. Kill mode must be set to 'control-group'. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
}
2014-06-04 16:19:00 +02:00
if ( ! strv_isempty ( s - > symlinks ) & & ! socket_find_symlink_target ( s ) ) {
log_error_unit ( UNIT ( s ) - > id , " %s has symlinks set but none or more than one node in the file system. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
}
2013-12-02 23:30:19 +01:00
return 0 ;
}
static int socket_load ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
int r ;
assert ( u ) ;
assert ( u - > load_state = = UNIT_STUB ) ;
r = unit_load_fragment_and_dropin ( u ) ;
if ( r < 0 )
return r ;
if ( u - > load_state = = UNIT_LOADED ) {
/* This is a new unit? Then let's add in some extras */
r = socket_add_extras ( s ) ;
2012-07-16 12:44:42 +02:00
if ( r < 0 )
return r ;
2010-04-06 02:43:58 +02:00
}
2010-04-15 06:19:54 +02:00
return socket_verify ( s ) ;
2010-01-26 07:02:51 +01:00
}
2013-05-03 04:51:50 +02:00
_const_ static const char * listen_lookup ( int family , int type ) {
2011-04-10 03:27:00 +02:00
if ( family = = AF_NETLINK )
return " ListenNetlink " ;
2010-01-23 03:35:54 +01:00
if ( type = = SOCK_STREAM )
return " ListenStream " ;
else if ( type = = SOCK_DGRAM )
return " ListenDatagram " ;
else if ( type = = SOCK_SEQPACKET )
return " ListenSequentialPacket " ;
2010-01-26 04:18:44 +01:00
assert_not_reached ( " Unknown socket type " ) ;
2010-01-23 03:35:54 +01:00
return NULL ;
}
2010-01-26 21:39:06 +01:00
static void socket_dump ( Unit * u , FILE * f , const char * prefix ) {
2014-08-14 19:36:11 +02:00
char time_string [ FORMAT_TIMESPAN_MAX ] ;
2010-01-23 01:52:57 +01:00
SocketExecCommand c ;
2010-01-26 21:39:06 +01:00
Socket * s = SOCKET ( u ) ;
2010-01-23 03:35:54 +01:00
SocketPort * p ;
2010-02-03 14:25:50 +01:00
const char * prefix2 ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2010-01-27 06:33:27 +01:00
assert ( f ) ;
2010-01-23 01:52:57 +01:00
2014-08-21 16:15:49 +02:00
prefix = strempty ( prefix ) ;
2013-12-02 23:30:19 +01:00
prefix2 = strappenda ( prefix , " \t " ) ;
2010-01-27 02:16:27 +01:00
2010-01-23 01:52:57 +01:00
fprintf ( f ,
" %sSocket State: %s \n "
2012-02-03 03:27:25 +01:00
" %sResult: %s \n "
2010-01-23 03:35:54 +01:00
" %sBindIPv6Only: %s \n "
2010-02-12 02:02:14 +01:00
" %sBacklog: %u \n "
" %sSocketMode: %04o \n "
2010-07-01 00:29:17 +02:00
" %sDirectoryMode: %04o \n "
" %sKeepAlive: %s \n "
2014-07-28 08:48:29 +02:00
" %sNoDelay: %s \n "
2010-08-03 13:33:40 +02:00
" %sFreeBind: %s \n "
2011-05-19 13:22:31 +02:00
" %sTransparent: %s \n "
2011-05-19 18:10:19 +02:00
" %sBroadcast: %s \n "
2012-01-31 23:58:15 +01:00
" %sPassCredentials: %s \n "
2012-03-13 00:00:27 +01:00
" %sPassSecurity: %s \n "
2014-06-04 13:10:43 +02:00
" %sTCPCongestion: %s \n "
2014-07-24 10:40:28 +02:00
" %sRemoveOnStop: %s \n "
" %sSELinuxContextFromNet: %s \n " ,
2010-04-21 03:27:44 +02:00
prefix , socket_state_to_string ( s - > state ) ,
2012-02-03 03:27:25 +01:00
prefix , socket_result_to_string ( s - > result ) ,
2010-05-21 23:41:25 +02:00
prefix , socket_address_bind_ipv6_only_to_string ( s - > bind_ipv6_only ) ,
2010-02-12 02:02:14 +01:00
prefix , s - > backlog ,
prefix , s - > socket_mode ,
2010-07-01 00:29:17 +02:00
prefix , s - > directory_mode ,
prefix , yes_no ( s - > keep_alive ) ,
2014-07-28 08:48:29 +02:00
prefix , yes_no ( s - > no_delay ) ,
2010-08-03 13:33:40 +02:00
prefix , yes_no ( s - > free_bind ) ,
2011-05-19 13:22:31 +02:00
prefix , yes_no ( s - > transparent ) ,
2011-05-19 18:10:19 +02:00
prefix , yes_no ( s - > broadcast ) ,
2011-11-29 22:15:41 +01:00
prefix , yes_no ( s - > pass_cred ) ,
2012-03-13 00:00:27 +01:00
prefix , yes_no ( s - > pass_sec ) ,
2014-06-04 13:10:43 +02:00
prefix , strna ( s - > tcp_congestion ) ,
2014-07-24 10:40:28 +02:00
prefix , yes_no ( s - > remove_on_stop ) ,
prefix , yes_no ( s - > selinux_context_from_net ) ) ;
2010-01-23 03:35:54 +01:00
2010-04-08 03:48:27 +02:00
if ( s - > control_pid > 0 )
fprintf ( f ,
2014-04-25 13:45:15 +02:00
" %sControl PID: " PID_FMT " \n " ,
prefix , s - > control_pid ) ;
2010-04-08 03:48:27 +02:00
2010-01-27 04:31:52 +01:00
if ( s - > bind_to_device )
fprintf ( f ,
" %sBindToDevice: %s \n " ,
prefix , s - > bind_to_device ) ;
2010-04-15 06:19:54 +02:00
if ( s - > accept )
fprintf ( f ,
2010-06-19 04:25:28 +02:00
" %sAccepted: %u \n "
" %sNConnections: %u \n "
" %sMaxConnections: %u \n " ,
prefix , s - > n_accepted ,
prefix , s - > n_connections ,
prefix , s - > max_connections ) ;
2010-04-15 06:19:54 +02:00
2010-07-01 00:29:17 +02:00
if ( s - > priority > = 0 )
fprintf ( f ,
" %sPriority: %i \n " ,
prefix , s - > priority ) ;
if ( s - > receive_buffer > 0 )
fprintf ( f ,
" %sReceiveBuffer: %zu \n " ,
prefix , s - > receive_buffer ) ;
if ( s - > send_buffer > 0 )
fprintf ( f ,
" %sSendBuffer: %zu \n " ,
prefix , s - > send_buffer ) ;
if ( s - > ip_tos > = 0 )
fprintf ( f ,
" %sIPTOS: %i \n " ,
prefix , s - > ip_tos ) ;
if ( s - > ip_ttl > = 0 )
fprintf ( f ,
" %sIPTTL: %i \n " ,
prefix , s - > ip_ttl ) ;
if ( s - > pipe_size > 0 )
fprintf ( f ,
" %sPipeSize: %zu \n " ,
prefix , s - > pipe_size ) ;
if ( s - > mark > = 0 )
fprintf ( f ,
" %sMark: %i \n " ,
prefix , s - > mark ) ;
2011-05-17 19:37:03 +02:00
if ( s - > mq_maxmsg > 0 )
fprintf ( f ,
" %sMessageQueueMaxMessages: %li \n " ,
prefix , s - > mq_maxmsg ) ;
if ( s - > mq_msgsize > 0 )
fprintf ( f ,
" %sMessageQueueMessageSize: %li \n " ,
prefix , s - > mq_msgsize ) ;
2013-11-19 21:12:59 +01:00
if ( s - > reuse_port )
2013-07-08 20:28:14 +02:00
fprintf ( f ,
" %sReusePort: %s \n " ,
2013-11-19 21:12:59 +01:00
prefix , yes_no ( s - > reuse_port ) ) ;
2013-07-08 20:28:14 +02:00
2012-10-29 23:30:05 +01:00
if ( s - > smack )
fprintf ( f ,
" %sSmackLabel: %s \n " ,
prefix , s - > smack ) ;
if ( s - > smack_ip_in )
fprintf ( f ,
" %sSmackLabelIPIn: %s \n " ,
prefix , s - > smack_ip_in ) ;
if ( s - > smack_ip_out )
fprintf ( f ,
" %sSmackLabelIPOut: %s \n " ,
prefix , s - > smack_ip_out ) ;
2014-06-05 09:55:53 +02:00
if ( ! isempty ( s - > user ) | | ! isempty ( s - > group ) )
fprintf ( f ,
" %sOwnerUser: %s \n "
" %sOwnerGroup: %s \n " ,
prefix , strna ( s - > user ) ,
prefix , strna ( s - > group ) ) ;
2014-08-19 21:57:37 +02:00
if ( s - > keep_alive_time > 0 )
2014-08-14 19:36:11 +02:00
fprintf ( f ,
2014-08-19 21:57:37 +02:00
" %sKeepAliveTimeSec: %s \n " ,
prefix , format_timespan ( time_string , FORMAT_TIMESPAN_MAX , s - > keep_alive_time , USEC_PER_SEC ) ) ;
2014-08-14 19:36:11 +02:00
2014-08-19 21:57:37 +02:00
if ( s - > keep_alive_interval )
2014-08-14 19:36:11 +02:00
fprintf ( f ,
2014-08-19 21:57:37 +02:00
" %sKeepAliveIntervalSec: %s \n " ,
prefix , format_timespan ( time_string , FORMAT_TIMESPAN_MAX , s - > keep_alive_interval , USEC_PER_SEC ) ) ;
2014-08-14 19:36:11 +02:00
2014-08-19 21:57:37 +02:00
if ( s - > keep_alive_cnt )
2014-08-14 19:36:11 +02:00
fprintf ( f ,
" %sKeepAliveProbes: %u \n " ,
prefix , s - > keep_alive_cnt ) ;
2014-08-19 21:57:37 +02:00
if ( s - > defer_accept )
2014-08-14 19:36:12 +02:00
fprintf ( f ,
2014-08-19 21:57:37 +02:00
" %sDeferAcceptSec: %s \n " ,
prefix , format_timespan ( time_string , FORMAT_TIMESPAN_MAX , s - > defer_accept , USEC_PER_SEC ) ) ;
2014-08-14 19:36:12 +02:00
2010-01-26 04:18:44 +01:00
LIST_FOREACH ( port , p , s - > ports ) {
2010-01-23 01:52:57 +01:00
2010-01-23 03:35:54 +01:00
if ( p - > type = = SOCKET_SOCKET ) {
const char * t ;
int r ;
2010-08-11 22:04:22 +02:00
char * k = NULL ;
2010-01-23 03:35:54 +01:00
if ( ( r = socket_address_print ( & p - > address , & k ) ) < 0 )
t = strerror ( - r ) ;
else
t = k ;
2011-04-10 03:27:00 +02:00
fprintf ( f , " %s%s: %s \n " , prefix , listen_lookup ( socket_address_family ( & p - > address ) , p - > address . type ) , t ) ;
2010-01-23 03:35:54 +01:00
free ( k ) ;
2011-04-20 05:02:23 +02:00
} else if ( p - > type = = SOCKET_SPECIAL )
fprintf ( f , " %sListenSpecial: %s \n " , prefix , p - > path ) ;
2011-05-17 19:37:03 +02:00
else if ( p - > type = = SOCKET_MQUEUE )
fprintf ( f , " %sListenMessageQueue: %s \n " , prefix , p - > path ) ;
2011-04-20 05:02:23 +02:00
else
2010-01-23 03:35:54 +01:00
fprintf ( f , " %sListenFIFO: %s \n " , prefix , p - > path ) ;
}
2010-01-23 01:52:57 +01:00
exec_context_dump ( & s - > exec_context , f , prefix ) ;
2012-07-19 23:47:10 +02:00
kill_context_dump ( & s - > kill_context , f , prefix ) ;
2010-01-23 01:52:57 +01:00
2010-04-10 17:53:17 +02:00
for ( c = 0 ; c < _SOCKET_EXEC_COMMAND_MAX ; c + + ) {
2010-01-27 02:16:27 +01:00
if ( ! s - > exec_command [ c ] )
continue ;
2010-01-23 01:52:57 +01:00
2010-04-23 20:25:55 +02:00
fprintf ( f , " %s-> %s: \n " ,
2010-04-21 03:27:44 +02:00
prefix , socket_exec_command_to_string ( c ) ) ;
2010-01-27 02:16:27 +01:00
exec_command_dump_list ( s - > exec_command [ c ] , f , prefix2 ) ;
2010-01-23 01:52:57 +01:00
}
}
2010-04-15 06:19:54 +02:00
static int instance_from_socket ( int fd , unsigned nr , char * * instance ) {
socklen_t l ;
char * r ;
2014-03-12 20:09:25 +01:00
union sockaddr_union local , remote ;
2010-04-15 06:19:54 +02:00
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 ,
2012-03-14 03:07:26 +01:00
" %u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u " ,
nr ,
2010-04-15 06:19:54 +02:00
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 : {
2012-09-15 18:58:48 +02:00
static const unsigned char ipv4_prefix [ ] = {
2010-05-20 20:46:06 +02:00
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xFF , 0xFF
} ;
if ( memcmp ( & local . in6 . sin6_addr , ipv4_prefix , sizeof ( ipv4_prefix ) ) = = 0 & &
memcmp ( & remote . in6 . sin6_addr , ipv4_prefix , sizeof ( ipv4_prefix ) ) = = 0 ) {
const uint8_t
* a = local . in6 . sin6_addr . s6_addr + 12 ,
* b = remote . in6 . sin6_addr . s6_addr + 12 ;
if ( asprintf ( & r ,
2012-03-14 03:07:26 +01:00
" %u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u " ,
nr ,
2010-05-20 20:46:06 +02:00
a [ 0 ] , a [ 1 ] , a [ 2 ] , a [ 3 ] ,
ntohs ( local . in6 . sin6_port ) ,
b [ 0 ] , b [ 1 ] , b [ 2 ] , b [ 3 ] ,
ntohs ( remote . in6 . sin6_port ) ) < 0 )
return - ENOMEM ;
} else {
char a [ INET6_ADDRSTRLEN ] , b [ INET6_ADDRSTRLEN ] ;
if ( asprintf ( & r ,
2012-03-14 03:07:26 +01:00
" %u-%s:%u-%s:%u " ,
nr ,
2010-05-20 20:46:06 +02:00
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 ;
}
2010-04-15 06:19:54 +02:00
break ;
}
case AF_UNIX : {
struct ucred ucred ;
2013-12-24 15:53:04 +01:00
int k ;
2010-04-15 06:19:54 +02:00
2013-12-24 15:53:04 +01:00
k = getpeercred ( fd , & ucred ) ;
2014-04-20 03:58:03 +02:00
if ( k > = 0 ) {
if ( asprintf ( & r ,
" %u- " PID_FMT " - " UID_FMT ,
nr , ucred . pid , ucred . uid ) < 0 )
return - ENOMEM ;
} else if ( k = = - ENODATA ) {
/* This handles the case where somebody is
* connecting from another pid / uid namespace
* ( e . g . from outside of our container ) . */
if ( asprintf ( & r ,
" %u-unknown " ,
nr ) < 0 )
return - ENOMEM ;
} else
2013-12-24 15:53:04 +01:00
return k ;
2014-04-19 13:53:11 +02:00
break ;
2010-04-15 06:19:54 +02:00
}
default :
assert_not_reached ( " Unhandled socket type. " ) ;
}
* instance = r ;
return 0 ;
}
2010-01-26 04:18:44 +01:00
static void socket_close_fds ( Socket * s ) {
2010-01-23 22:56:47 +01:00
SocketPort * p ;
2014-06-04 16:19:00 +02:00
char * * i ;
2010-01-23 22:56:47 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
LIST_FOREACH ( port , p , s - > ports ) {
2013-11-19 21:12:59 +01:00
p - > event_source = sd_event_source_unref ( p - > event_source ) ;
2010-01-23 22:56:47 +01:00
if ( p - > fd < 0 )
continue ;
2014-03-18 19:22:43 +01:00
p - > fd = safe_close ( p - > fd ) ;
2010-04-21 03:27:44 +02:00
2014-06-04 13:10:43 +02:00
/* One little note: we should normally not 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 ! */
if ( s - > remove_on_stop ) {
switch ( p - > type ) {
case SOCKET_FIFO :
unlink ( p - > path ) ;
break ;
case SOCKET_MQUEUE :
mq_unlink ( p - > path ) ;
break ;
case SOCKET_SOCKET :
socket_address_unlink ( & p - > address ) ;
break ;
default :
break ;
}
}
2010-01-23 22:56:47 +01:00
}
2014-06-04 16:19:00 +02:00
if ( s - > remove_on_stop )
STRV_FOREACH ( i , s - > symlinks )
unlink ( * i ) ;
2010-01-23 22:56:47 +01:00
}
2010-07-01 00:29:17 +02:00
static void socket_apply_socket_options ( Socket * s , int fd ) {
2014-10-23 18:06:51 +02:00
int r ;
2010-07-01 00:29:17 +02:00
assert ( s ) ;
assert ( fd > = 0 ) ;
if ( s - > keep_alive ) {
int b = s - > keep_alive ;
if ( setsockopt ( fd , SOL_SOCKET , SO_KEEPALIVE , & b , sizeof ( b ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_KEEPALIVE failed: %m " ) ;
2010-07-01 00:29:17 +02:00
}
2014-08-14 19:36:11 +02:00
if ( s - > keep_alive_time ) {
int value = s - > keep_alive_time / USEC_PER_SEC ;
if ( setsockopt ( fd , SOL_TCP , TCP_KEEPIDLE , & value , sizeof ( value ) ) < 0 )
log_warning_unit ( UNIT ( s ) - > id , " TCP_KEEPIDLE failed: %m " ) ;
}
if ( s - > keep_alive_interval ) {
int value = s - > keep_alive_interval / USEC_PER_SEC ;
if ( setsockopt ( fd , SOL_TCP , TCP_KEEPINTVL , & value , sizeof ( value ) ) < 0 )
log_warning_unit ( UNIT ( s ) - > id , " TCP_KEEPINTVL failed: %m " ) ;
}
if ( s - > keep_alive_cnt ) {
int value = s - > keep_alive_cnt ;
if ( setsockopt ( fd , SOL_SOCKET , TCP_KEEPCNT , & value , sizeof ( value ) ) < 0 )
log_warning_unit ( UNIT ( s ) - > id , " TCP_KEEPCNT failed: %m " ) ;
}
2014-08-14 19:36:12 +02:00
if ( s - > defer_accept ) {
int value = s - > defer_accept / USEC_PER_SEC ;
if ( setsockopt ( fd , SOL_TCP , TCP_DEFER_ACCEPT , & value , sizeof ( value ) ) < 0 )
log_warning_unit ( UNIT ( s ) - > id , " TCP_DEFER_ACCEPT failed: %m " ) ;
}
2014-07-28 08:48:29 +02:00
if ( s - > no_delay ) {
int b = s - > no_delay ;
if ( setsockopt ( fd , SOL_TCP , TCP_NODELAY , & b , sizeof ( b ) ) < 0 )
log_warning_unit ( UNIT ( s ) - > id , " TCP_NODELAY failed: %m " ) ;
}
2011-05-19 18:10:19 +02:00
if ( s - > broadcast ) {
int one = 1 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_BROADCAST , & one , sizeof ( one ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_BROADCAST failed: %m " ) ;
2011-05-19 18:10:19 +02:00
}
2011-11-29 22:15:41 +01:00
if ( s - > pass_cred ) {
int one = 1 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_PASSCRED , & one , sizeof ( one ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_PASSCRED failed: %m " ) ;
2011-11-29 22:15:41 +01:00
}
2012-03-13 00:00:27 +01:00
if ( s - > pass_sec ) {
int one = 1 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_PASSSEC , & one , sizeof ( one ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_PASSSEC failed: %m " ) ;
2012-03-13 00:00:27 +01:00
}
2010-07-01 00:29:17 +02:00
if ( s - > priority > = 0 )
if ( setsockopt ( fd , SOL_SOCKET , SO_PRIORITY , & s - > priority , sizeof ( s - > priority ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_PRIORITY failed: %m " ) ;
2010-07-01 00:29:17 +02:00
if ( s - > receive_buffer > 0 ) {
int value = ( int ) s - > receive_buffer ;
2012-01-27 18:58:02 +01:00
/* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
2011-05-20 18:41:44 +02:00
if ( setsockopt ( fd , SOL_SOCKET , SO_RCVBUFFORCE , & value , sizeof ( value ) ) < 0 )
2012-01-27 18:58:02 +01:00
if ( setsockopt ( fd , SOL_SOCKET , SO_RCVBUF , & value , sizeof ( value ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_RCVBUF failed: %m " ) ;
2010-07-01 00:29:17 +02:00
}
if ( s - > send_buffer > 0 ) {
int value = ( int ) s - > send_buffer ;
2011-05-20 18:41:44 +02:00
if ( setsockopt ( fd , SOL_SOCKET , SO_SNDBUFFORCE , & value , sizeof ( value ) ) < 0 )
2012-01-27 18:58:02 +01:00
if ( setsockopt ( fd , SOL_SOCKET , SO_SNDBUF , & value , sizeof ( value ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_SNDBUF failed: %m " ) ;
2010-07-01 00:29:17 +02:00
}
if ( s - > mark > = 0 )
if ( setsockopt ( fd , SOL_SOCKET , SO_MARK , & s - > mark , sizeof ( s - > mark ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " SO_MARK failed: %m " ) ;
2010-07-01 00:29:17 +02:00
if ( s - > ip_tos > = 0 )
if ( setsockopt ( fd , IPPROTO_IP , IP_TOS , & s - > ip_tos , sizeof ( s - > ip_tos ) ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " IP_TOS failed: %m " ) ;
2010-07-01 00:29:17 +02:00
2010-07-01 15:27:30 +02:00
if ( s - > ip_ttl > = 0 ) {
2014-10-23 18:06:51 +02:00
int x ;
2010-07-01 15:27:30 +02:00
r = setsockopt ( fd , IPPROTO_IP , IP_TTL , & s - > ip_ttl , sizeof ( s - > ip_ttl ) ) ;
2010-09-20 21:33:14 +02:00
if ( socket_ipv6_is_supported ( ) )
x = setsockopt ( fd , IPPROTO_IPV6 , IPV6_UNICAST_HOPS , & s - > ip_ttl , sizeof ( s - > ip_ttl ) ) ;
else {
x = - 1 ;
errno = EAFNOSUPPORT ;
}
2010-07-01 15:27:30 +02:00
if ( r < 0 & & x < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" IP_TTL/IPV6_UNICAST_HOPS failed: %m " ) ;
2010-07-01 15:27:30 +02:00
}
2010-08-03 13:33:40 +02:00
if ( s - > tcp_congestion )
if ( setsockopt ( fd , SOL_TCP , TCP_CONGESTION , s - > tcp_congestion , strlen ( s - > tcp_congestion ) + 1 ) < 0 )
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id , " TCP_CONGESTION failed: %m " ) ;
2012-10-29 23:30:05 +01:00
2013-11-19 21:12:59 +01:00
if ( s - > reuse_port ) {
int b = s - > reuse_port ;
2013-11-16 22:18:13 +01:00
if ( setsockopt ( fd , SOL_SOCKET , SO_REUSEPORT , & b , sizeof ( b ) ) < 0 )
2013-07-08 20:28:14 +02:00
log_warning_unit ( UNIT ( s ) - > id , " SO_REUSEPORT failed: %m " ) ;
}
2014-10-23 18:06:51 +02:00
if ( s - > smack_ip_in ) {
r = mac_smack_apply_ip_in_fd ( fd , s - > smack_ip_in ) ;
if ( r < 0 )
log_error_unit ( UNIT ( s ) - > id , " mac_smack_apply_ip_in_fd: %s " , strerror ( - r ) ) ;
}
2013-10-11 09:47:31 +02:00
2014-10-23 18:06:51 +02:00
if ( s - > smack_ip_out ) {
r = mac_smack_apply_ip_out_fd ( fd , s - > smack_ip_out ) ;
if ( r < 0 )
log_error_unit ( UNIT ( s ) - > id , " mac_smack_apply_ip_out_fd: %s " , strerror ( - r ) ) ;
}
2010-07-01 00:29:17 +02:00
}
2010-07-16 19:42:27 +02:00
static void socket_apply_fifo_options ( Socket * s , int fd ) {
2014-10-23 18:06:51 +02:00
int r ;
2010-07-01 00:29:17 +02:00
assert ( s ) ;
assert ( fd > = 0 ) ;
if ( s - > pipe_size > 0 )
if ( fcntl ( fd , F_SETPIPE_SZ , s - > pipe_size ) < 0 )
2014-10-23 18:06:51 +02:00
log_warning_unit ( UNIT ( s ) - > id , " F_SETPIPE_SZ: %m " ) ;
2012-10-29 23:30:05 +01:00
2014-10-23 18:06:51 +02:00
if ( s - > smack ) {
r = mac_smack_apply_fd ( fd , s - > smack ) ;
if ( r < 0 )
log_error_unit ( UNIT ( s ) - > id , " mac_smack_apply_fd: %s " , strerror ( - r ) ) ;
}
2010-07-01 00:29:17 +02:00
}
2010-07-16 19:42:27 +02:00
static int fifo_address_create (
const char * path ,
mode_t directory_mode ,
mode_t socket_mode ,
int * _fd ) {
2010-07-22 23:01:25 +02:00
int fd = - 1 , r = 0 ;
2010-07-16 19:42:27 +02:00
struct stat st ;
mode_t old_mask ;
assert ( path ) ;
assert ( _fd ) ;
2012-05-31 12:40:20 +02:00
mkdir_parents_label ( path , directory_mode ) ;
2010-07-16 19:42:27 +02:00
2014-10-23 10:23:46 +02:00
r = mac_selinux_context_set ( path , S_IFIFO ) ;
2012-04-17 16:05:03 +02:00
if ( r < 0 )
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 15:39:54 +02:00
goto fail ;
2010-07-16 19:42:27 +02:00
/* Enforce the right access mode for the fifo */
old_mask = umask ( ~ socket_mode ) ;
/* Include the original umask in our mask */
umask ( ~ socket_mode | old_mask ) ;
r = mkfifo ( path , socket_mode ) ;
umask ( old_mask ) ;
2011-04-16 03:42:37 +02:00
if ( r < 0 & & errno ! = EEXIST ) {
2010-07-16 19:42:27 +02:00
r = - errno ;
goto fail ;
}
2012-11-06 15:54:17 +01:00
if ( ( fd = open ( path , O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW ) ) < 0 ) {
2010-07-16 19:42:27 +02:00
r = - errno ;
goto fail ;
}
2014-10-23 10:23:46 +02:00
mac_selinux_context_clear ( ) ;
2010-07-22 23:01:25 +02:00
2010-07-16 19:42:27 +02:00
if ( fstat ( fd , & st ) < 0 ) {
r = - errno ;
goto fail ;
}
if ( ! S_ISFIFO ( st . st_mode ) | |
2010-07-20 20:40:49 +02:00
( st . st_mode & 0777 ) ! = ( socket_mode & ~ old_mask ) | |
2012-11-06 15:54:17 +01:00
st . st_uid ! = getuid ( ) | |
st . st_gid ! = getgid ( ) ) {
2010-07-16 19:42:27 +02:00
r = - EEXIST ;
goto fail ;
}
* _fd = fd ;
return 0 ;
fail :
2014-10-23 10:23:46 +02:00
mac_selinux_context_clear ( ) ;
2014-03-18 19:22:43 +01:00
safe_close ( fd ) ;
2010-07-16 19:42:27 +02:00
return r ;
}
2011-04-20 05:02:23 +02:00
static int special_address_create (
const char * path ,
int * _fd ) {
int fd = - 1 , r = 0 ;
struct stat st ;
assert ( path ) ;
assert ( _fd ) ;
2014-06-04 16:19:00 +02:00
fd = open ( path , O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW ) ;
if ( fd < 0 ) {
2011-04-20 05:02:23 +02:00
r = - errno ;
goto fail ;
}
if ( fstat ( fd , & st ) < 0 ) {
r = - errno ;
goto fail ;
}
/* Check whether this is a /proc, /sys or /dev file or char device */
if ( ! S_ISREG ( st . st_mode ) & & ! S_ISCHR ( st . st_mode ) ) {
r = - EEXIST ;
goto fail ;
}
* _fd = fd ;
return 0 ;
fail :
2014-03-18 19:22:43 +01:00
safe_close ( fd ) ;
2011-04-20 05:02:23 +02:00
return r ;
}
2011-05-17 19:37:03 +02:00
static int mq_address_create (
const char * path ,
mode_t mq_mode ,
long maxmsg ,
long msgsize ,
int * _fd ) {
int fd = - 1 , r = 0 ;
struct stat st ;
mode_t old_mask ;
struct mq_attr _attr , * attr = NULL ;
assert ( path ) ;
assert ( _fd ) ;
if ( maxmsg > 0 & & msgsize > 0 ) {
zero ( _attr ) ;
_attr . mq_flags = O_NONBLOCK ;
_attr . mq_maxmsg = maxmsg ;
_attr . mq_msgsize = msgsize ;
attr = & _attr ;
}
/* Enforce the right access mode for the mq */
old_mask = umask ( ~ mq_mode ) ;
/* Include the original umask in our mask */
umask ( ~ mq_mode | old_mask ) ;
fd = mq_open ( path , O_RDONLY | O_CLOEXEC | O_NONBLOCK | O_CREAT , mq_mode , attr ) ;
umask ( old_mask ) ;
2011-09-23 01:43:28 +02:00
if ( fd < 0 ) {
2011-05-17 19:37:03 +02:00
r = - errno ;
goto fail ;
}
if ( fstat ( fd , & st ) < 0 ) {
r = - errno ;
goto fail ;
}
if ( ( st . st_mode & 0777 ) ! = ( mq_mode & ~ old_mask ) | |
st . st_uid ! = getuid ( ) | |
st . st_gid ! = getgid ( ) ) {
r = - EEXIST ;
goto fail ;
}
* _fd = fd ;
return 0 ;
fail :
2014-03-18 19:22:43 +01:00
safe_close ( fd ) ;
2011-05-17 19:37:03 +02:00
return r ;
}
2014-06-04 16:19:00 +02:00
static int socket_symlink ( Socket * s ) {
const char * p ;
char * * i ;
assert ( s ) ;
p = socket_find_symlink_target ( s ) ;
if ( ! p )
return 0 ;
STRV_FOREACH ( i , s - > symlinks )
symlink ( p , * i ) ;
return 0 ;
}
2010-01-26 04:18:44 +01:00
static int socket_open_fds ( Socket * s ) {
2010-01-23 22:56:47 +01:00
SocketPort * p ;
int r ;
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 15:39:54 +02:00
char * label = NULL ;
2010-08-20 02:27:05 +02:00
bool know_label = false ;
2010-01-23 22:56:47 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
LIST_FOREACH ( port , p , s - > ports ) {
2010-01-23 22:56:47 +01:00
2010-01-26 04:18:44 +01:00
if ( p - > fd > = 0 )
continue ;
2010-01-23 22:56:47 +01:00
if ( p - > type = = SOCKET_SOCKET ) {
2010-08-20 02:27:05 +02:00
2014-10-23 18:58:18 +02:00
if ( ! know_label ) {
/* Figure out label, if we don't it know
* yet . We do it once , for the first
* socket where we need this and
* remember it for the rest . */
if ( s - > selinux_context_from_net ) {
/* Get it from the network label */
r = mac_selinux_get_our_label ( & label ) ;
if ( r < 0 & & r ! = EOPNOTSUPP )
goto rollback ;
2010-08-20 02:27:05 +02:00
2014-10-23 18:58:18 +02:00
} else {
/* Get it from the executable we are about to start */
r = socket_instantiate_service ( s ) ;
if ( r < 0 )
goto rollback ;
if ( UNIT_ISSET ( s - > service ) & &
SERVICE ( UNIT_DEREF ( s - > service ) ) - > exec_command [ SERVICE_EXEC_START ] ) {
r = mac_selinux_get_create_label_from_exe ( SERVICE ( UNIT_DEREF ( s - > service ) ) - > exec_command [ SERVICE_EXEC_START ] - > path , & label ) ;
if ( r < 0 & & r ! = - EPERM & & r ! = EOPNOTSUPP )
goto rollback ;
}
2011-07-28 23:39:29 +02:00
}
2010-08-20 02:27:05 +02:00
know_label = true ;
}
2013-11-06 22:30:35 +01:00
r = socket_address_listen (
& p - > address ,
SOCK_CLOEXEC | SOCK_NONBLOCK ,
s - > backlog ,
s - > bind_ipv6_only ,
s - > bind_to_device ,
s - > free_bind ,
s - > transparent ,
s - > directory_mode ,
s - > socket_mode ,
label ) ;
if ( r < 0 )
2010-01-23 22:56:47 +01:00
goto rollback ;
2013-11-06 22:30:35 +01:00
p - > fd = r ;
2010-07-01 00:29:17 +02:00
socket_apply_socket_options ( s , p - > fd ) ;
2014-06-04 16:19:00 +02:00
socket_symlink ( s ) ;
2010-07-01 00:29:17 +02:00
2011-04-20 05:02:23 +02:00
} else if ( p - > type = = SOCKET_SPECIAL ) {
2013-11-06 22:30:35 +01:00
r = special_address_create (
p - > path ,
& p - > fd ) ;
if ( r < 0 )
2011-04-20 05:02:23 +02:00
goto rollback ;
2010-07-16 19:42:27 +02:00
} else if ( p - > type = = SOCKET_FIFO ) {
2010-01-23 22:56:47 +01:00
2013-11-06 22:30:35 +01:00
r = fifo_address_create (
p - > path ,
s - > directory_mode ,
s - > socket_mode ,
& p - > fd ) ;
if ( r < 0 )
2010-01-23 22:56:47 +01:00
goto rollback ;
2010-07-16 19:42:27 +02:00
socket_apply_fifo_options ( s , p - > fd ) ;
2014-06-04 16:19:00 +02:00
socket_symlink ( s ) ;
2011-05-17 19:37:03 +02:00
} else if ( p - > type = = SOCKET_MQUEUE ) {
2010-01-23 22:56:47 +01:00
2013-11-06 22:30:35 +01:00
r = mq_address_create (
p - > path ,
s - > socket_mode ,
s - > mq_maxmsg ,
s - > mq_msgsize ,
& p - > fd ) ;
if ( r < 0 )
2011-05-17 19:37:03 +02:00
goto rollback ;
2010-07-16 19:42:27 +02:00
} else
assert_not_reached ( " Unknown port type " ) ;
2010-01-26 04:18:44 +01:00
}
2014-10-23 10:23:46 +02:00
mac_selinux_free ( label ) ;
2010-01-26 04:18:44 +01:00
return 0 ;
rollback :
socket_close_fds ( s ) ;
2014-10-23 10:23:46 +02:00
mac_selinux_free ( label ) ;
2014-10-23 18:58:18 +02:00
2010-01-26 04:18:44 +01:00
return r ;
}
static void socket_unwatch_fds ( Socket * s ) {
SocketPort * p ;
2013-11-19 21:12:59 +01:00
int r ;
2010-01-24 00:39:29 +01:00
2010-01-26 04:18:44 +01:00
assert ( s ) ;
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > fd < 0 )
continue ;
2014-06-05 12:24:03 +02:00
if ( ! p - > event_source )
continue ;
r = sd_event_source_set_enabled ( p - > event_source , SD_EVENT_OFF ) ;
if ( r < 0 )
log_debug_unit ( UNIT ( s ) - > id , " Failed to disable event source. " ) ;
2010-01-23 22:56:47 +01:00
}
2010-01-26 04:18:44 +01:00
}
static int socket_watch_fds ( Socket * s ) {
SocketPort * p ;
int r ;
assert ( s ) ;
2010-01-23 22:56:47 +01:00
2010-01-26 04:18:44 +01:00
LIST_FOREACH ( port , p , s - > ports ) {
if ( p - > fd < 0 )
continue ;
2013-11-19 21:12:59 +01:00
if ( p - > event_source )
r = sd_event_source_set_enabled ( p - > event_source , SD_EVENT_ON ) ;
else
2014-02-19 23:54:58 +01:00
r = sd_event_add_io ( UNIT ( s ) - > manager - > event , & p - > event_source , p - > fd , EPOLLIN , socket_dispatch_io , p ) ;
2010-04-15 06:19:54 +02:00
2013-11-19 21:12:59 +01:00
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " Failed to watch listening fds: %s " , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
goto fail ;
2013-11-19 21:12:59 +01:00
}
2010-01-26 04:18:44 +01:00
}
2010-01-23 22:56:47 +01:00
2010-01-23 03:35:54 +01:00
return 0 ;
2010-01-23 22:56:47 +01:00
2010-01-26 04:18:44 +01: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 ;
2014-06-04 13:10:43 +02:00
if ( ! IN_SET ( state ,
SOCKET_START_PRE ,
2014-06-05 09:55:53 +02:00
SOCKET_START_CHOWN ,
2014-06-04 13:10:43 +02:00
SOCKET_START_POST ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_PRE_SIGKILL ,
SOCKET_STOP_POST ,
SOCKET_FINAL_SIGTERM ,
SOCKET_FINAL_SIGKILL ) ) {
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 04:18:44 +01:00
s - > control_command = NULL ;
2010-04-21 03:27:44 +02:00
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
2010-04-10 17:53:17 +02:00
}
2010-01-26 04:18:44 +01:00
2010-04-21 03:27:44 +02:00
if ( state ! = SOCKET_LISTENING )
socket_unwatch_fds ( s ) ;
2014-06-04 13:10:43 +02:00
if ( ! IN_SET ( state ,
2014-06-05 09:55:53 +02:00
SOCKET_START_CHOWN ,
2014-06-04 13:10:43 +02:00
SOCKET_START_POST ,
SOCKET_LISTENING ,
SOCKET_RUNNING ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_PRE_SIGKILL ) )
2010-01-26 04:18:44 +01:00
socket_close_fds ( s ) ;
2010-04-10 17:53:17 +02:00
if ( state ! = old_state )
2013-12-02 23:30:19 +01:00
log_debug_unit ( UNIT ( s ) - > id , " %s changed %s -> %s " ,
UNIT ( s ) - > id , socket_state_to_string ( old_state ) , socket_state_to_string ( state ) ) ;
2010-01-27 04:31:52 +01:00
2011-01-20 13:17:22 +01:00
unit_notify ( UNIT ( s ) , state_translation_table [ old_state ] , state_translation_table [ state ] , true ) ;
2010-01-26 04:18:44 +01:00
}
2010-04-21 03:27:44 +02:00
static int socket_coldplug ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
int r ;
assert ( s ) ;
assert ( s - > state = = SOCKET_DEAD ) ;
2013-12-02 23:30:19 +01:00
if ( s - > deserialized_state = = s - > state )
return 0 ;
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > deserialized_state ,
SOCKET_START_PRE ,
SOCKET_START_CHOWN ,
SOCKET_START_POST ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_PRE_SIGKILL ,
SOCKET_STOP_POST ,
SOCKET_FINAL_SIGTERM ,
SOCKET_FINAL_SIGKILL ) ) {
2010-04-21 03:27:44 +02:00
2013-12-02 23:30:19 +01:00
if ( s - > control_pid < = 0 )
return - EBADMSG ;
2010-04-21 03:27:44 +02:00
2013-12-02 23:30:19 +01:00
r = unit_watch_pid ( UNIT ( s ) , s - > control_pid ) ;
if ( r < 0 )
return r ;
2010-04-21 03:27:44 +02:00
2013-12-02 23:30:19 +01:00
r = socket_arm_timer ( s ) ;
if ( r < 0 )
return r ;
}
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > deserialized_state ,
SOCKET_START_CHOWN ,
SOCKET_START_POST ,
SOCKET_LISTENING ,
SOCKET_RUNNING ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_PRE_SIGKILL ) ) {
2013-12-02 23:30:19 +01:00
r = socket_open_fds ( s ) ;
if ( r < 0 )
return r ;
}
2010-04-21 03:27:44 +02:00
2013-12-02 23:30:19 +01:00
if ( s - > deserialized_state = = SOCKET_LISTENING ) {
r = socket_watch_fds ( s ) ;
if ( r < 0 )
return r ;
2010-04-21 03:27:44 +02:00
}
2013-12-02 23:30:19 +01:00
socket_set_state ( s , s - > deserialized_state ) ;
2010-04-21 03:27:44 +02:00
return 0 ;
}
2010-04-10 17:53:17 +02:00
static int socket_spawn ( Socket * s , ExecCommand * c , pid_t * _pid ) {
2014-06-05 09:55:53 +02:00
_cleanup_free_ char * * argv = NULL ;
2010-01-26 04:18:44 +01:00
pid_t pid ;
int r ;
2014-08-23 15:28:37 +02:00
ExecParameters exec_params = {
. apply_permissions = true ,
. apply_chroot = true ,
. apply_tty_stdin = true ,
} ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
assert ( c ) ;
assert ( _pid ) ;
2013-06-27 04:14:27 +02:00
unit_realize_cgroup ( UNIT ( s ) ) ;
2013-11-27 20:23:18 +01:00
r = unit_setup_exec_runtime ( UNIT ( s ) ) ;
if ( r < 0 )
goto fail ;
2013-11-19 21:12:59 +01:00
r = socket_arm_timer ( s ) ;
2012-11-23 21:37:58 +01:00
if ( r < 0 )
2010-04-10 17:53:17 +02:00
goto fail ;
2010-01-26 04:18:44 +01:00
2013-09-17 17:03:46 +02:00
r = unit_full_printf_strv ( UNIT ( s ) , c - > argv , & argv ) ;
if ( r < 0 )
2010-04-15 03:11:11 +02:00
goto fail ;
2014-08-23 15:28:37 +02:00
exec_params . argv = argv ;
exec_params . environment = UNIT ( s ) - > manager - > environment ;
exec_params . confirm_spawn = UNIT ( s ) - > manager - > confirm_spawn ;
exec_params . cgroup_supported = UNIT ( s ) - > manager - > cgroup_supported ;
exec_params . cgroup_path = UNIT ( s ) - > cgroup_path ;
exec_params . runtime_prefix = manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ;
exec_params . unit_id = UNIT ( s ) - > id ;
2010-04-15 03:11:11 +02:00
r = exec_spawn ( c ,
& s - > exec_context ,
2014-08-23 15:28:37 +02:00
& exec_params ,
2013-11-27 20:23:18 +01:00
s - > exec_runtime ,
2010-04-15 03:11:11 +02:00
& pid ) ;
2014-06-18 20:34:52 +02:00
if ( r < 0 )
goto fail ;
2010-04-15 03:11:11 +02:00
2014-06-05 09:55:53 +02:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
2010-04-15 03:11:11 +02:00
if ( r < 0 )
2014-06-05 09:55:53 +02:00
/* FIXME: we need to do something here */
2010-01-26 04:18:44 +01:00
goto fail ;
2014-06-05 09:55:53 +02:00
* _pid = pid ;
return 0 ;
fail :
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
return r ;
}
static int socket_chown ( Socket * s , pid_t * _pid ) {
pid_t pid ;
int r ;
r = socket_arm_timer ( s ) ;
if ( r < 0 )
goto fail ;
/* We have to resolve the user names out-of-process, hence
* let ' s fork here . It ' s messy , but well , what can we do ? */
pid = fork ( ) ;
if ( pid < 0 )
return - errno ;
if ( pid = = 0 ) {
SocketPort * p ;
uid_t uid = ( uid_t ) - 1 ;
gid_t gid = ( gid_t ) - 1 ;
int ret ;
default_signals ( SIGNALS_CRASH_HANDLER , SIGNALS_IGNORE , - 1 ) ;
ignore_signals ( SIGPIPE , - 1 ) ;
log_forget_fds ( ) ;
if ( ! isempty ( s - > user ) ) {
const char * user = s - > user ;
r = get_user_creds ( & user , & uid , & gid , NULL , NULL ) ;
if ( r < 0 ) {
ret = EXIT_USER ;
goto fail_child ;
}
}
if ( ! isempty ( s - > group ) ) {
const char * group = s - > group ;
r = get_group_creds ( & group , & gid ) ;
if ( r < 0 ) {
ret = EXIT_GROUP ;
goto fail_child ;
}
}
LIST_FOREACH ( port , p , s - > ports ) {
2014-06-06 23:29:09 +02:00
const char * path = NULL ;
2014-06-05 09:55:53 +02:00
if ( p - > type = = SOCKET_SOCKET )
path = socket_address_get_path ( & p - > address ) ;
else if ( p - > type = = SOCKET_FIFO )
path = p - > path ;
if ( ! path )
continue ;
if ( chown ( path , uid , gid ) < 0 ) {
r = - errno ;
ret = EXIT_CHOWN ;
goto fail_child ;
}
}
_exit ( 0 ) ;
fail_child :
log_open ( ) ;
log_error ( " Failed to chown socket at step %s: %s " , exit_status_to_string ( ret , EXIT_STATUS_SYSTEMD ) , strerror ( - r ) ) ;
_exit ( ret ) ;
}
2013-11-19 21:12:59 +01:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-01-23 22:56:47 +01:00
2010-01-26 04:18:44 +01:00
* _pid = pid ;
return 0 ;
fail :
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-01-23 22:56:47 +01:00
return r ;
2010-01-23 03:35:54 +01:00
}
2012-02-03 02:31:54 +01:00
static void socket_enter_dead ( Socket * s , SocketResult f ) {
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2012-02-03 02:31:54 +01:00
if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2013-11-27 20:23:18 +01:00
exec_runtime_destroy ( s - > exec_runtime ) ;
s - > exec_runtime = exec_runtime_unref ( s - > exec_runtime ) ;
2014-03-03 17:14:07 +01:00
exec_context_destroy_runtime_directory ( & s - > exec_context , manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ) ;
2012-02-03 02:31:54 +01:00
socket_set_state ( s , s - > result ! = SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:31:54 +01:00
static void socket_enter_signal ( Socket * s , SocketState state , SocketResult f ) ;
2010-04-13 02:06:27 +02:00
2012-02-03 02:31:54 +01:00
static void socket_enter_stop_post ( Socket * s , SocketResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:31:54 +01:00
if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 03:27:44 +02:00
s - > control_command_id = SOCKET_EXEC_STOP_POST ;
2014-06-05 09:55:53 +02:00
s - > control_command = s - > exec_command [ SOCKET_EXEC_STOP_POST ] ;
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
if ( s - > control_command ) {
r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
socket_set_state ( s , SOCKET_STOP_POST ) ;
} else
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , SOCKET_SUCCESS ) ;
2010-01-26 04:18:44 +01:00
return ;
fail :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run 'stop-post' task: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:31:54 +01:00
static void socket_enter_signal ( Socket * s , SocketState state , SocketResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:31:54 +01:00
if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2013-01-26 05:53:30 +01:00
r = unit_kill_context (
UNIT ( s ) ,
& s - > kill_context ,
state ! = SOCKET_STOP_PRE_SIGTERM & & state ! = SOCKET_FINAL_SIGTERM ,
- 1 ,
s - > control_pid ,
false ) ;
if ( r < 0 )
goto fail ;
2010-01-26 04:18:44 +01:00
2013-01-26 05:53:30 +01:00
if ( r > 0 ) {
2013-11-19 21:12:59 +01:00
r = socket_arm_timer ( s ) ;
2012-11-23 21:37:58 +01:00
if ( r < 0 )
2010-04-13 02:06:27 +02:00
goto fail ;
2010-01-28 01:59:41 +01:00
2010-04-13 02:06:27 +02:00
socket_set_state ( s , state ) ;
2014-01-29 14:58:04 +01:00
} else if ( state = = SOCKET_STOP_PRE_SIGTERM )
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGKILL , SOCKET_SUCCESS ) ;
else if ( state = = SOCKET_STOP_PRE_SIGKILL )
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_SUCCESS ) ;
2014-01-29 14:58:04 +01:00
else if ( state = = SOCKET_FINAL_SIGTERM )
socket_enter_signal ( s , SOCKET_FINAL_SIGKILL , SOCKET_SUCCESS ) ;
2010-04-13 02:06:27 +02:00
else
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_SUCCESS ) ;
2010-01-26 04:18:44 +01:00
return ;
fail :
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to kill processes: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
if ( state = = SOCKET_STOP_PRE_SIGTERM | | state = = SOCKET_STOP_PRE_SIGKILL )
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
else
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:31:54 +01:00
static void socket_enter_stop_pre ( Socket * s , SocketResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:31:54 +01:00
if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 03:27:44 +02:00
s - > control_command_id = SOCKET_EXEC_STOP_PRE ;
2014-06-05 09:55:53 +02:00
s - > control_command = s - > exec_command [ SOCKET_EXEC_STOP_PRE ] ;
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
if ( s - > control_command ) {
r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
socket_set_state ( s , SOCKET_STOP_PRE ) ;
} else
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_SUCCESS ) ;
2010-01-26 04:18:44 +01:00
return ;
fail :
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to run 'stop-pre' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2010-01-27 05:33:11 +01:00
static void socket_enter_listening ( Socket * s ) {
int r ;
assert ( s ) ;
2012-02-03 02:31:54 +01:00
r = socket_watch_fds ( s ) ;
if ( r < 0 ) {
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to watch sockets: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-27 05:33:11 +01:00
goto fail ;
}
socket_set_state ( s , SOCKET_LISTENING ) ;
return ;
fail :
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-27 05:33:11 +01:00
}
2010-01-26 04:18:44 +01:00
static void socket_enter_start_post ( Socket * s ) {
int r ;
assert ( s ) ;
2014-06-05 09:55:53 +02:00
socket_unwatch_control_pid ( s ) ;
s - > control_command_id = SOCKET_EXEC_START_POST ;
s - > control_command = s - > exec_command [ SOCKET_EXEC_START_POST ] ;
if ( s - > control_command ) {
r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " %s failed to run 'start-post' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
goto fail ;
}
socket_set_state ( s , SOCKET_START_POST ) ;
} else
socket_enter_listening ( s ) ;
return ;
fail :
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
}
static void socket_enter_start_chown ( Socket * s ) {
int r ;
assert ( s ) ;
2012-02-03 02:31:54 +01:00
r = socket_open_fds ( s ) ;
if ( r < 0 ) {
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to listen on sockets: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
goto fail ;
}
2014-06-05 09:55:53 +02:00
if ( ! isempty ( s - > user ) | | ! isempty ( s - > group ) ) {
2010-04-11 00:22:36 +02:00
2014-06-05 09:55:53 +02:00
socket_unwatch_control_pid ( s ) ;
s - > control_command_id = SOCKET_EXEC_START_CHOWN ;
s - > control_command = NULL ;
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
r = socket_chown ( s , & s - > control_pid ) ;
2012-02-03 02:31:54 +01:00
if ( r < 0 ) {
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to fork 'start-chown' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
goto fail ;
}
2014-06-05 09:55:53 +02:00
socket_set_state ( s , SOCKET_START_CHOWN ) ;
2010-04-13 02:06:27 +02:00
} else
2014-06-05 09:55:53 +02:00
socket_enter_start_post ( s ) ;
2010-01-26 04:18:44 +01:00
return ;
fail :
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
static void socket_enter_start_pre ( Socket * s ) {
int r ;
assert ( s ) ;
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-04-21 03:27:44 +02:00
s - > control_command_id = SOCKET_EXEC_START_PRE ;
2014-06-05 09:55:53 +02:00
s - > control_command = s - > exec_command [ SOCKET_EXEC_START_PRE ] ;
2010-04-21 03:27:44 +02:00
2014-06-05 09:55:53 +02:00
if ( s - > control_command ) {
2013-12-02 23:30:19 +01:00
r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ;
2014-06-05 09:55:53 +02:00
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " %s failed to run 'start-pre' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
goto fail ;
2014-06-05 09:55:53 +02:00
}
2010-01-26 04:18:44 +01:00
2010-04-13 02:06:27 +02:00
socket_set_state ( s , SOCKET_START_PRE ) ;
} else
2014-06-05 09:55:53 +02:00
socket_enter_start_chown ( s ) ;
2010-01-26 04:18:44 +01:00
return ;
fail :
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2010-04-15 06:19:54 +02:00
static void socket_enter_running ( Socket * s , int cfd ) {
2013-11-19 21:12:59 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2010-07-13 00:27:27 +02:00
/* We don't take connections anymore if we are supposed to
* shut down anyway */
2013-04-26 02:57:41 +02:00
if ( unit_stop_pending ( UNIT ( s ) ) ) {
2013-12-02 23:30:19 +01:00
log_debug_unit ( UNIT ( s ) - > id , " Suppressing connection request on %s since unit stop is scheduled. " , UNIT ( s ) - > id ) ;
2011-01-26 02:55:35 +01:00
2010-07-13 00:51:48 +02:00
if ( cfd > = 0 )
2014-03-18 19:22:43 +01:00
safe_close ( cfd ) ;
2010-07-13 00:51:48 +02:00
else {
/* Flush all sockets by closing and reopening them */
socket_close_fds ( s ) ;
2013-12-16 21:26:21 +01:00
r = socket_open_fds ( s ) ;
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " %s failed to listen on sockets: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
return ;
}
2012-01-20 23:44:22 +01:00
r = socket_watch_fds ( s ) ;
if ( r < 0 ) {
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to watch sockets: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-07-13 00:51:48 +02:00
}
}
2010-07-13 00:27:27 +02:00
return ;
}
2010-04-15 06:19:54 +02:00
if ( cfd < 0 ) {
2012-01-06 23:08:54 +01:00
Iterator i ;
2013-12-02 23:30:19 +01:00
Unit * other ;
2010-10-05 19:49:15 +02:00
bool pending = false ;
/* If there's already a start pending don't bother to
* do anything */
2013-12-02 23:30:19 +01:00
SET_FOREACH ( other , UNIT ( s ) - > dependencies [ UNIT_TRIGGERS ] , i )
if ( unit_active_or_pending ( other ) ) {
2012-01-06 23:08:54 +01:00
pending = true ;
break ;
}
2010-10-05 19:49:15 +02:00
2012-01-20 23:44:22 +01:00
if ( ! pending ) {
2014-05-22 09:56:21 +02:00
if ( ! UNIT_ISSET ( s - > service ) ) {
log_error_unit ( UNIT ( s ) - > id , " %s: service to activate vanished, refusing activation. " , UNIT ( s ) - > id ) ;
r = - ENOENT ;
goto fail ;
}
2012-01-20 23:44:22 +01:00
r = manager_add_job ( UNIT ( s ) - > manager , JOB_START , UNIT_DEREF ( s - > service ) , JOB_REPLACE , true , & error , NULL ) ;
if ( r < 0 )
2010-10-05 19:49:15 +02:00
goto fail ;
2012-01-20 23:44:22 +01:00
}
2010-04-15 06:19:54 +02:00
socket_set_state ( s , SOCKET_RUNNING ) ;
} else {
2013-11-16 22:18:12 +01:00
_cleanup_free_ char * prefix = NULL , * instance = NULL , * name = NULL ;
2010-07-16 19:42:27 +02:00
Service * service ;
2010-04-15 06:19:54 +02:00
2010-06-19 04:25:28 +02:00
if ( s - > n_connections > = s - > max_connections ) {
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s: Too many incoming connections (%u) " , UNIT ( s ) - > id , s - > n_connections ) ;
2014-03-18 19:22:43 +01:00
safe_close ( cfd ) ;
2010-06-19 04:25:28 +02:00
return ;
}
2012-01-20 23:44:22 +01:00
r = socket_instantiate_service ( s ) ;
if ( r < 0 )
2010-07-16 19:42:27 +02:00
goto fail ;
2012-01-20 23:44:22 +01:00
r = instance_from_socket ( cfd , s - > n_accepted , & instance ) ;
if ( r < 0 ) {
if ( r ! = - ENOTCONN )
goto fail ;
/* ENOTCONN is legitimate if TCP RST was received.
* This connection is over , but the socket unit lives on . */
2014-03-18 19:22:43 +01:00
safe_close ( cfd ) ;
2012-01-20 23:44:22 +01:00
return ;
}
2010-04-15 06:19:54 +02:00
2012-01-20 23:44:22 +01:00
prefix = unit_name_to_prefix ( UNIT ( s ) - > id ) ;
if ( ! prefix ) {
2010-04-15 06:19:54 +02:00
r = - ENOMEM ;
goto fail ;
}
name = unit_name_build ( prefix , instance , " .service " ) ;
2010-05-20 20:46:17 +02:00
if ( ! name ) {
2010-04-15 06:19:54 +02:00
r = - ENOMEM ;
2010-05-20 20:46:17 +02:00
goto fail ;
}
2010-04-15 06:19:54 +02:00
2012-01-20 23:44:22 +01:00
r = unit_add_name ( UNIT_DEREF ( s - > service ) , name ) ;
2013-11-16 22:18:12 +01:00
if ( r < 0 )
2010-04-15 06:19:54 +02:00
goto fail ;
2010-07-16 19:42:27 +02:00
2012-01-06 23:08:54 +01:00
service = SERVICE ( UNIT_DEREF ( s - > service ) ) ;
unit_ref_unset ( & s - > service ) ;
2010-07-16 19:42:27 +02:00
s - > n_accepted + + ;
2010-04-15 06:19:54 +02:00
2012-01-15 12:25:20 +01:00
UNIT ( service ) - > no_gc = false ;
2010-08-11 02:07:59 +02:00
2010-07-16 19:42:27 +02:00
unit_choose_id ( UNIT ( service ) , name ) ;
2014-07-24 10:40:28 +02:00
r = service_set_socket_fd ( service , cfd , s , s - > selinux_context_from_net ) ;
2012-01-20 23:44:22 +01:00
if ( r < 0 )
2010-04-15 06:19:54 +02:00
goto fail ;
cfd = - 1 ;
2010-06-19 04:25:28 +02:00
s - > n_connections + + ;
2012-01-20 23:44:22 +01:00
r = manager_add_job ( UNIT ( s ) - > manager , JOB_START , UNIT ( service ) , JOB_REPLACE , true , & error , NULL ) ;
if ( r < 0 )
2010-04-15 06:19:54 +02:00
goto fail ;
2010-08-20 02:26:05 +02:00
/* Notify clients about changed counters */
unit_add_to_dbus_queue ( UNIT ( s ) ) ;
2010-04-15 06:19:54 +02:00
}
2010-01-26 04:18:44 +01:00
return ;
fail :
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s " ,
UNIT ( s ) - > id , cfd > = 0 ? " template " : " non-template " ,
2013-11-19 21:12:59 +01:00
bus_error_message ( & error , r ) ) ;
2013-12-02 23:30:19 +01:00
2012-04-02 21:49:00 +02:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
2014-03-18 19:22:43 +01:00
safe_close ( cfd ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:31:54 +01:00
static void socket_run_next ( Socket * s ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
assert ( s - > control_command ) ;
assert ( s - > control_command - > command_next ) ;
2010-04-11 00:22:36 +02:00
socket_unwatch_control_pid ( s ) ;
2010-01-26 04:18:44 +01:00
s - > control_command = s - > control_command - > command_next ;
2013-12-02 23:30:19 +01:00
r = socket_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
return ;
fail :
2013-12-02 23:30:19 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to run next task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-04-13 02:06:27 +02:00
if ( s - > state = = SOCKET_START_POST )
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
else if ( s - > state = = SOCKET_STOP_POST )
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
else
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , SOCKET_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2010-01-26 21:39:06 +01:00
static int socket_start ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
2010-01-23 22:56:47 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
/* We cannot fulfill this request right now, try again later
* please ! */
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > state ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGKILL ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_POST ,
SOCKET_FINAL_SIGTERM ,
SOCKET_FINAL_SIGKILL ) )
2010-01-26 04:18:44 +01:00
return - EAGAIN ;
2014-06-05 12:24:03 +02:00
/* Already on it! */
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > state ,
SOCKET_START_PRE ,
SOCKET_START_CHOWN ,
SOCKET_START_POST ) )
2010-01-26 04:18:44 +01:00
return 0 ;
2010-01-23 22:56:47 +01:00
2010-01-26 04:18:44 +01:00
/* Cannot run this without the service being around */
2013-06-20 03:45:08 +02:00
if ( UNIT_ISSET ( s - > service ) ) {
2012-01-06 23:08:54 +01:00
Service * service ;
service = SERVICE ( UNIT_DEREF ( s - > service ) ) ;
2012-01-15 12:25:20 +01:00
if ( UNIT ( service ) - > load_state ! = UNIT_LOADED ) {
2013-12-02 23:30:19 +01:00
log_error_unit ( u - > id , " Socket service %s not loaded, refusing. " , UNIT ( service ) - > id ) ;
2010-04-15 06:19:54 +02:00
return - ENOENT ;
2011-04-10 03:27:19 +02:00
}
2010-04-15 06:19:54 +02:00
2011-02-21 15:32:17 +01:00
/* If the service is already active we cannot start the
2010-04-15 06:19:54 +02:00
* socket */
2012-01-06 23:08:54 +01:00
if ( service - > state ! = SERVICE_DEAD & &
service - > state ! = SERVICE_FAILED & &
service - > state ! = SERVICE_AUTO_RESTART ) {
2013-12-02 23:30:19 +01:00
log_error_unit ( u - > id , " Socket service %s already active, refusing. " , UNIT ( service ) - > id ) ;
2010-04-15 06:19:54 +02:00
return - EBUSY ;
2011-04-10 03:27:19 +02:00
}
2010-04-15 06:19:54 +02:00
}
2010-04-10 17:53:17 +02:00
2010-08-31 00:23:34 +02:00
assert ( s - > state = = SOCKET_DEAD | | s - > state = = SOCKET_FAILED ) ;
2010-01-23 22:56:47 +01:00
2012-02-03 02:31:54 +01:00
s - > result = SOCKET_SUCCESS ;
2010-01-26 04:18:44 +01:00
socket_enter_start_pre ( s ) ;
2013-12-02 23:30:19 +01:00
2010-01-26 04:18:44 +01:00
return 0 ;
}
2010-01-23 22:56:47 +01:00
2010-01-26 21:39:06 +01:00
static int socket_stop ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2010-04-10 17:53:17 +02:00
/* Already on it */
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > state ,
SOCKET_STOP_PRE ,
SOCKET_STOP_PRE_SIGTERM ,
SOCKET_STOP_PRE_SIGKILL ,
SOCKET_STOP_POST ,
SOCKET_FINAL_SIGTERM ,
SOCKET_FINAL_SIGKILL ) )
2010-04-10 17:53:17 +02:00
return 0 ;
2010-07-10 04:52:00 +02:00
/* If there's already something running we go directly into
* kill mode . */
2014-06-05 09:55:53 +02:00
if ( IN_SET ( s - > state ,
SOCKET_START_PRE ,
SOCKET_START_CHOWN ,
SOCKET_START_POST ) ) {
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGTERM , SOCKET_SUCCESS ) ;
2010-07-10 04:52:00 +02:00
return - EAGAIN ;
}
2010-01-26 04:18:44 +01:00
assert ( s - > state = = SOCKET_LISTENING | | s - > state = = SOCKET_RUNNING ) ;
2010-01-23 22:56:47 +01:00
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_SUCCESS ) ;
2010-01-23 03:35:54 +01:00
return 0 ;
}
2010-04-21 03:27:44 +02: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 ) ) ;
2012-02-03 02:31:54 +01:00
unit_serialize_item ( u , f , " result " , socket_result_to_string ( s - > result ) ) ;
2010-04-21 03:27:44 +02:00
unit_serialize_item_format ( u , f , " n-accepted " , " %u " , s - > n_accepted ) ;
if ( s - > control_pid > 0 )
2014-04-25 13:45:15 +02:00
unit_serialize_item_format ( u , f , " control-pid " , PID_FMT , s - > control_pid ) ;
2010-04-21 03:27:44 +02:00
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 ;
2013-11-27 20:23:18 +01:00
copy = fdset_put_dup ( fds , p - > fd ) ;
if ( copy < 0 )
2010-04-21 03:27:44 +02:00
return copy ;
if ( p - > type = = SOCKET_SOCKET ) {
2013-11-27 20:23:18 +01:00
_cleanup_free_ char * t = NULL ;
2010-04-21 03:27:44 +02:00
2012-12-22 19:25:10 +01:00
r = socket_address_print ( & p - > address , & t ) ;
if ( r < 0 )
2010-04-21 03:27:44 +02:00
return r ;
2011-04-10 03:27:00 +02:00
if ( socket_address_family ( & p - > address ) = = AF_NETLINK )
unit_serialize_item_format ( u , f , " netlink " , " %i %s " , copy , t ) ;
else
unit_serialize_item_format ( u , f , " socket " , " %i %i %s " , copy , p - > address . type , t ) ;
2013-11-27 20:23:18 +01:00
2011-04-20 05:02:23 +02:00
} else if ( p - > type = = SOCKET_SPECIAL )
unit_serialize_item_format ( u , f , " special " , " %i %s " , copy , p - > path ) ;
2012-12-22 19:25:10 +01:00
else if ( p - > type = = SOCKET_MQUEUE )
unit_serialize_item_format ( u , f , " mqueue " , " %i %s " , copy , p - > path ) ;
2011-04-20 05:02:23 +02:00
else {
2010-04-21 03:27:44 +02:00
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 ) ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
if ( streq ( key , " state " ) ) {
SocketState state ;
2012-12-22 19:25:10 +01:00
state = socket_state_from_string ( value ) ;
if ( state < 0 )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse state value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else
s - > deserialized_state = state ;
2012-02-03 02:31:54 +01:00
} else if ( streq ( key , " result " ) ) {
SocketResult f ;
2010-04-21 03:27:44 +02:00
2012-02-03 02:31:54 +01:00
f = socket_result_from_string ( value ) ;
if ( f < 0 )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse result value %s " , value ) ;
2012-02-03 02:31:54 +01:00
else if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " n-accepted " ) ) {
unsigned k ;
2010-08-11 22:04:22 +02:00
if ( safe_atou ( value , & k ) < 0 )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse n-accepted value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else
s - > n_accepted + = k ;
} else if ( streq ( key , " control-pid " ) ) {
2010-06-17 22:55:53 +02:00
pid_t pid ;
2010-04-21 03:27:44 +02:00
2010-08-11 22:04:22 +02:00
if ( parse_pid ( value , & pid ) < 0 )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse control-pid value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else
2010-06-17 22:55:53 +02:00
s - > control_pid = pid ;
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " control-command " ) ) {
SocketExecCommand id ;
2013-01-05 18:00:35 +01:00
id = socket_exec_command_from_string ( value ) ;
if ( id < 0 )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse exec-command value %s " , value ) ;
2010-04-21 03:27:44 +02:00
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 ) )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse fifo value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else {
LIST_FOREACH ( port , p , s - > ports )
2011-04-20 05:02:23 +02:00
if ( p - > type = = SOCKET_FIFO & &
streq_ptr ( p - > path , value + skip ) )
break ;
if ( p ) {
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2011-04-20 05:02:23 +02:00
p - > fd = fdset_remove ( fds , fd ) ;
}
}
} else if ( streq ( key , " special " ) ) {
int fd , skip = 0 ;
SocketPort * p ;
if ( sscanf ( value , " %i %n " , & fd , & skip ) < 1 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse special value %s " , value ) ;
2011-04-20 05:02:23 +02:00
else {
LIST_FOREACH ( port , p , s - > ports )
if ( p - > type = = SOCKET_SPECIAL & &
streq_ptr ( p - > path , value + skip ) )
2010-04-21 03:27:44 +02:00
break ;
if ( p ) {
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2010-04-21 03:27:44 +02:00
p - > fd = fdset_remove ( fds , fd ) ;
}
}
2012-12-22 19:25:10 +01:00
} else if ( streq ( key , " mqueue " ) ) {
int fd , skip = 0 ;
SocketPort * p ;
if ( sscanf ( value , " %i %n " , & fd , & skip ) < 1 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse mqueue value %s " , value ) ;
2012-12-22 19:25:10 +01:00
else {
LIST_FOREACH ( port , p , s - > ports )
if ( p - > type = = SOCKET_MQUEUE & &
streq_ptr ( p - > path , value + skip ) )
break ;
if ( p ) {
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2012-12-22 19:25:10 +01:00
p - > fd = fdset_remove ( fds , fd ) ;
}
}
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " socket " ) ) {
2010-06-05 00:52:30 +02:00
int fd , type , skip = 0 ;
2010-04-21 03:27:44 +02:00
SocketPort * p ;
2010-06-05 00:52:30 +02:00
if ( sscanf ( value , " %i %i %n " , & fd , & type , & skip ) < 2 | | fd < 0 | | type < 0 | | ! fdset_contains ( fds , fd ) )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse socket value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else {
LIST_FOREACH ( port , p , s - > ports )
2010-06-05 00:52:30 +02:00
if ( socket_address_is ( & p - > address , value + skip , type ) )
2010-04-21 03:27:44 +02:00
break ;
if ( p ) {
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2010-04-21 03:27:44 +02:00
p - > fd = fdset_remove ( fds , fd ) ;
}
}
2011-04-10 03:27:00 +02:00
} else if ( streq ( key , " netlink " ) ) {
int fd , skip = 0 ;
SocketPort * p ;
if ( sscanf ( value , " %i %n " , & fd , & skip ) < 1 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
2013-12-02 23:30:19 +01:00
log_debug_unit ( u - > id , " Failed to parse socket value %s " , value ) ;
2011-04-10 03:27:00 +02:00
else {
LIST_FOREACH ( port , p , s - > ports )
if ( socket_address_is_netlink ( & p - > address , value + skip ) )
break ;
if ( p ) {
2014-03-18 19:22:43 +01:00
safe_close ( p - > fd ) ;
2011-04-10 03:27:00 +02:00
p - > fd = fdset_remove ( fds , fd ) ;
}
}
2010-04-21 03:27:44 +02:00
} else
2013-12-02 23:30:19 +01:00
log_debug_unit ( UNIT ( s ) - > id , " Unknown serialization key '%s' " , key ) ;
2010-04-21 03:27:44 +02:00
return 0 ;
}
2012-12-22 19:30:07 +01:00
static int socket_distribute_fds ( Unit * u , FDSet * fds ) {
Socket * s = SOCKET ( u ) ;
SocketPort * p ;
assert ( u ) ;
LIST_FOREACH ( port , p , s - > ports ) {
Iterator i ;
int fd ;
if ( p - > type ! = SOCKET_SOCKET )
continue ;
if ( p - > fd > = 0 )
continue ;
FDSET_FOREACH ( fd , fds , i ) {
if ( socket_address_matches_fd ( & p - > address , fd ) ) {
p - > fd = fdset_remove ( fds , fd ) ;
s - > deserialized_state = SOCKET_LISTENING ;
break ;
}
}
}
return 0 ;
}
2013-05-03 04:51:50 +02:00
_pure_ static UnitActiveState socket_active_state ( Unit * u ) {
2010-01-26 21:39:06 +01:00
assert ( u ) ;
2010-01-23 01:52:57 +01:00
2010-01-27 04:31:52 +01:00
return state_translation_table [ SOCKET ( u ) - > state ] ;
2010-01-23 01:52:57 +01:00
}
2013-05-03 04:51:50 +02:00
_pure_ static const char * socket_sub_state_to_string ( Unit * u ) {
2010-04-13 20:59:01 +02:00
assert ( u ) ;
2010-04-21 03:27:44 +02:00
return socket_state_to_string ( SOCKET ( u ) - > state ) ;
2010-04-13 20:59:01 +02:00
}
2013-04-01 22:09:45 +02:00
const char * socket_port_type_to_string ( SocketPort * p ) {
assert ( p ) ;
switch ( p - > type ) {
2013-11-19 21:12:59 +01:00
case SOCKET_SOCKET :
switch ( p - > address . type ) {
case SOCK_STREAM :
return " Stream " ;
case SOCK_DGRAM :
return " Datagram " ;
case SOCK_SEQPACKET :
return " SequentialPacket " ;
case SOCK_RAW :
if ( socket_address_family ( & p - > address ) = = AF_NETLINK )
return " Netlink " ;
default :
return NULL ;
}
case SOCKET_SPECIAL :
return " Special " ;
case SOCKET_MQUEUE :
return " MessageQueue " ;
case SOCKET_FIFO :
return " FIFO " ;
default :
return NULL ;
2013-04-01 22:09:45 +02:00
}
}
2013-05-03 04:51:50 +02:00
_pure_ static bool socket_check_gc ( Unit * u ) {
2010-06-19 04:25:28 +02:00
Socket * s = SOCKET ( u ) ;
assert ( u ) ;
return s - > n_connections > 0 ;
}
2013-11-19 21:12:59 +01:00
static int socket_dispatch_io ( sd_event_source * source , int fd , uint32_t revents , void * userdata ) {
SocketPort * p = userdata ;
2010-04-15 06:19:54 +02:00
int cfd = - 1 ;
2010-01-24 00:39:29 +01:00
2013-11-19 21:12:59 +01:00
assert ( p ) ;
2010-04-16 23:24:39 +02:00
assert ( fd > = 0 ) ;
2010-01-24 00:39:29 +01:00
2013-11-19 21:12:59 +01:00
if ( p - > socket - > state ! = SOCKET_LISTENING )
return 0 ;
2010-05-24 01:45:54 +02:00
2013-11-19 21:12:59 +01:00
log_debug_unit ( UNIT ( p - > socket ) - > id , " Incoming traffic on %s " , UNIT ( p - > socket ) - > id ) ;
2010-01-24 00:39:29 +01:00
2013-11-19 21:12:59 +01:00
if ( revents ! = EPOLLIN ) {
2011-04-26 21:39:14 +02:00
2013-11-19 21:12:59 +01:00
if ( revents & EPOLLHUP )
2013-12-02 23:30:19 +01:00
log_error_unit ( UNIT ( p - > socket ) - > id , " %s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that. " ,
2013-11-19 21:12:59 +01:00
UNIT ( p - > socket ) - > id ) ;
2011-04-26 21:39:14 +02:00
else
2013-12-02 23:30:19 +01:00
log_error_unit ( UNIT ( p - > socket ) - > id , " %s: Got unexpected poll event (0x%x) on socket. " ,
2013-11-19 21:12:59 +01:00
UNIT ( p - > socket ) - > id , revents ) ;
2011-04-26 21:39:14 +02:00
2010-04-16 23:24:39 +02:00
goto fail ;
2010-04-15 06:19:54 +02:00
}
2013-11-19 21:12:59 +01:00
if ( p - > socket - > accept & &
p - > type = = SOCKET_SOCKET & &
socket_address_can_accept ( & p - > address ) ) {
2010-04-15 06:19:54 +02:00
for ( ; ; ) {
2012-09-18 01:16:23 +02:00
cfd = accept4 ( fd , NULL , NULL , SOCK_NONBLOCK ) ;
if ( cfd < 0 ) {
2010-04-15 06:19:54 +02:00
if ( errno = = EINTR )
continue ;
2013-11-19 21:12:59 +01:00
log_error_unit ( UNIT ( p - > socket ) - > id ,
2013-01-05 18:00:35 +01:00
" Failed to accept socket: %m " ) ;
2010-04-16 23:24:39 +02:00
goto fail ;
2010-04-15 06:19:54 +02:00
}
break ;
}
2010-07-01 00:29:17 +02:00
2013-11-19 21:12:59 +01:00
socket_apply_socket_options ( p - > socket , cfd ) ;
2010-04-15 06:19:54 +02:00
}
2010-01-24 00:39:29 +01:00
2013-11-19 21:12:59 +01:00
socket_enter_running ( p - > socket , cfd ) ;
return 0 ;
2010-04-16 23:24:39 +02:00
fail :
2013-11-19 21:12:59 +01:00
socket_enter_stop_pre ( p - > socket , SOCKET_FAILURE_RESOURCES ) ;
return 0 ;
2010-01-24 00:39:29 +01:00
}
2010-01-26 21:39:06 +01:00
static void socket_sigchld_event ( Unit * u , pid_t pid , int code , int status ) {
Socket * s = SOCKET ( u ) ;
2012-02-03 02:31:54 +01:00
SocketResult f ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
assert ( pid > = 0 ) ;
2010-01-23 01:52:57 +01:00
2010-06-16 05:10:31 +02:00
if ( pid ! = s - > control_pid )
return ;
2010-01-23 03:35:54 +01:00
2010-01-26 04:18:44 +01:00
s - > control_pid = 0 ;
2012-08-13 13:58:01 +02:00
if ( is_clean_exit ( code , status , NULL ) )
2012-02-03 02:31:54 +01:00
f = SOCKET_SUCCESS ;
else if ( code = = CLD_EXITED )
f = SOCKET_FAILURE_EXIT_CODE ;
else if ( code = = CLD_KILLED )
f = SOCKET_FAILURE_SIGNAL ;
else if ( code = = CLD_DUMPED )
f = SOCKET_FAILURE_CORE_DUMP ;
else
2014-06-05 12:24:03 +02:00
assert_not_reached ( " Unknown sigchld code " ) ;
2010-06-16 05:10:31 +02:00
2010-07-12 02:25:42 +02:00
if ( s - > control_command ) {
2011-05-18 01:07:31 +02:00
exec_status_exit ( & s - > control_command - > exec_status , & s - > exec_context , pid , code , status ) ;
2010-04-21 03:27:44 +02:00
2010-07-12 02:25:42 +02:00
if ( s - > control_command - > ignore )
2012-02-03 02:31:54 +01:00
f = SOCKET_SUCCESS ;
2010-07-12 02:25:42 +02:00
}
2013-01-05 18:00:35 +01:00
log_full_unit ( f = = SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE ,
u - > id ,
" %s control process exited, code=%s status=%i " ,
u - > id , sigchld_code_to_string ( code ) , status ) ;
2010-01-26 04:18:44 +01:00
2012-02-03 02:31:54 +01:00
if ( f ! = SOCKET_SUCCESS )
s - > result = f ;
if ( s - > control_command & &
s - > control_command - > command_next & &
f = = SOCKET_SUCCESS ) {
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s running next command for state %s " ,
u - > id , socket_state_to_string ( s - > state ) ) ;
2012-02-03 02:31:54 +01:00
socket_run_next ( s ) ;
2010-01-27 04:31:52 +01:00
} else {
2010-04-21 03:27:44 +02:00
s - > control_command = NULL ;
s - > control_command_id = _SOCKET_EXEC_COMMAND_INVALID ;
2010-01-26 04:18:44 +01:00
/* No further commands for this step, so let's figure
* out what to do next */
2010-01-23 01:52:57 +01:00
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s got final SIGCHLD for state %s " ,
u - > id , socket_state_to_string ( s - > state ) ) ;
2010-01-27 04:31:52 +01:00
2010-01-26 04:18:44 +01:00
switch ( s - > state ) {
case SOCKET_START_PRE :
2012-02-03 02:31:54 +01:00
if ( f = = SOCKET_SUCCESS )
2014-06-05 09:55:53 +02:00
socket_enter_start_chown ( s ) ;
2010-01-26 04:18:44 +01:00
else
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , f ) ;
2010-01-26 04:18:44 +01:00
break ;
2014-06-05 09:55:53 +02:00
case SOCKET_START_CHOWN :
if ( f = = SOCKET_SUCCESS )
socket_enter_start_post ( s ) ;
else
socket_enter_stop_pre ( s , f ) ;
break ;
2010-01-26 04:18:44 +01:00
case SOCKET_START_POST :
2012-02-03 02:31:54 +01:00
if ( f = = SOCKET_SUCCESS )
2010-01-27 05:33:11 +01:00
socket_enter_listening ( s ) ;
2010-01-26 04:18:44 +01:00
else
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , f ) ;
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_PRE :
case SOCKET_STOP_PRE_SIGTERM :
case SOCKET_STOP_PRE_SIGKILL :
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , f ) ;
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_POST :
2010-04-13 02:06:27 +02:00
case SOCKET_FINAL_SIGTERM :
case SOCKET_FINAL_SIGKILL :
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , f ) ;
2010-01-26 04:18:44 +01:00
break ;
default :
assert_not_reached ( " Uh, control process died at wrong time. " ) ;
}
}
2010-08-20 02:26:05 +02:00
/* Notify clients about changed exit status */
unit_add_to_dbus_queue ( u ) ;
2010-01-26 04:18:44 +01:00
}
2010-01-23 01:52:57 +01:00
2013-11-19 21:12:59 +01:00
static int socket_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) {
Socket * s = SOCKET ( userdata ) ;
2010-01-23 01:52:57 +01:00
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2013-11-19 21:12:59 +01:00
assert ( s - > timer_event_source = = source ) ;
2010-01-26 04:18:44 +01:00
switch ( s - > state ) {
case SOCKET_START_PRE :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s starting timed out. Terminating. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , SOCKET_FAILURE_TIMEOUT ) ;
2011-03-31 15:35:40 +02:00
break ;
2010-04-13 02:06:27 +02:00
2014-06-05 09:55:53 +02:00
case SOCKET_START_CHOWN :
2010-01-26 04:18:44 +01:00
case SOCKET_START_POST :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s starting timed out. Stopping. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_stop_pre ( s , SOCKET_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_PRE :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out. Terminating. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGTERM , SOCKET_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_PRE_SIGTERM :
2012-07-19 23:47:10 +02:00
if ( s - > kill_context . send_sigkill ) {
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out. Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_STOP_PRE_SIGKILL , SOCKET_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
} else {
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out. Skipping SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
}
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_PRE_SIGKILL :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s still around after SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_stop_post ( s , SOCKET_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SOCKET_STOP_POST :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out (2). Terminating. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGTERM , SOCKET_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
2010-04-13 02:06:27 +02:00
case SOCKET_FINAL_SIGTERM :
2012-07-19 23:47:10 +02:00
if ( s - > kill_context . send_sigkill ) {
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out (2). Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_signal ( s , SOCKET_FINAL_SIGKILL , SOCKET_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
} else {
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s stopping timed out (2). Skipping SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
}
2010-01-26 04:18:44 +01:00
break ;
2010-04-13 02:06:27 +02:00
case SOCKET_FINAL_SIGKILL :
2014-06-05 09:55:53 +02:00
log_warning_unit ( UNIT ( s ) - > id , " %s still around after SIGKILL (2). Entering failed mode. " , UNIT ( s ) - > id ) ;
2012-02-03 02:31:54 +01:00
socket_enter_dead ( s , SOCKET_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
default :
assert_not_reached ( " Timeout at wrong time. " ) ;
}
2013-11-19 21:12:59 +01:00
return 0 ;
2010-01-23 01:52:57 +01:00
}
2010-01-26 07:02:51 +01: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 + + ;
2011-09-23 02:39:28 +02:00
if ( rn_fds < = 0 ) {
* fds = NULL ;
* n_fds = 0 ;
return 0 ;
}
2010-08-11 22:04:22 +02:00
if ( ! ( rfds = new ( int , rn_fds ) ) )
2010-01-26 07:02:51 +01:00
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 ;
}
2013-12-02 23:30:19 +01:00
static void socket_reset_failed ( Unit * u ) {
Socket * s = SOCKET ( u ) ;
assert ( s ) ;
if ( s - > state = = SOCKET_FAILED )
socket_set_state ( s , SOCKET_DEAD ) ;
s - > result = SOCKET_SUCCESS ;
}
2013-07-22 10:52:53 +02:00
static void socket_notify_service_dead ( Socket * s , bool failed_permanent ) {
2010-01-27 06:19:48 +01:00
assert ( s ) ;
2010-06-19 04:25:28 +02:00
/* The service is dead. Dang!
*
* This is strictly for one - instance - for - all - connections
* services . */
2010-01-27 06:19:48 +01:00
if ( s - > state = = SOCKET_RUNNING ) {
2013-12-02 23:30:19 +01:00
log_debug_unit ( UNIT ( s ) - > id , " %s got notified about service death (failed permanently: %s) " , UNIT ( s ) - > id , yes_no ( failed_permanent ) ) ;
2012-03-06 01:29:29 +01:00
if ( failed_permanent )
socket_enter_stop_pre ( s , SOCKET_FAILURE_SERVICE_FAILED_PERMANENT ) ;
2012-03-05 22:47:54 +01:00
else
socket_enter_listening ( s ) ;
2010-01-27 06:19:48 +01:00
}
}
2010-06-19 04:25:28 +02:00
void socket_connection_unref ( Socket * s ) {
assert ( s ) ;
/* The service is dead. Yay!
*
2011-02-21 15:32:17 +01:00
* This is strictly for one - instance - per - connection
2010-06-19 04:25:28 +02:00
* services . */
assert ( s - > n_connections > 0 ) ;
s - > n_connections - - ;
2013-12-02 23:30:19 +01:00
log_debug_unit ( UNIT ( s ) - > id , " %s: One connection closed, %u left. " , UNIT ( s ) - > id , s - > n_connections ) ;
2010-07-18 04:58:01 +02:00
}
2013-07-22 10:52:53 +02:00
static void socket_trigger_notify ( Unit * u , Unit * other ) {
Socket * s = SOCKET ( u ) ;
2013-12-02 23:30:19 +01:00
Service * se ;
2013-07-22 10:52:53 +02:00
assert ( u ) ;
assert ( other ) ;
/* Don't propagate state changes from the service if we are
already down or accepting connections */
if ( ( s - > state ! = SOCKET_RUNNING & &
s - > state ! = SOCKET_LISTENING ) | |
s - > accept )
return ;
if ( other - > load_state ! = UNIT_LOADED | |
other - > type ! = UNIT_SERVICE )
return ;
2013-12-02 23:30:19 +01:00
se = SERVICE ( other ) ;
2013-07-22 10:52:53 +02:00
if ( se - > state = = SERVICE_FAILED )
socket_notify_service_dead ( s , se - > result = = SERVICE_FAILURE_START_LIMIT ) ;
if ( se - > state = = SERVICE_DEAD | |
se - > state = = SERVICE_STOP | |
se - > state = = SERVICE_STOP_SIGTERM | |
se - > state = = SERVICE_STOP_SIGKILL | |
se - > state = = SERVICE_STOP_POST | |
se - > state = = SERVICE_FINAL_SIGTERM | |
se - > state = = SERVICE_FINAL_SIGKILL | |
se - > state = = SERVICE_AUTO_RESTART )
socket_notify_service_dead ( s , false ) ;
if ( se - > state = = SERVICE_RUNNING )
socket_set_state ( s , SOCKET_RUNNING ) ;
}
2013-11-19 21:12:59 +01:00
static int socket_kill ( Unit * u , KillWho who , int signo , sd_bus_error * error ) {
2013-03-02 22:31:09 +01:00
return unit_kill_common ( u , who , signo , - 1 , SOCKET ( u ) - > control_pid , error ) ;
2010-10-22 16:11:50 +02:00
}
2014-01-27 06:57:34 +01:00
static int socket_get_timeout ( Unit * u , uint64_t * timeout ) {
Socket * s = SOCKET ( u ) ;
int r ;
if ( ! s - > timer_event_source )
return 0 ;
r = sd_event_source_get_time ( s - > timer_event_source , timeout ) ;
if ( r < 0 )
return r ;
return 1 ;
}
2010-04-21 03:27:44 +02:00
static const char * const socket_state_table [ _SOCKET_STATE_MAX ] = {
[ SOCKET_DEAD ] = " dead " ,
[ SOCKET_START_PRE ] = " start-pre " ,
2014-06-05 09:55:53 +02:00
[ SOCKET_START_CHOWN ] = " start-chown " ,
2010-04-21 03:27:44 +02:00
[ 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 " ,
2010-08-31 00:23:34 +02:00
[ SOCKET_FAILED ] = " failed "
2010-04-21 03:27:44 +02:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_state , SocketState ) ;
static const char * const socket_exec_command_table [ _SOCKET_EXEC_COMMAND_MAX ] = {
[ SOCKET_EXEC_START_PRE ] = " StartPre " ,
2014-06-05 09:55:53 +02:00
[ SOCKET_EXEC_START_CHOWN ] = " StartChown " ,
2010-04-21 03:27:44 +02:00
[ SOCKET_EXEC_START_POST ] = " StartPost " ,
[ SOCKET_EXEC_STOP_PRE ] = " StopPre " ,
[ SOCKET_EXEC_STOP_POST ] = " StopPost "
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_exec_command , SocketExecCommand ) ;
2012-02-03 02:31:54 +01:00
static const char * const socket_result_table [ _SOCKET_RESULT_MAX ] = {
[ SOCKET_SUCCESS ] = " success " ,
[ SOCKET_FAILURE_RESOURCES ] = " resources " ,
[ SOCKET_FAILURE_TIMEOUT ] = " timeout " ,
[ SOCKET_FAILURE_EXIT_CODE ] = " exit-code " ,
[ SOCKET_FAILURE_SIGNAL ] = " signal " ,
2012-03-05 22:47:54 +01:00
[ SOCKET_FAILURE_CORE_DUMP ] = " core-dump " ,
2012-03-06 01:29:29 +01:00
[ SOCKET_FAILURE_SERVICE_FAILED_PERMANENT ] = " service-failed-permanent "
2012-02-03 02:31:54 +01:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_result , SocketResult ) ;
2010-01-26 21:39:06 +01:00
const UnitVTable socket_vtable = {
2012-01-15 10:53:49 +01:00
. object_size = sizeof ( Socket ) ,
2013-11-19 21:12:59 +01:00
. exec_context_offset = offsetof ( Socket , exec_context ) ,
. cgroup_context_offset = offsetof ( Socket , cgroup_context ) ,
. kill_context_offset = offsetof ( Socket , kill_context ) ,
2013-11-27 20:23:18 +01:00
. exec_runtime_offset = offsetof ( Socket , exec_runtime ) ,
2012-09-18 11:40:01 +02:00
2011-08-01 00:43:05 +02:00
. sections =
" Unit \0 "
" Socket \0 "
" Install \0 " ,
2013-06-27 04:14:27 +02:00
. private_section = " Socket " ,
2013-01-19 01:01:41 +01:00
2010-01-26 04:18:44 +01:00
. init = socket_init ,
. done = socket_done ,
2010-04-21 03:27:44 +02:00
. load = socket_load ,
. coldplug = socket_coldplug ,
2010-01-26 04:18:44 +01:00
2010-01-23 01:52:57 +01:00
. dump = socket_dump ,
2010-01-23 03:35:54 +01:00
. start = socket_start ,
. stop = socket_stop ,
2010-01-23 01:52:57 +01:00
2013-11-19 21:12:59 +01:00
. kill = socket_kill ,
2014-01-27 06:57:34 +01:00
. get_timeout = socket_get_timeout ,
2010-04-21 03:27:44 +02:00
. serialize = socket_serialize ,
. deserialize_item = socket_deserialize_item ,
2012-12-22 19:30:07 +01:00
. distribute_fds = socket_distribute_fds ,
2010-04-21 03:27:44 +02:00
2010-01-23 01:52:57 +01:00
. active_state = socket_active_state ,
2010-04-13 20:59:01 +02:00
. sub_state_to_string = socket_sub_state_to_string ,
2010-01-23 01:52:57 +01:00
2010-06-19 04:25:28 +02:00
. check_gc = socket_check_gc ,
2010-01-26 04:18:44 +01:00
. sigchld_event = socket_sigchld_event ,
2010-04-18 03:08:16 +02:00
2013-07-22 10:52:53 +02:00
. trigger_notify = socket_trigger_notify ,
2010-08-31 00:23:34 +02:00
. reset_failed = socket_reset_failed ,
2010-07-18 04:58:01 +02:00
2010-08-20 02:26:05 +02:00
. bus_interface = " org.freedesktop.systemd1.Socket " ,
2013-11-19 21:12:59 +01:00
. bus_vtable = bus_socket_vtable ,
2013-06-27 23:21:21 +02:00
. bus_set_property = bus_socket_set_property ,
. bus_commit_properties = bus_socket_commit_properties ,
2012-05-13 18:18:54 +02:00
. status_message_formats = {
/*.starting_stopping = {
[ 0 ] = " Starting socket %s... " ,
[ 1 ] = " Stopping socket %s... " ,
} , */
. finished_start_job = {
[ JOB_DONE ] = " Listening on %s. " ,
[ JOB_FAILED ] = " Failed to listen on %s. " ,
[ JOB_DEPENDENCY ] = " Dependency failed for %s. " ,
[ JOB_TIMEOUT ] = " Timed out starting %s. " ,
} ,
. finished_stop_job = {
[ JOB_DONE ] = " Closed %s. " ,
[ JOB_FAILED ] = " Failed stopping %s. " ,
[ JOB_TIMEOUT ] = " Timed out stopping %s. " ,
} ,
} ,
2010-01-23 01:52:57 +01:00
} ;