2016-02-18 02:53:35 +03:00
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# 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, see <http://www.gnu.org/licenses/>.
from . import cfg
from . import objectmanager
from . import utils
2016-11-04 21:26:31 +03:00
from . cfg import BUS_NAME , BASE_INTERFACE , BASE_OBJ_PATH , MANAGER_OBJ_PATH
2016-02-18 02:53:35 +03:00
import threading
from . import cmdhandler
import time
import signal
import dbus
2016-09-19 18:29:26 +03:00
import dbus . mainloop . glib
2016-02-18 02:53:35 +03:00
from . import lvmdb
# noinspection PyUnresolvedReferences
2016-03-09 01:04:44 +03:00
from gi . repository import GLib
2016-11-10 21:19:48 +03:00
from . fetch import StateUpdate
2016-02-18 02:53:35 +03:00
from . manager import Manager
import queue
from . import udevwatch
2022-08-18 01:24:08 +03:00
from . utils import log_debug , log_error , log_msg , DebugMessages
2016-02-18 02:53:35 +03:00
import argparse
2016-02-22 23:28:11 +03:00
import os
2016-08-29 22:26:16 +03:00
import sys
2022-06-07 16:20:06 +03:00
from . cmdhandler import LvmFlightRecorder , supports_vdo , supports_json
2017-03-09 00:31:45 +03:00
from . request import RequestEntry
2016-02-18 02:53:35 +03:00
class Lvm ( objectmanager . ObjectManager ) :
def __init__ ( self , object_path ) :
super ( Lvm , self ) . __init__ ( object_path , BASE_INTERFACE )
def process_request ( ) :
while cfg . run . value != 0 :
2016-11-04 02:27:22 +03:00
# noinspection PyBroadException
2016-02-18 02:53:35 +03:00
try :
2024-03-27 19:49:05 +03:00
req = cfg . worker_q . get ( True , cfg . G_LOOP_TMO )
2016-02-18 02:53:35 +03:00
log_debug (
2019-10-11 18:46:22 +03:00
" Method start: %s with args %s (callback = %s ) " %
( str ( req . method ) , str ( req . arguments ) , str ( req . cb ) ) )
2016-02-18 02:53:35 +03:00
req . run_cmd ( )
2019-10-11 18:46:22 +03:00
log_debug ( " Method complete: %s " % str ( req . method ) )
2016-02-18 02:53:35 +03:00
except queue . Empty :
pass
2022-08-26 19:10:24 +03:00
except SystemExit :
break
2022-08-31 19:18:55 +03:00
except Exception as e :
st = utils . extract_stack_trace ( e )
2016-02-25 23:57:12 +03:00
utils . log_error ( " process_request exception: \n %s " % st )
2022-08-18 01:21:19 +03:00
log_debug ( " process_request thread exiting! " )
2016-02-18 02:53:35 +03:00
2022-08-10 01:55:27 +03:00
def check_fr_size ( value ) :
2016-12-01 01:45:50 +03:00
v = int ( value )
if v < 0 :
raise argparse . ArgumentTypeError (
" positive integers only ( ' %s ' invalid) " % value )
return v
2017-09-25 23:20:03 +03:00
def install_signal_handlers ( ) :
# Because of the glib main loop stuff the python signal handler code is
2023-02-16 19:24:06 +03:00
# apparently not usable, and we need to use the glib calls instead
2017-09-25 23:20:03 +03:00
signal_add = None
if hasattr ( GLib , ' unix_signal_add ' ) :
signal_add = GLib . unix_signal_add
elif hasattr ( GLib , ' unix_signal_add_full ' ) :
signal_add = GLib . unix_signal_add_full
if signal_add :
signal_add ( GLib . PRIORITY_HIGH , signal . SIGHUP , utils . handler , signal . SIGHUP )
signal_add ( GLib . PRIORITY_HIGH , signal . SIGINT , utils . handler , signal . SIGINT )
signal_add ( GLib . PRIORITY_HIGH , signal . SIGUSR1 , utils . handler , signal . SIGUSR1 )
2022-08-10 01:44:10 +03:00
signal_add ( GLib . PRIORITY_HIGH , signal . SIGUSR2 , utils . handler , signal . SIGUSR2 )
2022-09-20 22:28:57 +03:00
signal_add ( GLib . PRIORITY_HIGH , signal . SIGTERM , utils . handler , signal . SIGTERM )
2017-09-25 23:20:03 +03:00
else :
log_error ( " GLib.unix_signal_[add|add_full] are NOT available! " )
2022-08-09 04:44:32 +03:00
def process_args ( ) :
2016-02-18 02:53:35 +03:00
parser = argparse . ArgumentParser ( )
2016-08-29 23:07:55 +03:00
parser . add_argument (
" --udev " , action = ' store_true ' ,
help = " Use udev for updating state " ,
default = False ,
dest = ' use_udev ' )
parser . add_argument (
" --debug " , action = ' store_true ' ,
help = " Dump debug messages " , default = False ,
dest = ' debug ' )
parser . add_argument (
" --nojson " , action = ' store_false ' ,
help = " Do not use LVM JSON output (disables lvmshell) " , default = True ,
dest = ' use_json ' )
parser . add_argument (
" --lvmshell " , action = ' store_true ' ,
help = " Use the lvm shell, not fork & exec lvm " ,
default = False ,
dest = ' use_lvm_shell ' )
2016-11-30 03:01:56 +03:00
parser . add_argument (
2022-08-10 01:55:27 +03:00
" --frsize " ,
help = " Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump) " ,
2016-11-30 03:01:56 +03:00
default = 10 ,
2022-08-10 01:55:27 +03:00
type = check_fr_size ,
dest = ' fr_size ' )
2016-06-28 21:32:39 +03:00
2022-08-09 04:44:32 +03:00
args = parser . parse_args ( )
2022-06-07 16:20:06 +03:00
2022-08-09 04:44:32 +03:00
if not args . use_json :
2022-06-07 16:20:06 +03:00
log_error ( " Daemon no longer supports lvm without JSON support, exiting! " )
sys . exit ( 1 )
else :
if not supports_json ( ) :
log_error ( " Un-supported version of LVM, daemon requires JSON output, exiting! " )
sys . exit ( 1 )
2022-08-09 04:44:32 +03:00
# Add udev watching
if args . use_udev :
# Make sure this msg ends up in the journal, so we know
2022-10-18 20:30:09 +03:00
log_msg ( ' The --udev option is no longer supported, '
' the daemon always uses a combination of dbus notify from lvm tools and udev ' )
2022-08-09 04:44:32 +03:00
return args
2022-09-01 05:25:36 +03:00
def running_under_systemd ( ) :
""" "
Checks to see if we are running under systemd , by checking damon fd 0 , 1
systemd sets stdin to / dev / null and 1 & 2 are a socket
"""
base = " /proc/self/fd "
stdout = os . readlink ( " %s /0 " % base )
if stdout == " /dev/null " :
stdout = os . readlink ( " %s /1 " % base )
if " socket " in stdout :
return True
return False
2022-08-09 04:44:32 +03:00
def main ( ) :
start = time . time ( )
2022-09-30 19:49:49 +03:00
use_session = os . getenv ( ' LVM_DBUSD_USE_SESSION ' , False )
2022-08-09 04:44:32 +03:00
2022-08-24 23:37:56 +03:00
# Ensure that we get consistent output for parsing stdout/stderr and that we
# are using the lvmdbusd profile.
2022-08-09 04:44:32 +03:00
os . environ [ " LC_ALL " ] = " C "
2022-08-24 23:37:56 +03:00
os . environ [ " LVM_COMMAND_PROFILE " ] = " lvmdbusd "
2022-08-09 04:44:32 +03:00
2022-09-01 05:25:36 +03:00
# Indicator if we are running under systemd
cfg . systemd = running_under_systemd ( )
2022-08-09 04:44:32 +03:00
# Add simple command line handling
cfg . args = process_args ( )
2017-03-09 00:31:45 +03:00
cfg . create_request_entry = RequestEntry
2016-02-18 02:53:35 +03:00
2016-11-30 03:01:56 +03:00
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
2022-08-10 01:55:27 +03:00
cfg . flightrecorder = LvmFlightRecorder ( cfg . args . fr_size )
2016-11-30 03:01:56 +03:00
2022-08-18 01:24:08 +03:00
# Create a circular buffer for debug logs
cfg . debug = DebugMessages ( )
2022-05-25 23:59:11 +03:00
log_debug ( " Using lvm binary: %s " % cfg . LVM_CMD )
2019-10-08 00:57:05 +03:00
# We will dynamically add interfaces which support vdo if it
# exists.
cfg . vdo_support = supports_vdo ( )
2016-02-18 02:53:35 +03:00
# List of threads that we start up
thread_list = [ ]
2017-09-25 23:20:03 +03:00
install_signal_handlers ( )
2016-02-18 02:53:35 +03:00
2022-08-09 04:48:10 +03:00
with utils . LockFile ( cfg . LOCK_FILE ) :
dbus . mainloop . glib . DBusGMainLoop ( set_as_default = True )
dbus . mainloop . glib . threads_init ( )
2016-02-22 23:28:11 +03:00
2022-08-09 04:48:10 +03:00
cmdhandler . set_execution ( cfg . args . use_lvm_shell )
2016-11-11 18:46:12 +03:00
2022-08-09 04:48:10 +03:00
if use_session :
cfg . bus = dbus . SessionBus ( )
else :
cfg . bus = dbus . SystemBus ( )
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus . service . BusName ( BUS_NAME , cfg . bus )
cfg . om = Lvm ( BASE_OBJ_PATH )
cfg . om . register_object ( Manager ( MANAGER_OBJ_PATH ) )
cfg . db = lvmdb . DataStore ( vdo_support = cfg . vdo_support )
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list . append (
threading . Thread ( target = process_request , name = ' process_request ' ) )
2023-02-16 19:24:06 +03:00
# Have a single thread handling updating lvm and the dbus model, so we
2022-08-09 04:48:10 +03:00
# don't have multiple threads doing this as the same time
updater = StateUpdate ( )
thread_list . append ( updater . thread )
cfg . load = updater . load
cfg . loop = GLib . MainLoop ( )
for thread in thread_list :
thread . damon = True
thread . start ( )
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch . add ( )
end = time . time ( )
log_debug (
' Service ready! total time= %.4f , lvm time= %.4f count= %d ' %
( end - start , cmdhandler . total_time , cmdhandler . total_count ) ,
' bg_black ' , ' fg_light_green ' )
try :
if cfg . run . value != 0 :
cfg . loop . run ( )
udevwatch . remove ( )
for thread in thread_list :
thread . join ( )
except KeyboardInterrupt :
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils . handler ( signal . SIGINT )
2016-02-18 02:53:35 +03:00
return 0