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
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-02-03 15:03:47 +03:00
( 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-02-03 15:03:47 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-02-03 15:03:47 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-23 03:52:57 +03:00
# include <errno.h>
2010-04-17 01:24:39 +04:00
# include <limits.h>
# include <sys/mount.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/epoll.h>
# include <sys/stat.h>
# include <linux/auto_fs4.h>
# include <linux/auto_dev-ioctl.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 "automount.h"
2012-12-05 14:59:05 +04:00
# include "mount.h"
2010-01-23 03:52:57 +03:00
# include "load-fragment.h"
# include "load-dropin.h"
2010-04-17 01:24:39 +04:00
# include "unit-name.h"
2010-07-10 04:41:06 +04:00
# include "special.h"
2010-08-12 00:58:34 +04:00
# include "label.h"
2012-04-10 23:54:31 +04:00
# include "mkdir.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2013-11-20 00:12:59 +04:00
# include "dbus-automount.h"
# include "bus-util.h"
# include "bus-error.h"
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
static const UnitActiveState state_translation_table [ _AUTOMOUNT_STATE_MAX ] = {
[ AUTOMOUNT_DEAD ] = UNIT_INACTIVE ,
[ AUTOMOUNT_WAITING ] = UNIT_ACTIVE ,
[ AUTOMOUNT_RUNNING ] = UNIT_ACTIVE ,
2010-08-31 02:17:56 +04:00
[ AUTOMOUNT_FAILED ] = UNIT_FAILED
2010-04-10 19:53:17 +04:00
} ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
static int open_dev_autofs ( Manager * m ) ;
2013-11-20 00:12:59 +04:00
static int automount_dispatch_io ( sd_event_source * s , int fd , uint32_t events , void * userdata ) ;
2010-04-17 01:24:39 +04:00
2010-04-10 19:53:17 +04:00
static void automount_init ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
2010-01-23 03:52:57 +03:00
2010-04-17 01:24:39 +04:00
assert ( u ) ;
2012-01-15 15:04:08 +04:00
assert ( u - > load_state = = UNIT_STUB ) ;
2010-04-17 01:24:39 +04:00
2013-11-20 00:12:59 +04:00
a - > pipe_fd = - 1 ;
2010-07-02 03:17:21 +04:00
a - > directory_mode = 0755 ;
2012-01-15 15:25:20 +04:00
UNIT ( a ) - > ignore_on_isolate = true ;
2010-04-17 01:24:39 +04:00
}
2013-09-13 06:45:49 +04:00
static void repeat_unmount ( const char * path ) {
2010-04-17 01:24:39 +04:00
assert ( path ) ;
for ( ; ; ) {
2010-05-19 05:42:05 +04:00
/* If there are multiple mounts on a mount point, this
* removes them all */
2010-04-17 01:24:39 +04:00
if ( umount2 ( path , MNT_DETACH ) > = 0 )
continue ;
if ( errno ! = EINVAL )
2014-11-28 21:29:59 +03:00
log_error_errno ( errno , " Failed to unmount: %m " ) ;
2010-04-17 01:24:39 +04:00
break ;
}
}
static void unmount_autofs ( Automount * a ) {
assert ( a ) ;
if ( a - > pipe_fd < 0 )
return ;
automount_send_ready ( a , - EHOSTDOWN ) ;
2013-11-20 00:12:59 +04:00
a - > pipe_event_source = sd_event_source_unref ( a - > pipe_event_source ) ;
2014-03-18 22:22:43 +04:00
a - > pipe_fd = safe_close ( a - > pipe_fd ) ;
2010-04-17 01:24:39 +04:00
2010-04-21 05:27:44 +04:00
/* If we reload/reexecute things we keep the mount point
* around */
if ( a - > where & &
2012-01-15 15:25:20 +04:00
( UNIT ( a ) - > manager - > exit_code ! = MANAGER_RELOAD & &
UNIT ( a ) - > manager - > exit_code ! = MANAGER_REEXECUTE ) )
2013-09-13 06:45:49 +04:00
repeat_unmount ( a - > where ) ;
2010-04-17 01:24:39 +04:00
}
static void automount_done ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
assert ( a ) ;
unmount_autofs ( a ) ;
2010-04-21 05:27:44 +04:00
free ( a - > where ) ;
a - > where = NULL ;
set_free ( a - > tokens ) ;
a - > tokens = NULL ;
2010-04-17 01:24:39 +04:00
}
2013-09-26 22:14:24 +04:00
static int automount_add_mount_links ( Automount * a ) {
_cleanup_free_ char * parent = NULL ;
2010-05-13 05:07:16 +04:00
int r ;
assert ( a ) ;
2010-05-19 05:42:05 +04:00
2013-09-26 22:14:24 +04:00
r = path_get_parent ( a - > where , & parent ) ;
2012-11-21 06:10:49 +04:00
if ( r < 0 )
2010-05-13 05:07:16 +04:00
return r ;
2013-09-26 22:14:24 +04:00
return unit_require_mounts_for ( UNIT ( a ) , parent ) ;
2010-05-13 05:07:16 +04:00
}
2010-07-13 00:55:27 +04:00
static int automount_add_default_dependencies ( Automount * a ) {
int r ;
assert ( a ) ;
2012-09-18 19:11:12 +04:00
if ( UNIT ( a ) - > manager - > running_as ! = SYSTEMD_SYSTEM )
2012-05-22 21:23:33 +04:00
return 0 ;
2010-10-29 08:04:03 +04:00
2012-05-22 21:23:33 +04:00
r = unit_add_two_dependencies_by_name ( UNIT ( a ) , UNIT_BEFORE , UNIT_CONFLICTS , SPECIAL_UMOUNT_TARGET , NULL , true ) ;
if ( r < 0 )
return r ;
2010-07-13 00:55:27 +04:00
return 0 ;
}
2010-04-17 01:24:39 +04:00
static int automount_verify ( Automount * a ) {
bool b ;
2014-06-24 21:00:32 +04:00
_cleanup_free_ char * e = NULL ;
2010-04-17 01:24:39 +04:00
assert ( a ) ;
2012-01-15 15:25:20 +04:00
if ( UNIT ( a ) - > load_state ! = UNIT_LOADED )
2010-04-17 01:24:39 +04:00
return 0 ;
2010-07-10 04:41:25 +04:00
if ( path_equal ( a - > where , " / " ) ) {
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id , " Cannot have an automount unit for the root directory. Refusing. " ) ;
2010-07-10 04:41:25 +04:00
return - EINVAL ;
}
2012-11-21 06:10:49 +04:00
e = unit_name_from_path ( a - > where , " .automount " ) ;
if ( ! e )
2010-04-17 01:24:39 +04:00
return - ENOMEM ;
b = unit_has_name ( UNIT ( a ) , e ) ;
if ( ! b ) {
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id , " %s's Where setting doesn't match unit name. Refusing. " , UNIT ( a ) - > id ) ;
2010-04-17 01:24:39 +04:00
return - EINVAL ;
}
return 0 ;
2010-04-10 19:53:17 +04:00
}
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
static int automount_load ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
2013-04-23 22:53:16 +04:00
int r ;
2010-04-06 04:43:58 +04:00
2010-04-10 19:53:17 +04:00
assert ( u ) ;
2012-01-15 15:04:08 +04:00
assert ( u - > load_state = = UNIT_STUB ) ;
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
/* Load a .automount file */
2012-11-21 06:10:49 +04:00
r = unit_load_fragment_and_dropin_optional ( u ) ;
if ( r < 0 )
2010-04-10 19:53:17 +04:00
return r ;
2010-04-06 04:43:58 +04:00
2012-01-15 15:04:08 +04:00
if ( u - > load_state = = UNIT_LOADED ) {
2012-01-07 02:08:54 +04:00
Unit * x ;
2010-04-06 04:43:58 +04:00
2012-11-21 06:10:49 +04:00
if ( ! a - > where ) {
a - > where = unit_name_to_path ( u - > id ) ;
if ( ! a - > where )
2010-04-21 05:27:44 +04:00
return - ENOMEM ;
2012-11-21 06:10:49 +04:00
}
2010-04-21 05:27:44 +04:00
path_kill_slashes ( a - > where ) ;
2013-04-23 22:53:16 +04:00
r = unit_load_related_unit ( u , " .mount " , & x ) ;
2012-11-21 06:10:49 +04:00
if ( r < 0 )
2010-05-13 05:07:16 +04:00
return r ;
2013-04-23 22:53:16 +04:00
r = unit_add_two_dependencies ( u , UNIT_BEFORE , UNIT_TRIGGERS , x , true ) ;
2012-01-07 02:08:54 +04:00
if ( r < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2013-04-23 22:53:16 +04:00
r = automount_add_mount_links ( a ) ;
2012-01-07 02:08:54 +04:00
if ( r < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-07-10 04:41:06 +04:00
2012-11-21 06:10:49 +04:00
if ( UNIT ( a ) - > default_dependencies ) {
r = automount_add_default_dependencies ( a ) ;
if ( r < 0 )
2010-07-10 04:41:06 +04:00
return r ;
2012-11-21 06:10:49 +04:00
}
2010-04-06 04:43:58 +04:00
}
2010-04-17 01:24:39 +04:00
return automount_verify ( a ) ;
2010-01-23 03:52:57 +03:00
}
2010-04-17 01:24:39 +04:00
static void automount_set_state ( Automount * a , AutomountState state ) {
AutomountState old_state ;
2010-04-10 19:53:17 +04:00
assert ( a ) ;
2010-01-26 06:18:44 +03:00
2010-04-17 01:24:39 +04:00
old_state = a - > state ;
a - > state = state ;
if ( state ! = AUTOMOUNT_WAITING & &
state ! = AUTOMOUNT_RUNNING )
unmount_autofs ( a ) ;
if ( state ! = old_state )
2014-11-27 22:20:23 +03:00
log_unit_debug ( UNIT ( a ) - > id ,
2013-01-05 21:00:35 +04:00
" %s changed %s -> %s " ,
UNIT ( a ) - > id ,
automount_state_to_string ( old_state ) ,
automount_state_to_string ( state ) ) ;
2010-04-17 01:24:39 +04:00
2011-01-20 15:17:22 +03:00
unit_notify ( UNIT ( a ) , state_translation_table [ old_state ] , state_translation_table [ state ] , true ) ;
2010-01-26 06:18:44 +03:00
}
2010-04-21 05:27:44 +04:00
static int automount_coldplug ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
int r ;
assert ( a ) ;
assert ( a - > state = = AUTOMOUNT_DEAD ) ;
if ( a - > deserialized_state ! = a - > state ) {
2012-11-21 06:10:49 +04:00
r = open_dev_autofs ( u - > manager ) ;
if ( r < 0 )
2010-04-21 05:27:44 +04:00
return r ;
if ( a - > deserialized_state = = AUTOMOUNT_WAITING | |
a - > deserialized_state = = AUTOMOUNT_RUNNING ) {
assert ( a - > pipe_fd > = 0 ) ;
2014-02-20 02:54:58 +04:00
r = sd_event_add_io ( u - > manager - > event , & a - > pipe_event_source , a - > pipe_fd , EPOLLIN , automount_dispatch_io , u ) ;
2012-11-21 06:10:49 +04:00
if ( r < 0 )
2010-04-21 05:27:44 +04:00
return r ;
}
automount_set_state ( a , a - > deserialized_state ) ;
}
return 0 ;
}
2010-01-26 23:39:06 +03:00
static void automount_dump ( Unit * u , FILE * f , const char * prefix ) {
2010-04-21 05:27:44 +04:00
Automount * a = AUTOMOUNT ( u ) ;
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
assert ( a ) ;
2010-01-23 03:52:57 +03:00
fprintf ( f ,
2010-04-21 05:27:44 +04:00
" %sAutomount State: %s \n "
2012-02-03 06:27:25 +04:00
" %sResult: %s \n "
2010-07-02 03:17:21 +04:00
" %sWhere: %s \n "
" %sDirectoryMode: %04o \n " ,
2010-04-21 05:27:44 +04:00
prefix , automount_state_to_string ( a - > state ) ,
2012-02-03 06:27:25 +04:00
prefix , automount_result_to_string ( a - > result ) ,
2010-07-02 03:17:21 +04:00
prefix , a - > where ,
prefix , a - > directory_mode ) ;
2010-01-23 03:52:57 +03:00
}
2012-02-03 06:27:25 +04:00
static void automount_enter_dead ( Automount * a , AutomountResult f ) {
2010-04-17 01:24:39 +04:00
assert ( a ) ;
2012-02-03 06:27:25 +04:00
if ( f ! = AUTOMOUNT_SUCCESS )
a - > result = f ;
2010-04-17 01:24:39 +04:00
2012-02-03 06:27:25 +04:00
automount_set_state ( a , a - > result ! = AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD ) ;
2010-04-17 01:24:39 +04:00
}
static int open_dev_autofs ( Manager * m ) {
struct autofs_dev_ioctl param ;
assert ( m ) ;
if ( m - > dev_autofs_fd > = 0 )
return m - > dev_autofs_fd ;
2012-07-03 18:25:50 +04:00
label_fix ( " /dev/autofs " , false , false ) ;
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 17:39:54 +04:00
2012-11-21 06:10:49 +04:00
m - > dev_autofs_fd = open ( " /dev/autofs " , O_CLOEXEC | O_RDONLY ) ;
2014-11-28 21:57:32 +03:00
if ( m - > dev_autofs_fd < 0 )
return log_error_errno ( errno , " Failed to open /dev/autofs: %m " ) ;
2010-04-17 01:24:39 +04:00
init_autofs_dev_ioctl ( & param ) ;
if ( ioctl ( m - > dev_autofs_fd , AUTOFS_DEV_IOCTL_VERSION , & param ) < 0 ) {
2014-03-18 22:22:43 +04:00
m - > dev_autofs_fd = safe_close ( m - > dev_autofs_fd ) ;
2010-04-17 01:24:39 +04:00
return - errno ;
}
log_debug ( " Autofs kernel version %i.%i " , param . ver_major , param . ver_minor ) ;
return m - > dev_autofs_fd ;
}
static int open_ioctl_fd ( int dev_autofs_fd , const char * where , dev_t devid ) {
struct autofs_dev_ioctl * param ;
size_t l ;
assert ( dev_autofs_fd > = 0 ) ;
assert ( where ) ;
l = sizeof ( struct autofs_dev_ioctl ) + strlen ( where ) + 1 ;
2012-11-21 06:10:49 +04:00
param = alloca ( l ) ;
2010-04-17 01:24:39 +04:00
init_autofs_dev_ioctl ( param ) ;
param - > size = l ;
param - > ioctlfd = - 1 ;
param - > openmount . devid = devid ;
strcpy ( param - > path , where ) ;
2012-11-21 06:10:49 +04:00
if ( ioctl ( dev_autofs_fd , AUTOFS_DEV_IOCTL_OPENMOUNT , param ) < 0 )
return - errno ;
2010-04-17 01:24:39 +04:00
2012-11-21 06:10:49 +04:00
if ( param - > ioctlfd < 0 )
return - EIO ;
2010-04-17 01:24:39 +04:00
2010-04-21 05:27:44 +04:00
fd_cloexec ( param - > ioctlfd , true ) ;
2012-11-21 06:10:49 +04:00
return param - > ioctlfd ;
2010-04-17 01:24:39 +04:00
}
static int autofs_protocol ( int dev_autofs_fd , int ioctl_fd ) {
uint32_t major , minor ;
struct autofs_dev_ioctl param ;
assert ( dev_autofs_fd > = 0 ) ;
assert ( ioctl_fd > = 0 ) ;
init_autofs_dev_ioctl ( & param ) ;
param . ioctlfd = ioctl_fd ;
if ( ioctl ( dev_autofs_fd , AUTOFS_DEV_IOCTL_PROTOVER , & param ) < 0 )
return - errno ;
major = param . protover . version ;
init_autofs_dev_ioctl ( & param ) ;
param . ioctlfd = ioctl_fd ;
if ( ioctl ( dev_autofs_fd , AUTOFS_DEV_IOCTL_PROTOSUBVER , & param ) < 0 )
return - errno ;
minor = param . protosubver . sub_version ;
log_debug ( " Autofs protocol version %i.%i " , major , minor ) ;
return 0 ;
}
static int autofs_set_timeout ( int dev_autofs_fd , int ioctl_fd , time_t sec ) {
struct autofs_dev_ioctl param ;
assert ( dev_autofs_fd > = 0 ) ;
assert ( ioctl_fd > = 0 ) ;
init_autofs_dev_ioctl ( & param ) ;
param . ioctlfd = ioctl_fd ;
param . timeout . timeout = sec ;
if ( ioctl ( dev_autofs_fd , AUTOFS_DEV_IOCTL_TIMEOUT , & param ) < 0 )
return - errno ;
return 0 ;
}
static int autofs_send_ready ( int dev_autofs_fd , int ioctl_fd , uint32_t token , int status ) {
struct autofs_dev_ioctl param ;
assert ( dev_autofs_fd > = 0 ) ;
assert ( ioctl_fd > = 0 ) ;
init_autofs_dev_ioctl ( & param ) ;
param . ioctlfd = ioctl_fd ;
if ( status ) {
param . fail . token = token ;
param . fail . status = status ;
} else
param . ready . token = token ;
if ( ioctl ( dev_autofs_fd , status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY , & param ) < 0 )
return - errno ;
return 0 ;
}
int automount_send_ready ( Automount * a , int status ) {
2014-03-18 22:22:43 +04:00
_cleanup_close_ int ioctl_fd = - 1 ;
2010-04-17 01:24:39 +04:00
unsigned token ;
2014-03-18 22:22:43 +04:00
int r ;
2010-04-17 01:24:39 +04:00
assert ( a ) ;
assert ( status < = 0 ) ;
if ( set_isempty ( a - > tokens ) )
return 0 ;
2012-11-21 06:10:49 +04:00
ioctl_fd = open_ioctl_fd ( UNIT ( a ) - > manager - > dev_autofs_fd , a - > where , a - > dev_id ) ;
2014-03-18 22:22:43 +04:00
if ( ioctl_fd < 0 )
return ioctl_fd ;
2010-04-17 01:24:39 +04:00
if ( status )
2014-11-28 15:17:02 +03:00
log_unit_debug_errno ( UNIT ( a ) - > id , status , " Sending failure: %m " ) ;
2010-04-17 01:24:39 +04:00
else
2014-11-27 22:20:23 +03:00
log_unit_debug ( UNIT ( a ) - > id , " Sending success. " ) ;
2010-04-17 01:24:39 +04:00
2010-08-12 00:04:22 +04:00
r = 0 ;
2010-04-17 01:24:39 +04:00
/* Autofs thankfully does not hand out 0 as a token */
while ( ( token = PTR_TO_UINT ( set_steal_first ( a - > tokens ) ) ) ) {
int k ;
/* Autofs fun fact II:
*
* if you pass a positive status code here , the kernel will
* freeze ! Yay ! */
2012-11-21 06:10:49 +04:00
k = autofs_send_ready ( UNIT ( a ) - > manager - > dev_autofs_fd ,
ioctl_fd ,
token ,
status ) ;
if ( k < 0 )
2010-04-17 01:24:39 +04:00
r = k ;
}
return r ;
}
static void automount_enter_waiting ( Automount * a ) {
2014-03-18 22:22:43 +04:00
_cleanup_close_ int ioctl_fd = - 1 ;
2010-04-17 01:24:39 +04:00
int p [ 2 ] = { - 1 , - 1 } ;
char name [ 32 ] , options [ 128 ] ;
bool mounted = false ;
2014-03-18 22:22:43 +04:00
int r , dev_autofs_fd ;
2010-04-17 01:24:39 +04:00
struct stat st ;
assert ( a ) ;
assert ( a - > pipe_fd < 0 ) ;
assert ( a - > where ) ;
if ( a - > tokens )
set_clear ( a - > tokens ) ;
2012-11-21 06:10:49 +04:00
dev_autofs_fd = open_dev_autofs ( UNIT ( a ) - > manager ) ;
if ( dev_autofs_fd < 0 ) {
2010-04-17 01:24:39 +04:00
r = dev_autofs_fd ;
goto fail ;
}
/* We knowingly ignore the results of this call */
2012-05-31 14:40:20 +04:00
mkdir_p_label ( a - > where , 0555 ) ;
2010-04-17 01:24:39 +04:00
2012-12-05 14:59:05 +04:00
warn_if_dir_nonempty ( a - > meta . id , a - > where ) ;
2012-09-18 20:59:01 +04:00
2010-04-21 05:27:44 +04:00
if ( pipe2 ( p , O_NONBLOCK | O_CLOEXEC ) < 0 ) {
2010-04-17 01:24:39 +04:00
r = - errno ;
goto fail ;
}
snprintf ( options , sizeof ( options ) , " fd=%i,pgrp=%u,minproto=5,maxproto=5,direct " , p [ 1 ] , ( unsigned ) getpgrp ( ) ) ;
char_array_0 ( options ) ;
snprintf ( name , sizeof ( name ) , " systemd-%u " , ( unsigned ) getpid ( ) ) ;
char_array_0 ( name ) ;
if ( mount ( name , a - > where , " autofs " , 0 , options ) < 0 ) {
r = - errno ;
goto fail ;
}
mounted = true ;
2014-03-18 22:22:43 +04:00
p [ 1 ] = safe_close ( p [ 1 ] ) ;
2010-04-17 01:24:39 +04:00
if ( stat ( a - > where , & st ) < 0 ) {
r = - errno ;
goto fail ;
}
2012-11-21 06:10:49 +04:00
ioctl_fd = open_ioctl_fd ( dev_autofs_fd , a - > where , st . st_dev ) ;
if ( ioctl_fd < 0 ) {
2010-04-17 01:24:39 +04:00
r = ioctl_fd ;
goto fail ;
}
2012-11-21 06:10:49 +04:00
r = autofs_protocol ( dev_autofs_fd , ioctl_fd ) ;
if ( r < 0 )
2010-04-17 01:24:39 +04:00
goto fail ;
2012-11-21 06:10:49 +04:00
r = autofs_set_timeout ( dev_autofs_fd , ioctl_fd , 300 ) ;
if ( r < 0 )
2010-04-17 01:24:39 +04:00
goto fail ;
/* Autofs fun fact:
*
* Unless we close the ioctl fd here , for some weird reason
* the direct mount will not receive events from the
* kernel . */
2014-02-20 02:54:58 +04:00
r = sd_event_add_io ( UNIT ( a ) - > manager - > event , & a - > pipe_event_source , p [ 0 ] , EPOLLIN , automount_dispatch_io , a ) ;
2012-11-21 06:10:49 +04:00
if ( r < 0 )
2010-04-17 01:24:39 +04:00
goto fail ;
a - > pipe_fd = p [ 0 ] ;
a - > dev_id = st . st_dev ;
automount_set_state ( a , AUTOMOUNT_WAITING ) ;
return ;
fail :
2014-03-24 06:22:44 +04:00
safe_close_pair ( p ) ;
2010-04-17 01:24:39 +04:00
if ( mounted )
2013-09-13 06:45:49 +04:00
repeat_unmount ( a - > where ) ;
2010-04-17 01:24:39 +04:00
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id ,
2013-01-05 21:00:35 +04:00
" Failed to initialize automounter: %s " , strerror ( - r ) ) ;
2012-02-03 06:27:25 +04:00
automount_enter_dead ( a , AUTOMOUNT_FAILURE_RESOURCES ) ;
2010-04-17 01:24:39 +04:00
}
static void automount_enter_runnning ( Automount * a ) {
2013-11-20 00:12:59 +04:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-04-23 22:53:16 +04:00
struct stat st ;
int r ;
2010-04-17 01:24:39 +04:00
assert ( a ) ;
2010-07-13 02:27:27 +04:00
/* We don't take mount requests anymore if we are supposed to
* shut down anyway */
2013-04-26 04:57:41 +04:00
if ( unit_stop_pending ( UNIT ( a ) ) ) {
2014-11-27 22:20:23 +03:00
log_unit_debug ( UNIT ( a ) - > id ,
2013-01-05 21:00:35 +04:00
" Suppressing automount request on %s since unit stop is scheduled. " , UNIT ( a ) - > id ) ;
2010-07-13 02:27:27 +04:00
automount_send_ready ( a , - EHOSTDOWN ) ;
return ;
}
2012-05-31 14:40:20 +04:00
mkdir_p_label ( a - > where , a - > directory_mode ) ;
2010-04-17 01:24:39 +04:00
2010-07-02 03:17:21 +04:00
/* Before we do anything, let's see if somebody is playing games with us? */
if ( lstat ( a - > where , & st ) < 0 ) {
2014-11-27 22:20:23 +03:00
log_unit_warning ( UNIT ( a ) - > id ,
2013-01-05 21:00:35 +04:00
" %s failed to stat automount point: %m " , UNIT ( a ) - > id ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
}
if ( ! S_ISDIR ( st . st_mode ) | | st . st_dev ! = a - > dev_id )
2014-11-27 22:20:23 +03:00
log_unit_info ( UNIT ( a ) - > id ,
2013-01-05 21:00:35 +04:00
" %s's automount point already active? " , UNIT ( a ) - > id ) ;
2013-04-23 22:53:16 +04:00
else {
r = manager_add_job ( UNIT ( a ) - > manager , JOB_START , UNIT_TRIGGER ( UNIT ( a ) ) ,
JOB_REPLACE , true , & error , NULL ) ;
if ( r < 0 ) {
2014-11-27 22:20:23 +03:00
log_unit_warning ( UNIT ( a ) - > id ,
2013-04-23 22:53:16 +04:00
" %s failed to queue mount startup job: %s " ,
2013-11-20 00:12:59 +04:00
UNIT ( a ) - > id , bus_error_message ( & error , r ) ) ;
2013-04-23 22:53:16 +04:00
goto fail ;
}
2010-04-17 01:24:39 +04:00
}
automount_set_state ( a , AUTOMOUNT_RUNNING ) ;
return ;
fail :
2012-02-03 06:27:25 +04:00
automount_enter_dead ( a , AUTOMOUNT_FAILURE_RESOURCES ) ;
2010-04-17 01:24:39 +04:00
}
static int automount_start ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
assert ( a ) ;
2010-08-31 02:17:56 +04:00
assert ( a - > state = = AUTOMOUNT_DEAD | | a - > state = = AUTOMOUNT_FAILED ) ;
2010-05-24 07:25:33 +04:00
2011-08-23 02:37:35 +04:00
if ( path_is_mount_point ( a - > where , false ) ) {
2014-11-27 22:20:23 +03:00
log_unit_error ( u - > id ,
2013-01-05 21:00:35 +04:00
" Path %s is already a mount point, refusing start for %s " ,
a - > where , u - > id ) ;
2010-04-17 01:24:39 +04:00
return - EEXIST ;
}
2013-04-23 22:53:16 +04:00
if ( UNIT_TRIGGER ( u ) - > load_state ! = UNIT_LOADED )
2010-05-24 07:25:33 +04:00
return - ENOENT ;
2010-04-17 01:24:39 +04:00
2012-02-03 06:27:25 +04:00
a - > result = AUTOMOUNT_SUCCESS ;
2010-04-17 01:24:39 +04:00
automount_enter_waiting ( a ) ;
return 0 ;
}
static int automount_stop ( Unit * u ) {
Automount * a = AUTOMOUNT ( u ) ;
assert ( a ) ;
assert ( a - > state = = AUTOMOUNT_WAITING | | a - > state = = AUTOMOUNT_RUNNING ) ;
2012-02-03 06:27:25 +04:00
automount_enter_dead ( a , AUTOMOUNT_SUCCESS ) ;
2010-04-17 01:24:39 +04:00
return 0 ;
}
2010-04-21 05:27:44 +04:00
static int automount_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Automount * a = AUTOMOUNT ( u ) ;
void * p ;
Iterator i ;
assert ( a ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , automount_state_to_string ( a - > state ) ) ;
2012-02-03 06:27:25 +04:00
unit_serialize_item ( u , f , " result " , automount_result_to_string ( a - > result ) ) ;
2010-04-21 05:27:44 +04:00
unit_serialize_item_format ( u , f , " dev-id " , " %u " , ( unsigned ) a - > dev_id ) ;
SET_FOREACH ( p , a - > tokens , i )
unit_serialize_item_format ( u , f , " token " , " %u " , PTR_TO_UINT ( p ) ) ;
if ( a - > pipe_fd > = 0 ) {
int copy ;
2012-11-21 06:10:49 +04:00
copy = fdset_put_dup ( fds , a - > pipe_fd ) ;
if ( copy < 0 )
2010-04-21 05:27:44 +04:00
return copy ;
unit_serialize_item_format ( u , f , " pipe-fd " , " %i " , copy ) ;
}
return 0 ;
}
static int automount_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Automount * a = AUTOMOUNT ( u ) ;
int r ;
assert ( a ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
AutomountState state ;
2012-11-21 06:10:49 +04:00
state = automount_state_from_string ( value ) ;
if ( state < 0 )
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Failed to parse state value %s " , value ) ;
2010-04-21 05:27:44 +04:00
else
a - > deserialized_state = state ;
2012-02-03 06:27:25 +04:00
} else if ( streq ( key , " result " ) ) {
AutomountResult f ;
f = automount_result_from_string ( value ) ;
if ( f < 0 )
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Failed to parse result value %s " , value ) ;
2012-02-03 06:27:25 +04:00
else if ( f ! = AUTOMOUNT_SUCCESS )
a - > result = f ;
2010-04-21 05:27:44 +04:00
} else if ( streq ( key , " dev-id " ) ) {
unsigned d ;
if ( safe_atou ( value , & d ) < 0 )
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Failed to parse dev-id value %s " , value ) ;
2010-04-21 05:27:44 +04:00
else
a - > dev_id = ( unsigned ) d ;
} else if ( streq ( key , " token " ) ) {
unsigned token ;
if ( safe_atou ( value , & token ) < 0 )
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Failed to parse token value %s " , value ) ;
2010-04-21 05:27:44 +04:00
else {
if ( ! a - > tokens )
2014-08-13 03:00:18 +04:00
if ( ! ( a - > tokens = set_new ( NULL ) ) )
2010-04-21 05:27:44 +04:00
return - ENOMEM ;
2012-11-21 06:10:49 +04:00
r = set_put ( a - > tokens , UINT_TO_PTR ( token ) ) ;
if ( r < 0 )
2010-04-21 05:27:44 +04:00
return r ;
}
} else if ( streq ( key , " pipe-fd " ) ) {
int fd ;
if ( safe_atoi ( value , & fd ) < 0 | | fd < 0 | | ! fdset_contains ( fds , fd ) )
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Failed to parse pipe-fd value %s " , value ) ;
2010-04-21 05:27:44 +04:00
else {
2014-03-18 22:22:43 +04:00
safe_close ( a - > pipe_fd ) ;
2010-04-21 05:27:44 +04:00
a - > pipe_fd = fdset_remove ( fds , fd ) ;
}
} else
2014-11-27 22:20:23 +03:00
log_unit_debug ( u - > id , " Unknown serialization key '%s' " , key ) ;
2010-04-21 05:27:44 +04:00
return 0 ;
}
2010-01-26 23:39:06 +03:00
static UnitActiveState automount_active_state ( Unit * u ) {
2010-04-21 05:27:44 +04:00
assert ( u ) ;
2010-01-26 23:39:06 +03:00
2010-04-10 19:53:17 +04:00
return state_translation_table [ AUTOMOUNT ( u ) - > state ] ;
2010-01-23 03:52:57 +03:00
}
2010-04-13 22:59:01 +04:00
static const char * automount_sub_state_to_string ( Unit * u ) {
assert ( u ) ;
2010-04-21 05:27:44 +04:00
return automount_state_to_string ( AUTOMOUNT ( u ) - > state ) ;
2010-04-13 22:59:01 +04:00
}
2010-04-21 08:01:13 +04:00
static bool automount_check_gc ( Unit * u ) {
2013-04-23 22:53:16 +04:00
assert ( u ) ;
2010-04-21 08:01:13 +04:00
2013-04-23 22:53:16 +04:00
if ( ! UNIT_TRIGGER ( u ) )
2010-09-06 03:04:59 +04:00
return false ;
2013-04-23 22:53:16 +04:00
return UNIT_VTABLE ( UNIT_TRIGGER ( u ) ) - > check_gc ( UNIT_TRIGGER ( u ) ) ;
2010-04-21 08:01:13 +04:00
}
2013-11-20 00:12:59 +04:00
static int automount_dispatch_io ( sd_event_source * s , int fd , uint32_t events , void * userdata ) {
2010-04-17 01:24:39 +04:00
union autofs_v5_packet_union packet ;
2013-11-20 00:12:59 +04:00
Automount * a = AUTOMOUNT ( userdata ) ;
2010-04-17 01:24:39 +04:00
ssize_t l ;
int r ;
assert ( a ) ;
assert ( fd = = a - > pipe_fd ) ;
if ( events ! = EPOLLIN ) {
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id , " Got invalid poll event on pipe. " ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
}
2012-11-21 06:10:49 +04:00
l = loop_read ( a - > pipe_fd , & packet , sizeof ( packet ) , true ) ;
if ( l ! = sizeof ( packet ) ) {
2014-11-28 15:54:40 +03:00
if ( l < 0 )
log_unit_error_errno ( UNIT ( a ) - > id , l , " Invalid read from pipe: %m " ) ;
else
log_unit_error ( UNIT ( a ) - > id , " Invalid read from pipe: short read " ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
}
switch ( packet . hdr . type ) {
case autofs_ptype_missing_direct :
2010-10-29 00:20:01 +04:00
if ( packet . v5_packet . pid > 0 ) {
2012-11-22 03:40:45 +04:00
_cleanup_free_ char * p = NULL ;
2010-10-29 00:20:01 +04:00
2011-10-07 23:06:39 +04:00
get_process_comm ( packet . v5_packet . pid , & p ) ;
2014-11-27 22:20:23 +03:00
log_unit_info ( UNIT ( a ) - > id ,
2015-01-21 06:22:15 +03:00
" Got automount request for %s, triggered by % " PRIu32 " (%s) " ,
2013-12-31 02:22:26 +04:00
a - > where , packet . v5_packet . pid , strna ( p ) ) ;
2010-10-29 00:20:01 +04:00
} else
2014-11-27 22:20:23 +03:00
log_unit_debug ( UNIT ( a ) - > id , " Got direct mount request on %s " , a - > where ) ;
2010-04-17 01:24:39 +04:00
2014-08-13 03:00:18 +04:00
r = set_ensure_allocated ( & a - > tokens , NULL ) ;
2012-11-21 06:10:49 +04:00
if ( r < 0 ) {
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id , " Failed to allocate token set. " ) ;
2012-11-21 06:10:49 +04:00
goto fail ;
}
2010-04-21 05:27:44 +04:00
2012-11-21 06:10:49 +04:00
r = set_put ( a - > tokens , UINT_TO_PTR ( packet . v5_packet . wait_queue_token ) ) ;
if ( r < 0 ) {
2014-11-28 15:17:02 +03:00
log_unit_error_errno ( UNIT ( a ) - > id , r , " Failed to remember token: %m " ) ;
2010-04-17 01:24:39 +04:00
goto fail ;
}
automount_enter_runnning ( a ) ;
break ;
default :
2014-11-27 22:20:23 +03:00
log_unit_error ( UNIT ( a ) - > id , " Received unknown automount request %i " , packet . hdr . type ) ;
2010-04-17 01:24:39 +04:00
break ;
}
2013-11-20 00:12:59 +04:00
return 0 ;
2010-04-17 01:24:39 +04:00
fail :
2012-02-03 06:27:25 +04:00
automount_enter_dead ( a , AUTOMOUNT_FAILURE_RESOURCES ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2010-04-17 01:24:39 +04:00
}
static void automount_shutdown ( Manager * m ) {
assert ( m ) ;
2014-03-18 22:22:43 +04:00
m - > dev_autofs_fd = safe_close ( m - > dev_autofs_fd ) ;
2010-04-17 01:24:39 +04:00
}
2010-08-31 02:17:56 +04:00
static void automount_reset_failed ( Unit * u ) {
2010-07-18 06:58:01 +04:00
Automount * a = AUTOMOUNT ( u ) ;
assert ( a ) ;
2010-08-31 02:17:56 +04:00
if ( a - > state = = AUTOMOUNT_FAILED )
2010-07-18 06:58:01 +04:00
automount_set_state ( a , AUTOMOUNT_DEAD ) ;
2012-02-03 06:27:25 +04:00
a - > result = AUTOMOUNT_SUCCESS ;
2010-07-18 06:58:01 +04:00
}
2014-12-12 23:05:32 +03:00
static bool automount_supported ( Manager * m ) {
static int supported = - 1 ;
assert ( m ) ;
if ( supported < 0 )
supported = access ( " /dev/autofs " , F_OK ) > = 0 ;
return supported ;
}
2010-04-21 05:27:44 +04:00
static const char * const automount_state_table [ _AUTOMOUNT_STATE_MAX ] = {
[ AUTOMOUNT_DEAD ] = " dead " ,
[ AUTOMOUNT_WAITING ] = " waiting " ,
[ AUTOMOUNT_RUNNING ] = " running " ,
2010-08-31 02:17:56 +04:00
[ AUTOMOUNT_FAILED ] = " failed "
2010-04-21 05:27:44 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( automount_state , AutomountState ) ;
2012-02-03 06:27:25 +04:00
static const char * const automount_result_table [ _AUTOMOUNT_RESULT_MAX ] = {
[ AUTOMOUNT_SUCCESS ] = " success " ,
[ AUTOMOUNT_FAILURE_RESOURCES ] = " resources "
} ;
DEFINE_STRING_TABLE_LOOKUP ( automount_result , AutomountResult ) ;
2010-01-26 23:39:06 +03:00
const UnitVTable automount_vtable = {
2012-01-15 13:53:49 +04:00
. object_size = sizeof ( Automount ) ,
2013-11-20 00:12:59 +04:00
2011-08-01 02:43:05 +04:00
. sections =
" Unit \0 "
" Automount \0 "
" Install \0 " ,
2010-01-23 03:52:57 +03:00
2010-04-10 19:53:17 +04:00
. no_alias = true ,
2010-04-17 01:24:39 +04:00
. no_instances = true ,
2010-04-10 19:53:17 +04:00
2010-01-26 06:18:44 +03:00
. init = automount_init ,
2010-04-10 19:53:17 +04:00
. load = automount_load ,
2010-01-26 06:18:44 +03:00
. done = automount_done ,
2010-01-23 03:52:57 +03:00
2010-04-21 05:27:44 +04:00
. coldplug = automount_coldplug ,
2010-01-26 06:18:44 +03:00
. dump = automount_dump ,
2010-01-23 03:52:57 +03:00
2010-04-17 01:24:39 +04:00
. start = automount_start ,
. stop = automount_stop ,
2010-04-21 05:27:44 +04:00
. serialize = automount_serialize ,
. deserialize_item = automount_deserialize_item ,
2010-04-13 22:59:01 +04:00
. active_state = automount_active_state ,
2010-04-17 01:24:39 +04:00
. sub_state_to_string = automount_sub_state_to_string ,
2010-04-21 08:01:13 +04:00
. check_gc = automount_check_gc ,
2010-08-31 02:17:56 +04:00
. reset_failed = automount_reset_failed ,
2010-07-18 06:58:01 +04:00
2010-08-20 04:26:05 +04:00
. bus_interface = " org.freedesktop.systemd1.Automount " ,
2013-11-20 00:12:59 +04:00
. bus_vtable = bus_automount_vtable ,
2010-04-18 05:08:16 +04:00
2012-05-13 20:18:54 +04:00
. shutdown = automount_shutdown ,
2014-12-12 23:05:32 +03:00
. supported = automount_supported ,
2012-05-13 20:18:54 +04:00
. status_message_formats = {
. finished_start_job = {
[ JOB_DONE ] = " Set up automount %s. " ,
[ JOB_FAILED ] = " Failed to set up automount %s. " ,
[ JOB_DEPENDENCY ] = " Dependency failed for %s. " ,
} ,
. finished_stop_job = {
[ JOB_DONE ] = " Unset automount %s. " ,
[ JOB_FAILED ] = " Failed to unset automount %s. " ,
} ,
} ,
2010-01-23 03:52:57 +03:00
} ;