Mini Shell
#!/opt/cloudlinux/venv/bin/python3 -Ibb
# 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
# Script for create PHP data index
import getopt
import os
import os.path
import sys
import tempfile
from dataclasses import dataclass
import clselect
import clselect.utils
import secureio
from clselect.clselectexcept import ClSelectExcept
from clcommon.utils import mod_makedirs
@dataclass
class CachePhpDataOpts:
"""
Dataclass for commandline option flags.
"""
usage: bool = False
delete_cache: bool = False
only_native: bool = False
def usage():
"""
Print the help message for this script.
"""
print("Usage: " + sys.argv[0] + " [-d]")
print("Options:")
print(" -h | --help : print this message")
print(" -d | --delete : delete cache")
print(" -n | --native : update only native version cache")
def _write_lines_to_file(filename, line_to_write):
"""
Writes lines to file via temp
:param filename: file name to write
:param line_to_write: Data to write
:return: None
"""
if not os.path.isdir(clselect.ClSelect.CACHEFILE_DIR):
mod_makedirs(clselect.ClSelect.CACHEFILE_DIR, 0o755)
_, temp_file_name = tempfile.mkstemp(dir=clselect.ClSelect.CACHEFILE_DIR)
f = open(temp_file_name, "w", encoding="utf8")
f.write(line_to_write)
f.close()
os.rename(temp_file_name, filename)
os.chmod(filename, 0o644)
def _get_all_php_paths():
"""
Retrives php binary path for all available php version
:return: dictionary with php versions and paths. Example:
{'5.1': '/opt/alt/php51/usr/bin/php',
'5.2': '/opt/alt/php52/usr/bin/php',
'5.3': '/opt/alt/php53/usr/bin/php',
'5.4': '/opt/alt/php54/usr/bin/php',
'5.5': '/opt/alt/php55/usr/bin/php',
'5.6': '/opt/alt/php56/usr/bin/php',
'4.4': '/opt/alt/php44/usr/bin/php',
'7.0': '/opt/alt/php70/usr/bin/php',
'7.1': '/opt/alt/php71/usr/bin/php',
'native': '/usr/bin/php'}
"""
cl_select = clselect.ClSelect()
# Reads /etc/cl.selector/selector.conf
return cl_select.get_all_php_binaries_paths()
def build_dat_files(only_native=False):
"""
Generates cache files (.dat) for alt-php versions
:return: None
"""
try:
all_php_paths = _get_all_php_paths()
if only_native:
all_php_paths = (
{"native": all_php_paths["native"]}
if all_php_paths.get("native")
else {}
)
# prepare dir
secureio.create_dir_secure(
path=clselect.ClSelect.CACHEFILE_CAGEFS_DIR,
perm=0o755,
uid=0,
gid=0,
parent_path=os.path.dirname(clselect.ClSelect.CACHEFILE_CAGEFS_DIR))
# cache built-in modules
for version, php_bin_path in all_php_paths.items():
# if php binary is not exist - pass this version
if not os.path.exists(php_bin_path):
continue
# Build arguments
php_args_base = [
php_bin_path,
"-d",
"opcache.enable_cli=0",
"-d",
"display_startup_errors=0",
"-d",
"display_errors=1",
"-d",
"error_reporting=E_ALL",
]
php_args = php_args_base[:]
php_args.append("-qm")
if version != "native":
# Set PHP_INI_SCAN_DIR equal to the path to an empty directory
# (directory absence in case if CageFS not installed suits too, doesn't generate errors)
# to avoid loading any additional .ini files (e.g. /opt/alt/phpXX/etc/php.d/default.ini)
env_data = {"PHP_INI_SCAN_DIR": "/usr/share/cagefs/.cagefs.empty"}
else:
env_data = None
# Run php binary
php_output = clselect.utils.run_command(php_args, env_data=env_data)
for filename in (
clselect.ClSelect.CACHEFILE_PATTERN % version,
clselect.ClSelect.CACHEFILE_CAGEFS_PATTERN % version,
):
_write_lines_to_file(filename, php_output)
if version == "native":
php_output = clselect.utils.run_command(php_args_base + ["-n", "-v"])
for filename in (
clselect.ClSelect.CACHEFILE_NATIVE_VER_PATTERN,
clselect.ClSelect.CACHEFILE_NATIVE_VER_CAGEFS_PATTERN,
):
_write_lines_to_file(filename, php_output)
except ClSelectExcept.ConfigNotFound:
# /etc/cl.selector/selector.conf absent - no alt-php installed - ignore
pass
except Exception as e:
sys.stderr.write(str(e))
def prepare():
"""
Switch the working directory and parse CLI arguments.
:return: Dataclass with CLI option flags.
:rtype: CachePhpDataOpts
"""
# Some alt-php versions (specifically alt-php51) could try to load
# files ./php.ini and ./php-cli.ini relative to the current directory.
# This is unsafe if it ever executes under root from a directory
# in which a user can write a malicious INI file to, e.g. /home/user1.
# While this is supposed to be fixed on alt-php level, we can additionally secure
# this attack vector by changing the working dir here.
# The root directory is safe from such attacks, and always exists.
# See CLARCH-105 for details.
root_dir_path = os.path.abspath(os.sep)
os.chdir(root_dir_path)
cmd_opts = CachePhpDataOpts()
try:
opts, _ = getopt.getopt(sys.argv[1:], "dhn", ["delete", "help", "native"])
except getopt.GetoptError as err:
print(str(err))
usage()
sys.exit(2)
for o, _ in opts:
if o in ("-h", "--help"):
cmd_opts.usage = True
elif o in ("-d", "--delete"):
cmd_opts.delete_cache = True
elif o in ("-n", "--native"):
cmd_opts.only_native = True
else:
usage()
sys.exit(2)
return cmd_opts
def main():
"""
Main function.
Depending on options, either creates or deletes PHP cache files.
"""
opts = prepare()
try:
if opts.usage:
usage()
sys.exit(2)
elif opts.delete_cache:
for file_name in [
pattern % version
for version, _path in _get_all_php_paths()
for pattern in [clselect.ClSelect.CACHEFILE_PATTERN, clselect.ClSelect.CACHEFILE_CAGEFS_PATTERN]
] + [
clselect.ClSelect.CACHEFILE_NATIVE_VER_PATTERN,
clselect.ClSelect.CACHEFILE_NATIVE_VER_CAGEFS_PATTERN,
]:
try:
os.unlink(file_name)
except (OSError, IOError):
pass
sys.exit(0)
except ClSelectExcept.ConfigNotFound:
# /etc/cl.selector/selector.conf absent - no alt-php installed - ignore
pass
except Exception as e:
sys.stderr.write(str(e))
# Creates .dat file for each php version
build_dat_files(opts.only_native)
sys.exit(0)
if __name__ == "__main__":
main()
Zerion Mini Shell 1.0