File: //opt/cloudlinux/venv/lib64/python3.11/site-packages/clveconfig/ve_lock.py
#!/usr/bin/python
# coding=utf-8
#
# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
import fcntl
import os
from contextlib import contextmanager
CONFIG_DIR = '/etc/container'
LOCK_FILE = os.path.join(CONFIG_DIR, '.ve.cfg.lock')
# TODO: probably should be encapsulated
LOCK_FD = None
LOCK_WRITE = False
class LockFailedException(Exception):
pass
def setup_global_lock(write=False):
global LOCK_FD
global LOCK_WRITE
if LOCK_FD is not None:
return False
if write:
LOCK_WRITE = True
try:
# Create the lock file root-only (0600) so unprivileged users cannot
# open it and hold the blocking flock, which would hang root config ops.
fd = os.open(LOCK_FILE, os.O_RDWR | os.O_CREAT, 0o600)
# Tighten any pre-existing world-readable (0644) lock file; the create
# mode above is a no-op when the file already exists.
os.chmod(LOCK_FILE, 0o600)
LOCK_FD = os.fdopen(fd, 'r+', encoding='utf-8')
fcntl.flock(LOCK_FD.fileno(), fcntl.LOCK_EX)
except IOError as e:
raise LockFailedException("IO error happened while getting lock") from e
LOCK_FD.seek(0, 0)
LOCK_FD.truncate()
LOCK_FD.write(str(os.getpid()))
LOCK_FD.flush()
return True
def release_lock():
global LOCK_FD
# write locks released only on process exit
if LOCK_WRITE:
return False
if LOCK_FD is not None:
LOCK_FD.close()
LOCK_FD = None
return True
@contextmanager
def acquire_lock(write=False):
"""
Usage:
with acquire_lock():
... do something with ve.cfg ...
"""
setup_global_lock(write)
yield
release_lock()