2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-23 03:52:57 +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-23 03:52:57 +03:00
# include <errno.h>
2010-01-29 04:07:41 +03:00
# include <stdio.h>
# include <mntent.h>
2010-01-29 08:04:08 +03:00
# include <sys/epoll.h>
2010-04-10 19:53:17 +04:00
# include <signal.h>
2010-01-23 03:52:57 +03:00
2010-01-26 23:39:06 +03:00
# include "unit.h"
2010-01-23 03:52:57 +03:00
# include "mount.h"
# include "load-fragment.h"
# include "load-dropin.h"
2010-01-29 04:07:41 +03:00
# include "log.h"
2010-04-10 19:53:17 +04:00
# include "strv.h"
# include "mount-setup.h"
2010-04-15 05:11:11 +04:00
# include "unit-name.h"
2010-04-18 05:08:16 +04:00
# include "dbus-mount.h"
2010-06-18 06:22:59 +04:00
# include "special.h"
2010-01-23 03:52:57 +03:00
2010-01-29 05:18:09 +03:00
static const UnitActiveState state_translation_table [ _MOUNT_STATE_MAX ] = {
[ MOUNT_DEAD ] = UNIT_INACTIVE ,
[ MOUNT_MOUNTING ] = UNIT_ACTIVATING ,
2010-04-10 19:53:17 +04:00
[ MOUNT_MOUNTING_DONE ] = UNIT_ACTIVE ,
2010-01-29 05:18:09 +03:00
[ MOUNT_MOUNTED ] = UNIT_ACTIVE ,
2010-07-01 05:34:15 +04:00
[ MOUNT_REMOUNTING ] = UNIT_RELOADING ,
2010-01-29 05:18:09 +03:00
[ MOUNT_UNMOUNTING ] = UNIT_DEACTIVATING ,
2010-04-10 19:53:17 +04:00
[ MOUNT_MOUNTING_SIGTERM ] = UNIT_DEACTIVATING ,
[ MOUNT_MOUNTING_SIGKILL ] = UNIT_DEACTIVATING ,
2010-07-01 05:34:15 +04:00
[ MOUNT_REMOUNTING_SIGTERM ] = UNIT_RELOADING ,
[ MOUNT_REMOUNTING_SIGKILL ] = UNIT_RELOADING ,
2010-04-10 19:53:17 +04:00
[ MOUNT_UNMOUNTING_SIGTERM ] = UNIT_DEACTIVATING ,
[ MOUNT_UNMOUNTING_SIGKILL ] = UNIT_DEACTIVATING ,
2010-08-31 02:23:34 +04:00
[ MOUNT_FAILED ] = UNIT_FAILED
2010-01-29 05:18:09 +03:00
} ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
static void mount_init ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
m - > timeout_usec = DEFAULT_TIMEOUT_USEC ;
2010-07-02 02:28:44 +04:00
m - > directory_mode = 0755 ;
2010-07-08 07:22:34 +04:00
exec_context_init ( & m - > exec_context ) ;
2010-04-21 05:27:44 +04:00
/* We need to make sure that /bin/mount is always called in
* the same process group as us , so that the autofs kernel
* side doesn ' t send us another mount request while we are
* already trying to comply its last one . */
2010-07-05 03:08:13 +04:00
m - > exec_context . same_pgrp = true ;
2010-04-17 01:24:39 +04:00
2010-04-21 05:27:44 +04:00
m - > timer_watch . type = WATCH_INVALID ;
m - > control_command_id = _MOUNT_EXEC_COMMAND_INVALID ;
2010-04-17 01:24:39 +04:00
}
2010-04-21 05:27:44 +04:00
static void mount_unwatch_control_pid ( Mount * m ) {
2010-04-11 02:22:36 +04:00
assert ( m ) ;
if ( m - > control_pid < = 0 )
return ;
unit_unwatch_pid ( UNIT ( m ) , m - > control_pid ) ;
m - > control_pid = 0 ;
}
2010-04-10 19:53:17 +04:00
static void mount_parameters_done ( MountParameters * p ) {
assert ( p ) ;
free ( p - > what ) ;
free ( p - > options ) ;
free ( p - > fstype ) ;
p - > what = p - > options = p - > fstype = NULL ;
}
2010-01-26 23:39:06 +03:00
static void mount_done ( Unit * u ) {
2010-01-29 08:04:08 +03:00
Mount * m = MOUNT ( u ) ;
2010-01-26 06:18:44 +03:00
2010-01-29 08:04:08 +03:00
assert ( m ) ;
2010-01-26 06:18:44 +03:00
2010-04-10 19:53:17 +04:00
free ( m - > where ) ;
m - > where = NULL ;
2010-01-29 05:18:09 +03:00
2010-04-10 19:53:17 +04:00
mount_parameters_done ( & m - > parameters_etc_fstab ) ;
mount_parameters_done ( & m - > parameters_proc_self_mountinfo ) ;
mount_parameters_done ( & m - > parameters_fragment ) ;
2010-01-29 08:04:08 +03:00
2010-04-10 19:53:17 +04:00
exec_context_done ( & m - > exec_context ) ;
exec_command_done_array ( m - > exec_command , _MOUNT_EXEC_COMMAND_MAX ) ;
m - > control_command = NULL ;
2010-01-29 05:18:09 +03:00
2010-04-21 05:27:44 +04:00
mount_unwatch_control_pid ( m ) ;
2010-01-29 05:18:09 +03:00
2010-04-10 19:53:17 +04:00
unit_unwatch_timer ( u , & m - > timer_watch ) ;
2010-01-29 05:18:09 +03:00
}
2010-05-13 05:07:16 +04:00
static int mount_add_mount_links ( Mount * m ) {
Meta * other ;
2010-01-29 04:07:41 +03:00
int r ;
2010-05-13 05:07:16 +04:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
/* Adds in links to other mount points that might lie below or
* above us in the hierarchy */
2010-04-10 19:53:17 +04:00
2010-05-13 05:07:16 +04:00
LIST_FOREACH ( units_per_type , other , m - > meta . manager - > units_per_type [ UNIT_MOUNT ] ) {
Mount * n = ( Mount * ) other ;
2010-05-09 20:44:11 +04:00
2010-05-13 05:07:16 +04:00
if ( n = = m )
continue ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
if ( n - > meta . load_state ! = UNIT_LOADED )
continue ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
if ( path_startswith ( m - > where , n - > where ) ) {
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_AFTER , UNIT ( n ) , true ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
if ( n - > from_etc_fstab | | n - > from_fragment )
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_REQUIRES , UNIT ( n ) , true ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
} else if ( path_startswith ( n - > where , m - > where ) ) {
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_BEFORE , UNIT ( n ) , true ) ) < 0 )
return r ;
if ( m - > from_etc_fstab | | m - > from_fragment )
if ( ( r = unit_add_dependency ( UNIT ( n ) , UNIT_REQUIRES , UNIT ( m ) , true ) ) < 0 )
return r ;
}
}
2010-01-29 04:07:41 +03:00
return 0 ;
}
2010-05-13 05:07:16 +04:00
static int mount_add_swap_links ( Mount * m ) {
2010-01-29 08:04:08 +03:00
Meta * other ;
2010-01-29 04:07:41 +03:00
int r ;
2010-05-13 05:07:16 +04:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
LIST_FOREACH ( units_per_type , other , m - > meta . manager - > units_per_type [ UNIT_SWAP ] )
if ( ( r = swap_add_one_mount_link ( ( Swap * ) other , m ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
return 0 ;
}
2010-01-29 04:07:41 +03:00
2010-05-24 07:25:33 +04:00
static int mount_add_path_links ( Mount * m ) {
Meta * other ;
int r ;
assert ( m ) ;
LIST_FOREACH ( units_per_type , other , m - > meta . manager - > units_per_type [ UNIT_PATH ] )
if ( ( r = path_add_one_mount_link ( ( Path * ) other , m ) ) < 0 )
return r ;
return 0 ;
}
2010-05-13 05:07:16 +04:00
static int mount_add_automount_links ( Mount * m ) {
Meta * other ;
int r ;
2010-04-10 19:53:17 +04:00
2010-05-13 05:07:16 +04:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
LIST_FOREACH ( units_per_type , other , m - > meta . manager - > units_per_type [ UNIT_AUTOMOUNT ] )
if ( ( r = automount_add_one_mount_link ( ( Automount * ) other , m ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
return 0 ;
}
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
static int mount_add_socket_links ( Mount * m ) {
Meta * other ;
int r ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
2010-05-13 05:07:16 +04:00
LIST_FOREACH ( units_per_type , other , m - > meta . manager - > units_per_type [ UNIT_SOCKET ] )
if ( ( r = socket_add_one_mount_link ( ( Socket * ) other , m ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
return 0 ;
}
2010-05-09 20:44:11 +04:00
static char * mount_test_option ( const char * haystack , const char * needle ) {
2010-04-10 19:53:17 +04:00
struct mntent me ;
assert ( needle ) ;
/* Like glibc's hasmntopt(), but works on a string, not a
* struct mntent */
if ( ! haystack )
return false ;
zero ( me ) ;
me . mnt_opts = ( char * ) haystack ;
2010-05-09 20:44:11 +04:00
return hasmntopt ( & me , needle ) ;
2010-04-10 19:53:17 +04:00
}
static int mount_add_target_links ( Mount * m ) {
const char * target ;
MountParameters * p ;
2010-04-21 05:27:44 +04:00
Unit * tu ;
2010-04-10 19:53:17 +04:00
int r ;
2010-05-17 00:46:03 +04:00
bool noauto , handle , automount , user ;
2010-04-10 19:53:17 +04:00
assert ( m ) ;
if ( m - > from_fragment )
p = & m - > parameters_fragment ;
else if ( m - > from_etc_fstab )
p = & m - > parameters_etc_fstab ;
else
return 0 ;
2010-05-09 20:44:11 +04:00
noauto = ! ! mount_test_option ( p - > options , MNTOPT_NOAUTO ) ;
2010-05-17 00:46:03 +04:00
user = mount_test_option ( p - > options , " user " ) | | mount_test_option ( p - > options , " users " ) ;
2010-08-25 05:11:26 +04:00
handle = ! ! mount_test_option ( p - > options , " comment=systemd.mount " ) | |
m - > meta . manager - > mount_auto ;
2010-05-09 20:44:11 +04:00
automount = ! ! mount_test_option ( p - > options , " comment=systemd.automount " ) ;
2010-04-10 19:53:17 +04:00
if ( mount_test_option ( p - > options , " _netdev " ) | |
fstype_is_network ( p - > fstype ) )
target = SPECIAL_REMOTE_FS_TARGET ;
else
target = SPECIAL_LOCAL_FS_TARGET ;
2010-07-08 04:43:18 +04:00
if ( ( r = manager_load_unit ( m - > meta . manager , target , NULL , NULL , & tu ) ) < 0 )
2010-04-10 19:53:17 +04:00
return r ;
2010-06-19 05:15:59 +04:00
if ( automount & & m - > meta . manager - > running_as = = MANAGER_SYSTEM ) {
2010-04-21 05:27:44 +04:00
Unit * am ;
if ( ( r = unit_load_related_unit ( UNIT ( m ) , " .automount " , & am ) ) < 0 )
2010-04-13 23:55:34 +04:00
return r ;
2010-04-10 19:53:17 +04:00
2010-07-03 21:46:38 +04:00
return unit_add_two_dependencies ( tu , UNIT_AFTER , UNIT_WANTS , UNIT ( am ) , true ) ;
2010-04-21 05:27:44 +04:00
} else {
2010-08-25 23:24:21 +04:00
/* Automatically add mount points that aren't natively
* configured to local - fs . target */
if ( ! noauto & &
handle & &
! m - > from_fragment )
2010-06-19 05:15:59 +04:00
if ( user | | m - > meta . manager - > running_as = = MANAGER_SYSTEM )
2010-05-17 00:46:03 +04:00
if ( ( r = unit_add_dependency ( tu , UNIT_WANTS , UNIT ( m ) , true ) ) < 0 )
return r ;
2010-04-21 05:27:44 +04:00
2010-04-21 08:01:13 +04:00
return unit_add_dependency ( UNIT ( m ) , UNIT_BEFORE , tu , true ) ;
2010-04-21 05:27:44 +04:00
}
2010-04-10 19:53:17 +04:00
}
2010-08-25 22:37:04 +04:00
static int mount_add_device_links ( Mount * m ) {
MountParameters * p ;
bool nofail , noauto ;
assert ( m ) ;
if ( m - > from_fragment )
p = & m - > parameters_fragment ;
else if ( m - > from_etc_fstab )
p = & m - > parameters_etc_fstab ;
else
return 0 ;
if ( ! p - > what | | path_equal ( m - > where , " / " ) )
return 0 ;
noauto = ! ! mount_test_option ( p - > options , MNTOPT_NOAUTO ) ;
nofail = ! ! mount_test_option ( p - > options , " nofail " ) ;
return unit_add_node_link ( UNIT ( m ) , p - > what ,
! noauto & & nofail & &
UNIT ( m ) - > meta . manager - > running_as = = MANAGER_SYSTEM ) ;
}
2010-07-13 00:55:27 +04:00
static int mount_add_default_dependencies ( Mount * m ) {
int r ;
assert ( m ) ;
2010-08-06 04:23:45 +04:00
if ( m - > meta . manager - > running_as = = MANAGER_SYSTEM & &
! path_equal ( m - > where , " / " ) ) {
2010-07-13 00:55:27 +04:00
2010-08-06 03:30:20 +04:00
if ( ( r = unit_add_dependency_by_name ( UNIT ( m ) , UNIT_AFTER , SPECIAL_FSCK_TARGET , NULL , true ) ) < 0 )
2010-07-13 00:55:27 +04:00
return r ;
2010-08-10 00:32:30 +04:00
if ( ( r = unit_add_two_dependencies_by_name ( UNIT ( m ) , UNIT_BEFORE , UNIT_CONFLICTED_BY , SPECIAL_UMOUNT_TARGET , NULL , true ) ) < 0 )
2010-08-06 04:23:45 +04:00
return r ;
2010-07-13 00:55:27 +04:00
}
return 0 ;
}
2010-04-17 01:24:39 +04:00
static int mount_verify ( Mount * m ) {
bool b ;
char * e ;
assert ( m ) ;
2010-05-21 05:32:21 +04:00
if ( m - > meta . load_state ! = UNIT_LOADED )
2010-04-17 01:24:39 +04:00
return 0 ;
2010-05-21 05:32:21 +04:00
if ( ! m - > from_etc_fstab & & ! m - > from_fragment & & ! m - > from_proc_self_mountinfo )
return - ENOENT ;
2010-04-21 05:27:44 +04:00
if ( ! ( e = unit_name_from_path ( m - > where , " .mount " ) ) )
2010-04-17 01:24:39 +04:00
return - ENOMEM ;
b = unit_has_name ( UNIT ( m ) , e ) ;
free ( e ) ;
if ( ! b ) {
2010-06-19 18:55:49 +04:00
log_error ( " %s's Where setting doesn't match unit name. Refusing. " , m - > meta . id ) ;
2010-04-17 01:24:39 +04:00
return - EINVAL ;
}
2010-05-14 04:29:45 +04:00
if ( m - > meta . fragment_path & & ! m - > parameters_fragment . what ) {
2010-06-19 18:55:49 +04:00
log_error ( " %s's What setting is missing. Refusing. " , m - > meta . id ) ;
2010-05-14 04:29:45 +04:00
return - EBADMSG ;
}
2010-07-10 06:49:37 +04:00
if ( m - > exec_context . pam_name & & m - > exec_context . kill_mode ! = KILL_CONTROL_GROUP ) {
2010-06-19 18:57:54 +04:00
log_error ( " %s has PAM enabled. Kill mode must be set to 'control-group'. Refusing. " , m - > meta . id ) ;
return - EINVAL ;
}
2010-04-17 01:24:39 +04:00
return 0 ;
}
2010-04-10 19:53:17 +04:00
static int mount_load ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
int r ;
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
if ( ( r = unit_load_fragment_and_dropin_optional ( u ) ) < 0 )
return r ;
/* This is a new unit? Then let's add in some extras */
if ( u - > meta . load_state = = UNIT_LOADED ) {
2010-05-14 04:29:45 +04:00
const char * what = NULL ;
2010-05-13 05:07:16 +04:00
2010-05-14 04:29:45 +04:00
if ( m - > meta . fragment_path )
m - > from_fragment = true ;
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( ! m - > where )
if ( ! ( m - > where = unit_name_to_path ( u - > meta . id ) ) )
return - ENOMEM ;
path_kill_slashes ( m - > where ) ;
2010-05-14 04:29:45 +04:00
if ( ! m - > meta . description )
if ( ( r = unit_set_description ( u , m - > where ) ) < 0 )
return r ;
2010-04-10 19:53:17 +04:00
2010-05-14 04:29:45 +04:00
if ( m - > from_fragment & & m - > parameters_fragment . what )
what = m - > parameters_fragment . what ;
else if ( m - > from_etc_fstab & & m - > parameters_etc_fstab . what )
what = m - > parameters_etc_fstab . what ;
else if ( m - > from_proc_self_mountinfo & & m - > parameters_proc_self_mountinfo . what )
what = m - > parameters_proc_self_mountinfo . what ;
2010-04-10 19:53:17 +04:00
2010-08-25 22:37:04 +04:00
if ( ( r = mount_add_device_links ( m ) ) < 0 )
return r ;
2010-05-13 05:07:16 +04:00
if ( ( r = mount_add_mount_links ( m ) ) < 0 )
return r ;
if ( ( r = mount_add_socket_links ( m ) ) < 0 )
return r ;
if ( ( r = mount_add_swap_links ( m ) ) < 0 )
2010-04-10 19:53:17 +04:00
return r ;
2010-05-24 07:25:33 +04:00
if ( ( r = mount_add_path_links ( m ) ) < 0 )
return r ;
2010-05-13 05:07:16 +04:00
if ( ( r = mount_add_automount_links ( m ) ) < 0 )
2010-04-10 19:53:17 +04:00
return r ;
2010-05-13 05:07:16 +04:00
if ( ( r = mount_add_target_links ( m ) ) < 0 )
2010-04-10 19:53:17 +04:00
return r ;
if ( ( r = unit_add_default_cgroup ( u ) ) < 0 )
return r ;
2010-07-10 04:41:06 +04:00
2010-07-13 00:55:27 +04:00
if ( m - > meta . default_dependencies )
if ( ( r = mount_add_default_dependencies ( m ) ) < 0 )
2010-07-10 04:41:06 +04:00
return r ;
2010-04-10 19:53:17 +04:00
}
2010-04-17 01:24:39 +04:00
return mount_verify ( m ) ;
2010-04-10 19:53:17 +04:00
}
2010-04-21 05:27:44 +04:00
static int mount_notify_automount ( Mount * m , int status ) {
Unit * p ;
int r ;
assert ( m ) ;
if ( ( r = unit_get_related_unit ( UNIT ( m ) , " .automount " , & p ) ) < 0 )
return r = = - ENOENT ? 0 : r ;
return automount_send_ready ( AUTOMOUNT ( p ) , status ) ;
}
2010-04-10 19:53:17 +04:00
static void mount_set_state ( Mount * m , MountState state ) {
MountState old_state ;
assert ( m ) ;
old_state = m - > state ;
m - > state = state ;
if ( state ! = MOUNT_MOUNTING & &
state ! = MOUNT_MOUNTING_DONE & &
state ! = MOUNT_REMOUNTING & &
state ! = MOUNT_UNMOUNTING & &
state ! = MOUNT_MOUNTING_SIGTERM & &
state ! = MOUNT_MOUNTING_SIGKILL & &
state ! = MOUNT_UNMOUNTING_SIGTERM & &
state ! = MOUNT_UNMOUNTING_SIGKILL & &
state ! = MOUNT_REMOUNTING_SIGTERM & &
state ! = MOUNT_REMOUNTING_SIGKILL ) {
unit_unwatch_timer ( UNIT ( m ) , & m - > timer_watch ) ;
2010-04-21 05:27:44 +04:00
mount_unwatch_control_pid ( m ) ;
2010-04-10 19:53:17 +04:00
m - > control_command = NULL ;
2010-04-21 05:27:44 +04:00
m - > control_command_id = _MOUNT_EXEC_COMMAND_INVALID ;
2010-04-10 19:53:17 +04:00
}
2010-04-17 01:24:39 +04:00
if ( state = = MOUNT_MOUNTED | |
state = = MOUNT_REMOUNTING )
mount_notify_automount ( m , 0 ) ;
else if ( state = = MOUNT_DEAD | |
state = = MOUNT_UNMOUNTING | |
state = = MOUNT_MOUNTING_SIGTERM | |
state = = MOUNT_MOUNTING_SIGKILL | |
state = = MOUNT_REMOUNTING_SIGTERM | |
state = = MOUNT_REMOUNTING_SIGKILL | |
state = = MOUNT_UNMOUNTING_SIGTERM | |
state = = MOUNT_UNMOUNTING_SIGKILL | |
2010-08-31 02:23:34 +04:00
state = = MOUNT_FAILED )
2010-04-17 01:24:39 +04:00
mount_notify_automount ( m , - ENODEV ) ;
2010-04-10 19:53:17 +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
m - > meta . id ,
2010-04-21 05:27:44 +04:00
mount_state_to_string ( old_state ) ,
mount_state_to_string ( state ) ) ;
2010-04-10 19:53:17 +04:00
unit_notify ( UNIT ( m ) , state_translation_table [ old_state ] , state_translation_table [ state ] ) ;
}
static int mount_coldplug ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
2010-04-21 05:27:44 +04:00
MountState new_state = MOUNT_DEAD ;
int r ;
2010-04-10 19:53:17 +04:00
assert ( m ) ;
assert ( m - > state = = MOUNT_DEAD ) ;
2010-04-21 05:27:44 +04:00
if ( m - > deserialized_state ! = m - > state )
new_state = m - > deserialized_state ;
else if ( m - > from_proc_self_mountinfo )
new_state = MOUNT_MOUNTED ;
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( new_state ! = m - > state ) {
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( new_state = = MOUNT_MOUNTING | |
new_state = = MOUNT_MOUNTING_DONE | |
new_state = = MOUNT_REMOUNTING | |
new_state = = MOUNT_UNMOUNTING | |
new_state = = MOUNT_MOUNTING_SIGTERM | |
new_state = = MOUNT_MOUNTING_SIGKILL | |
new_state = = MOUNT_UNMOUNTING_SIGTERM | |
new_state = = MOUNT_UNMOUNTING_SIGKILL | |
new_state = = MOUNT_REMOUNTING_SIGTERM | |
new_state = = MOUNT_REMOUNTING_SIGKILL ) {
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( m - > control_pid < = 0 )
return - EBADMSG ;
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = unit_watch_pid ( UNIT ( m ) , m - > control_pid ) ) < 0 )
return r ;
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = unit_watch_timer ( UNIT ( m ) , m - > timeout_usec , & m - > timer_watch ) ) < 0 )
return r ;
}
2010-04-10 19:53:17 +04:00
2010-04-21 05:27:44 +04:00
mount_set_state ( m , new_state ) ;
}
2010-04-10 19:53:17 +04:00
return 0 ;
}
static void mount_dump ( Unit * u , FILE * f , const char * prefix ) {
Mount * m = MOUNT ( u ) ;
MountParameters * p ;
assert ( m ) ;
assert ( f ) ;
if ( m - > from_proc_self_mountinfo )
p = & m - > parameters_proc_self_mountinfo ;
else if ( m - > from_fragment )
p = & m - > parameters_fragment ;
else
p = & m - > parameters_etc_fstab ;
fprintf ( f ,
" %sMount State: %s \n "
" %sWhere: %s \n "
" %sWhat: %s \n "
" %sFile System Type: %s \n "
" %sOptions: %s \n "
" %sFrom /etc/fstab: %s \n "
" %sFrom /proc/self/mountinfo: %s \n "
" %sFrom fragment: %s \n "
2010-07-02 02:28:44 +04:00
" %sDirectoryMode: %04o \n " ,
2010-04-21 05:27:44 +04:00
prefix , mount_state_to_string ( m - > state ) ,
2010-04-10 19:53:17 +04:00
prefix , m - > where ,
prefix , strna ( p - > what ) ,
prefix , strna ( p - > fstype ) ,
prefix , strna ( p - > options ) ,
prefix , yes_no ( m - > from_etc_fstab ) ,
prefix , yes_no ( m - > from_proc_self_mountinfo ) ,
prefix , yes_no ( m - > from_fragment ) ,
2010-07-02 02:28:44 +04:00
prefix , m - > directory_mode ) ;
2010-04-10 19:53:17 +04:00
if ( m - > control_pid > 0 )
fprintf ( f ,
2010-06-19 06:35:52 +04:00
" %sControl PID: %lu \n " ,
prefix , ( unsigned long ) m - > control_pid ) ;
2010-04-10 19:53:17 +04:00
exec_context_dump ( & m - > exec_context , f , prefix ) ;
}
2010-04-21 05:27:44 +04:00
static int mount_spawn ( Mount * m , ExecCommand * c , pid_t * _pid ) {
pid_t pid ;
int r ;
assert ( m ) ;
assert ( c ) ;
assert ( _pid ) ;
if ( ( r = unit_watch_timer ( UNIT ( m ) , m - > timeout_usec , & m - > timer_watch ) ) < 0 )
goto fail ;
if ( ( r = exec_spawn ( c ,
NULL ,
& m - > exec_context ,
NULL , 0 ,
2010-05-10 01:53:52 +04:00
m - > meta . manager - > environment ,
2010-04-21 05:27:44 +04:00
true ,
true ,
2010-07-08 06:09:17 +04:00
true ,
2010-07-08 07:22:34 +04:00
m - > meta . manager - > confirm_spawn ,
2010-06-19 18:55:49 +04:00
m - > meta . cgroup_bondings ,
2010-04-21 05:27:44 +04:00
& pid ) ) < 0 )
goto fail ;
if ( ( r = unit_watch_pid ( UNIT ( m ) , pid ) ) < 0 )
/* FIXME: we need to do something here */
goto fail ;
* _pid = pid ;
return 0 ;
fail :
unit_unwatch_timer ( UNIT ( m ) , & m - > timer_watch ) ;
return r ;
}
2010-04-10 19:53:17 +04:00
static void mount_enter_dead ( Mount * m , bool success ) {
assert ( m ) ;
if ( ! success )
m - > failure = true ;
2010-08-31 02:23:34 +04:00
mount_set_state ( m , m - > failure ? MOUNT_FAILED : MOUNT_DEAD ) ;
2010-04-10 19:53:17 +04:00
}
2010-04-13 04:06:27 +04:00
static void mount_enter_mounted ( Mount * m , bool success ) {
assert ( m ) ;
if ( ! success )
m - > failure = true ;
mount_set_state ( m , MOUNT_MOUNTED ) ;
}
2010-04-10 19:53:17 +04:00
static void mount_enter_signal ( Mount * m , MountState state , bool success ) {
int r ;
2010-09-01 01:24:47 +04:00
Set * pid_set = NULL ;
bool wait_for_exit = false ;
2010-04-10 19:53:17 +04:00
assert ( m ) ;
if ( ! success )
m - > failure = true ;
2010-07-10 06:49:37 +04:00
if ( m - > exec_context . kill_mode ! = KILL_NONE ) {
2010-04-13 04:06:27 +04:00
int sig = ( state = = MOUNT_MOUNTING_SIGTERM | |
state = = MOUNT_UNMOUNTING_SIGTERM | |
2010-07-10 06:49:37 +04:00
state = = MOUNT_REMOUNTING_SIGTERM ) ? m - > exec_context . kill_signal : SIGKILL ;
2010-04-10 19:53:17 +04:00
2010-09-01 01:24:47 +04:00
if ( m - > control_pid > 0 ) {
if ( kill ( m - > exec_context . kill_mode = = KILL_PROCESS_GROUP ?
- m - > control_pid :
m - > control_pid , sig ) < 0 & & errno ! = ESRCH )
2010-04-10 19:53:17 +04:00
2010-09-01 01:24:47 +04:00
log_warning ( " Failed to kill control process %li: %m " , ( long ) m - > control_pid ) ;
else
wait_for_exit = true ;
2010-04-10 19:53:17 +04:00
}
2010-09-01 01:24:47 +04:00
if ( m - > exec_context . kill_mode = = KILL_CONTROL_GROUP ) {
2010-07-10 06:49:37 +04:00
2010-09-01 01:24:47 +04:00
if ( ! ( pid_set = set_new ( trivial_hash_func , trivial_compare_func ) ) ) {
r = - ENOMEM ;
2010-04-10 19:53:17 +04:00
goto fail ;
}
2010-09-01 01:24:47 +04:00
/* Exclude the control pid from being killed via the cgroup */
if ( m - > control_pid > 0 )
if ( ( r = set_put ( pid_set , LONG_TO_PTR ( m - > control_pid ) ) ) < 0 )
goto fail ;
if ( ( r = cgroup_bonding_kill_list ( m - > meta . cgroup_bondings , sig , pid_set ) ) < 0 ) {
if ( r ! = - EAGAIN & & r ! = - ESRCH & & r ! = - ENOENT )
log_warning ( " Failed to kill control group: %s " , strerror ( - r ) ) ;
} else if ( r > 0 )
wait_for_exit = true ;
set_free ( pid_set ) ;
}
2010-04-10 19:53:17 +04:00
}
2010-09-01 01:24:47 +04:00
if ( wait_for_exit ) {
2010-04-13 04:06:27 +04:00
if ( ( r = unit_watch_timer ( UNIT ( m ) , m - > timeout_usec , & m - > timer_watch ) ) < 0 )
goto fail ;
2010-04-10 19:53:17 +04:00
2010-04-13 04:06:27 +04:00
mount_set_state ( m , state ) ;
} else if ( state = = MOUNT_REMOUNTING_SIGTERM | | state = = MOUNT_REMOUNTING_SIGKILL )
mount_enter_mounted ( m , true ) ;
else
2010-04-10 19:53:17 +04:00
mount_enter_dead ( m , true ) ;
return ;
fail :
2010-06-19 18:55:49 +04:00
log_warning ( " %s failed to kill processes: %s " , m - > meta . id , strerror ( - r ) ) ;
2010-04-10 19:53:17 +04:00
2010-04-13 04:06:27 +04:00
if ( state = = MOUNT_REMOUNTING_SIGTERM | | state = = MOUNT_REMOUNTING_SIGKILL )
mount_enter_mounted ( m , false ) ;
else
mount_enter_dead ( m , false ) ;
2010-09-01 01:24:47 +04:00
if ( pid_set )
set_free ( pid_set ) ;
2010-04-10 19:53:17 +04:00
}
static void mount_enter_unmounting ( Mount * m , bool success ) {
int r ;
assert ( m ) ;
if ( ! success )
m - > failure = true ;
2010-04-21 05:27:44 +04:00
m - > control_command_id = MOUNT_EXEC_UNMOUNT ;
m - > control_command = m - > exec_command + MOUNT_EXEC_UNMOUNT ;
2010-04-10 19:53:17 +04:00
if ( ( r = exec_command_set (
2010-04-21 05:27:44 +04:00
m - > control_command ,
2010-04-10 19:53:17 +04:00
" /bin/umount " ,
m - > where ,
NULL ) ) < 0 )
goto fail ;
2010-04-21 05:27:44 +04:00
mount_unwatch_control_pid ( m ) ;
2010-04-11 02:22:36 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = mount_spawn ( m , m - > control_command , & m - > control_pid ) ) < 0 )
2010-04-10 19:53:17 +04:00
goto fail ;
mount_set_state ( m , MOUNT_UNMOUNTING ) ;
return ;
fail :
2010-06-19 18:55:49 +04:00
log_warning ( " %s failed to run 'umount' task: %s " , m - > meta . id , strerror ( - r ) ) ;
2010-04-10 19:53:17 +04:00
mount_enter_mounted ( m , false ) ;
}
2010-04-17 01:24:39 +04:00
static void mount_enter_mounting ( Mount * m ) {
2010-04-10 19:53:17 +04:00
int r ;
assert ( m ) ;
2010-04-21 05:27:44 +04:00
m - > control_command_id = MOUNT_EXEC_MOUNT ;
m - > control_command = m - > exec_command + MOUNT_EXEC_MOUNT ;
2010-04-10 19:53:17 +04:00
2010-07-02 02:28:44 +04:00
mkdir_p ( m - > where , m - > directory_mode ) ;
2010-04-10 19:53:17 +04:00
if ( m - > from_fragment )
r = exec_command_set (
2010-04-21 05:27:44 +04:00
m - > control_command ,
2010-04-10 19:53:17 +04:00
" /bin/mount " ,
m - > parameters_fragment . what ,
m - > where ,
" -t " , m - > parameters_fragment . fstype ,
2010-04-17 01:24:39 +04:00
m - > parameters_fragment . options ? " -o " : NULL , m - > parameters_fragment . options ,
2010-04-10 19:53:17 +04:00
NULL ) ;
else if ( m - > from_etc_fstab )
r = exec_command_set (
2010-04-21 05:27:44 +04:00
m - > control_command ,
2010-04-10 19:53:17 +04:00
" /bin/mount " ,
m - > where ,
NULL ) ;
else
r = - ENOENT ;
if ( r < 0 )
goto fail ;
2010-04-21 05:27:44 +04:00
mount_unwatch_control_pid ( m ) ;
2010-04-11 02:22:36 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = mount_spawn ( m , m - > control_command , & m - > control_pid ) ) < 0 )
2010-04-10 19:53:17 +04:00
goto fail ;
mount_set_state ( m , MOUNT_MOUNTING ) ;
return ;
fail :
2010-06-19 18:55:49 +04:00
log_warning ( " %s failed to run 'mount' task: %s " , m - > meta . id , strerror ( - r ) ) ;
2010-04-10 19:53:17 +04:00
mount_enter_dead ( m , false ) ;
}
2010-04-17 01:24:39 +04:00
static void mount_enter_mounting_done ( Mount * m ) {
2010-04-10 19:53:17 +04:00
assert ( m ) ;
mount_set_state ( m , MOUNT_MOUNTING_DONE ) ;
}
static void mount_enter_remounting ( Mount * m , bool success ) {
int r ;
assert ( m ) ;
if ( ! success )
m - > failure = true ;
2010-04-21 05:27:44 +04:00
m - > control_command_id = MOUNT_EXEC_REMOUNT ;
m - > control_command = m - > exec_command + MOUNT_EXEC_REMOUNT ;
2010-04-10 19:53:17 +04:00
if ( m - > from_fragment ) {
char * buf = NULL ;
const char * o ;
if ( m - > parameters_fragment . options ) {
if ( ! ( buf = strappend ( " remount, " , m - > parameters_fragment . options ) ) ) {
r = - ENOMEM ;
goto fail ;
}
o = buf ;
} else
o = " remount " ;
r = exec_command_set (
2010-04-21 05:27:44 +04:00
m - > control_command ,
2010-04-10 19:53:17 +04:00
" /bin/mount " ,
m - > parameters_fragment . what ,
m - > where ,
" -t " , m - > parameters_fragment . fstype ,
" -o " , o ,
NULL ) ;
free ( buf ) ;
} else if ( m - > from_etc_fstab )
r = exec_command_set (
2010-04-21 05:27:44 +04:00
m - > control_command ,
2010-04-10 19:53:17 +04:00
" /bin/mount " ,
m - > where ,
" -o " , " remount " ,
NULL ) ;
else
r = - ENOENT ;
if ( r < 0 ) {
r = - ENOMEM ;
goto fail ;
}
2010-04-21 05:27:44 +04:00
mount_unwatch_control_pid ( m ) ;
2010-04-11 02:22:36 +04:00
2010-04-21 05:27:44 +04:00
if ( ( r = mount_spawn ( m , m - > control_command , & m - > control_pid ) ) < 0 )
2010-04-10 19:53:17 +04:00
goto fail ;
mount_set_state ( m , MOUNT_REMOUNTING ) ;
return ;
fail :
2010-08-12 00:04:22 +04:00
log_warning ( " %s failed to run 'remount' task: %s " , m - > meta . id , strerror ( - r ) ) ;
2010-04-10 19:53:17 +04:00
mount_enter_mounted ( m , false ) ;
}
static int mount_start ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
/* We cannot fulfill this request right now, try again later
* please ! */
if ( m - > state = = MOUNT_UNMOUNTING | |
m - > state = = MOUNT_UNMOUNTING_SIGTERM | |
m - > state = = MOUNT_UNMOUNTING_SIGKILL )
return - EAGAIN ;
/* Already on it! */
if ( m - > state = = MOUNT_MOUNTING | |
m - > state = = MOUNT_MOUNTING_SIGTERM | |
m - > state = = MOUNT_MOUNTING_SIGKILL )
return 0 ;
2010-08-31 02:23:34 +04:00
assert ( m - > state = = MOUNT_DEAD | | m - > state = = MOUNT_FAILED ) ;
2010-04-10 19:53:17 +04:00
m - > failure = false ;
2010-04-17 01:24:39 +04:00
mount_enter_mounting ( m ) ;
2010-04-10 19:53:17 +04:00
return 0 ;
}
static int mount_stop ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
/* Already on it */
if ( m - > state = = MOUNT_UNMOUNTING | |
m - > state = = MOUNT_UNMOUNTING_SIGKILL | |
m - > state = = MOUNT_UNMOUNTING_SIGTERM )
return 0 ;
2010-07-10 06:52:00 +04:00
assert ( m - > state = = MOUNT_MOUNTING | |
m - > state = = MOUNT_MOUNTING_DONE | |
m - > state = = MOUNT_MOUNTED | |
m - > state = = MOUNT_MOUNTING_SIGTERM | |
m - > state = = MOUNT_MOUNTING_SIGKILL | |
m - > state = = MOUNT_REMOUNTING | |
m - > state = = MOUNT_REMOUNTING_SIGTERM | |
m - > state = = MOUNT_REMOUNTING_SIGKILL ) ;
2010-04-10 19:53:17 +04:00
mount_enter_unmounting ( m , true ) ;
return 0 ;
}
static int mount_reload ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
if ( m - > state = = MOUNT_MOUNTING_DONE )
return - EAGAIN ;
assert ( m - > state = = MOUNT_MOUNTED ) ;
mount_enter_remounting ( m , true ) ;
return 0 ;
}
2010-04-21 05:27:44 +04:00
static int mount_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , mount_state_to_string ( m - > state ) ) ;
unit_serialize_item ( u , f , " failure " , yes_no ( m - > failure ) ) ;
if ( m - > control_pid > 0 )
2010-06-18 00:55:53 +04:00
unit_serialize_item_format ( u , f , " control-pid " , " %lu " , ( unsigned long ) m - > control_pid ) ;
2010-04-21 05:27:44 +04:00
if ( m - > control_command_id > = 0 )
unit_serialize_item ( u , f , " control-command " , mount_exec_command_to_string ( m - > control_command_id ) ) ;
return 0 ;
}
static int mount_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Mount * m = MOUNT ( u ) ;
assert ( u ) ;
assert ( key ) ;
assert ( value ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
MountState state ;
if ( ( state = mount_state_from_string ( value ) ) < 0 )
log_debug ( " Failed to parse state value %s " , value ) ;
else
m - > deserialized_state = state ;
} else if ( streq ( key , " failure " ) ) {
int b ;
if ( ( b = parse_boolean ( value ) ) < 0 )
log_debug ( " Failed to parse failure value %s " , value ) ;
else
m - > failure = b | | m - > failure ;
} else if ( streq ( key , " control-pid " ) ) {
2010-06-18 00:55:53 +04:00
pid_t pid ;
2010-04-21 05:27:44 +04:00
2010-08-12 00:04:22 +04:00
if ( parse_pid ( value , & pid ) < 0 )
2010-04-21 05:27:44 +04:00
log_debug ( " Failed to parse control-pid value %s " , value ) ;
else
2010-06-18 00:55:53 +04:00
m - > control_pid = pid ;
2010-04-21 05:27:44 +04:00
} else if ( streq ( key , " control-command " ) ) {
MountExecCommand id ;
if ( ( id = mount_exec_command_from_string ( value ) ) < 0 )
log_debug ( " Failed to parse exec-command value %s " , value ) ;
else {
m - > control_command_id = id ;
m - > control_command = m - > exec_command + id ;
}
} else
log_debug ( " Unknown serialization key '%s' " , key ) ;
return 0 ;
}
2010-04-10 19:53:17 +04:00
static UnitActiveState mount_active_state ( Unit * u ) {
assert ( u ) ;
return state_translation_table [ MOUNT ( u ) - > state ] ;
}
2010-04-13 22:59:01 +04:00
static const char * mount_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
2010-04-21 05:27:44 +04:00
return mount_state_to_string ( MOUNT ( u ) - > state ) ;
2010-04-13 22:59:01 +04:00
}
2010-04-21 08:01:13 +04:00
static bool mount_check_gc ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
return m - > from_etc_fstab | | m - > from_proc_self_mountinfo ;
}
2010-04-10 19:53:17 +04:00
static void mount_sigchld_event ( Unit * u , pid_t pid , int code , int status ) {
Mount * m = MOUNT ( u ) ;
bool success ;
assert ( m ) ;
assert ( pid > = 0 ) ;
2010-06-16 07:10:31 +04:00
if ( pid ! = m - > control_pid )
return ;
2010-04-10 19:53:17 +04:00
m - > control_pid = 0 ;
2010-06-16 07:10:31 +04:00
success = is_clean_exit ( code , status ) ;
m - > failure = m - > failure | | ! success ;
2010-04-21 05:27:44 +04:00
if ( m - > control_command ) {
2010-07-04 20:49:58 +04:00
exec_status_exit ( & m - > control_command - > exec_status , pid , code , status ) ;
2010-04-21 05:27:44 +04:00
m - > control_command = NULL ;
m - > control_command_id = _MOUNT_EXEC_COMMAND_INVALID ;
}
2010-07-17 06:17:30 +04:00
log_full ( success ? LOG_DEBUG : LOG_NOTICE ,
" %s mount process exited, code=%s status=%i " , u - > meta . id , sigchld_code_to_string ( code ) , status ) ;
2010-04-10 19:53:17 +04:00
/* Note that mount(8) returning and the kernel sending us a
* mount table change event might happen out - of - order . If an
* operation succeed we assume the kernel will follow soon too
* and already change into the resulting state . If it fails
* we check if the kernel still knows about the mount . and
* change state accordingly . */
switch ( m - > state ) {
case MOUNT_MOUNTING :
case MOUNT_MOUNTING_DONE :
case MOUNT_MOUNTING_SIGKILL :
case MOUNT_MOUNTING_SIGTERM :
case MOUNT_REMOUNTING :
case MOUNT_REMOUNTING_SIGKILL :
case MOUNT_REMOUNTING_SIGTERM :
2010-05-21 05:32:58 +04:00
if ( success )
2010-04-10 19:53:17 +04:00
mount_enter_mounted ( m , true ) ;
else if ( m - > from_proc_self_mountinfo )
mount_enter_mounted ( m , false ) ;
else
mount_enter_dead ( m , false ) ;
break ;
case MOUNT_UNMOUNTING :
case MOUNT_UNMOUNTING_SIGKILL :
case MOUNT_UNMOUNTING_SIGTERM :
if ( success )
mount_enter_dead ( m , true ) ;
else if ( m - > from_proc_self_mountinfo )
mount_enter_mounted ( m , false ) ;
else
mount_enter_dead ( m , false ) ;
break ;
default :
assert_not_reached ( " Uh, control process died at wrong time. " ) ;
}
2010-08-20 04:26:05 +04:00
/* Notify clients about changed exit status */
unit_add_to_dbus_queue ( u ) ;
2010-04-10 19:53:17 +04:00
}
static void mount_timer_event ( Unit * u , uint64_t elapsed , Watch * w ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
assert ( elapsed = = 1 ) ;
assert ( w = = & m - > timer_watch ) ;
switch ( m - > state ) {
case MOUNT_MOUNTING :
case MOUNT_MOUNTING_DONE :
2010-04-15 05:11:11 +04:00
log_warning ( " %s mounting timed out. Stopping. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_MOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_REMOUNTING :
2010-04-15 05:11:11 +04:00
log_warning ( " %s remounting timed out. Stopping. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_REMOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_UNMOUNTING :
2010-04-15 05:11:11 +04:00
log_warning ( " %s unmounting timed out. Stopping. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_UNMOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_MOUNTING_SIGTERM :
2010-04-15 05:11:11 +04:00
log_warning ( " %s mounting timed out. Killing. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_MOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_REMOUNTING_SIGTERM :
2010-04-15 05:11:11 +04:00
log_warning ( " %s remounting timed out. Killing. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_REMOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_UNMOUNTING_SIGTERM :
2010-04-15 05:11:11 +04:00
log_warning ( " %s unmounting timed out. Killing. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
mount_enter_signal ( m , MOUNT_UNMOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_MOUNTING_SIGKILL :
case MOUNT_REMOUNTING_SIGKILL :
case MOUNT_UNMOUNTING_SIGKILL :
2010-04-15 05:11:11 +04:00
log_warning ( " %s mount process still around after SIGKILL. Ignoring. " , u - > meta . id ) ;
2010-04-10 19:53:17 +04:00
if ( m - > from_proc_self_mountinfo )
mount_enter_mounted ( m , false ) ;
else
mount_enter_dead ( m , false ) ;
break ;
default :
assert_not_reached ( " Timeout at wrong time. " ) ;
}
}
static int mount_add_one (
Manager * m ,
const char * what ,
const char * where ,
const char * options ,
const char * fstype ,
bool from_proc_self_mountinfo ,
bool set_flags ) {
2010-01-29 04:07:41 +03:00
int r ;
Unit * u ;
bool delete ;
2010-04-10 19:53:17 +04:00
char * e , * w = NULL , * o = NULL , * f = NULL ;
2010-05-14 04:29:45 +04:00
MountParameters * p ;
2010-01-29 04:07:41 +03:00
2010-01-29 05:18:09 +03:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
assert ( what ) ;
assert ( where ) ;
2010-04-10 19:53:17 +04:00
assert ( options ) ;
assert ( fstype ) ;
assert ( ! set_flags | | from_proc_self_mountinfo ) ;
/* Ignore API mount points. They should never be referenced in
* dependencies ever . */
if ( mount_point_is_api ( where ) )
return 0 ;
2010-01-29 04:07:41 +03:00
2010-04-17 01:24:39 +04:00
if ( streq ( fstype , " autofs " ) )
return 0 ;
2010-05-14 04:29:45 +04:00
/* probably some kind of swap, ignore */
if ( ! is_path ( where ) )
2010-01-29 04:07:41 +03:00
return 0 ;
2010-04-21 05:27:44 +04:00
if ( ! ( e = unit_name_from_path ( where , " .mount " ) ) )
2010-01-29 04:07:41 +03:00
return - ENOMEM ;
if ( ! ( u = manager_get_unit ( m , e ) ) ) {
delete = true ;
if ( ! ( u = unit_new ( m ) ) ) {
free ( e ) ;
return - ENOMEM ;
}
r = unit_add_name ( u , e ) ;
free ( e ) ;
if ( r < 0 )
goto fail ;
2010-04-10 19:53:17 +04:00
if ( ! ( MOUNT ( u ) - > where = strdup ( where ) ) ) {
2010-05-09 20:44:11 +04:00
r = - ENOMEM ;
goto fail ;
}
2010-01-29 05:18:09 +03:00
2010-01-29 08:45:59 +03:00
unit_add_to_load_queue ( u ) ;
2010-01-29 04:07:41 +03:00
} else {
delete = false ;
free ( e ) ;
}
2010-04-10 19:53:17 +04:00
if ( ! ( w = strdup ( what ) ) | |
! ( o = strdup ( options ) ) | |
! ( f = strdup ( fstype ) ) ) {
r = - ENOMEM ;
goto fail ;
}
if ( from_proc_self_mountinfo ) {
2010-05-14 04:29:45 +04:00
p = & MOUNT ( u ) - > parameters_proc_self_mountinfo ;
2010-04-10 19:53:17 +04:00
if ( set_flags ) {
MOUNT ( u ) - > is_mounted = true ;
MOUNT ( u ) - > just_mounted = ! MOUNT ( u ) - > from_proc_self_mountinfo ;
2010-05-14 04:29:45 +04:00
MOUNT ( u ) - > just_changed = ! streq_ptr ( p - > options , o ) ;
2010-04-10 19:53:17 +04:00
}
2010-01-29 08:04:08 +03:00
2010-01-29 05:18:09 +03:00
MOUNT ( u ) - > from_proc_self_mountinfo = true ;
2010-01-29 08:04:08 +03:00
} else {
2010-05-14 04:29:45 +04:00
p = & MOUNT ( u ) - > parameters_etc_fstab ;
2010-01-29 05:18:09 +03:00
MOUNT ( u ) - > from_etc_fstab = true ;
2010-01-29 08:04:08 +03:00
}
2010-01-29 05:18:09 +03:00
2010-05-14 04:29:45 +04:00
free ( p - > what ) ;
p - > what = w ;
2010-01-29 04:07:41 +03:00
2010-05-14 04:29:45 +04:00
free ( p - > options ) ;
p - > options = o ;
2010-04-10 19:53:17 +04:00
2010-05-14 04:29:45 +04:00
free ( p - > fstype ) ;
p - > fstype = f ;
2010-01-29 04:07:41 +03:00
2010-02-05 02:38:41 +03:00
unit_add_to_dbus_queue ( u ) ;
2010-01-29 04:07:41 +03:00
return 0 ;
fail :
2010-04-10 19:53:17 +04:00
free ( w ) ;
free ( o ) ;
free ( f ) ;
2010-01-29 04:07:41 +03:00
if ( delete & & u )
unit_free ( u ) ;
2010-05-14 04:29:45 +04:00
return r ;
2010-01-29 04:07:41 +03:00
}
static char * fstab_node_to_udev_node ( char * p ) {
2010-08-20 04:46:15 +04:00
char * dn , * t , * u ;
2010-01-29 04:07:41 +03:00
int r ;
/* FIXME: to follow udev's logic 100% we need to leave valid
* UTF8 chars unescaped */
if ( startswith ( p , " LABEL= " ) ) {
2010-09-16 02:36:41 +04:00
if ( ! ( u = unquote ( p + 6 , " \" \' " ) ) )
2010-08-20 04:46:15 +04:00
return NULL ;
t = xescape ( u , " / " ) ;
free ( u ) ;
if ( ! t )
2010-01-29 04:07:41 +03:00
return NULL ;
2010-01-29 05:18:09 +03:00
r = asprintf ( & dn , " /dev/disk/by-label/%s " , t ) ;
2010-01-29 04:07:41 +03:00
free ( t ) ;
if ( r < 0 )
return NULL ;
return dn ;
}
if ( startswith ( p , " UUID= " ) ) {
2010-09-16 02:36:41 +04:00
if ( ! ( u = unquote ( p + 5 , " \" \' " ) ) )
2010-08-20 04:46:15 +04:00
return NULL ;
t = xescape ( u , " / " ) ;
free ( u ) ;
if ( ! t )
2010-01-29 04:07:41 +03:00
return NULL ;
2010-01-29 05:18:09 +03:00
r = asprintf ( & dn , " /dev/disk/by-uuid/%s " , ascii_strlower ( t ) ) ;
2010-01-29 04:07:41 +03:00
free ( t ) ;
if ( r < 0 )
return NULL ;
return dn ;
}
return strdup ( p ) ;
}
2010-05-09 20:44:11 +04:00
static int mount_find_pri ( char * options ) {
char * end , * pri ;
unsigned long r ;
if ( ! ( pri = mount_test_option ( options , " pri= " ) ) )
return 0 ;
pri + = 4 ;
errno = 0 ;
r = strtoul ( pri , & end , 10 ) ;
if ( errno ! = 0 )
return - errno ;
if ( end = = pri | | ( * end ! = ' , ' & & * end ! = 0 ) )
return - EINVAL ;
return ( int ) r ;
}
2010-04-10 19:53:17 +04:00
static int mount_load_etc_fstab ( Manager * m ) {
2010-01-29 04:07:41 +03:00
FILE * f ;
int r ;
struct mntent * me ;
assert ( m ) ;
errno = 0 ;
if ( ! ( f = setmntent ( " /etc/fstab " , " r " ) ) )
return - errno ;
while ( ( me = getmntent ( f ) ) ) {
char * where , * what ;
if ( ! ( what = fstab_node_to_udev_node ( me - > mnt_fsname ) ) ) {
r = - ENOMEM ;
goto finish ;
}
if ( ! ( where = strdup ( me - > mnt_dir ) ) ) {
free ( what ) ;
r = - ENOMEM ;
goto finish ;
}
if ( what [ 0 ] = = ' / ' )
path_kill_slashes ( what ) ;
if ( where [ 0 ] = = ' / ' )
path_kill_slashes ( where ) ;
2010-05-09 20:44:11 +04:00
if ( streq ( me - > mnt_type , " swap " ) ) {
int pri ;
if ( ( pri = mount_find_pri ( me - > mnt_opts ) ) < 0 )
r = pri ;
else
r = swap_add_one ( m ,
what ,
pri ,
2010-05-14 04:29:45 +04:00
! ! mount_test_option ( me - > mnt_opts , MNTOPT_NOAUTO ) ,
2010-08-25 22:37:04 +04:00
! ! mount_test_option ( me - > mnt_opts , " nofail " ) ,
2010-05-14 04:29:45 +04:00
! ! mount_test_option ( me - > mnt_opts , " comment=systemd.swapon " ) ,
2010-05-09 20:44:11 +04:00
false ) ;
} else
r = mount_add_one ( m , what , where , me - > mnt_opts , me - > mnt_type , false , false ) ;
2010-01-29 04:07:41 +03:00
free ( what ) ;
free ( where ) ;
if ( r < 0 )
goto finish ;
}
r = 0 ;
finish :
endmntent ( f ) ;
return r ;
}
2010-01-29 08:04:08 +03:00
static int mount_load_proc_self_mountinfo ( Manager * m , bool set_flags ) {
2010-01-29 04:07:41 +03:00
int r ;
2010-06-03 01:03:39 +04:00
char * device , * path , * options , * options2 , * fstype , * d , * p , * o ;
2010-01-29 04:07:41 +03:00
assert ( m ) ;
2010-01-29 08:04:08 +03:00
rewind ( m - > proc_self_mountinfo ) ;
2010-01-29 04:07:41 +03:00
for ( ; ; ) {
int k ;
2010-04-10 19:53:17 +04:00
2010-06-03 01:03:39 +04:00
device = path = options = options2 = fstype = d = p = o = NULL ;
2010-01-29 04:07:41 +03:00
2010-01-29 08:04:08 +03:00
if ( ( k = fscanf ( m - > proc_self_mountinfo ,
2010-01-29 04:07:41 +03:00
" %*s " /* (1) mount id */
" %*s " /* (2) parent id */
" %*s " /* (3) major:minor */
" %*s " /* (4) root */
" %ms " /* (5) mount point */
2010-04-10 19:53:17 +04:00
" %ms " /* (6) mount options */
2010-01-29 04:07:41 +03:00
" %*[^-] " /* (7) optional fields */
" - " /* (8) seperator */
2010-04-10 19:53:17 +04:00
" %ms " /* (9) file system type */
2010-01-29 08:04:08 +03:00
" %ms " /* (10) mount source */
2010-06-03 01:03:39 +04:00
" %ms " /* (11) mount options 2 */
2010-01-29 08:04:08 +03:00
" %*[^ \n ] " , /* some rubbish at the end */
2010-01-29 04:07:41 +03:00
& path ,
2010-04-10 19:53:17 +04:00
& options ,
& fstype ,
2010-06-03 01:03:39 +04:00
& device ,
& options2 ) ) ! = 5 ) {
2010-01-29 04:07:41 +03:00
2010-01-29 08:04:08 +03:00
if ( k = = EOF )
break ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
r = - EBADMSG ;
goto finish ;
2010-01-29 04:07:41 +03:00
}
2010-06-03 01:03:39 +04:00
if ( asprintf ( & o , " %s,%s " , options , options2 ) < 0 ) {
r = - ENOMEM ;
goto finish ;
}
2010-04-10 19:53:17 +04:00
if ( ! ( d = cunescape ( device ) ) | |
! ( p = cunescape ( path ) ) ) {
r = - ENOMEM ;
goto finish ;
2010-01-29 04:07:41 +03:00
}
2010-06-03 01:03:39 +04:00
if ( ( r = mount_add_one ( m , d , p , o , fstype , true , set_flags ) ) < 0 )
2010-04-10 19:53:17 +04:00
goto finish ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
free ( device ) ;
free ( path ) ;
free ( options ) ;
2010-06-03 01:03:39 +04:00
free ( options2 ) ;
2010-04-10 19:53:17 +04:00
free ( fstype ) ;
2010-01-29 04:07:41 +03:00
free ( d ) ;
free ( p ) ;
2010-06-03 01:03:39 +04:00
free ( o ) ;
2010-01-29 04:07:41 +03:00
}
2010-04-10 19:53:17 +04:00
r = 0 ;
finish :
free ( device ) ;
free ( path ) ;
free ( options ) ;
2010-06-03 01:03:39 +04:00
free ( options2 ) ;
2010-04-10 19:53:17 +04:00
free ( fstype ) ;
free ( d ) ;
free ( p ) ;
2010-06-03 01:03:39 +04:00
free ( o ) ;
2010-04-10 19:53:17 +04:00
return r ;
}
static void mount_shutdown ( Manager * m ) {
assert ( m ) ;
2010-04-21 05:27:44 +04:00
if ( m - > proc_self_mountinfo ) {
2010-04-10 19:53:17 +04:00
fclose ( m - > proc_self_mountinfo ) ;
2010-04-21 05:27:44 +04:00
m - > proc_self_mountinfo = NULL ;
}
2010-01-29 04:07:41 +03:00
}
static int mount_enumerate ( Manager * m ) {
int r ;
2010-01-29 08:04:08 +03:00
struct epoll_event ev ;
2010-01-29 04:07:41 +03:00
assert ( m ) ;
2010-04-21 05:27:44 +04:00
if ( ! m - > proc_self_mountinfo ) {
if ( ! ( m - > proc_self_mountinfo = fopen ( " /proc/self/mountinfo " , " re " ) ) )
return - errno ;
2010-01-29 08:04:08 +03:00
2010-04-21 05:27:44 +04:00
m - > mount_watch . type = WATCH_MOUNT ;
m - > mount_watch . fd = fileno ( m - > proc_self_mountinfo ) ;
2010-01-29 08:04:08 +03:00
2010-04-21 05:27:44 +04:00
zero ( ev ) ;
ev . events = EPOLLERR ;
ev . data . ptr = & m - > mount_watch ;
2010-01-29 08:04:08 +03:00
2010-04-21 05:27:44 +04:00
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > mount_watch . fd , & ev ) < 0 )
return - errno ;
}
2010-01-29 08:04:08 +03:00
2010-04-10 19:53:17 +04:00
if ( ( r = mount_load_etc_fstab ( m ) ) < 0 )
2010-01-29 04:07:41 +03:00
goto fail ;
2010-01-29 08:04:08 +03:00
if ( ( r = mount_load_proc_self_mountinfo ( m , false ) ) < 0 )
2010-01-29 04:07:41 +03:00
goto fail ;
return 0 ;
fail :
mount_shutdown ( m ) ;
return r ;
2010-01-23 03:52:57 +03:00
}
2010-01-29 08:04:08 +03:00
void mount_fd_event ( Manager * m , int events ) {
Meta * meta ;
int r ;
assert ( m ) ;
2010-01-29 08:45:59 +03:00
assert ( events = = EPOLLERR ) ;
2010-01-29 08:04:08 +03:00
/* The manager calls this for every fd event happening on the
* / proc / self / mountinfo file , which informs us about mounting
* table changes */
if ( ( r = mount_load_proc_self_mountinfo ( m , true ) ) < 0 ) {
2010-08-12 00:04:22 +04:00
log_error ( " Failed to reread /proc/self/mountinfo: %s " , strerror ( - r ) ) ;
2010-04-10 19:53:17 +04:00
/* Reset flags, just in case, for later calls */
LIST_FOREACH ( units_per_type , meta , m - > units_per_type [ UNIT_MOUNT ] ) {
Mount * mount = ( Mount * ) meta ;
mount - > is_mounted = mount - > just_mounted = mount - > just_changed = false ;
}
2010-01-29 08:04:08 +03:00
return ;
}
manager_dispatch_load_queue ( m ) ;
LIST_FOREACH ( units_per_type , meta , m - > units_per_type [ UNIT_MOUNT ] ) {
Mount * mount = ( Mount * ) meta ;
2010-04-10 19:53:17 +04:00
if ( ! mount - > is_mounted ) {
/* This has just been unmounted. */
2010-01-29 08:04:08 +03:00
mount - > from_proc_self_mountinfo = false ;
2010-04-10 19:53:17 +04:00
switch ( mount - > state ) {
case MOUNT_MOUNTED :
mount_enter_dead ( mount , true ) ;
break ;
default :
mount_set_state ( mount , mount - > state ) ;
break ;
}
} else if ( mount - > just_mounted | | mount - > just_changed ) {
/* New or changed entrymount */
switch ( mount - > state ) {
case MOUNT_DEAD :
2010-08-31 02:23:34 +04:00
case MOUNT_FAILED :
2010-04-10 19:53:17 +04:00
mount_enter_mounted ( mount , true ) ;
break ;
case MOUNT_MOUNTING :
2010-04-17 01:24:39 +04:00
mount_enter_mounting_done ( mount ) ;
2010-04-10 19:53:17 +04:00
break ;
default :
/* Nothing really changed, but let's
* issue an notification call
* nonetheless , in case somebody is
* waiting for this . ( e . g . file system
* ro / rw remounts . ) */
mount_set_state ( mount , mount - > state ) ;
break ;
}
}
/* Reset the flags for later calls */
mount - > is_mounted = mount - > just_mounted = mount - > just_changed = false ;
}
}
2010-08-31 02:23:34 +04:00
static void mount_reset_failed ( Unit * u ) {
2010-07-18 06:58:01 +04:00
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
2010-08-31 02:23:34 +04:00
if ( m - > state = = MOUNT_FAILED )
2010-07-18 06:58:01 +04:00
mount_set_state ( m , MOUNT_DEAD ) ;
m - > failure = false ;
}
2010-04-21 05:27:44 +04:00
static const char * const mount_state_table [ _MOUNT_STATE_MAX ] = {
[ MOUNT_DEAD ] = " dead " ,
[ MOUNT_MOUNTING ] = " mounting " ,
[ MOUNT_MOUNTING_DONE ] = " mounting-done " ,
[ MOUNT_MOUNTED ] = " mounted " ,
[ MOUNT_REMOUNTING ] = " remounting " ,
[ MOUNT_UNMOUNTING ] = " unmounting " ,
[ MOUNT_MOUNTING_SIGTERM ] = " mounting-sigterm " ,
[ MOUNT_MOUNTING_SIGKILL ] = " mounting-sigkill " ,
[ MOUNT_REMOUNTING_SIGTERM ] = " remounting-sigterm " ,
[ MOUNT_REMOUNTING_SIGKILL ] = " remounting-sigkill " ,
[ MOUNT_UNMOUNTING_SIGTERM ] = " unmounting-sigterm " ,
[ MOUNT_UNMOUNTING_SIGKILL ] = " unmounting-sigkill " ,
2010-08-31 02:23:34 +04:00
[ MOUNT_FAILED ] = " failed "
2010-04-21 05:27:44 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( mount_state , MountState ) ;
static const char * const mount_exec_command_table [ _MOUNT_EXEC_COMMAND_MAX ] = {
[ MOUNT_EXEC_MOUNT ] = " ExecMount " ,
[ MOUNT_EXEC_UNMOUNT ] = " ExecUnmount " ,
[ MOUNT_EXEC_REMOUNT ] = " ExecRemount " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( mount_exec_command , MountExecCommand ) ;
2010-01-26 23:39:06 +03:00
const UnitVTable mount_vtable = {
2010-01-23 03:52:57 +03:00
. suffix = " .mount " ,
2010-04-10 19:53:17 +04:00
. no_alias = true ,
2010-04-15 05:11:11 +04:00
. no_instances = true ,
2010-04-22 04:42:59 +04:00
. no_isolate = true ,
2010-07-07 02:00:59 +04:00
. show_status = true ,
2010-04-10 19:53:17 +04:00
. init = mount_init ,
. load = mount_load ,
2010-01-26 06:18:44 +03:00
. done = mount_done ,
2010-04-10 19:53:17 +04:00
2010-01-29 05:18:09 +03:00
. coldplug = mount_coldplug ,
2010-01-26 06:18:44 +03:00
. dump = mount_dump ,
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
. start = mount_start ,
. stop = mount_stop ,
. reload = mount_reload ,
2010-04-21 05:27:44 +04:00
. serialize = mount_serialize ,
. deserialize_item = mount_deserialize_item ,
2010-01-29 05:18:09 +03:00
. active_state = mount_active_state ,
2010-04-13 22:59:01 +04:00
. sub_state_to_string = mount_sub_state_to_string ,
2010-01-29 04:07:41 +03:00
2010-04-21 08:01:13 +04:00
. check_gc = mount_check_gc ,
2010-04-10 19:53:17 +04:00
. sigchld_event = mount_sigchld_event ,
. timer_event = mount_timer_event ,
2010-08-31 02:23:34 +04:00
. reset_failed = mount_reset_failed ,
2010-07-18 06:58:01 +04:00
2010-08-20 04:26:05 +04:00
. bus_interface = " org.freedesktop.systemd1.Mount " ,
2010-04-18 05:08:16 +04:00
. bus_message_handler = bus_mount_message_handler ,
2010-08-20 04:26:05 +04:00
. bus_invalidating_properties = bus_mount_invalidating_properties ,
2010-04-18 05:08:16 +04:00
2010-01-29 05:18:09 +03:00
. enumerate = mount_enumerate ,
. shutdown = mount_shutdown
2010-01-23 03:52:57 +03:00
} ;