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 01:52:57 +01:00
# include <errno.h>
2010-01-26 04:18:44 +01:00
# include <signal.h>
2010-02-14 01:09:01 +01:00
# include <dirent.h>
# include <unistd.h>
2012-02-09 13:05:23 +01:00
# include <sys/reboot.h>
2014-03-25 14:15:45 +01:00
# include <linux/reboot.h>
# include <sys/syscall.h>
2010-01-23 01:52:57 +01:00
2012-02-09 13:05:23 +01:00
# include "manager.h"
2010-01-26 21:39:06 +01:00
# include "unit.h"
2010-01-23 01:52:57 +01:00
# include "service.h"
# include "load-fragment.h"
# include "load-dropin.h"
2010-01-26 04:18:44 +01:00
# include "log.h"
2010-02-14 01:09:01 +01:00
# include "strv.h"
2010-04-15 03:11:11 +02:00
# include "unit-name.h"
2012-09-18 11:27:56 +02:00
# include "unit-printf.h"
2010-04-18 03:08:16 +02:00
# include "dbus-service.h"
2010-06-18 04:22:59 +02:00
# include "special.h"
2011-01-20 18:22:03 +01:00
# include "exit-status.h"
2011-03-17 04:02:35 +01:00
# include "def.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2011-03-17 04:02:35 +01:00
# include "util.h"
2012-03-12 22:22:16 +01:00
# include "utf8.h"
2013-02-11 03:46:08 +01:00
# include "env-util.h"
2013-02-14 12:26:13 +01:00
# include "fileio.h"
2013-11-19 21:12:59 +01:00
# include "bus-error.h"
# include "bus-util.h"
2010-01-26 04:18:44 +01:00
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2010-10-08 02:49:44 +02:00
2011-03-17 04:02:35 +01:00
# define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
2010-10-08 02:49:44 +02:00
2010-04-24 05:02:25 +02:00
typedef enum RunlevelType {
RUNLEVEL_UP ,
2012-11-16 18:46:36 +01:00
RUNLEVEL_DOWN
2010-04-24 05:02:25 +02:00
} RunlevelType ;
static const struct {
const char * path ;
const char * target ;
const RunlevelType type ;
} rcnd_table [ ] = {
2010-07-20 22:30:45 +02:00
/* Standard SysV runlevels for start-up */
2010-06-18 04:22:59 +02:00
{ " rc1.d " , SPECIAL_RESCUE_TARGET , RUNLEVEL_UP } ,
2010-05-13 22:24:22 +02:00
{ " rc2.d " , SPECIAL_RUNLEVEL2_TARGET , RUNLEVEL_UP } ,
{ " rc3.d " , SPECIAL_RUNLEVEL3_TARGET , RUNLEVEL_UP } ,
{ " rc4.d " , SPECIAL_RUNLEVEL4_TARGET , RUNLEVEL_UP } ,
{ " rc5.d " , SPECIAL_RUNLEVEL5_TARGET , RUNLEVEL_UP } ,
2010-07-20 22:30:45 +02:00
/* Standard SysV runlevels for shutdown */
{ " rc0.d " , SPECIAL_POWEROFF_TARGET , RUNLEVEL_DOWN } ,
{ " rc6.d " , SPECIAL_REBOOT_TARGET , RUNLEVEL_DOWN }
/* Note that the order here matters, as we read the
directories in this order , and we want to make sure that
sysv_start_priority is known when we first load the
unit . And that value we only know from S links . Hence
2012-11-16 18:46:36 +01:00
UP must be read before DOWN */
2010-04-06 02:43:58 +02:00
} ;
2010-04-24 05:02:25 +02:00
# define RUNLEVELS_UP "12345"
2010-09-21 05:23:12 +02:00
# endif
2010-04-24 05:02:25 +02:00
2010-01-27 04:31:52 +01:00
static const UnitActiveState state_translation_table [ _SERVICE_STATE_MAX ] = {
2010-01-26 21:39:06 +01:00
[ SERVICE_DEAD ] = UNIT_INACTIVE ,
[ SERVICE_START_PRE ] = UNIT_ACTIVATING ,
[ SERVICE_START ] = UNIT_ACTIVATING ,
[ SERVICE_START_POST ] = UNIT_ACTIVATING ,
[ SERVICE_RUNNING ] = UNIT_ACTIVE ,
2010-04-13 02:06:27 +02:00
[ SERVICE_EXITED ] = UNIT_ACTIVE ,
2010-07-01 03:34:15 +02:00
[ SERVICE_RELOAD ] = UNIT_RELOADING ,
2010-01-26 21:39:06 +01:00
[ SERVICE_STOP ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_SIGTERM ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_SIGKILL ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_POST ] = UNIT_DEACTIVATING ,
[ SERVICE_FINAL_SIGTERM ] = UNIT_DEACTIVATING ,
[ SERVICE_FINAL_SIGKILL ] = UNIT_DEACTIVATING ,
2010-08-31 00:23:34 +02:00
[ SERVICE_FAILED ] = UNIT_FAILED ,
2010-07-01 00:31:53 +02:00
[ SERVICE_AUTO_RESTART ] = UNIT_ACTIVATING
2010-01-26 04:18:44 +01:00
} ;
2010-01-23 01:52:57 +01:00
2012-05-24 02:22:35 +02:00
/* For Type=idle we never want to delay any other jobs, hence we
* consider idle jobs active as soon as we start working on them */
static const UnitActiveState state_translation_table_idle [ _SERVICE_STATE_MAX ] = {
[ SERVICE_DEAD ] = UNIT_INACTIVE ,
[ SERVICE_START_PRE ] = UNIT_ACTIVE ,
[ SERVICE_START ] = UNIT_ACTIVE ,
[ SERVICE_START_POST ] = UNIT_ACTIVE ,
[ SERVICE_RUNNING ] = UNIT_ACTIVE ,
[ SERVICE_EXITED ] = UNIT_ACTIVE ,
[ SERVICE_RELOAD ] = UNIT_RELOADING ,
[ SERVICE_STOP ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_SIGTERM ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_SIGKILL ] = UNIT_DEACTIVATING ,
[ SERVICE_STOP_POST ] = UNIT_DEACTIVATING ,
[ SERVICE_FINAL_SIGTERM ] = UNIT_DEACTIVATING ,
[ SERVICE_FINAL_SIGKILL ] = UNIT_DEACTIVATING ,
[ SERVICE_FAILED ] = UNIT_FAILED ,
[ SERVICE_AUTO_RESTART ] = UNIT_ACTIVATING
} ;
2013-11-19 21:12:59 +01:00
static int service_dispatch_io ( sd_event_source * source , int fd , uint32_t events , void * userdata ) ;
static int service_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) ;
static int service_dispatch_watchdog ( sd_event_source * source , usec_t usec , void * userdata ) ;
2013-12-11 20:49:43 +01:00
static void service_enter_signal ( Service * s , ServiceState state , ServiceResult f ) ;
2010-04-21 03:27:44 +02:00
static void service_init ( Unit * u ) {
Service * s = SERVICE ( 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
2013-11-04 17:47:43 +01:00
s - > timeout_start_usec = u - > manager - > default_timeout_start_usec ;
s - > timeout_stop_usec = u - > manager - > default_timeout_stop_usec ;
s - > restart_usec = u - > manager - > default_restart_usec ;
2012-05-03 14:46:29 +02:00
s - > type = _SERVICE_TYPE_INVALID ;
2012-02-08 10:10:34 +01:00
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2010-04-21 03:27:44 +02:00
s - > sysv_start_priority = - 1 ;
2011-03-30 00:43:16 +02:00
s - > sysv_start_priority_from_rcnd = - 1 ;
2010-09-21 05:23:12 +02:00
# endif
2010-04-21 03:27:44 +02:00
s - > socket_fd = - 1 ;
2011-02-13 18:51:30 +01:00
s - > guess_main_pid = true ;
2010-04-21 03:27:44 +02:00
2014-02-24 23:50:10 +01:00
RATELIMIT_INIT ( s - > start_limit , u - > manager - > default_start_limit_interval , u - > manager - > default_start_limit_burst ) ;
2010-04-21 03:27:44 +02:00
s - > control_command_id = _SERVICE_EXEC_COMMAND_INVALID ;
}
2010-04-11 00:22:36 +02:00
static void service_unwatch_control_pid ( Service * s ) {
assert ( s ) ;
if ( s - > control_pid < = 0 )
return ;
unit_unwatch_pid ( UNIT ( s ) , s - > control_pid ) ;
s - > control_pid = 0 ;
}
static void service_unwatch_main_pid ( Service * s ) {
assert ( s ) ;
if ( s - > main_pid < = 0 )
return ;
unit_unwatch_pid ( UNIT ( s ) , s - > main_pid ) ;
s - > main_pid = 0 ;
}
2012-01-19 23:58:07 +01:00
static void service_unwatch_pid_file ( Service * s ) {
if ( ! s - > pid_file_pathspec )
return ;
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id , " Stopping watch for %s's PID file %s " ,
UNIT ( s ) - > id , s - > pid_file_pathspec - > path ) ;
2013-11-19 21:12:59 +01:00
path_spec_unwatch ( s - > pid_file_pathspec ) ;
2012-01-19 23:58:07 +01:00
path_spec_done ( s - > pid_file_pathspec ) ;
free ( s - > pid_file_pathspec ) ;
s - > pid_file_pathspec = NULL ;
}
2010-06-17 22:55:53 +02:00
static int service_set_main_pid ( Service * s , pid_t pid ) {
2010-06-18 22:05:29 +02:00
pid_t ppid ;
2010-06-17 22:55:53 +02:00
assert ( s ) ;
if ( pid < = 1 )
return - EINVAL ;
if ( pid = = getpid ( ) )
return - EINVAL ;
2013-10-01 05:06:56 +02:00
if ( s - > main_pid = = pid & & s - > main_pid_known )
return 0 ;
if ( s - > main_pid ! = pid ) {
service_unwatch_main_pid ( s ) ;
exec_status_start ( & s - > main_exec_status , pid ) ;
}
2013-08-09 16:40:57 +02:00
2011-04-28 04:56:53 +02:00
s - > main_pid = pid ;
s - > main_pid_known = true ;
if ( get_parent_of_pid ( pid , & ppid ) > = 0 & & ppid ! = getpid ( ) ) {
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" %s: Supervising process " PID_FMT " which is not our child. We'll most likely not notice when it exits. " ,
UNIT ( s ) - > id , pid ) ;
2010-06-18 22:05:29 +02:00
2011-04-28 04:56:53 +02:00
s - > main_pid_alien = true ;
} else
s - > main_pid_alien = false ;
2010-06-17 22:55:53 +02:00
return 0 ;
}
2010-04-15 06:19:54 +02:00
static void service_close_socket_fd ( Service * s ) {
assert ( s ) ;
if ( s - > socket_fd < 0 )
return ;
2014-03-18 19:22:43 +01:00
s - > socket_fd = safe_close ( s - > socket_fd ) ;
2010-04-15 06:19:54 +02:00
}
2010-06-19 04:25:28 +02:00
static void service_connection_unref ( Service * s ) {
assert ( s ) ;
2013-06-20 03:45:08 +02:00
if ( ! UNIT_ISSET ( s - > accept_socket ) )
2010-06-19 04:25:28 +02:00
return ;
2012-01-06 23:08:54 +01:00
socket_connection_unref ( SOCKET ( UNIT_DEREF ( s - > accept_socket ) ) ) ;
unit_ref_unset ( & s - > accept_socket ) ;
2010-06-19 04:25:28 +02:00
}
2012-02-01 17:17:12 +01:00
static void service_stop_watchdog ( Service * s ) {
assert ( s ) ;
2013-11-19 21:12:59 +01:00
s - > watchdog_event_source = sd_event_source_unref ( s - > watchdog_event_source ) ;
2013-12-11 20:49:43 +01:00
s - > watchdog_timestamp = DUAL_TIMESTAMP_NULL ;
2012-02-01 17:17:12 +01:00
}
2013-12-11 20:49:43 +01:00
static void service_start_watchdog ( Service * s ) {
2012-02-08 10:10:34 +01:00
int r ;
assert ( s ) ;
2013-12-11 20:49:43 +01:00
if ( s - > watchdog_usec < = 0 )
2012-02-08 10:10:34 +01:00
return ;
2013-11-19 21:12:59 +01:00
if ( s - > watchdog_event_source ) {
r = sd_event_source_set_time ( s - > watchdog_event_source , s - > watchdog_timestamp . monotonic + s - > watchdog_usec ) ;
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " %s failed to reset watchdog timer: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
return ;
}
2013-12-11 20:49:43 +01:00
r = sd_event_source_set_enabled ( s - > watchdog_event_source , SD_EVENT_ONESHOT ) ;
2013-12-12 20:16:06 +01:00
} else {
2014-03-24 02:49:09 +01:00
r = sd_event_add_time (
UNIT ( s ) - > manager - > event ,
& s - > watchdog_event_source ,
CLOCK_MONOTONIC ,
s - > watchdog_timestamp . monotonic + s - > watchdog_usec , 0 ,
service_dispatch_watchdog , s ) ;
2013-12-12 20:16:06 +01:00
if ( r < 0 ) {
log_warning_unit ( UNIT ( s ) - > id , " %s failed to add watchdog timer: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
return ;
}
/* Let's process everything else which might be a sign
* of living before we consider a service died . */
r = sd_event_source_set_priority ( s - > watchdog_event_source , SD_EVENT_PRIORITY_IDLE ) ;
}
2013-11-19 21:12:59 +01:00
2012-02-08 10:10:34 +01:00
if ( r < 0 )
2013-12-11 20:49:43 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s failed to install watchdog timer: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-08 10:10:34 +01:00
}
2012-02-01 17:17:12 +01:00
static void service_reset_watchdog ( Service * s ) {
assert ( s ) ;
dual_timestamp_get ( & s - > watchdog_timestamp ) ;
2013-12-11 20:49:43 +01:00
service_start_watchdog ( s ) ;
2012-02-01 17:17:12 +01:00
}
2010-01-26 21:39:06 +01:00
static void service_done ( Unit * u ) {
Service * s = SERVICE ( u ) ;
2010-01-26 07:02:51 +01:00
assert ( s ) ;
free ( s - > pid_file ) ;
s - > pid_file = NULL ;
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2010-04-07 20:27:52 +02:00
free ( s - > sysv_runlevels ) ;
s - > sysv_runlevels = NULL ;
2010-09-21 05:23:12 +02:00
# endif
2010-04-07 20:27:52 +02:00
2010-06-16 05:10:31 +02:00
free ( s - > status_text ) ;
s - > status_text = NULL ;
2014-03-25 14:15:45 +01:00
free ( s - > reboot_arg ) ;
s - > reboot_arg = NULL ;
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 , _SERVICE_EXEC_COMMAND_MAX ) ;
2010-01-26 07:02:51 +01:00
s - > control_command = NULL ;
2011-01-20 18:46:38 +01:00
s - > main_command = NULL ;
2010-01-26 07:02:51 +01:00
2012-08-13 13:58:01 +02:00
set_free ( s - > restart_ignore_status . code ) ;
s - > restart_ignore_status . code = NULL ;
set_free ( s - > restart_ignore_status . signal ) ;
s - > restart_ignore_status . signal = NULL ;
set_free ( s - > success_status . code ) ;
s - > success_status . code = NULL ;
set_free ( s - > success_status . signal ) ;
s - > success_status . signal = NULL ;
2010-01-26 07:02:51 +01:00
/* This will leak a process, but at least no memory or any of
* our resources */
2010-04-11 00:22:36 +02:00
service_unwatch_main_pid ( s ) ;
service_unwatch_control_pid ( s ) ;
2012-01-19 23:58:07 +01:00
service_unwatch_pid_file ( s ) ;
2010-01-26 07:02:51 +01:00
2010-04-15 23:16:16 +02:00
if ( s - > bus_name ) {
2012-01-15 12:04:08 +01:00
unit_unwatch_bus_name ( u , s - > bus_name ) ;
2010-04-15 23:16:16 +02:00
free ( s - > bus_name ) ;
s - > bus_name = NULL ;
}
2010-04-15 06:19:54 +02:00
service_close_socket_fd ( s ) ;
2010-06-19 04:25:28 +02:00
service_connection_unref ( s ) ;
2010-04-15 06:19:54 +02:00
2012-01-06 23:08:54 +01:00
unit_ref_unset ( & s - > accept_socket ) ;
2010-10-05 19:49:15 +02:00
2012-02-08 10:10:34 +01:00
service_stop_watchdog ( s ) ;
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
}
static int service_arm_timer ( Service * s , usec_t usec ) {
int r ;
assert ( s ) ;
if ( s - > timer_event_source ) {
r = sd_event_source_set_time ( s - > timer_event_source , now ( CLOCK_MONOTONIC ) + 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 ) + usec , 0 ,
service_dispatch_timer , s ) ;
2010-01-26 07:02:51 +01:00
}
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2010-05-19 03:44:07 +02:00
static char * sysv_translate_name ( const char * name ) {
char * r ;
2014-03-15 19:40:07 +01:00
r = new ( char , strlen ( name ) + strlen ( " .service " ) + 1 ) ;
2013-01-16 21:09:03 +01:00
if ( ! r )
2010-05-19 03:44:07 +02:00
return NULL ;
2010-12-27 18:41:54 +01:00
if ( endswith ( name , " .sh " ) )
2013-01-12 23:31:46 +01:00
/* Drop .sh suffix */
2010-12-27 18:41:54 +01:00
strcpy ( stpcpy ( r , name ) - 3 , " .service " ) ;
2010-05-19 03:44:07 +02:00
else
2013-01-12 23:31:46 +01:00
/* Normal init script name */
2010-05-19 03:44:07 +02:00
strcpy ( stpcpy ( r , name ) , " .service " ) ;
return r ;
}
2010-09-28 21:08:39 +02:00
static int sysv_translate_facility ( const char * name , const char * filename , char * * _r ) {
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:02 +02:00
/* We silently ignore the $ prefix here. According to the LSB
* spec it simply indicates whether something is a
* standardized name or a distribution - specific one . Since we
* just follow what already exists and do not introduce new
* uses or names we don ' t care who introduced a new name . */
2010-02-14 01:09:01 +01:00
static const char * const table [ ] = {
2010-05-24 19:56:25 +02:00
/* LSB defined facilities */
2013-01-16 21:09:03 +01:00
" local_fs " , NULL ,
2010-09-28 18:30:02 +02:00
" network " , SPECIAL_NETWORK_TARGET ,
" named " , SPECIAL_NSS_LOOKUP_TARGET ,
" portmap " , SPECIAL_RPCBIND_TARGET ,
" remote_fs " , SPECIAL_REMOTE_FS_TARGET ,
2013-01-16 21:09:03 +01:00
" syslog " , NULL ,
2011-04-06 19:18:11 +02:00
" time " , SPECIAL_TIME_SYNC_TARGET ,
2010-02-14 01:09:01 +01:00
} ;
unsigned i ;
char * r ;
2010-09-28 21:08:39 +02:00
const char * n ;
2010-02-14 01:09:01 +01:00
2010-09-28 21:08:39 +02:00
assert ( name ) ;
assert ( _r ) ;
2010-09-28 18:30:02 +02:00
2010-09-28 21:08:39 +02:00
n = * name = = ' $ ' ? name + 1 : name ;
2010-09-28 18:30:02 +02:00
2010-09-28 21:08:39 +02:00
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + = 2 ) {
2010-09-28 18:30:02 +02:00
2010-09-28 21:08:39 +02:00
if ( ! streq ( table [ i ] , n ) )
continue ;
2010-02-14 01:09:01 +01:00
2010-09-28 21:08:39 +02:00
if ( ! table [ i + 1 ] )
return 0 ;
2013-01-16 21:09:03 +01:00
r = strdup ( table [ i + 1 ] ) ;
if ( ! r )
return log_oom ( ) ;
2010-09-28 21:08:39 +02:00
goto finish ;
}
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:02 +02:00
/* If we don't know this name, fallback heuristics to figure
2010-10-14 00:54:48 +02:00
* out whether something is a target or a service alias . */
2010-09-28 18:30:02 +02:00
2011-01-06 23:52:58 +01:00
if ( * name = = ' $ ' ) {
if ( ! unit_prefix_is_valid ( n ) )
return - EINVAL ;
2010-09-28 21:08:39 +02:00
/* Facilities starting with $ are most likely targets */
r = unit_name_build ( n , NULL , " .target " ) ;
2011-01-06 23:52:58 +01:00
} else if ( filename & & streq ( name , filename ) )
2011-02-21 15:32:17 +01:00
/* Names equaling the file name of the services are redundant */
2010-09-28 21:08:39 +02:00
return 0 ;
2010-09-13 23:54:21 +02:00
else
2010-09-28 21:08:39 +02:00
/* Everything else we assume to be normal service names */
r = sysv_translate_name ( n ) ;
2010-02-14 01:09:01 +01:00
2010-09-13 23:54:21 +02:00
if ( ! r )
2010-02-14 01:09:01 +01:00
return - ENOMEM ;
finish :
2011-03-04 14:54:15 +01:00
* _r = r ;
2010-02-14 01:09:01 +01:00
return 1 ;
}
2010-05-19 03:44:37 +02:00
static int sysv_fix_order ( Service * s ) {
2012-01-15 12:04:08 +01:00
Unit * other ;
2010-02-14 01:09:01 +01:00
int r ;
assert ( s ) ;
if ( s - > sysv_start_priority < 0 )
return 0 ;
2010-04-06 02:43:58 +02:00
/* For each pair of services where at least one lacks a LSB
* header , we use the start priority value to order things . */
2010-02-14 01:09:01 +01:00
2012-01-15 12:25:20 +01:00
LIST_FOREACH ( units_by_type , other , UNIT ( s ) - > manager - > units_by_type [ UNIT_SERVICE ] ) {
2010-02-14 01:09:01 +01:00
Service * t ;
UnitDependency d ;
2010-08-05 19:46:31 +02:00
bool special_s , special_t ;
2010-02-14 01:09:01 +01:00
2012-01-15 12:37:16 +01:00
t = SERVICE ( other ) ;
2010-02-14 01:09:01 +01:00
if ( s = = t )
continue ;
2010-09-27 23:24:17 +02:00
2012-01-15 12:25:20 +01:00
if ( UNIT ( t ) - > load_state ! = UNIT_LOADED )
2010-09-27 23:24:17 +02:00
continue ;
2010-02-14 01:09:01 +01:00
if ( t - > sysv_start_priority < 0 )
continue ;
2010-04-10 05:05:05 +02:00
/* If both units have modern headers we don't care
* about the priorities */
2012-01-15 12:25:20 +01:00
if ( ( UNIT ( s ) - > fragment_path | | s - > sysv_has_lsb ) & &
( UNIT ( t ) - > fragment_path | | t - > sysv_has_lsb ) )
2010-04-06 02:43:58 +02:00
continue ;
2010-08-05 19:46:31 +02:00
special_s = s - > sysv_runlevels & & ! chars_intersect ( RUNLEVELS_UP , s - > sysv_runlevels ) ;
special_t = t - > sysv_runlevels & & ! chars_intersect ( RUNLEVELS_UP , t - > sysv_runlevels ) ;
if ( special_t & & ! special_s )
d = UNIT_AFTER ;
else if ( special_s & & ! special_t )
d = UNIT_BEFORE ;
else if ( t - > sysv_start_priority < s - > sysv_start_priority )
2010-02-14 01:09:01 +01:00
d = UNIT_AFTER ;
else if ( t - > sysv_start_priority > s - > sysv_start_priority )
d = UNIT_BEFORE ;
else
continue ;
/* FIXME: Maybe we should compare the name here lexicographically? */
2011-03-31 15:35:40 +02:00
if ( ( r = unit_add_dependency ( UNIT ( s ) , d , UNIT ( t ) , true ) ) < 0 )
2010-02-14 01:09:01 +01:00
return r ;
}
return 0 ;
}
static ExecCommand * exec_command_new ( const char * path , const char * arg1 ) {
ExecCommand * c ;
if ( ! ( c = new0 ( ExecCommand , 1 ) ) )
return NULL ;
if ( ! ( c - > path = strdup ( path ) ) ) {
free ( c ) ;
return NULL ;
}
if ( ! ( c - > argv = strv_new ( path , arg1 , NULL ) ) ) {
free ( c - > path ) ;
free ( c ) ;
return NULL ;
}
return c ;
}
2012-10-16 10:14:03 +02:00
static int sysv_exec_commands ( Service * s , const bool supports_reload ) {
2010-02-14 01:09:01 +01:00
ExecCommand * c ;
assert ( s ) ;
2012-05-22 23:08:24 +02:00
assert ( s - > is_sysv ) ;
assert ( UNIT ( s ) - > source_path ) ;
2010-02-14 01:09:01 +01:00
2012-05-22 23:08:24 +02:00
c = exec_command_new ( UNIT ( s ) - > source_path , " start " ) ;
if ( ! c )
2010-02-14 01:09:01 +01:00
return - ENOMEM ;
exec_command_append_list ( s - > exec_command + SERVICE_EXEC_START , c ) ;
2012-05-22 23:08:24 +02:00
c = exec_command_new ( UNIT ( s ) - > source_path , " stop " ) ;
if ( ! c )
2010-02-14 01:09:01 +01:00
return - ENOMEM ;
exec_command_append_list ( s - > exec_command + SERVICE_EXEC_STOP , c ) ;
2012-10-16 10:14:03 +02:00
if ( supports_reload ) {
c = exec_command_new ( UNIT ( s ) - > source_path , " reload " ) ;
if ( ! c )
return - ENOMEM ;
exec_command_append_list ( s - > exec_command + SERVICE_EXEC_RELOAD , c ) ;
}
2010-02-14 01:09:01 +01:00
return 0 ;
}
2012-10-16 10:14:03 +02:00
static bool usage_contains_reload ( const char * line ) {
return ( strcasestr ( line , " {reload| " ) | |
strcasestr ( line , " {reload} " ) | |
strcasestr ( line , " {reload \" " ) | |
strcasestr ( line , " |reload| " ) | |
strcasestr ( line , " |reload} " ) | |
strcasestr ( line , " |reload \" " ) ) ;
}
2010-04-10 17:53:17 +02:00
static int service_load_sysv_path ( Service * s , const char * path ) {
2010-02-14 01:09:01 +01:00
FILE * f ;
Unit * u ;
unsigned line = 0 ;
int r ;
enum {
NORMAL ,
DESCRIPTION ,
LSB ,
2012-10-16 10:14:03 +02:00
LSB_DESCRIPTION ,
USAGE_CONTINUATION
2010-02-14 01:09:01 +01:00
} state = NORMAL ;
2010-09-28 18:30:32 +02:00
char * short_description = NULL , * long_description = NULL , * chkconfig_description = NULL , * description ;
2011-06-15 15:34:19 +02:00
struct stat st ;
2012-10-16 10:14:03 +02:00
bool supports_reload = false ;
2010-04-06 02:43:58 +02:00
assert ( s ) ;
assert ( path ) ;
2010-02-14 01:09:01 +01:00
u = UNIT ( s ) ;
2012-05-22 23:08:24 +02:00
f = fopen ( path , " re " ) ;
if ( ! f ) {
2010-02-14 01:09:01 +01:00
r = errno = = ENOENT ? 0 : - errno ;
goto finish ;
}
2011-06-15 15:34:19 +02:00
if ( fstat ( fileno ( f ) , & st ) < 0 ) {
r = - errno ;
goto finish ;
}
2012-05-22 23:08:24 +02:00
free ( u - > source_path ) ;
u - > source_path = strdup ( path ) ;
if ( ! u - > source_path ) {
2010-02-14 01:09:01 +01:00
r = - ENOMEM ;
goto finish ;
}
2012-05-22 23:08:24 +02:00
u - > source_mtime = timespec_load ( & st . st_mtim ) ;
2011-06-15 15:34:19 +02:00
if ( null_or_empty ( & st ) ) {
2012-01-15 12:04:08 +01:00
u - > load_state = UNIT_MASKED ;
2011-06-15 15:34:19 +02:00
r = 0 ;
goto finish ;
}
2012-05-22 23:08:24 +02:00
s - > is_sysv = true ;
2010-02-14 01:09:01 +01:00
while ( ! feof ( f ) ) {
char l [ LINE_MAX ] , * t ;
if ( ! fgets ( l , sizeof ( l ) , f ) ) {
if ( feof ( f ) )
break ;
r = - errno ;
2013-01-05 18:00:35 +01:00
log_error_unit ( u - > id ,
" Failed to read configuration file '%s': %s " ,
path , strerror ( - r ) ) ;
2010-02-14 01:09:01 +01:00
goto finish ;
}
line + + ;
t = strstrip ( l ) ;
2012-10-16 10:14:03 +02:00
if ( * t ! = ' # ' ) {
/* Try to figure out whether this init script supports
* the reload operation . This heuristic looks for
* " Usage " lines which include the reload option . */
if ( state = = USAGE_CONTINUATION | |
( state = = NORMAL & & strcasestr ( t , " usage " ) ) ) {
if ( usage_contains_reload ( t ) ) {
supports_reload = true ;
state = NORMAL ;
} else if ( t [ strlen ( t ) - 1 ] = = ' \\ ' )
state = USAGE_CONTINUATION ;
else
state = NORMAL ;
}
2010-02-14 01:09:01 +01:00
continue ;
2012-10-16 10:14:03 +02:00
}
2010-02-14 01:09:01 +01:00
if ( state = = NORMAL & & streq ( t , " ### BEGIN INIT INFO " ) ) {
state = LSB ;
2010-04-06 02:43:58 +02:00
s - > sysv_has_lsb = true ;
2010-02-14 01:09:01 +01:00
continue ;
}
if ( ( state = = LSB_DESCRIPTION | | state = = LSB ) & & streq ( t , " ### END INIT INFO " ) ) {
state = NORMAL ;
continue ;
}
t + + ;
t + = strspn ( t , WHITESPACE ) ;
if ( state = = NORMAL ) {
/* Try to parse Red Hat style chkconfig headers */
2010-05-24 19:23:11 +02:00
if ( startswith_no_case ( t , " chkconfig: " ) ) {
2010-02-14 01:09:01 +01:00
int start_priority ;
2010-04-07 20:27:52 +02:00
char runlevels [ 16 ] , * k ;
2010-02-14 01:09:01 +01:00
state = NORMAL ;
2014-03-24 19:55:47 +01:00
if ( sscanf ( t + 10 , " %15s %i %*i " , runlevels , & start_priority ) ! = 2 ) {
log_warning_unit ( u - > id , " [%s:%u] Failed to parse chkconfig line. Ignoring. " , path , line ) ;
2010-02-14 01:09:01 +01:00
continue ;
}
2010-05-13 22:24:22 +02:00
/* A start priority gathered from the
* symlink farms is preferred over the
* data from the LSB header . */
2010-04-07 20:27:52 +02:00
if ( start_priority < 0 | | start_priority > 99 )
2014-03-24 19:55:47 +01:00
log_warning_unit ( u - > id , " [%s:%u] Start priority out of range. Ignoring. " , path , line ) ;
2011-03-30 00:43:16 +02:00
else
2014-03-24 19:55:47 +01:00
log_debug_unit ( u - > id , " [%s:%u] Ignoring start priority set in the chkconfig file. " , path , line ) ;
2010-04-07 20:27:52 +02:00
char_array_0 ( runlevels ) ;
k = delete_chars ( runlevels , WHITESPACE " - " ) ;
if ( k [ 0 ] ) {
char * d ;
2014-03-24 19:55:47 +01:00
d = strdup ( k ) ;
if ( ! d ) {
2010-04-07 20:27:52 +02:00
r = - ENOMEM ;
goto finish ;
}
free ( s - > sysv_runlevels ) ;
s - > sysv_runlevels = d ;
2010-02-14 01:09:01 +01:00
}
2010-09-28 18:30:32 +02:00
} else if ( startswith_no_case ( t , " description: " ) ) {
2010-02-14 01:09:01 +01:00
size_t k = strlen ( t ) ;
char * d ;
2010-09-28 18:30:32 +02:00
const char * j ;
2010-02-14 01:09:01 +01:00
if ( t [ k - 1 ] = = ' \\ ' ) {
state = DESCRIPTION ;
t [ k - 1 ] = 0 ;
}
2010-09-28 18:30:32 +02:00
if ( ( j = strstrip ( t + 12 ) ) & & * j ) {
if ( ! ( d = strdup ( j ) ) ) {
r = - ENOMEM ;
goto finish ;
}
} else
d = NULL ;
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
free ( chkconfig_description ) ;
chkconfig_description = d ;
2010-02-14 01:09:01 +01:00
2010-05-24 19:23:11 +02:00
} else if ( startswith_no_case ( t , " pidfile: " ) ) {
2010-02-14 01:09:01 +01:00
char * fn ;
state = NORMAL ;
fn = strstrip ( t + 8 ) ;
if ( ! path_is_absolute ( fn ) ) {
2013-01-05 18:00:35 +01:00
log_warning_unit ( u - > id ,
" [%s:%u] PID file not absolute. Ignoring. " ,
path , line ) ;
2010-02-14 01:09:01 +01:00
continue ;
}
if ( ! ( fn = strdup ( fn ) ) ) {
r = - ENOMEM ;
goto finish ;
}
free ( s - > pid_file ) ;
s - > pid_file = fn ;
}
} else if ( state = = DESCRIPTION ) {
/* Try to parse Red Hat style description
* continuation */
size_t k = strlen ( t ) ;
2010-09-28 18:30:32 +02:00
char * j ;
2010-02-14 01:09:01 +01:00
if ( t [ k - 1 ] = = ' \\ ' )
t [ k - 1 ] = 0 ;
else
state = NORMAL ;
2010-09-28 18:30:32 +02:00
if ( ( j = strstrip ( t ) ) & & * j ) {
char * d = NULL ;
if ( chkconfig_description )
2012-07-13 13:41:01 +02:00
d = strjoin ( chkconfig_description , " " , j , NULL ) ;
2010-09-28 18:30:32 +02:00
else
d = strdup ( j ) ;
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
if ( ! d ) {
r = - ENOMEM ;
goto finish ;
}
free ( chkconfig_description ) ;
chkconfig_description = d ;
}
2010-02-14 01:09:01 +01:00
} else if ( state = = LSB | | state = = LSB_DESCRIPTION ) {
2010-05-24 19:23:11 +02:00
if ( startswith_no_case ( t , " Provides: " ) ) {
2010-02-14 01:09:01 +01:00
char * i , * w ;
size_t z ;
state = LSB ;
2010-07-07 20:58:41 +02:00
FOREACH_WORD_QUOTED ( w , z , t + 9 , i ) {
2010-02-14 01:09:01 +01:00
char * n , * m ;
if ( ! ( n = strndup ( w , z ) ) ) {
r = - ENOMEM ;
goto finish ;
}
2013-12-07 03:29:55 +01:00
r = sysv_translate_facility ( n , basename ( path ) , & m ) ;
2010-02-14 01:09:01 +01:00
free ( n ) ;
if ( r < 0 )
goto finish ;
if ( r = = 0 )
continue ;
2010-04-01 21:30:40 +02:00
if ( unit_name_to_type ( m ) = = UNIT_SERVICE )
2013-03-21 15:40:45 +01:00
r = unit_merge_by_name ( u , m ) ;
2011-03-18 05:26:25 +01:00
else
/* NB: SysV targets
* which are provided
* by a service are
* pulled in by the
* services , as an
* indication that the
* generic service is
* now available . This
* is strictly
* one - way . The
* targets do NOT pull
* in the SysV
* services ! */
r = unit_add_two_dependencies_by_name ( u , UNIT_BEFORE , UNIT_WANTS , m , NULL , true ) ;
2010-04-01 21:30:40 +02:00
2010-02-14 01:09:01 +01:00
if ( r < 0 )
2013-01-05 18:00:35 +01:00
log_error_unit ( u - > id ,
" [%s:%u] Failed to add LSB Provides name %s, ignoring: %s " ,
path , line , m , strerror ( - r ) ) ;
2010-08-26 04:08:28 +02:00
free ( m ) ;
2010-02-14 01:09:01 +01:00
}
2010-05-24 19:23:11 +02:00
} else if ( startswith_no_case ( t , " Required-Start: " ) | |
startswith_no_case ( t , " Should-Start: " ) | |
startswith_no_case ( t , " X-Start-Before: " ) | |
startswith_no_case ( t , " X-Start-After: " ) ) {
2010-02-14 01:09:01 +01:00
char * i , * w ;
size_t z ;
state = LSB ;
2010-07-07 20:58:41 +02:00
FOREACH_WORD_QUOTED ( w , z , strchr ( t , ' : ' ) + 1 , i ) {
2010-02-14 01:09:01 +01:00
char * n , * m ;
if ( ! ( n = strndup ( w , z ) ) ) {
r = - ENOMEM ;
goto finish ;
}
2013-12-07 03:29:55 +01:00
r = sysv_translate_facility ( n , basename ( path ) , & m ) ;
2011-01-06 23:52:58 +01:00
if ( r < 0 ) {
2013-01-05 18:00:35 +01:00
log_error_unit ( u - > id ,
" [%s:%u] Failed to translate LSB dependency %s, ignoring: %s " ,
path , line , n , strerror ( - r ) ) ;
2011-01-06 23:52:58 +01:00
free ( n ) ;
continue ;
}
free ( n ) ;
2010-02-14 01:09:01 +01:00
if ( r = = 0 )
continue ;
2010-05-24 19:23:11 +02:00
r = unit_add_dependency_by_name ( u , startswith_no_case ( t , " X-Start-Before: " ) ? UNIT_BEFORE : UNIT_AFTER , m , NULL , true ) ;
2010-02-14 01:09:01 +01:00
if ( r < 0 )
2013-01-05 18:00:35 +01:00
log_error_unit ( u - > id , " [%s:%u] Failed to add dependency on %s, ignoring: %s " ,
path , line , m , strerror ( - r ) ) ;
2010-08-26 04:08:28 +02:00
free ( m ) ;
2010-02-14 01:09:01 +01:00
}
2010-05-24 19:23:11 +02:00
} else if ( startswith_no_case ( t , " Default-Start: " ) ) {
2010-04-07 20:27:52 +02:00
char * k , * d ;
state = LSB ;
k = delete_chars ( t + 14 , WHITESPACE " - " ) ;
if ( k [ 0 ] ! = 0 ) {
if ( ! ( d = strdup ( k ) ) ) {
r = - ENOMEM ;
goto finish ;
}
free ( s - > sysv_runlevels ) ;
s - > sysv_runlevels = d ;
}
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
} else if ( startswith_no_case ( t , " Description: " ) ) {
char * d , * j ;
2010-07-07 02:16:14 +02:00
2010-02-14 01:09:01 +01:00
state = LSB_DESCRIPTION ;
2010-09-28 18:30:32 +02:00
if ( ( j = strstrip ( t + 12 ) ) & & * j ) {
if ( ! ( d = strdup ( j ) ) ) {
r = - ENOMEM ;
goto finish ;
}
} else
d = NULL ;
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
free ( long_description ) ;
long_description = d ;
2010-02-14 01:09:01 +01:00
2010-07-07 02:16:14 +02:00
} else if ( startswith_no_case ( t , " Short-Description: " ) ) {
2010-09-28 18:30:32 +02:00
char * d , * j ;
2010-02-14 01:09:01 +01:00
state = LSB ;
2010-09-28 18:30:32 +02:00
if ( ( j = strstrip ( t + 18 ) ) & & * j ) {
if ( ! ( d = strdup ( j ) ) ) {
r = - ENOMEM ;
goto finish ;
}
} else
d = NULL ;
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
free ( short_description ) ;
short_description = d ;
2010-02-14 01:09:01 +01:00
} else if ( state = = LSB_DESCRIPTION ) {
if ( startswith ( l , " # \t " ) | | startswith ( l , " # " ) ) {
2010-09-28 18:30:32 +02:00
char * j ;
2010-02-14 01:09:01 +01:00
2010-09-28 18:30:32 +02:00
if ( ( j = strstrip ( t ) ) & & * j ) {
char * d = NULL ;
if ( long_description )
2012-07-13 13:41:01 +02:00
d = strjoin ( long_description , " " , t , NULL ) ;
2010-09-28 18:30:32 +02:00
else
d = strdup ( j ) ;
if ( ! d ) {
r = - ENOMEM ;
goto finish ;
}
free ( long_description ) ;
long_description = d ;
2010-02-14 01:09:01 +01:00
}
} else
state = LSB ;
}
}
}
2012-10-16 10:14:03 +02:00
if ( ( r = sysv_exec_commands ( s , supports_reload ) ) < 0 )
2010-02-14 01:09:01 +01:00
goto finish ;
2010-07-03 19:48:33 +02:00
if ( s - > sysv_runlevels & & ! chars_intersect ( RUNLEVELS_UP , s - > sysv_runlevels ) ) {
2010-04-07 20:28:44 +02:00
/* If there a runlevels configured for this service
* but none of the standard ones , then we assume this
* is some special kind of service ( which might be
* needed for early boot ) and don ' t create any links
* to it . */
2012-01-15 12:25:20 +01:00
UNIT ( s ) - > default_dependencies = false ;
2010-04-24 05:02:25 +02:00
/* Don't timeout special services during boot (like fsck) */
2012-08-07 14:41:48 +02:00
s - > timeout_start_usec = 0 ;
s - > timeout_stop_usec = 0 ;
} else {
s - > timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC ;
s - > timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC ;
}
2010-04-13 02:06:27 +02:00
/* Special setting for all SysV services */
2010-06-02 19:15:42 +02:00
s - > type = SERVICE_FORKING ;
2011-07-05 10:14:12 +02:00
s - > remain_after_exit = ! s - > pid_file ;
2011-10-11 20:21:06 +02:00
s - > guess_main_pid = false ;
2010-10-05 20:30:44 +02:00
s - > restart = SERVICE_RESTART_NO ;
2012-02-09 03:18:04 +01:00
s - > exec_context . ignore_sigpipe = false ;
2012-07-19 23:47:10 +02:00
s - > kill_context . kill_mode = KILL_PROCESS ;
2010-04-13 02:06:27 +02:00
2010-09-28 18:30:32 +02:00
/* We use the long description only if
* no short description is set . */
if ( short_description )
description = short_description ;
else if ( chkconfig_description )
description = chkconfig_description ;
else if ( long_description )
description = long_description ;
else
description = NULL ;
if ( description ) {
char * d ;
2011-03-08 18:51:20 +01:00
if ( ! ( d = strappend ( s - > sysv_has_lsb ? " LSB: " : " SYSV: " , description ) ) ) {
2010-09-28 18:30:32 +02:00
r = - ENOMEM ;
goto finish ;
}
2012-01-15 12:04:08 +01:00
u - > description = d ;
2010-09-28 18:30:32 +02:00
}
2014-03-24 19:55:47 +01:00
/* Initialize the start priority from what has been set in the
* / etc / rcN . d / hierarchies if we load the unit file as SysV
* init script . */
2011-03-30 00:43:16 +02:00
if ( s - > sysv_start_priority_from_rcnd > = 0 )
s - > sysv_start_priority = s - > sysv_start_priority_from_rcnd ;
2012-01-15 12:04:08 +01:00
u - > load_state = UNIT_LOADED ;
2010-04-06 02:43:58 +02:00
r = 0 ;
2010-02-14 01:09:01 +01:00
finish :
if ( f )
fclose ( f ) ;
2010-09-28 18:30:32 +02:00
free ( short_description ) ;
free ( long_description ) ;
free ( chkconfig_description ) ;
2010-02-14 01:09:01 +01:00
return r ;
}
2010-04-10 17:53:17 +02:00
static int service_load_sysv_name ( Service * s , const char * name ) {
2010-02-14 01:09:01 +01:00
char * * p ;
assert ( s ) ;
assert ( name ) ;
2013-06-28 04:12:58 +02:00
/* For SysV services we strip the *.sh suffixes. */
2013-03-24 10:06:38 +01:00
if ( endswith ( name , " .sh.service " ) )
2010-05-19 21:52:30 +02:00
return - ENOENT ;
2012-01-15 12:25:20 +01:00
STRV_FOREACH ( p , UNIT ( s ) - > manager - > lookup_paths . sysvinit_path ) {
2010-02-14 01:09:01 +01:00
char * path ;
int r ;
2012-07-13 13:41:01 +02:00
path = strjoin ( * p , " / " , name , NULL ) ;
2011-08-01 02:39:22 +02:00
if ( ! path )
2010-02-14 01:09:01 +01:00
return - ENOMEM ;
assert ( endswith ( path , " .service " ) ) ;
path [ strlen ( path ) - 8 ] = 0 ;
2010-04-10 17:53:17 +02:00
r = service_load_sysv_path ( s , path ) ;
2010-05-13 22:24:22 +02:00
2012-01-15 12:25:20 +01:00
if ( r > = 0 & & UNIT ( s ) - > load_state = = UNIT_STUB ) {
2013-01-12 23:50:56 +01:00
/* Try *.sh source'able init scripts */
2010-05-13 22:24:22 +02:00
strcat ( path , " .sh " ) ;
r = service_load_sysv_path ( s , path ) ;
}
2010-02-14 01:09:01 +01:00
free ( path ) ;
2010-04-06 02:43:58 +02:00
if ( r < 0 )
2010-02-14 01:09:01 +01:00
return r ;
2010-04-06 02:43:58 +02:00
2013-01-04 22:43:41 +01:00
if ( UNIT ( s ) - > load_state ! = UNIT_STUB )
2010-04-06 02:43:58 +02:00
break ;
2010-02-14 01:09:01 +01:00
}
return 0 ;
}
2010-04-10 17:53:17 +02:00
static int service_load_sysv ( Service * s ) {
2010-02-14 01:09:01 +01:00
const char * t ;
Iterator i ;
int r ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
/* Load service data from SysV init scripts, preferably with
* LSB headers . . . */
2012-01-15 12:25:20 +01:00
if ( strv_isempty ( UNIT ( s ) - > manager - > lookup_paths . sysvinit_path ) )
2010-02-14 01:09:01 +01:00
return 0 ;
2012-01-15 12:25:20 +01:00
if ( ( t = UNIT ( s ) - > id ) )
2010-04-10 17:53:17 +02:00
if ( ( r = service_load_sysv_name ( s , t ) ) < 0 )
2010-02-14 01:09:01 +01:00
return r ;
2012-01-15 12:25:20 +01:00
if ( UNIT ( s ) - > load_state = = UNIT_STUB )
SET_FOREACH ( t , UNIT ( s ) - > names , i ) {
if ( t = = UNIT ( s ) - > id )
2010-04-10 17:53:17 +02:00
continue ;
2010-08-11 22:04:22 +02:00
if ( ( r = service_load_sysv_name ( s , t ) ) < 0 )
2010-04-06 02:43:58 +02:00
return r ;
2012-01-15 12:25:20 +01:00
if ( UNIT ( s ) - > load_state ! = UNIT_STUB )
2010-04-06 02:43:58 +02:00
break ;
}
2010-02-14 01:09:01 +01:00
return 0 ;
2010-01-23 01:52:57 +01:00
}
2010-09-21 05:23:12 +02:00
# endif
2010-01-23 01:52:57 +01:00
2010-04-13 04:00:03 +02:00
static int service_verify ( Service * s ) {
assert ( s ) ;
2012-01-15 12:25:20 +01:00
if ( UNIT ( s ) - > load_state ! = UNIT_LOADED )
2010-04-13 04:00:03 +02:00
return 0 ;
if ( ! s - > exec_command [ SERVICE_EXEC_START ] ) {
2014-01-29 13:49:54 +01:00
log_error_unit ( UNIT ( s ) - > id , " %s lacks ExecStart setting. Refusing. " , UNIT ( s ) - > id ) ;
2010-04-13 04:00:03 +02:00
return - EINVAL ;
}
2010-08-13 18:23:01 +02:00
if ( s - > type ! = SERVICE_ONESHOT & &
s - > exec_command [ SERVICE_EXEC_START ] - > command_next ) {
2014-01-29 13:49:54 +01:00
log_error_unit ( UNIT ( s ) - > id , " %s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing. " , UNIT ( s ) - > id ) ;
2010-06-19 04:25:28 +02:00
return - EINVAL ;
}
2013-08-09 12:54:10 +02:00
if ( s - > type = = SERVICE_ONESHOT & & s - > restart ! = SERVICE_RESTART_NO ) {
2014-01-29 13:49:54 +01:00
log_error_unit ( UNIT ( s ) - > id , " %s has Restart setting other than no, which isn't allowed for Type=oneshot services. Refusing. " , UNIT ( s ) - > id ) ;
2013-08-09 12:54:10 +02:00
return - EINVAL ;
}
2010-04-15 23:16:16 +02:00
if ( s - > type = = SERVICE_DBUS & & ! s - > bus_name ) {
2014-01-29 13:49:54 +01:00
log_error_unit ( UNIT ( s ) - > id , " %s is of type D-Bus but no D-Bus service name has been specified. Refusing. " , UNIT ( s ) - > id ) ;
2010-06-19 16:57:54 +02:00
return - EINVAL ;
}
2012-05-03 14:42:49 +02:00
if ( s - > bus_name & & s - > type ! = SERVICE_DBUS )
2014-01-29 13:49:54 +01:00
log_warning_unit ( UNIT ( s ) - > id , " %s has a D-Bus service name specified, but is not of type dbus. Ignoring. " , UNIT ( s ) - > id ) ;
2012-05-03 14:42:49 +02:00
2014-01-29 13:49:54 +01:00
if ( s - > exec_context . pam_name & & ! ( s - > kill_context . kill_mode = = KILL_CONTROL_GROUP | | s - > kill_context . kill_mode = = KILL_MIXED ) ) {
log_error_unit ( UNIT ( s ) - > id , " %s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing. " , UNIT ( s ) - > id ) ;
2010-04-15 23:16:16 +02:00
return - EINVAL ;
}
2010-04-13 04:00:03 +02:00
return 0 ;
}
2010-07-03 19:48:33 +02:00
static int service_add_default_dependencies ( Service * s ) {
int r ;
assert ( s ) ;
/* Add a number of automatic dependencies useful for the
* majority of services . */
/* First, pull in base system */
2014-01-06 04:52:17 +01:00
r = unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_AFTER , UNIT_REQUIRES ,
SPECIAL_BASIC_TARGET , NULL , true ) ;
if ( r < 0 )
return r ;
2010-07-03 19:48:33 +02:00
/* Second, activate normal shutdown */
2013-03-02 14:28:58 +01:00
r = unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_BEFORE , UNIT_CONFLICTS ,
SPECIAL_SHUTDOWN_TARGET , NULL , true ) ;
return r ;
2010-07-03 19:48:33 +02:00
}
2011-09-22 03:29:51 +02:00
static void service_fix_output ( Service * s ) {
assert ( s ) ;
/* If nothing has been explicitly configured, patch default
* output in . If input is socket / tty we avoid this however ,
* since in that case we want output to default to the same
* place as we read input from . */
if ( s - > exec_context . std_error = = EXEC_OUTPUT_INHERIT & &
s - > exec_context . std_output = = EXEC_OUTPUT_INHERIT & &
s - > exec_context . std_input = = EXEC_INPUT_NULL )
2012-01-15 12:25:20 +01:00
s - > exec_context . std_error = UNIT ( s ) - > manager - > default_std_error ;
2011-09-22 03:29:51 +02:00
if ( s - > exec_context . std_output = = EXEC_OUTPUT_INHERIT & &
s - > exec_context . std_input = = EXEC_INPUT_NULL )
2012-01-15 12:25:20 +01:00
s - > exec_context . std_output = UNIT ( s ) - > manager - > default_std_output ;
2011-09-22 03:29:51 +02:00
}
2010-04-10 17:53:17 +02:00
static int service_load ( Unit * u ) {
int r ;
Service * s = SERVICE ( u ) ;
assert ( s ) ;
2010-01-29 04:42:57 +01:00
2010-01-23 01:52:57 +01:00
/* Load a .service file */
2013-06-28 04:12:58 +02:00
r = unit_load_fragment ( u ) ;
if ( r < 0 )
2010-01-23 01:52:57 +01:00
return r ;
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2010-04-01 21:30:40 +02:00
/* Load a classic init script as a fallback, if we couldn't find anything */
2013-06-28 04:12:58 +02:00
if ( u - > load_state = = UNIT_STUB ) {
r = service_load_sysv ( s ) ;
if ( r < 0 )
2010-04-06 02:43:58 +02:00
return r ;
2013-06-28 04:12:58 +02:00
}
2010-09-21 05:23:12 +02:00
# endif
2010-01-28 02:44:47 +01:00
2010-04-06 02:43:58 +02:00
/* Still nothing found? Then let's give up */
2012-01-15 12:04:08 +01:00
if ( u - > load_state = = UNIT_STUB )
2010-04-06 02:43:58 +02:00
return - ENOENT ;
2010-01-26 04:18:44 +01:00
2010-04-06 02:43:58 +02:00
/* This is a new unit? Then let's add in some extras */
2012-01-15 12:04:08 +01:00
if ( u - > load_state = = UNIT_LOADED ) {
2013-06-28 04:12:58 +02:00
/* We were able to load something, then let's add in
* the dropin directories . */
r = unit_load_dropin ( u ) ;
if ( r < 0 )
return r ;
2012-05-03 14:46:29 +02:00
if ( s - > type = = _SERVICE_TYPE_INVALID )
s - > type = s - > bus_name ? SERVICE_DBUS : SERVICE_SIMPLE ;
2012-08-07 14:41:48 +02:00
/* Oneshot services have disabled start timeout by default */
if ( s - > type = = SERVICE_ONESHOT & & ! s - > start_timeout_defined )
s - > timeout_start_usec = 0 ;
2012-06-14 17:07:07 +02:00
2011-09-23 17:42:21 +02:00
service_fix_output ( s ) ;
2014-03-19 20:40:05 +01:00
r = unit_patch_contexts ( u ) ;
if ( r < 0 )
return r ;
2013-03-02 14:28:58 +01:00
r = unit_add_exec_dependencies ( u , & s - > exec_context ) ;
if ( r < 0 )
2010-04-06 02:43:58 +02:00
return r ;
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 ;
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2013-03-02 14:28:58 +01:00
r = sysv_fix_order ( s ) ;
if ( r < 0 )
2010-04-06 02:43:58 +02:00
return r ;
2010-09-21 05:23:12 +02:00
# endif
2010-04-15 23:16:16 +02:00
2010-06-18 23:12:48 +02:00
if ( s - > type = = SERVICE_NOTIFY & & s - > notify_access = = NOTIFY_NONE )
s - > notify_access = NOTIFY_MAIN ;
2010-07-03 19:48:33 +02:00
2012-02-09 21:11:25 +01:00
if ( s - > watchdog_usec > 0 & & s - > notify_access = = NOTIFY_NONE )
s - > notify_access = NOTIFY_MAIN ;
2014-03-19 20:40:05 +01:00
if ( s - > bus_name ) {
r = unit_watch_bus_name ( u , s - > bus_name ) ;
2013-03-02 14:28:58 +01:00
if ( r < 0 )
2010-07-03 19:48:33 +02:00
return r ;
2013-03-02 14:28:58 +01:00
}
2012-07-16 12:44:42 +02:00
2014-03-19 20:40:05 +01:00
if ( u - > default_dependencies ) {
r = service_add_default_dependencies ( s ) ;
if ( r < 0 )
return r ;
}
2010-03-31 16:29:55 +02:00
}
2010-04-13 04:00:03 +02:00
return service_verify ( s ) ;
2010-01-26 04:18:44 +01:00
}
2010-01-26 21:39:06 +01:00
static void service_dump ( Unit * u , FILE * f , const char * prefix ) {
2010-01-23 01:52:57 +01:00
ServiceExecCommand c ;
2010-01-26 21:39:06 +01:00
Service * s = SERVICE ( u ) ;
2010-02-03 14:21:48 +01:00
const char * prefix2 ;
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * p2 = NULL ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2010-02-03 14:21:48 +01:00
p2 = strappend ( prefix , " \t " ) ;
prefix2 = p2 ? p2 : prefix ;
2010-01-26 07:02:51 +01:00
2010-01-23 01:52:57 +01:00
fprintf ( f ,
2010-02-14 22:43:08 +01:00
" %sService State: %s \n "
2012-02-03 02:01:35 +01:00
" %sResult: %s \n "
" %sReload Result: %s \n "
2010-02-14 22:43:08 +01:00
" %sPermissionsStartOnly: %s \n "
2010-03-31 16:29:55 +02:00
" %sRootDirectoryStartOnly: %s \n "
2010-08-17 19:37:36 +02:00
" %sRemainAfterExit: %s \n "
2011-02-13 18:51:30 +01:00
" %sGuessMainPID: %s \n "
2010-06-18 23:12:48 +02:00
" %sType: %s \n "
2010-08-09 17:03:46 +02:00
" %sRestart: %s \n "
2010-06-18 23:12:48 +02:00
" %sNotifyAccess: %s \n " ,
2010-02-14 22:43:08 +01:00
prefix , service_state_to_string ( s - > state ) ,
2012-02-03 02:01:35 +01:00
prefix , service_result_to_string ( s - > result ) ,
prefix , service_result_to_string ( s - > reload_result ) ,
2010-02-14 22:43:08 +01:00
prefix , yes_no ( s - > permissions_start_only ) ,
2010-03-31 16:29:55 +02:00
prefix , yes_no ( s - > root_directory_start_only ) ,
2010-08-17 19:37:36 +02:00
prefix , yes_no ( s - > remain_after_exit ) ,
2011-02-13 18:51:30 +01:00
prefix , yes_no ( s - > guess_main_pid ) ,
2010-06-18 23:12:48 +02:00
prefix , service_type_to_string ( s - > type ) ,
2010-08-09 17:03:46 +02:00
prefix , service_restart_to_string ( s - > restart ) ,
2010-06-18 23:12:48 +02:00
prefix , notify_access_to_string ( s - > notify_access ) ) ;
2010-01-23 01:52:57 +01:00
2010-04-08 03:48:27 +02:00
if ( s - > control_pid > 0 )
fprintf ( f ,
2013-12-30 23:22:26 +01:00
" %sControl PID: " PID_FMT " \n " ,
prefix , s - > control_pid ) ;
2010-04-08 03:48:27 +02:00
if ( s - > main_pid > 0 )
fprintf ( f ,
2013-12-30 23:22:26 +01:00
" %sMain PID: " PID_FMT " \n "
2011-04-28 04:56:53 +02:00
" %sMain PID Known: %s \n "
" %sMain PID Alien: %s \n " ,
2013-12-30 23:22:26 +01:00
prefix , s - > main_pid ,
2011-04-28 04:56:53 +02:00
prefix , yes_no ( s - > main_pid_known ) ,
prefix , yes_no ( s - > main_pid_alien ) ) ;
2010-04-08 03:48:27 +02:00
2010-01-26 04:18:44 +01:00
if ( s - > pid_file )
fprintf ( f ,
" %sPIDFile: %s \n " ,
prefix , s - > pid_file ) ;
2010-04-15 23:16:16 +02:00
if ( s - > bus_name )
fprintf ( f ,
" %sBusName: %s \n "
" %sBus Name Good: %s \n " ,
prefix , s - > bus_name ,
prefix , yes_no ( s - > bus_name_good ) ) ;
2012-07-19 23:47:10 +02:00
kill_context_dump ( & s - > kill_context , f , prefix ) ;
2010-01-23 01:52:57 +01:00
exec_context_dump ( & s - > exec_context , f , prefix ) ;
2010-04-10 17:53:17 +02:00
for ( c = 0 ; c < _SERVICE_EXEC_COMMAND_MAX ; c + + ) {
2010-01-23 01:52:57 +01:00
2010-01-26 07:02:51 +01:00
if ( ! s - > exec_command [ c ] )
continue ;
2010-04-23 20:25:55 +02:00
fprintf ( f , " %s-> %s: \n " ,
2010-01-30 01:55:42 +01:00
prefix , service_exec_command_to_string ( c ) ) ;
2010-01-26 07:02:51 +01:00
exec_command_dump_list ( s - > exec_command [ c ] , f , prefix2 ) ;
2010-01-23 01:52:57 +01:00
}
2010-01-26 07:02:51 +01:00
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2012-05-22 23:08:24 +02:00
if ( s - > is_sysv )
2010-02-14 01:09:01 +01:00
fprintf ( f ,
2010-10-13 03:57:04 +02:00
" %sSysV Init Script has LSB Header: %s \n "
" %sSysVEnabled: %s \n " ,
prefix , yes_no ( s - > sysv_has_lsb ) ,
prefix , yes_no ( s - > sysv_enabled ) ) ;
2010-02-14 01:09:01 +01:00
if ( s - > sysv_start_priority > = 0 )
fprintf ( f ,
2010-10-13 03:57:04 +02:00
" %sSysVStartPriority: %i \n " ,
prefix , s - > sysv_start_priority ) ;
2010-02-14 01:09:01 +01:00
2010-04-07 20:27:52 +02:00
if ( s - > sysv_runlevels )
fprintf ( f , " %sSysVRunLevels: %s \n " ,
prefix , s - > sysv_runlevels ) ;
2010-09-21 05:23:12 +02:00
# endif
2010-04-06 02:43:58 +02:00
2010-06-16 05:10:31 +02:00
if ( s - > status_text )
fprintf ( f , " %sStatus Text: %s \n " ,
prefix , s - > status_text ) ;
2010-01-23 01:52:57 +01:00
}
2011-11-10 09:55:47 +01:00
static int service_load_pid_file ( Service * s , bool may_warn ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * k = NULL ;
2010-01-26 04:18:44 +01:00
int r ;
2010-06-17 22:55:53 +02:00
pid_t pid ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
if ( ! s - > pid_file )
2011-09-21 02:25:17 +02:00
return - ENOENT ;
2010-01-26 04:18:44 +01:00
2013-03-02 14:28:58 +01:00
r = read_one_line_file ( s - > pid_file , & k ) ;
if ( r < 0 ) {
2011-11-10 09:55:47 +01:00
if ( may_warn )
2013-01-05 18:00:35 +01:00
log_info_unit ( UNIT ( s ) - > id ,
" PID file %s not readable (yet?) after %s. " ,
s - > pid_file , service_state_to_string ( s - > state ) ) ;
2010-01-26 04:18:44 +01:00
return r ;
2011-09-22 13:10:32 +02:00
}
2010-01-26 04:18:44 +01:00
2010-06-17 22:55:53 +02:00
r = parse_pid ( k , & pid ) ;
2013-03-03 07:32:34 +01:00
if ( r < 0 ) {
if ( may_warn )
log_info_unit ( UNIT ( s ) - > id ,
" Failed to read PID from file %s: %s " ,
s - > pid_file , strerror ( - r ) ) ;
2010-06-17 22:55:53 +02:00
return r ;
2013-03-03 07:32:34 +01:00
}
2010-06-15 19:47:13 +02:00
2014-02-17 18:28:53 +01:00
if ( ! pid_is_alive ( pid ) ) {
2011-11-10 09:55:47 +01:00
if ( may_warn )
2014-02-17 18:28:53 +01:00
log_info_unit ( UNIT ( s ) - > id , " PID " PID_FMT " read from file %s does not exist or is a zombie. " , pid , s - > pid_file ) ;
2010-04-08 03:48:52 +02:00
2014-02-14 19:38:50 +01:00
return - ESRCH ;
}
2011-09-20 21:43:30 +02:00
if ( s - > main_pid_known ) {
if ( pid = = s - > main_pid )
return 0 ;
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" Main PID changing: " PID_FMT " -> " PID_FMT ,
s - > main_pid , pid ) ;
2011-09-20 21:43:30 +02:00
service_unwatch_main_pid ( s ) ;
s - > main_pid_known = false ;
2011-12-03 02:13:30 +01:00
} else
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" Main PID loaded: " PID_FMT , pid ) ;
2011-09-20 21:43:30 +02:00
2013-03-02 14:28:58 +01:00
r = service_set_main_pid ( s , pid ) ;
if ( r < 0 )
2010-04-08 04:05:56 +02:00
return r ;
2013-03-02 14:28:58 +01:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
2013-03-03 07:32:34 +01:00
if ( r < 0 ) {
2010-06-17 22:55:53 +02:00
/* FIXME: we need to do something here */
2013-03-03 07:32:34 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" Failed to watch PID " PID_FMT " from service %s " ,
pid , UNIT ( s ) - > id ) ;
2010-06-17 22:55:53 +02:00
return r ;
2013-03-03 07:32:34 +01:00
}
2010-01-26 04:18:44 +01:00
return 0 ;
}
2010-10-27 03:16:49 +02:00
static int service_search_main_pid ( Service * s ) {
pid_t pid ;
int r ;
assert ( s ) ;
2011-02-13 18:51:30 +01:00
/* If we know it anyway, don't ever fallback to unreliable
* heuristics */
2010-10-27 03:16:49 +02:00
if ( s - > main_pid_known )
return 0 ;
2011-02-13 18:51:30 +01:00
if ( ! s - > guess_main_pid )
return 0 ;
2010-10-27 03:16:49 +02:00
assert ( s - > main_pid < = 0 ) ;
2013-06-27 04:14:27 +02:00
pid = unit_search_main_pid ( UNIT ( s ) ) ;
2013-03-02 14:28:58 +01:00
if ( pid < = 0 )
2010-10-27 03:16:49 +02:00
return - ENOENT ;
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" Main PID guessed: " PID_FMT , pid ) ;
2013-03-02 14:28:58 +01:00
r = service_set_main_pid ( s , pid ) ;
if ( r < 0 )
2010-10-27 03:16:49 +02:00
return r ;
2013-03-02 14:28:58 +01:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
if ( r < 0 )
2010-10-27 03:16:49 +02:00
/* FIXME: we need to do something here */
2013-04-30 01:46:19 +02:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-30 23:22:26 +01:00
" Failed to watch PID " PID_FMT " from service %s " ,
pid , UNIT ( s ) - > id ) ;
2014-02-23 01:26:27 +01:00
return r ;
2010-10-27 03:16:49 +02:00
}
2010-01-26 04:18:44 +01:00
static void service_set_state ( Service * s , ServiceState state ) {
ServiceState old_state ;
2012-05-24 02:22:35 +02:00
const UnitActiveState * table ;
2013-12-11 20:49:43 +01:00
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2012-05-24 02:22:35 +02:00
table = s - > type = = SERVICE_IDLE ? state_translation_table_idle : state_translation_table ;
2010-01-26 04:18:44 +01:00
old_state = s - > state ;
2010-01-23 01:52:57 +01:00
s - > state = state ;
2010-01-26 04:18:44 +01:00
2011-12-03 02:13:30 +01:00
service_unwatch_pid_file ( s ) ;
2013-12-11 20:49:43 +01:00
if ( ! IN_SET ( state ,
SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST ,
SERVICE_RELOAD ,
2013-12-18 04:19:20 +01:00
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
2013-12-11 20:49:43 +01:00
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ,
SERVICE_AUTO_RESTART ) )
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-01-26 04:18:44 +01:00
2013-12-11 20:49:43 +01:00
if ( ! IN_SET ( state ,
SERVICE_START , SERVICE_START_POST ,
SERVICE_RUNNING , SERVICE_RELOAD ,
2013-12-18 04:19:20 +01:00
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) ) {
2010-04-11 00:22:36 +02:00
service_unwatch_main_pid ( s ) ;
2011-01-20 18:46:38 +01:00
s - > main_command = NULL ;
}
2010-01-26 04:18:44 +01:00
2013-12-11 20:49:43 +01:00
if ( ! IN_SET ( state ,
SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST ,
SERVICE_RELOAD ,
2013-12-18 04:19:20 +01:00
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
2013-12-11 20:49:43 +01:00
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) ) {
2010-04-11 00:22:36 +02:00
service_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 = _SERVICE_EXEC_COMMAND_INVALID ;
2010-04-10 17:53:17 +02:00
}
2010-01-26 04:18:44 +01:00
2014-02-06 17:17:51 +01:00
if ( IN_SET ( state , SERVICE_DEAD , SERVICE_FAILED , SERVICE_AUTO_RESTART ) )
unit_unwatch_all_pids ( UNIT ( s ) ) ;
2013-12-11 20:49:43 +01:00
if ( ! IN_SET ( state ,
SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST ,
SERVICE_RUNNING , SERVICE_RELOAD ,
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL , SERVICE_STOP_POST ,
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) & &
2012-01-15 12:25:20 +01:00
! ( state = = SERVICE_DEAD & & UNIT ( s ) - > job ) ) {
2010-04-15 06:19:54 +02:00
service_close_socket_fd ( s ) ;
2010-06-19 04:25:28 +02:00
service_connection_unref ( s ) ;
}
2010-04-15 06:19:54 +02:00
2013-12-12 03:03:03 +01:00
if ( ! IN_SET ( state , SERVICE_START_POST , SERVICE_RUNNING , SERVICE_RELOAD ) )
2012-02-01 17:17:12 +01:00
service_stop_watchdog ( s ) ;
2010-07-12 02:31:40 +02:00
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves . . . */
2012-01-15 12:25:20 +01:00
if ( state = = SERVICE_EXITED & & UNIT ( s ) - > manager - > n_reloading < = 0 )
2013-06-27 04:14:27 +02:00
unit_destroy_cgroup ( UNIT ( s ) ) ;
2010-07-12 02:31:40 +02:00
2013-11-14 15:52:54 +01:00
/* For remain_after_exit services, let's see if we can "release" the
* hold on the console , since unit_notify ( ) only does that in case of
* change of state */
if ( state = = SERVICE_EXITED & & s - > remain_after_exit & &
UNIT ( s ) - > manager - > n_on_console > 0 ) {
ExecContext * ec = unit_get_exec_context ( UNIT ( s ) ) ;
if ( ec & & exec_context_may_touch_console ( ec ) ) {
Manager * m = UNIT ( s ) - > manager ;
m - > n_on_console - - ;
if ( m - > n_on_console = = 0 )
/* unset no_console_output flag, since the console is free */
m - > no_console_output = false ;
}
}
2010-04-10 17:53:17 +02:00
if ( old_state ! = state )
2013-12-11 20:49:43 +01:00
log_debug_unit ( UNIT ( s ) - > id , " %s changed %s -> %s " , UNIT ( s ) - > id , service_state_to_string ( old_state ) , service_state_to_string ( state ) ) ;
2010-01-27 04:31:52 +01:00
2012-05-24 02:22:35 +02:00
unit_notify ( UNIT ( s ) , table [ old_state ] , table [ state ] , s - > reload_result = = SERVICE_SUCCESS ) ;
2012-02-03 02:01:35 +01:00
s - > reload_result = SERVICE_SUCCESS ;
2010-01-26 04:18:44 +01:00
}
2010-04-21 03:27:44 +02:00
static int service_coldplug ( Unit * u ) {
Service * s = SERVICE ( u ) ;
int r ;
assert ( s ) ;
assert ( s - > state = = SERVICE_DEAD ) ;
if ( s - > deserialized_state ! = s - > state ) {
2013-12-18 04:19:20 +01:00
if ( IN_SET ( s - > deserialized_state ,
SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST ,
SERVICE_RELOAD ,
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) ) {
2013-11-22 19:17:52 +01:00
usec_t k ;
2013-07-01 00:03:57 +02:00
2013-12-18 04:19:20 +01:00
k = IN_SET ( s - > deserialized_state , SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST , SERVICE_RELOAD ) ? s - > timeout_start_usec : s - > timeout_stop_usec ;
2010-04-23 20:28:33 +02:00
2013-11-22 19:17:52 +01:00
/* For the start/stop timeouts 0 means off */
if ( k > 0 ) {
r = service_arm_timer ( s , k ) ;
2012-11-23 21:37:58 +01:00
if ( r < 0 )
2010-04-23 20:28:33 +02:00
return r ;
}
}
2010-04-21 03:27:44 +02:00
2013-11-22 19:17:52 +01:00
if ( s - > deserialized_state = = SERVICE_AUTO_RESTART ) {
/* The restart timeouts 0 means immediately */
r = service_arm_timer ( s , s - > restart_usec ) ;
if ( r < 0 )
return r ;
}
2014-02-17 18:28:53 +01:00
if ( pid_is_unwaited ( s - > main_pid ) & &
2013-12-18 04:19:20 +01:00
( ( s - > deserialized_state = = SERVICE_START & & IN_SET ( s - > type , SERVICE_FORKING , SERVICE_DBUS , SERVICE_ONESHOT , SERVICE_NOTIFY ) ) | |
IN_SET ( s - > deserialized_state ,
SERVICE_START , SERVICE_START_POST ,
SERVICE_RUNNING , SERVICE_RELOAD ,
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) ) ) {
r = unit_watch_pid ( UNIT ( s ) , s - > main_pid ) ;
if ( r < 0 )
return r ;
}
2010-04-21 03:27:44 +02:00
2014-02-17 18:28:53 +01:00
if ( pid_is_unwaited ( s - > control_pid ) & &
2013-12-18 04:19:20 +01:00
IN_SET ( s - > deserialized_state ,
SERVICE_START_PRE , SERVICE_START , SERVICE_START_POST ,
SERVICE_RELOAD ,
SERVICE_STOP , SERVICE_STOP_SIGTERM , SERVICE_STOP_SIGKILL ,
SERVICE_STOP_POST ,
SERVICE_FINAL_SIGTERM , SERVICE_FINAL_SIGKILL ) ) {
r = unit_watch_pid ( UNIT ( s ) , s - > control_pid ) ;
if ( r < 0 )
return r ;
}
2010-04-21 03:27:44 +02:00
2014-02-06 17:17:51 +01:00
if ( ! IN_SET ( s - > deserialized_state , SERVICE_DEAD , SERVICE_FAILED , SERVICE_AUTO_RESTART ) )
unit_watch_all_pids ( UNIT ( s ) ) ;
2013-12-11 20:49:43 +01:00
if ( IN_SET ( s - > deserialized_state , SERVICE_START_POST , SERVICE_RUNNING , SERVICE_RELOAD ) )
service_start_watchdog ( s ) ;
2012-02-08 10:10:34 +01:00
2010-04-21 03:27:44 +02:00
service_set_state ( s , s - > deserialized_state ) ;
}
2013-11-22 19:17:52 +01:00
2010-04-21 03:27:44 +02:00
return 0 ;
}
2010-01-26 07:02:51 +01:00
static int service_collect_fds ( Service * s , int * * fds , unsigned * n_fds ) {
Iterator i ;
int r ;
int * rfds = NULL ;
unsigned rn_fds = 0 ;
2012-01-06 23:08:54 +01:00
Unit * u ;
2010-01-26 07:02:51 +01:00
assert ( s ) ;
assert ( fds ) ;
assert ( n_fds ) ;
2010-06-19 04:25:28 +02:00
if ( s - > socket_fd > = 0 )
return 0 ;
2012-01-15 12:25:20 +01:00
SET_FOREACH ( u , UNIT ( s ) - > dependencies [ UNIT_TRIGGERED_BY ] , i ) {
2010-01-26 07:02:51 +01:00
int * cfds ;
unsigned cn_fds ;
2012-01-06 23:08:54 +01:00
Socket * sock ;
2012-01-15 12:04:08 +01:00
if ( u - > type ! = UNIT_SOCKET )
2012-01-06 23:08:54 +01:00
continue ;
sock = SOCKET ( u ) ;
2010-01-26 07:02:51 +01:00
2013-03-02 14:28:58 +01:00
r = socket_collect_fds ( sock , & cfds , & cn_fds ) ;
if ( r < 0 )
2010-01-26 07:02:51 +01:00
goto fail ;
if ( ! cfds )
continue ;
if ( ! rfds ) {
rfds = cfds ;
rn_fds = cn_fds ;
} else {
int * t ;
2013-03-02 14:28:58 +01:00
t = new ( int , rn_fds + cn_fds ) ;
if ( ! t ) {
2010-01-26 07:02:51 +01:00
free ( cfds ) ;
r = - ENOMEM ;
goto fail ;
}
2011-04-06 02:25:39 +02:00
memcpy ( t , rfds , rn_fds * sizeof ( int ) ) ;
memcpy ( t + rn_fds , cfds , cn_fds * sizeof ( int ) ) ;
2010-01-26 07:02:51 +01:00
free ( rfds ) ;
free ( cfds ) ;
rfds = t ;
rn_fds = rn_fds + cn_fds ;
}
}
* fds = rfds ;
* n_fds = rn_fds ;
2010-01-27 22:41:57 +01:00
2010-01-26 07:02:51 +01:00
return 0 ;
fail :
free ( rfds ) ;
2010-01-27 22:41:57 +01:00
2010-01-26 07:02:51 +01:00
return r ;
}
2010-02-14 22:43:08 +01:00
static int service_spawn (
Service * s ,
ExecCommand * c ,
bool timeout ,
bool pass_fds ,
bool apply_permissions ,
bool apply_chroot ,
2010-07-08 04:09:17 +02:00
bool apply_tty_stdin ,
2010-06-18 23:12:48 +02:00
bool set_notify_socket ,
2012-04-13 23:24:47 +02:00
bool is_control ,
2010-02-14 22:43:08 +01:00
pid_t * _pid ) {
2010-01-26 04:18:44 +01:00
pid_t pid ;
int r ;
2013-03-02 14:28:58 +01:00
int * fds = NULL ;
2013-04-18 09:11:22 +02:00
_cleanup_free_ int * fdsbuf = NULL ;
2010-07-08 00:47:35 +02:00
unsigned n_fds = 0 , n_env = 0 ;
2013-04-18 09:11:22 +02:00
_cleanup_strv_free_ char
2013-03-02 14:28:58 +01:00
* * argv = NULL , * * final_env = NULL , * * our_env = NULL ;
2013-06-27 04:14:27 +02:00
const char * path ;
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 ;
2010-06-19 04:25:28 +02:00
if ( pass_fds | |
s - > exec_context . std_input = = EXEC_INPUT_SOCKET | |
s - > exec_context . std_output = = EXEC_OUTPUT_SOCKET | |
s - > exec_context . std_error = = EXEC_OUTPUT_SOCKET ) {
2010-04-15 06:19:54 +02:00
if ( s - > socket_fd > = 0 ) {
fds = & s - > socket_fd ;
n_fds = 1 ;
2010-06-19 04:25:28 +02:00
} else {
2013-03-02 14:28:58 +01:00
r = service_collect_fds ( s , & fdsbuf , & n_fds ) ;
if ( r < 0 )
2010-06-19 04:25:28 +02:00
goto fail ;
fds = fdsbuf ;
}
2010-04-15 06:19:54 +02:00
}
2010-01-26 07:02:51 +01:00
2013-11-22 19:17:52 +01:00
if ( timeout & & s - > timeout_start_usec > 0 ) {
r = service_arm_timer ( s , s - > timeout_start_usec ) ;
if ( r < 0 )
goto fail ;
} else
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
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 ;
2013-12-22 22:14:05 +01:00
our_env = new0 ( char * , 4 ) ;
2012-10-18 01:18:50 +02:00
if ( ! our_env ) {
2010-07-08 00:47:35 +02:00
r = - ENOMEM ;
goto fail ;
}
2010-06-18 23:12:48 +02:00
2010-07-08 00:47:35 +02:00
if ( set_notify_socket )
2012-01-15 12:25:20 +01:00
if ( asprintf ( our_env + n_env + + , " NOTIFY_SOCKET=%s " , UNIT ( s ) - > manager - > notify_socket ) < 0 ) {
2010-06-18 23:12:48 +02:00
r = - ENOMEM ;
goto fail ;
}
2010-07-08 00:47:35 +02:00
if ( s - > main_pid > 0 )
2013-12-30 23:22:26 +01:00
if ( asprintf ( our_env + n_env + + , " MAINPID= " PID_FMT , s - > main_pid ) < 0 ) {
2010-06-18 23:12:48 +02:00
r = - ENOMEM ;
goto fail ;
}
2010-07-08 00:47:35 +02:00
2013-06-27 04:14:27 +02:00
if ( UNIT ( s ) - > manager - > running_as ! = SYSTEMD_SYSTEM )
2013-12-30 23:22:26 +01:00
if ( asprintf ( our_env + n_env + + , " MANAGERPID= " PID_FMT , getpid ( ) ) < 0 ) {
2012-10-18 01:18:50 +02:00
r = - ENOMEM ;
goto fail ;
}
final_env = strv_env_merge ( 2 , UNIT ( s ) - > manager - > environment , our_env , NULL ) ;
if ( ! final_env ) {
2010-07-08 00:47:35 +02:00
r = - ENOMEM ;
goto fail ;
}
2010-06-18 23:12:48 +02:00
2013-06-27 04:14:27 +02:00
if ( is_control & & UNIT ( s ) - > cgroup_path ) {
path = strappenda ( UNIT ( s ) - > cgroup_path , " /control " ) ;
cg_create ( SYSTEMD_CGROUP_CONTROLLER , path ) ;
} else
path = UNIT ( s ) - > cgroup_path ;
2010-04-15 03:11:11 +02:00
r = exec_spawn ( c ,
argv ,
& s - > exec_context ,
fds , n_fds ,
2010-07-08 00:47:35 +02:00
final_env ,
2010-04-15 03:11:11 +02:00
apply_permissions ,
apply_chroot ,
2010-07-08 04:09:17 +02:00
apply_tty_stdin ,
2012-01-15 12:25:20 +01:00
UNIT ( s ) - > manager - > confirm_spawn ,
2013-09-24 04:56:05 +02:00
UNIT ( s ) - > manager - > cgroup_supported ,
2013-06-27 04:14:27 +02:00
path ,
2014-03-03 17:14:07 +01:00
manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ,
2012-06-21 22:40:47 +02:00
UNIT ( s ) - > id ,
2013-12-22 22:14:05 +01:00
s - > watchdog_usec ,
2012-04-24 14:28:00 +02:00
s - > type = = SERVICE_IDLE ? UNIT ( s ) - > manager - > idle_pipe : NULL ,
2013-11-27 20:23:18 +01:00
s - > exec_runtime ,
2010-04-15 03:11:11 +02:00
& pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2013-03-02 14:28:58 +01:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
/* FIXME: we need to do something here */
goto fail ;
* _pid = pid ;
2010-01-23 01:52:57 +01:00
return 0 ;
2010-01-26 04:18:44 +01:00
fail :
if ( timeout )
2013-11-19 21:12:59 +01:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-01-26 04:18:44 +01:00
return r ;
}
2010-04-13 02:06:27 +02:00
static int main_pid_good ( Service * s ) {
assert ( s ) ;
/* Returns 0 if the pid is dead, 1 if it is good, -1 if we
* don ' t know */
/* If we know the pid file, then lets just check if it is
* still valid */
2011-04-28 04:56:53 +02:00
if ( s - > main_pid_known ) {
/* If it's an alien child let's check if it is still
* alive . . . */
2013-06-09 18:28:44 +02:00
if ( s - > main_pid_alien & & s - > main_pid > 0 )
2014-02-17 18:28:53 +01:00
return pid_is_alive ( s - > main_pid ) ;
2011-04-28 04:56:53 +02:00
/* .. otherwise assume we'll get a SIGCHLD for it,
* which we really should wait for to collect exit
* status and code */
2010-04-13 02:06:27 +02:00
return s - > main_pid > 0 ;
2011-04-28 04:56:53 +02:00
}
2010-04-13 02:06:27 +02:00
/* We don't know the pid */
return - EAGAIN ;
}
2013-05-03 04:51:50 +02:00
_pure_ static int control_pid_good ( Service * s ) {
2010-04-13 02:06:27 +02:00
assert ( s ) ;
return s - > control_pid > 0 ;
}
static int cgroup_good ( Service * s ) {
int r ;
assert ( s ) ;
2013-06-27 04:14:27 +02:00
if ( ! UNIT ( s ) - > cgroup_path )
return 0 ;
r = cg_is_empty_recursive ( SYSTEMD_CGROUP_CONTROLLER , UNIT ( s ) - > cgroup_path , true ) ;
2013-03-02 14:28:58 +01:00
if ( r < 0 )
2010-04-13 02:06:27 +02:00
return r ;
return ! r ;
}
2012-02-03 02:01:35 +01:00
static void service_enter_dead ( Service * s , ServiceResult f , bool allow_restart ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2012-06-26 11:42:52 +02:00
service_set_state ( s , s - > result ! = SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD ) ;
2010-01-26 04:18:44 +01:00
if ( allow_restart & &
2010-08-09 23:33:48 +02:00
! s - > forbid_restart & &
2010-01-26 04:18:44 +01:00
( s - > restart = = SERVICE_RESTART_ALWAYS | |
2012-02-03 02:01:35 +01:00
( s - > restart = = SERVICE_RESTART_ON_SUCCESS & & s - > result = = SERVICE_SUCCESS ) | |
( s - > restart = = SERVICE_RESTART_ON_FAILURE & & s - > result ! = SERVICE_SUCCESS ) | |
2013-07-25 14:07:59 +02:00
( s - > restart = = SERVICE_RESTART_ON_WATCHDOG & & s - > result = = SERVICE_FAILURE_WATCHDOG ) | |
2012-02-03 02:01:35 +01:00
( s - > restart = = SERVICE_RESTART_ON_ABORT & & ( s - > result = = SERVICE_FAILURE_SIGNAL | |
2012-08-13 13:58:01 +02:00
s - > result = = SERVICE_FAILURE_CORE_DUMP ) ) ) & &
( s - > result ! = SERVICE_FAILURE_EXIT_CODE | |
! set_contains ( s - > restart_ignore_status . code , INT_TO_PTR ( s - > main_exec_status . status ) ) ) & &
( s - > result ! = SERVICE_FAILURE_SIGNAL | |
2013-11-19 21:12:59 +01:00
! set_contains ( s - > restart_ignore_status . signal , INT_TO_PTR ( s - > main_exec_status . status ) ) ) ) {
2010-01-26 04:18:44 +01:00
2013-11-19 21:12:59 +01:00
r = service_arm_timer ( s , s - > restart_usec ) ;
2012-02-03 02:01:35 +01:00
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
service_set_state ( s , SERVICE_AUTO_RESTART ) ;
2012-06-26 11:42:52 +02:00
}
2010-01-26 04:18:44 +01:00
2010-08-09 23:33:48 +02:00
s - > forbid_restart = false ;
2014-03-03 17:14:07 +01:00
/* We want fresh tmpdirs in case service is started again immediately */
2013-11-27 20:23:18 +01:00
exec_runtime_destroy ( s - > exec_runtime ) ;
s - > exec_runtime = exec_runtime_unref ( s - > exec_runtime ) ;
2013-03-14 18:12:27 +01:00
2014-03-03 17:14:07 +01:00
/* Also, remove the runtime directory in */
exec_context_destroy_runtime_directory ( & s - > exec_context , manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ) ;
2013-08-28 19:27:44 +02:00
/* Try to delete the pid file. At this point it will be
* out - of - date , and some software might be confused by it , so
* let ' s remove it . */
if ( s - > pid_file )
unlink_noerrno ( s - > pid_file ) ;
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 install restart timer: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_RESOURCES , false ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_enter_stop_post ( Service * s , ServiceResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2014-02-06 17:17:51 +01:00
unit_watch_all_pids ( UNIT ( s ) ) ;
2010-04-11 00:22:36 +02:00
2013-03-02 14:28:58 +01:00
s - > control_command = s - > exec_command [ SERVICE_EXEC_STOP_POST ] ;
if ( s - > control_command ) {
2011-01-20 18:46:38 +01:00
s - > control_command_id = SERVICE_EXEC_STOP_POST ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
true ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_STOP_POST ) ;
} else
2014-01-29 14:58:04 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_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:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_enter_signal ( Service * s , ServiceState state , ServiceResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2014-02-06 17:17:51 +01:00
unit_watch_all_pids ( UNIT ( s ) ) ;
2013-01-26 05:53:30 +01:00
r = unit_kill_context (
UNIT ( s ) ,
& s - > kill_context ,
state ! = SERVICE_STOP_SIGTERM & & state ! = SERVICE_FINAL_SIGTERM ,
s - > main_pid ,
s - > control_pid ,
s - > main_pid_alien ) ;
2014-01-29 14:58:04 +01:00
2013-01-26 05:53:30 +01:00
if ( r < 0 )
goto fail ;
2010-01-26 04:18:44 +01:00
2013-01-26 05:53:30 +01:00
if ( r > 0 ) {
2012-08-07 14:41:48 +02:00
if ( s - > timeout_stop_usec > 0 ) {
2013-11-19 21:12:59 +01:00
r = service_arm_timer ( s , s - > timeout_stop_usec ) ;
2012-08-07 14:41:48 +02:00
if ( r < 0 )
2010-04-23 20:28:33 +02:00
goto fail ;
2012-08-07 14:41:48 +02:00
}
2010-01-28 01:59:41 +01:00
2010-04-13 02:06:27 +02:00
service_set_state ( s , state ) ;
2014-01-29 14:58:04 +01:00
} else if ( state = = SERVICE_STOP_SIGTERM )
service_enter_signal ( s , SERVICE_STOP_SIGKILL , SERVICE_SUCCESS ) ;
else if ( state = = SERVICE_STOP_SIGKILL )
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , SERVICE_SUCCESS ) ;
2014-01-29 14:58:04 +01:00
else if ( state = = SERVICE_FINAL_SIGTERM )
service_enter_signal ( s , SERVICE_FINAL_SIGKILL , SERVICE_SUCCESS ) ;
2010-04-13 02:06:27 +02:00
else
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_SUCCESS , true ) ;
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 kill processes: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
2010-04-13 02:06:27 +02:00
if ( state = = SERVICE_STOP_SIGTERM | | state = = SERVICE_STOP_SIGKILL )
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
else
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_RESOURCES , true ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_enter_stop ( Service * s , ServiceResult f ) {
2010-01-26 04:18:44 +01:00
int r ;
2010-06-17 22:55:53 +02:00
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2014-02-06 17:17:51 +01:00
unit_watch_all_pids ( UNIT ( s ) ) ;
2010-04-11 00:22:36 +02:00
2013-03-02 14:28:58 +01:00
s - > control_command = s - > exec_command [ SERVICE_EXEC_STOP ] ;
if ( s - > control_command ) {
2011-01-20 18:46:38 +01:00
s - > control_command_id = SERVICE_EXEC_STOP ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
false ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_STOP ) ;
} else
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_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' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_enter_running ( Service * s , ServiceResult f ) {
2010-06-22 04:09:50 +02:00
int main_pid_ok , cgroup_ok ;
2010-04-13 02:06:27 +02:00
assert ( s ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-04-13 02:06:27 +02:00
2010-06-22 04:09:50 +02:00
main_pid_ok = main_pid_good ( s ) ;
cgroup_ok = cgroup_good ( s ) ;
if ( ( main_pid_ok > 0 | | ( main_pid_ok < 0 & & cgroup_ok ! = 0 ) ) & &
2010-04-15 23:16:16 +02:00
( s - > bus_name_good | | s - > type ! = SERVICE_DBUS ) )
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_RUNNING ) ;
2010-08-17 19:37:36 +02:00
else if ( s - > remain_after_exit )
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_EXITED ) ;
else
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_SUCCESS ) ;
2010-04-13 02:06:27 +02:00
}
2010-01-26 04:18:44 +01:00
static void service_enter_start_post ( Service * s ) {
int r ;
assert ( s ) ;
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2013-12-11 20:49:43 +01:00
service_reset_watchdog ( s ) ;
2012-02-08 10:10:34 +01:00
2013-03-02 14:28:58 +01:00
s - > control_command = s - > exec_command [ SERVICE_EXEC_START_POST ] ;
if ( s - > control_command ) {
2011-01-20 18:46:38 +01:00
s - > control_command_id = SERVICE_EXEC_START_POST ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
false ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_START_POST ) ;
} else
2012-02-03 02:01:35 +01:00
service_enter_running ( s , SERVICE_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 'start-post' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
2013-06-27 04:14:27 +02:00
static void service_kill_control_processes ( Service * s ) {
char * p ;
if ( ! UNIT ( s ) - > cgroup_path )
return ;
p = strappenda ( UNIT ( s ) - > cgroup_path , " /control " ) ;
cg_kill_recursive ( SYSTEMD_CGROUP_CONTROLLER , p , SIGKILL , true , true , true , NULL ) ;
}
2010-01-26 04:18:44 +01:00
static void service_enter_start ( Service * s ) {
2013-06-27 04:14:27 +02:00
ExecCommand * c ;
2010-01-26 04:18:44 +01:00
pid_t pid ;
int r ;
assert ( s ) ;
assert ( s - > exec_command [ SERVICE_EXEC_START ] ) ;
2010-08-13 18:23:01 +02:00
assert ( ! s - > exec_command [ SERVICE_EXEC_START ] - > command_next | | s - > type = = SERVICE_ONESHOT ) ;
2010-01-26 04:18:44 +01:00
2013-08-09 16:40:57 +02:00
service_unwatch_control_pid ( s ) ;
service_unwatch_main_pid ( s ) ;
2010-04-13 02:06:27 +02:00
2012-01-11 01:51:32 +01:00
/* We want to ensure that nobody leaks processes from
* START_PRE here , so let ' s go on a killing spree , People
* should not spawn long running processes from START_PRE . */
2013-06-27 04:14:27 +02:00
service_kill_control_processes ( s ) ;
2012-01-11 01:51:32 +01:00
2011-01-20 18:46:38 +01:00
if ( s - > type = = SERVICE_FORKING ) {
s - > control_command_id = SERVICE_EXEC_START ;
c = s - > control_command = s - > exec_command [ SERVICE_EXEC_START ] ;
s - > main_command = NULL ;
} else {
s - > control_command_id = _SERVICE_EXEC_COMMAND_INVALID ;
s - > control_command = NULL ;
c = s - > main_command = s - > exec_command [ SERVICE_EXEC_START ] ;
}
2010-08-13 18:23:01 +02:00
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
c ,
2013-03-02 14:28:58 +01:00
s - > type = = SERVICE_FORKING | | s - > type = = SERVICE_DBUS | |
s - > type = = SERVICE_NOTIFY | | s - > type = = SERVICE_ONESHOT ,
2012-04-13 23:24:47 +02:00
true ,
true ,
true ,
true ,
s - > notify_access ! = NOTIFY_NONE ,
false ,
& pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2012-04-24 14:28:00 +02:00
if ( s - > type = = SERVICE_SIMPLE | | s - > type = = SERVICE_IDLE ) {
2010-01-26 04:18:44 +01:00
/* For simple services we immediately start
* the START_POST binaries . */
2010-06-17 22:55:53 +02:00
service_set_main_pid ( s , pid ) ;
2010-01-26 04:18:44 +01:00
service_enter_start_post ( s ) ;
} else if ( s - > type = = SERVICE_FORKING ) {
/* For forking services we wait until the start
* process exited . */
2010-06-18 22:05:29 +02:00
s - > control_pid = pid ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_START ) ;
2010-08-13 18:23:01 +02:00
} else if ( s - > type = = SERVICE_ONESHOT | |
2010-06-16 05:10:31 +02:00
s - > type = = SERVICE_DBUS | |
s - > type = = SERVICE_NOTIFY ) {
2010-01-30 02:07:35 +01:00
2010-08-13 18:23:01 +02:00
/* For oneshot services we wait until the start
2010-01-30 02:07:35 +01:00
* process exited , too , but it is our main process . */
2010-04-15 23:16:16 +02:00
/* For D-Bus services we know the main pid right away,
2010-06-16 05:10:31 +02:00
* but wait for the bus name to appear on the
* bus . Notify services are similar . */
2010-04-15 23:16:16 +02:00
2010-06-17 22:55:53 +02:00
service_set_main_pid ( s , pid ) ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_START ) ;
2010-01-26 04:18:44 +01:00
} else
assert_not_reached ( " Unknown service type " ) ;
return ;
fail :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run 'start' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
}
static void service_enter_start_pre ( Service * s ) {
int r ;
assert ( s ) ;
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2013-03-02 14:28:58 +01:00
s - > control_command = s - > exec_command [ SERVICE_EXEC_START_PRE ] ;
if ( s - > control_command ) {
2012-01-11 01:51:32 +01:00
/* Before we start anything, let's clear up what might
* be left from previous runs . */
2013-06-27 04:14:27 +02:00
service_kill_control_processes ( s ) ;
2012-01-11 01:51:32 +01:00
2011-01-20 18:46:38 +01:00
s - > control_command_id = SERVICE_EXEC_START_PRE ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
true ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_START_PRE ) ;
} else
2010-01-26 04:18:44 +01:00
service_enter_start ( s ) ;
return ;
fail :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run 'start-pre' task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_RESOURCES , true ) ;
2010-01-26 04:18:44 +01:00
}
static void service_enter_restart ( Service * s ) {
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 ;
2010-07-08 02:43:18 +02:00
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2012-07-18 02:28:08 +02:00
if ( UNIT ( s ) - > job & & UNIT ( s ) - > job - > type = = JOB_STOP ) {
/* Don't restart things if we are going down anyway */
2013-01-05 18:00:35 +01:00
log_info_unit ( UNIT ( s ) - > id ,
" Stop job pending for unit, delaying automatic restart. " ) ;
2010-11-01 17:50:43 +01:00
2013-11-19 21:12:59 +01:00
r = service_arm_timer ( s , s - > restart_usec ) ;
2012-07-18 02:28:08 +02:00
if ( r < 0 )
2010-11-01 17:50:43 +01:00
goto fail ;
2012-04-29 15:35:40 +02:00
return ;
2010-11-01 17:50:43 +01:00
}
2012-04-03 05:45:35 +02:00
/* Any units that are bound to this service must also be
* restarted . We use JOB_RESTART ( instead of the more obvious
* JOB_START ) here so that those dependency jobs will be added
* as well . */
r = manager_add_job ( UNIT ( s ) - > manager , JOB_RESTART , UNIT ( s ) , JOB_FAIL , false , & error , NULL ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2012-07-18 02:28:08 +02:00
/* Note that we stay in the SERVICE_AUTO_RESTART state here,
* it will be canceled as part of the service_stop ( ) call that
* is executed as part of JOB_RESTART . */
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
" %s scheduled restart job. " , UNIT ( s ) - > id ) ;
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 schedule restart job: %s " ,
2013-11-19 21:12:59 +01:00
UNIT ( s ) - > id , bus_error_message ( & error , - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_RESOURCES , false ) ;
2010-01-26 04:18:44 +01:00
}
static void service_enter_reload ( Service * s ) {
int r ;
assert ( s ) ;
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2013-03-02 14:28:58 +01:00
s - > control_command = s - > exec_command [ SERVICE_EXEC_RELOAD ] ;
if ( s - > control_command ) {
2011-01-20 18:46:38 +01:00
s - > control_command_id = SERVICE_EXEC_RELOAD ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
false ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
2010-04-13 02:06:27 +02:00
service_set_state ( s , SERVICE_RELOAD ) ;
} else
2012-02-03 02:01:35 +01:00
service_enter_running ( s , SERVICE_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 'reload' task: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
s - > reload_result = SERVICE_FAILURE_RESOURCES ;
service_enter_running ( s , SERVICE_SUCCESS ) ;
2010-01-26 04:18:44 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_run_next_control ( Service * s ) {
2010-01-26 04:18:44 +01:00
int r ;
assert ( s ) ;
assert ( s - > control_command ) ;
assert ( s - > control_command - > command_next ) ;
2010-08-13 18:23:01 +02:00
assert ( s - > control_command_id ! = SERVICE_EXEC_START ) ;
2010-01-26 04:18:44 +01:00
2010-08-13 18:23:01 +02:00
s - > control_command = s - > control_command - > command_next ;
2010-04-11 00:22:36 +02:00
service_unwatch_control_pid ( s ) ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > control_command ,
true ,
false ,
! s - > permissions_start_only ,
! s - > root_directory_start_only ,
s - > control_command_id = = SERVICE_EXEC_START_PRE | |
s - > control_command_id = = SERVICE_EXEC_STOP_POST ,
false ,
true ,
& s - > control_pid ) ;
if ( r < 0 )
2010-01-26 04:18:44 +01:00
goto fail ;
return ;
fail :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run next control task: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-01-26 04:18:44 +01:00
2010-04-13 02:06:27 +02:00
if ( s - > state = = SERVICE_START_PRE )
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2010-04-13 02:06:27 +02:00
else if ( s - > state = = SERVICE_STOP )
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2010-01-26 04:18:44 +01:00
else if ( s - > state = = SERVICE_STOP_POST )
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_RESOURCES , true ) ;
2011-01-20 13:17:22 +01:00
else if ( s - > state = = SERVICE_RELOAD ) {
2012-02-03 02:01:35 +01:00
s - > reload_result = SERVICE_FAILURE_RESOURCES ;
service_enter_running ( s , SERVICE_SUCCESS ) ;
2011-01-20 13:17:22 +01:00
} else
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_FAILURE_RESOURCES ) ;
2010-01-23 01:52:57 +01:00
}
2012-02-03 02:01:35 +01:00
static void service_run_next_main ( Service * s ) {
2010-08-13 18:23:01 +02:00
pid_t pid ;
int r ;
assert ( s ) ;
2011-01-20 18:46:38 +01:00
assert ( s - > main_command ) ;
assert ( s - > main_command - > command_next ) ;
assert ( s - > type = = SERVICE_ONESHOT ) ;
2010-08-13 18:23:01 +02:00
2011-01-20 18:46:38 +01:00
s - > main_command = s - > main_command - > command_next ;
2010-08-13 18:23:01 +02:00
service_unwatch_main_pid ( s ) ;
2012-04-13 23:24:47 +02:00
r = service_spawn ( s ,
s - > main_command ,
2012-06-14 17:07:07 +02:00
true ,
2012-04-13 23:24:47 +02:00
true ,
true ,
true ,
true ,
s - > notify_access ! = NOTIFY_NONE ,
false ,
& pid ) ;
if ( r < 0 )
2010-08-13 18:23:01 +02:00
goto fail ;
service_set_main_pid ( s , pid ) ;
return ;
fail :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run next main task: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_FAILURE_RESOURCES ) ;
2010-08-13 18:23:01 +02:00
}
2012-02-09 13:05:23 +01:00
static int service_start_limit_test ( Service * s ) {
assert ( s ) ;
if ( ratelimit_test ( & s - > start_limit ) )
return 0 ;
2014-03-25 14:15:45 +01:00
if ( s - > start_limit_action = = SERVICE_START_LIMIT_REBOOT | |
s - > start_limit_action = = SERVICE_START_LIMIT_REBOOT_FORCE )
update_reboot_param_file ( s - > reboot_arg ) ;
2012-02-09 13:05:23 +01:00
switch ( s - > start_limit_action ) {
case SERVICE_START_LIMIT_NONE :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s start request repeated too quickly, refusing to start. " ,
UNIT ( s ) - > id ) ;
2012-02-09 13:05:23 +01:00
break ;
case SERVICE_START_LIMIT_REBOOT : {
2013-11-19 21:12:59 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2012-02-09 13:05:23 +01:00
int r ;
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s start request repeated too quickly, rebooting. " , UNIT ( s ) - > id ) ;
2012-02-09 13:05:23 +01:00
2013-03-02 14:28:58 +01:00
r = manager_add_job_by_name ( UNIT ( s ) - > manager , JOB_START ,
SPECIAL_REBOOT_TARGET , JOB_REPLACE ,
true , & error , NULL ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
2013-01-05 18:00:35 +01:00
log_error_unit ( UNIT ( s ) - > id ,
2013-11-19 21:12:59 +01:00
" Failed to reboot: %s. " , bus_error_message ( & error , r ) ) ;
2012-02-09 13:05:23 +01:00
break ;
}
case SERVICE_START_LIMIT_REBOOT_FORCE :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s start request repeated too quickly, forcibly rebooting. " , UNIT ( s ) - > id ) ;
2012-02-09 13:05:23 +01:00
UNIT ( s ) - > manager - > exit_code = MANAGER_REBOOT ;
break ;
case SERVICE_START_LIMIT_REBOOT_IMMEDIATE :
2013-01-05 18:00:35 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s start request repeated too quickly, rebooting immediately. " , UNIT ( s ) - > id ) ;
2012-11-16 01:30:29 +01:00
sync ( ) ;
2014-03-25 14:15:45 +01:00
if ( s - > reboot_arg ) {
log_info ( " Rebooting with argument '%s'. " , s - > reboot_arg ) ;
syscall ( SYS_reboot , LINUX_REBOOT_MAGIC1 , LINUX_REBOOT_MAGIC2 ,
LINUX_REBOOT_CMD_RESTART2 , s - > reboot_arg ) ;
}
log_info ( " Rebooting. " ) ;
2012-02-09 13:05:23 +01:00
reboot ( RB_AUTOBOOT ) ;
break ;
default :
2013-01-05 18:00:35 +01:00
log_error_unit ( UNIT ( s ) - > id ,
" start limit action=%i " , s - > start_limit_action ) ;
2012-02-09 13:05:23 +01:00
assert_not_reached ( " Unknown StartLimitAction. " ) ;
}
return - ECANCELED ;
}
2010-01-26 21:39:06 +01:00
static int service_start ( Unit * u ) {
Service * s = SERVICE ( u ) ;
2012-02-09 13:05:23 +01:00
int r ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
/* We cannot fulfill this request right now, try again later
* please ! */
if ( s - > state = = SERVICE_STOP | |
s - > state = = SERVICE_STOP_SIGTERM | |
s - > state = = SERVICE_STOP_SIGKILL | |
s - > state = = SERVICE_STOP_POST | |
s - > state = = SERVICE_FINAL_SIGTERM | |
s - > state = = SERVICE_FINAL_SIGKILL )
2010-01-23 01:52:57 +01:00
return - EAGAIN ;
2010-01-26 04:18:44 +01:00
/* Already on it! */
if ( s - > state = = SERVICE_START_PRE | |
s - > state = = SERVICE_START | |
s - > state = = SERVICE_START_POST )
return 0 ;
2012-04-29 15:35:51 +02:00
/* A service that will be restarted must be stopped first to
2012-07-13 23:34:40 +02:00
* trigger BindsTo and / or OnFailure dependencies . If a user
2012-04-29 15:35:51 +02:00
* does not want to wait for the holdoff time to elapse , the
2012-07-18 02:42:43 +02:00
* service should be manually restarted , not started . We
* simply return EAGAIN here , so that any start jobs stay
* queued , and assume that the auto restart timer will
* eventually trigger the restart . */
if ( s - > state = = SERVICE_AUTO_RESTART )
2012-07-18 02:28:08 +02:00
return - EAGAIN ;
2012-04-29 15:35:51 +02:00
assert ( s - > state = = SERVICE_DEAD | | s - > state = = SERVICE_FAILED ) ;
2010-01-23 01:52:57 +01:00
2010-01-29 04:42:57 +01:00
/* Make sure we don't enter a busy loop of some kind. */
2012-02-09 13:05:23 +01:00
r = service_start_limit_test ( s ) ;
2012-03-05 22:47:54 +01:00
if ( r < 0 ) {
2012-08-22 05:02:33 +02:00
service_enter_dead ( s , SERVICE_FAILURE_START_LIMIT , false ) ;
2012-02-09 13:05:23 +01:00
return r ;
2012-03-05 22:47:54 +01:00
}
2010-01-29 04:42:57 +01:00
2012-02-03 02:01:35 +01:00
s - > result = SERVICE_SUCCESS ;
s - > reload_result = SERVICE_SUCCESS ;
2010-01-26 04:18:44 +01:00
s - > main_pid_known = false ;
2011-04-28 04:56:53 +02:00
s - > main_pid_alien = false ;
2010-08-09 23:33:48 +02:00
s - > forbid_restart = false ;
2010-01-26 04:18:44 +01:00
service_enter_start_pre ( s ) ;
return 0 ;
2010-01-23 01:52:57 +01:00
}
2010-01-26 21:39:06 +01:00
static int service_stop ( Unit * u ) {
Service * s = SERVICE ( u ) ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2012-04-29 15:35:48 +02:00
/* Don't create restart jobs from here. */
2010-08-09 23:33:48 +02:00
s - > forbid_restart = true ;
2010-01-26 04:18:44 +01:00
2010-04-10 17:53:17 +02:00
/* Already on it */
if ( s - > state = = SERVICE_STOP | |
s - > state = = SERVICE_STOP_SIGTERM | |
s - > state = = SERVICE_STOP_SIGKILL | |
s - > state = = SERVICE_STOP_POST | |
s - > state = = SERVICE_FINAL_SIGTERM | |
s - > state = = SERVICE_FINAL_SIGKILL )
return 0 ;
2012-04-29 15:35:48 +02:00
/* A restart will be scheduled or is in progress. */
2010-01-26 04:18:44 +01:00
if ( s - > state = = SERVICE_AUTO_RESTART ) {
2012-06-26 11:42:52 +02:00
service_set_state ( s , SERVICE_DEAD ) ;
2010-01-26 04:18:44 +01:00
return 0 ;
}
2010-07-10 04:52:00 +02:00
/* If there's already something running we go directly into
* kill mode . */
if ( s - > state = = SERVICE_START_PRE | |
s - > state = = SERVICE_START | |
s - > state = = SERVICE_START_POST | |
s - > state = = SERVICE_RELOAD ) {
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_SUCCESS ) ;
2010-07-10 04:52:00 +02:00
return 0 ;
}
2010-01-23 01:52:57 +01:00
2010-07-10 04:52:00 +02:00
assert ( s - > state = = SERVICE_RUNNING | |
s - > state = = SERVICE_EXITED ) ;
2010-04-23 22:55:14 +02:00
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_SUCCESS ) ;
2010-01-23 01:52:57 +01:00
return 0 ;
}
2010-01-26 21:39:06 +01:00
static int service_reload ( Unit * u ) {
Service * s = SERVICE ( u ) ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2010-04-13 02:06:27 +02:00
assert ( s - > state = = SERVICE_RUNNING | | s - > state = = SERVICE_EXITED ) ;
2010-01-26 04:18:44 +01:00
service_enter_reload ( s ) ;
2010-01-23 01:52:57 +01:00
return 0 ;
}
2013-05-03 04:51:50 +02:00
_pure_ static bool service_can_reload ( Unit * u ) {
2010-01-26 21:39:06 +01:00
Service * s = SERVICE ( u ) ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
return ! ! s - > exec_command [ SERVICE_EXEC_RELOAD ] ;
}
2010-04-21 03:27:44 +02:00
static int service_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Service * s = SERVICE ( u ) ;
assert ( u ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , service_state_to_string ( s - > state ) ) ;
2012-02-03 02:01:35 +01:00
unit_serialize_item ( u , f , " result " , service_result_to_string ( s - > result ) ) ;
unit_serialize_item ( u , f , " reload-result " , service_result_to_string ( s - > reload_result ) ) ;
2010-04-21 03:27:44 +02:00
if ( s - > control_pid > 0 )
2013-12-30 23:22:26 +01:00
unit_serialize_item_format ( u , f , " control-pid " , PID_FMT ,
s - > control_pid ) ;
2010-04-21 03:27:44 +02:00
2010-06-17 22:55:53 +02:00
if ( s - > main_pid_known & & s - > main_pid > 0 )
2013-12-30 23:22:26 +01:00
unit_serialize_item_format ( u , f , " main-pid " , PID_FMT , s - > main_pid ) ;
2010-04-21 03:27:44 +02:00
unit_serialize_item ( u , f , " main-pid-known " , yes_no ( s - > main_pid_known ) ) ;
2010-07-21 05:16:45 +02:00
if ( s - > status_text )
unit_serialize_item ( u , f , " status-text " , s - > status_text ) ;
2012-02-03 02:31:54 +01:00
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here , we will start from the
* first one again */
2010-04-21 03:27:44 +02:00
if ( s - > control_command_id > = 0 )
2013-03-02 14:28:58 +01:00
unit_serialize_item ( u , f , " control-command " ,
service_exec_command_to_string ( s - > control_command_id ) ) ;
2010-04-21 03:27:44 +02:00
if ( s - > socket_fd > = 0 ) {
int copy ;
if ( ( copy = fdset_put_dup ( fds , s - > socket_fd ) ) < 0 )
return copy ;
unit_serialize_item_format ( u , f , " socket-fd " , " %i " , copy ) ;
}
2010-07-07 04:12:59 +02:00
if ( s - > main_exec_status . pid > 0 ) {
2013-12-30 23:22:26 +01:00
unit_serialize_item_format ( u , f , " main-exec-status-pid " , PID_FMT ,
s - > main_exec_status . pid ) ;
2013-03-02 14:28:58 +01:00
dual_timestamp_serialize ( f , " main-exec-status-start " ,
& s - > main_exec_status . start_timestamp ) ;
dual_timestamp_serialize ( f , " main-exec-status-exit " ,
& s - > main_exec_status . exit_timestamp ) ;
2010-07-07 04:12:59 +02:00
2010-10-28 03:16:03 +02:00
if ( dual_timestamp_is_set ( & s - > main_exec_status . exit_timestamp ) ) {
2013-03-02 14:28:58 +01:00
unit_serialize_item_format ( u , f , " main-exec-status-code " , " %i " ,
s - > main_exec_status . code ) ;
unit_serialize_item_format ( u , f , " main-exec-status-status " , " %i " ,
s - > main_exec_status . status ) ;
2010-07-07 04:12:59 +02:00
}
}
2012-02-01 17:17:12 +01:00
if ( dual_timestamp_is_set ( & s - > watchdog_timestamp ) )
2013-12-11 20:49:43 +01:00
dual_timestamp_serialize ( f , " watchdog-timestamp " , & s - > watchdog_timestamp ) ;
2010-07-07 04:12:59 +02:00
2013-10-07 05:06:35 +02:00
if ( s - > forbid_restart )
2013-10-09 00:13:55 +02:00
unit_serialize_item ( u , f , " forbid-restart " , yes_no ( s - > forbid_restart ) ) ;
2013-10-07 05:06:35 +02:00
2010-04-21 03:27:44 +02:00
return 0 ;
}
static int service_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Service * s = SERVICE ( u ) ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
ServiceState state ;
2013-03-02 14:28:58 +01:00
state = service_state_from_string ( value ) ;
if ( state < 0 )
2013-01-05 18:00:35 +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:01:35 +01:00
} else if ( streq ( key , " result " ) ) {
ServiceResult f ;
f = service_result_from_string ( value ) ;
if ( f < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse result value %s " , value ) ;
2012-02-03 02:01:35 +01:00
else if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
} else if ( streq ( key , " reload-result " ) ) {
ServiceResult f ;
f = service_result_from_string ( value ) ;
if ( f < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse reload result value %s " , value ) ;
2012-02-03 02:01:35 +01:00
else if ( f ! = SERVICE_SUCCESS )
s - > reload_result = f ;
2010-04-21 03:27:44 +02:00
} 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-01-05 18:00:35 +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-18 22:05:29 +02:00
s - > control_pid = pid ;
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " main-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-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse main-pid value %s " , value ) ;
2013-10-01 05:06:56 +02:00
else {
service_set_main_pid ( s , pid ) ;
unit_watch_pid ( UNIT ( s ) , pid ) ;
}
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " main-pid-known " ) ) {
int b ;
2013-03-02 14:28:58 +01:00
b = parse_boolean ( value ) ;
if ( b < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse main-pid-known value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else
s - > main_pid_known = b ;
2010-07-21 05:16:45 +02:00
} else if ( streq ( key , " status-text " ) ) {
char * t ;
2013-03-02 14:28:58 +01:00
t = strdup ( value ) ;
if ( ! t )
log_oom ( ) ;
else {
2010-07-21 05:16:45 +02:00
free ( s - > status_text ) ;
s - > status_text = t ;
}
2010-04-21 03:27:44 +02:00
} else if ( streq ( key , " control-command " ) ) {
ServiceExecCommand id ;
2013-03-02 14:28:58 +01:00
id = service_exec_command_from_string ( value ) ;
if ( id < 0 )
2013-01-05 18:00:35 +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 , " socket-fd " ) ) {
int fd ;
if ( safe_atoi ( value , & fd ) < 0 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse socket-fd value %s " , value ) ;
2010-04-21 03:27:44 +02:00
else {
2014-03-18 19:22:43 +01:00
safe_close ( s - > socket_fd ) ;
2010-04-21 03:27:44 +02:00
s - > socket_fd = fdset_remove ( fds , fd ) ;
}
2010-07-07 04:12:59 +02:00
} else if ( streq ( key , " main-exec-status-pid " ) ) {
pid_t pid ;
2010-08-11 22:04:22 +02:00
if ( parse_pid ( value , & pid ) < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse main-exec-status-pid value %s " , value ) ;
2010-07-07 04:12:59 +02:00
else
s - > main_exec_status . pid = pid ;
} else if ( streq ( key , " main-exec-status-code " ) ) {
int i ;
2010-08-11 22:04:22 +02:00
if ( safe_atoi ( value , & i ) < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse main-exec-status-code value %s " , value ) ;
2010-07-07 04:12:59 +02:00
else
s - > main_exec_status . code = i ;
} else if ( streq ( key , " main-exec-status-status " ) ) {
int i ;
2010-08-11 22:04:22 +02:00
if ( safe_atoi ( value , & i ) < 0 )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Failed to parse main-exec-status-status value %s " , value ) ;
2010-07-07 04:12:59 +02:00
else
s - > main_exec_status . status = i ;
2010-10-28 03:16:03 +02:00
} else if ( streq ( key , " main-exec-status-start " ) )
dual_timestamp_deserialize ( value , & s - > main_exec_status . start_timestamp ) ;
else if ( streq ( key , " main-exec-status-exit " ) )
dual_timestamp_deserialize ( value , & s - > main_exec_status . exit_timestamp ) ;
2012-02-01 17:17:12 +01:00
else if ( streq ( key , " watchdog-timestamp " ) )
dual_timestamp_deserialize ( value , & s - > watchdog_timestamp ) ;
2013-11-27 20:23:18 +01:00
else if ( streq ( key , " forbid-restart " ) ) {
2013-10-07 05:06:35 +02:00
int b ;
b = parse_boolean ( value ) ;
if ( b < 0 )
2013-10-09 00:13:55 +02:00
log_debug_unit ( u - > id , " Failed to parse forbid-restart value %s " , value ) ;
2013-10-07 05:06:35 +02:00
else
s - > forbid_restart = b ;
2013-03-14 18:12:27 +01:00
} else
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id , " Unknown serialization key '%s' " , key ) ;
2010-04-21 03:27:44 +02:00
return 0 ;
}
2013-05-03 04:51:50 +02:00
_pure_ static UnitActiveState service_active_state ( Unit * u ) {
2012-05-24 02:22:35 +02:00
const UnitActiveState * table ;
2010-01-26 21:39:06 +01:00
assert ( u ) ;
2010-01-23 01:52:57 +01:00
2012-05-24 02:22:35 +02:00
table = SERVICE ( u ) - > type = = SERVICE_IDLE ? state_translation_table_idle : state_translation_table ;
return table [ SERVICE ( u ) - > state ] ;
2010-01-26 04:18:44 +01:00
}
2010-04-13 20:59:01 +02:00
static const char * service_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
return service_state_to_string ( SERVICE ( u ) - > state ) ;
}
2010-04-21 06:01:13 +02:00
static bool service_check_gc ( Unit * u ) {
Service * s = SERVICE ( u ) ;
assert ( s ) ;
2011-02-25 01:49:10 +01:00
/* Never clean up services that still have a process around,
* even if the service is formally dead . */
if ( cgroup_good ( s ) > 0 | |
main_pid_good ( s ) > 0 | |
control_pid_good ( s ) > 0 )
return true ;
# ifdef HAVE_SYSV_COMPAT
2012-05-22 23:08:24 +02:00
if ( s - > is_sysv )
2011-02-25 01:49:10 +01:00
return true ;
2010-09-21 05:23:12 +02:00
# endif
2010-04-21 06:01:13 +02:00
2011-02-25 01:49:10 +01:00
return false ;
}
2013-05-03 04:51:50 +02:00
_pure_ static bool service_check_snapshot ( Unit * u ) {
2010-04-21 06:01:13 +02:00
Service * s = SERVICE ( u ) ;
assert ( s ) ;
2013-11-20 09:35:04 +01:00
return ( s - > socket_fd < 0 ) ;
2010-04-21 06:01:13 +02:00
}
2011-12-03 02:13:30 +01:00
static int service_retry_pid_file ( Service * s ) {
int r ;
assert ( s - > pid_file ) ;
assert ( s - > state = = SERVICE_START | | s - > state = = SERVICE_START_POST ) ;
r = service_load_pid_file ( s , false ) ;
if ( r < 0 )
return r ;
service_unwatch_pid_file ( s ) ;
2012-02-03 02:01:35 +01:00
service_enter_running ( s , SERVICE_SUCCESS ) ;
2011-12-03 02:13:30 +01:00
return 0 ;
}
static int service_watch_pid_file ( Service * s ) {
int r ;
2013-01-05 18:00:35 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
" Setting watch for %s's PID file %s " ,
UNIT ( s ) - > id , s - > pid_file_pathspec - > path ) ;
2013-11-19 21:12:59 +01:00
r = path_spec_watch ( s - > pid_file_pathspec , service_dispatch_io ) ;
2011-12-03 02:13:30 +01:00
if ( r < 0 )
goto fail ;
/* the pidfile might have appeared just before we set the watch */
2013-03-03 07:32:34 +01:00
log_debug_unit ( UNIT ( s ) - > id ,
" Trying to read %s's PID file %s in case it changed " ,
UNIT ( s ) - > id , s - > pid_file_pathspec - > path ) ;
2011-12-03 02:13:30 +01:00
service_retry_pid_file ( s ) ;
return 0 ;
fail :
2013-01-05 18:00:35 +01:00
log_error_unit ( UNIT ( s ) - > id ,
" Failed to set a watch for %s's PID file %s: %s " ,
UNIT ( s ) - > id , s - > pid_file_pathspec - > path , strerror ( - r ) ) ;
2011-12-03 02:13:30 +01:00
service_unwatch_pid_file ( s ) ;
return r ;
}
static int service_demand_pid_file ( Service * s ) {
PathSpec * ps ;
assert ( s - > pid_file ) ;
assert ( ! s - > pid_file_pathspec ) ;
ps = new0 ( PathSpec , 1 ) ;
if ( ! ps )
return - ENOMEM ;
2013-11-19 21:12:59 +01:00
ps - > unit = UNIT ( s ) ;
2011-12-03 02:13:30 +01:00
ps - > path = strdup ( s - > pid_file ) ;
if ( ! ps - > path ) {
free ( ps ) ;
return - ENOMEM ;
}
path_kill_slashes ( ps - > path ) ;
/* PATH_CHANGED would not be enough. There are daemons (sendmail) that
* keep their PID file open all the time . */
ps - > type = PATH_MODIFIED ;
ps - > inotify_fd = - 1 ;
s - > pid_file_pathspec = ps ;
return service_watch_pid_file ( s ) ;
}
2013-11-19 21:12:59 +01:00
static int service_dispatch_io ( sd_event_source * source , int fd , uint32_t events , void * userdata ) {
2013-11-25 22:20:57 +01:00
PathSpec * p = userdata ;
Service * s ;
assert ( p ) ;
s = SERVICE ( p - > unit ) ;
2011-12-03 02:13:30 +01:00
assert ( s ) ;
assert ( fd > = 0 ) ;
assert ( s - > state = = SERVICE_START | | s - > state = = SERVICE_START_POST ) ;
assert ( s - > pid_file_pathspec ) ;
2012-01-06 23:08:54 +01:00
assert ( path_spec_owns_inotify_fd ( s - > pid_file_pathspec , fd ) ) ;
2011-12-03 02:13:30 +01:00
2013-11-19 21:12:59 +01:00
log_debug_unit ( UNIT ( s ) - > id , " inotify event for %s " , UNIT ( s ) - > id ) ;
2011-12-03 02:13:30 +01:00
2013-11-25 22:20:57 +01:00
if ( path_spec_fd_event ( p , events ) < 0 )
2011-12-03 02:13:30 +01:00
goto fail ;
if ( service_retry_pid_file ( s ) = = 0 )
2013-11-19 21:12:59 +01:00
return 0 ;
2011-12-03 02:13:30 +01:00
if ( service_watch_pid_file ( s ) < 0 )
goto fail ;
2013-11-19 21:12:59 +01:00
return 0 ;
2011-12-03 02:13:30 +01:00
fail :
service_unwatch_pid_file ( s ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2013-11-19 21:12:59 +01:00
return 0 ;
2011-12-03 02:13:30 +01:00
}
2014-02-06 17:17:51 +01:00
static void service_notify_cgroup_empty_event ( Unit * u ) {
Service * s = SERVICE ( u ) ;
assert ( u ) ;
log_debug_unit ( u - > id , " %s: cgroup is empty " , u - > id ) ;
switch ( s - > state ) {
/* Waiting for SIGCHLD is usually more interesting,
* because it includes return codes / signals . Which is
* why we ignore the cgroup events for most cases ,
* except when we don ' t know pid which to expect the
* SIGCHLD for . */
case SERVICE_START :
case SERVICE_START_POST :
/* If we were hoping for the daemon to write its PID file,
* we can give up now . */
if ( s - > pid_file_pathspec ) {
log_warning_unit ( u - > id ,
" %s never wrote its PID file. Failing. " , UNIT ( s ) - > id ) ;
service_unwatch_pid_file ( s ) ;
if ( s - > state = = SERVICE_START )
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
else
service_enter_stop ( s , SERVICE_FAILURE_RESOURCES ) ;
}
break ;
case SERVICE_RUNNING :
/* service_enter_running() will figure out what to do */
service_enter_running ( s , SERVICE_SUCCESS ) ;
break ;
case SERVICE_STOP_SIGTERM :
case SERVICE_STOP_SIGKILL :
if ( main_pid_good ( s ) < = 0 & & ! control_pid_good ( s ) )
service_enter_stop_post ( s , SERVICE_SUCCESS ) ;
break ;
case SERVICE_STOP_POST :
case SERVICE_FINAL_SIGTERM :
case SERVICE_FINAL_SIGKILL :
if ( main_pid_good ( s ) < = 0 & & ! control_pid_good ( s ) )
service_enter_dead ( s , SERVICE_SUCCESS , true ) ;
break ;
default :
;
}
}
2010-01-26 21:39:06 +01:00
static void service_sigchld_event ( Unit * u , pid_t pid , int code , int status ) {
Service * s = SERVICE ( u ) ;
2012-02-03 02:01:35 +01:00
ServiceResult f ;
2010-01-23 01:52:57 +01:00
assert ( s ) ;
2010-01-26 04:18:44 +01:00
assert ( pid > = 0 ) ;
2012-08-13 13:58:01 +02:00
if ( UNIT ( s ) - > fragment_path ? is_clean_exit ( code , status , & s - > success_status ) :
is_clean_exit_lsb ( code , status , & s - > success_status ) )
2012-02-03 02:01:35 +01:00
f = SERVICE_SUCCESS ;
else if ( code = = CLD_EXITED )
f = SERVICE_FAILURE_EXIT_CODE ;
else if ( code = = CLD_KILLED )
f = SERVICE_FAILURE_SIGNAL ;
else if ( code = = CLD_DUMPED )
f = SERVICE_FAILURE_CORE_DUMP ;
2010-08-19 03:18:49 +02:00
else
2012-02-03 02:31:54 +01:00
assert_not_reached ( " Unknown code " ) ;
2010-01-26 04:18:44 +01:00
if ( s - > main_pid = = pid ) {
2011-09-20 21:43:30 +02:00
/* Forking services may occasionally move to a new PID.
* As long as they update the PID file before exiting the old
* PID , they ' re fine . */
2011-09-22 13:10:32 +02:00
if ( service_load_pid_file ( s , false ) = = 0 )
2011-09-20 21:43:30 +02:00
return ;
2010-01-26 04:18:44 +01:00
s - > main_pid = 0 ;
2011-05-18 01:07:31 +02:00
exec_status_exit ( & s - > main_exec_status , & s - > exec_context , pid , code , status ) ;
2010-01-26 04:18:44 +01:00
2011-01-20 18:46:38 +01:00
if ( s - > main_command ) {
2013-01-14 21:05:17 +01:00
/* If this is not a forking service than the
* main process got started and hence we copy
* the exit status so that it is recorded both
* as main and as control process exit
* status */
2011-01-20 18:46:38 +01:00
s - > main_command - > exec_status = s - > main_exec_status ;
2010-07-12 02:25:42 +02:00
2011-01-20 18:46:38 +01:00
if ( s - > main_command - > ignore )
2012-02-03 02:01:35 +01:00
f = SERVICE_SUCCESS ;
2013-01-14 21:05:17 +01:00
} else if ( s - > exec_command [ SERVICE_EXEC_START ] ) {
/* If this is a forked process, then we should
* ignore the return value if this was
* configured for the starter process */
if ( s - > exec_command [ SERVICE_EXEC_START ] - > ignore )
f = SERVICE_SUCCESS ;
2010-01-26 04:18:44 +01:00
}
2013-01-17 18:55:06 +01:00
log_struct_unit ( f = = SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE ,
u - > id ,
2012-10-11 00:11:24 +02:00
" MESSAGE=%s: main process exited, code=%s, status=%i/%s " ,
u - > id , sigchld_code_to_string ( code ) , status ,
strna ( code = = CLD_EXITED
? exit_status_to_string ( status , EXIT_STATUS_FULL )
: signal_to_string ( status ) ) ,
" EXIT_CODE=%s " , sigchld_code_to_string ( code ) ,
" EXIT_STATUS=%i " , status ,
NULL ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2011-01-20 18:46:38 +01:00
if ( s - > main_command & &
s - > main_command - > command_next & &
2012-02-03 02:01:35 +01:00
f = = SERVICE_SUCCESS ) {
2010-01-26 04:18:44 +01:00
2010-08-13 18:23:01 +02:00
/* There is another command to *
* execute , so let ' s do that . */
2010-01-26 04:18:44 +01:00
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s running next main command for state %s " ,
u - > id , service_state_to_string ( s - > state ) ) ;
2012-02-03 02:01:35 +01:00
service_run_next_main ( s ) ;
2010-01-26 04:18:44 +01:00
2010-08-13 18:23:01 +02:00
} else {
/* The service exited, so the service is officially
* gone . */
2011-01-20 18:46:38 +01:00
s - > main_command = NULL ;
2010-08-13 18:23:01 +02:00
switch ( s - > state ) {
case SERVICE_START_POST :
case SERVICE_RELOAD :
case SERVICE_STOP :
/* Need to wait until the operation is
* done */
2010-06-04 21:23:00 +02:00
break ;
2010-01-30 02:07:35 +01:00
2010-08-13 18:23:01 +02:00
case SERVICE_START :
if ( s - > type = = SERVICE_ONESHOT ) {
/* This was our main goal, so let's go on */
2012-02-03 02:01:35 +01:00
if ( f = = SERVICE_SUCCESS )
2010-08-13 18:23:01 +02:00
service_enter_start_post ( s ) ;
else
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , f ) ;
2010-08-13 18:23:01 +02:00
break ;
}
2010-01-26 04:18:44 +01:00
2012-09-17 14:55:56 +02:00
/* Fall through */
2010-08-13 18:23:01 +02:00
case SERVICE_RUNNING :
2012-02-03 02:01:35 +01:00
service_enter_running ( s , f ) ;
2010-08-13 18:23:01 +02:00
break ;
2010-01-26 04:18:44 +01:00
2010-08-13 18:23:01 +02:00
case SERVICE_STOP_SIGTERM :
case SERVICE_STOP_SIGKILL :
2010-01-23 01:52:57 +01:00
2010-08-13 18:23:01 +02:00
if ( ! control_pid_good ( s ) )
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , f ) ;
2010-01-23 01:52:57 +01:00
2010-08-13 18:23:01 +02:00
/* If there is still a control process, wait for that first */
break ;
2013-12-18 04:19:20 +01:00
case SERVICE_STOP_POST :
case SERVICE_FINAL_SIGTERM :
case SERVICE_FINAL_SIGKILL :
if ( ! control_pid_good ( s ) )
service_enter_dead ( s , f , true ) ;
break ;
2010-08-13 18:23:01 +02:00
default :
assert_not_reached ( " Uh, main process died at wrong time. " ) ;
}
2010-01-26 04:18:44 +01:00
}
2010-01-23 01:52:57 +01:00
2010-01-26 04:18:44 +01:00
} else if ( s - > control_pid = = pid ) {
2010-08-13 18:23:01 +02:00
s - > control_pid = 0 ;
2010-07-12 02:25:42 +02:00
if ( s - > control_command ) {
2013-03-02 14:28:58 +01: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:01:35 +01:00
f = SERVICE_SUCCESS ;
2010-07-12 02:25:42 +02:00
}
2013-01-05 18:00:35 +01:00
log_full_unit ( f = = SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE , u - > id ,
" %s: control process exited, code=%s status=%i " ,
u - > id , sigchld_code_to_string ( code ) , status ) ;
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS )
s - > result = f ;
2010-01-26 04:18:44 +01:00
2012-05-03 21:54:44 +02:00
/* Immediately get rid of the cgroup, so that the
* kernel doesn ' t delay the cgroup empty messages for
* the service cgroup any longer than necessary */
2013-06-27 04:14:27 +02:00
service_kill_control_processes ( s ) ;
2012-05-03 21:54:44 +02:00
2010-08-13 18:23:01 +02:00
if ( s - > control_command & &
s - > control_command - > command_next & &
2012-02-03 02:01:35 +01:00
f = = SERVICE_SUCCESS ) {
2010-01-26 04:18:44 +01:00
/* There is another command to *
* execute , so let ' s do that . */
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s running next control command for state %s " ,
u - > id , service_state_to_string ( s - > state ) ) ;
2012-02-03 02:01:35 +01:00
service_run_next_control ( s ) ;
2010-01-26 04:18:44 +01:00
2010-04-13 02:06:27 +02:00
} else {
2010-01-26 04:18:44 +01:00
/* No further commands for this step, so let's
* figure out what to do next */
2010-04-21 03:27:44 +02:00
s - > control_command = NULL ;
s - > control_command_id = _SERVICE_EXEC_COMMAND_INVALID ;
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s got final SIGCHLD for state %s " ,
u - > id , service_state_to_string ( s - > state ) ) ;
2010-01-27 05:32:31 +01:00
2010-01-26 04:18:44 +01:00
switch ( s - > state ) {
case SERVICE_START_PRE :
2012-02-03 02:01:35 +01:00
if ( f = = SERVICE_SUCCESS )
2010-01-26 04:18:44 +01:00
service_enter_start ( s ) ;
else
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , f ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_START :
2012-09-17 14:55:56 +02:00
if ( s - > type ! = SERVICE_FORKING )
/* Maybe spurious event due to a reload that changed the type? */
break ;
2010-01-26 04:18:44 +01:00
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS ) {
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , f ) ;
2011-12-03 02:13:30 +01:00
break ;
}
2010-01-26 04:18:44 +01:00
2011-12-03 02:13:30 +01:00
if ( s - > pid_file ) {
2012-02-03 02:01:35 +01:00
bool has_start_post ;
int r ;
2011-12-03 02:13:30 +01:00
/* Let's try to load the pid file here if we can.
* The PID file might actually be created by a START_POST
* script . In that case don ' t worry if the loading fails . */
2012-02-03 02:01:35 +01:00
has_start_post = ! ! s - > exec_command [ SERVICE_EXEC_START_POST ] ;
r = service_load_pid_file ( s , ! has_start_post ) ;
2011-12-03 02:13:30 +01:00
if ( ! has_start_post & & r < 0 ) {
r = service_demand_pid_file ( s ) ;
if ( r < 0 | | ! cgroup_good ( s ) )
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_RESOURCES ) ;
2011-12-03 02:13:30 +01:00
break ;
}
2010-01-26 04:18:44 +01:00
} else
2011-12-03 02:13:30 +01:00
service_search_main_pid ( s ) ;
2010-01-26 04:18:44 +01:00
2011-12-03 02:13:30 +01:00
service_enter_start_post ( s ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_START_POST :
2012-02-03 02:01:35 +01:00
if ( f ! = SERVICE_SUCCESS ) {
service_enter_stop ( s , f ) ;
2011-12-03 21:34:34 +01:00
break ;
2010-01-26 04:18:44 +01:00
}
2011-12-03 21:34:34 +01:00
if ( s - > pid_file ) {
2012-02-03 02:01:35 +01:00
int r ;
r = service_load_pid_file ( s , true ) ;
2011-12-03 21:34:34 +01:00
if ( r < 0 ) {
r = service_demand_pid_file ( s ) ;
if ( r < 0 | | ! cgroup_good ( s ) )
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_FAILURE_RESOURCES ) ;
2011-12-03 21:34:34 +01:00
break ;
}
} else
service_search_main_pid ( s ) ;
2012-02-03 02:01:35 +01:00
service_enter_running ( s , SERVICE_SUCCESS ) ;
2011-02-13 18:51:30 +01:00
break ;
2010-01-26 04:18:44 +01:00
case SERVICE_RELOAD :
2012-02-03 02:01:35 +01:00
if ( f = = SERVICE_SUCCESS ) {
2011-09-22 13:10:32 +02:00
service_load_pid_file ( s , true ) ;
2011-02-13 18:51:30 +01:00
service_search_main_pid ( s ) ;
}
2012-02-03 02:01:35 +01:00
s - > reload_result = f ;
service_enter_running ( s , SERVICE_SUCCESS ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_STOP :
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , f ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_STOP_SIGTERM :
case SERVICE_STOP_SIGKILL :
if ( main_pid_good ( s ) < = 0 )
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , f ) ;
2010-01-26 04:18:44 +01:00
/* If there is still a service
* process around , wait until
* that one quit , too */
break ;
case SERVICE_STOP_POST :
case SERVICE_FINAL_SIGTERM :
case SERVICE_FINAL_SIGKILL :
2013-12-18 04:19:20 +01:00
if ( main_pid_good ( s ) < = 0 )
service_enter_dead ( s , f , true ) ;
2010-01-26 04:18:44 +01:00
break ;
default :
assert_not_reached ( " Uh, control process died at wrong time. " ) ;
}
}
2010-06-16 05:10:31 +02:00
}
2010-08-20 02:26:05 +02:00
/* Notify clients about changed exit status */
unit_add_to_dbus_queue ( u ) ;
2014-02-06 17:17:51 +01:00
/* We got one SIGCHLD for the service, let's watch all
* processes that are now running of the service , and watch
* that . Among the PIDs we then watch will be children
* reassigned to us , which hopefully allows us to identify
* when all children are gone */
unit_tidy_watch_pids ( u , s - > main_pid , s - > control_pid ) ;
unit_watch_all_pids ( u ) ;
/* If the PID set is empty now, then let's finish this off */
if ( set_isempty ( u - > pids ) )
service_notify_cgroup_empty_event ( u ) ;
2010-01-26 04:18:44 +01:00
}
2013-11-19 21:12:59 +01:00
static int service_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) {
Service * s = SERVICE ( userdata ) ;
2010-01-26 04:18:44 +01:00
assert ( s ) ;
2013-11-19 21:12:59 +01:00
assert ( source = = s - > timer_event_source ) ;
2010-01-26 04:18:44 +01:00
switch ( s - > state ) {
case SERVICE_START_PRE :
case SERVICE_START :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s %s operation timed out. Terminating. " ,
UNIT ( s ) - > id ,
s - > state = = SERVICE_START ? " start " : " start-pre " ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_TIMEOUT ) ;
2010-04-13 02:06:27 +02:00
break ;
2010-01-26 04:18:44 +01:00
case SERVICE_START_POST :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s start-post operation timed out. Stopping. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_stop ( s , SERVICE_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
2011-01-20 13:17:22 +01:00
case SERVICE_RELOAD :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s reload operation timed out. Stopping. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
s - > reload_result = SERVICE_FAILURE_TIMEOUT ;
service_enter_running ( s , SERVICE_SUCCESS ) ;
2011-01-20 13:17:22 +01:00
break ;
2010-01-26 04:18:44 +01:00
case SERVICE_STOP :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s stopping timed out. Terminating. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_STOP_SIGTERM :
2012-07-19 23:47:10 +02:00
if ( s - > kill_context . send_sigkill ) {
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s stop-sigterm timed out. Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_STOP_SIGKILL , SERVICE_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
} else {
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s stop-sigterm timed out. Skipping SIGKILL. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , SERVICE_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
}
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_STOP_SIGKILL :
2011-02-21 15:32:17 +01:00
/* Uh, we sent a SIGKILL and it is still not gone?
2010-01-26 04:18:44 +01:00
* Must be something we cannot kill , so let ' s just be
* weirded out and continue */
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s still around after SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_stop_post ( s , SERVICE_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_STOP_POST :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s stop-post timed out. Terminating. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGTERM , SERVICE_FAILURE_TIMEOUT ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_FINAL_SIGTERM :
2012-07-19 23:47:10 +02:00
if ( s - > kill_context . send_sigkill ) {
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s stop-final-sigterm timed out. Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_signal ( s , SERVICE_FINAL_SIGKILL , SERVICE_FAILURE_TIMEOUT ) ;
2011-01-18 22:55:54 +01:00
} else {
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode. " ,
2013-11-19 21:12:59 +01:00
UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_TIMEOUT , false ) ;
2011-01-18 22:55:54 +01:00
}
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_FINAL_SIGKILL :
2013-11-19 21:12:59 +01:00
log_warning_unit ( UNIT ( s ) - > id ,
2013-12-28 02:03:27 +01:00
" %s still around after final SIGKILL. Entering failed mode. " , UNIT ( s ) - > id ) ;
2012-02-03 02:01:35 +01:00
service_enter_dead ( s , SERVICE_FAILURE_TIMEOUT , true ) ;
2010-01-26 04:18:44 +01:00
break ;
case SERVICE_AUTO_RESTART :
2013-11-19 21:12:59 +01:00
log_info_unit ( UNIT ( s ) - > id ,
2014-02-13 23:10:12 +01:00
s - > restart_usec > 0 ?
" %s holdoff time over, scheduling restart. " :
" %s has no holdoff time, scheduling restart. " ,
UNIT ( s ) - > id ) ;
2010-01-26 04:18:44 +01:00
service_enter_restart ( s ) ;
break ;
default :
assert_not_reached ( " Timeout at wrong time. " ) ;
}
2013-11-19 21:12:59 +01:00
return 0 ;
}
static int service_dispatch_watchdog ( sd_event_source * source , usec_t usec , void * userdata ) {
Service * s = SERVICE ( userdata ) ;
assert ( s ) ;
assert ( source = = s - > watchdog_event_source ) ;
2013-12-11 20:49:43 +01:00
log_error_unit ( UNIT ( s ) - > id , " %s watchdog timeout! " , UNIT ( s ) - > id ) ;
service_enter_signal ( s , SERVICE_STOP_SIGTERM , SERVICE_FAILURE_WATCHDOG ) ;
2013-11-19 21:12:59 +01:00
return 0 ;
2010-01-23 01:52:57 +01:00
}
2010-06-18 23:12:48 +02:00
static void service_notify_message ( Unit * u , pid_t pid , char * * tags ) {
2010-06-16 05:10:31 +02:00
Service * s = SERVICE ( u ) ;
const char * e ;
2013-12-19 21:34:09 +01:00
bool notify_dbus = false ;
2010-06-16 05:10:31 +02:00
assert ( u ) ;
2013-12-30 23:22:26 +01:00
log_debug_unit ( u - > id , " %s: Got notification message from PID " PID_FMT " (%s...) " ,
u - > id , pid , tags & & * tags ? tags [ 0 ] : " (empty) " ) ;
2013-12-30 17:21:56 +01:00
2010-06-18 23:12:48 +02:00
if ( s - > notify_access = = NOTIFY_NONE ) {
2013-01-05 18:00:35 +01:00
log_warning_unit ( u - > id ,
2013-12-30 23:22:26 +01:00
" %s: Got notification message from PID " PID_FMT " , but reception is disabled. " ,
u - > id , pid ) ;
2010-06-18 23:12:48 +02:00
return ;
}
2014-02-14 02:04:09 +01:00
if ( s - > notify_access = = NOTIFY_MAIN & & pid ! = s - > main_pid ) {
if ( s - > main_pid ! = 0 )
log_warning_unit ( u - > id , " %s: Got notification message from PID " PID_FMT " , but reception only permitted for main PID " PID_FMT , u - > id , pid , s - > main_pid ) ;
else
2014-02-14 02:05:40 +01:00
log_debug_unit ( u - > id , " %s: Got notification message from PID " PID_FMT " , but reception only permitted for main PID which is currently not known " , u - > id , pid ) ;
2010-06-18 23:12:48 +02:00
return ;
}
2010-06-16 05:10:31 +02:00
/* Interpret MAINPID= */
if ( ( e = strv_find_prefix ( tags , " MAINPID= " ) ) & &
( s - > state = = SERVICE_START | |
s - > state = = SERVICE_START_POST | |
s - > state = = SERVICE_RUNNING | |
s - > state = = SERVICE_RELOAD ) ) {
2010-06-17 22:55:53 +02:00
if ( parse_pid ( e + 8 , & pid ) < 0 )
2013-12-19 21:34:09 +01:00
log_warning_unit ( u - > id , " Failed to parse notification message %s " , e ) ;
2010-06-16 05:10:31 +02:00
else {
2013-12-19 21:34:09 +01:00
log_debug_unit ( u - > id , " %s: got %s " , u - > id , e ) ;
2010-06-17 22:55:53 +02:00
service_set_main_pid ( s , pid ) ;
2013-10-01 05:06:56 +02:00
unit_watch_pid ( UNIT ( s ) , pid ) ;
2013-12-19 21:34:09 +01:00
notify_dbus = true ;
2010-06-16 05:10:31 +02:00
}
}
/* Interpret READY= */
2013-12-19 21:34:09 +01:00
if ( s - > type = = SERVICE_NOTIFY & & s - > state = = SERVICE_START & & strv_find ( tags , " READY=1 " ) ) {
log_debug_unit ( u - > id , " %s: got READY=1 " , u - > id ) ;
2010-06-16 05:10:31 +02:00
service_enter_start_post ( s ) ;
2013-12-19 21:34:09 +01:00
notify_dbus = true ;
2010-06-16 05:10:31 +02:00
}
/* Interpret STATUS= */
2012-03-12 22:22:16 +01:00
e = strv_find_prefix ( tags , " STATUS= " ) ;
if ( e ) {
2010-06-16 05:10:31 +02:00
char * t ;
2010-07-21 05:16:45 +02:00
if ( e [ 7 ] ) {
2012-03-12 22:22:16 +01:00
if ( ! utf8_is_valid ( e + 7 ) ) {
2013-12-19 21:34:09 +01:00
log_warning_unit ( u - > id , " Status message in notification is not UTF-8 clean. " ) ;
2012-03-12 22:22:16 +01:00
return ;
}
2013-12-19 21:34:09 +01:00
log_debug_unit ( u - > id , " %s: got %s " , u - > id , e ) ;
2012-03-12 22:22:16 +01:00
t = strdup ( e + 7 ) ;
if ( ! t ) {
2013-12-19 21:34:09 +01:00
log_oom ( ) ;
2010-07-21 05:16:45 +02:00
return ;
}
2013-12-19 21:34:09 +01:00
} else
t = NULL ;
2010-06-16 05:10:31 +02:00
2013-12-19 21:34:09 +01:00
if ( ! streq_ptr ( s - > status_text , t ) ) {
2010-07-21 05:16:45 +02:00
free ( s - > status_text ) ;
s - > status_text = t ;
2013-12-19 21:34:09 +01:00
notify_dbus = true ;
} else
free ( t ) ;
2010-06-16 05:10:31 +02:00
}
2013-12-11 20:49:43 +01:00
2014-03-14 21:13:38 +01:00
/* Interpret WATCHDOG= */
2012-02-01 17:17:12 +01:00
if ( strv_find ( tags , " WATCHDOG=1 " ) ) {
2013-12-11 20:49:43 +01:00
log_debug_unit ( u - > id , " %s: got WATCHDOG=1 " , u - > id ) ;
service_reset_watchdog ( s ) ;
2012-02-01 17:17:12 +01:00
}
2010-08-20 02:26:05 +02:00
/* Notify clients about changed status or main pid */
2013-12-19 21:34:09 +01:00
if ( notify_dbus )
unit_add_to_dbus_queue ( u ) ;
2010-06-16 05:10:31 +02:00
}
2014-01-27 06:57:34 +01:00
static int service_get_timeout ( Unit * u , uint64_t * timeout ) {
Service * s = SERVICE ( 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-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2011-06-29 13:59:34 +02:00
2010-02-14 01:09:01 +01:00
static int service_enumerate ( Manager * m ) {
char * * p ;
unsigned i ;
2013-04-18 09:11:22 +02:00
_cleanup_closedir_ DIR * d = NULL ;
_cleanup_free_ char * path = NULL , * fpath = NULL , * name = NULL ;
2013-03-25 00:59:00 +01:00
Set * runlevel_services [ ELEMENTSOF ( rcnd_table ) ] = { } ;
2013-04-18 09:11:22 +02:00
_cleanup_set_free_ Set * shutdown_services = NULL ;
2010-09-03 03:56:05 +02:00
Unit * service ;
Iterator j ;
2010-02-14 01:09:01 +01:00
int r ;
assert ( m ) ;
2012-09-18 17:11:12 +02:00
if ( m - > running_as ! = SYSTEMD_SYSTEM )
2011-07-01 23:53:44 +02:00
return 0 ;
2010-06-15 14:45:15 +02:00
STRV_FOREACH ( p , m - > lookup_paths . sysvrcnd_path )
2010-04-24 05:02:25 +02:00
for ( i = 0 ; i < ELEMENTSOF ( rcnd_table ) ; i + + ) {
2010-02-14 01:09:01 +01:00
struct dirent * de ;
free ( path ) ;
2012-07-13 13:41:01 +02:00
path = strjoin ( * p , " / " , rcnd_table [ i ] . path , NULL ) ;
2011-08-01 01:55:31 +02:00
if ( ! path ) {
2010-02-14 01:09:01 +01:00
r = - ENOMEM ;
goto finish ;
}
if ( d )
closedir ( d ) ;
2013-03-02 14:28:58 +01:00
d = opendir ( path ) ;
if ( ! d ) {
2010-02-14 01:09:01 +01:00
if ( errno ! = ENOENT )
2013-11-26 09:38:02 +01:00
log_warning ( " opendir(%s) failed: %m " , path ) ;
2010-02-14 01:09:01 +01:00
continue ;
}
while ( ( de = readdir ( d ) ) ) {
2010-04-24 04:26:33 +02:00
int a , b ;
2010-02-14 01:09:01 +01:00
if ( ignore_file ( de - > d_name ) )
continue ;
if ( de - > d_name [ 0 ] ! = ' S ' & & de - > d_name [ 0 ] ! = ' K ' )
continue ;
if ( strlen ( de - > d_name ) < 4 )
continue ;
2010-04-24 04:26:33 +02:00
a = undecchar ( de - > d_name [ 1 ] ) ;
b = undecchar ( de - > d_name [ 2 ] ) ;
if ( a < 0 | | b < 0 )
continue ;
2010-02-14 01:09:01 +01:00
free ( fpath ) ;
2012-07-13 13:41:01 +02:00
fpath = strjoin ( path , " / " , de - > d_name , NULL ) ;
2011-09-23 01:43:28 +02:00
if ( ! fpath ) {
2010-02-14 01:09:01 +01:00
r = - ENOMEM ;
goto finish ;
}
if ( access ( fpath , X_OK ) < 0 ) {
if ( errno ! = ENOENT )
2013-11-26 09:38:02 +01:00
log_warning ( " access() failed on %s: %m " , fpath ) ;
2010-02-14 01:09:01 +01:00
continue ;
}
free ( name ) ;
2013-03-02 14:28:58 +01:00
name = sysv_translate_name ( de - > d_name + 3 ) ;
if ( ! name ) {
r = log_oom ( ) ;
2010-02-14 01:09:01 +01:00
goto finish ;
}
2013-01-05 18:00:35 +01:00
r = manager_load_unit_prepare ( m , name , NULL , NULL , & service ) ;
if ( r < 0 ) {
2010-05-13 22:24:22 +02:00
log_warning ( " Failed to prepare unit %s: %s " , name , strerror ( - r ) ) ;
continue ;
}
2010-02-14 01:09:01 +01:00
2010-09-03 03:56:05 +02:00
if ( de - > d_name [ 0 ] = = ' S ' ) {
2012-11-16 18:46:36 +01:00
if ( rcnd_table [ i ] . type = = RUNLEVEL_UP ) {
2011-03-30 00:43:16 +02:00
SERVICE ( service ) - > sysv_start_priority_from_rcnd =
MAX ( a * 10 + b , SERVICE ( service ) - > sysv_start_priority_from_rcnd ) ;
2010-04-24 04:26:33 +02:00
2010-09-03 03:56:05 +02:00
SERVICE ( service ) - > sysv_enabled = true ;
2010-09-03 04:08:16 +02:00
}
2010-04-24 04:26:33 +02:00
2013-03-02 14:28:58 +01:00
r = set_ensure_allocated ( & runlevel_services [ i ] ,
trivial_hash_func , trivial_compare_func ) ;
if ( r < 0 )
2010-09-03 03:56:05 +02:00
goto finish ;
2010-02-14 01:09:01 +01:00
2013-03-02 14:28:58 +01:00
r = set_put ( runlevel_services [ i ] , service ) ;
if ( r < 0 )
2010-02-14 01:09:01 +01:00
goto finish ;
2010-04-06 02:43:58 +02:00
2010-06-07 02:42:01 +02:00
} else if ( de - > d_name [ 0 ] = = ' K ' & &
2012-11-16 18:46:36 +01:00
( rcnd_table [ i ] . type = = RUNLEVEL_DOWN ) ) {
2010-04-23 05:22:20 +02:00
2013-03-02 14:28:58 +01:00
r = set_ensure_allocated ( & shutdown_services ,
trivial_hash_func , trivial_compare_func ) ;
if ( r < 0 )
2010-09-03 03:56:05 +02:00
goto finish ;
2013-03-02 14:28:58 +01:00
r = set_put ( shutdown_services , service ) ;
if ( r < 0 )
2010-02-14 01:09:01 +01:00
goto finish ;
}
}
}
2010-09-03 03:56:05 +02:00
/* Now we loaded all stubs and are aware of the lowest
start - up priority for all services , not let ' s actually load
the services , this will also tell us which services are
actually native now */
manager_dispatch_load_queue ( m ) ;
/* If this is a native service, rely on native ways to pull in
* a service , don ' t pull it in via sysv rcN . d links . */
for ( i = 0 ; i < ELEMENTSOF ( rcnd_table ) ; i + + )
SET_FOREACH ( service , runlevel_services [ i ] , j ) {
service = unit_follow_merge ( service ) ;
2012-01-15 12:04:08 +01:00
if ( service - > fragment_path )
2010-09-03 03:56:05 +02:00
continue ;
2013-03-02 14:28:58 +01:00
r = unit_add_two_dependencies_by_name_inverse (
service , UNIT_AFTER , UNIT_WANTS ,
rcnd_table [ i ] . target , NULL , true ) ;
if ( r < 0 )
2010-09-03 03:56:05 +02:00
goto finish ;
}
/* We honour K links only for halt/reboot. For the normal
* runlevels we assume the stop jobs will be implicitly added
2011-02-21 15:32:17 +01:00
* by the core logic . Also , we don ' t really distinguish here
2010-09-03 03:56:05 +02:00
* between the runlevels 0 and 6 and just add them to the
2012-11-16 18:46:36 +01:00
* special shutdown target . */
2010-09-03 03:56:05 +02:00
SET_FOREACH ( service , shutdown_services , j ) {
service = unit_follow_merge ( service ) ;
2012-01-15 12:04:08 +01:00
if ( service - > fragment_path )
2010-09-03 03:56:05 +02:00
continue ;
2013-03-02 14:28:58 +01:00
r = unit_add_two_dependencies_by_name (
service , UNIT_BEFORE , UNIT_CONFLICTS ,
SPECIAL_SHUTDOWN_TARGET , NULL , true ) ;
if ( r < 0 )
2010-09-03 03:56:05 +02:00
goto finish ;
}
2010-02-14 01:09:01 +01:00
r = 0 ;
finish :
2010-05-13 22:24:22 +02:00
2010-09-03 03:56:05 +02:00
for ( i = 0 ; i < ELEMENTSOF ( rcnd_table ) ; i + + )
set_free ( runlevel_services [ i ] ) ;
2010-02-14 01:09:01 +01:00
return r ;
}
2010-09-21 05:23:12 +02:00
# endif
2010-02-14 01:09:01 +01:00
2010-04-15 23:16:16 +02:00
static void service_bus_name_owner_change (
Unit * u ,
const char * name ,
const char * old_owner ,
const char * new_owner ) {
Service * s = SERVICE ( u ) ;
2013-11-19 21:12:59 +01:00
int r ;
2010-04-15 23:16:16 +02:00
assert ( s ) ;
assert ( name ) ;
assert ( streq ( s - > bus_name , name ) ) ;
assert ( old_owner | | new_owner ) ;
if ( old_owner & & new_owner )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s's D-Bus name %s changed owner from %s to %s " ,
u - > id , name , old_owner , new_owner ) ;
2010-04-15 23:16:16 +02:00
else if ( old_owner )
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s's D-Bus name %s no longer registered by %s " ,
u - > id , name , old_owner ) ;
2010-04-15 23:16:16 +02:00
else
2013-01-05 18:00:35 +01:00
log_debug_unit ( u - > id ,
" %s's D-Bus name %s now registered by %s " ,
u - > id , name , new_owner ) ;
2010-04-15 23:16:16 +02:00
s - > bus_name_good = ! ! new_owner ;
if ( s - > type = = SERVICE_DBUS ) {
/* service_enter_running() will figure out what to
* do */
if ( s - > state = = SERVICE_RUNNING )
2012-02-03 02:01:35 +01:00
service_enter_running ( s , SERVICE_SUCCESS ) ;
2010-04-15 23:16:16 +02:00
else if ( s - > state = = SERVICE_START & & new_owner )
service_enter_start_post ( s ) ;
} else if ( new_owner & &
s - > main_pid < = 0 & &
( s - > state = = SERVICE_START | |
s - > state = = SERVICE_START_POST | |
s - > state = = SERVICE_RUNNING | |
s - > state = = SERVICE_RELOAD ) ) {
2013-11-28 17:50:02 +01:00
_cleanup_bus_creds_unref_ sd_bus_creds * creds = NULL ;
2013-11-19 21:12:59 +01:00
pid_t pid ;
2010-04-15 23:16:16 +02:00
2013-11-19 21:12:59 +01:00
/* Try to acquire PID from bus service */
2010-04-15 23:16:16 +02:00
2013-11-30 04:14:10 +01:00
r = sd_bus_get_owner ( u - > manager - > api_bus , name , SD_BUS_CREDS_PID , & creds ) ;
2013-11-28 17:50:02 +01:00
if ( r > = 0 )
r = sd_bus_creds_get_pid ( creds , & pid ) ;
2013-11-19 21:12:59 +01:00
if ( r > = 0 ) {
log_debug_unit ( u - > id , " %s's D-Bus name %s is now owned by process %u " , u - > id , name , ( unsigned ) pid ) ;
2010-04-15 23:16:16 +02:00
2013-11-19 21:12:59 +01:00
service_set_main_pid ( s , pid ) ;
unit_watch_pid ( UNIT ( s ) , pid ) ;
}
2013-10-01 05:06:56 +02:00
}
2010-04-15 23:16:16 +02:00
}
2010-06-19 04:25:28 +02:00
int service_set_socket_fd ( Service * s , int fd , Socket * sock ) {
2013-12-24 21:18:21 +01:00
_cleanup_free_ char * peer = NULL ;
int r ;
2012-01-06 23:08:54 +01:00
2010-04-15 06:19:54 +02:00
assert ( s ) ;
assert ( fd > = 0 ) ;
/* This is called by the socket code when instantiating a new
* service for a stream socket and the socket needs to be
* configured . */
2012-01-15 12:25:20 +01:00
if ( UNIT ( s ) - > load_state ! = UNIT_LOADED )
2010-04-15 06:19:54 +02:00
return - EINVAL ;
if ( s - > socket_fd > = 0 )
return - EBUSY ;
if ( s - > state ! = SERVICE_DEAD )
return - EAGAIN ;
2013-12-24 21:18:21 +01:00
if ( getpeername_pretty ( fd , & peer ) > = 0 ) {
if ( UNIT ( s ) - > description ) {
_cleanup_free_ char * a ;
a = strjoin ( UNIT ( s ) - > description , " ( " , peer , " ) " , NULL ) ;
if ( ! a )
return - ENOMEM ;
r = unit_set_description ( UNIT ( s ) , a ) ;
} else
r = unit_set_description ( UNIT ( s ) , peer ) ;
if ( r < 0 )
return r ;
}
2010-04-15 06:19:54 +02:00
s - > socket_fd = fd ;
2010-06-19 04:25:28 +02:00
2012-01-06 23:08:54 +01:00
unit_ref_set ( & s - > accept_socket , UNIT ( sock ) ) ;
return unit_add_two_dependencies ( UNIT ( sock ) , UNIT_BEFORE , UNIT_TRIGGERS , UNIT ( s ) , false ) ;
2010-04-15 06:19:54 +02:00
}
2010-08-31 00:23:34 +02:00
static void service_reset_failed ( Unit * u ) {
2010-07-18 04:58:01 +02:00
Service * s = SERVICE ( u ) ;
assert ( s ) ;
2010-08-31 00:23:34 +02:00
if ( s - > state = = SERVICE_FAILED )
2010-07-18 04:58:01 +02:00
service_set_state ( s , SERVICE_DEAD ) ;
2012-02-03 02:01:35 +01:00
s - > result = SERVICE_SUCCESS ;
s - > reload_result = SERVICE_SUCCESS ;
2012-07-04 00:23:42 +02:00
RATELIMIT_RESET ( s - > start_limit ) ;
2010-07-18 04:58:01 +02:00
}
2013-11-19 21:12:59 +01:00
static int service_kill ( Unit * u , KillWho who , int signo , sd_bus_error * error ) {
2010-10-22 16:11:50 +02:00
Service * s = SERVICE ( u ) ;
2013-08-09 16:40:57 +02:00
2013-03-02 22:31:09 +01:00
return unit_kill_common ( u , who , signo , s - > main_pid , s - > control_pid , error ) ;
2010-10-22 16:11:50 +02:00
}
2010-01-30 01:55:42 +01:00
static const char * const service_state_table [ _SERVICE_STATE_MAX ] = {
[ SERVICE_DEAD ] = " dead " ,
[ SERVICE_START_PRE ] = " start-pre " ,
[ SERVICE_START ] = " start " ,
[ SERVICE_START_POST ] = " start-post " ,
[ SERVICE_RUNNING ] = " running " ,
2010-04-13 02:06:27 +02:00
[ SERVICE_EXITED ] = " exited " ,
2010-01-30 01:55:42 +01:00
[ SERVICE_RELOAD ] = " reload " ,
[ SERVICE_STOP ] = " stop " ,
[ SERVICE_STOP_SIGTERM ] = " stop-sigterm " ,
[ SERVICE_STOP_SIGKILL ] = " stop-sigkill " ,
[ SERVICE_STOP_POST ] = " stop-post " ,
[ SERVICE_FINAL_SIGTERM ] = " final-sigterm " ,
[ SERVICE_FINAL_SIGKILL ] = " final-sigkill " ,
2010-08-31 00:23:34 +02:00
[ SERVICE_FAILED ] = " failed " ,
2010-01-30 01:55:42 +01:00
[ SERVICE_AUTO_RESTART ] = " auto-restart " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( service_state , ServiceState ) ;
static const char * const service_restart_table [ _SERVICE_RESTART_MAX ] = {
2010-10-05 20:30:44 +02:00
[ SERVICE_RESTART_NO ] = " no " ,
[ SERVICE_RESTART_ON_SUCCESS ] = " on-success " ,
2010-10-08 18:34:54 +02:00
[ SERVICE_RESTART_ON_FAILURE ] = " on-failure " ,
2013-07-25 14:07:59 +02:00
[ SERVICE_RESTART_ON_WATCHDOG ] = " on-watchdog " ,
2010-10-08 18:34:54 +02:00
[ SERVICE_RESTART_ON_ABORT ] = " on-abort " ,
[ SERVICE_RESTART_ALWAYS ] = " always "
2010-01-30 01:55:42 +01:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( service_restart , ServiceRestart ) ;
static const char * const service_type_table [ _SERVICE_TYPE_MAX ] = {
[ SERVICE_SIMPLE ] = " simple " ,
2010-07-01 19:39:35 +02:00
[ SERVICE_FORKING ] = " forking " ,
2010-08-13 18:23:01 +02:00
[ SERVICE_ONESHOT ] = " oneshot " ,
2010-06-16 05:10:31 +02:00
[ SERVICE_DBUS ] = " dbus " ,
2012-04-24 14:28:00 +02:00
[ SERVICE_NOTIFY ] = " notify " ,
[ SERVICE_IDLE ] = " idle "
2010-01-30 01:55:42 +01:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( service_type , ServiceType ) ;
2010-04-10 17:53:17 +02:00
static const char * const service_exec_command_table [ _SERVICE_EXEC_COMMAND_MAX ] = {
2010-01-30 01:55:42 +01:00
[ SERVICE_EXEC_START_PRE ] = " ExecStartPre " ,
[ SERVICE_EXEC_START ] = " ExecStart " ,
[ SERVICE_EXEC_START_POST ] = " ExecStartPost " ,
[ SERVICE_EXEC_RELOAD ] = " ExecReload " ,
[ SERVICE_EXEC_STOP ] = " ExecStop " ,
[ SERVICE_EXEC_STOP_POST ] = " ExecStopPost " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( service_exec_command , ServiceExecCommand ) ;
2010-06-18 23:12:48 +02:00
static const char * const notify_access_table [ _NOTIFY_ACCESS_MAX ] = {
[ NOTIFY_NONE ] = " none " ,
[ NOTIFY_MAIN ] = " main " ,
[ NOTIFY_ALL ] = " all "
} ;
DEFINE_STRING_TABLE_LOOKUP ( notify_access , NotifyAccess ) ;
2012-02-03 02:01:35 +01:00
static const char * const service_result_table [ _SERVICE_RESULT_MAX ] = {
[ SERVICE_SUCCESS ] = " success " ,
[ SERVICE_FAILURE_RESOURCES ] = " resources " ,
[ SERVICE_FAILURE_TIMEOUT ] = " timeout " ,
[ SERVICE_FAILURE_EXIT_CODE ] = " exit-code " ,
[ SERVICE_FAILURE_SIGNAL ] = " signal " ,
2012-02-08 10:10:34 +01:00
[ SERVICE_FAILURE_CORE_DUMP ] = " core-dump " ,
2012-08-22 05:02:33 +02:00
[ SERVICE_FAILURE_WATCHDOG ] = " watchdog " ,
[ SERVICE_FAILURE_START_LIMIT ] = " start-limit "
2012-02-03 02:01:35 +01:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( service_result , ServiceResult ) ;
2012-02-09 13:05:23 +01:00
static const char * const start_limit_action_table [ _SERVICE_START_LIMIT_MAX ] = {
[ SERVICE_START_LIMIT_NONE ] = " none " ,
[ SERVICE_START_LIMIT_REBOOT ] = " reboot " ,
[ SERVICE_START_LIMIT_REBOOT_FORCE ] = " reboot-force " ,
[ SERVICE_START_LIMIT_REBOOT_IMMEDIATE ] = " reboot-immediate "
} ;
DEFINE_STRING_TABLE_LOOKUP ( start_limit_action , StartLimitAction ) ;
2010-01-26 21:39:06 +01:00
const UnitVTable service_vtable = {
2012-01-15 10:53:49 +01:00
. object_size = sizeof ( Service ) ,
2013-11-19 21:12:59 +01:00
. exec_context_offset = offsetof ( Service , exec_context ) ,
. cgroup_context_offset = offsetof ( Service , cgroup_context ) ,
. kill_context_offset = offsetof ( Service , kill_context ) ,
2013-11-27 20:23:18 +01:00
. exec_runtime_offset = offsetof ( Service , exec_runtime ) ,
2012-09-18 11:40:01 +02:00
2011-08-01 00:43:05 +02:00
. sections =
" Unit \0 "
" Service \0 "
" Install \0 " ,
2013-06-27 04:14:27 +02:00
. private_section = " Service " ,
2013-01-19 01:01:41 +01:00
2010-01-26 04:18:44 +01:00
. init = service_init ,
. done = service_done ,
2010-04-21 03:27:44 +02:00
. load = service_load ,
. coldplug = service_coldplug ,
2010-01-26 04:18:44 +01:00
2010-01-23 01:52:57 +01:00
. dump = service_dump ,
. start = service_start ,
. stop = service_stop ,
. reload = service_reload ,
2010-01-26 04:18:44 +01:00
. can_reload = service_can_reload ,
2010-10-22 16:11:50 +02:00
. kill = service_kill ,
2010-04-21 03:27:44 +02:00
. serialize = service_serialize ,
. deserialize_item = service_deserialize_item ,
2010-01-23 01:52:57 +01:00
. active_state = service_active_state ,
2010-04-13 20:59:01 +02:00
. sub_state_to_string = service_sub_state_to_string ,
2010-01-23 01:52:57 +01:00
2010-04-21 06:01:13 +02:00
. check_gc = service_check_gc ,
. check_snapshot = service_check_snapshot ,
2010-01-26 04:18:44 +01:00
. sigchld_event = service_sigchld_event ,
2010-02-14 01:09:01 +01:00
2010-08-31 00:23:34 +02:00
. reset_failed = service_reset_failed ,
2010-07-18 04:58:01 +02:00
2013-06-27 04:14:27 +02:00
. notify_cgroup_empty = service_notify_cgroup_empty_event ,
2010-06-16 05:10:31 +02:00
. notify_message = service_notify_message ,
2010-03-31 16:29:55 +02:00
2010-04-15 23:16:16 +02:00
. bus_name_owner_change = service_bus_name_owner_change ,
2010-08-20 02:26:05 +02:00
. bus_interface = " org.freedesktop.systemd1.Service " ,
2013-11-19 21:12:59 +01:00
. bus_vtable = bus_service_vtable ,
2013-06-27 23:21:21 +02:00
. bus_set_property = bus_service_set_property ,
. bus_commit_properties = bus_service_commit_properties ,
2010-04-18 03:08:16 +02:00
2014-01-27 06:57:34 +01:00
. get_timeout = service_get_timeout ,
2010-09-21 05:23:12 +02:00
# ifdef HAVE_SYSV_COMPAT
2012-05-13 18:18:54 +02:00
. enumerate = service_enumerate ,
2010-09-21 05:23:12 +02:00
# endif
2013-11-19 21:12:59 +01:00
. can_transient = true ,
2012-05-13 18:18:54 +02:00
. status_message_formats = {
. starting_stopping = {
[ 0 ] = " Starting %s... " ,
[ 1 ] = " Stopping %s... " ,
} ,
. finished_start_job = {
[ JOB_DONE ] = " Started %s. " ,
[ JOB_FAILED ] = " Failed to start %s. " ,
[ JOB_DEPENDENCY ] = " Dependency failed for %s. " ,
[ JOB_TIMEOUT ] = " Timed out starting %s. " ,
} ,
. finished_stop_job = {
[ JOB_DONE ] = " Stopped %s. " ,
[ JOB_FAILED ] = " Stopped (with error) %s. " ,
[ JOB_TIMEOUT ] = " Timed out stopping %s. " ,
} ,
} ,
2010-01-23 01:52:57 +01:00
} ;