Edit file File name : extensions.py Content :# -*- 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 from __future__ import print_function from __future__ import division from __future__ import absolute_import import sys import os import pwd from future.moves import configparser as ConfigParser import subprocess import signal import re import tempfile from builtins import map from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH # To keep all configuration under one name selector_conf = { 'ALTERNATIVES_CONFIG':'/etc/cl.selector/selector.conf', 'DEFAULTS_CONFIG':'/etc/cl.selector/defaults.cfg', 'CAGEFS_PATH':'/var/cagefs', 'NATIVE_PATH':'/usr/share/cagefs-skeleton/usr/selector', 'CAGEFS_CHECK_PATH':'/usr/share/cagefs-skeleton/bin', 'USER_SKELETON_PATH':'/usr/selector', 'SYS_ALT_PATH':'/opt/alt', 'PHP_INI':'alt_php.ini', 'NATIVE_CONF':'/etc/cl.selector/native.conf', 'NEW_INI_PATH':'/usr/share/cagefs-skeleton/usr/selector.etc/php.ini' } # Conflicting extesions that must not be enabled together conflicts = { 'eaccelerator':set(['apc','xcache', 'xcache_3']), 'apc':set(['eaccelerator','xcache','zend_optimizer', 'xcache_3']), 'xcache':set(['apc','eaccelerator', 'xcache_3']), 'xcache_3':set(['apc','eaccelerator', 'xcache']), 'zend_optimizer':set(['apc']), 'idn':set(['intl']), 'intl':set(['idn']), } def user_check(username): try: pwd.getpwnam(username) except KeyError: return None return str( pwd.getpwnam(username).pw_uid )[-2:] def cagefs_user_check(username): """ Check that cagefs enabled for user """ LIBDIR = '/usr/share/cagefs' sys.path.append(LIBDIR) try: import cagefsctl except ImportError: print('ERROR: CageFS not installed.') sys.exit(1) try: return cagefsctl.is_user_enabled(username) except AttributeError: print('ERROR: CageFS version is unsupported. Please update CageFS.') sys.exit(1) def process_config(item): """ Parses selector config file and returns an installed selector versions in the dictionary config file format: php 5.4 5.4.9 /opt/alt/php54/usr/bin/php-cgi php-cli 5.4 5.4.9 /opt/alt/php54/usr/bin/php php-fpm 5.4 5.4.9 /opt/alt/php54/usr/sbin/php-fpm php.ini 5.4 5.4.9 /opt/alt/php54/etc/php.ini """ try: data = getattr( process_config,'data' ) return data except AttributeError: pass names = {} if not os.path.isfile(selector_conf['ALTERNATIVES_CONFIG']): print('WARN:Alternatives config not found. Using native version') return names for line in open(selector_conf['ALTERNATIVES_CONFIG']): stripped_line = line.strip() if stripped_line == "": continue subj, major, full, path = stripped_line.split() # parsing line by spaces if item not in subj: continue if major not in names: names[major] = {} names[major]['full'] = full if 'paths' not in names[major]: names[major]['paths'] = {} names[major]['paths'][subj] = path process_config.data = names return names def process_defaults(item, version=None): """ Parses defaults config and returns state of versions (enabled/disabled) and default version """ c = ConfigParser.ConfigParser(interpolation=None, strict=False) config = c.read( [ selector_conf['DEFAULTS_CONFIG'] ] ) # if no defaults.cfg, native is assumed to be default if not config: if not version: return {'native':set(['default'])} return '' if version: if c.has_option(item + version, 'modules'): return c.get(item + version, 'modules') else: return '' default_version = 'native' # set default to native to start with versions = {} for i in c.sections(): if i.startswith(item): #strip interpreter name from version v = i[len(item):] versions[v] = set() # add 'disabled' flag to versions set if disabled if c.has_option(i,'state') and c.get(i,'state') == 'disabled': versions[v].add('disabled') if c.has_option('versions',item): default_version = c.get('versions',item) if not default_version in versions: versions[default_version] = set() # mark default version versions[default_version].add('default') return versions def process_conflicts(extlist): """ Get a comma-separated extensions string and returns extensions set having taken into account conficting extensions """ if not extlist: return set() if type(extlist) is str: extlist = extlist.split(',') # extensions to enable extset = set() for ext in extlist: if ext in conflicts: i = extset.intersection(conflicts[ext]) if not i: # no conflicts extset.add(ext) else: # print warnings and skip the extension print('WARN:' + ext + ' skipped as conflicting (' + ','.join(i) + ').') continue else: extset.add(ext) return extset def get_sys_alt_path(item, version=None): """ Returns system alternatives path or error if it does not exist """ if not version: print("ERROR:no version") sys.exit(1) else: if '.' not in version: print("ERROR:wrong version") sys.exit(1) module_dir = os.path.join( selector_conf['SYS_ALT_PATH'], item + version.replace( '.', '' ), 'etc', item + '.d.all' ) if not os.path.isdir( module_dir ): print('ERROR:Alternatives directory not found.') sys.exit(2) return module_dir skip_user_check = False def get_user_ext_path(item, username, version): cagefs_user_path = user_check(username) if not cagefs_user_path: print("ERROR:No such user") return None if not skip_user_check: if not cagefs_user_check(username): print("ERROR:User is not in cagefs") return None user_modules_dir = os.path.join( selector_conf['CAGEFS_PATH'], cagefs_user_path, username, 'etc', 'cl.'+item+'.d' ) if not os.path.isdir( user_modules_dir ): print('ERROR:No user alternatives directory.') return None return os.path.join( user_modules_dir, 'alt-' + item + version.replace( '.', '' ) ) def get_user_path(username): """ Return user cl selector path or None if a problem arises """ cagefs_user_path = user_check(username) if not cagefs_user_path: print("ERROR:No such user") return None if not skip_user_check: if not cagefs_user_check(username): print("ERROR:User is not in cagefs") return None # A given user ETC path # (e.g. /var/cagefs/07/blissie/etc/cl.selector) # for interpreter binaries symlinks selector_path = os.path.join( selector_conf['CAGEFS_PATH'], cagefs_user_path, username, 'etc', 'cl.selector' ) return selector_path def process_dependencies(item, version, ext): """ Finds dependencies for an extension """ try: getattr( process_dependencies,'paths' ) except AttributeError: process_dependencies.paths = {} if version in process_dependencies.paths: sys_alt_path = process_dependencies.paths[version] else: sys_alt_path = get_sys_alt_path( item, version ) process_dependencies.paths[version] = sys_alt_path file = os.path.join( sys_alt_path, ext+'.ini' ) if not os.path.isfile(file): print("WARN:No such extension (%s)" % (ext,)) return [] quirks = {'ixed':'sourceguardian'} ini = open( file, 'r' ) extlist = [] extdict = {} templist = [] for line in ini: if line.startswith('\n'): continue if line.startswith(';') or line.startswith('#'): continue # We single out strings containing 'extension' word and # try to figure out an extension name if 'extension' in line: if '/' in line: extname = line[ line.rfind('/')+1:line.find('.') ] else: extname = line[ line.find('=')+1:line.find('.') ].lstrip(r' "') if '-' in extname: extname = extname[ :extname.rfind('-') ] if extname in quirks: extname = quirks[extname] elif ext in extname: extname = ext elif ('_' in ext) and (''.join(map((lambda x:x.capitalize()),ext.split('_'))) == extname): extname = ext extlist.append(extname) try: extdict[extname].append(line) except NameError: templist.append(line) except KeyError: extdict[extname] = [] extdict[extname].append(';---'+extname+'---\n') extdict[extname].extend(templist) templist = [] extdict[extname].append(line) ini.close() final_list = [] for ext in extlist: final_list.append( {'name':ext,'data':extdict[ext]} ) return final_list def update_defaults(item, version, modules=None, action=None): """ Updates default interpreter version and moduleset for a version indefaults.cfg """ if os.geteuid() != 0: print("ERROR:Superuser privileges required") sys.exit(1) if not version: print("ERROR:Version must be specified") return data = {} if os.path.isfile( selector_conf['DEFAULTS_CONFIG'] ): cfg=open(selector_conf['DEFAULTS_CONFIG'],'r') for line in cfg: if line.startswith('\n'): continue if line.startswith(';') or line.startswith('#'): continue if '[' in line and ']' in line: section = line[line.find('[')+1:line.rfind(']')].strip() if section not in data: data[section] = {} continue if item in line: try: data[section][item] = line[line.index('=')+1:].strip() except ValueError: pass continue if 'modules' in line: try: modlist = line[line.index('=')+1:].strip() except ValueError: continue try: data[section]['modules'] = modlist except (NameError, KeyError): pass continue if 'state' in line and 'disabled' in line: try: data[section]['state'] = 'disabled' except (NameError, KeyError): pass cfg.close() if 'versions' not in data: # no file data['versions'] = {} data['versions'][item] = 'native' # update modules list taking into account # conflicts and dependencies version_key = item + version if modules: extlist = [] extset = set() for ext in process_conflicts(modules): for _e in process_dependencies(item, version, ext): if _e['name'] in extset: # this module has already been enabled continue if _e['name'] != ext and _e['name'] not in modules: # this is a dependency. Inform about it print("WARN:%s enabled as dependency (%s)" % (_e['name'], ext)) extset.add(_e['name']) extlist.append(_e['name']) modules = ','.join(extlist) if version_key not in data: data[version_key] = {} data[version_key]['modules'] = modules elif action: if action == 'disable': if version_key not in data: data[version_key] = {} data[version_key]['state'] = 'disabled' else: if version_key in data and 'state' in data[version_key]: del data[version_key]['state'] if 'native' in version_key: del data[version_key] else: data['versions'][item] = version cfg=open(selector_conf['DEFAULTS_CONFIG'],'w') v = data.pop('versions') # versions section must be on top if item in v: cfg.write( "[versions]\n%s=%s\n\n" % ( item, v[item] ) ) for d in sorted(data.keys()): options = [] for o in data[d]: options.append( o + '=' + data[d][o] ) cfg.write( "[%s]\n%s\n\n" % ( d, '\n'.join(options) ) ) cfg.close() def get_alternatives( item, username ): """ Returns currently selected interpreter version of a binary for a specified user """ entries = process_config(item) if not username: defaults = process_defaults(item) if defaults: default = list(filter((lambda x:'default' in defaults[x]),list(defaults.keys())))[0] if default in entries: return { 'major': default, 'full': entries[default]['full'], 'paths': list(map( (lambda x: entries[default]['paths'][x]), list(entries[default]['paths'].keys()) )) } else: return {'major': default, 'full': default, 'paths': []} return {} selector_path = get_user_path(username) if not selector_path: sys.exit(1) if os.path.isdir(selector_path): for obj in os.listdir(selector_path): if not obj.startswith(item): continue link_to_alternative = os.path.join( selector_path, obj ) if os.path.islink( link_to_alternative ): link_destination = os.readlink( link_to_alternative ) if item == obj and os.path.dirname(link_destination) == selector_conf['USER_SKELETON_PATH']: return { 'major':'native', 'full':'native', 'paths':[link_destination] } for key in entries: if item in entries[key]['paths'] and entries[key]['paths'][item] == link_destination: return { 'major':key, 'full':entries[key]['full'], 'paths':list(map( (lambda x:entries[key]['paths'][x]), list(entries[key]['paths'].keys()) )) } return {} def get_alternatives_summary( item, username ): """ Returns alternatives set and marks selected alternative """ entries = process_config(item) # get defaults as a dictionary defaults = process_defaults(item) for v in defaults.keys(): if 'default' in defaults[v]: default_version = v output = {} # native version is always present output['native'] = set() if 'native' in defaults: output['native'].update(defaults['native']) for key in entries: if key not in output: output[key] = set() if key in defaults: output[key].update(defaults[key]) if not username: return output selector_path = get_user_path(username) if not selector_path: sys.exit(1) if os.path.isdir(selector_path): for obj in os.listdir(selector_path): if not obj.startswith(item): continue link_to_alternative = os.path.join( selector_path, obj ) if os.path.islink( link_to_alternative ): link_destination = os.readlink( link_to_alternative ) if item == obj and os.path.dirname(link_destination) == selector_conf['USER_SKELETON_PATH']: if 'disabled' in output['native']: print('WARN:Native version is disabled. Defaults used') set_alternatives(item, default_version, username, True) output[default_version].add('selected') return output else: output['native'].add('selected') return output for key in entries: if item in entries[key]['paths'] and entries[key]['paths'][item] == link_destination: if 'disabled' in output[key]: print('WARN:Version %s is disabled. Defaults used' % (key,)) set_alternatives(item, default_version, username, True) output[default_version].add('selected') return output else: output[key].add('selected') return output def set_alternatives( item, version, username, backup=False ): if not os.path.isdir(selector_conf['CAGEFS_CHECK_PATH']): print('ERROR:CageFS not found.') sys.exit(2) new_ini_set = False entries = process_config(item) if not entries: return selector_path = get_user_path(username) if not selector_path: sys.exit(1) if not os.path.isdir( selector_path ): print('ERROR:No user selector directory.') sys.exit(2) for file in os.listdir( selector_path ): if item not in file: continue link_to_alternative = os.path.join( selector_path, file ) if os.path.islink( link_to_alternative ) or os.path.isfile( link_to_alternative ): try: os.unlink( link_to_alternative ) except OSError as e: if e.errno == 2: pass else: print("ERROR: %s %s" % ( e.strerror, file )) sys.exit(2) if version == 'native': if not os.path.isdir(selector_conf['NATIVE_PATH']): print('ERROR:No directory for native binary.') sys.exit(2) if os.path.exists(selector_conf['NEW_INI_PATH']): try: target = os.path.basename(selector_conf['NEW_INI_PATH']) source = os.path.join( selector_conf['USER_SKELETON_PATH']+'.etc', target) destination = os.path.join(selector_path, target) os.symlink(source, destination) new_ini_set = True except OSError as e: print("Could not create a symlink: %s" % ( e.strerror, )) sys.exit(1) for binary in os.listdir( selector_conf['NATIVE_PATH'] ): if item not in binary: continue if binary.endswith('.ini') and new_ini_set: continue destination = os.path.join( selector_path, binary ) source = os.path.join( selector_conf['USER_SKELETON_PATH'], binary ) try: os.symlink( source, destination ) except OSError as e: print("Could not create a symlink: %s" % ( e.strerror, )) sys.exit(1) else: for source in entries[version]['paths'].keys(): destination = os.path.join( selector_path, source ) try: os.symlink( entries[version]['paths'][source], destination ) except OSError as e: print("Could not create a symlink: %s" % ( e.strerror, )) sys.exit(1) # Rewrite user php.ini if item == 'php': is_error = False try: from clcagefslib.selector.panel.da import da_change_user_php_ini from clcagefslib.selector.panel.isp import ispmanager_create_user_wrapper except ImportError as e: print("Could not import cagefs module: %s" % str(e)) is_error = True if not is_error: da_change_user_php_ini(username, version) ispmanager_create_user_wrapper(username, version) from clselect.cluserselect import ClUserSelect pw = pwd.getpwnam(username) ClUserSelect.switch_symlink_for_alt_php(version, pw, exit_on_error=False) if backup: save_config(item, username) reload_processes(item, username) def list_extensions( item, username, version=None, showall=False ): """ Collects info about enabled and all installed selector extensions for a specified (or currently selected version) and returns it in ordered structure for further processing """ if version: if version == 'native': if username: print("WARN:No extensions for native binary") sys.exit(0) else: return dict.fromkeys(get_builtins(item,version),-1) else: if not '.' in version: print('ERROR:Wrong version format') sys.exit(1) else: if username: version = get_alternatives( item, username )['major'] else: config_data = process_defaults(item) for v in config_data.keys(): if 'default' in config_data[v]: version = v break enabled = {} if username: user_dir = get_user_ext_path(item, username, version) if not user_dir: sys.exit(2); user_path = os.path.join(user_dir, selector_conf['PHP_INI']) if os.path.isfile(user_path): ini_file = open(user_path, 'r') for line in ini_file: if line.startswith(';---'): module_name = line[ 4 : line.rfind('---') ] enabled[module_name] = 1 ini_file.close() if not showall: return [ enabled ] ini_dir = get_sys_alt_path( item, version ) modules = {} for entry in os.listdir( ini_dir ): if not entry.endswith('.ini'): continue modules[ entry[ : entry.find('.ini') ] ] = 0 if username: return [ enabled, modules ] enabled = process_defaults(item, version) for ext in enabled.split(','): if ext in modules: modules[ext] = 1 modules.update( dict.fromkeys( get_builtins( item, version ), -1 ) ) return modules def enable_extension( item, usernames, extstring, version=None, backup=False ): """ Enable comma-separated list of extensions for comma-separated list of users Enabling extesions is made by means of regenerating one .ini file for enabled modules """ if version: if (version == 'native'): print("WARN:Operation not supported") sys.exit(0) else: if not '.' in version: print("ERROR:Wrong version (" + version + ")") sys.exit(1) for username in usernames.split(','): if not version: version = get_alternatives( item, username)['major'] user_dir = get_user_ext_path(item, username, version) if not user_dir: continue user_path = os.path.join(user_dir, selector_conf['PHP_INI']) ini_dir = get_sys_alt_path(item, version) # Use _load_ini_contents to read extensions and options from clselect.cluserextselect import ClUserExtSelect content, extlist, extdict = ClUserExtSelect._load_ini_contents(user_path) checklist = extlist[:] checklist.extend(extstring.split(',')) checked_set = process_conflicts(checklist) for ext in extstring.split(','): if ext not in checked_set: continue for _e in process_dependencies(item, version, ext): if _e['name'] in extdict: # this module has already been enabled continue if _e['name'] != ext: # this is a dependency. Inform about it print("WARN:%s enabled as dependency (%s)" % (_e['name'], ext)) extlist.append(_e['name']) extdict[_e['name']] = _e['data'] if 'ioncube_loader' in extdict: content.append( ''.join( extdict['ioncube_loader'] ) ) del extdict['ioncube_loader'] for ext in extlist: if ext in extdict: content.append( ''.join( extdict[ext] ) ) process_path( username, user_dir, selector_conf['PHP_INI'], "\n".join(content)+"\n" ) if backup: save_config( item, username ) reload_processes( item, username ) def disable_extension( item, usernames, extnames, version=None, backup=False ): if version: if (version == 'native'): print("WARN:Operation not supported") sys.exit(0) else: if not '.' in version: print("ERROR:Wrong version (" + version + ")") sys.exit(1) for username in usernames.split(','): if not version: version = get_alternatives( item, username)['major'] user_dir = get_user_ext_path(item, username, version) if not user_dir: continue if not os.path.isdir( user_dir ): continue user_path = os.path.join(user_dir, selector_conf['PHP_INI']) if not os.path.isfile(user_path): continue ini_dir = get_sys_alt_path(item, version) # Use _load_ini_contents to read extensions and options from clselect.cluserextselect import ClUserExtSelect content, extlist, extdict = ClUserExtSelect._load_ini_contents(user_path) exclusions_set = set( extnames.split(',') ) depdict = {} for ext in extlist: extset = set(map((lambda x:x['name']), process_dependencies(item, version, ext))) if len(extset) > 1: # there are dependencies extset.discard(ext) # leave only dependencies in set for s in extset: if s not in depdict: depdict[s] = set() depdict[s].add(ext) # to form dependencies dictionary for ext in extlist: if ext in exclusions_set: # if we want to remove extension if ext in depdict: # but if we see it is a dependency if set(extlist).intersection(depdict[ext]) and exclusions_set.intersection(depdict[ext]) != depdict[ext]: print("WARN:%s left as dependency (%s)" % (ext, ','.join(depdict[ext]))) continue # we skip it if dependant modules are to be left del extdict[ext] # else remove it for ext in extlist: if ext in extdict: content.append( ''.join( extdict[ext] ) ) process_path( username, user_dir, selector_conf['PHP_INI'], "\n".join(content)+"\n" ) if backup: save_config( item, username ) reload_processes( item, username ) # ToDo: not used ? def update_extensions( item, usernames, extstring, version=None, backup=False ): """ Enable comma-separated list of extensions for comma-separated list of users Enabling extesions is made by means of regenerating one .ini file for enabled modules """ if version: if (version == 'native'): print("WARN:Operation not supported") sys.exit(0) else: if not '.' in version: print("ERROR:Wrong version (" + version + ")") sys.exit(1) for username in usernames.split(','): if not version: version = get_alternatives( item, username)['major'] user_dir = get_user_ext_path(item, username, version) if not user_dir: continue if not os.path.isdir( user_dir ): continue user_path = os.path.join(user_dir, selector_conf['PHP_INI']) if not os.path.isfile(user_path): continue ini_dir = get_sys_alt_path(item, version) extdict = {} extlist = [] content = [] ini_file = open(user_path, 'r') is_content = False for line in ini_file: # we want to preserve stuff in this section # Check if it is content block if line.startswith(';>==='): is_content = True content.append(line) # Processing content elif is_content: # Skip comments if line.startswith(';') and not line.startswith(';<==='): continue # Append until the end of block ('<===') content.append(line) if line.startswith(';<==='): is_content = False ini_file.close() for ext in process_conflicts(extstring): for _e in process_dependencies(item, version, ext): if _e['name'] in extdict: # this module has already been enabled continue if _e['name'] != ext and _e['name'] not in extstring: # this is a dependency. Inform about it print("WARN:%s enabled as dependency (%s)" % (_e['name'], ext)) extlist.append(_e['name']) extdict[_e['name']] = _e['data'] if 'ioncube_loader' in extdict: content.append( ''.join( extdict['ioncube_loader'] ) ) del extdict['ioncube_loader'] for ext in extlist: if ext in extdict: content.append( ''.join( extdict[ext] ) ) process_path( username, user_dir, selector_conf['PHP_INI'], "\n".join(content)+"\n" ) if backup: save_config( item, username ) reload_processes( item, username ) def save_config( item, username ): config = {} userindex = user_check(username) path = os.path.join('/var/cagefs', userindex, username, 'etc/cl.selector') modpath = os.path.join('/var/cagefs',userindex, username, 'etc/cl.php.d' ) config_path = os.path.join( pwd.getpwnam(username).pw_dir, '.cl.selector' ) if not os.path.isdir(path): return else: for i in ['php', 'php-cli', 'lsphp', 'php-fpm']: fullpath = os.path.join(path,i) if not os.path.islink(fullpath): continue linkpath = os.path.realpath(fullpath) if linkpath.startswith(selector_conf['USER_SKELETON_PATH']): config['versions'] = item + '=native' break elif linkpath.startswith(selector_conf['SYS_ALT_PATH']): try: # extract string like 'php54' from path like /opt/alt/php54/etc/php.d.all version_string = linkpath[ linkpath.index( '/', len(selector_conf['SYS_ALT_PATH']) )+1 : linkpath.index( '/', len(selector_conf['SYS_ALT_PATH'])+1 ) ] version_string = version_string[len(item):] config['versions'] = '='.join( ( item, '.'.join( (version_string[:1], version_string[1:],) ) ) ) break except ValueError: continue # traverse subdirectories and extract versions # from directory names strings like 'alt-php54' if os.path.isdir(modpath): for version in os.listdir(modpath): version_path = os.path.join(modpath,version) try: digits = version[ version.index(item)+len(item): ] # Handle incorrect paths if digits.find('\\') >= 0: continue section = item + '.'.join( ( digits[:1], digits[1:] ) ) config[section] = [] except ValueError: continue content = [ "[versions]\n" + config.pop('versions') + "\n" ] for v in config: content.append('[' + v + "]\nmodules=" + ','.join(list(list_extensions(item, username, v[len(item):])[0].keys())) + "\n") process_path( username, config_path, 'defaults.cfg', "\n".join(content)+"\n" ) def process_path(username, path, filename=None, filecontent=None): """ writes files changing to target user uid/gid """ obj_uid = pwd.getpwnam(username).pw_uid obj_gid = pwd.getpwnam(username).pw_gid euid_is_changed = False subj_euid = os.geteuid() subj_egid = os.getegid() filepath = os.path.join(path, filename) if os.path.islink(filepath): try: os.unlink(filepath) except OSError: print("ERROR:cannot delete symlink in user home") sys.exit(13) if subj_euid != obj_uid: try: os.setegid(obj_gid) os.seteuid(obj_uid) euid_is_changed = True except OSError: print("ERROR:Failed to change to %s EUID" % (username,)) sys.exit(1) if not os.path.isdir(path): try: os.mkdir(path) except OSError: pass if filename and filecontent: file_path = os.path.join( path, filename ) try: fd, temp_path = tempfile.mkstemp( prefix='lvetmp_', dir=path ) file = os.fdopen(fd, 'w') file.write(filecontent) file.close() except (IOError, OSError): try: if os.path.exists(temp_path): os.unlink(temp_path) except: pass else: try: mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH os.rename(temp_path, file_path) os.chmod(file_path, mask) except OSError: pass if euid_is_changed: os.setegid(subj_egid) os.seteuid(subj_euid) def reload_processes( item, username ): ps = subprocess.Popen(['/bin/ps','-U',username,'-u',username],stdout=subprocess.PIPE) lines = ps.communicate()[0].split("\n") processes = [] for row in lines: parts = row.rstrip().split() try: parts[-1].index(item) os.kill( int(parts[0]), signal.SIGHUP ) except IndexError: continue except ValueError: continue def get_builtins(item, version): data = process_config(item) binary = item + '-cli' if version in data: path = data[version]['paths'][binary] else: path = get_native_path(item) list = subprocess.Popen([path,'-qm'],stdout=subprocess.PIPE,stderr=subprocess.STDOUT) lines = list.communicate()[0] zend_index = lines.find('[Zend') patt = re.compile(r"^\w") stripped = lines[:((zend_index >= 0 and zend_index) or len(lines))] builtins = [] for ext in stripped.split("\n"): if not patt.match(ext): continue builtins.append("_".join( re.split( "\s+", ext.lower() ) ) ) return builtins def get_native_path(item): """ Returns native interpreter binary path """ if os.path.isfile(selector_conf['NATIVE_CONF']): cfg = open(selector_conf['NATIVE_CONF']) binary = item + '-cli' binary_paths = [] for line in cfg: if line.startswith('#'): continue if binary in line: path = line[line.find(binary)+len(binary)+1:].strip('\'"=\n ') binary_paths.append(path) for p in binary_paths: if os.path.isfile(p) and not os.path.islink(p): return p # if not found suppose cpanel cli binary return '/usr/bin/php' Save