#-*- coding: utf-8 -*- # Copyright 2008-2010 Calculate Ltd. 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 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: ldapUser = None from operator import itemgetter class clLocale: lang = { #Belarussian 'be_BY' : { 'locale':'be_BY.UTF-8', 'keymap':'by', 'dumpkeys_charset': 'koi8-u', 'consolefont':'Cyr_a8x16', 'xkblayout':'us,by', 'language':'be', }, #Bulgarian 'bg_BG' : { 'locale':'bg_BG.UTF-8', 'keymap':'bg_bds-utf8', 'dumpkeys_charset': '', 'consolefont':'ter-m14n', 'xkblayout':'us,bg', 'language':'bg', }, #Belgian 'fr_BE' : { 'locale':'fr_BE.UTF-8', 'keymap':'be-latin1', 'dumpkeys_charset':'', 'consolefont':'lat9w-16', 'xkblayout':'us,be', 'language':'fr', }, #Brazilian Portuguese 'pt_BR' : { 'locale':'pt_BR.UTF-8', 'keymap':'br-abnt2', 'dumpkeys_charset':'', 'consolefont':'lat9w-16', 'xkblayout':'pt,us', 'language':'pt_BR', }, #Canadian French 'fr_CA' : { 'locale':'fr_CA.UTF-8', 'keymap':'cf', 'dumpkeys_charset':'', 'consolefont':'default8x16', 'xkblayout':'us,ca_enhanced', 'language':'fr', }, #Danish 'da_DK' : { 'locale':'da_DK.UTF-8', 'keymap':'dk-latin1', 'dumpkeys_charset':'', 'consolefont':'lat0-16', 'xkblayout':'us,dk', 'language':'da', }, #French 'fr_FR' : { 'locale':'fr_FR.UTF-8', 'keymap':'fr-latin9', 'dumpkeys_charset':'', 'consolefont':'lat0-16', 'xkblayout':'fr,us', 'language':'fr', }, #German 'de_DE' : { 'locale':'de_DE.UTF-8', 'keymap':'de-latin1', 'dumpkeys_charset':'', 'consolefont':'lat9w-16', 'xkblayout':'de,us', 'language':'de', }, #Icelandic 'is_IS' : { 'locale':'is_IS.UTF-8', 'keymap':'is-latin1', 'dumpkeys_charset':'', 'consolefont':'cp850-8x16', 'xkblayout':'us,is', 'language':'is', }, #Italian 'it_IT' : { 'locale':'it_IT.UTF-8', 'keymap':'it', 'dumpkeys_charset':'', 'consolefont':'default8x16', 'xkblayout':'us,it', 'language':'it', }, #Norwegian 'nn_NO' : { 'locale':'nn_NO.UTF-8', 'keymap':'no-latin1', 'dumpkeys_charset':'', 'consolefont':'lat9w-16', 'xkblayout':'us,no', 'language':'nn', }, #Polish 'pl_PL' : { 'locale':'pl_PL.UTF-8', 'keymap':'pl', 'dumpkeys_charset':'', 'consolefont':'lat2-16', 'xkblayout':'us,pl', 'language':'pl', }, #Portuguese 'pt_PT' : { 'locale':'pl_PL.UTF-8@euro', 'keymap':'pt-latin9', 'dumpkeys_charset':'', 'consolefont':'lat0-16', 'xkblayout':'pt,us', 'language':'pt', }, #Romanian 'ro_RO' : { 'locale':'ro_RO.UTF-8', 'keymap':'ro_win', 'dumpkeys_charset':'', 'consolefont':'lat2-16', 'xkblayout':'ro,us', 'language':'ro', }, #Russian 'ru_RU' : { 'locale':'ru_RU.UTF-8', 'keymap':'-u ruwin_cplk-UTF-8', 'dumpkeys_charset':'', 'consolefont':'ter-k14n', 'xkblayout':'us,ru(winkeys)', 'language':'ru', }, #Spanish 'es_ES' : { 'locale':'es_ES.UTF-8', 'keymap':'es euro2', 'dumpkeys_charset':'', 'consolefont':'lat0-16', 'xkblayout':'es,us', 'language':'es', }, #Swedish 'sv_SE' : { 'locale':'sv_SE.UTF-8', 'keymap':'sv-latin1', 'dumpkeys_charset':'', 'consolefont':'lat0-16', 'xkblayout':'us,se', 'language':'sv', }, #Ukrainian 'uk_UA' : { 'locale':'uk_UA.UTF-8', 'keymap':'ua-utf', 'dumpkeys_charset':'koi8-u', 'consolefont':'ter-v14n', 'xkblayout':'us,ua(winkeys)', 'language':'uk', }, #United Kingdom/British 'en_GB' : { 'locale':'en_GB.UTF-8', 'keymap':'uk', 'dumpkeys_charset':'', 'consolefont':'LatArCyrHeb-16', 'xkblayout':'us,gb', 'language':'en', }, #United State/English 'en_US' : { 'locale':'en_US.UTF-8', 'keymap':'us', 'dumpkeys_charset':'', 'consolefont':'LatArCyrHeb-16', 'xkblayout':'us', 'language':'en', } } def getLangs(self): return self.lang.keys() def getLanguages(self): return map(lambda x:self.lang[x]['language'], self.lang.keys()) def isLangExists(self,lang): return lang in self.lang.keys() def isValueInFieldExists(self,field,value): return value in map(lambda x:self.lang[x][field],self.lang.keys()) def getFields(self,field): return [ l[1][field] for l in self.lang.items() ] def getFieldByLang(self,field,lang): return self.lang.get(lang, self.lang['en_US'])[field] def getFieldByKeymap(self,field,keymap): return self.lang.get(self.getLangByField('keymap',keymap), self.lang['en_US'])[field] def getLangByField(self,field,value): langs = [lang[0] for lang in self.lang.items() if lang[1][field] == value ] if not langs: return 'en_US' else: return langs[0] class varsShare: """Share methods and attributs for fill vars methods""" dictNetworkManagers = {"openrc":"sys-apps/openrc", "networkmanager":"net-misc/networkmanager"} dictLinuxName = {"CLD":"Calculate Linux Desktop", "CLDX":"Calculate Linux Desktop", "CLDG":"Calculate Linux Desktop", "CDS":"Calculate Directory Server", "CLS":"Calculate Linux Scratch", "CSS":"Calculate Scratch Server", "CMC":"Calculate Media Center", "Gentoo":"Gentoo"} dictLinuxSubName = {"CLD":"KDE", "CLDX":"XFCE", "CLDG":"GNOME"} dictNameSystem = {'CDS':'server', 'CLD':'desktop', 'CLDG':'desktop', 'CLDX':'desktop', 'CLS':'desktop', 'CMC':'desktop', 'CSS':'server'} # data object from LDAP _ldapUserObject = False # user data from LDAP _ldapUserData = {} reFindVer = re.compile( "(?<=version )(\d+\.?\d*\.?\d*\.?\d*)([^\d* ])*(\d*)") def getFilesByType(self,pathname,descr): """Get files from "pathname" has "descr" in descriptions""" return list(self.get_files_by_type(pathname, descr)) def get_files_by_type(self, pathname, descr): ftype = typeFile(magic=0x4).getMType 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""" reInitrdVer = re.compile("(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=0x4).getMType kernelfile = path.join(chroot,'boot',kernel) typeKernelFile = ftype(kernelfile) if typeKernelFile == 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.getFilesByType(bootdir,"ASCII cpio archive") initramfsWithVer = \ 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[0],initrd_version_by_name(x[0])), initramfsFiles)) if initramfsWithVer: return path.split(min(initramfsWithVer, key=itemgetter(0))[0])[-1] return "" def getDirList(self,pathname): """Get directory list by pathname""" dirs = [] if path.exists(pathname): dirs = filter(lambda x: path.isdir(path.join(pathname,x)), os.listdir(pathname)) return dirs def getUserInfo(self): """Get information about user from LDAP in dict format""" userName = self.Get('ur_login') if userName: if userName in self._ldapUserData: return self._ldapUserData[userName] elif not ldapUser is None: ldapObj = self.getLdapUserObject() if ldapObj: userInfo = ldapObj.getUserLdapInfo(userName) if userInfo: self._ldapUserData[userName] = userInfo return userInfo return {} def getLdapUserObject(self): """Get data obejct from LDAP""" if not self._ldapUserObject: self._ldapUserObject = ldapUser() return self._ldapUserObject def _runos(self, cmd, env={}): """Return result of os command perform""" if not env: env.update(os.environ.items() + [("PATH",getpathenv())] +\ env.items()) retCode, programOut = runOsCommand(cmd, None, env_dict=env) if not retCode: return programOut return False def get_composite_from_xorgconf(self,chroot="/"): """Get composite value from xorg.conf""" xorgConfig = path.join(chroot, "etc/X11/xorg.conf") try: confLines = open(xorgConfig,"r").readlines() except: return None flagStartExtensions = False lineCompositeTmp = "" lineComposite = "" for line in confLines: line = line.strip() if flagStartExtensions: if line.startswith('EndSection'): lineComposite = lineCompositeTmp break elif line.startswith('Section'): break if line.startswith('Option') and '"Composite"' in line: lineCompositeTmp = line else: if '"Extensions"' in line and line.startswith('Section'): flagStartExtensions = True if lineComposite: listOpt = filter(lambda x: x.strip(), lineComposite.split('"')) if len(listOpt) == 3: ret = listOpt[2].lower() if ret in ("on","true","yes","1"): return "on" elif ret in ("off","false","no","0"): return "off" return None def getValueFromCmdLine(self,option,num): """Get value of parameter from boot params Parameters: option param name num number part of value parameter (, split) """ cmdLine = "/proc/cmdline" calculateParam = "calculate" names = ("lang","keymap","timezone", "resolution","video","composite","domain","domain_pw") # try get timezone from kernel calculate param try: if type(num) == str and not num.isdigit(): name = num num = names.index(name) else: name = names[int(num)] for param in open(cmdLine,"r").read().split(" "): parname,op,value = param.partition("=") if parname == calculateParam and op == "=": # new format if ":" in value: params = dict( map(lambda x:x.partition(':')[0::2], filter(lambda x:x, value.split(',')))) return params.get(name,"").strip() # old format else: values = value.split(",") if len(values) > num and values[num].strip(): return values[num].strip() except (IOError,ValueError,IndexError),e: return "" def getValueFromConfig(self,config,name): """Get value of parameter from bash type file Parameters: config config file name name param name """ reMatch = re.compile("^%s\s*=\s*\"?(.*?)(\"\s*)?$"%name, re.I) try: if path.exists(config): for line in open(config,"r").readlines(): match = reMatch.match(line) if match: return match.groups()[0].strip() except: pass return False def getX11Resolution(self): """Return current screen resolution (width, height), X must be ran""" lines=self._runos("xdpyinfo") if not lines: return "" reRes = re.compile("dimensions:\s+(\d+)x(\d+)\s+pixels") searchRes=False for line in lines: searchRes = reRes.search(line) if searchRes: break if searchRes: return (searchRes.group(1), searchRes.group(2)) else: return "" def getShortnameByMakeprofile(self,systemroot): """Get shortname by symlink of make.profile""" for makeprofile in (path.join(systemroot,'etc/portage/make.profile'), path.join(systemroot,'etc/make.profile')): if path.exists(makeprofile): link = os.readlink(makeprofile) for pattern in ('/calculate/(?:desktop|server)/(%s)/', '/distros/profiles/(%s)/'): reMakeProfileLink = re.compile(pattern% "|".join(self.dictLinuxName.keys()),re.S) shortnameSearch = reMakeProfileLink.search(link) if shortnameSearch: return shortnameSearch.groups()[0] return None def getShortnameByIni(self,systemroot): """Get shortname by calculate.ini file""" inifile = path.join(systemroot,'etc/calculate/calculate.ini') if path.exists(inifile): FD = open(inifile) data = FD.readlines() FD.close() shortNameList = filter(lambda y:y, map(lambda x:\ len(x.split("="))==2 and\ x.split("=")[0]=="calculate" and\ x.split("=")[1].strip(), data)) if shortNameList: return shortNameList[0] def detectOtherShortname(self,systemroot): """Detect other system. Now only Gentoo.""" gentooFile = path.join(systemroot,"etc/gentoo-release") if path.exists(gentooFile): return "Gentoo" return None def getVersionFromMetapackage(self,systemroot,shortname): """Get version from meta package""" pkgInfoDir = path.join(systemroot,'var/db/pkg/app-misc/') if not os.access(pkgInfoDir,os.R_OK): return None metaPkgs = sorted(filter(lambda x:"calculate-meta" in x or \ "%s-meta"%shortname.lower() in x, os.listdir(pkgInfoDir))) if metaPkgs: reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") findVer = reFindVer.search(metaPkgs[0]) if findVer: return findVer.group() return None def getVersionFromCalculateIni(self,systemroot): """Get version from calculate ini""" pathname = path.join(systemroot, 'etc/calculate/calculate.ini') if path.exists(pathname): FD = open(pathname) data = FD.readlines() FD.close() verList = filter(lambda y:y, map(lambda x:\ len(x.split("="))==2 and\ x.split("=")[0]=="linuxver" and\ x.split("=")[1].strip(), data)) if verList: reVer=re.compile("^(\d+\.)*\d$",re.S) reRes = filter(reVer.search,verList) if reRes: return reRes[0] def selectVar(self,selField,where="",eq=""): """Select value from matrix variables Example: selectVar("os_disk_dev",where="os_disk_mount",eq="/")""" res = filter(lambda x:x[1] == eq, zip(self.Get(selField), self.Get(where))) or [("","")] return res[0][0] def getVersionFromGentooFiles(self,systemroot): """Get version from gentoo files""" gentooFile = path.join(systemroot,"etc/gentoo-release") systemVersion = "" flagGentoo = False reVer=re.compile("^(\d+\.)*\d+$",re.S) if path.exists(gentooFile): gentooLink = path.join(systemroot,"etc/make.profile") if path.islink(gentooLink): vers = filter(reVer.search, os.readlink(gentooLink).split('/')) if vers: return vers[-1] def getVersionFromUname(self): """Get version from uname""" textLines = self._runos("uname -r") reVer=re.compile("^(\d+\.)*\d",re.S) kernelVersion = "" if textLines: kernelVersion = textLines[0] if kernelVersion: reRes = reVer.search(kernelVersion) if reRes: return reRes.group() def isChroot(self,pid): """Detect chroot mode by different mountinfo""" if not os.access('/proc/self/mountinfo',R_OK) or \ not os.access('/proc/1/mountinfo',R_OK): return False return open('/proc/1/mountinfo','r').read() != \ open('/proc/self/mountinfo','r').read() def getProgPath(self,progname): """Get full path of program or False""" baseprogname = os.path.basename(progname) env = {"LANG":"C"} env.update(os.environ.items() + [("PATH",getpathenv())] +\ env.items()) res = self._runos("which %s"%progname,env=env) if res: return res[0].strip() elif os.path.isabs(progname) and os.path.exists(progname): return progname else: return False def getVideoByDefault(self,drivers_list): """Get video by default, or wrong specified""" workedModules = map(lambda x:x[0], filter(lambda x:x[1].isdigit() and int(x[1])>0, map(lambda x:x.split()[:3:2], open('/proc/modules','r')))) if "nouveau" in workedModules: defaultNvidia = "nouveau" elif "nvidia" in drivers_list: defaultNvidia = "nvidia" else: defaultNvidia = "nv" if "radeon" in workedModules: defaultAti = "radeon" elif "fglrx" in drivers_list: defaultAti = "fglrx" else: defaultAti = "radeon" defaultDriver = { 'nvidia':defaultNvidia, 'ati':defaultAti, 'intel':'intel', 'via':'via', 'vmware':'vmware'} hr_video = self.Get('hr_video') if hr_video in defaultDriver and \ defaultDriver[hr_video] in drivers_list: return defaultDriver[hr_video] else: return "other" def getKernelUid(self,device): """Get Kernel UID by UUID of device""" blkidProcess = process('/sbin/blkid','-c','/dev/null','-s','UUID', '-o','value',device) res = blkidProcess.read().strip() if res: 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