# -*- coding: utf-8 -*- # Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import re from os import path from calculate.lib.datavars import (Variable, ReadonlyVariable, ReadonlyTableVariable, FieldValue, HumanReadable, VariableInterface) from calculate.lib.utils.files import (readFile, typeFile, process, listDirectory, MAGIC_SYMLINK, MAGIC_COMPRESS) from calculate.lib.utils.kernel import InitrdFile from calculate.lib.cl_lang import setLocalTranslate _ = lambda x: x setLocalTranslate('cl_install3', sys.modules[__name__]) from operator import itemgetter from calculate.lib.utils.files import readLinesFile from calculate.lib.utils.common import (getKernelUid, getTupleVersion, getValueFromCmdLine, CmdlineParams) from itertools import * from calculate.install.distr import DistributiveError class VariableOsInstallKernelScheduler(Variable): """ Install scheduler opts (cfq,bfq,none,deadline) """ type = "choice" opt = ["--scheduler"] metavalue = "SCHEDULER" def init(self): self.help = _("toggle the I/O scheduler") self.label = _("I/O scheduler") def check_scheduler(self, scheduler): return scheduler in self.Select('os_install_kernel_schedule_name', where='os_install_kernel_schedule_set', eq='on') def get_default(self): root_devs = self.Select('os_install_disk_parent', where='os_install_disk_mount', eq='/', limit=1).split(',') for root_dev in root_devs: dev_ssd, dev_virtual = self.Select(['os_device_ssd_set', 'os_device_virtual_set'], where='os_device_dev', eq=root_dev, limit=1) if ((dev_ssd == 'on' or dev_virtual == 'on') and self.check_scheduler("noop")): return "noop" return self.Get('os_install_kernel_schedule_default') def get(self): """Get scheduler for install root device""" if self.Get('os_root_type') == 'livecd': return self.get_default() else: currentScheduler = getValueFromCmdLine( CmdlineParams.IOScheduler) if currentScheduler in map(lambda x: x[0], self.choice()): return currentScheduler return self.Get('os_install_kernel_schedule_default') def choice(self): schedulers = {"deadline": "Deadline", "cfq": "CFQ", "noop": "No-op", "bfq": "BFQ"} return [(x, schedulers.get(x, x)) for x in self.Select('os_install_kernel_schedule_name', where='os_install_kernel_schedule_set', eq='on')] + [("auto", _("Default"))] def set(self, value): if value == "auto": return self.get_default() return value def uncompatible(self): """ Unavailable for flash installation """ if self.Get('os_install_root_type') == 'flash': return _("I/O scheduler unavailable for Flash install") class KernelConfig(object): def __init__(self, kernel_config): self.data = readFile(kernel_config).split('\n') self.config = kernel_config def __iter__(self): return iter(self.data) def __str__(self): return "kernel config (%s)" % self.config def __len__(self): return len(self.data) def __contains__(self, item): if "=" in item: if item.endswith("=n"): key = "# %s is not set" % item[:-2] else: key = item else: key = "%s=" % item return any(key in x for x in self) class VariableOsInstallKernelConfig(ReadonlyVariable): """ Install config kernel filename """ def get_kernel_src(self, distr_path): """ Get version of kernel from .config """ kernel_src = 'usr/src/linux' makefile_path = path.join(distr_path, kernel_src, "Makefile") # get version from Makefile re_makefile = re.compile(r"^VERSION = (\S+)\n" r"PATCHLEVEL = (\S+)\n" r"SUBLEVEL = (\S+)\n" r"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 configs(self, distr_path): src_kernel_ver = self.get_kernel_src(distr_path) if src_kernel_ver: yield path.join("boot", "config-%s" % src_kernel_ver) if self.Get('cl_chroot_path') == '/': ver = process('/bin/uname', '-r').read().strip() yield path.join("boot", "config-%s" % ver) yield 'usr/src/linux/.config' def get(self): image = self.Get('cl_image') if image: with image: try: distrPath = image.getDirectory() for config in self.configs(distrPath): config_name = path.join(distrPath, config) if path.exists(config_name): return KernelConfig(config_name) except DistributiveError: return "" return "" class VariableOsKernelConfig(VariableOsInstallKernelConfig): """ Current config kernel """ def configs(self, distr_path): ver = process('/bin/uname', '-r').read().strip() yield path.join("boot", "config-%s" % ver) yield 'usr/src/linux/.config' def get(self): for config in self.configs("/"): config_name = path.join("/", config) if path.exists(config_name): return KernelConfig(config_name) return "" class VariableOsInstallKernelScheduleDefault(Variable): """ IO планировщик по умолчанию """ type = "choice" def get(self): for line in self.Get('os_install_kernel_config'): if "CONFIG_DEFAULT_IOSCHED=" in line: key, op, value = line.partition("=") return value.strip('"') return "cfq" def choice(self): return self.Select('os_install_kernel_schedule_name', where='os_install_kernel_schedule_set', eq='on') class VariableOsInstallKernelScheduleData(ReadonlyTableVariable): """ Information about kernel schedule """ source = ['os_install_kernel_schedule_name', 'os_install_kernel_schedule_set'] def get(self, hr=HumanReadable.No): schedulers = {'CONFIG_IOSCHED_BFQ=y': 'bfq', 'CONFIG_IOSCHED_NOOP=y': 'noop', 'CONFIG_IOSCHED_CFQ=y': 'cfq', 'CONFIG_IOSCHED_DEADLINE=y': 'deadline'} installed = list(map(schedulers.get, filter(lambda x: x in schedulers, self.Get('os_install_kernel_config')))) or ['cfq'] return [[x, "on" if x in installed else "off"] for x in sorted(schedulers.values())] setValue = Variable.setValue class VariableOsInstallKernelScheduleName(FieldValue, ReadonlyVariable): """ Schedule name """ type = "list" source_variable = "os_install_kernel_schedule_data" column = 0 class VariableOsInstallKernelScheduleSet(FieldValue, ReadonlyVariable): """ Kernel has schedule """ type = "list-bool" source_variable = "os_install_kernel_schedule_data" column = 1 class VariableOsInstallKernelTuxoniceSet(ReadonlyVariable): """ Available BFQ in kernel """ type = "bool" def get(self): if any("CONFIG_TOI_CORE=y" in x for x in self.Get('os_install_kernel_config')): return "on" return "off" class VariableOsInstallKernelBfqSet(ReadonlyVariable): """ Available BFQ in kernel """ type = "bool" def get(self): if any("CONFIG_IOSCHED_BFQ=y" in x for x in self.Get('os_install_kernel_config')): return "on" return "off" class VariableOsInstallNomodeset(Variable): type = "bool" def get(self): cmdLine = '/proc/cmdline' if 'nomodeset' in readFile(cmdLine): return "on" return "off" class VariableOsInstallKernelAttr(Variable): """ Install kernel attributes """ def get(self): def generate(): # 5 sec for usb hdd boot if self.GetBool('os_install_nomodeset'): yield "nomodeset" if self.Get('os_install_root_type') == 'usb-hdd': yield "scandelay=5" if (self.GetBool('os_install_mdadm_set') or self.GetBool('os_install_lvm_set')): yield "rd.auto" yield "rd.retry=40" return " ".join(generate()) class VariableOsInstallKernelResume(ReadonlyVariable): """ Install kernel resume """ def get(self): """install kernel resume parameter""" for dev, partuuid, install in zip(self.Get('os_install_disk_use'), self.Get('os_install_disk_partuuid'), self.Get('os_install_disk_mount')): if install == "swap": if self.Get('os_install_kernel_tuxonice_set') == 'on': return "tuxonice tuxonice_resume=%s real_resume=%s" % ( dev, dev) else: if partuuid: return "resume=PARTUUID=%s" % partuuid else: return "resume=%s" % dev return "" class KernelHelper(VariableInterface): """ Helper for kernel variables """ reFindVer = re.compile( r"(?<=version )(\d+\.?\d*\.?\d*\.?\d*)([^\d* ])*(\d*)") def getFilesByType(self, pathname, descr): """Get files from "pathname" has "descr" in descriptions""" filelist = map(lambda x: path.join(pathname, x), os.listdir(pathname)) ftype = typeFile(magic=MAGIC_COMPRESS | MAGIC_SYMLINK).getMType filesWithType = map(lambda x: (x, ftype(x)), filter(path.exists, filelist)) return list(filter(lambda x: x[1] and descr in x[1], filesWithType)) def getInitrdFiles(self, pathname): filelist = list(map(lambda x: path.join(pathname, x), os.listdir(pathname))) return [x for x in filelist if path.exists(x) and InitrdFile.is_cpio(x)] def getInitrd(self, arch, shortname, chroot, kernel, suffix="", notsuffix=""): """Get initrd for kernel""" reInitrdVer = re.compile(r"(initrd|initramfs)-(.+?)(-install)?$", re.S) def initrd_version_by_name(filename): resInitrdVer = reInitrdVer.search(filename) if resInitrdVer: return resInitrdVer.groups()[1] return "" ftype = typeFile(magic=MAGIC_COMPRESS | MAGIC_SYMLINK).getMType kernelfile = path.join(chroot, 'boot', kernel) typeKernelFile = ftype(kernelfile) if typeKernelFile is None: return "" resKernelVer = self.reFindVer.search(ftype(kernelfile)) if resKernelVer: kernelVersion = "%s-%s-%s" % \ (resKernelVer.group().replace('-calculate', ''), arch, shortname) origKernelVer = resKernelVer.group() bootdir = path.join(chroot, 'boot') initramfsFiles = self.getInitrdFiles(bootdir) initramfsWithVer = \ list(filter(lambda x: (kernelVersion in x[1] or origKernelVer in x[1]) and \ x[0].endswith(suffix) and \ ( not notsuffix or not x[0].endswith(notsuffix)), map(lambda x: (x, initrd_version_by_name(x)), initramfsFiles))) if initramfsWithVer: return path.split(min(initramfsWithVer, key=itemgetter(0))[0])[-1] return "" class VariableOsInstallKernel(ReadonlyVariable, KernelHelper): """ Kernel filename """ def get(self): bootdir = path.join(self.Get('cl_chroot_path'), 'boot') modulesdir = path.join(self.Get('cl_chroot_path'), 'lib/modules') validKernel = listDirectory(modulesdir) kernelFiles = self.getFilesByType(bootdir, "Linux kernel") installMarch = self.Get('os_install_arch_machine') kernelsWithVer = \ list(map(lambda x: ( x[0], (getTupleVersion("".join(x[1].groups()[0:3:2])), path.getmtime(x[0]))), # convert version to tuple( versionTuple, mtime) # version detect, for this version lib contains moudules # kernel arch equal install arch filter(lambda x: x[1] and x[1].group() in validKernel and installMarch in x[0].rpartition('/')[2], # (filename,version) map(lambda x: (x[0], self.reFindVer.search(x[1])), kernelFiles)))) if kernelsWithVer: return path.split(max(kernelsWithVer, key=itemgetter(1))[0])[-1] else: return "vmlinuz" class VariableOsInstallInitrd(ReadonlyVariable, KernelHelper): """ Optimized initramfs filename """ def get(self): return self.getInitrd(self.Get('os_install_arch_machine'), self.Get('os_install_linux_shortname'), self.Get('cl_chroot_path'), self.Get('os_install_kernel'), suffix="", notsuffix="-install") or \ self.getInitrd(self.Get('os_install_arch_machine'), self.Get('os_install_linux_shortname'), self.Get('cl_chroot_path'), self.Get('os_install_kernel'), suffix="-install")[:-8] \ or "initrd" class VariableOsInstallInitrdInstall(ReadonlyVariable, KernelHelper): """ Install initramfs filename """ def get(self): return self.getInitrd(self.Get('os_install_arch_machine'), self.Get('os_install_linux_shortname'), self.Get('cl_chroot_path'), self.Get('os_install_kernel'), suffix="-install") or "initrd-install" class VariableOsInstallSystemMap(ReadonlyVariable): """ Install system map filename """ def get(self): systemmapfile = self.Get('os_install_kernel').replace('vmlinuz', 'System.map') if systemmapfile.startswith('System.map') and path.exists( path.join(self.Get('cl_chroot_path'), 'boot', systemmapfile)): return systemmapfile else: return "" class VariableOsInstallKernelCpufreq(ReadonlyVariable): """ Cpufreq modules """ def get(self): """Get cpufreq (and other from modules_3= param) from conf.d/modules""" cpufreqmods = list(map(lambda x: x.partition('=')[2].strip("\n '\""), filter(lambda x: x.startswith('modules_3'), readLinesFile('/etc/conf.d/modules')))) if cpufreqmods: return cpufreqmods[0] else: return "" class VariableClInstallKernelUid(ReadonlyVariable): """ Variable install kernel UID """ def get(self): return getKernelUid(self.Get('os_install_root_dev')) class VariableClInstallKernelBuild(Variable): """ Переменная используемся для GRP дистрибутивов и сборки нескольких ядер """ value = "" class VariableClInstallKernelVersion(VariableOsInstallKernelConfig): """ Версия ядра в /usr/src/linux """ def get(self): image = self.Get('cl_image') if image: with image: try: distrPath = image.getDirectory() return self.get_kernel_src(distrPath) except DistributiveError as e: return "" return ""