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 ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <stdio.h>
# include <unistd.h>
# include <errno.h>
# include <stdarg.h>
2013-07-22 16:04:12 +04:00
# include <syslog.h>
2012-07-31 18:20:24 +04:00
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2013-06-15 04:28:54 +04:00
# include <limits.h> /* For PATH_MAX for musl libc */
2012-07-31 18:20:24 +04:00
# include "lvm2app.h"
2013-08-15 11:57:30 +04:00
# include "configure.h" /* for LVM_PATH */
2012-07-31 18:20:24 +04:00
# define KMSG_DEV_PATH " / dev / kmsg"
# define LVM_CONF_USE_LVMETAD "global / use_lvmetad"
2013-07-17 18:21:18 +04:00
# define UNIT_TARGET_LOCAL_FS "local-fs.target"
# define UNIT_TARGET_REMOTE_FS "remote-fs.target"
2012-07-31 18:20:24 +04:00
static char unit_path [ PATH_MAX ] ;
static char target_path [ PATH_MAX ] ;
2013-07-22 16:04:12 +04:00
static char message [ PATH_MAX + 3 ] ; /* +3 for '<n>' where n is the log level */
2012-07-31 18:20:24 +04:00
static int kmsg_fd = - 1 ;
2013-07-17 18:21:18 +04:00
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 "
} ;
2013-07-22 16:04:12 +04:00
__attribute__ ( ( format ( printf , 2 , 3 ) ) )
static void kmsg ( int log_level , const char * format , . . . )
2012-07-31 18:20:24 +04:00
{
va_list ap ;
int n ;
2013-07-22 16:04:12 +04:00
snprintf ( message , 4 , " <%d> " , log_level ) ;
2012-07-31 18:20:24 +04:00
va_start ( ap , format ) ;
2013-07-22 16:04:12 +04:00
n = vsnprintf ( message + 3 , PATH_MAX , format , ap ) ;
2012-07-31 18:20:24 +04:00
va_end ( ap ) ;
2013-07-22 16:04:12 +04:00
if ( kmsg_fd < 0 | | ( n < 0 | | ( ( unsigned ) n + 1 > PATH_MAX ) ) )
2012-07-31 18:20:24 +04:00
return ;
2013-07-22 16:04:12 +04:00
/* The n+4: +3 for "<n>" prefix and +1 for '\0' suffix */
( void ) write ( kmsg_fd , message , n + 4 ) ;
2012-07-31 18:20:24 +04:00
}
static int lvm_uses_lvmetad ( void )
{
lvm_t lvm ;
int r ;
if ( ! ( lvm = lvm_init ( NULL ) ) ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: Failed to initialize library context for activation generator. \n " ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
r = lvm_config_find_bool ( lvm , LVM_CONF_USE_LVMETAD , 0 ) ;
lvm_quit ( lvm ) ;
return r ;
}
static int register_unit_with_target ( const char * dir , const char * unit , const char * target )
{
int r = 1 ;
if ( dm_snprintf ( target_path , PATH_MAX , " %s/%s.wants " , dir , target ) < 0 ) {
r = 0 ; goto out ;
}
( void ) dm_prepare_selinux_context ( target_path , S_IFDIR ) ;
if ( mkdir ( target_path , 0755 ) < 0 & & errno ! = EEXIST ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: Failed to create target directory %s: %m. \n " , target_path ) ;
2012-07-31 18:20:24 +04:00
r = 0 ; goto out ;
}
if ( dm_snprintf ( target_path , PATH_MAX , " %s/%s.wants/%s " , dir , target , unit ) < 0 ) {
r = 0 ; goto out ;
}
( void ) dm_prepare_selinux_context ( target_path , S_IFLNK ) ;
if ( symlink ( unit_path , target_path ) < 0 ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: Failed to create symlink for unit %s: %m. \n " , unit ) ;
2012-07-31 18:20:24 +04:00
r = 0 ;
}
out :
dm_prepare_selinux_context ( NULL , 0 ) ;
return r ;
}
2013-07-17 18:21:18 +04:00
static int generate_unit ( const char * dir , int unit )
2012-07-31 18:20:24 +04:00
{
FILE * f ;
2013-07-17 18:21:18 +04: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
2013-07-17 18:21:18 +04:00
if ( dm_snprintf ( unit_path , PATH_MAX , " %s/%s " , dir , unit_name ) < 0 )
2012-07-31 18:20:24 +04:00
return 0 ;
if ( ! ( f = fopen ( unit_path , " wxe " ) ) ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: 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 "
" # This unit is responsible for direct activation of LVM2 logical volumes \n "
" # if lvmetad daemon is not used (global/use_lvmetad=0 lvm.conf setting), \n "
" # hence volume autoactivation is not applicable. \n "
" # Direct LVM2 activation requires udev to be settled! \n \n "
" [Unit] \n "
" Description=Activation of LVM2 logical volumes \n "
" Documentation=man:lvm(8) man:vgchange(8) \n "
" SourcePath=/etc/lvm/lvm.conf \n "
" DefaultDependencies=no \n " , f ) ;
2013-07-17 18:21:18 +04:00
if ( unit = = UNIT_NET ) {
2013-09-16 13:47:09 +04:00
fprintf ( f , " After=%s iscsi.service fcoe.service \n "
" Before=remote-fs.target shutdown.target \n \n "
" [Service] \n "
" ExecStartPre=/usr/bin/udevadm settle \n " , unit_names [ UNIT_MAIN ] ) ;
2013-07-17 18:21:18 +04:00
} else {
if ( unit = = UNIT_EARLY ) {
2013-07-24 13:06:28 +04:00
fputs ( " After=systemd-udev-settle.service \n "
" Before=cryptsetup.target \n " , f ) ;
2013-07-17 18:21:18 +04:00
} else
2013-09-16 13:47:09 +04:00
fprintf ( f , " After= %s cryptsetup.target \n " , unit_names [ UNIT_EARLY ] ) ;
2013-07-17 18:21:18 +04:00
fputs ( " Before=local-fs.target shutdown.target \n "
2013-07-24 13:06:28 +04: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
2013-08-15 11:57:30 +04:00
fputs ( " ExecStart= " LVM_PATH " vgchange -aay --sysinit \n "
2012-07-31 18:20:24 +04:00
" Type=oneshot \n " , f ) ;
if ( fclose ( f ) < 0 ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: Failed to write unit file %s: %m. \n " , unit_name ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
2013-07-17 18:21:18 +04:00
if ( ! register_unit_with_target ( dir , unit_name , target_name ) ) {
2013-07-22 16:04:12 +04:00
kmsg ( LOG_ERR , " LVM: Failed to register unit %s with target %s. \n " , unit_name , target_name ) ;
2012-07-31 18:20:24 +04:00
return 0 ;
}
return 1 ;
}
int main ( int argc , char * argv [ ] )
{
const char * dir ;
int r = EXIT_SUCCESS ;
2012-08-01 10:57:12 +04:00
kmsg_fd = open ( KMSG_DEV_PATH , O_WRONLY | O_NOCTTY ) ;
2012-07-31 18:20:24 +04:00
2013-08-28 18:06:51 +04:00
if ( argc ! = 4 ) {
kmsg ( LOG_ERR , " LVM: Incorrect number of arguments for activation generator. \n " ) ;
2012-07-31 18:20:24 +04:00
r = EXIT_FAILURE ; goto out ;
}
/* If lvmetad used, rely on autoactivation instead of direct activation. */
2013-08-22 10:14:11 +04:00
if ( lvm_uses_lvmetad ( ) )
2012-07-31 18:20:24 +04:00
goto out ;
2013-08-28 18:06:51 +04:00
dir = argv [ 1 ] ;
2012-07-31 18:20:24 +04:00
2013-07-17 18:21:18 +04:00
if ( ! generate_unit ( dir , UNIT_EARLY ) | |
! generate_unit ( dir , UNIT_MAIN ) | |
! generate_unit ( dir , UNIT_NET ) )
2012-07-31 18:20:24 +04:00
r = EXIT_FAILURE ;
out :
2013-08-22 10:14:11 +04:00
if ( r )
kmsg ( LOG_ERR , " LVM: Activation generator failed. \n " ) ;
2012-07-31 18:20:24 +04:00
if ( kmsg_fd ! = - 1 )
2012-08-17 02:48:28 +04:00
( void ) close ( kmsg_fd ) ;
2012-07-31 18:20:24 +04:00
return r ;
}