2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-26 23:39:06 +03:00
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-26 23:39:06 +03:00
# include <assert.h>
# include <errno.h>
# include <string.h>
# include <sys/epoll.h>
# include <sys/timerfd.h>
# include <sys/poll.h>
2010-01-27 02:15:56 +03:00
# include <stdlib.h>
# include <unistd.h>
2010-07-17 02:57:51 +04:00
# include <sys/stat.h>
2010-01-26 23:39:06 +03:00
# include "set.h"
# include "unit.h"
# include "macro.h"
# include "strv.h"
# include "load-fragment.h"
# include "load-dropin.h"
# include "log.h"
2010-04-15 05:11:11 +04:00
# include "unit-name.h"
# include "specifier.h"
2010-04-18 05:08:16 +04:00
# include "dbus-unit.h"
2010-06-18 06:22:59 +04:00
# include "special.h"
2010-07-11 02:50:49 +04:00
# include "cgroup-util.h"
2010-08-11 03:43:23 +04:00
# include "missing.h"
2011-08-20 02:20:41 +04:00
# include "cgroup-attr.h"
2010-01-26 23:39:06 +03:00
const UnitVTable * const unit_vtable [ _UNIT_TYPE_MAX ] = {
[ UNIT_SERVICE ] = & service_vtable ,
[ UNIT_TIMER ] = & timer_vtable ,
[ UNIT_SOCKET ] = & socket_vtable ,
[ UNIT_TARGET ] = & target_vtable ,
[ UNIT_DEVICE ] = & device_vtable ,
[ UNIT_MOUNT ] = & mount_vtable ,
[ UNIT_AUTOMOUNT ] = & automount_vtable ,
2010-05-09 20:44:11 +04:00
[ UNIT_SNAPSHOT ] = & snapshot_vtable ,
2010-05-24 07:25:33 +04:00
[ UNIT_SWAP ] = & swap_vtable ,
[ UNIT_PATH ] = & path_vtable
2010-01-26 23:39:06 +03:00
} ;
Unit * unit_new ( Manager * m ) {
Unit * u ;
assert ( m ) ;
if ( ! ( u = new0 ( Unit , 1 ) ) )
return NULL ;
if ( ! ( u - > meta . names = set_new ( string_hash_func , string_compare_func ) ) ) {
free ( u ) ;
return NULL ;
}
u - > meta . manager = m ;
u - > meta . type = _UNIT_TYPE_INVALID ;
2010-06-03 16:26:50 +04:00
u - > meta . deserialized_job = _JOB_TYPE_INVALID ;
2010-07-03 21:48:33 +04:00
u - > meta . default_dependencies = true ;
2011-07-31 20:28:02 +04:00
u - > meta . unit_file_state = _UNIT_FILE_STATE_INVALID ;
2010-01-26 23:39:06 +03:00
return u ;
}
2010-04-06 18:32:07 +04:00
bool unit_has_name ( Unit * u , const char * name ) {
assert ( u ) ;
assert ( name ) ;
return ! ! set_get ( u - > meta . names , ( char * ) name ) ;
}
2010-01-26 23:39:06 +03:00
int unit_add_name ( Unit * u , const char * text ) {
UnitType t ;
2010-07-16 21:40:24 +04:00
char * s , * i = NULL ;
2010-01-26 23:39:06 +03:00
int r ;
assert ( u ) ;
assert ( text ) ;
2010-04-15 05:11:11 +04:00
if ( unit_name_is_template ( text ) ) {
if ( ! u - > meta . instance )
return - EINVAL ;
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
s = unit_name_replace_instance ( text , u - > meta . instance ) ;
} else
s = strdup ( text ) ;
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
if ( ! s )
return - ENOMEM ;
2010-01-26 23:39:06 +03:00
2010-10-08 05:09:25 +04:00
if ( ! unit_name_is_valid ( s , false ) ) {
2010-04-15 05:11:11 +04:00
r = - EINVAL ;
goto fail ;
}
2010-04-10 19:53:17 +04:00
2010-04-15 05:11:11 +04:00
assert_se ( ( t = unit_name_to_type ( s ) ) > = 0 ) ;
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
if ( u - > meta . type ! = _UNIT_TYPE_INVALID & & t ! = u - > meta . type ) {
r = - EINVAL ;
goto fail ;
}
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
if ( ( r = unit_name_to_instance ( s , & i ) ) < 0 )
goto fail ;
2010-01-26 23:39:06 +03:00
2011-04-28 03:26:39 +04:00
if ( i & & unit_vtable [ t ] - > no_instances ) {
r = - EINVAL ;
2010-04-15 05:11:11 +04:00
goto fail ;
2011-04-28 03:26:39 +04:00
}
2010-04-15 05:11:11 +04:00
2010-07-16 21:40:24 +04:00
/* Ensure that this unit is either instanced or not instanced,
* but not both . */
if ( u - > meta . type ! = _UNIT_TYPE_INVALID & & ! u - > meta . instance ! = ! i ) {
2010-04-15 05:11:11 +04:00
r = - EINVAL ;
goto fail ;
}
if ( unit_vtable [ t ] - > no_alias & &
! set_isempty ( u - > meta . names ) & &
! set_get ( u - > meta . names , s ) ) {
r = - EEXIST ;
goto fail ;
}
2010-04-22 04:56:42 +04:00
if ( hashmap_size ( u - > meta . manager - > units ) > = MANAGER_MAX_NAMES ) {
r = - E2BIG ;
goto fail ;
}
2010-04-15 05:11:11 +04:00
if ( ( r = set_put ( u - > meta . names , s ) ) < 0 ) {
if ( r = = - EEXIST )
r = 0 ;
goto fail ;
2010-01-26 23:39:06 +03:00
}
if ( ( r = hashmap_put ( u - > meta . manager - > units , s , u ) ) < 0 ) {
set_remove ( u - > meta . names , s ) ;
2010-04-15 05:11:11 +04:00
goto fail ;
2010-01-26 23:39:06 +03:00
}
2010-04-10 19:53:17 +04:00
if ( u - > meta . type = = _UNIT_TYPE_INVALID ) {
2010-01-29 08:04:08 +03:00
2010-04-10 19:53:17 +04:00
u - > meta . type = t ;
2010-04-15 05:11:11 +04:00
u - > meta . id = s ;
u - > meta . instance = i ;
2011-05-24 01:53:43 +04:00
LIST_PREPEND ( Meta , units_by_type , u - > meta . manager - > units_by_type [ t ] , & u - > meta ) ;
2010-04-10 19:53:17 +04:00
if ( UNIT_VTABLE ( u ) - > init )
UNIT_VTABLE ( u ) - > init ( u ) ;
2010-04-15 05:11:11 +04:00
} else
free ( i ) ;
2010-01-26 23:39:06 +03:00
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-01-26 23:39:06 +03:00
return 0 ;
2010-04-15 05:11:11 +04:00
fail :
free ( s ) ;
free ( i ) ;
return r ;
2010-01-26 23:39:06 +03:00
}
2010-01-29 03:49:34 +03:00
int unit_choose_id ( Unit * u , const char * name ) {
2010-07-16 21:40:24 +04:00
char * s , * t = NULL , * i ;
int r ;
2010-01-29 03:49:34 +03:00
assert ( u ) ;
assert ( name ) ;
2010-04-15 05:11:11 +04:00
if ( unit_name_is_template ( name ) ) {
if ( ! u - > meta . instance )
return - EINVAL ;
if ( ! ( t = unit_name_replace_instance ( name , u - > meta . instance ) ) )
return - ENOMEM ;
name = t ;
}
2010-01-29 03:49:34 +03:00
/* Selects one of the names of this unit as the id */
2010-04-15 05:11:11 +04:00
s = set_get ( u - > meta . names , ( char * ) name ) ;
free ( t ) ;
2010-01-29 03:49:34 +03:00
2010-04-15 05:11:11 +04:00
if ( ! s )
2010-01-29 03:49:34 +03:00
return - ENOENT ;
2010-07-16 21:40:24 +04:00
if ( ( r = unit_name_to_instance ( s , & i ) ) < 0 )
return r ;
2010-01-29 03:49:34 +03:00
u - > meta . id = s ;
2010-07-16 21:40:24 +04:00
free ( u - > meta . instance ) ;
u - > meta . instance = i ;
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-04-15 05:11:11 +04:00
2010-01-29 03:49:34 +03:00
return 0 ;
}
2010-01-29 05:18:09 +03:00
int unit_set_description ( Unit * u , const char * description ) {
char * s ;
assert ( u ) ;
if ( ! ( s = strdup ( description ) ) )
return - ENOMEM ;
free ( u - > meta . description ) ;
u - > meta . description = s ;
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-01-29 05:18:09 +03:00
return 0 ;
}
2010-04-21 08:01:13 +04:00
bool unit_check_gc ( Unit * u ) {
assert ( u ) ;
2010-05-18 06:05:27 +04:00
if ( u - > meta . load_state = = UNIT_STUB )
return true ;
2010-04-21 08:01:13 +04:00
if ( UNIT_VTABLE ( u ) - > no_gc )
return true ;
2010-08-11 04:07:59 +04:00
if ( u - > meta . no_gc )
return true ;
2010-04-21 08:01:13 +04:00
if ( u - > meta . job )
return true ;
if ( unit_active_state ( u ) ! = UNIT_INACTIVE )
return true ;
if ( UNIT_VTABLE ( u ) - > check_gc )
if ( UNIT_VTABLE ( u ) - > check_gc ( u ) )
return true ;
return false ;
}
2010-01-26 23:39:06 +03:00
void unit_add_to_load_queue ( Unit * u ) {
assert ( u ) ;
2010-04-10 06:42:36 +04:00
assert ( u - > meta . type ! = _UNIT_TYPE_INVALID ) ;
2010-01-26 23:39:06 +03:00
if ( u - > meta . load_state ! = UNIT_STUB | | u - > meta . in_load_queue )
return ;
LIST_PREPEND ( Meta , load_queue , u - > meta . manager - > load_queue , & u - > meta ) ;
u - > meta . in_load_queue = true ;
}
2010-04-06 04:43:58 +04:00
void unit_add_to_cleanup_queue ( Unit * u ) {
assert ( u ) ;
if ( u - > meta . in_cleanup_queue )
return ;
LIST_PREPEND ( Meta , cleanup_queue , u - > meta . manager - > cleanup_queue , & u - > meta ) ;
u - > meta . in_cleanup_queue = true ;
}
2010-04-21 08:01:13 +04:00
void unit_add_to_gc_queue ( Unit * u ) {
assert ( u ) ;
if ( u - > meta . in_gc_queue | | u - > meta . in_cleanup_queue )
return ;
if ( unit_check_gc ( u ) )
return ;
LIST_PREPEND ( Meta , gc_queue , u - > meta . manager - > gc_queue , & u - > meta ) ;
u - > meta . in_gc_queue = true ;
u - > meta . manager - > n_in_gc_queue + + ;
if ( u - > meta . manager - > gc_queue_timestamp < = 0 )
u - > meta . manager - > gc_queue_timestamp = now ( CLOCK_MONOTONIC ) ;
}
2010-02-05 02:38:41 +03:00
void unit_add_to_dbus_queue ( Unit * u ) {
assert ( u ) ;
2010-04-10 06:42:36 +04:00
assert ( u - > meta . type ! = _UNIT_TYPE_INVALID ) ;
2010-02-05 02:38:41 +03:00
2010-05-16 05:57:07 +04:00
if ( u - > meta . load_state = = UNIT_STUB | | u - > meta . in_dbus_queue )
2010-02-05 02:38:41 +03:00
return ;
2010-07-05 02:58:07 +04:00
/* Shortcut things if nobody cares */
if ( ! bus_has_subscriber ( u - > meta . manager ) ) {
2010-05-16 05:57:07 +04:00
u - > meta . sent_dbus_new_signal = true ;
return ;
}
2010-02-05 02:38:41 +03:00
LIST_PREPEND ( Meta , dbus_queue , u - > meta . manager - > dbus_unit_queue , & u - > meta ) ;
u - > meta . in_dbus_queue = true ;
}
2010-01-26 23:39:06 +03:00
static void bidi_set_free ( Unit * u , Set * s ) {
Iterator i ;
Unit * other ;
assert ( u ) ;
/* Frees the set and makes sure we are dropped from the
* inverse pointers */
SET_FOREACH ( other , s , i ) {
UnitDependency d ;
for ( d = 0 ; d < _UNIT_DEPENDENCY_MAX ; d + + )
set_remove ( other - > meta . dependencies [ d ] , u ) ;
2010-04-21 08:01:13 +04:00
unit_add_to_gc_queue ( other ) ;
2010-01-26 23:39:06 +03:00
}
set_free ( s ) ;
}
void unit_free ( Unit * u ) {
UnitDependency d ;
Iterator i ;
char * t ;
assert ( u ) ;
2010-02-05 02:38:41 +03:00
bus_unit_send_removed_signal ( u ) ;
2010-06-05 00:31:33 +04:00
if ( u - > meta . load_state ! = UNIT_STUB )
if ( UNIT_VTABLE ( u ) - > done )
UNIT_VTABLE ( u ) - > done ( u ) ;
2010-01-26 23:39:06 +03:00
SET_FOREACH ( t , u - > meta . names , i )
hashmap_remove_value ( u - > meta . manager - > units , t , u ) ;
2010-06-05 04:16:20 +04:00
if ( u - > meta . job )
job_free ( u - > meta . job ) ;
for ( d = 0 ; d < _UNIT_DEPENDENCY_MAX ; d + + )
bidi_set_free ( u , u - > meta . dependencies [ d ] ) ;
2010-01-29 08:04:08 +03:00
if ( u - > meta . type ! = _UNIT_TYPE_INVALID )
2011-05-24 01:53:43 +04:00
LIST_REMOVE ( Meta , units_by_type , u - > meta . manager - > units_by_type [ u - > meta . type ] , & u - > meta ) ;
2010-01-29 08:04:08 +03:00
2010-01-26 23:39:06 +03:00
if ( u - > meta . in_load_queue )
LIST_REMOVE ( Meta , load_queue , u - > meta . manager - > load_queue , & u - > meta ) ;
2010-02-05 02:38:41 +03:00
if ( u - > meta . in_dbus_queue )
LIST_REMOVE ( Meta , dbus_queue , u - > meta . manager - > dbus_unit_queue , & u - > meta ) ;
2010-04-06 04:43:58 +04:00
if ( u - > meta . in_cleanup_queue )
LIST_REMOVE ( Meta , cleanup_queue , u - > meta . manager - > cleanup_queue , & u - > meta ) ;
2010-04-21 08:01:13 +04:00
if ( u - > meta . in_gc_queue ) {
LIST_REMOVE ( Meta , gc_queue , u - > meta . manager - > gc_queue , & u - > meta ) ;
u - > meta . manager - > n_in_gc_queue - - ;
}
2011-07-06 02:47:39 +04:00
cgroup_bonding_free_list ( u - > meta . cgroup_bondings , u - > meta . manager - > n_reloading < = 0 ) ;
2011-08-20 02:20:41 +04:00
cgroup_attribute_free_list ( u - > meta . cgroup_attributes ) ;
2010-01-26 23:39:06 +03:00
free ( u - > meta . description ) ;
2010-02-14 03:01:10 +03:00
free ( u - > meta . fragment_path ) ;
2010-01-26 23:39:06 +03:00
2010-06-15 04:45:26 +04:00
set_free_free ( u - > meta . names ) ;
2010-01-26 23:39:06 +03:00
2010-10-13 04:15:41 +04:00
condition_free_list ( u - > meta . conditions ) ;
2010-04-15 05:11:11 +04:00
free ( u - > meta . instance ) ;
2010-01-26 23:39:06 +03:00
free ( u ) ;
}
UnitActiveState unit_active_state ( Unit * u ) {
assert ( u ) ;
2010-07-01 02:31:53 +04:00
if ( u - > meta . load_state = = UNIT_MERGED )
return unit_active_state ( unit_follow_merge ( u ) ) ;
/* After a reload it might happen that a unit is not correctly
* loaded but still has a process around . That ' s why we won ' t
2010-08-31 02:23:34 +04:00
* shortcut failed loading to UNIT_INACTIVE_FAILED . */
2010-01-26 23:39:06 +03:00
return UNIT_VTABLE ( u ) - > active_state ( u ) ;
}
2010-04-13 22:59:01 +04:00
const char * unit_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
return UNIT_VTABLE ( u ) - > sub_state_to_string ( u ) ;
}
2010-04-06 04:43:58 +04:00
static void complete_move ( Set * * s , Set * * other ) {
assert ( s ) ;
assert ( other ) ;
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
if ( ! * other )
return ;
2010-01-26 23:39:06 +03:00
if ( * s )
2010-04-06 04:43:58 +04:00
set_move ( * s , * other ) ;
else {
* s = * other ;
* other = NULL ;
}
}
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
static void merge_names ( Unit * u , Unit * other ) {
char * t ;
Iterator i ;
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
assert ( u ) ;
assert ( other ) ;
complete_move ( & u - > meta . names , & other - > meta . names ) ;
2010-06-15 04:45:26 +04:00
set_free_free ( other - > meta . names ) ;
2010-04-06 04:43:58 +04:00
other - > meta . names = NULL ;
other - > meta . id = NULL ;
SET_FOREACH ( t , u - > meta . names , i )
assert_se ( hashmap_replace ( u - > meta . manager - > units , t , u ) = = 0 ) ;
2010-01-26 23:39:06 +03:00
}
2010-04-06 04:43:58 +04:00
static void merge_dependencies ( Unit * u , Unit * other , UnitDependency d ) {
Iterator i ;
Unit * back ;
2010-01-26 23:39:06 +03:00
int r ;
2010-04-06 04:43:58 +04:00
assert ( u ) ;
assert ( other ) ;
assert ( d < _UNIT_DEPENDENCY_MAX ) ;
2010-09-14 03:31:41 +04:00
/* Fix backwards pointers */
2010-04-06 04:43:58 +04:00
SET_FOREACH ( back , other - > meta . dependencies [ d ] , i ) {
UnitDependency k ;
for ( k = 0 ; k < _UNIT_DEPENDENCY_MAX ; k + + )
if ( ( r = set_remove_and_put ( back - > meta . dependencies [ k ] , other , u ) ) < 0 ) {
if ( r = = - EEXIST )
set_remove ( back - > meta . dependencies [ k ] , other ) ;
else
assert ( r = = - ENOENT ) ;
}
}
complete_move ( & u - > meta . dependencies [ d ] , & other - > meta . dependencies [ d ] ) ;
set_free ( other - > meta . dependencies [ d ] ) ;
other - > meta . dependencies [ d ] = NULL ;
}
int unit_merge ( Unit * u , Unit * other ) {
2010-01-26 23:39:06 +03:00
UnitDependency d ;
assert ( u ) ;
assert ( other ) ;
assert ( u - > meta . manager = = other - > meta . manager ) ;
2010-04-15 05:11:11 +04:00
assert ( u - > meta . type ! = _UNIT_TYPE_INVALID ) ;
2010-01-26 23:39:06 +03:00
2010-04-08 06:34:42 +04:00
other = unit_follow_merge ( other ) ;
2010-04-06 04:43:58 +04:00
if ( other = = u )
return 0 ;
2010-04-15 05:11:11 +04:00
if ( u - > meta . type ! = other - > meta . type )
return - EINVAL ;
2010-07-16 21:40:24 +04:00
if ( ! u - > meta . instance ! = ! other - > meta . instance )
2010-01-26 23:39:06 +03:00
return - EINVAL ;
2010-04-08 06:34:42 +04:00
if ( other - > meta . load_state ! = UNIT_STUB & &
2010-08-31 02:23:34 +04:00
other - > meta . load_state ! = UNIT_ERROR )
2010-04-06 04:43:58 +04:00
return - EEXIST ;
2010-01-26 23:39:06 +03:00
2010-04-10 06:42:36 +04:00
if ( other - > meta . job )
return - EEXIST ;
2010-08-31 02:23:34 +04:00
if ( ! UNIT_IS_INACTIVE_OR_FAILED ( unit_active_state ( other ) ) )
2010-04-10 06:42:36 +04:00
return - EEXIST ;
2010-01-26 23:39:06 +03:00
/* Merge names */
2010-04-06 04:43:58 +04:00
merge_names ( u , other ) ;
2010-01-26 23:39:06 +03:00
/* Merge dependencies */
for ( d = 0 ; d < _UNIT_DEPENDENCY_MAX ; d + + )
2010-04-06 04:43:58 +04:00
merge_dependencies ( u , other , d ) ;
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
other - > meta . load_state = UNIT_MERGED ;
other - > meta . merged_into = u ;
2010-04-10 06:43:21 +04:00
/* If there is still some data attached to the other node, we
* don ' t need it anymore , and can free it . */
if ( other - > meta . load_state ! = UNIT_STUB )
if ( UNIT_VTABLE ( other ) - > done )
UNIT_VTABLE ( other ) - > done ( other ) ;
unit_add_to_dbus_queue ( u ) ;
2010-04-06 04:43:58 +04:00
unit_add_to_cleanup_queue ( other ) ;
return 0 ;
}
int unit_merge_by_name ( Unit * u , const char * name ) {
Unit * other ;
2010-04-15 05:11:11 +04:00
int r ;
char * s = NULL ;
2010-04-06 04:43:58 +04:00
assert ( u ) ;
assert ( name ) ;
2010-04-15 05:11:11 +04:00
if ( unit_name_is_template ( name ) ) {
if ( ! u - > meta . instance )
return - EINVAL ;
if ( ! ( s = unit_name_replace_instance ( name , u - > meta . instance ) ) )
return - ENOMEM ;
name = s ;
}
2010-04-06 04:43:58 +04:00
if ( ! ( other = manager_get_unit ( u - > meta . manager , name ) ) )
2010-04-15 05:11:11 +04:00
r = unit_add_name ( u , name ) ;
else
r = unit_merge ( u , other ) ;
2010-04-06 04:43:58 +04:00
2010-04-15 05:11:11 +04:00
free ( s ) ;
return r ;
2010-04-06 04:43:58 +04:00
}
Unit * unit_follow_merge ( Unit * u ) {
assert ( u ) ;
while ( u - > meta . load_state = = UNIT_MERGED )
assert_se ( u = u - > meta . merged_into ) ;
return u ;
}
int unit_add_exec_dependencies ( Unit * u , ExecContext * c ) {
int r ;
assert ( u ) ;
assert ( c ) ;
2010-05-20 03:21:38 +04:00
if ( c - > std_output ! = EXEC_OUTPUT_KMSG & &
c - > std_output ! = EXEC_OUTPUT_SYSLOG & &
2011-02-15 03:27:53 +03:00
c - > std_output ! = EXEC_OUTPUT_KMSG_AND_CONSOLE & &
c - > std_output ! = EXEC_OUTPUT_SYSLOG_AND_CONSOLE & &
2010-05-20 03:21:38 +04:00
c - > std_error ! = EXEC_OUTPUT_KMSG & &
2011-02-15 03:27:53 +03:00
c - > std_error ! = EXEC_OUTPUT_SYSLOG_AND_CONSOLE & &
c - > std_error ! = EXEC_OUTPUT_KMSG & &
c - > std_error ! = EXEC_OUTPUT_SYSLOG_AND_CONSOLE )
2010-04-06 04:43:58 +04:00
return 0 ;
/* If syslog or kernel logging is requested, make sure our own
* logging daemon is run first . */
2010-06-19 05:15:59 +04:00
if ( u - > meta . manager - > running_as = = MANAGER_SYSTEM )
2011-08-31 00:42:49 +04:00
if ( ( r = unit_add_two_dependencies_by_name ( u , UNIT_REQUIRES , UNIT_AFTER , SPECIAL_STDOUT_SYSLOG_BRIDGE_SOCKET , NULL , true ) ) < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-01-26 23:39:06 +03:00
return 0 ;
}
const char * unit_description ( Unit * u ) {
assert ( u ) ;
if ( u - > meta . description )
return u - > meta . description ;
2010-09-28 01:24:17 +04:00
return strna ( u - > meta . id ) ;
2010-01-26 23:39:06 +03:00
}
void unit_dump ( Unit * u , FILE * f , const char * prefix ) {
char * t ;
UnitDependency d ;
Iterator i ;
2010-02-03 16:21:48 +03:00
char * p2 ;
const char * prefix2 ;
2010-05-14 05:05:38 +04:00
char
timestamp1 [ FORMAT_TIMESTAMP_MAX ] ,
timestamp2 [ FORMAT_TIMESTAMP_MAX ] ,
timestamp3 [ FORMAT_TIMESTAMP_MAX ] ,
2010-07-17 06:09:28 +04:00
timestamp4 [ FORMAT_TIMESTAMP_MAX ] ,
timespan [ FORMAT_TIMESPAN_MAX ] ;
2010-07-21 07:00:29 +04:00
Unit * following ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-04-15 05:11:11 +04:00
assert ( u - > meta . type > = 0 ) ;
2010-01-26 23:39:06 +03:00
if ( ! prefix )
prefix = " " ;
2010-02-03 16:21:48 +03:00
p2 = strappend ( prefix , " \t " ) ;
prefix2 = p2 ? p2 : prefix ;
2010-01-26 23:39:06 +03:00
fprintf ( f ,
2010-04-23 22:25:55 +04:00
" %s-> Unit %s: \n "
2010-01-26 23:39:06 +03:00
" %s \t Description: %s \n "
2010-04-15 05:11:11 +04:00
" %s \t Instance: %s \n "
2010-01-26 23:39:06 +03:00
" %s \t Unit Load State: %s \n "
2010-04-10 06:43:57 +04:00
" %s \t Unit Active State: %s \n "
2010-05-14 05:05:38 +04:00
" %s \t Inactive Exit Timestamp: %s \n "
2010-04-10 06:43:57 +04:00
" %s \t Active Enter Timestamp: %s \n "
2010-04-21 08:01:13 +04:00
" %s \t Active Exit Timestamp: %s \n "
2010-05-14 05:05:38 +04:00
" %s \t Inactive Enter Timestamp: %s \n "
2010-07-17 02:57:51 +04:00
" %s \t GC Check Good: %s \n "
" %s \t Need Daemon Reload: %s \n " ,
2010-04-15 05:11:11 +04:00
prefix , u - > meta . id ,
2010-01-26 23:39:06 +03:00
prefix , unit_description ( u ) ,
2010-04-15 05:11:11 +04:00
prefix , strna ( u - > meta . instance ) ,
2010-01-30 03:55:42 +03:00
prefix , unit_load_state_to_string ( u - > meta . load_state ) ,
2010-04-10 06:43:57 +04:00
prefix , unit_active_state_to_string ( unit_active_state ( u ) ) ,
2010-05-24 03:45:54 +04:00
prefix , strna ( format_timestamp ( timestamp1 , sizeof ( timestamp1 ) , u - > meta . inactive_exit_timestamp . realtime ) ) ,
prefix , strna ( format_timestamp ( timestamp2 , sizeof ( timestamp2 ) , u - > meta . active_enter_timestamp . realtime ) ) ,
prefix , strna ( format_timestamp ( timestamp3 , sizeof ( timestamp3 ) , u - > meta . active_exit_timestamp . realtime ) ) ,
prefix , strna ( format_timestamp ( timestamp4 , sizeof ( timestamp4 ) , u - > meta . inactive_enter_timestamp . realtime ) ) ,
2010-07-17 02:57:51 +04:00
prefix , yes_no ( unit_check_gc ( u ) ) ,
prefix , yes_no ( unit_need_daemon_reload ( u ) ) ) ;
2010-01-27 02:15:56 +03:00
2010-01-26 23:39:06 +03:00
SET_FOREACH ( t , u - > meta . names , i )
fprintf ( f , " %s \t Name: %s \n " , prefix , t ) ;
2010-07-21 07:00:29 +04:00
if ( ( following = unit_following ( u ) ) )
fprintf ( f , " %s \t Following: %s \n " , prefix , following - > meta . id ) ;
2010-07-20 22:33:19 +04:00
2010-04-06 04:43:58 +04:00
if ( u - > meta . fragment_path )
fprintf ( f , " %s \t Fragment Path: %s \n " , prefix , u - > meta . fragment_path ) ;
2010-07-17 06:09:28 +04:00
if ( u - > meta . job_timeout > 0 )
fprintf ( f , " %s \t Job Timeout: %s \n " , prefix , format_timespan ( timespan , sizeof ( timespan ) , u - > meta . job_timeout ) ) ;
2010-10-13 04:15:41 +04:00
condition_dump_list ( u - > meta . conditions , f , prefix ) ;
2011-03-17 06:36:19 +03:00
if ( dual_timestamp_is_set ( & u - > meta . condition_timestamp ) )
fprintf ( f ,
" %s \t Condition Timestamp: %s \n "
" %s \t Condition Result: %s \n " ,
prefix , strna ( format_timestamp ( timestamp1 , sizeof ( timestamp1 ) , u - > meta . condition_timestamp . realtime ) ) ,
prefix , yes_no ( u - > meta . condition_result ) ) ;
2010-01-26 23:39:06 +03:00
for ( d = 0 ; d < _UNIT_DEPENDENCY_MAX ; d + + ) {
Unit * other ;
SET_FOREACH ( other , u - > meta . dependencies [ d ] , i )
2010-04-15 05:11:11 +04:00
fprintf ( f , " %s \t %s: %s \n " , prefix , unit_dependency_to_string ( d ) , other - > meta . id ) ;
2010-01-26 23:39:06 +03:00
}
2010-04-06 04:43:58 +04:00
if ( u - > meta . load_state = = UNIT_LOADED ) {
2011-08-20 02:20:41 +04:00
CGroupBonding * b ;
CGroupAttribute * a ;
2010-04-10 06:44:24 +04:00
fprintf ( f ,
2010-07-03 21:48:33 +04:00
" %s \t StopWhenUnneeded: %s \n "
2010-08-10 22:57:21 +04:00
" %s \t RefuseManualStart: %s \n "
" %s \t RefuseManualStop: %s \n "
2011-04-07 06:11:31 +04:00
" %s \t DefaultDependencies: %s \n "
2011-04-14 05:55:03 +04:00
" %s \t OnFailureIsolate: %s \n "
2011-05-05 12:58:55 +04:00
" %s \t IgnoreOnIsolate: %s \n "
" %s \t IgnoreOnSnapshot: %s \n " ,
2010-07-03 21:48:33 +04:00
prefix , yes_no ( u - > meta . stop_when_unneeded ) ,
2010-08-10 22:57:21 +04:00
prefix , yes_no ( u - > meta . refuse_manual_start ) ,
prefix , yes_no ( u - > meta . refuse_manual_stop ) ,
2011-04-07 06:11:31 +04:00
prefix , yes_no ( u - > meta . default_dependencies ) ,
2011-04-14 05:55:03 +04:00
prefix , yes_no ( u - > meta . on_failure_isolate ) ,
2011-05-05 12:58:55 +04:00
prefix , yes_no ( u - > meta . ignore_on_isolate ) ,
prefix , yes_no ( u - > meta . ignore_on_snapshot ) ) ;
2010-04-10 06:44:24 +04:00
2010-04-06 04:43:58 +04:00
LIST_FOREACH ( by_unit , b , u - > meta . cgroup_bondings )
fprintf ( f , " %s \t ControlGroup: %s:%s \n " ,
prefix , b - > controller , b - > path ) ;
2010-03-31 18:29:55 +04:00
2011-08-20 02:42:50 +04:00
LIST_FOREACH ( by_unit , a , u - > meta . cgroup_attributes ) {
char * v = NULL ;
if ( a - > map_callback )
a - > map_callback ( a - > controller , a - > name , a - > value , & v ) ;
2011-08-20 02:20:41 +04:00
fprintf ( f , " %s \t ControlGroupAttribute: %s %s \" %s \" \n " ,
2011-08-20 02:42:50 +04:00
prefix , a - > controller , a - > name , v ? v : a - > value ) ;
free ( v ) ;
}
2011-08-20 02:20:41 +04:00
2010-04-06 04:43:58 +04:00
if ( UNIT_VTABLE ( u ) - > dump )
UNIT_VTABLE ( u ) - > dump ( u , f , prefix2 ) ;
2010-04-10 06:44:24 +04:00
} else if ( u - > meta . load_state = = UNIT_MERGED )
fprintf ( f ,
" %s \t Merged into: %s \n " ,
2010-04-15 05:11:11 +04:00
prefix , u - > meta . merged_into - > meta . id ) ;
2010-08-31 02:23:34 +04:00
else if ( u - > meta . load_state = = UNIT_ERROR )
2010-08-12 03:05:35 +04:00
fprintf ( f , " %s \t Load Error Code: %s \n " , prefix , strerror ( - u - > meta . load_error ) ) ;
2010-01-26 23:39:06 +03:00
if ( u - > meta . job )
job_dump ( u - > meta . job , f , prefix2 ) ;
2010-02-03 16:21:48 +03:00
free ( p2 ) ;
2010-01-26 23:39:06 +03:00
}
/* Common implementation for multiple backends */
2010-04-10 19:53:17 +04:00
int unit_load_fragment_and_dropin ( Unit * u ) {
2010-04-06 04:43:58 +04:00
int r ;
assert ( u ) ;
/* Load a .service file */
2010-04-10 19:53:17 +04:00
if ( ( r = unit_load_fragment ( u ) ) < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state = = UNIT_STUB )
2010-04-06 04:43:58 +04:00
return - ENOENT ;
/* Load drop-in directory data */
if ( ( r = unit_load_dropin ( unit_follow_merge ( u ) ) ) < 0 )
return r ;
return 0 ;
}
/* Common implementation for multiple backends */
2010-04-10 19:53:17 +04:00
int unit_load_fragment_and_dropin_optional ( Unit * u ) {
2010-04-06 04:43:58 +04:00
int r ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-04-06 04:43:58 +04:00
/* Same as unit_load_fragment_and_dropin(), but whether
* something can be loaded or not doesn ' t matter . */
/* Load a .service file */
2010-04-10 19:53:17 +04:00
if ( ( r = unit_load_fragment ( u ) ) < 0 )
2010-01-26 23:39:06 +03:00
return r ;
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state = = UNIT_STUB )
u - > meta . load_state = UNIT_LOADED ;
2010-01-28 04:44:47 +03:00
2010-01-26 23:39:06 +03:00
/* Load drop-in directory data */
2010-04-06 04:43:58 +04:00
if ( ( r = unit_load_dropin ( unit_follow_merge ( u ) ) ) < 0 )
2010-01-26 23:39:06 +03:00
return r ;
2010-04-06 04:43:58 +04:00
return 0 ;
2010-01-26 23:39:06 +03:00
}
2010-09-14 03:51:30 +04:00
int unit_add_default_target_dependency ( Unit * u , Unit * target ) {
2010-09-13 14:06:49 +04:00
assert ( u ) ;
assert ( target ) ;
if ( target - > meta . type ! = UNIT_TARGET )
return 0 ;
2011-02-21 17:32:17 +03:00
/* Only add the dependency if both units are loaded, so that
2010-09-14 03:51:30 +04:00
* that loop check below is reliable */
if ( u - > meta . load_state ! = UNIT_LOADED | |
target - > meta . load_state ! = UNIT_LOADED )
return 0 ;
2011-03-08 05:24:42 +03:00
/* If either side wants no automatic dependencies, then let's
* skip this */
if ( ! u - > meta . default_dependencies | |
target - > meta . default_dependencies )
return 0 ;
2010-09-13 14:06:49 +04:00
/* Don't create loops */
if ( set_get ( target - > meta . dependencies [ UNIT_BEFORE ] , u ) )
return 0 ;
return unit_add_dependency ( target , UNIT_AFTER , u , true ) ;
}
static int unit_add_default_dependencies ( Unit * u ) {
2011-03-08 05:24:42 +03:00
static const UnitDependency deps [ ] = {
UNIT_REQUIRED_BY ,
UNIT_REQUIRED_BY_OVERRIDABLE ,
UNIT_WANTED_BY ,
UNIT_BOUND_BY
} ;
2010-09-14 03:51:30 +04:00
Unit * target ;
2010-09-13 14:06:49 +04:00
Iterator i ;
int r ;
2011-03-08 05:24:42 +03:00
unsigned k ;
2010-09-13 14:06:49 +04:00
assert ( u ) ;
2011-03-08 05:24:42 +03:00
for ( k = 0 ; k < ELEMENTSOF ( deps ) ; k + + )
SET_FOREACH ( target , u - > meta . dependencies [ deps [ k ] ] , i )
if ( ( r = unit_add_default_target_dependency ( u , target ) ) < 0 )
return r ;
2010-10-29 01:18:47 +04:00
2010-09-13 14:06:49 +04:00
return 0 ;
}
2010-01-26 23:39:06 +03:00
int unit_load ( Unit * u ) {
int r ;
assert ( u ) ;
if ( u - > meta . in_load_queue ) {
LIST_REMOVE ( Meta , load_queue , u - > meta . manager - > load_queue , & u - > meta ) ;
u - > meta . in_load_queue = false ;
}
2010-04-10 19:53:17 +04:00
if ( u - > meta . type = = _UNIT_TYPE_INVALID )
return - EINVAL ;
2010-01-26 23:39:06 +03:00
if ( u - > meta . load_state ! = UNIT_STUB )
return 0 ;
2010-04-10 19:53:17 +04:00
if ( UNIT_VTABLE ( u ) - > load )
if ( ( r = UNIT_VTABLE ( u ) - > load ( u ) ) < 0 )
2010-01-26 23:39:06 +03:00
goto fail ;
2010-04-06 04:43:58 +04:00
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state = = UNIT_STUB ) {
2010-04-06 04:43:58 +04:00
r = - ENOENT ;
goto fail ;
}
2010-09-13 14:06:49 +04:00
if ( u - > meta . load_state = = UNIT_LOADED & &
u - > meta . default_dependencies )
if ( ( r = unit_add_default_dependencies ( u ) ) < 0 )
goto fail ;
2011-04-07 20:47:35 +04:00
if ( u - > meta . on_failure_isolate & &
set_size ( u - > meta . dependencies [ UNIT_ON_FAILURE ] ) > 1 ) {
log_error ( " More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing. " ,
u - > meta . id ) ;
r = - EINVAL ;
goto fail ;
}
2010-04-06 04:43:58 +04:00
assert ( ( u - > meta . load_state ! = UNIT_MERGED ) = = ! u - > meta . merged_into ) ;
unit_add_to_dbus_queue ( unit_follow_merge ( u ) ) ;
2010-04-21 08:01:13 +04:00
unit_add_to_gc_queue ( u ) ;
2010-01-26 23:39:06 +03:00
return 0 ;
fail :
2010-08-31 02:23:34 +04:00
u - > meta . load_state = UNIT_ERROR ;
2010-08-12 03:05:35 +04:00
u - > meta . load_error = r ;
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-04-06 04:43:58 +04:00
2010-08-12 03:05:35 +04:00
log_debug ( " Failed to load configuration for %s: %s " , u - > meta . id , strerror ( - r ) ) ;
2010-04-06 04:43:58 +04:00
2010-01-26 23:39:06 +03:00
return r ;
}
2011-03-10 01:58:17 +03:00
bool unit_condition_test ( Unit * u ) {
assert ( u ) ;
dual_timestamp_get ( & u - > meta . condition_timestamp ) ;
u - > meta . condition_result = condition_test_list ( u - > meta . conditions ) ;
return u - > meta . condition_result ;
}
2010-01-26 23:39:06 +03:00
/* Errors:
2010-05-20 03:14:43 +04:00
* - EBADR : This unit type does not support starting .
* - EALREADY : Unit is already started .
* - EAGAIN : An operation is already in progress . Retry later .
* - ECANCELED : Too many requests for now .
2010-01-26 23:39:06 +03:00
*/
int unit_start ( Unit * u ) {
UnitActiveState state ;
2010-11-15 01:26:53 +03:00
Unit * following ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-07-01 02:31:53 +04:00
if ( u - > meta . load_state ! = UNIT_LOADED )
return - EINVAL ;
2010-02-12 04:40:28 +03:00
/* If this is already (being) started, then this will
* succeed . Note that this will even succeed if this unit is
* not startable by the user . This is relied on to detect when
* we need to wait for units and when waiting is finished . */
2010-01-26 23:39:06 +03:00
state = unit_active_state ( u ) ;
if ( UNIT_IS_ACTIVE_OR_RELOADING ( state ) )
return - EALREADY ;
2010-10-13 04:15:41 +04:00
/* If the conditions failed, don't do anything at all */
2011-03-10 01:58:17 +03:00
if ( ! unit_condition_test ( u ) ) {
2010-10-13 04:15:41 +04:00
log_debug ( " Starting of %s requested but condition failed. Ignoring. " , u - > meta . id ) ;
return - EALREADY ;
}
2010-11-15 01:26:53 +03:00
/* Forward to the main object, if we aren't it. */
if ( ( following = unit_following ( u ) ) ) {
log_debug ( " Redirecting start request from %s to %s. " , u - > meta . id , following - > meta . id ) ;
return unit_start ( following ) ;
}
/* If it is stopped, but we cannot start it, then fail */
if ( ! UNIT_VTABLE ( u ) - > start )
return - EBADR ;
2010-01-26 23:39:06 +03:00
/* We don't suppress calls to ->start() here when we are
* already starting , to allow this request to be used as a
* " hurry up " call , for example when the unit is in some " auto
* restart " state where it waits for a holdoff timer to elapse
* before it will start again . */
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-07-07 02:00:59 +04:00
unit_status_printf ( u , " Starting %s... \n " , unit_description ( u ) ) ;
2010-01-26 23:39:06 +03:00
return UNIT_VTABLE ( u ) - > start ( u ) ;
}
bool unit_can_start ( Unit * u ) {
assert ( u ) ;
return ! ! UNIT_VTABLE ( u ) - > start ;
}
2010-08-31 00:45:46 +04:00
bool unit_can_isolate ( Unit * u ) {
assert ( u ) ;
return unit_can_start ( u ) & &
u - > meta . allow_isolate ;
}
2010-01-26 23:39:06 +03:00
/* Errors:
* - EBADR : This unit type does not support stopping .
* - EALREADY : Unit is already stopped .
* - EAGAIN : An operation is already in progress . Retry later .
*/
int unit_stop ( Unit * u ) {
UnitActiveState state ;
2010-11-15 01:26:53 +03:00
Unit * following ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
state = unit_active_state ( u ) ;
2010-08-31 02:23:34 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( state ) )
2010-01-26 23:39:06 +03:00
return - EALREADY ;
2010-11-15 01:26:53 +03:00
if ( ( following = unit_following ( u ) ) ) {
log_debug ( " Redirecting stop request from %s to %s. " , u - > meta . id , following - > meta . id ) ;
return unit_stop ( following ) ;
}
2010-02-12 04:40:28 +03:00
if ( ! UNIT_VTABLE ( u ) - > stop )
return - EBADR ;
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-07-07 02:00:59 +04:00
unit_status_printf ( u , " Stopping %s... \n " , unit_description ( u ) ) ;
2010-01-26 23:39:06 +03:00
return UNIT_VTABLE ( u ) - > stop ( u ) ;
}
/* Errors:
* - EBADR : This unit type does not support reloading .
* - ENOEXEC : Unit is not started .
* - EAGAIN : An operation is already in progress . Retry later .
*/
int unit_reload ( Unit * u ) {
UnitActiveState state ;
2010-11-15 01:26:53 +03:00
Unit * following ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-07-01 02:31:53 +04:00
if ( u - > meta . load_state ! = UNIT_LOADED )
return - EINVAL ;
2010-01-26 23:39:06 +03:00
if ( ! unit_can_reload ( u ) )
return - EBADR ;
state = unit_active_state ( u ) ;
2010-08-12 00:04:22 +04:00
if ( state = = UNIT_RELOADING )
2010-01-26 23:39:06 +03:00
return - EALREADY ;
2010-08-12 00:04:22 +04:00
if ( state ! = UNIT_ACTIVE )
2010-01-26 23:39:06 +03:00
return - ENOEXEC ;
2010-11-15 01:26:53 +03:00
if ( ( following = unit_following ( u ) ) ) {
log_debug ( " Redirecting reload request from %s to %s. " , u - > meta . id , following - > meta . id ) ;
return unit_reload ( following ) ;
}
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-01-26 23:39:06 +03:00
return UNIT_VTABLE ( u ) - > reload ( u ) ;
}
bool unit_can_reload ( Unit * u ) {
assert ( u ) ;
if ( ! UNIT_VTABLE ( u ) - > reload )
return false ;
if ( ! UNIT_VTABLE ( u ) - > can_reload )
return true ;
return UNIT_VTABLE ( u ) - > can_reload ( u ) ;
}
2010-09-28 01:27:21 +04:00
static void unit_check_unneeded ( Unit * u ) {
2010-01-29 22:47:09 +03:00
Iterator i ;
Unit * other ;
assert ( u ) ;
/* If this service shall be shut down when unneeded then do
* so . */
if ( ! u - > meta . stop_when_unneeded )
return ;
if ( ! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( u ) ) )
return ;
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRED_BY ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
return ;
2010-04-15 05:11:11 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRED_BY_OVERRIDABLE ] , i )
2010-01-29 22:47:09 +03:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
return ;
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_WANTED_BY ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
return ;
2010-10-29 01:18:47 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_BOUND_BY ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
return ;
2010-07-07 19:57:54 +04:00
log_info ( " Service %s is not needed anymore. Stopping. " , u - > meta . id ) ;
2010-01-29 22:47:09 +03:00
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_STOP , u , JOB_FAIL , true , NULL , NULL ) ;
2010-01-29 22:47:09 +03:00
}
2010-01-26 23:39:06 +03:00
static void retroactively_start_dependencies ( Unit * u ) {
Iterator i ;
Unit * other ;
assert ( u ) ;
assert ( UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( u ) ) ) ;
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRES ] , i )
2010-10-29 01:18:47 +04:00
if ( ! set_get ( u - > meta . dependencies [ UNIT_AFTER ] , other ) & &
! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
manager_add_job ( u - > meta . manager , JOB_START , other , JOB_REPLACE , true , NULL , NULL ) ;
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_BIND_TO ] , i )
if ( ! set_get ( u - > meta . dependencies [ UNIT_AFTER ] , other ) & &
! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_START , other , JOB_REPLACE , true , NULL , NULL ) ;
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRES_OVERRIDABLE ] , i )
2010-10-29 01:18:47 +04:00
if ( ! set_get ( u - > meta . dependencies [ UNIT_AFTER ] , other ) & &
! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_START , other , JOB_FAIL , false , NULL , NULL ) ;
2010-01-26 23:39:06 +03:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUISITE ] , i )
2010-10-29 01:18:47 +04:00
if ( ! set_get ( u - > meta . dependencies [ UNIT_AFTER ] , other ) & &
! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_START , other , JOB_REPLACE , true , NULL , NULL ) ;
2010-01-26 23:39:06 +03:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_WANTS ] , i )
2010-10-29 01:18:47 +04:00
if ( ! set_get ( u - > meta . dependencies [ UNIT_AFTER ] , other ) & &
! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_START , other , JOB_FAIL , false , NULL , NULL ) ;
2010-01-26 23:39:06 +03:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_CONFLICTS ] , i )
2010-10-29 01:18:47 +04:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-07-08 04:43:18 +04:00
manager_add_job ( u - > meta . manager , JOB_STOP , other , JOB_REPLACE , true , NULL , NULL ) ;
2010-08-10 00:32:30 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_CONFLICTED_BY ] , i )
2010-10-29 01:18:47 +04:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-08-10 00:32:30 +04:00
manager_add_job ( u - > meta . manager , JOB_STOP , other , JOB_REPLACE , true , NULL , NULL ) ;
2010-01-26 23:39:06 +03:00
}
static void retroactively_stop_dependencies ( Unit * u ) {
Iterator i ;
Unit * other ;
assert ( u ) ;
assert ( UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( u ) ) ) ;
2010-10-29 01:18:47 +04:00
/* Pull down units which are bound to us recursively if enabled */
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_BOUND_BY ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-10-28 05:38:52 +04:00
manager_add_job ( u - > meta . manager , JOB_STOP , other , JOB_REPLACE , true , NULL , NULL ) ;
2010-01-29 22:47:09 +03:00
/* Garbage collect services that might not be needed anymore, if enabled */
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRES ] , i )
2010-01-26 23:39:06 +03:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( other ) ;
2010-04-15 05:11:11 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUIRES_OVERRIDABLE ] , i )
2010-01-29 22:47:09 +03:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( other ) ;
2010-01-29 22:47:09 +03:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_WANTS ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( other ) ;
2010-01-29 22:47:09 +03:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUISITE ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( other ) ;
2010-04-15 05:11:11 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_REQUISITE_OVERRIDABLE ] , i )
2010-01-29 22:47:09 +03:00
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( other ) ;
2010-10-29 01:18:47 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_BIND_TO ] , i )
if ( ! UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( other ) ) )
unit_check_unneeded ( other ) ;
2010-01-26 23:39:06 +03:00
}
2011-02-24 05:24:23 +03:00
void unit_trigger_on_failure ( Unit * u ) {
Unit * other ;
Iterator i ;
assert ( u ) ;
2011-04-07 06:11:31 +04:00
if ( set_size ( u - > meta . dependencies [ UNIT_ON_FAILURE ] ) < = 0 )
return ;
log_info ( " Triggering OnFailure= dependencies of %s. " , u - > meta . id ) ;
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_ON_FAILURE ] , i ) {
int r ;
if ( ( r = manager_add_job ( u - > meta . manager , JOB_START , other , u - > meta . on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE , true , NULL , NULL ) ) < 0 )
log_error ( " Failed to enqueue OnFailure= job: %s " , strerror ( - r ) ) ;
}
2011-02-24 05:24:23 +03:00
}
2011-01-20 15:17:22 +03:00
void unit_notify ( Unit * u , UnitActiveState os , UnitActiveState ns , bool reload_success ) {
2010-07-13 04:17:53 +04:00
bool unexpected ;
2010-04-08 03:22:51 +04:00
2010-01-26 23:39:06 +03:00
assert ( u ) ;
assert ( os < _UNIT_ACTIVE_STATE_MAX ) ;
assert ( ns < _UNIT_ACTIVE_STATE_MAX ) ;
2010-04-10 06:45:44 +04:00
/* Note that this is called for all low-level state changes,
* even if they might map to the same high - level
* UnitActiveState ! That means that ns = = os is OK an expected
* behaviour here . For example : if a mount point is remounted
2010-08-11 06:38:55 +04:00
* this function will be called too ! */
2010-01-26 23:39:06 +03:00
2011-07-06 02:47:39 +04:00
if ( u - > meta . manager - > n_reloading < = 0 ) {
2011-03-30 22:04:20 +04:00
dual_timestamp ts ;
2010-05-14 05:05:38 +04:00
2011-03-30 22:04:20 +04:00
dual_timestamp_get ( & ts ) ;
2010-05-14 05:05:38 +04:00
2011-03-30 22:04:20 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( os ) & & ! UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
u - > meta . inactive_exit_timestamp = ts ;
else if ( ! UNIT_IS_INACTIVE_OR_FAILED ( os ) & & UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
u - > meta . inactive_enter_timestamp = ts ;
if ( ! UNIT_IS_ACTIVE_OR_RELOADING ( os ) & & UNIT_IS_ACTIVE_OR_RELOADING ( ns ) )
u - > meta . active_enter_timestamp = ts ;
else if ( UNIT_IS_ACTIVE_OR_RELOADING ( os ) & & ! UNIT_IS_ACTIVE_OR_RELOADING ( ns ) )
u - > meta . active_exit_timestamp = ts ;
timer_unit_notify ( u , ns ) ;
path_unit_notify ( u , ns ) ;
}
2010-01-26 23:39:06 +03:00
2010-08-31 02:23:34 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
2010-07-10 19:34:42 +04:00
cgroup_bonding_trim_list ( u - > meta . cgroup_bondings , true ) ;
2010-01-26 23:39:06 +03:00
if ( u - > meta . job ) {
2010-07-13 04:17:53 +04:00
unexpected = false ;
2010-01-26 23:39:06 +03:00
if ( u - > meta . job - > state = = JOB_WAITING )
/* So we reached a different state for this
* job . Let ' s see if we can run it now if it
* failed previously due to EAGAIN . */
2010-02-05 02:38:41 +03:00
job_add_to_run_queue ( u - > meta . job ) ;
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
/* Let's check whether this state change constitutes a
2011-02-21 17:32:17 +03:00
* finished job , or maybe contradicts a running job and
2010-06-04 22:13:05 +04:00
* hence needs to invalidate jobs . */
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
switch ( u - > meta . job - > type ) {
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
case JOB_START :
case JOB_VERIFY_ACTIVE :
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
if ( UNIT_IS_ACTIVE_OR_RELOADING ( ns ) )
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , JOB_DONE ) ;
2010-06-04 22:13:05 +04:00
else if ( u - > meta . job - > state = = JOB_RUNNING & & ns ! = UNIT_ACTIVATING ) {
unexpected = true ;
2010-08-11 06:02:58 +04:00
2010-08-31 02:23:34 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , ns = = UNIT_FAILED ? JOB_FAILED : JOB_DONE ) ;
2010-06-04 22:13:05 +04:00
}
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
break ;
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
case JOB_RELOAD :
case JOB_RELOAD_OR_START :
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
if ( u - > meta . job - > state = = JOB_RUNNING ) {
2010-04-08 03:22:51 +04:00
if ( ns = = UNIT_ACTIVE )
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , reload_success ? JOB_DONE : JOB_FAILED ) ;
2010-07-01 05:34:15 +04:00
else if ( ns ! = UNIT_ACTIVATING & & ns ! = UNIT_RELOADING ) {
2010-04-08 03:22:51 +04:00
unexpected = true ;
2010-08-11 06:02:58 +04:00
2010-08-31 02:23:34 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , ns = = UNIT_FAILED ? JOB_FAILED : JOB_DONE ) ;
2010-04-08 03:22:51 +04:00
}
2010-06-04 22:13:05 +04:00
}
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
break ;
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
case JOB_STOP :
case JOB_RESTART :
case JOB_TRY_RESTART :
2010-01-26 23:39:06 +03:00
2010-08-31 02:23:34 +04:00
if ( UNIT_IS_INACTIVE_OR_FAILED ( ns ) )
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , JOB_DONE ) ;
2010-06-04 22:13:05 +04:00
else if ( u - > meta . job - > state = = JOB_RUNNING & & ns ! = UNIT_DEACTIVATING ) {
unexpected = true ;
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( u - > meta . job , JOB_FAILED ) ;
2010-06-04 22:13:05 +04:00
}
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
break ;
2010-01-26 23:39:06 +03:00
2010-06-04 22:13:05 +04:00
default :
assert_not_reached ( " Job type unknown " ) ;
2010-01-26 23:39:06 +03:00
}
2010-07-13 04:17:53 +04:00
} else
unexpected = true ;
2011-07-06 02:47:39 +04:00
if ( u - > meta . manager - > n_reloading < = 0 ) {
2010-01-29 22:47:09 +03:00
2011-03-30 22:04:20 +04:00
/* If this state change happened without being
* requested by a job , then let ' s retroactively start
* or stop dependencies . We skip that step when
* deserializing , since we don ' t want to create any
* additional jobs just because something is already
* activated . */
if ( unexpected ) {
if ( UNIT_IS_INACTIVE_OR_FAILED ( os ) & & UNIT_IS_ACTIVE_OR_ACTIVATING ( ns ) )
retroactively_start_dependencies ( u ) ;
else if ( UNIT_IS_ACTIVE_OR_ACTIVATING ( os ) & & UNIT_IS_INACTIVE_OR_DEACTIVATING ( ns ) )
retroactively_stop_dependencies ( u ) ;
}
2010-07-17 02:58:47 +04:00
2011-03-30 22:04:20 +04:00
if ( ns ! = os & & ns = = UNIT_FAILED ) {
log_notice ( " Unit %s entered failed state. " , u - > meta . id ) ;
unit_trigger_on_failure ( u ) ;
2010-08-11 06:38:55 +04:00
}
2011-03-30 22:16:07 +04:00
}
2010-04-10 19:53:17 +04:00
2011-03-30 22:16:07 +04:00
/* Some names are special */
if ( UNIT_IS_ACTIVE_OR_RELOADING ( ns ) ) {
if ( unit_has_name ( u , SPECIAL_DBUS_SERVICE ) )
/* The bus just might have become available,
* hence try to connect to it , if we aren ' t
* yet connected . */
bus_init ( u - > meta . manager , true ) ;
if ( u - > meta . type = = UNIT_SERVICE & &
! UNIT_IS_ACTIVE_OR_RELOADING ( os ) & &
2011-07-06 02:47:39 +04:00
u - > meta . manager - > n_reloading < = 0 ) {
2011-03-30 22:16:07 +04:00
/* Write audit record if we have just finished starting up */
manager_send_unit_audit ( u - > meta . manager , u , AUDIT_SERVICE_START , true ) ;
u - > meta . in_audit = true ;
}
2010-10-06 05:55:49 +04:00
2011-03-30 22:16:07 +04:00
if ( ! UNIT_IS_ACTIVE_OR_RELOADING ( os ) )
manager_send_unit_plymouth ( u - > meta . manager , u ) ;
2011-03-30 22:04:20 +04:00
2011-03-30 22:16:07 +04:00
} else {
2011-03-30 22:04:20 +04:00
2011-03-30 22:16:07 +04:00
/* We don't care about D-Bus here, since we'll get an
* asynchronous notification for it anyway . */
2010-08-11 06:38:55 +04:00
2011-03-30 22:16:07 +04:00
if ( u - > meta . type = = UNIT_SERVICE & &
UNIT_IS_INACTIVE_OR_FAILED ( ns ) & &
! UNIT_IS_INACTIVE_OR_FAILED ( os ) & &
2011-07-06 02:47:39 +04:00
u - > meta . manager - > n_reloading < = 0 ) {
2010-08-11 03:43:23 +04:00
2011-03-30 22:16:07 +04:00
/* Hmm, if there was no start record written
* write it now , so that we always have a nice
* pair */
if ( ! u - > meta . in_audit ) {
manager_send_unit_audit ( u - > meta . manager , u , AUDIT_SERVICE_START , ns = = UNIT_INACTIVE ) ;
2010-08-11 06:38:55 +04:00
2011-03-30 22:16:07 +04:00
if ( ns = = UNIT_INACTIVE )
manager_send_unit_audit ( u - > meta . manager , u , AUDIT_SERVICE_STOP , true ) ;
} else
/* Write audit record if we have just finished shutting down */
manager_send_unit_audit ( u - > meta . manager , u , AUDIT_SERVICE_STOP , ns = = UNIT_INACTIVE ) ;
2011-03-30 22:04:20 +04:00
2011-03-30 22:16:07 +04:00
u - > meta . in_audit = false ;
2010-08-11 06:38:55 +04:00
}
2010-04-06 18:32:07 +04:00
}
2011-03-30 22:16:07 +04:00
manager_recheck_syslog ( u - > meta . manager ) ;
2010-01-29 22:47:09 +03:00
/* Maybe we finished startup and are now ready for being
* stopped because unneeded ? */
2010-09-28 01:27:21 +04:00
unit_check_unneeded ( u ) ;
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-04-21 08:01:13 +04:00
unit_add_to_gc_queue ( u ) ;
2010-01-26 23:39:06 +03:00
}
2010-01-27 06:31:52 +03:00
int unit_watch_fd ( Unit * u , int fd , uint32_t events , Watch * w ) {
2010-01-26 23:39:06 +03:00
struct epoll_event ev ;
assert ( u ) ;
assert ( fd > = 0 ) ;
2010-01-27 06:31:52 +03:00
assert ( w ) ;
2010-02-01 05:33:24 +03:00
assert ( w - > type = = WATCH_INVALID | | ( w - > type = = WATCH_FD & & w - > fd = = fd & & w - > data . unit = = u ) ) ;
2010-01-26 23:39:06 +03:00
zero ( ev ) ;
2010-01-27 06:31:52 +03:00
ev . data . ptr = w ;
2010-01-26 23:39:06 +03:00
ev . events = events ;
2010-01-27 06:31:52 +03:00
if ( epoll_ctl ( u - > meta . manager - > epoll_fd ,
w - > type = = WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD ,
fd ,
& ev ) < 0 )
return - errno ;
2010-01-26 23:39:06 +03:00
2010-01-27 06:31:52 +03:00
w - > fd = fd ;
w - > type = WATCH_FD ;
2010-02-01 05:33:24 +03:00
w - > data . unit = u ;
2010-01-26 23:39:06 +03:00
2010-01-27 06:31:52 +03:00
return 0 ;
2010-01-26 23:39:06 +03:00
}
2010-01-27 06:31:52 +03:00
void unit_unwatch_fd ( Unit * u , Watch * w ) {
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-01-27 06:31:52 +03:00
assert ( w ) ;
2010-01-26 23:39:06 +03:00
2010-01-27 06:31:52 +03:00
if ( w - > type = = WATCH_INVALID )
return ;
2010-02-01 05:33:24 +03:00
assert ( w - > type = = WATCH_FD ) ;
assert ( w - > data . unit = = u ) ;
2010-01-27 06:31:52 +03:00
assert_se ( epoll_ctl ( u - > meta . manager - > epoll_fd , EPOLL_CTL_DEL , w - > fd , NULL ) > = 0 ) ;
w - > fd = - 1 ;
w - > type = WATCH_INVALID ;
2010-02-01 05:33:24 +03:00
w - > data . unit = NULL ;
2010-01-26 23:39:06 +03:00
}
int unit_watch_pid ( Unit * u , pid_t pid ) {
assert ( u ) ;
assert ( pid > = 1 ) ;
2010-04-16 01:16:16 +04:00
/* Watch a specific PID. We only support one unit watching
* each PID for now . */
2010-07-11 02:50:49 +04:00
return hashmap_put ( u - > meta . manager - > watch_pids , LONG_TO_PTR ( pid ) , u ) ;
2010-01-26 23:39:06 +03:00
}
void unit_unwatch_pid ( Unit * u , pid_t pid ) {
assert ( u ) ;
assert ( pid > = 1 ) ;
2010-07-11 02:50:49 +04:00
hashmap_remove_value ( u - > meta . manager - > watch_pids , LONG_TO_PTR ( pid ) , u ) ;
2010-01-26 23:39:06 +03:00
}
2010-01-27 06:31:52 +03:00
int unit_watch_timer ( Unit * u , usec_t delay , Watch * w ) {
2010-01-26 23:39:06 +03:00
struct itimerspec its ;
2010-01-27 06:31:52 +03:00
int flags , fd ;
2010-01-26 23:39:06 +03:00
bool ours ;
assert ( u ) ;
2010-01-27 06:31:52 +03:00
assert ( w ) ;
2010-07-17 06:09:28 +04:00
assert ( w - > type = = WATCH_INVALID | | ( w - > type = = WATCH_UNIT_TIMER & & w - > data . unit = = u ) ) ;
2010-01-26 23:39:06 +03:00
/* This will try to reuse the old timer if there is one */
2010-07-17 06:09:28 +04:00
if ( w - > type = = WATCH_UNIT_TIMER ) {
assert ( w - > data . unit = = u ) ;
assert ( w - > fd > = 0 ) ;
2010-01-26 23:39:06 +03:00
ours = false ;
2010-01-27 06:31:52 +03:00
fd = w - > fd ;
2010-07-17 06:09:28 +04:00
} else if ( w - > type = = WATCH_INVALID ) {
2010-01-26 23:39:06 +03:00
ours = true ;
if ( ( fd = timerfd_create ( CLOCK_MONOTONIC , TFD_NONBLOCK | TFD_CLOEXEC ) ) < 0 )
return - errno ;
2010-07-17 06:09:28 +04:00
} else
assert_not_reached ( " Invalid watch type " ) ;
2010-01-26 23:39:06 +03:00
zero ( its ) ;
if ( delay < = 0 ) {
/* Set absolute time in the past, but not 0, since we
* don ' t want to disarm the timer */
its . it_value . tv_sec = 0 ;
its . it_value . tv_nsec = 1 ;
flags = TFD_TIMER_ABSTIME ;
} else {
timespec_store ( & its . it_value , delay ) ;
flags = 0 ;
}
/* This will also flush the elapse counter */
if ( timerfd_settime ( fd , flags , & its , NULL ) < 0 )
goto fail ;
2010-01-27 06:31:52 +03:00
if ( w - > type = = WATCH_INVALID ) {
struct epoll_event ev ;
2010-01-26 23:39:06 +03:00
2010-01-27 06:31:52 +03:00
zero ( ev ) ;
ev . data . ptr = w ;
2010-01-29 08:45:59 +03:00
ev . events = EPOLLIN ;
2010-01-27 06:31:52 +03:00
if ( epoll_ctl ( u - > meta . manager - > epoll_fd , EPOLL_CTL_ADD , fd , & ev ) < 0 )
goto fail ;
}
2010-07-17 06:09:28 +04:00
w - > type = WATCH_UNIT_TIMER ;
2010-01-27 06:31:52 +03:00
w - > fd = fd ;
2010-02-01 05:33:24 +03:00
w - > data . unit = u ;
2010-01-26 23:39:06 +03:00
return 0 ;
fail :
if ( ours )
2010-02-01 05:33:24 +03:00
close_nointr_nofail ( fd ) ;
2010-01-26 23:39:06 +03:00
return - errno ;
}
2010-01-27 06:31:52 +03:00
void unit_unwatch_timer ( Unit * u , Watch * w ) {
2010-01-26 23:39:06 +03:00
assert ( u ) ;
2010-01-27 06:31:52 +03:00
assert ( w ) ;
2010-01-26 23:39:06 +03:00
2010-01-27 06:31:52 +03:00
if ( w - > type = = WATCH_INVALID )
2010-01-26 23:39:06 +03:00
return ;
2010-07-17 06:09:28 +04:00
assert ( w - > type = = WATCH_UNIT_TIMER ) ;
assert ( w - > data . unit = = u ) ;
assert ( w - > fd > = 0 ) ;
2010-01-27 06:31:52 +03:00
assert_se ( epoll_ctl ( u - > meta . manager - > epoll_fd , EPOLL_CTL_DEL , w - > fd , NULL ) > = 0 ) ;
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( w - > fd ) ;
2010-01-27 06:31:52 +03:00
w - > fd = - 1 ;
w - > type = WATCH_INVALID ;
2010-02-01 05:33:24 +03:00
w - > data . unit = NULL ;
2010-01-26 23:39:06 +03:00
}
bool unit_job_is_applicable ( Unit * u , JobType j ) {
assert ( u ) ;
assert ( j > = 0 & & j < _JOB_TYPE_MAX ) ;
switch ( j ) {
case JOB_VERIFY_ACTIVE :
case JOB_START :
2010-11-14 23:57:10 +03:00
case JOB_STOP :
2010-01-26 23:39:06 +03:00
return true ;
case JOB_RESTART :
case JOB_TRY_RESTART :
return unit_can_start ( u ) ;
case JOB_RELOAD :
return unit_can_reload ( u ) ;
case JOB_RELOAD_OR_START :
return unit_can_reload ( u ) & & unit_can_start ( u ) ;
default :
assert_not_reached ( " Invalid job type " ) ;
}
}
2010-04-21 08:01:13 +04:00
int unit_add_dependency ( Unit * u , UnitDependency d , Unit * other , bool add_reference ) {
2010-01-26 23:39:06 +03:00
static const UnitDependency inverse_table [ _UNIT_DEPENDENCY_MAX ] = {
[ UNIT_REQUIRES ] = UNIT_REQUIRED_BY ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUIRES_OVERRIDABLE ] = UNIT_REQUIRED_BY_OVERRIDABLE ,
2010-01-26 23:39:06 +03:00
[ UNIT_WANTS ] = UNIT_WANTED_BY ,
[ UNIT_REQUISITE ] = UNIT_REQUIRED_BY ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUISITE_OVERRIDABLE ] = UNIT_REQUIRED_BY_OVERRIDABLE ,
2010-10-29 01:18:47 +04:00
[ UNIT_BIND_TO ] = UNIT_BOUND_BY ,
2010-01-26 23:39:06 +03:00
[ UNIT_REQUIRED_BY ] = _UNIT_DEPENDENCY_INVALID ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUIRED_BY_OVERRIDABLE ] = _UNIT_DEPENDENCY_INVALID ,
2010-01-26 23:39:06 +03:00
[ UNIT_WANTED_BY ] = _UNIT_DEPENDENCY_INVALID ,
2010-10-29 01:18:47 +04:00
[ UNIT_BOUND_BY ] = UNIT_BIND_TO ,
2010-08-10 00:32:30 +04:00
[ UNIT_CONFLICTS ] = UNIT_CONFLICTED_BY ,
[ UNIT_CONFLICTED_BY ] = UNIT_CONFLICTS ,
2010-01-26 23:39:06 +03:00
[ UNIT_BEFORE ] = UNIT_AFTER ,
2010-04-21 08:01:13 +04:00
[ UNIT_AFTER ] = UNIT_BEFORE ,
2010-07-17 02:58:47 +04:00
[ UNIT_ON_FAILURE ] = _UNIT_DEPENDENCY_INVALID ,
2010-04-21 08:01:13 +04:00
[ UNIT_REFERENCES ] = UNIT_REFERENCED_BY ,
[ UNIT_REFERENCED_BY ] = UNIT_REFERENCES
2010-01-26 23:39:06 +03:00
} ;
2010-04-21 08:01:13 +04:00
int r , q = 0 , v = 0 , w = 0 ;
2010-01-26 23:39:06 +03:00
assert ( u ) ;
assert ( d > = 0 & & d < _UNIT_DEPENDENCY_MAX ) ;
assert ( other ) ;
2010-09-28 01:24:17 +04:00
u = unit_follow_merge ( u ) ;
other = unit_follow_merge ( other ) ;
2010-01-26 23:39:06 +03:00
/* We won't allow dependencies on ourselves. We will not
* consider them an error however . */
if ( u = = other )
return 0 ;
2010-07-17 02:58:47 +04:00
if ( ( r = set_ensure_allocated ( & u - > meta . dependencies [ d ] , trivial_hash_func , trivial_compare_func ) ) < 0 )
2010-01-26 23:39:06 +03:00
return r ;
2010-07-17 02:58:47 +04:00
if ( inverse_table [ d ] ! = _UNIT_DEPENDENCY_INVALID )
if ( ( r = set_ensure_allocated ( & other - > meta . dependencies [ inverse_table [ d ] ] , trivial_hash_func , trivial_compare_func ) ) < 0 )
return r ;
2010-04-21 08:01:13 +04:00
if ( add_reference )
if ( ( r = set_ensure_allocated ( & u - > meta . dependencies [ UNIT_REFERENCES ] , trivial_hash_func , trivial_compare_func ) ) < 0 | |
( r = set_ensure_allocated ( & other - > meta . dependencies [ UNIT_REFERENCED_BY ] , trivial_hash_func , trivial_compare_func ) ) < 0 )
return r ;
2010-01-26 23:39:06 +03:00
2010-04-21 08:01:13 +04:00
if ( ( q = set_put ( u - > meta . dependencies [ d ] , other ) ) < 0 )
return q ;
2010-01-26 23:39:06 +03:00
2010-07-17 02:58:47 +04:00
if ( inverse_table [ d ] ! = _UNIT_DEPENDENCY_INVALID )
if ( ( v = set_put ( other - > meta . dependencies [ inverse_table [ d ] ] , u ) ) < 0 ) {
r = v ;
goto fail ;
}
2010-04-21 08:01:13 +04:00
if ( add_reference ) {
if ( ( w = set_put ( u - > meta . dependencies [ UNIT_REFERENCES ] , other ) ) < 0 ) {
r = w ;
goto fail ;
}
if ( ( r = set_put ( other - > meta . dependencies [ UNIT_REFERENCED_BY ] , u ) ) < 0 )
goto fail ;
2010-01-26 23:39:06 +03:00
}
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-01-26 23:39:06 +03:00
return 0 ;
2010-04-21 08:01:13 +04:00
fail :
if ( q > 0 )
set_remove ( u - > meta . dependencies [ d ] , other ) ;
if ( v > 0 )
set_remove ( other - > meta . dependencies [ inverse_table [ d ] ] , u ) ;
if ( w > 0 )
set_remove ( u - > meta . dependencies [ UNIT_REFERENCES ] , other ) ;
return r ;
2010-01-26 23:39:06 +03:00
}
2010-01-27 02:15:56 +03:00
2010-07-03 21:46:38 +04:00
int unit_add_two_dependencies ( Unit * u , UnitDependency d , UnitDependency e , Unit * other , bool add_reference ) {
int r ;
assert ( u ) ;
if ( ( r = unit_add_dependency ( u , d , other , add_reference ) ) < 0 )
return r ;
if ( ( r = unit_add_dependency ( u , e , other , add_reference ) ) < 0 )
return r ;
return 0 ;
}
2010-04-15 05:11:11 +04:00
static const char * resolve_template ( Unit * u , const char * name , const char * path , char * * p ) {
char * s ;
assert ( u ) ;
assert ( name | | path ) ;
if ( ! name )
name = file_name_from_path ( path ) ;
if ( ! unit_name_is_template ( name ) ) {
* p = NULL ;
return name ;
}
if ( u - > meta . instance )
s = unit_name_replace_instance ( name , u - > meta . instance ) ;
else {
char * i ;
if ( ! ( i = unit_name_to_prefix ( u - > meta . id ) ) )
return NULL ;
s = unit_name_replace_instance ( name , i ) ;
free ( i ) ;
}
if ( ! s )
return NULL ;
* p = s ;
return s ;
}
2010-04-21 08:01:13 +04:00
int unit_add_dependency_by_name ( Unit * u , UnitDependency d , const char * name , const char * path , bool add_reference ) {
2010-01-28 08:43:23 +03:00
Unit * other ;
int r ;
2010-04-15 05:11:11 +04:00
char * s ;
2010-01-28 08:43:23 +03:00
2010-04-15 05:11:11 +04:00
assert ( u ) ;
assert ( name | | path ) ;
2010-01-28 08:43:23 +03:00
2010-04-15 05:11:11 +04:00
if ( ! ( name = resolve_template ( u , name , path , & s ) ) )
return - ENOMEM ;
2010-01-28 08:43:23 +03:00
2010-07-08 04:43:18 +04:00
if ( ( r = manager_load_unit ( u - > meta . manager , name , path , NULL , & other ) ) < 0 )
2010-04-15 05:11:11 +04:00
goto finish ;
2010-04-21 08:01:13 +04:00
r = unit_add_dependency ( u , d , other , add_reference ) ;
2010-04-15 05:11:11 +04:00
finish :
free ( s ) ;
return r ;
2010-01-28 08:43:23 +03:00
}
2010-07-03 21:46:38 +04:00
int unit_add_two_dependencies_by_name ( Unit * u , UnitDependency d , UnitDependency e , const char * name , const char * path , bool add_reference ) {
Unit * other ;
int r ;
char * s ;
assert ( u ) ;
assert ( name | | path ) ;
if ( ! ( name = resolve_template ( u , name , path , & s ) ) )
return - ENOMEM ;
2010-07-08 04:43:18 +04:00
if ( ( r = manager_load_unit ( u - > meta . manager , name , path , NULL , & other ) ) < 0 )
2010-07-03 21:46:38 +04:00
goto finish ;
r = unit_add_two_dependencies ( u , d , e , other , add_reference ) ;
finish :
free ( s ) ;
return r ;
}
2010-04-21 08:01:13 +04:00
int unit_add_dependency_by_name_inverse ( Unit * u , UnitDependency d , const char * name , const char * path , bool add_reference ) {
2010-04-01 23:30:40 +04:00
Unit * other ;
int r ;
2010-04-15 05:11:11 +04:00
char * s ;
2010-04-01 23:30:40 +04:00
2010-04-15 05:11:11 +04:00
assert ( u ) ;
assert ( name | | path ) ;
2010-04-01 23:30:40 +04:00
2010-04-15 05:11:11 +04:00
if ( ! ( name = resolve_template ( u , name , path , & s ) ) )
return - ENOMEM ;
2010-04-01 23:30:40 +04:00
2010-07-08 04:43:18 +04:00
if ( ( r = manager_load_unit ( u - > meta . manager , name , path , NULL , & other ) ) < 0 )
2010-04-15 05:11:11 +04:00
goto finish ;
2010-04-21 08:01:13 +04:00
r = unit_add_dependency ( other , d , u , add_reference ) ;
2010-04-15 05:11:11 +04:00
finish :
free ( s ) ;
return r ;
2010-04-01 23:30:40 +04:00
}
2010-07-03 21:46:38 +04:00
int unit_add_two_dependencies_by_name_inverse ( Unit * u , UnitDependency d , UnitDependency e , const char * name , const char * path , bool add_reference ) {
Unit * other ;
int r ;
char * s ;
assert ( u ) ;
assert ( name | | path ) ;
if ( ! ( name = resolve_template ( u , name , path , & s ) ) )
return - ENOMEM ;
2010-07-08 04:43:18 +04:00
if ( ( r = manager_load_unit ( u - > meta . manager , name , path , NULL , & other ) ) < 0 )
2010-07-03 21:46:38 +04:00
goto finish ;
if ( ( r = unit_add_two_dependencies ( other , d , e , u , add_reference ) ) < 0 )
goto finish ;
finish :
free ( s ) ;
return r ;
}
2010-01-27 02:15:56 +03:00
int set_unit_path ( const char * p ) {
char * cwd , * c ;
int r ;
/* This is mostly for debug purposes */
if ( path_is_absolute ( p ) ) {
if ( ! ( c = strdup ( p ) ) )
return - ENOMEM ;
} else {
if ( ! ( cwd = get_current_dir_name ( ) ) )
return - errno ;
r = asprintf ( & c , " %s/%s " , cwd , p ) ;
free ( cwd ) ;
if ( r < 0 )
return - ENOMEM ;
}
2010-02-13 03:07:02 +03:00
if ( setenv ( " SYSTEMD_UNIT_PATH " , c , 0 ) < 0 ) {
2010-01-27 02:15:56 +03:00
r = - errno ;
free ( c ) ;
return r ;
}
return 0 ;
}
2010-01-28 08:44:30 +03:00
2010-02-01 05:33:24 +03:00
char * unit_dbus_path ( Unit * u ) {
char * p , * e ;
assert ( u ) ;
2010-08-09 19:02:09 +04:00
if ( ! u - > meta . id )
return NULL ;
2010-04-15 05:11:11 +04:00
if ( ! ( e = bus_path_escape ( u - > meta . id ) ) )
2010-02-01 05:33:24 +03:00
return NULL ;
2010-07-12 20:16:44 +04:00
p = strappend ( " /org/freedesktop/systemd1/unit/ " , e ) ;
2010-02-01 05:33:24 +03:00
free ( e ) ;
2010-07-12 20:16:44 +04:00
2010-02-01 05:33:24 +03:00
return p ;
}
2010-03-31 18:29:55 +04:00
int unit_add_cgroup ( Unit * u , CGroupBonding * b ) {
int r ;
assert ( u ) ;
assert ( b ) ;
2010-07-12 20:16:44 +04:00
2010-03-31 18:29:55 +04:00
assert ( b - > path ) ;
2011-06-30 04:41:01 +04:00
if ( ! b - > controller ) {
2010-07-12 20:16:44 +04:00
if ( ! ( b - > controller = strdup ( SYSTEMD_CGROUP_CONTROLLER ) ) )
return - ENOMEM ;
2011-06-30 04:41:01 +04:00
b - > ours = true ;
}
2010-03-31 18:29:55 +04:00
/* Ensure this hasn't been added yet */
assert ( ! b - > unit ) ;
2010-11-17 23:27:53 +03:00
if ( streq ( b - > controller , SYSTEMD_CGROUP_CONTROLLER ) ) {
CGroupBonding * l ;
2010-03-31 18:29:55 +04:00
2010-11-17 23:27:53 +03:00
l = hashmap_get ( u - > meta . manager - > cgroup_bondings , b - > path ) ;
LIST_PREPEND ( CGroupBonding , by_path , l , b ) ;
if ( ( r = hashmap_replace ( u - > meta . manager - > cgroup_bondings , b - > path , l ) ) < 0 ) {
LIST_REMOVE ( CGroupBonding , by_path , l , b ) ;
return r ;
}
2010-03-31 18:29:55 +04:00
}
LIST_PREPEND ( CGroupBonding , by_unit , u - > meta . cgroup_bondings , b ) ;
b - > unit = u ;
return 0 ;
}
2010-04-10 06:46:52 +04:00
static char * default_cgroup_path ( Unit * u ) {
char * p ;
assert ( u ) ;
2010-04-15 08:19:54 +04:00
if ( u - > meta . instance ) {
char * t ;
2010-04-10 06:46:52 +04:00
2011-08-01 04:45:51 +04:00
t = unit_name_template ( u - > meta . id ) ;
if ( ! t )
2010-04-15 08:19:54 +04:00
return NULL ;
2011-08-01 04:45:51 +04:00
p = join ( u - > meta . manager - > cgroup_hierarchy , " / " , t , " / " , u - > meta . instance , NULL ) ;
2010-04-15 08:19:54 +04:00
free ( t ) ;
} else
2011-08-01 04:45:51 +04:00
p = join ( u - > meta . manager - > cgroup_hierarchy , " / " , u - > meta . id , NULL ) ;
2010-04-15 08:19:54 +04:00
2011-08-01 04:45:51 +04:00
return p ;
2010-04-10 06:46:52 +04:00
}
2010-03-31 18:29:55 +04:00
int unit_add_cgroup_from_text ( Unit * u , const char * name ) {
2010-04-10 06:46:52 +04:00
char * controller = NULL , * path = NULL ;
CGroupBonding * b = NULL ;
2011-06-30 04:41:01 +04:00
bool ours = false ;
2010-03-31 18:29:55 +04:00
int r ;
assert ( u ) ;
assert ( name ) ;
2010-07-12 20:16:44 +04:00
if ( ( r = cg_split_spec ( name , & controller , & path ) ) < 0 )
return r ;
2010-03-31 18:29:55 +04:00
2011-06-30 04:41:01 +04:00
if ( ! path ) {
2010-07-12 20:16:44 +04:00
path = default_cgroup_path ( u ) ;
2011-06-30 04:41:01 +04:00
ours = true ;
}
2010-04-10 06:46:52 +04:00
2011-06-30 04:41:01 +04:00
if ( ! controller ) {
2010-07-10 19:38:50 +04:00
controller = strdup ( SYSTEMD_CGROUP_CONTROLLER ) ;
2011-06-30 04:41:01 +04:00
ours = true ;
}
2010-04-10 06:46:52 +04:00
2010-07-12 20:16:44 +04:00
if ( ! path | | ! controller ) {
free ( path ) ;
free ( controller ) ;
return - ENOMEM ;
2010-03-31 18:29:55 +04:00
}
2010-04-10 06:46:52 +04:00
if ( cgroup_bonding_find_list ( u - > meta . cgroup_bondings , controller ) ) {
r = - EEXIST ;
goto fail ;
}
2010-03-31 18:29:55 +04:00
2010-04-10 06:46:52 +04:00
if ( ! ( b = new0 ( CGroupBonding , 1 ) ) ) {
2010-03-31 18:29:55 +04:00
r = - ENOMEM ;
goto fail ;
}
2010-04-10 06:46:52 +04:00
b - > controller = controller ;
b - > path = path ;
2011-06-30 04:41:01 +04:00
b - > ours = ours ;
b - > essential = streq ( controller , SYSTEMD_CGROUP_CONTROLLER ) ;
2010-03-31 18:29:55 +04:00
if ( ( r = unit_add_cgroup ( u , b ) ) < 0 )
goto fail ;
return 0 ;
fail :
2010-04-10 06:46:52 +04:00
free ( path ) ;
free ( controller ) ;
2010-03-31 18:29:55 +04:00
free ( b ) ;
return r ;
}
2010-11-18 02:42:35 +03:00
static int unit_add_one_default_cgroup ( Unit * u , const char * controller ) {
2010-11-17 23:27:53 +03:00
CGroupBonding * b = NULL ;
2010-03-31 18:29:55 +04:00
int r = - ENOMEM ;
assert ( u ) ;
2010-11-18 02:42:35 +03:00
if ( ! controller )
controller = SYSTEMD_CGROUP_CONTROLLER ;
2010-03-31 18:29:55 +04:00
2010-11-18 02:42:35 +03:00
if ( cgroup_bonding_find_list ( u - > meta . cgroup_bondings , controller ) )
return 0 ;
2010-03-31 18:29:55 +04:00
2010-11-18 02:42:35 +03:00
if ( ! ( b = new0 ( CGroupBonding , 1 ) ) )
return - ENOMEM ;
2010-03-31 18:29:55 +04:00
2010-11-18 02:42:35 +03:00
if ( ! ( b - > controller = strdup ( controller ) ) )
goto fail ;
2010-11-17 23:27:53 +03:00
2010-11-18 02:42:35 +03:00
if ( ! ( b - > path = default_cgroup_path ( u ) ) )
goto fail ;
2010-11-17 23:27:53 +03:00
2010-11-18 02:42:35 +03:00
b - > ours = true ;
b - > essential = streq ( controller , SYSTEMD_CGROUP_CONTROLLER ) ;
2010-11-17 23:27:53 +03:00
2010-11-18 02:42:35 +03:00
if ( ( r = unit_add_cgroup ( u , b ) ) < 0 )
goto fail ;
2010-03-31 18:29:55 +04:00
return 0 ;
fail :
2010-11-18 02:42:35 +03:00
free ( b - > path ) ;
free ( b - > controller ) ;
free ( b ) ;
2010-03-31 18:29:55 +04:00
return r ;
}
2010-11-18 02:42:35 +03:00
int unit_add_default_cgroups ( Unit * u ) {
2011-08-20 02:20:41 +04:00
CGroupAttribute * a ;
2010-11-18 02:42:35 +03:00
char * * c ;
int r ;
2011-08-20 02:20:41 +04:00
2010-11-18 02:42:35 +03:00
assert ( u ) ;
/* Adds in the default cgroups, if they weren't specified
* otherwise . */
2011-04-13 06:35:34 +04:00
if ( ! u - > meta . manager - > cgroup_hierarchy )
return 0 ;
2010-11-18 02:42:35 +03:00
if ( ( r = unit_add_one_default_cgroup ( u , NULL ) ) < 0 )
return r ;
STRV_FOREACH ( c , u - > meta . manager - > default_controllers )
2011-08-20 02:20:41 +04:00
unit_add_one_default_cgroup ( u , * c ) ;
LIST_FOREACH ( by_unit , a , u - > meta . cgroup_attributes )
unit_add_one_default_cgroup ( u , a - > controller ) ;
2010-11-18 02:42:35 +03:00
return 0 ;
}
2010-03-31 18:29:55 +04:00
CGroupBonding * unit_get_default_cgroup ( Unit * u ) {
assert ( u ) ;
2010-07-10 19:38:50 +04:00
return cgroup_bonding_find_list ( u - > meta . cgroup_bondings , SYSTEMD_CGROUP_CONTROLLER ) ;
2010-03-31 18:29:55 +04:00
}
2011-08-20 02:20:41 +04:00
int unit_add_cgroup_attribute ( Unit * u , const char * controller , const char * name , const char * value , CGroupAttributeMapCallback map_callback ) {
int r ;
char * c = NULL ;
CGroupAttribute * a ;
assert ( u ) ;
assert ( name ) ;
assert ( value ) ;
if ( ! controller ) {
const char * dot ;
dot = strchr ( name , ' . ' ) ;
if ( ! dot )
return - EINVAL ;
c = strndup ( name , dot - name ) ;
if ( ! c )
return - ENOMEM ;
controller = c ;
}
if ( streq ( controller , SYSTEMD_CGROUP_CONTROLLER ) ) {
r = - EINVAL ;
goto finish ;
}
a = new0 ( CGroupAttribute , 1 ) ;
if ( ! a ) {
r = - ENOMEM ;
goto finish ;
}
if ( c ) {
a - > controller = c ;
c = NULL ;
} else
a - > controller = strdup ( controller ) ;
a - > name = strdup ( name ) ;
a - > value = strdup ( value ) ;
if ( ! a - > controller | | ! a - > name | | ! a - > value ) {
free ( a - > controller ) ;
free ( a - > name ) ;
free ( a - > value ) ;
free ( a ) ;
return - ENOMEM ;
}
a - > map_callback = map_callback ;
LIST_PREPEND ( CGroupAttribute , by_unit , u - > meta . cgroup_attributes , a ) ;
r = 0 ;
finish :
free ( c ) ;
return r ;
}
2010-04-10 06:48:33 +04:00
int unit_load_related_unit ( Unit * u , const char * type , Unit * * _found ) {
char * t ;
int r ;
assert ( u ) ;
assert ( type ) ;
assert ( _found ) ;
2010-04-15 05:11:11 +04:00
if ( ! ( t = unit_name_change_suffix ( u - > meta . id , type ) ) )
2010-04-10 06:48:33 +04:00
return - ENOMEM ;
assert ( ! unit_has_name ( u , t ) ) ;
2010-07-08 04:43:18 +04:00
r = manager_load_unit ( u - > meta . manager , t , NULL , NULL , _found ) ;
2010-04-10 06:48:33 +04:00
free ( t ) ;
2010-04-15 05:11:11 +04:00
assert ( r < 0 | | * _found ! = u ) ;
2010-04-10 06:48:33 +04:00
return r ;
}
2010-04-21 05:27:44 +04:00
int unit_get_related_unit ( Unit * u , const char * type , Unit * * _found ) {
Unit * found ;
char * t ;
assert ( u ) ;
assert ( type ) ;
assert ( _found ) ;
if ( ! ( t = unit_name_change_suffix ( u - > meta . id , type ) ) )
return - ENOMEM ;
assert ( ! unit_has_name ( u , t ) ) ;
found = manager_get_unit ( u - > meta . manager , t ) ;
free ( t ) ;
if ( ! found )
return - ENOENT ;
* _found = found ;
return 0 ;
}
2010-04-15 05:11:11 +04:00
static char * specifier_prefix_and_instance ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
return unit_name_to_prefix_and_instance ( u - > meta . id ) ;
}
static char * specifier_prefix ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
return unit_name_to_prefix ( u - > meta . id ) ;
}
static char * specifier_prefix_unescaped ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
char * p , * r ;
assert ( u ) ;
if ( ! ( p = unit_name_to_prefix ( u - > meta . id ) ) )
return NULL ;
r = unit_name_unescape ( p ) ;
free ( p ) ;
return r ;
}
static char * specifier_instance_unescaped ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
if ( u - > meta . instance )
return unit_name_unescape ( u - > meta . instance ) ;
return strdup ( " " ) ;
}
2010-10-20 18:16:45 +04:00
static char * specifier_filename ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
if ( u - > meta . instance )
return unit_name_path_unescape ( u - > meta . instance ) ;
return unit_name_to_path ( u - > meta . instance ) ;
}
2011-07-01 02:41:18 +04:00
static char * specifier_cgroup ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
return default_cgroup_path ( u ) ;
}
static char * specifier_cgroup_root ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
char * p ;
assert ( u ) ;
if ( specifier = = ' r ' )
return strdup ( u - > meta . manager - > cgroup_hierarchy ) ;
if ( parent_of_path ( u - > meta . manager - > cgroup_hierarchy , & p ) < 0 )
return strdup ( " " ) ;
if ( streq ( p , " / " ) ) {
free ( p ) ;
return strdup ( " " ) ;
}
return p ;
}
static char * specifier_runtime ( char specifier , void * data , void * userdata ) {
Unit * u = userdata ;
assert ( u ) ;
if ( u - > meta . manager - > running_as = = MANAGER_USER ) {
const char * e ;
e = getenv ( " XDG_RUNTIME_DIR " ) ;
if ( e )
return strdup ( e ) ;
}
return strdup ( " /run " ) ;
}
2010-04-15 05:11:11 +04:00
char * unit_name_printf ( Unit * u , const char * format ) {
/*
* This will use the passed string as format string and
* replace the following specifiers :
*
* % n : the full id of the unit ( foo @ bar . waldo )
* % N : the id of the unit without the suffix ( foo @ bar )
* % p : the prefix ( foo )
* % i : the instance ( bar )
*/
const Specifier table [ ] = {
{ ' n ' , specifier_string , u - > meta . id } ,
{ ' N ' , specifier_prefix_and_instance , NULL } ,
{ ' p ' , specifier_prefix , NULL } ,
{ ' i ' , specifier_string , u - > meta . instance } ,
{ 0 , NULL , NULL }
} ;
assert ( u ) ;
assert ( format ) ;
return specifier_printf ( format , table , u ) ;
}
char * unit_full_printf ( Unit * u , const char * format ) {
/* This is similar to unit_name_printf() but also supports
2011-07-01 02:41:18 +04:00
* unescaping . Also , adds a couple of additional codes :
*
* % c cgroup path of unit
* % r root cgroup path of this systemd instance ( e . g . " /user/lennart/shared/systemd-4711 " )
* % R parent of root cgroup path ( e . g . " /usr/lennart/shared " )
* % t the runtime directory to place sockets in ( e . g . " /run " or $ XDG_RUNTIME_DIR )
*/
2010-04-15 05:11:11 +04:00
const Specifier table [ ] = {
{ ' n ' , specifier_string , u - > meta . id } ,
{ ' N ' , specifier_prefix_and_instance , NULL } ,
{ ' p ' , specifier_prefix , NULL } ,
{ ' P ' , specifier_prefix_unescaped , NULL } ,
{ ' i ' , specifier_string , u - > meta . instance } ,
{ ' I ' , specifier_instance_unescaped , NULL } ,
2010-10-20 18:16:45 +04:00
{ ' f ' , specifier_filename , NULL } ,
2011-07-01 02:41:18 +04:00
{ ' c ' , specifier_cgroup , NULL } ,
{ ' r ' , specifier_cgroup_root , NULL } ,
{ ' R ' , specifier_cgroup_root , NULL } ,
{ ' t ' , specifier_runtime , NULL } ,
2010-04-15 05:11:11 +04:00
{ 0 , NULL , NULL }
} ;
assert ( u ) ;
assert ( format ) ;
return specifier_printf ( format , table , u ) ;
}
char * * unit_full_printf_strv ( Unit * u , char * * l ) {
size_t n ;
char * * r , * * i , * * j ;
/* Applies unit_full_printf to every entry in l */
assert ( u ) ;
n = strv_length ( l ) ;
if ( ! ( r = new ( char * , n + 1 ) ) )
return NULL ;
for ( i = l , j = r ; * i ; i + + , j + + )
if ( ! ( * j = unit_full_printf ( u , * i ) ) )
goto fail ;
* j = NULL ;
return r ;
fail :
2011-03-31 17:35:40 +04:00
for ( j - - ; j > = r ; j - - )
2010-04-15 05:11:11 +04:00
free ( * j ) ;
free ( r ) ;
return NULL ;
}
2010-04-16 01:16:16 +04:00
int unit_watch_bus_name ( Unit * u , const char * name ) {
assert ( u ) ;
assert ( name ) ;
/* Watch a specific name on the bus. We only support one unit
* watching each name for now . */
return hashmap_put ( u - > meta . manager - > watch_bus , name , u ) ;
}
void unit_unwatch_bus_name ( Unit * u , const char * name ) {
assert ( u ) ;
assert ( name ) ;
hashmap_remove_value ( u - > meta . manager - > watch_bus , name , u ) ;
}
2010-04-21 05:27:44 +04:00
bool unit_can_serialize ( Unit * u ) {
assert ( u ) ;
return UNIT_VTABLE ( u ) - > serialize & & UNIT_VTABLE ( u ) - > deserialize_item ;
}
int unit_serialize ( Unit * u , FILE * f , FDSet * fds ) {
int r ;
assert ( u ) ;
assert ( f ) ;
assert ( fds ) ;
if ( ! unit_can_serialize ( u ) )
return 0 ;
if ( ( r = UNIT_VTABLE ( u ) - > serialize ( u , f , fds ) ) < 0 )
return r ;
2010-06-03 16:26:50 +04:00
if ( u - > meta . job )
unit_serialize_item ( u , f , " job " , job_type_to_string ( u - > meta . job - > type ) ) ;
2010-10-27 02:01:12 +04:00
dual_timestamp_serialize ( f , " inactive-exit-timestamp " , & u - > meta . inactive_exit_timestamp ) ;
dual_timestamp_serialize ( f , " active-enter-timestamp " , & u - > meta . active_enter_timestamp ) ;
dual_timestamp_serialize ( f , " active-exit-timestamp " , & u - > meta . active_exit_timestamp ) ;
dual_timestamp_serialize ( f , " inactive-enter-timestamp " , & u - > meta . inactive_enter_timestamp ) ;
2011-03-17 06:36:19 +03:00
dual_timestamp_serialize ( f , " condition-timestamp " , & u - > meta . condition_timestamp ) ;
if ( dual_timestamp_is_set ( & u - > meta . condition_timestamp ) )
unit_serialize_item ( u , f , " condition-result " , yes_no ( u - > meta . condition_result ) ) ;
2010-10-27 02:01:12 +04:00
2010-04-21 05:27:44 +04:00
/* End marker */
fputc ( ' \n ' , f ) ;
return 0 ;
}
void unit_serialize_item_format ( Unit * u , FILE * f , const char * key , const char * format , . . . ) {
va_list ap ;
assert ( u ) ;
assert ( f ) ;
assert ( key ) ;
assert ( format ) ;
fputs ( key , f ) ;
fputc ( ' = ' , f ) ;
va_start ( ap , format ) ;
vfprintf ( f , format , ap ) ;
va_end ( ap ) ;
fputc ( ' \n ' , f ) ;
}
void unit_serialize_item ( Unit * u , FILE * f , const char * key , const char * value ) {
assert ( u ) ;
assert ( f ) ;
assert ( key ) ;
assert ( value ) ;
fprintf ( f , " %s=%s \n " , key , value ) ;
}
int unit_deserialize ( Unit * u , FILE * f , FDSet * fds ) {
int r ;
assert ( u ) ;
assert ( f ) ;
assert ( fds ) ;
if ( ! unit_can_serialize ( u ) )
return 0 ;
for ( ; ; ) {
2011-04-07 20:48:50 +04:00
char line [ LINE_MAX ] , * l , * v ;
2010-04-21 05:27:44 +04:00
size_t k ;
if ( ! fgets ( line , sizeof ( line ) , f ) ) {
if ( feof ( f ) )
return 0 ;
return - errno ;
}
2010-08-11 22:19:27 +04:00
char_array_0 ( line ) ;
2010-04-21 05:27:44 +04:00
l = strstrip ( line ) ;
/* End marker */
if ( l [ 0 ] = = 0 )
return 0 ;
k = strcspn ( l , " = " ) ;
if ( l [ k ] = = ' = ' ) {
l [ k ] = 0 ;
v = l + k + 1 ;
} else
v = l + k ;
2010-06-03 16:26:50 +04:00
if ( streq ( l , " job " ) ) {
JobType type ;
if ( ( type = job_type_from_string ( v ) ) < 0 )
log_debug ( " Failed to parse job type value %s " , v ) ;
else
u - > meta . deserialized_job = type ;
continue ;
2010-10-28 04:19:21 +04:00
} else if ( streq ( l , " inactive-exit-timestamp " ) ) {
2010-10-28 05:16:03 +04:00
dual_timestamp_deserialize ( v , & u - > meta . inactive_exit_timestamp ) ;
2010-10-28 04:19:21 +04:00
continue ;
} else if ( streq ( l , " active-enter-timestamp " ) ) {
2010-10-28 05:16:03 +04:00
dual_timestamp_deserialize ( v , & u - > meta . active_enter_timestamp ) ;
2010-10-28 04:19:21 +04:00
continue ;
} else if ( streq ( l , " active-exit-timestamp " ) ) {
2010-10-28 05:16:03 +04:00
dual_timestamp_deserialize ( v , & u - > meta . active_exit_timestamp ) ;
2010-10-28 04:19:21 +04:00
continue ;
} else if ( streq ( l , " inactive-enter-timestamp " ) ) {
2010-10-28 05:16:03 +04:00
dual_timestamp_deserialize ( v , & u - > meta . inactive_enter_timestamp ) ;
2010-10-28 04:19:21 +04:00
continue ;
2011-03-17 06:36:19 +03:00
} else if ( streq ( l , " condition-timestamp " ) ) {
dual_timestamp_deserialize ( v , & u - > meta . condition_timestamp ) ;
continue ;
} else if ( streq ( l , " condition-result " ) ) {
int b ;
if ( ( b = parse_boolean ( v ) ) < 0 )
log_debug ( " Failed to parse condition result value %s " , v ) ;
else
u - > meta . condition_result = b ;
2011-03-30 01:32:31 +04:00
continue ;
2010-10-28 04:19:21 +04:00
}
2010-06-03 16:26:50 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = UNIT_VTABLE ( u ) - > deserialize_item ( u , l , v , fds ) ) < 0 )
return r ;
}
}
2010-05-13 05:07:16 +04:00
int unit_add_node_link ( Unit * u , const char * what , bool wants ) {
Unit * device ;
char * e ;
int r ;
assert ( u ) ;
if ( ! what )
return 0 ;
/* Adds in links to the device node that this unit is based on */
2010-05-16 20:13:58 +04:00
if ( ! is_device_path ( what ) )
2010-05-13 05:07:16 +04:00
return 0 ;
if ( ! ( e = unit_name_build_escape ( what + 1 , NULL , " .device " ) ) )
return - ENOMEM ;
2010-07-08 04:43:18 +04:00
r = manager_load_unit ( u - > meta . manager , e , NULL , NULL , & device ) ;
2010-05-13 05:07:16 +04:00
free ( e ) ;
if ( r < 0 )
return r ;
2010-10-29 01:18:47 +04:00
if ( ( r = unit_add_two_dependencies ( u , UNIT_AFTER , UNIT_BIND_TO , device , true ) ) < 0 )
2010-05-13 05:07:16 +04:00
return r ;
if ( wants )
if ( ( r = unit_add_dependency ( device , UNIT_WANTS , u , false ) ) < 0 )
return r ;
return 0 ;
}
2010-04-21 05:27:44 +04:00
2010-06-03 16:26:50 +04:00
int unit_coldplug ( Unit * u ) {
int r ;
assert ( u ) ;
if ( UNIT_VTABLE ( u ) - > coldplug )
if ( ( r = UNIT_VTABLE ( u ) - > coldplug ( u ) ) < 0 )
return r ;
if ( u - > meta . deserialized_job > = 0 ) {
2011-04-06 21:09:33 +04:00
if ( ( r = manager_add_job ( u - > meta . manager , u - > meta . deserialized_job , u , JOB_IGNORE_REQUIREMENTS , false , NULL , NULL ) ) < 0 )
2010-06-03 16:26:50 +04:00
return r ;
u - > meta . deserialized_job = _JOB_TYPE_INVALID ;
}
return 0 ;
}
2010-07-07 02:00:59 +04:00
void unit_status_printf ( Unit * u , const char * format , . . . ) {
va_list ap ;
assert ( u ) ;
assert ( format ) ;
if ( ! UNIT_VTABLE ( u ) - > show_status )
return ;
2011-09-01 23:05:06 +04:00
if ( ! manager_get_show_status ( u - > meta . manager ) )
2010-07-07 02:00:59 +04:00
return ;
if ( ! manager_is_booting_or_shutting_down ( u - > meta . manager ) )
return ;
va_start ( ap , format ) ;
status_vprintf ( format , ap ) ;
va_end ( ap ) ;
}
2010-07-17 02:57:51 +04:00
bool unit_need_daemon_reload ( Unit * u ) {
assert ( u ) ;
2011-06-15 17:34:19 +04:00
if ( u - > meta . fragment_path ) {
struct stat st ;
2010-07-17 02:57:51 +04:00
2011-06-15 17:34:19 +04:00
zero ( st ) ;
if ( stat ( u - > meta . fragment_path , & st ) < 0 )
/* What, cannot access this anymore? */
return true ;
2010-07-17 02:57:51 +04:00
2011-06-15 17:34:19 +04:00
if ( u - > meta . fragment_mtime > 0 & &
timespec_load ( & st . st_mtim ) ! = u - > meta . fragment_mtime )
return true ;
}
if ( UNIT_VTABLE ( u ) - > need_daemon_reload )
return UNIT_VTABLE ( u ) - > need_daemon_reload ( u ) ;
return false ;
2010-07-17 02:57:51 +04:00
}
2010-08-31 02:23:34 +04:00
void unit_reset_failed ( Unit * u ) {
2010-07-18 06:58:01 +04:00
assert ( u ) ;
2010-08-31 02:23:34 +04:00
if ( UNIT_VTABLE ( u ) - > reset_failed )
UNIT_VTABLE ( u ) - > reset_failed ( u ) ;
2010-07-18 06:58:01 +04:00
}
2010-07-21 07:00:29 +04:00
Unit * unit_following ( Unit * u ) {
assert ( u ) ;
if ( UNIT_VTABLE ( u ) - > following )
return UNIT_VTABLE ( u ) - > following ( u ) ;
return NULL ;
}
2010-09-01 05:35:04 +04:00
bool unit_pending_inactive ( Unit * u ) {
assert ( u ) ;
/* Returns true if the unit is inactive or going down */
if ( UNIT_IS_INACTIVE_OR_DEACTIVATING ( unit_active_state ( u ) ) )
return true ;
if ( u - > meta . job & & u - > meta . job - > type = = JOB_STOP )
return true ;
return false ;
}
2010-10-05 21:49:15 +04:00
bool unit_pending_active ( Unit * u ) {
assert ( u ) ;
/* Returns true if the unit is inactive or going down */
if ( UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( u ) ) )
return true ;
if ( u - > meta . job & &
( u - > meta . job - > type = = JOB_START | |
u - > meta . job - > type = = JOB_RELOAD_OR_START | |
u - > meta . job - > type = = JOB_RESTART ) )
return true ;
return false ;
}
2010-10-06 04:33:40 +04:00
UnitType unit_name_to_type ( const char * n ) {
UnitType t ;
assert ( n ) ;
for ( t = 0 ; t < _UNIT_TYPE_MAX ; t + + )
if ( endswith ( n , unit_vtable [ t ] - > suffix ) )
return t ;
return _UNIT_TYPE_INVALID ;
}
2010-10-08 05:09:25 +04:00
bool unit_name_is_valid ( const char * n , bool template_ok ) {
2010-10-06 04:33:40 +04:00
UnitType t ;
t = unit_name_to_type ( n ) ;
if ( t < 0 | | t > = _UNIT_TYPE_MAX )
return false ;
2010-10-08 05:09:25 +04:00
return unit_name_is_valid_no_type ( n , template_ok ) ;
2010-10-06 04:33:40 +04:00
}
2010-10-22 18:11:50 +04:00
int unit_kill ( Unit * u , KillWho w , KillMode m , int signo , DBusError * error ) {
assert ( u ) ;
assert ( w > = 0 & & w < _KILL_WHO_MAX ) ;
assert ( m > = 0 & & m < _KILL_MODE_MAX ) ;
assert ( signo > 0 ) ;
assert ( signo < _NSIG ) ;
if ( m = = KILL_NONE )
return 0 ;
if ( ! UNIT_VTABLE ( u ) - > kill )
return - ENOTSUP ;
return UNIT_VTABLE ( u ) - > kill ( u , w , m , signo , error ) ;
}
2010-11-15 01:47:53 +03:00
int unit_following_set ( Unit * u , Set * * s ) {
assert ( u ) ;
assert ( s ) ;
if ( UNIT_VTABLE ( u ) - > following_set )
return UNIT_VTABLE ( u ) - > following_set ( u , s ) ;
* s = NULL ;
return 0 ;
}
2011-07-31 20:28:02 +04:00
UnitFileState unit_get_unit_file_state ( Unit * u ) {
assert ( u ) ;
if ( u - > meta . unit_file_state < 0 & & u - > meta . fragment_path )
u - > meta . unit_file_state = unit_file_get_state (
u - > meta . manager - > running_as = = MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER ,
NULL , file_name_from_path ( u - > meta . fragment_path ) ) ;
return u - > meta . unit_file_state ;
}
2010-01-30 03:55:42 +03:00
static const char * const unit_load_state_table [ _UNIT_LOAD_STATE_MAX ] = {
[ UNIT_STUB ] = " stub " ,
[ UNIT_LOADED ] = " loaded " ,
2010-08-31 02:23:34 +04:00
[ UNIT_ERROR ] = " error " ,
2010-10-08 04:31:36 +04:00
[ UNIT_MERGED ] = " merged " ,
2010-10-08 20:21:52 +04:00
[ UNIT_MASKED ] = " masked "
2010-01-30 03:55:42 +03:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( unit_load_state , UnitLoadState ) ;
static const char * const unit_active_state_table [ _UNIT_ACTIVE_STATE_MAX ] = {
[ UNIT_ACTIVE ] = " active " ,
2010-07-01 05:34:15 +04:00
[ UNIT_RELOADING ] = " reloading " ,
2010-01-30 03:55:42 +03:00
[ UNIT_INACTIVE ] = " inactive " ,
2010-08-31 02:23:34 +04:00
[ UNIT_FAILED ] = " failed " ,
2010-01-30 03:55:42 +03:00
[ UNIT_ACTIVATING ] = " activating " ,
[ UNIT_DEACTIVATING ] = " deactivating "
} ;
DEFINE_STRING_TABLE_LOOKUP ( unit_active_state , UnitActiveState ) ;
static const char * const unit_dependency_table [ _UNIT_DEPENDENCY_MAX ] = {
[ UNIT_REQUIRES ] = " Requires " ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUIRES_OVERRIDABLE ] = " RequiresOverridable " ,
2010-01-30 03:55:42 +03:00
[ UNIT_WANTS ] = " Wants " ,
[ UNIT_REQUISITE ] = " Requisite " ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUISITE_OVERRIDABLE ] = " RequisiteOverridable " ,
2010-01-30 03:55:42 +03:00
[ UNIT_REQUIRED_BY ] = " RequiredBy " ,
2010-04-15 05:11:11 +04:00
[ UNIT_REQUIRED_BY_OVERRIDABLE ] = " RequiredByOverridable " ,
2010-10-29 01:18:47 +04:00
[ UNIT_BIND_TO ] = " BindTo " ,
2010-01-30 03:55:42 +03:00
[ UNIT_WANTED_BY ] = " WantedBy " ,
[ UNIT_CONFLICTS ] = " Conflicts " ,
2010-08-10 00:32:30 +04:00
[ UNIT_CONFLICTED_BY ] = " ConflictedBy " ,
2010-10-29 01:18:47 +04:00
[ UNIT_BOUND_BY ] = " BoundBy " ,
2010-01-30 03:55:42 +03:00
[ UNIT_BEFORE ] = " Before " ,
[ UNIT_AFTER ] = " After " ,
2010-04-21 08:01:13 +04:00
[ UNIT_REFERENCES ] = " References " ,
2010-07-17 02:58:47 +04:00
[ UNIT_REFERENCED_BY ] = " ReferencedBy " ,
[ UNIT_ON_FAILURE ] = " OnFailure "
2010-01-30 03:55:42 +03:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( unit_dependency , UnitDependency ) ;