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-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-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-04-10 19:53:17 +04:00
[ MOUNT_REMOUNTING ] = UNIT_ACTIVE_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 ,
[ MOUNT_REMOUNTING_SIGTERM ] = UNIT_ACTIVE_RELOADING ,
[ MOUNT_REMOUNTING_SIGKILL ] = UNIT_ACTIVE_RELOADING ,
[ MOUNT_UNMOUNTING_SIGTERM ] = UNIT_DEACTIVATING ,
[ MOUNT_UNMOUNTING_SIGKILL ] = UNIT_DEACTIVATING ,
2010-01-29 05:18:09 +03:00
[ MOUNT_MAINTAINANCE ] = UNIT_INACTIVE ,
} ;
2010-01-23 03:52:57 +03:00
2010-01-29 05:18:09 +03:00
static const char * const state_string_table [ _MOUNT_STATE_MAX ] = {
[ MOUNT_DEAD ] = " dead " ,
[ MOUNT_MOUNTING ] = " mounting " ,
2010-04-10 19:53:17 +04:00
[ MOUNT_MOUNTING_DONE ] = " mounting-done " ,
2010-01-29 05:18:09 +03:00
[ MOUNT_MOUNTED ] = " mounted " ,
2010-04-10 19:53:17 +04:00
[ MOUNT_REMOUNTING ] = " remounting " ,
2010-01-29 05:18:09 +03:00
[ MOUNT_UNMOUNTING ] = " unmounting " ,
2010-04-10 19:53:17 +04:00
[ 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-01-29 05:18:09 +03:00
[ MOUNT_MAINTAINANCE ] = " maintainance "
} ;
2010-01-23 03:52:57 +03:00
2010-04-11 02:22:36 +04:00
static void service_unwatch_control_pid ( Mount * m ) {
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-11 02:22:36 +04:00
service_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-04-10 19:53:17 +04:00
static void mount_init ( Unit * u ) {
2010-01-29 05:18:09 +03:00
Mount * m = MOUNT ( u ) ;
2010-04-10 19:53:17 +04:00
assert ( u ) ;
assert ( u - > meta . load_state = = UNIT_STUB ) ;
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
m - > state = 0 ;
m - > from_etc_fstab = false ;
m - > from_proc_self_mountinfo = false ;
m - > from_fragment = false ;
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
m - > is_mounted = false ;
m - > just_mounted = false ;
m - > just_changed = false ;
2010-01-29 05:18:09 +03:00
2010-04-10 19:53:17 +04:00
m - > timeout_usec = DEFAULT_TIMEOUT_USEC ;
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
zero ( m - > exec_command ) ;
exec_context_init ( & m - > exec_context ) ;
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
m - > kill_mode = 0 ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
m - > control_pid = 0 ;
m - > failure = false ;
2010-01-29 08:04:08 +03:00
2010-04-10 19:53:17 +04:00
m - > timer_watch . type = WATCH_INVALID ;
2010-01-29 04:07:41 +03:00
}
static int mount_add_node_links ( Mount * m ) {
Unit * device ;
char * e ;
int r ;
2010-04-10 19:53:17 +04:00
const char * what ;
2010-01-29 04:07:41 +03:00
assert ( m ) ;
/* Adds in links to the device that this node is based on */
2010-04-10 19:53:17 +04:00
if ( m - > parameters_fragment . what )
what = m - > parameters_fragment . what ;
else if ( m - > parameters_etc_fstab . what )
what = m - > parameters_etc_fstab . what ;
else
/* We observe kernel mounts only while they are live,
* hence don ' t create any links for them */
return 0 ;
if ( ! path_startswith ( what , " /dev/ " ) )
2010-01-29 04:07:41 +03:00
return 0 ;
2010-04-10 19:53:17 +04:00
if ( ! ( e = unit_name_escape_path ( what + 1 , " .device " ) ) )
2010-01-29 04:07:41 +03:00
return - ENOMEM ;
r = manager_load_unit ( UNIT ( m ) - > meta . manager , e , & device ) ;
free ( e ) ;
if ( r < 0 )
return r ;
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_AFTER , device ) ) < 0 )
return r ;
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_REQUIRES , device ) ) < 0 )
return r ;
2010-04-10 19:53:17 +04:00
if ( UNIT ( m ) - > meta . manager - > running_as = = MANAGER_INIT | |
UNIT ( m ) - > meta . manager - > running_as = = MANAGER_SYSTEM )
if ( ( r = unit_add_dependency ( device , UNIT_WANTS , UNIT ( m ) ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
return 0 ;
}
static int mount_add_path_links ( Mount * m ) {
2010-01-29 08:04:08 +03:00
Meta * other ;
2010-01-29 04:07:41 +03:00
int r ;
2010-04-10 19:53:17 +04:00
assert ( m ) ;
2010-01-29 04:07:41 +03:00
/* Adds in link to other mount points, that might lie below or
* above us in the hierarchy */
2010-01-29 08:04:08 +03:00
LIST_FOREACH ( units_per_type , other , UNIT ( m ) - > meta . manager - > units_per_type [ UNIT_MOUNT ] ) {
2010-01-29 04:07:41 +03:00
Mount * n ;
2010-01-29 08:04:08 +03:00
n = ( Mount * ) other ;
2010-01-29 04:07:41 +03:00
2010-01-29 08:04:08 +03:00
if ( n = = m )
2010-02-14 03:09:22 +03:00
continue ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
if ( m - > meta . load_state ! = UNIT_LOADED )
continue ;
2010-01-29 04:07:41 +03:00
if ( path_startswith ( m - > where , n - > where ) ) {
2010-04-10 19:53:17 +04:00
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_AFTER , UNIT ( other ) ) ) < 0 )
2010-01-29 04:07:41 +03:00
return r ;
2010-04-10 19:53:17 +04:00
if ( n - > from_etc_fstab | | n - > from_fragment )
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_REQUIRES , UNIT ( other ) ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
} else if ( path_startswith ( n - > where , m - > where ) ) {
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
if ( ( r = unit_add_dependency ( UNIT ( m ) , UNIT_BEFORE , UNIT ( other ) ) ) < 0 )
2010-01-29 04:07:41 +03:00
return r ;
2010-04-10 19:53:17 +04:00
if ( m - > from_etc_fstab | | m - > from_fragment )
if ( ( r = unit_add_dependency ( UNIT ( other ) , UNIT_REQUIRES , UNIT ( m ) ) ) < 0 )
return r ;
2010-01-29 04:07:41 +03:00
}
}
return 0 ;
}
2010-04-10 19:53:17 +04:00
static bool mount_test_option ( const char * haystack , const char * needle ) {
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 ;
return ! ! hasmntopt ( & me , needle ) ;
}
static int mount_add_target_links ( Mount * m ) {
const char * target ;
MountParameters * p ;
Unit * u ;
int r ;
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 - > fstype )
return 0 ;
if ( mount_test_option ( p - > options , MNTOPT_NOAUTO ) )
return 0 ;
if ( mount_test_option ( p - > options , " _netdev " ) | |
fstype_is_network ( p - > fstype ) )
target = SPECIAL_REMOTE_FS_TARGET ;
else
target = SPECIAL_LOCAL_FS_TARGET ;
if ( ( r = manager_load_unit ( UNIT ( m ) - > meta . manager , target , & u ) ) < 0 )
return r ;
if ( ( r = unit_add_dependency ( u , UNIT_WANTS , UNIT ( m ) ) ) < 0 )
return r ;
return unit_add_dependency ( UNIT ( m ) , UNIT_BEFORE , u ) ;
}
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 ) {
/* Minor validity checking */
if ( ( m - > parameters_fragment . options | | m - > parameters_fragment . fstype ) & & ! m - > parameters_fragment . what )
return - EBADMSG ;
if ( m - > parameters_fragment . what )
m - > from_fragment = true ;
if ( ( r = mount_add_node_links ( MOUNT ( u ) ) ) < 0 )
return r ;
if ( ( r = mount_add_path_links ( MOUNT ( u ) ) ) < 0 )
return r ;
if ( ( r = mount_add_target_links ( MOUNT ( u ) ) ) < 0 )
return r ;
if ( ( r = unit_add_default_cgroup ( u ) ) < 0 )
return r ;
}
return 0 ;
}
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-11 02:22:36 +04:00
service_unwatch_control_pid ( m ) ;
2010-04-10 19:53:17 +04:00
m - > control_command = NULL ;
}
if ( state ! = old_state )
log_debug ( " %s changed %s → %s " , unit_id ( UNIT ( m ) ) , state_string_table [ old_state ] , state_string_table [ state ] ) ;
unit_notify ( UNIT ( m ) , state_translation_table [ old_state ] , state_translation_table [ state ] ) ;
}
static int mount_coldplug ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
assert ( m - > state = = MOUNT_DEAD ) ;
if ( m - > from_proc_self_mountinfo )
mount_set_state ( m , MOUNT_MOUNTED ) ;
return 0 ;
}
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 ,
& m - > exec_context ,
NULL , 0 ,
true ,
true ,
2010-04-13 04:06:27 +04:00
UNIT ( m ) - > meta . manager - > confirm_spawn ,
2010-04-10 19:53:17 +04:00
UNIT ( m ) - > meta . cgroup_bondings ,
& 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 ;
}
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 "
" %sKillMode: %s \n " ,
prefix , state_string_table [ m - > state ] ,
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 ) ,
prefix , kill_mode_to_string ( m - > kill_mode ) ) ;
if ( m - > control_pid > 0 )
fprintf ( f ,
" %sControl PID: %llu \n " ,
prefix , ( unsigned long long ) m - > control_pid ) ;
exec_context_dump ( & m - > exec_context , f , prefix ) ;
}
static void mount_enter_dead ( Mount * m , bool success ) {
assert ( m ) ;
if ( ! success )
m - > failure = true ;
mount_set_state ( m , m - > failure ? MOUNT_MAINTAINANCE : MOUNT_DEAD ) ;
}
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-04-13 04:06:27 +04:00
bool sent = false ;
2010-04-10 19:53:17 +04:00
assert ( m ) ;
if ( ! success )
m - > failure = true ;
2010-04-13 04:06:27 +04:00
if ( m - > kill_mode ! = KILL_NONE ) {
int sig = ( state = = MOUNT_MOUNTING_SIGTERM | |
state = = MOUNT_UNMOUNTING_SIGTERM | |
state = = MOUNT_REMOUNTING_SIGTERM ) ? SIGTERM : SIGKILL ;
2010-04-10 19:53:17 +04:00
if ( m - > kill_mode = = KILL_CONTROL_GROUP ) {
if ( ( r = cgroup_bonding_kill_list ( UNIT ( m ) - > meta . cgroup_bondings , sig ) ) < 0 ) {
if ( r ! = - EAGAIN & & r ! = - ESRCH )
goto fail ;
} else
sent = true ;
}
2010-04-13 04:06:27 +04:00
if ( ! sent & & m - > control_pid > 0 )
2010-04-10 19:53:17 +04:00
if ( kill ( m - > kill_mode = = KILL_PROCESS ? m - > control_pid : - m - > control_pid , sig ) < 0 & & errno ! = ESRCH ) {
r = - errno ;
goto fail ;
}
}
2010-04-13 04:06:27 +04:00
if ( sent ) {
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 :
log_warning ( " %s failed to kill processes: %s " , unit_id ( UNIT ( m ) ) , strerror ( - r ) ) ;
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-04-10 19:53:17 +04:00
}
static void mount_enter_unmounting ( Mount * m , bool success ) {
ExecCommand * c ;
int r ;
assert ( m ) ;
if ( ! success )
m - > failure = true ;
m - > control_command = c = m - > exec_command + MOUNT_EXEC_UNMOUNT ;
if ( ( r = exec_command_set (
c ,
" /bin/umount " ,
m - > where ,
NULL ) ) < 0 )
goto fail ;
2010-04-11 02:22:36 +04:00
service_unwatch_control_pid ( m ) ;
2010-04-10 19:53:17 +04:00
if ( ( r = mount_spawn ( m , c , & m - > control_pid ) ) < 0 )
goto fail ;
mount_set_state ( m , MOUNT_UNMOUNTING ) ;
return ;
fail :
log_warning ( " %s failed to run umount exectuable: %s " , unit_id ( UNIT ( m ) ) , strerror ( - r ) ) ;
mount_enter_mounted ( m , false ) ;
}
static void mount_enter_mounting ( Mount * m , bool success ) {
ExecCommand * c ;
int r ;
assert ( m ) ;
if ( ! success )
m - > failure = true ;
m - > control_command = c = m - > exec_command + MOUNT_EXEC_MOUNT ;
if ( m - > from_fragment )
r = exec_command_set (
c ,
" /bin/mount " ,
m - > parameters_fragment . what ,
m - > where ,
" -t " , m - > parameters_fragment . fstype ,
" -o " , m - > parameters_fragment . options ,
NULL ) ;
else if ( m - > from_etc_fstab )
r = exec_command_set (
c ,
" /bin/mount " ,
m - > where ,
NULL ) ;
else
r = - ENOENT ;
if ( r < 0 )
goto fail ;
2010-04-11 02:22:36 +04:00
service_unwatch_control_pid ( m ) ;
2010-04-10 19:53:17 +04:00
if ( ( r = mount_spawn ( m , c , & m - > control_pid ) ) < 0 )
goto fail ;
mount_set_state ( m , MOUNT_MOUNTING ) ;
return ;
fail :
log_warning ( " %s failed to run mount exectuable: %s " , unit_id ( UNIT ( m ) ) , strerror ( - r ) ) ;
mount_enter_dead ( m , false ) ;
}
static void mount_enter_mounting_done ( Mount * m , bool success ) {
assert ( m ) ;
if ( ! success )
m - > failure = true ;
mount_set_state ( m , MOUNT_MOUNTING_DONE ) ;
}
static void mount_enter_remounting ( Mount * m , bool success ) {
ExecCommand * c ;
int r ;
assert ( m ) ;
if ( ! success )
m - > failure = true ;
m - > control_command = c = m - > exec_command + MOUNT_EXEC_REMOUNT ;
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 (
c ,
" /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 (
c ,
" /bin/mount " ,
m - > where ,
" -o " , " remount " ,
NULL ) ;
else
r = - ENOENT ;
if ( r < 0 ) {
r = - ENOMEM ;
goto fail ;
}
2010-04-11 02:22:36 +04:00
service_unwatch_control_pid ( m ) ;
2010-04-10 19:53:17 +04:00
if ( ( r = mount_spawn ( m , c , & m - > control_pid ) ) < 0 )
goto fail ;
mount_set_state ( m , MOUNT_REMOUNTING ) ;
return ;
fail :
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 ;
assert ( m - > state = = MOUNT_DEAD | | m - > state = = MOUNT_MAINTAINANCE ) ;
m - > failure = false ;
mount_enter_mounting ( m , true ) ;
return 0 ;
}
static int mount_stop ( Unit * u ) {
Mount * m = MOUNT ( u ) ;
assert ( m ) ;
/* Cann't do this right now. */
if ( m - > state = = MOUNT_MOUNTING | |
m - > state = = MOUNT_MOUNTING_DONE | |
m - > state = = MOUNT_MOUNTING_SIGTERM | |
m - > state = = MOUNT_MOUNTING_SIGKILL | |
m - > state = = MOUNT_REMOUNTING | |
m - > state = = MOUNT_REMOUNTING_SIGTERM | |
m - > state = = MOUNT_REMOUNTING_SIGKILL )
return - EAGAIN ;
/* Already on it */
if ( m - > state = = MOUNT_UNMOUNTING | |
m - > state = = MOUNT_UNMOUNTING_SIGKILL | |
m - > state = = MOUNT_UNMOUNTING_SIGTERM )
return 0 ;
assert ( m - > state = = MOUNT_MOUNTED ) ;
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 ;
}
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 ) ;
return state_string_table [ MOUNT ( u ) - > state ] ;
}
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 ) ;
success = code = = CLD_EXITED & & status = = 0 ;
m - > failure = m - > failure | | ! success ;
assert ( m - > control_pid = = pid ) ;
assert ( m - > control_command ) ;
exec_status_fill ( & m - > control_command - > exec_status , pid , code , status ) ;
m - > control_pid = 0 ;
log_debug ( " %s control process exited, code=%s status=%i " , unit_id ( u ) , sigchld_code_to_string ( code ) , status ) ;
/* 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 :
if ( success & & m - > from_proc_self_mountinfo )
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. " ) ;
}
}
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 :
log_warning ( " %s mounting timed out. Stopping. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_MOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_REMOUNTING :
log_warning ( " %s remounting timed out. Stopping. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_REMOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_UNMOUNTING :
log_warning ( " %s unmounting timed out. Stopping. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_UNMOUNTING_SIGTERM , false ) ;
break ;
case MOUNT_MOUNTING_SIGTERM :
log_warning ( " %s mounting timed out. Killing. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_MOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_REMOUNTING_SIGTERM :
log_warning ( " %s remounting timed out. Killing. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_REMOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_UNMOUNTING_SIGTERM :
log_warning ( " %s unmounting timed out. Killing. " , unit_id ( u ) ) ;
mount_enter_signal ( m , MOUNT_UNMOUNTING_SIGKILL , false ) ;
break ;
case MOUNT_MOUNTING_SIGKILL :
case MOUNT_REMOUNTING_SIGKILL :
case MOUNT_UNMOUNTING_SIGKILL :
log_warning ( " %s mount process still around after SIGKILL. Ignoring. " , unit_id ( u ) ) ;
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 ;
MountParameters * mp ;
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
/* probably some kind of swap, which we don't cover for now */
if ( where [ 0 ] ! = ' / ' )
return 0 ;
if ( streq ( where , " / " ) )
2010-02-14 03:02:46 +03:00
e = strdup ( " -.mount " ) ;
2010-01-29 04:07:41 +03:00
else
2010-02-14 03:02:46 +03:00
e = unit_name_escape_path ( where + 1 , " .mount " ) ;
2010-01-29 04:07:41 +03:00
if ( ! e )
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-01-29 05:18:09 +03:00
r = - ENOMEM ;
goto fail ;
}
if ( ( r = unit_set_description ( u , where ) ) < 0 )
2010-01-29 04:07:41 +03:00
goto fail ;
2010-01-29 08:04:08 +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 ) {
mp = & MOUNT ( u ) - > parameters_proc_self_mountinfo ;
if ( set_flags ) {
MOUNT ( u ) - > is_mounted = true ;
MOUNT ( u ) - > just_mounted = ! MOUNT ( u ) - > from_proc_self_mountinfo ;
MOUNT ( u ) - > just_changed = ! streq_ptr ( MOUNT ( u ) - > parameters_proc_self_mountinfo . options , o ) ;
}
2010-01-29 08:04:08 +03:00
2010-01-29 05:18:09 +03:00
MOUNT ( u ) - > from_proc_self_mountinfo = true ;
2010-04-10 19:53:17 +04:00
2010-01-29 08:04:08 +03:00
} else {
2010-04-10 19:53:17 +04:00
mp = & 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-04-10 19:53:17 +04:00
free ( mp - > what ) ;
mp - > what = w ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
free ( mp - > options ) ;
mp - > options = o ;
free ( mp - > fstype ) ;
mp - > 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 ) ;
return 0 ;
}
static char * fstab_node_to_udev_node ( char * p ) {
char * dn , * t ;
int r ;
/* FIXME: to follow udev's logic 100% we need to leave valid
* UTF8 chars unescaped */
if ( startswith ( p , " LABEL= " ) ) {
2010-01-29 05:18:09 +03:00
if ( ! ( t = xescape ( p + 6 , " / " ) ) )
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-01-29 05:18:09 +03:00
if ( ! ( t = xescape ( p + 5 , " / " ) ) )
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-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-04-10 19:53:17 +04:00
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-04-10 19:53:17 +04:00
char * device , * path , * options , * fstype , * d , * p ;
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
device = path = options = fstype = d = p = 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 */
" %*[^ \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 ,
& device ) ) ! = 4 ) {
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-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-04-10 19:53:17 +04:00
if ( ( r = mount_add_one ( m , d , p , options , fstype , true , set_flags ) ) < 0 )
goto finish ;
2010-01-29 04:07:41 +03:00
2010-04-10 19:53:17 +04:00
free ( device ) ;
free ( path ) ;
free ( options ) ;
free ( fstype ) ;
2010-01-29 04:07:41 +03:00
free ( d ) ;
free ( p ) ;
}
2010-04-10 19:53:17 +04:00
r = 0 ;
finish :
free ( device ) ;
free ( path ) ;
free ( options ) ;
free ( fstype ) ;
free ( d ) ;
free ( p ) ;
return r ;
}
static void mount_shutdown ( Manager * m ) {
assert ( m ) ;
if ( m - > proc_self_mountinfo )
fclose ( m - > proc_self_mountinfo ) ;
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-01-29 08:04:08 +03:00
if ( ! ( m - > proc_self_mountinfo = fopen ( " /proc/self/mountinfo " , " r " ) ) )
return - errno ;
m - > mount_watch . type = WATCH_MOUNT ;
m - > mount_watch . fd = fileno ( m - > proc_self_mountinfo ) ;
zero ( ev ) ;
ev . events = EPOLLERR ;
ev . data . ptr = & m - > mount_watch ;
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > mount_watch . fd , & ev ) < 0 )
return - errno ;
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 ) {
log_error ( " Failed to reread /proc/self/mountinfo: %s " , strerror ( - errno ) ) ;
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 :
case MOUNT_MAINTAINANCE :
mount_enter_mounted ( mount , true ) ;
break ;
case MOUNT_MOUNTING :
mount_enter_mounting_done ( mount , true ) ;
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 ;
}
}
int mount_path_is_mounted ( Manager * m , const char * path ) {
char * t ;
int r ;
assert ( m ) ;
assert ( path ) ;
if ( path [ 0 ] ! = ' / ' )
return 1 ;
if ( ! ( t = strdup ( path ) ) )
return - ENOMEM ;
path_kill_slashes ( t ) ;
for ( ; ; ) {
char * e , * slash ;
Unit * u ;
if ( ! ( e = unit_name_escape_path ( t + 1 , " .mount " ) ) ) {
r = - ENOMEM ;
goto finish ;
}
u = manager_get_unit ( m , e ) ;
free ( e ) ;
if ( u & &
( MOUNT ( u ) - > from_etc_fstab | | MOUNT ( u ) - > from_fragment ) & &
MOUNT ( u ) - > state ! = MOUNT_MOUNTED ) {
r = 0 ;
goto finish ;
2010-01-29 08:04:08 +03:00
}
2010-04-10 19:53:17 +04:00
assert_se ( slash = strrchr ( t , ' / ' ) ) ;
if ( slash = = t ) {
r = 1 ;
goto finish ;
}
* slash = 0 ;
2010-01-29 08:04:08 +03:00
}
2010-04-10 19:53:17 +04:00
r = 1 ;
finish :
free ( t ) ;
return r ;
2010-01-29 08:04:08 +03:00
}
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 ,
. 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-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-10 19:53:17 +04:00
. sigchld_event = mount_sigchld_event ,
. timer_event = mount_timer_event ,
2010-01-29 05:18:09 +03:00
. enumerate = mount_enumerate ,
. shutdown = mount_shutdown
2010-01-23 03:52:57 +03:00
} ;