2010-01-23 03:52:57 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-04-18 05:07:42 +04:00
# include <errno.h>
2010-01-26 23:39:06 +03:00
# include "unit.h"
2010-01-23 03:52:57 +03:00
# include "snapshot.h"
2010-04-18 05:07:42 +04:00
# include "unit-name.h"
# include "dbus-snapshot.h"
2010-07-08 04:43:18 +04:00
# include "bus-errors.h"
2010-04-18 05:07:42 +04:00
static const UnitActiveState state_translation_table [ _SNAPSHOT_STATE_MAX ] = {
[ SNAPSHOT_DEAD ] = UNIT_INACTIVE ,
[ SNAPSHOT_ACTIVE ] = UNIT_ACTIVE
} ;
2010-04-21 05:27:44 +04:00
static void snapshot_set_state ( Snapshot * s , SnapshotState state ) {
SnapshotState old_state ;
assert ( s ) ;
2010-04-18 05:07:42 +04:00
2010-04-21 05:27:44 +04:00
old_state = s - > state ;
s - > state = state ;
2010-04-18 05:07:42 +04:00
2010-04-21 05:27:44 +04:00
if ( state ! = old_state )
2010-04-23 22:25:55 +04:00
log_debug ( " %s changed %s -> %s " ,
2010-06-19 18:55:49 +04:00
s - > meta . id ,
2010-04-21 05:27:44 +04:00
snapshot_state_to_string ( old_state ) ,
snapshot_state_to_string ( state ) ) ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
unit_notify ( UNIT ( s ) , state_translation_table [ old_state ] , state_translation_table [ state ] ) ;
}
2010-04-18 05:07:42 +04:00
2010-07-01 05:39:55 +04:00
static int snapshot_load ( Unit * u ) {
Snapshot * s = SNAPSHOT ( u ) ;
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
/* Make sure that only snapshots created via snapshot_create()
* can be loaded */
2010-07-13 21:01:20 +04:00
if ( ! s - > by_snapshot_create & & s - > meta . manager - > n_deserializing < = 0 )
2010-07-01 05:39:55 +04:00
return - ENOENT ;
u - > meta . load_state = UNIT_LOADED ;
return 0 ;
}
2010-04-21 05:27:44 +04:00
static int snapshot_coldplug ( Unit * u ) {
Snapshot * s = SNAPSHOT ( u ) ;
2010-04-18 05:07:42 +04:00
2010-04-21 05:27:44 +04:00
assert ( s ) ;
assert ( s - > state = = SNAPSHOT_DEAD ) ;
2010-04-18 05:07:42 +04:00
2010-04-21 05:27:44 +04:00
if ( s - > deserialized_state ! = s - > state )
snapshot_set_state ( s , s - > deserialized_state ) ;
2010-04-18 05:07:42 +04:00
return 0 ;
}
static void snapshot_dump ( Unit * u , FILE * f , const char * prefix ) {
2010-01-26 23:39:06 +03:00
Snapshot * s = SNAPSHOT ( u ) ;
2010-01-23 03:52:57 +03:00
assert ( s ) ;
2010-04-18 05:07:42 +04:00
assert ( f ) ;
2010-01-23 03:52:57 +03:00
2010-04-18 05:07:42 +04:00
fprintf ( f ,
" %sSnapshot State: %s \n "
" %sClean Up: %s \n " ,
2010-04-21 05:27:44 +04:00
prefix , snapshot_state_to_string ( s - > state ) ,
2010-04-18 05:07:42 +04:00
prefix , yes_no ( s - > cleanup ) ) ;
}
static int snapshot_start ( Unit * u ) {
Snapshot * s = SNAPSHOT ( u ) ;
assert ( s ) ;
assert ( s - > state = = SNAPSHOT_DEAD ) ;
snapshot_set_state ( s , SNAPSHOT_ACTIVE ) ;
if ( s - > cleanup )
unit_add_to_cleanup_queue ( u ) ;
return 0 ;
}
static int snapshot_stop ( Unit * u ) {
Snapshot * s = SNAPSHOT ( u ) ;
assert ( s ) ;
assert ( s - > state = = SNAPSHOT_ACTIVE ) ;
snapshot_set_state ( s , SNAPSHOT_DEAD ) ;
return 0 ;
2010-01-23 03:52:57 +03:00
}
2010-04-21 05:27:44 +04:00
static int snapshot_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Snapshot * s = SNAPSHOT ( u ) ;
Unit * other ;
Iterator i ;
assert ( s ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , snapshot_state_to_string ( s - > state ) ) ;
unit_serialize_item ( u , f , " cleanup " , yes_no ( s - > cleanup ) ) ;
2010-07-03 21:51:24 +04:00
SET_FOREACH ( other , u - > meta . dependencies [ UNIT_WANTS ] , i )
unit_serialize_item ( u , f , " wants " , other - > meta . id ) ;
2010-04-21 05:27:44 +04:00
return 0 ;
}
static int snapshot_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Snapshot * s = SNAPSHOT ( u ) ;
int r ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
SnapshotState state ;
if ( ( state = snapshot_state_from_string ( value ) ) < 0 )
log_debug ( " Failed to parse state value %s " , value ) ;
else
s - > deserialized_state = state ;
} else if ( streq ( key , " cleanup " ) ) {
if ( ( r = parse_boolean ( value ) ) < 0 )
log_debug ( " Failed to parse cleanup value %s " , value ) ;
else
s - > cleanup = r ;
2010-07-03 21:51:24 +04:00
} else if ( streq ( key , " wants " ) ) {
2010-04-21 05:27:44 +04:00
2010-07-03 21:51:24 +04:00
if ( ( r = unit_add_two_dependencies_by_name ( u , UNIT_AFTER , UNIT_WANTS , value , NULL , true ) ) < 0 )
2010-04-21 05:27:44 +04:00
return r ;
} else
log_debug ( " Unknown serialization key '%s' " , key ) ;
return 0 ;
}
2010-01-26 23:39:06 +03:00
static UnitActiveState snapshot_active_state ( Unit * u ) {
2010-04-18 05:07:42 +04:00
assert ( u ) ;
return state_translation_table [ SNAPSHOT ( u ) - > state ] ;
}
static const char * snapshot_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
2010-04-21 05:27:44 +04:00
return snapshot_state_to_string ( SNAPSHOT ( u ) - > state ) ;
2010-04-18 05:07:42 +04:00
}
2010-07-08 04:43:18 +04:00
int snapshot_create ( Manager * m , const char * name , bool cleanup , DBusError * e , Snapshot * * _s ) {
2010-04-21 05:27:44 +04:00
Iterator i ;
Unit * other , * u = NULL ;
2010-04-18 05:07:42 +04:00
char * n = NULL ;
int r ;
2010-04-21 05:27:44 +04:00
const char * k ;
2010-04-18 05:07:42 +04:00
assert ( m ) ;
assert ( _s ) ;
if ( name ) {
2010-07-08 04:43:18 +04:00
if ( ! unit_name_is_valid ( name ) ) {
dbus_set_error ( e , BUS_ERROR_INVALID_NAME , " Unit name %s is not valid. " , name ) ;
2010-04-18 05:07:42 +04:00
return - EINVAL ;
2010-07-08 04:43:18 +04:00
}
2010-04-18 05:07:42 +04:00
2010-07-08 04:43:18 +04:00
if ( unit_name_to_type ( name ) ! = UNIT_SNAPSHOT ) {
dbus_set_error ( e , BUS_ERROR_UNIT_TYPE_MISMATCH , " Unit name %s lacks snapshot suffix. " , name ) ;
2010-04-18 05:07:42 +04:00
return - EINVAL ;
2010-07-08 04:43:18 +04:00
}
2010-04-18 05:07:42 +04:00
2010-07-08 04:43:18 +04:00
if ( manager_get_unit ( m , name ) ) {
dbus_set_error ( e , BUS_ERROR_UNIT_EXISTS , " Snapshot %s exists already. " , name ) ;
2010-04-18 05:07:42 +04:00
return - EEXIST ;
2010-07-08 04:43:18 +04:00
}
2010-04-18 05:07:42 +04:00
} else {
for ( ; ; ) {
if ( asprintf ( & n , " snapshot-%u.snapshot " , + + m - > n_snapshots ) < 0 )
return - ENOMEM ;
if ( ! manager_get_unit ( m , n ) )
break ;
free ( n ) ;
}
name = n ;
}
2010-07-08 04:43:18 +04:00
r = manager_load_unit_prepare ( m , name , NULL , e , & u ) ;
2010-04-18 05:07:42 +04:00
free ( n ) ;
if ( r < 0 )
2010-04-21 05:27:44 +04:00
goto fail ;
2010-07-01 05:39:55 +04:00
SNAPSHOT ( u ) - > by_snapshot_create = true ;
manager_dispatch_load_queue ( m ) ;
assert ( u - > meta . load_state = = UNIT_LOADED ) ;
2010-04-21 05:27:44 +04:00
HASHMAP_FOREACH_KEY ( other , k , m - > units , i ) {
if ( UNIT_VTABLE ( other ) - > no_snapshots )
continue ;
if ( k ! = other - > meta . id )
continue ;
2010-04-21 08:01:13 +04:00
if ( UNIT_VTABLE ( other ) - > check_snapshot )
if ( ! UNIT_VTABLE ( other ) - > check_snapshot ( other ) )
continue ;
2010-04-21 05:27:44 +04:00
if ( ! UNIT_IS_ACTIVE_OR_ACTIVATING ( unit_active_state ( other ) ) )
continue ;
2010-07-03 21:51:24 +04:00
if ( ( r = unit_add_two_dependencies ( u , UNIT_AFTER , UNIT_WANTS , other , true ) ) < 0 )
2010-04-21 05:27:44 +04:00
goto fail ;
}
2010-04-18 05:07:42 +04:00
SNAPSHOT ( u ) - > cleanup = cleanup ;
* _s = SNAPSHOT ( u ) ;
return 0 ;
2010-04-21 05:27:44 +04:00
fail :
if ( u )
unit_add_to_cleanup_queue ( u ) ;
return r ;
2010-04-18 05:07:42 +04:00
}
void snapshot_remove ( Snapshot * s ) {
assert ( s ) ;
unit_add_to_cleanup_queue ( UNIT ( s ) ) ;
2010-01-26 06:18:44 +03:00
}
2010-04-21 05:27:44 +04:00
static const char * const snapshot_state_table [ _SNAPSHOT_STATE_MAX ] = {
[ SNAPSHOT_DEAD ] = " dead " ,
[ SNAPSHOT_ACTIVE ] = " active "
} ;
DEFINE_STRING_TABLE_LOOKUP ( snapshot_state , SnapshotState ) ;
2010-01-26 23:39:06 +03:00
const UnitVTable snapshot_vtable = {
2010-01-23 03:52:57 +03:00
. suffix = " .snapshot " ,
2010-04-18 05:07:42 +04:00
. no_alias = true ,
. no_instances = true ,
. no_snapshots = true ,
2010-04-21 08:01:13 +04:00
. no_gc = true ,
2010-04-18 05:07:42 +04:00
2010-07-01 05:39:55 +04:00
. load = snapshot_load ,
2010-04-21 05:27:44 +04:00
. coldplug = snapshot_coldplug ,
2010-04-18 05:07:42 +04:00
. dump = snapshot_dump ,
. start = snapshot_start ,
. stop = snapshot_stop ,
2010-04-21 05:27:44 +04:00
. serialize = snapshot_serialize ,
. deserialize_item = snapshot_deserialize_item ,
2010-04-18 05:07:42 +04:00
. active_state = snapshot_active_state ,
. sub_state_to_string = snapshot_sub_state_to_string ,
2010-01-23 03:52:57 +03:00
2010-04-18 05:07:42 +04:00
. bus_message_handler = bus_snapshot_message_handler
2010-01-23 03:52:57 +03:00
} ;