2014-05-01 20:37:14 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 - 2014 Red Hat , Inc . All rights reserved .
*
* This file is part of LVM2 .
*
* 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 Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser 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
2014-05-01 20:37:14 +04:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/misc/lvm-signal.h"
# include "lib/mm/memlock.h"
2014-05-01 20:37:14 +04:00
# include <signal.h>
2014-05-01 23:07:17 +04:00
static sigset_t _oldset ;
static int _signals_blocked = 0 ;
static volatile sig_atomic_t _sigint_caught = 0 ;
2017-04-10 19:16:09 +03:00
static volatile sig_atomic_t _handler_installed = 0 ;
2014-05-02 19:30:27 +04:00
/* Support 3 level nesting, increase if needed more */
# define MAX_SIGINTS 3
2021-04-01 12:32:29 +03:00
struct ar_sigs {
int sig ;
2024-05-04 01:25:33 +03:00
const char name [ 8 ] ;
2021-04-01 12:32:29 +03:00
int oldmasked [ MAX_SIGINTS ] ;
struct sigaction oldhandler [ MAX_SIGINTS ] ;
} ;
/* List of signals we want to allow/restore */
static struct ar_sigs _ar_sigs [ ] = {
{ SIGINT , " SIGINT " } ,
{ SIGTERM , " SIGTERM " } ,
} ;
2014-05-01 23:07:17 +04:00
static void _catch_sigint ( int unused __attribute__ ( ( unused ) ) )
{
_sigint_caught = 1 ;
}
int sigint_caught ( void ) {
if ( _sigint_caught )
log_error ( " Interrupted... " ) ;
return _sigint_caught ;
}
void sigint_clear ( void )
{
_sigint_caught = 0 ;
}
/*
* Temporarily allow keyboard interrupts to be intercepted and noted ;
* saves interrupt handler state for sigint_restore ( ) . Users should
* use the sigint_caught ( ) predicate to check whether interrupt was
* requested and act appropriately . Interrupt flags are never
* cleared automatically by this code , but the tools clear the flag
* before running each command in lvm_run_command ( ) . All other places
* where the flag needs to be cleared need to call sigint_clear ( ) .
*/
void sigint_allow ( void )
{
2023-07-13 13:32:44 +03:00
unsigned i , mask = 0 ;
2014-05-01 23:07:17 +04:00
struct sigaction handler ;
sigset_t sigs ;
2015-10-22 11:45:58 +03:00
if ( memlock_count_daemon ( ) )
return ;
2014-05-01 23:07:17 +04:00
/*
* Do not overwrite the backed - up handler data -
* just increase nesting count .
*/
2017-04-10 19:16:09 +03:00
if ( + + _handler_installed > MAX_SIGINTS )
2014-05-01 23:07:17 +04:00
return ;
2021-04-01 12:32:29 +03:00
/* Unmask signals. Remember to mask it again on restore. */
if ( sigprocmask ( 0 , NULL , & sigs ) )
log_sys_debug ( " sigprocmask " , " " ) ;
2014-05-02 19:34:22 +04:00
2021-04-01 12:32:29 +03:00
for ( i = 0 ; i < DM_ARRAY_SIZE ( _ar_sigs ) ; + + i ) {
/* Grab old sigaction for SIGNAL: shall not fail. */
if ( sigaction ( _ar_sigs [ i ] . sig , NULL , & handler ) )
log_sys_debug ( " sigaction " , _ar_sigs [ i ] . name ) ;
2014-05-01 23:07:17 +04:00
2021-04-01 12:32:29 +03:00
handler . sa_flags & = ~ SA_RESTART ; /* Clear restart flag */
handler . sa_handler = _catch_sigint ;
2014-05-01 23:07:17 +04:00
2021-04-01 12:32:29 +03:00
/* Override the signal handler: shall not fail. */
if ( sigaction ( _ar_sigs [ i ] . sig , & handler , & _ar_sigs [ i ] . oldhandler [ _handler_installed - 1 ] ) )
log_sys_debug ( " sigaction " , _ar_sigs [ i ] . name ) ;
2014-05-02 19:34:22 +04:00
2021-04-01 12:32:29 +03:00
if ( ( _ar_sigs [ i ] . oldmasked [ _handler_installed - 1 ] = sigismember ( & sigs , _ar_sigs [ i ] . sig ) ) ) {
sigdelset ( & sigs , _ar_sigs [ i ] . sig ) ;
mask = 1 ;
}
2014-05-01 23:07:17 +04:00
}
2021-04-01 12:32:29 +03:00
if ( mask & & sigprocmask ( SIG_SETMASK , & sigs , NULL ) )
log_sys_debug ( " sigprocmask " , " SIG_SETMASK " ) ;
2014-05-01 23:07:17 +04:00
}
void sigint_restore ( void )
{
2023-07-13 13:32:44 +03:00
unsigned i , mask = 0 ;
2021-04-01 12:32:29 +03:00
sigset_t sigs ;
2015-10-22 11:45:58 +03:00
if ( memlock_count_daemon ( ) )
return ;
2014-05-02 19:30:27 +04:00
if ( ! _handler_installed | |
2017-04-10 19:29:26 +03:00
- - _handler_installed > = MAX_SIGINTS )
2014-05-01 23:07:17 +04:00
return ;
2015-07-06 18:15:11 +03:00
/* Nesting count went below MAX_SIGINTS. */
2021-04-01 12:32:29 +03:00
sigprocmask ( 0 , NULL , & sigs ) ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _ar_sigs ) ; + + i )
if ( _ar_sigs [ i ] . oldmasked [ _handler_installed ] ) {
sigaddset ( & sigs , _ar_sigs [ i ] . sig ) ;
mask = 1 ;
}
if ( mask & & sigprocmask ( SIG_SETMASK , & sigs , NULL ) )
log_sys_debug ( " sigprocmask " , " SIG_SETMASK " ) ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _ar_sigs ) ; + + i )
if ( sigaction ( _ar_sigs [ i ] . sig , & _ar_sigs [ i ] . oldhandler [ _handler_installed ] , NULL ) )
log_sys_debug ( " sigaction " , _ar_sigs [ i ] . name ) ;
2014-05-01 23:07:17 +04:00
}
void block_signals ( uint32_t flags __attribute__ ( ( unused ) ) )
{
sigset_t set ;
2015-10-22 11:45:58 +03:00
if ( memlock_count_daemon ( ) )
return ;
2014-05-01 23:07:17 +04:00
if ( _signals_blocked )
return ;
if ( sigfillset ( & set ) ) {
log_sys_error ( " sigfillset " , " _block_signals " ) ;
return ;
}
if ( sigprocmask ( SIG_SETMASK , & set , & _oldset ) ) {
log_sys_error ( " sigprocmask " , " _block_signals " ) ;
return ;
}
_signals_blocked = 1 ;
}
void unblock_signals ( void )
{
2015-10-22 11:45:58 +03:00
if ( memlock_count_daemon ( ) )
return ;
2014-05-01 23:07:17 +04:00
/* Don't unblock signals while any locks are held */
if ( ! _signals_blocked )
return ;
if ( sigprocmask ( SIG_SETMASK , & _oldset , NULL ) ) {
log_sys_error ( " sigprocmask " , " _block_signals " ) ;
return ;
}
_signals_blocked = 0 ;
}
2021-03-12 13:18:53 +03:00
/* usleep with enabled signal handler.
* Returns 1 when there was interruption */
int interruptible_usleep ( useconds_t usec )
{
int r ;
sigint_allow ( ) ;
r = usleep ( usec ) ;
sigint_restore ( ) ;
return ( sigint_caught ( ) | | r ) ? 1 : 0 ;
}