2013-06-17 23:33:26 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2013 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
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
( 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <errno.h>
# include <signal.h>
# include <unistd.h>
# include "unit.h"
# include "slice.h"
# include "load-fragment.h"
# include "log.h"
# include "dbus-slice.h"
# include "special.h"
# include "unit-name.h"
static const UnitActiveState state_translation_table [ _SLICE_STATE_MAX ] = {
[ SLICE_DEAD ] = UNIT_INACTIVE ,
[ SLICE_ACTIVE ] = UNIT_ACTIVE
} ;
static void slice_set_state ( Slice * t , SliceState state ) {
SliceState old_state ;
assert ( t ) ;
old_state = t - > state ;
t - > state = state ;
if ( state ! = old_state )
log_debug ( " %s changed %s -> %s " ,
UNIT ( t ) - > id ,
slice_state_to_string ( old_state ) ,
slice_state_to_string ( state ) ) ;
unit_notify ( UNIT ( t ) , state_translation_table [ old_state ] , state_translation_table [ state ] , true ) ;
}
2013-06-27 06:14:27 +04:00
static int slice_add_parent_slice ( Slice * s ) {
2013-06-17 23:33:26 +04:00
char * a , * dash ;
Unit * parent ;
2013-06-27 06:14:27 +04:00
int r ;
2013-06-17 23:33:26 +04:00
assert ( s ) ;
2013-06-27 06:14:27 +04:00
if ( UNIT_ISSET ( UNIT ( s ) - > slice ) )
2013-06-17 23:33:26 +04:00
return 0 ;
2013-06-27 06:14:27 +04:00
if ( unit_has_name ( UNIT ( s ) , SPECIAL_ROOT_SLICE ) )
2013-06-17 23:33:26 +04:00
return 0 ;
2013-06-27 06:14:27 +04:00
a = strdupa ( UNIT ( s ) - > id ) ;
dash = strrchr ( a , ' - ' ) ;
if ( dash )
strcpy ( dash , " .slice " ) ;
else
a = ( char * ) SPECIAL_ROOT_SLICE ;
2013-06-17 23:33:26 +04:00
r = manager_load_unit ( UNIT ( s ) - > manager , a , NULL , NULL , & parent ) ;
if ( r < 0 )
return r ;
unit_ref_set ( & UNIT ( s ) - > slice , parent ) ;
return 0 ;
}
static int slice_add_default_dependencies ( Slice * s ) {
int r ;
assert ( s ) ;
/* Make sure slices are unloaded on shutdown */
2013-07-01 02:03:57 +04:00
r = unit_add_two_dependencies_by_name (
UNIT ( s ) ,
UNIT_BEFORE , UNIT_CONFLICTS ,
SPECIAL_SHUTDOWN_TARGET , NULL , true ) ;
2013-06-17 23:33:26 +04:00
if ( r < 0 )
return r ;
return 0 ;
}
static int slice_verify ( Slice * s ) {
assert ( s ) ;
if ( UNIT ( s ) - > load_state ! = UNIT_LOADED )
return 0 ;
if ( UNIT_DEREF ( UNIT ( s ) - > slice ) ) {
char * a , * dash ;
a = strdupa ( UNIT ( s ) - > id ) ;
dash = strrchr ( a , ' - ' ) ;
2013-06-27 06:14:27 +04:00
if ( dash )
2013-06-17 23:33:26 +04:00
strcpy ( dash , " .slice " ) ;
2013-06-27 06:14:27 +04:00
else
a = ( char * ) SPECIAL_ROOT_SLICE ;
2013-06-17 23:33:26 +04:00
2013-06-27 06:14:27 +04:00
if ( ! unit_has_name ( UNIT_DEREF ( UNIT ( s ) - > slice ) , a ) ) {
log_error_unit ( UNIT ( s ) - > id ,
" %s located outside its parent slice. Refusing. " , UNIT ( s ) - > id ) ;
return - EINVAL ;
2013-06-17 23:33:26 +04:00
}
}
return 0 ;
}
static int slice_load ( Unit * u ) {
Slice * s = SLICE ( u ) ;
int r ;
assert ( s ) ;
2013-06-27 06:14:27 +04:00
r = unit_load_fragment_and_dropin_optional ( u ) ;
2013-06-17 23:33:26 +04:00
if ( r < 0 )
return r ;
/* This is a new unit? Then let's add in some extras */
if ( u - > load_state = = UNIT_LOADED ) {
2014-03-19 23:40:05 +04:00
r = unit_patch_contexts ( u ) ;
if ( r < 0 )
return r ;
2013-06-27 06:14:27 +04:00
r = slice_add_parent_slice ( s ) ;
2013-06-17 23:33:26 +04:00
if ( r < 0 )
return r ;
if ( u - > default_dependencies ) {
r = slice_add_default_dependencies ( s ) ;
if ( r < 0 )
return r ;
}
}
return slice_verify ( s ) ;
}
static int slice_coldplug ( Unit * u ) {
Slice * t = SLICE ( u ) ;
assert ( t ) ;
assert ( t - > state = = SLICE_DEAD ) ;
if ( t - > deserialized_state ! = t - > state )
slice_set_state ( t , t - > deserialized_state ) ;
return 0 ;
}
static void slice_dump ( Unit * u , FILE * f , const char * prefix ) {
Slice * t = SLICE ( u ) ;
assert ( t ) ;
assert ( f ) ;
fprintf ( f ,
" %sSlice State: %s \n " ,
prefix , slice_state_to_string ( t - > state ) ) ;
2013-06-27 06:14:27 +04:00
cgroup_context_dump ( & t - > cgroup_context , f , prefix ) ;
2013-06-17 23:33:26 +04:00
}
static int slice_start ( Unit * u ) {
Slice * t = SLICE ( u ) ;
assert ( t ) ;
assert ( t - > state = = SLICE_DEAD ) ;
2013-06-27 06:14:27 +04:00
unit_realize_cgroup ( u ) ;
2013-06-17 23:33:26 +04:00
slice_set_state ( t , SLICE_ACTIVE ) ;
return 0 ;
}
static int slice_stop ( Unit * u ) {
Slice * t = SLICE ( u ) ;
assert ( t ) ;
assert ( t - > state = = SLICE_ACTIVE ) ;
2013-06-27 06:14:27 +04:00
/* We do not need to destroy the cgroup explicitly,
* unit_notify ( ) will do that for us anyway . */
2013-06-17 23:33:26 +04:00
slice_set_state ( t , SLICE_DEAD ) ;
return 0 ;
}
2013-11-20 00:12:59 +04:00
static int slice_kill ( Unit * u , KillWho who , int signo , sd_bus_error * error ) {
2013-06-17 23:33:26 +04:00
return unit_kill_common ( u , who , signo , - 1 , - 1 , error ) ;
}
static int slice_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Slice * s = SLICE ( u ) ;
assert ( s ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , slice_state_to_string ( s - > state ) ) ;
return 0 ;
}
static int slice_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Slice * s = SLICE ( u ) ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
SliceState state ;
state = slice_state_from_string ( value ) ;
if ( state < 0 )
log_debug ( " Failed to parse state value %s " , value ) ;
else
s - > deserialized_state = state ;
} else
log_debug ( " Unknown serialization key '%s' " , key ) ;
return 0 ;
}
_pure_ static UnitActiveState slice_active_state ( Unit * u ) {
assert ( u ) ;
return state_translation_table [ SLICE ( u ) - > state ] ;
}
_pure_ static const char * slice_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
return slice_state_to_string ( SLICE ( u ) - > state ) ;
}
static const char * const slice_state_table [ _SLICE_STATE_MAX ] = {
[ SLICE_DEAD ] = " dead " ,
[ SLICE_ACTIVE ] = " active "
} ;
DEFINE_STRING_TABLE_LOOKUP ( slice_state , SliceState ) ;
const UnitVTable slice_vtable = {
. object_size = sizeof ( Slice ) ,
2013-11-20 00:12:59 +04:00
. cgroup_context_offset = offsetof ( Slice , cgroup_context ) ,
2013-06-17 23:33:26 +04:00
. sections =
" Unit \0 "
" Slice \0 "
" Install \0 " ,
2013-06-27 06:14:27 +04:00
. private_section = " Slice " ,
2013-06-17 23:33:26 +04:00
. no_alias = true ,
. no_instances = true ,
. load = slice_load ,
2013-06-27 06:14:27 +04:00
2013-06-17 23:33:26 +04:00
. coldplug = slice_coldplug ,
. dump = slice_dump ,
. start = slice_start ,
. stop = slice_stop ,
. kill = slice_kill ,
. serialize = slice_serialize ,
. deserialize_item = slice_deserialize_item ,
. active_state = slice_active_state ,
. sub_state_to_string = slice_sub_state_to_string ,
. bus_interface = " org.freedesktop.systemd1.Slice " ,
2013-11-20 00:12:59 +04:00
. bus_vtable = bus_slice_vtable ,
2013-06-27 23:14:56 +04:00
. bus_set_property = bus_slice_set_property ,
. bus_commit_properties = bus_slice_commit_properties ,
2013-06-17 23:33:26 +04:00
. status_message_formats = {
. finished_start_job = {
2013-06-27 06:14:27 +04:00
[ JOB_DONE ] = " Created slice %s. " ,
2013-06-17 23:33:26 +04:00
[ JOB_DEPENDENCY ] = " Dependency failed for %s. " ,
} ,
. finished_stop_job = {
2013-06-27 06:14:27 +04:00
[ JOB_DONE ] = " Removed slice %s. " ,
2013-06-17 23:33:26 +04:00
} ,
} ,
} ;