2012-07-31 18:20:24 +04:00
/*
* Copyright ( C ) 2012 Red Hat , Inc . All rights reserved .
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2012-07-31 18:20:24 +04:00
*/
2018-06-07 18:15:04 +03:00
// Code in this file gets included in the unit tests.
# include "generator-internals.c"
2012-07-31 18:20:24 +04:00
2018-06-07 18:15:04 +03:00
// Logging
2012-07-31 18:20:24 +04:00
2018-06-07 18:15:04 +03:00
# define KMSG_DEV_PATH " / dev / kmsg"
static int _kmsg_fd ;
2013-07-17 18:21:18 +04:00
2018-06-07 18:15:04 +03:00
static void _log_init ( void )
{
// failing is harmless
_kmsg_fd = open ( KMSG_DEV_PATH , O_WRONLY | O_NOCTTY ) ;
}
2013-07-17 18:21:18 +04:00
2018-06-07 18:15:04 +03:00
static void _log_exit ( void )
{
if ( _kmsg_fd ! = - 1 )
( void ) close ( _kmsg_fd ) ;
}
__attribute__ ( ( format ( printf , 1 , 2 ) ) )
static void _error ( const char * format , . . . )
2012-07-31 18:20:24 +04:00
{
int n ;
2018-06-07 18:15:04 +03:00
va_list ap ;
2018-08-30 13:46:41 +03:00
char message [ PATH_MAX + 30 ] ; /* +3 for '<n>' where n is the log level and +27 for lvm2-activation-generator: " prefix */
2012-07-31 18:20:24 +04:00
2018-08-30 13:46:41 +03:00
snprintf ( message , 31 , " <%d>lvm2-activation-generator: " , LOG_ERR ) ;
2013-07-22 16:04:12 +04:00
2012-07-31 18:20:24 +04:00
va_start ( ap , format ) ;
2018-08-30 13:46:41 +03:00
n = vsnprintf ( message + 30 , PATH_MAX , format , ap ) ;
2012-07-31 18:20:24 +04:00
va_end ( ap ) ;
2018-06-07 18:15:04 +03:00
if ( _kmsg_fd < 0 | | ( n < 0 | | ( ( unsigned ) n + 1 > PATH_MAX ) ) )
2012-07-31 18:20:24 +04:00
return ;
2018-08-30 13:46:41 +03:00
/* The n+31: +30 for "<n>lvm2-activation-generator: " prefix and +1 for '\0' suffix */
2018-12-21 13:19:25 +03:00
if ( write ( _kmsg_fd , message , n + 31 ) < 0 )
_error ( " Failed to write activation message %s: %m. \n " , message ) ;
2012-07-31 18:20:24 +04:00
}
2018-06-07 18:15:04 +03:00
//----------------------------------------------------------------
2016-05-17 20:03:25 +03:00
2018-06-07 18:15:04 +03:00
# define UNIT_TARGET_LOCAL_FS "local-fs-pre.target"
# define UNIT_TARGET_REMOTE_FS "remote-fs-pre.target"
struct generator {
const char * dir ;
struct config cfg ;
2012-07-31 18:20:24 +04:00
2018-06-07 18:15:04 +03:00
int kmsg_fd ;
char unit_path [ PATH_MAX ] ;
char target_path [ PATH_MAX ] ;
} ;
enum {
UNIT_EARLY ,
UNIT_MAIN ,
UNIT_NET
} ;
static const char * _unit_names [ ] = {
[ UNIT_EARLY ] = " lvm2-activation-early.service " ,
[ UNIT_MAIN ] = " lvm2-activation.service " ,
[ UNIT_NET ] = " lvm2-activation-net.service "
} ;
//----------------------------------------------------------------
static int register_unit_with_target ( struct generator * gen , const char * unit ,
const char * target )
2012-07-31 18:20:24 +04:00
{
int r = 1 ;
2018-06-07 18:15:04 +03:00
if ( dm_snprintf ( gen - > target_path , PATH_MAX , " %s/%s.wants " , gen - > dir , target ) < 0 ) {
r = 0 ;
goto out ;
2012-07-31 18:20:24 +04:00
}
2018-06-07 18:15:04 +03:00
( void ) dm_prepare_selinux_context ( gen - > target_path , S_IFDIR ) ;
if ( mkdir ( gen - > target_path , 0755 ) < 0 & & errno ! = EEXIST ) {
2018-08-30 13:46:41 +03:00
_error ( " Failed to create target directory %s: %m. \n " , gen - > target_path ) ;
2018-06-07 18:15:04 +03:00
r = 0 ;
goto out ;
2012-07-31 18:20:24 +04:00
}
2018-06-07 18:15:04 +03:00
if ( dm_snprintf
( gen - > target_path , PATH_MAX , " %s/%s.wants/%s " , gen - > dir , target , unit ) < 0 ) {
r = 0 ;
goto out ;
2012-07-31 18:20:24 +04:00
}
2018-06-07 18:15:04 +03:00
( void ) dm_prepare_selinux_context ( gen - > target_path , S_IFLNK ) ;
if ( symlink ( gen - > unit_path , gen - > target_path ) < 0 ) {
2018-08-30 13:46:41 +03:00
_error ( " Failed to create symlink for unit %s: %m. \n " , unit ) ;
2012-07-31 18:20:24 +04:00
r = 0 ;
}
2018-06-07 18:15:04 +03:00
out :
2012-07-31 18:20:24 +04:00
dm_prepare_selinux_context ( NULL , 0 ) ;
return r ;
}
2018-06-07 18:15:04 +03:00
static int generate_unit ( struct generator * gen , int unit )
2012-07-31 18:20:24 +04:00
{
FILE * f ;
2018-06-07 18:15:04 +03:00
const char * unit_name = _unit_names [ unit ] ;
const char * target_name =
unit = = UNIT_NET ? UNIT_TARGET_REMOTE_FS : UNIT_TARGET_LOCAL_FS ;
2012-07-31 18:20:24 +04:00
2018-06-07 18:15:04 +03:00
if ( dm_snprintf ( gen - > unit_path , PATH_MAX , " %s/%s " , gen - > dir , unit_name )
< 0 )
2012-07-31 18:20:24 +04:00
return 0 ;
2018-06-07 18:15:04 +03:00
if ( ! ( f = fopen ( gen - > unit_path , " wxe " ) ) ) {
2018-08-30 13:46:41 +03:00
_error ( " Failed to create unit file %s: %m. \n " , unit_name ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
fputs ( " # Automatically generated by lvm2-activation-generator. \n "
" # \n "
2018-11-26 21:49:39 +03:00
" # This unit is responsible for direct activation of LVM logical volumes \n "
" # if event-based activation not used (global/event_activation=0 in \n "
" # lvm.conf). Direct LVM activation requires udev to be settled! \n \n "
2012-07-31 18:20:24 +04:00
" [Unit] \n "
2018-11-26 21:49:39 +03:00
" Description=LVM direct activation of logical volumes \n "
2014-03-13 16:01:06 +04:00
" Documentation=man:lvm2-activation-generator(8) \n "
2018-06-07 18:15:04 +03:00
" SourcePath=/etc/lvm/lvm.conf \n " " DefaultDependencies=no \n " , f ) ;
2012-07-31 18:20:24 +04:00
2019-04-09 13:10:17 +03:00
fputs ( " Conflicts=shutdown.target \n " , f ) ;
2013-07-17 18:21:18 +04:00
if ( unit = = UNIT_NET ) {
2018-08-30 13:35:58 +03:00
fprintf ( f , " After=%s iscsi.service fcoe.service rbdmap.service \n "
2015-09-23 14:17:12 +03:00
" Before=remote-fs-pre.target shutdown.target \n \n "
2013-09-16 13:47:09 +04:00
" [Service] \n "
2018-06-07 18:15:04 +03:00
" ExecStartPre=/usr/bin/udevadm settle \n " , _unit_names [ UNIT_MAIN ] ) ;
2013-07-17 18:21:18 +04:00
} else {
2018-06-07 18:15:04 +03:00
if ( unit = = UNIT_EARLY )
2013-07-24 13:06:28 +04:00
fputs ( " After=systemd-udev-settle.service \n "
" Before=cryptsetup.target \n " , f ) ;
2018-06-07 18:15:04 +03:00
else
fprintf ( f , " After=%s cryptsetup.target \n " , _unit_names [ UNIT_EARLY ] ) ;
2013-07-17 18:21:18 +04:00
2015-09-23 14:17:12 +03:00
fputs ( " Before=local-fs-pre.target shutdown.target \n "
2018-06-07 18:15:04 +03:00
" Wants=systemd-udev-settle.service \n \n " " [Service] \n " , f ) ;
2013-07-17 18:21:18 +04:00
}
2012-07-31 18:20:24 +04:00
2018-06-15 23:43:59 +03:00
fputs ( " ExecStart= " LVM_PATH " vgchange -aay " , f ) ;
2018-06-07 18:15:04 +03:00
if ( gen - > cfg . sysinit_needed )
fputs ( " --sysinit " , f ) ;
2015-05-21 12:07:07 +03:00
fputs ( " \n Type=oneshot \n " , f ) ;
2012-07-31 18:20:24 +04:00
if ( fclose ( f ) < 0 ) {
2018-08-30 13:46:41 +03:00
_error ( " Failed to write unit file %s: %m. \n " , unit_name ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
2018-06-07 18:15:04 +03:00
if ( ! register_unit_with_target ( gen , unit_name , target_name ) ) {
2018-08-30 13:46:41 +03:00
_error ( " Failed to register unit %s with target %s. \n " ,
2018-06-07 18:15:04 +03:00
unit_name , target_name ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
return 1 ;
}
2018-06-07 18:15:04 +03:00
static bool _parse_command_line ( struct generator * gen , int argc , const char * * argv )
2012-07-31 18:20:24 +04:00
{
2013-08-28 18:06:51 +04:00
if ( argc ! = 4 ) {
2018-08-30 13:46:41 +03:00
_error ( " Incorrect number of arguments for activation generator. \n " ) ;
2018-06-07 18:15:04 +03:00
return false ;
2012-07-31 18:20:24 +04:00
}
2018-06-07 18:15:04 +03:00
gen - > dir = argv [ 1 ] ;
return true ;
}
static bool _run ( int argc , const char * * argv )
{
bool r ;
mode_t old_mask ;
struct generator gen ;
if ( ! _parse_command_line ( & gen , argc , argv ) )
return false ;
2019-01-04 13:11:13 +03:00
if ( _get_config ( & gen . cfg , LVMCONFIG_PATH ) ) {
if ( gen . cfg . event_activation )
// If event_activation=1, pvscan --cache -aay does activation.
return true ;
}
2012-07-31 18:20:24 +04:00
2019-01-04 13:11:13 +03:00
/*
* Create the activation units if :
* - _get_config succeeded and event_activation = 0
* - _get_config failed , then this is a failsafe fallback
*/
2012-07-31 18:20:24 +04:00
2014-05-21 12:10:24 +04:00
/* mark lvm2-activation.*.service as world-accessible */
old_mask = umask ( 0022 ) ;
2015-05-21 12:07:07 +03:00
2018-06-07 18:15:04 +03:00
r = generate_unit ( & gen , UNIT_EARLY ) & &
generate_unit ( & gen , UNIT_MAIN ) & & generate_unit ( & gen , UNIT_NET ) ;
2015-05-21 12:07:07 +03:00
2014-05-21 12:10:24 +04:00
umask ( old_mask ) ;
2018-06-07 18:15:04 +03:00
2012-07-31 18:20:24 +04:00
return r ;
}
2018-06-07 18:15:04 +03:00
int main ( int argc , const char * * argv )
{
bool r ;
_log_init ( ) ;
r = _run ( argc , argv ) ;
if ( ! r )
2018-08-30 13:46:41 +03:00
_error ( " Activation generator failed. \n " ) ;
2018-06-07 18:15:04 +03:00
_log_exit ( ) ;
return r ? EXIT_SUCCESS : EXIT_FAILURE ;
}