2010-05-09 20:44:11 +04:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
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/>.
* * */
# include <errno.h>
# include <limits.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/epoll.h>
# include <sys/stat.h>
# include <sys/swap.h>
# include "unit.h"
# include "swap.h"
# include "load-fragment.h"
# include "load-dropin.h"
# include "unit-name.h"
# include "dbus-swap.h"
static const UnitActiveState state_translation_table [ _SWAP_STATE_MAX ] = {
[ SWAP_DEAD ] = UNIT_INACTIVE ,
[ SWAP_ACTIVE ] = UNIT_ACTIVE ,
[ SWAP_MAINTAINANCE ] = UNIT_INACTIVE
} ;
2010-05-14 04:29:45 +04:00
static void swap_init ( Unit * u ) {
2010-05-10 01:41:03 +04:00
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2010-05-14 04:29:45 +04:00
assert ( s - > meta . load_state = = UNIT_STUB ) ;
2010-05-10 01:41:03 +04:00
2010-05-14 04:29:45 +04:00
s - > parameters_etc_fstab . priority = s - > parameters_proc_swaps . priority = s - > parameters_fragment . priority = - 1 ;
2010-05-10 01:41:03 +04:00
}
2010-05-14 04:29:45 +04:00
static void swap_done ( Unit * u ) {
Swap * s = SWAP ( u ) ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
assert ( s ) ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
free ( s - > what ) ;
free ( s - > parameters_etc_fstab . what ) ;
free ( s - > parameters_proc_swaps . what ) ;
free ( s - > parameters_fragment . what ) ;
2010-05-09 20:44:11 +04:00
}
2010-05-13 05:07:16 +04:00
int swap_add_one_mount_link ( Swap * s , Mount * m ) {
int r ;
assert ( s ) ;
assert ( m ) ;
if ( s - > meta . load_state ! = UNIT_LOADED | |
m - > meta . load_state ! = UNIT_LOADED )
return 0 ;
2010-05-16 20:13:58 +04:00
if ( is_device_path ( s - > what ) )
return 0 ;
2010-05-13 05:07:16 +04:00
if ( ! path_startswith ( s - > what , m - > where ) )
return 0 ;
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_BEFORE , UNIT ( s ) , true ) ) < 0 )
return r ;
if ( ( r = unit_add_dependency ( UNIT ( s ) , UNIT_REQUIRES , UNIT ( m ) , true ) ) < 0 )
return r ;
return 0 ;
}
static int swap_add_mount_links ( Swap * s ) {
Meta * other ;
int r ;
assert ( s ) ;
LIST_FOREACH ( units_per_type , other , s - > meta . manager - > units_per_type [ UNIT_MOUNT ] )
if ( ( r = swap_add_one_mount_link ( s , ( Mount * ) other ) ) < 0 )
return r ;
return 0 ;
}
2010-05-09 20:44:11 +04:00
static int swap_add_target_links ( Swap * s ) {
Unit * tu ;
2010-05-14 04:29:45 +04:00
SwapParameters * p ;
2010-05-09 20:44:11 +04:00
int r ;
2010-05-14 04:29:45 +04:00
assert ( s ) ;
if ( s - > from_fragment )
p = & s - > parameters_fragment ;
else if ( s - > from_etc_fstab )
p = & s - > parameters_etc_fstab ;
else
return 0 ;
if ( ( r = manager_load_unit ( s - > meta . manager , SPECIAL_SWAP_TARGET , NULL , & tu ) ) < 0 )
2010-05-09 20:44:11 +04:00
return r ;
2010-05-14 04:29:45 +04:00
if ( ! p - > noauto & & p - > handle )
2010-05-13 05:07:16 +04:00
if ( ( r = unit_add_dependency ( tu , UNIT_WANTS , UNIT ( s ) , true ) ) < 0 )
return r ;
2010-05-09 20:44:11 +04:00
return unit_add_dependency ( UNIT ( s ) , UNIT_BEFORE , tu , true ) ;
}
2010-05-14 04:29:45 +04:00
static int swap_verify ( Swap * s ) {
bool b ;
char * e ;
if ( UNIT ( s ) - > meta . load_state ! = UNIT_LOADED )
return 0 ;
if ( ! ( e = unit_name_from_path ( s - > what , " .swap " ) ) )
return - ENOMEM ;
b = unit_has_name ( UNIT ( s ) , e ) ;
free ( e ) ;
if ( ! b ) {
log_error ( " %s: Value of \" What \" and unit name do not match, not loading. \n " , UNIT ( s ) - > meta . id ) ;
return - EINVAL ;
}
return 0 ;
}
2010-05-09 20:44:11 +04:00
static int swap_load ( Unit * u ) {
int r ;
Swap * s = SWAP ( u ) ;
assert ( s ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
/* Load a .swap file */
if ( ( r = unit_load_fragment_and_dropin_optional ( u ) ) < 0 )
return r ;
if ( u - > meta . load_state = = UNIT_LOADED ) {
2010-05-14 04:29:45 +04:00
if ( s - > meta . fragment_path )
s - > from_fragment = true ;
if ( ! s - > what ) {
if ( s - > parameters_fragment . what )
s - > what = strdup ( s - > parameters_fragment . what ) ;
else if ( s - > parameters_etc_fstab . what )
s - > what = strdup ( s - > parameters_etc_fstab . what ) ;
else if ( s - > parameters_proc_swaps . what )
s - > what = strdup ( s - > parameters_proc_swaps . what ) ;
else
s - > what = unit_name_to_path ( u - > meta . id ) ;
if ( ! s - > what )
2010-05-09 20:44:11 +04:00
return - ENOMEM ;
2010-05-14 04:29:45 +04:00
}
2010-05-09 20:44:11 +04:00
path_kill_slashes ( s - > what ) ;
2010-05-14 04:29:45 +04:00
if ( ! s - > meta . description )
if ( ( r = unit_set_description ( u , s - > what ) ) < 0 )
return r ;
2010-05-13 05:07:16 +04:00
if ( ( r = unit_add_node_link ( u , s - > what ,
( u - > meta . manager - > running_as = = MANAGER_INIT | |
u - > meta . manager - > running_as = = MANAGER_SYSTEM ) ) ) < 0 )
2010-05-09 20:44:11 +04:00
return r ;
2010-05-13 05:07:16 +04:00
if ( ( r = swap_add_mount_links ( s ) ) < 0 )
return r ;
2010-05-09 20:44:11 +04:00
if ( ( r = swap_add_target_links ( s ) ) < 0 )
return r ;
}
return swap_verify ( s ) ;
}
2010-05-14 04:29:45 +04:00
static int swap_find ( Manager * m , const char * what , Unit * * _u ) {
2010-05-09 20:44:11 +04:00
Unit * u ;
char * e ;
2010-05-14 04:29:45 +04:00
assert ( m ) ;
assert ( what ) ;
assert ( _u ) ;
/* /proc/swaps and /etc/fstab might refer to this device by
* different names ( e . g . one by uuid , the other by the kernel
* name ) , we hence need to look for all aliases we are aware
* of for this device */
if ( ! ( e = unit_name_from_path ( what , " .device " ) ) )
return - ENOMEM ;
u = manager_get_unit ( m , e ) ;
free ( e ) ;
if ( u ) {
Iterator i ;
const char * d ;
SET_FOREACH ( d , u - > meta . names , i ) {
Unit * k ;
if ( ! ( e = unit_name_change_suffix ( d , " .swap " ) ) )
return - ENOMEM ;
k = manager_get_unit ( m , e ) ;
free ( e ) ;
if ( k ) {
* _u = k ;
return 0 ;
}
}
}
* _u = NULL ;
return 0 ;
}
int swap_add_one (
Manager * m ,
const char * what ,
int priority ,
bool noauto ,
bool handle ,
bool from_proc_swaps ) {
Unit * u = NULL ;
char * e = NULL , * w = NULL ;
2010-05-09 20:44:11 +04:00
bool delete ;
int r ;
2010-05-14 04:29:45 +04:00
SwapParameters * p ;
assert ( m ) ;
assert ( what ) ;
2010-05-09 20:44:11 +04:00
if ( ! ( e = unit_name_from_path ( what , " .swap " ) ) )
return - ENOMEM ;
2010-05-14 04:29:45 +04:00
if ( ! ( u = manager_get_unit ( m , e ) ) )
if ( ( r = swap_find ( m , what , & u ) ) < 0 )
goto fail ;
if ( ! u ) {
2010-05-09 20:44:11 +04:00
delete = true ;
if ( ! ( u = unit_new ( m ) ) ) {
free ( e ) ;
return - ENOMEM ;
}
2010-05-14 04:29:45 +04:00
} else
delete = false ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
if ( ( r = unit_add_name ( u , e ) ) < 0 )
goto fail ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
if ( ! ( w = strdup ( what ) ) ) {
r = - ENOMEM ;
goto fail ;
}
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
if ( from_proc_swaps ) {
p = & SWAP ( u ) - > parameters_proc_swaps ;
SWAP ( u ) - > from_proc_swaps = true ;
} else {
p = & SWAP ( u ) - > parameters_etc_fstab ;
SWAP ( u ) - > from_etc_fstab = true ;
}
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
free ( p - > what ) ;
p - > what = w ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
p - > priority = priority ;
p - > noauto = noauto ;
p - > handle = handle ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
if ( delete )
unit_add_to_load_queue ( u ) ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
unit_add_to_dbus_queue ( u ) ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
free ( e ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
fail :
2010-05-14 04:29:45 +04:00
free ( w ) ;
free ( e ) ;
if ( delete & & u )
2010-05-09 20:44:11 +04:00
unit_free ( u ) ;
2010-05-14 04:29:45 +04:00
return r ;
2010-05-09 20:44:11 +04:00
}
static void swap_set_state ( Swap * s , SwapState state ) {
SwapState old_state ;
assert ( s ) ;
old_state = s - > state ;
s - > state = state ;
if ( state ! = old_state )
log_debug ( " %s changed %s -> %s " ,
UNIT ( s ) - > meta . id ,
swap_state_to_string ( old_state ) ,
swap_state_to_string ( state ) ) ;
unit_notify ( UNIT ( s ) , state_translation_table [ old_state ] , state_translation_table [ state ] ) ;
}
static int swap_coldplug ( Unit * u ) {
Swap * s = SWAP ( u ) ;
SwapState new_state = SWAP_DEAD ;
assert ( s ) ;
assert ( s - > state = = SWAP_DEAD ) ;
if ( s - > deserialized_state ! = s - > state )
new_state = s - > deserialized_state ;
2010-05-14 04:29:45 +04:00
else if ( s - > from_proc_swaps )
2010-05-09 20:44:11 +04:00
new_state = SWAP_ACTIVE ;
if ( new_state ! = s - > state )
2010-05-14 04:29:45 +04:00
swap_set_state ( s , new_state ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
static void swap_dump ( Unit * u , FILE * f , const char * prefix ) {
Swap * s = SWAP ( u ) ;
2010-05-14 04:29:45 +04:00
SwapParameters * p ;
2010-05-09 20:44:11 +04:00
assert ( s ) ;
2010-05-14 04:29:45 +04:00
assert ( f ) ;
if ( s - > from_proc_swaps )
p = & s - > parameters_proc_swaps ;
else if ( s - > from_fragment )
p = & s - > parameters_fragment ;
else
p = & s - > parameters_etc_fstab ;
2010-05-09 20:44:11 +04:00
fprintf ( f ,
2010-05-14 04:29:45 +04:00
" %sSwap State: %s \n "
2010-05-09 20:44:11 +04:00
" %sWhat: %s \n "
" %sPriority: %i \n "
2010-05-14 04:29:45 +04:00
" %sNoAuto: %s \n "
" %sHandle: %s \n "
" %sFrom /etc/fstab: %s \n "
" %sFrom /proc/swaps: %s \n "
" %sFrom fragment: %s \n " ,
2010-05-09 20:44:11 +04:00
prefix , swap_state_to_string ( s - > state ) ,
prefix , s - > what ,
2010-05-14 04:29:45 +04:00
prefix , p - > priority ,
prefix , yes_no ( p - > noauto ) ,
prefix , yes_no ( p - > handle ) ,
prefix , yes_no ( s - > from_etc_fstab ) ,
prefix , yes_no ( s - > from_proc_swaps ) ,
prefix , yes_no ( s - > from_fragment ) ) ;
2010-05-09 20:44:11 +04:00
}
static void swap_enter_dead ( Swap * s , bool success ) {
assert ( s ) ;
swap_set_state ( s , success ? SWAP_MAINTAINANCE : SWAP_DEAD ) ;
}
static int swap_start ( Unit * u ) {
Swap * s = SWAP ( u ) ;
2010-05-14 04:29:45 +04:00
int priority = - 1 ;
2010-05-09 20:44:11 +04:00
int r ;
assert ( s ) ;
assert ( s - > state = = SWAP_DEAD | | s - > state = = SWAP_MAINTAINANCE ) ;
2010-05-14 04:29:45 +04:00
if ( s - > from_fragment )
priority = s - > parameters_fragment . priority ;
else if ( s - > from_etc_fstab )
priority = s - > parameters_etc_fstab . priority ;
r = swapon ( s - > what , ( priority < < SWAP_FLAG_PRIO_SHIFT ) & SWAP_FLAG_PRIO_MASK ) ;
2010-05-09 20:44:11 +04:00
if ( r < 0 & & errno ! = EBUSY ) {
r = - errno ;
swap_enter_dead ( s , false ) ;
return r ;
}
swap_set_state ( s , SWAP_ACTIVE ) ;
return 0 ;
}
static int swap_stop ( Unit * u ) {
Swap * s = SWAP ( u ) ;
int r ;
assert ( s ) ;
assert ( s - > state = = SWAP_ACTIVE ) ;
r = swapoff ( s - > what ) ;
swap_enter_dead ( s , r > = 0 | | errno = = EINVAL ) ;
return 0 ;
}
static int swap_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , swap_state_to_string ( s - > state ) ) ;
return 0 ;
}
static int swap_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
SwapState state ;
if ( ( state = swap_state_from_string ( value ) ) < 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 ;
}
static UnitActiveState swap_active_state ( Unit * u ) {
assert ( u ) ;
return state_translation_table [ SWAP ( u ) - > state ] ;
}
static const char * swap_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
return swap_state_to_string ( SWAP ( u ) - > state ) ;
}
static bool swap_check_gc ( Unit * u ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2010-05-14 04:29:45 +04:00
return s - > from_etc_fstab | | s - > from_proc_swaps ;
2010-05-09 20:44:11 +04:00
}
static int swap_load_proc_swaps ( Manager * m ) {
rewind ( m - > proc_swaps ) ;
2010-05-10 05:34:31 +04:00
2010-05-14 04:29:45 +04:00
( void ) fscanf ( m - > proc_swaps , " %*s %*s %*s %*s %*s \n " ) ;
2010-05-09 20:44:11 +04:00
for ( ; ; ) {
char * dev = NULL , * d ;
int prio = 0 , k ;
2010-05-14 04:29:45 +04:00
if ( ( k = fscanf ( m - > proc_swaps ,
" %ms " /* device/file */
" %*s " /* type of swap */
" %*s " /* swap size */
" %*s " /* used */
" %i \n " , /* priority */
& dev , & prio ) ) ! = 2 ) {
2010-05-09 20:44:11 +04:00
if ( k = = EOF )
2010-05-14 04:29:45 +04:00
break ;
2010-05-09 20:44:11 +04:00
free ( dev ) ;
return - EBADMSG ;
}
2010-05-14 04:29:45 +04:00
d = cunescape ( dev ) ;
2010-05-09 20:44:11 +04:00
free ( dev ) ;
2010-05-14 04:29:45 +04:00
if ( ! d )
return - ENOMEM ;
k = swap_add_one ( m , d , prio , false , false , true ) ;
2010-05-09 20:44:11 +04:00
free ( d ) ;
if ( k < 0 )
return k ;
}
2010-05-14 04:29:45 +04:00
return 0 ;
2010-05-09 20:44:11 +04:00
}
static void swap_shutdown ( Manager * m ) {
assert ( m ) ;
if ( m - > proc_swaps ) {
fclose ( m - > proc_swaps ) ;
m - > proc_swaps = NULL ;
}
}
static const char * const swap_state_table [ _SWAP_STATE_MAX ] = {
[ SWAP_DEAD ] = " dead " ,
[ SWAP_ACTIVE ] = " active " ,
[ SWAP_MAINTAINANCE ] = " maintainance "
} ;
DEFINE_STRING_TABLE_LOOKUP ( swap_state , SwapState ) ;
static int swap_enumerate ( Manager * m ) {
int r ;
assert ( m ) ;
2010-05-14 04:29:45 +04:00
if ( ! m - > proc_swaps )
if ( ! ( m - > proc_swaps = fopen ( " /proc/swaps " , " re " ) ) )
return - errno ;
2010-05-09 20:44:11 +04:00
if ( ( r = swap_load_proc_swaps ( m ) ) < 0 )
swap_shutdown ( m ) ;
return r ;
}
const UnitVTable swap_vtable = {
. suffix = " .swap " ,
. no_instances = true ,
2010-05-10 01:41:03 +04:00
. no_isolate = true ,
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
. init = swap_init ,
2010-05-09 20:44:11 +04:00
. load = swap_load ,
2010-05-10 01:41:03 +04:00
. done = swap_done ,
2010-05-09 20:44:11 +04:00
. coldplug = swap_coldplug ,
. dump = swap_dump ,
. start = swap_start ,
. stop = swap_stop ,
. serialize = swap_serialize ,
. deserialize_item = swap_deserialize_item ,
. active_state = swap_active_state ,
. sub_state_to_string = swap_sub_state_to_string ,
. check_gc = swap_check_gc ,
. bus_message_handler = bus_swap_message_handler ,
2010-05-10 01:41:03 +04:00
. enumerate = swap_enumerate ,
. shutdown = swap_shutdown
2010-05-09 20:44:11 +04:00
} ;