diff --git a/pym/cl_distr.py b/pym/cl_distr.py index 2e14a93..e15a376 100644 --- a/pym/cl_distr.py +++ b/pym/cl_distr.py @@ -507,7 +507,7 @@ class Distributive(object, SignalInterrupt): if not rsyncCmd: raise DistributiveError(_("Failed to find '%s' command")%"rsync") try: - rsyncProcess = process(rsyncCmd, "-a","-H", "-x", + rsyncProcess = process(rsyncCmd, "-a","-H", "-x","-XX", "%s/"%fromdir,"%s/"%todir,stderr=STDOUT) self.addInterruptProcess(rsyncProcess) res = rsyncProcess.success() diff --git a/pym/cl_template.py b/pym/cl_template.py index 99aabf6..a822251 100644 --- a/pym/cl_template.py +++ b/pym/cl_template.py @@ -4233,6 +4233,9 @@ re.M|re.S) templateDirFile) return ("", False, []) + if " env=" in textTemplate: + return ("", False, []) + # Заменяем переменные на их значения textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) @@ -4878,6 +4881,8 @@ re.M|re.S) self.closeTemplFile() # Флаг копирования шаблона в конфигурационный файл flagCopyTemplate = True + if " env=" in self.textTemplate.partition('\n')[0]: + return False # Тип шаблона бинарный или текстовый templateFileType = self.getTemplateType() if templateFileType != "bin": @@ -5380,6 +5385,9 @@ class templateClt(scanDirectoryClt, template): return False return (self.createdDirs, self.filesApply) +class IniError(Exception): + pass + class iniParser(_error, templateFormat): """Класс для работы с ini файлами @@ -5408,6 +5416,16 @@ class iniParser(_error, templateFormat): def openRWIniFile(self): if not os.access(self.iniFile, os.R_OK): + if not os.path.exists(self.iniFile): + try: + # Создание файла + self.FD = open(self.iniFile, "w+") + fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX) + os.chmod(self.iniFile, self.mode) + except: + error = _("Unable to create the file") + ": " + self.iniFile + self.setError(error) + raise IniError(error) return "" try: self.FD = open(self.iniFile, "r+") @@ -5423,16 +5441,6 @@ class iniParser(_error, templateFormat): self.setError(_("Unable to write to the file") + ": " + self.iniFile) return False - if not os.path.exists(self.iniFile): - try: - # Создание файла - self.FD = open(self.iniFile, "w+") - fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX) - os.chmod(self.iniFile, self.mode) - except: - self.setError(_("Unable to create the file") + - ": " + self.iniFile) - return False if not self.FD: self.setError(_("Unable to write to the file") + ": " + self.iniFile) @@ -5440,8 +5448,6 @@ class iniParser(_error, templateFormat): self.FD.truncate(0) self.FD.seek(0) self.FD.write(txtConfig) - self.FD.close() - self.FD = None return True def setVar(self, strHeader, dictVar): @@ -5451,37 +5457,50 @@ class iniParser(_error, templateFormat): strHeader - имя области dictVar - словарь переменных """ - textIni = self.openRWIniFile() - nameFomat = self.checkIniFile(textIni) - if not nameFomat: - return False - if type(strHeader) in (tuple, list): - # формат plasma - classObj = self.getClassObj("plasma") - else: - if nameFomat == "plasma": - self.setError(_("Trying to write a variable of 'samba' format" - " to file %s (format - 'plasma')") - %self.iniFile) + try: + textIni = self.openRWIniFile() + nameFomat = self.checkIniFile(textIni) + if not nameFomat: return False - # формат samba - classObj = self.getClassObj("samba") - # создаем объект - # и записываем в него содержимое ini-файла - objIni = classObj(textIni) - # создаем текст из строки заголовка и - # словаря переменных области - txtConfig = objIni.createTxtConfig(strHeader, dictVar) - # создаем объект и записываем в него текст - objIniAdd = classObj(txtConfig) - # объединяем объекты для получения результирующего текста - objIni.join(objIniAdd) - # получаем текст - txtConfig = objIni.getConfig().encode("UTF-8") - # записываем его в ini файл - if not self.writeIniFile(txtConfig): + if type(strHeader) in (tuple, list): + # формат plasma + classObj = self.getClassObj("plasma") + else: + if nameFomat == "plasma": + self.setError(_("Trying to write a variable of 'samba' format" + " to file %s (format - 'plasma')") + %self.iniFile) + return False + # формат samba + classObj = self.getClassObj("samba") + # создаем объект + # и записываем в него содержимое ini-файла + objIni = classObj(textIni) + # создаем текст из строки заголовка и + # словаря переменных области + txtConfig = objIni.createTxtConfig(strHeader, dictVar) + # создаем объект и записываем в него текст + objIniAdd = classObj(txtConfig) + # объединяем объекты для получения результирующего текста + objIni.join(objIniAdd) + # получаем текст + txtConfig = objIni.getConfig().encode("UTF-8") + # записываем его в ini файл + if not self.writeIniFile(txtConfig): + return False + return True + except IniError: return False - return True + finally: + self._closeFD() + + def _closeFD(self): + if self.FD: + try: + self.FD.close() + except: + pass + self.FD = None def isEmptyFile(self, textIni): """Если файл пустой или содержит только комментарии - False diff --git a/pym/cl_utils.py b/pym/cl_utils.py index cd2acc5..2e1a607 100644 --- a/pym/cl_utils.py +++ b/pym/cl_utils.py @@ -124,7 +124,13 @@ class typeFile: def getMType(self, filename): """Информация о типе файла""" - ret = self.magicObject.file(filename) + try: + ret = self.magicObject.file(filename) + except UnicodeDecodeError: + try: + ret = self.magicObject.file(filename.decode('utf-8')) + except UnicodeDecodeError: + return None # fix for kernel 3.7.7 (bad work samba with big files) if ret is None and self.magicObject.errno() == 5: r,w = os.pipe() @@ -1473,3 +1479,44 @@ def countFiles(dirpath,onefilesystem=True): for dirname in mountDirs: dirnames.remove(dirname) return num + +class InitrdFile(object): + re_kver_path = re.compile("/modules/([^/]+)/kernel") + def __init__(self, _file): + self._file = _file + + def get_kernel_version(self): + for fn in self.get_names(): + if "/modules/" in fn and "/kernel" in fn: + m = self.re_kver_path.search(fn) + if m: + return m.group(1) + else: + break + return "" + + def get_names(self): + if not path.exists(self._file): + # raise IOError + open(self._file) + ftype = typeFile(magic=0x4).getMType + rdtype = ftype(self._file) + if "LZ4" in rdtype: + arch_cmd = '/usr/bin/lz4' + elif "XZ" in rdtype: + arch_cmd = '/usr/bin/xz' + else: + arch_cmd = '/bin/gzip' + gz = Popen([arch_cmd, "-dc", self._file], stdout=PIPE, stderr=PIPE, + close_fds=True) + cpio = Popen(["/bin/cpio","-tf"], stdout=PIPE, stdin=gz.stdout, + stderr=PIPE, close_fds=True) + try: + for fn in cpio.stdout.xreadlines(): + yield fn.rstrip() + finally: + cpio.terminate() + gz.terminate() + + def __iter__(self): + return iter(self.get_names()) diff --git a/pym/cl_vars_share.py b/pym/cl_vars_share.py index 52a114e..ec4981a 100644 --- a/pym/cl_vars_share.py +++ b/pym/cl_vars_share.py @@ -16,9 +16,11 @@ import os import sys -from cl_utils import getpathenv, runOsCommand, typeFile,process +from cl_utils import (getpathenv, runOsCommand, typeFile,process, + listDirectory, InitrdFile) import re from os import path, R_OK + try: from cl_ldap import ldapUser except ImportError: @@ -276,10 +278,13 @@ class varsShare: def getFilesByType(self,pathname,descr): """Get files from "pathname" has "descr" in descriptions""" - filelist = map(lambda x:path.join(pathname,x),os.listdir(pathname)) + return list(self.get_files_by_type(pathname, descr)) + + def get_files_by_type(self, pathname, descr): ftype = typeFile(magic=0x4).getMType - filesWithType = map(lambda x:(x,ftype(x)), filelist) - return filter(lambda x:descr in x[1],filesWithType) + for x in listDirectory(pathname, fullPath=True): + if descr in ftype(x): + yield x def getInitrd(self,arch,shortname,chroot,kernel,suffix="",notsuffix=""): """Get initrd for kernel""" @@ -629,3 +634,96 @@ class varsShare: return res[:8] else: return "no_uid" + + def get_current_kernel_src(self, prefix='/'): + """ + Get current kernel source directory + """ + src_path = "usr/src" + current_linux_src = path.join(src_path,"linux") + symlink_kernel = path.join(prefix,current_linux_src) + if not path.exists(symlink_kernel) or not path.islink(symlink_kernel): + raise ValueError("Failed to determine current kernel version") + return path.join(src_path,os.readlink(symlink_kernel)) + + def get_config_version(self, configfile): + re_config = re.compile("Automatically generated file;.*\n" + ".*?Linux/\S+\s+(\S+)\s", re.M) + if path.exists(configfile): + with open(configfile) as f: + match = re_config.search(f.read(200)) + if match: + return match.group(1) + + def get_src_kernel_version(self, kernel_src): + """ + Get version of kernel from .config + """ + config_path = path.join(kernel_src, ".config") + makefile_path = path.join(kernel_src, "Makefile") + + # get version from config + version = self.get_config_version(config_path) + if version: + return version + + # get version from Makefile + re_makefile = re.compile("^VERSION = (\S+)\n" + "PATCHLEVEL = (\S+)\n" + "SUBLEVEL = (\S+)\n" + "EXTRAVERSION = (\S*)\n", re.M) + if path.exists(makefile_path): + with open(makefile_path) as f: + match = re_makefile.search(f.read(200)) + if match: + return "{0}.{1}.{2}{3}".format(*match.groups()) + return "" + + def list_initramfs(self, prefix='/', bootdir='boot'): + boot_dir = path.join(prefix, bootdir) + return self.get_files_by_type(boot_dir,"ASCII cpio archive") + + def filter_initramfs(self, iterable, version=None): + for fn in iterable: + if InitrdFile(fn).get_kernel_version() == version: + yield fn + + def list_kernel(self, prefix='/', bootdir='boot'): + boot_dir = path.join(prefix, bootdir) + return self.get_files_by_type(boot_dir, "boot executable bzImage") + + def filter_kernel(self, iterable, version=None): + ftype = typeFile(magic=0x4).getMType + re_kver = re.compile("bzImage, version (\S+)\s") + for fn in iterable: + m = re_kver.search(ftype(fn)) + if m.group(1) == version: + yield fn + + def list_config(self, prefix='/', bootdir='boot'): + boot_dir = path.join(prefix, bootdir) + return self.get_files_by_type(boot_dir, "Linux make config build file") + + def filter_config(self, iterable, version=None): + for fn in iterable: + if self.get_config_version(fn) == version: + yield fn + + def list_system_map(self, prefix='/', bootdir='boot'): + boot_dir = path.join(prefix, bootdir) + for fn in listDirectory(boot_dir): + if fn.startswith("System.map"): + yield path.join(boot_dir, fn) + + def filter_system_map(self, iterable, version=None): + re_kver = re.compile("System.map-(\S+)$") + for fn in iterable: + m = re_kver.search(fn) + if m and m.group(1) == version: + yield fn + + def max_default(self, iterable, key=lambda x:x, default=None): + try: + return max(iterable, key=key) + except ValueError: + return default