Files
entropy/libraries/entropy/const.py

1418 lines
50 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayonlinux.org>
@contact: lxnay@sabayonlinux.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Framework constants module}.
This module contains all the Entropy constants used all around
the "entropy" package.
Some of the constants in this module are used as "default" for
the SystemSettings interface. So, make sure to read the documentation
of SystemSettings in the "entropy.core" module.
Even if possible, etpConst, etpUi, etpCache and etpSys objects
*SHOULD* be I{never ever modified manually}. This freedom could change
in future, so, if you want to produce a stable code, DON'T do that at all!
Basic Entropy constants handling functions are available in this module
and are all prefixed with "I{const_*}" or "I{initconfig_*}".
If you are writing a third party application, you should always try
to avoid to deal directly with functions here unless specified otherwise.
In fact, usually these here are wrapper in upper-level modules
(entropy.client, entropy.server, entropy.services).
"""
from __future__ import with_statement
import sys
import os
import stat
import errno
import fcntl
import signal
import gzip
import bz2
from entropy.i18n import _
# ETP_ARCH_CONST setup
# add more arches here
ETP_ARCH_MAP = {
("i386", "i486", "i586", "i686",): "x86",
("x86_64",): "amd64",
("sun4u",): None,
("ppc",): None,
}
_uname_m = os.uname()[4]
ETP_ARCH_CONST = 'UNKNOWN'
for arches, arch in ETP_ARCH_MAP.items():
if _uname_m in arches:
ETP_ARCH_CONST = arch
etpSys = {
'archs': ['alpha', 'amd64', 'amd64-fbsd', 'arm', 'hppa', 'ia64', 'm68k',
'mips', 'ppc', 'ppc64', 's390', 'sh', 'sparc', 'sparc-fbsd', 'x86',
'x86-fbsd'],
'keywords': set([ETP_ARCH_CONST, "~"+ETP_ARCH_CONST]),
'api': '3',
'arch': ETP_ARCH_CONST,
'rootdir': "",
'serverside': False,
}
etpUi = {
'debug': False,
'quiet': False,
'verbose': False,
'ask': False,
'pretend': False,
'mute': False,
'nolog': False,
'clean': False,
'warn': True,
}
if "--debug" in sys.argv:
etpUi['debug'] = True
# static logging stuff
ETP_LOGLEVEL_NORMAL = 1
ETP_LOGLEVEL_VERBOSE = 2
ETP_LOGPRI_INFO = "[ INFO ]"
ETP_LOGPRI_WARNING = "[ WARNING ]"
ETP_LOGPRI_ERROR = "[ ERROR ]"
# disk caching dictionary
etpCache = {
# used to store information about files that
# should be merged using "equo conf merge"
'configfiles': 'conf/scanfs',
'dbMatch': 'match/db', # db atom match cache
'dbSearch': 'search/db', # db search cache
# used to store info about repository dependencies solving
'atomMatch': 'atom_match/atom_match_',
'install': 'resume/resume_install', # resume cache (install)
'remove': 'resume/resume_remove', # resume cache (remove)
'world': 'resume/resume_world', # resume cache (world)
'world_update': 'world_update/world_cache_',
'critical_update': 'critical_update/critical_cache_',
'world_available': 'world_available/available_cache_',
'check_package_update': 'check_update/package_update_',
'advisories': 'security/advisories_cache_',
'dep_tree': 'deptree/dep_tree_',
'depends_tree': 'depends/depends_tree_',
'filter_satisfied_deps': 'depfilter/filter_satisfied_deps_',
'library_breakage': 'libs_break/library_breakage_',
'repolist': 'repos/repolist',
'repository_server': 'reposerver/item',
'eapi3_fetch': 'eapi3/segment_',
'ugc_votes': 'ugc/ugc_votes',
'ugc_downloads': 'ugc/ugc_downloads',
'ugc_docs': 'ugc/ugc_docs',
'ugc_srv_cache': 'ugc/ugc_srv_cache'
}
etpConst = {}
def initconfig_entropy_constants(rootdir):
"""
Main constants configurators, this is the only function that you should
call from the outside, anytime you want. it will reset all the variables
excluding those backed up previously.
@param rootdir: current root directory, if any, or ""
@type rootdir: string
@rtype: None
@return: None
@raise AttributeError: when specified rootdir is not a directory
"""
if rootdir and not os.path.isdir(rootdir):
raise AttributeError("not a valid chroot.")
# save backed up settings
if etpConst.has_key('backed_up'):
backed_up_settings = etpConst.pop('backed_up')
else:
backed_up_settings = {}
const_default_settings(rootdir)
const_read_entropy_release()
const_create_working_dirs()
const_setup_entropy_pid()
const_configure_lock_paths()
# reflow back settings
etpConst.update(backed_up_settings)
etpConst['backed_up'] = backed_up_settings.copy()
if sys.excepthook == sys.__excepthook__:
sys.excepthook = __const_handle_exception
def const_default_settings(rootdir):
"""
Initialization of all the Entropy base settings.
@param rootdir: current root directory, if any, or ""
@type rootdir: string
@rtype: None
@return: None
"""
default_etp_dir = rootdir+"/var/lib/entropy"
default_etp_tmpdir = "/tmp"
default_etp_repodir = "/packages/"+ETP_ARCH_CONST
default_etp_portdir = rootdir+"/usr/portage"
default_etp_distfilesdir = "/distfiles"
default_etp_dbdir = "/database/"+ETP_ARCH_CONST
default_etp_dbfile = "packages.db"
default_etp_dbclientfile = "equo.db"
default_etp_client_repodir = "/client"
default_etp_triggersdir = "/triggers/"+ETP_ARCH_CONST
default_etp_smartappsdir = "/smartapps/"+ETP_ARCH_CONST
default_etp_smartpackagesdir = "/smartpackages/"+ETP_ARCH_CONST
default_etp_cachesdir = "/caches/"
default_etp_securitydir = "/glsa/"
default_etp_setsdirname = "sets"
default_etp_setsdir = "/%s/" % (default_etp_setsdirname,)
default_etp_logdir = default_etp_dir+"/"+"logs"
default_etp_confdir = rootdir+"/etc/entropy"
default_etp_packagesdir = default_etp_confdir+"/packages"
default_etp_ugc_confdir = default_etp_confdir+"/ugc"
default_etp_syslogdir = rootdir+"/var/log/entropy/"
default_etp_vardir = rootdir+"/var/tmp/entropy"
cmdline = []
cmdline_file = "/proc/cmdline"
if os.access(cmdline_file, os.R_OK) and os.path.isfile(cmdline_file):
with open(cmdline_file, "r") as cmdline_f:
cmdline = cmdline_f.readline().strip().split()
etpConst.clear()
my_const = {
'server_repositories': {},
'community': {
'mode': False,
},
'cmdline': cmdline,
'backed_up': {},
# entropy default installation directory
'installdir': '/usr/lib/entropy',
# etpConst['packagestmpdir'] --> temp directory
'packagestmpdir': default_etp_dir+default_etp_tmpdir,
# etpConst['packagesbindir'] --> repository
# where the packages will be stored
# by clients: to query if a package has been already downloaded
# by servers or rsync mirrors: to store already
# uploaded packages to the main rsync server
'packagesbindir': default_etp_dir+default_etp_repodir,
# etpConst['smartappsdir'] location where smart apps files are places
'smartappsdir': default_etp_dir+default_etp_smartappsdir,
# etpConst['smartpackagesdir'] location where
# smart packages files are places
'smartpackagesdir': default_etp_dir+default_etp_smartpackagesdir,
# etpConst['triggersdir'] location where external triggers are placed
'triggersdir': default_etp_dir+default_etp_triggersdir,
# directory where is stored our local portage tree
'portagetreedir': default_etp_portdir,
# directory where our sources are downloaded
'distfilesdir': default_etp_portdir+default_etp_distfilesdir,
# directory where entropy stores its configuration
'confdir': default_etp_confdir,
# same as above + /packages
'confpackagesdir': default_etp_packagesdir,
# system package sets dir
'confsetsdir': default_etp_packagesdir+default_etp_setsdir,
# just the dirname
'confsetsdirname': default_etp_setsdirname,
# entropy.conf file
'entropyconf': default_etp_confdir+"/entropy.conf",
# repositories.conf file
'repositoriesconf': default_etp_confdir+"/repositories.conf",
# server.conf file (generic server side settings)
'serverconf': default_etp_confdir+"/server.conf",
# client.conf file (generic entropy client side settings)
'clientconf': default_etp_confdir+"/client.conf",
# socket.conf file
'socketconf': default_etp_confdir+"/socket.conf",
# user by client interfaces
'packagesrelativepath': "packages/"+ETP_ARCH_CONST+"/",
'entropyworkdir': default_etp_dir, # Entropy workdir
# Entropy unpack directory
'entropyunpackdir': default_etp_vardir,
# Entropy packages image directory
'entropyimagerelativepath': "image",
# Gentoo xpak temp directory path
'entropyxpakrelativepath': "xpak",
# Gentoo xpak metadata directory path
'entropyxpakdatarelativepath': "data",
# Gentoo xpak metadata file name
'entropyxpakfilename': "metadata.xpak",
# entropy repository database upload timestamp
'etpdatabasetimestampfile': default_etp_dbfile+".timestamp",
# entropy repository database owned (in repo) package files
'etpdatabasepkglist': default_etp_dbfile+".pkglist",
'etpdatabaseconflictingtaggedfile': default_etp_dbfile + \
".conflicting_tagged",
# file containing a list of packages that are strictly
# required by the repository, thus forced
'etpdatabasesytemmaskfile': default_etp_dbfile+".system_mask",
'etpdatabasemaskfile': default_etp_dbfile+".mask",
'etpdatabasekeywordsfile': default_etp_dbfile+".keywords",
'etpdatabaseupdatefile': default_etp_dbfile+".repo_updates",
'etpdatabaselicwhitelistfile': default_etp_dbfile+".lic_whitelist",
'etpdatabasecriticalfile': default_etp_dbfile+".critical",
# the local/remote database revision file
'etpdatabaserevisionfile': default_etp_dbfile+".revision",
# missing dependencies black list file
'etpdatabasemissingdepsblfile': default_etp_dbfile + \
".missing_deps_blacklist",
# compressed file that contains all the "meta"
# files in a repository dir
'etpdatabasemetafilesfile': default_etp_dbfile+".meta",
# file that contains a list of the "meta"
# files not available in the repository
'etpdatabasemetafilesnotfound': default_etp_dbfile+".meta_notfound",
'etpdatabasehashfile': default_etp_dbfile+".md5", # its checksum
# the remote database lock file
'etpdatabaselockfile': default_etp_dbfile+".lock",
# the remote database lock file
'etpdatabaseeapi3lockfile': default_etp_dbfile+".eapi3_lock",
# the remote database download lock file
'etpdatabasedownloadlockfile': default_etp_dbfile+".download.lock",
'etpdatabasecacertfile': "ca.cert",
'etpdatabaseservercertfile': "server.cert",
# when this file exists, the database is not synced
# anymore with the online one
'etpdatabasetaintfile': default_etp_dbfile+".tainted",
# Entropy sqlite database file default_etp_dir + \
# default_etp_dbdir+"/packages.db"
'etpdatabasefile': default_etp_dbfile,
# Entropy sqlite database file (gzipped)
'etpdatabasefilegzip': default_etp_dbfile+".gz",
# Entropy sqlite database file (bzipped2)
'etpdatabasefilebzip2': default_etp_dbfile+".bz2",
# Entropy sqlite database file (gzipped)
'etpdatabasefilegziplight': default_etp_dbfile+".light.gz",
'etpdatabasefilehashgziplight': default_etp_dbfile+".light.gz.md5",
# Entropy sqlite database file (bzipped2)
'etpdatabasefilebzip2light': default_etp_dbfile+".light.bz2",
'etpdatabasefilehashbzip2light': default_etp_dbfile+".light.bz2.md5",
# Entropy sqlite database dump file (bzipped2)
'etpdatabasedumpbzip2': default_etp_dbfile+".dump.bz2",
'etpdatabasedumphashfilebz2': default_etp_dbfile+".dump.bz2.md5",
# Entropy sqlite database dump file (gzipped)
'etpdatabasedumpgzip': default_etp_dbfile+".dump.gz",
'etpdatabasedumphashfilegzip': default_etp_dbfile+".dump.gz.md5",
# Entropy sqlite database dump file
'etpdatabasedump': default_etp_dbfile+".dump",
# Entropy sqlite database dump file (bzipped2) light ver
'etpdatabasedumplightbzip2': default_etp_dbfile+".dumplight.bz2",
# Entropy sqlite database dump file (gzipped) light ver
'etpdatabasedumplightgzip': default_etp_dbfile+".dumplight.gz",
# Entropy sqlite database dump file, light ver (no content)
'etpdatabasedumplighthashfilebz2': default_etp_dbfile+".dumplight.bz2.md5",
'etpdatabasedumplighthashfilegzip': default_etp_dbfile+".dumplight.gz.md5",
'etpdatabasedumplight': default_etp_dbfile+".dumplight",
# expiration based server-side packages removal
'etpdatabaseexpbasedpkgsrm': default_etp_dbfile+".fatscope",
# Entropy default compressed database format
'etpdatabasefileformat': "bz2",
# Entropy compressed databases format support
'etpdatabasesupportedcformats': ["bz2", "gz"],
'etpdatabasecompressclasses': {
"bz2": (bz2.BZ2File, "unpack_bzip2", "etpdatabasefilebzip2",
"etpdatabasedumpbzip2", "etpdatabasedumphashfilebz2",
"etpdatabasedumplightbzip2", "etpdatabasedumplighthashfilebz2",
"etpdatabasefilebzip2light","etpdatabasefilehashbzip2light",),
"gz": (gzip.GzipFile, "unpack_gzip", "etpdatabasefilegzip",
"etpdatabasedumpgzip", "etpdatabasedumphashfilegzip",
"etpdatabasedumplightgzip", "etpdatabasedumplighthashfilegzip",
"etpdatabasefilegziplight","etpdatabasefilehashgziplight",)
},
# enable/disable packages RSS feed feature
'rss-feed': True,
# default name of the RSS feed
'rss-name': "packages.rss",
'rss-light-name': "updates.rss", # light version
# default URL to the entropy web interface
# (overridden in reagent.conf)
'rss-base-url': "http://packages.sabayonlinux.org/",
# default URL to the Operating System website
# (overridden in reagent.conf)
'rss-website-url': "http://www.sabayonlinux.org/",
# xml file where will be dumped ServerInterface.rssMessages dictionary
'rss-dump-name': "rss_database_actions",
'rss-max-entries': 10000, # maximum rss entries
'rss-light-max-entries': 300, # max entries for the light version
'rss-managing-editor': "lxnay@sabayonlinux.org", # updates submitter
# repository RSS-based notice board content
'rss-notice-board': "notice.rss",
# File containing user data related to repository notice board
'rss-notice-board-userdata': "notice.rss.userdata",
'packagesetprefix': "@",
'userpackagesetsid': "__user__",
'setsconffilename': "sets.conf",
'cachedumpext': ".dmp",
'packagesext': ".tbz2",
'smartappsext': ".esa",
# Extension of the file that contains the checksum
# of its releated package file
'packagesmd5fileext': ".md5",
'packagessha512fileext': ".sha512",
'packagessha256fileext': ".sha256",
'packagessha1fileext': ".sha1",
# Extension of the file that "contains" expiration mtime
'packagesexpirationfileext': ".expired",
# number of days after a package will be removed from mirrors
'packagesexpirationdays': 15,
# name of the trigger file that would be executed
# by equo inside triggerTools
'triggername': "trigger",
'trigger_sh_interpreter': rootdir+"/usr/sbin/entropy.sh",
# entropy hardware hash generator executable
'etp_hw_hash_gen': rootdir+"/usr/bin/entropy_hwgen.sh",
# entropy client post valid branch migration (equo hop) script name
'etp_post_branch_hop_script': default_etp_dbfile+".post_branch.sh",
# entropy client post branch upgrade script
'etp_post_branch_upgrade_script': default_etp_dbfile+".post_upgrade.sh",
# previous branch file container
'etp_previous_branch_file': default_etp_confdir+"/.previous_branch",
'etp_in_branch_upgrade_file': default_etp_confdir+"/.in_branch_upgrade",
# proxy configuration constants, used system wide
'proxy': {
'ftp': os.getenv("FTP_PROXY"),
'http': os.getenv("HTTP_PROXY"),
'username': None,
'password': None
},
# Entropy log level (default: 1 - see entropy.conf for more info)
'entropyloglevel': 1,
# Entropy Socket Interface log level
'socketloglevel': 2,
'spmloglevel': 1,
# Log dir where ebuilds store their stuff
'logdir': default_etp_logdir,
'syslogdir': default_etp_syslogdir, # Entropy system tools log directory
'entropylogfile': default_etp_syslogdir+"entropy.log",
'equologfile': default_etp_syslogdir+"equo.log",
'spmlogfile': default_etp_syslogdir+"spm.log",
'socketlogfile': default_etp_syslogdir+"socket.log",
'etpdatabaseclientdir': default_etp_dir + default_etp_client_repodir + \
default_etp_dbdir,
# path to equo.db - client side database file
'etpdatabaseclientfilepath': default_etp_dir + \
default_etp_client_repodir + default_etp_dbdir + "/" + \
default_etp_dbclientfile,
# prefix of the name of self.dbname in
# entropy.db.LocalRepository class for the repositories
'dbnamerepoprefix': "repo_",
# prefix of database backups
'dbbackupprefix': 'etp_backup_',
# Entropy database API revision
'etpapi': etpSys['api'],
# contains the current running architecture
'currentarch': etpSys['arch'],
# Entropy supported Archs
'supportedarchs': etpSys['archs'],
# default choosen branch (overridden by setting in repositories.conf)
'branch': "4",
# default allowed package keywords
'keywords': etpSys['keywords'].copy(),
# allow multiple packages in single scope server-side?
# this makes possible to have multiple versions of packages
# and handle the removal through expiration (using creation date)
'expiration_based_scope': False,
# our official repository name
'officialserverrepositoryid': "sabayonlinux.org",
# our official repository name
'officialrepositoryid': "sabayonlinux.org",
'conntestlink': "http://www.sabayonlinux.org",
# tag to append to .tbz2 file before entropy database (must be 32bytes)
'databasestarttag': "|ENTROPY:PROJECT:DB:MAGIC:START|",
'pidfile': default_etp_dir+"/entropy.lock",
'applicationlock': False,
# option to keep a backup of config files after
# being overwritten by equo conf update
'filesbackup': True,
# option to enable forced installation of critical updates
'forcedupdates': True,
# collision protection option, see client.conf for more info
'collisionprotect': 1,
# list of user specified CONFIG_PROTECT directories
# (see Gentoo manual to understand the meaining of this parameter)
'configprotect': [],
# list of user specified CONFIG_PROTECT_MASK directories
'configprotectmask': [],
# list of user specified configuration files that
# should be ignored and kept as they are
'configprotectskip': [],
# installed database CONFIG_PROTECT directories
'dbconfigprotect': [],
# installed database CONFIG_PROTECT_MASK directories
'dbconfigprotectmask': [],
# this will be used to show the number of updated
# files at the end of the processes
'configprotectcounter': 0,
# default Entropy release version
'entropyversion': "1.0",
# default system name (overidden by entropy.conf settings)
'systemname': "Sabayon Linux",
# Product identificator (standard, professional...)
'product': "standard",
'errorstatus': default_etp_confdir+"/code",
'systemroot': rootdir, # default system root
'uid': os.getuid(), # current running UID
'entropygid': None,
'sysgroup': "entropy",
'defaultumask': 022,
'storeumask': 002,
'gentle_nice': 15,
'current_nice': 0,
'default_nice': 0,
'server_treeupdatescalled': set(),
'client_treeupdatescalled': set(),
'spm': {
'(r)depend_id': 0,
'pdepend_id': 1,
'mdepend_id': 2, # actually, this is entropy-only
'ebuild_file_extension': "ebuild",
'preinst_phase': "preinst",
'postinst_phase': "postinst",
'prerm_phase': "prerm",
'postrm_phase': "postrm",
'setup_phase': "setup",
'compile_phase': "compile",
'install_phase': "install",
'unpack_phase': "unpack",
'ebuild_pkg_tag_var': "ENTROPY_PROJECT_TAG",
'global_make_conf': rootdir+"/etc/make.conf",
'global_package_keywords': rootdir+"/etc/portage/package.keywords",
'global_package_use': rootdir+"/etc/portage/package.use",
'global_package_mask': rootdir+"/etc/portage/package.mask",
'global_package_unmask': rootdir+"/etc/portage/package.unmask",
'global_make_profile': rootdir+"/etc/make.profile",
'global_make_profile_link_name' : "profile.link",
# source package manager executable
'exec': rootdir+"/usr/bin/emerge",
'env_update_cmd': rootdir+"/usr/sbin/env-update",
'source_profile': ["source", rootdir+"/etc/profile"],
'source_build_ext': ".ebuild",
'ask_cmd': "--ask",
'info_cmd': "--info",
'remove_cmd': "-C",
'nodeps_cmd': "--nodeps",
'fetchonly_cmd': "--fetchonly",
'buildonly_cmd': "--buildonly",
'oneshot_cmd': "--oneshot",
'pretend_cmd': "--pretend",
'verbose_cmd': "--verbose",
'nocolor_cmd': "--color=n",
'backend': "portage", # default one
'xpak_entries': {
'description': "DESCRIPTION",
'homepage': "HOMEPAGE",
'chost': "CHOST",
'category': "CATEGORY",
'cflags': "CFLAGS",
'cxxflags': "CXXFLAGS",
'license': "LICENSE",
'src_uri': "SRC_URI",
'use': "USE",
'iuse': "IUSE",
'slot': "SLOT",
'provide': "PROVIDE",
'depend': "DEPEND",
'rdepend': "RDEPEND",
'pdepend': "PDEPEND",
'needed': "NEEDED",
'inherited': "INHERITED",
'keywords': "KEYWORDS",
'contents': "CONTENTS",
'counter': "COUNTER",
'defined_phases': "DEFINED_PHASES",
'pf': "PF",
},
'system_packages': [],
'ignore-spm-downgrades': False,
},
# entropy client packages download speed limit (in kb/sec)
'downloadspeedlimit': None,
# data storage directory, useful to speed up
# entropy client across multiple issued commands
'dumpstoragedir': default_etp_dir+default_etp_cachesdir,
# where GLSAs are stored
'securitydir': default_etp_dir+default_etp_securitydir,
'securityurl': "http://community.sabayonlinux.org/security"
"/security-advisories.tar.bz2",
'safemodeerrors': {
'clientdb': 1,
},
'safemodereasons': {
0: _("All fine"),
1: _("Corrupted Client Repository. Please restore a backup."),
},
'misc_counters': {
'forced_atoms_update_ids': {
'__idtype__': 1,
'kde': 1,
},
},
'system_settings_plugins_ids': {
'client_plugin': "client_plugin",
'server_plugin': "server_plugin",
'server_plugin_fatscope': "server_plugin_fatscope",
},
'clientserverrepoid': "__system__",
'clientdbid': "client",
'serverdbid': "etpdb:",
'genericdbid': "generic",
'systemreleasefile': "/etc/sabayon-release",
# these are constants, for real settings
# look ad SystemSettings class
'socket_service': { # here are the constants
'hostname': "localhost",
'port': 1026,
'ssl_port': 1027, # above + 1
'timeout': 200,
'forked_requests_timeout': 300,
'max_command_length': 768000, # bytes
'threads': 5,
'session_ttl': 15,
'default_uid': 0,
'max_connections': 5,
'max_connections_per_host': 15,
'max_connections_per_host_barrier': 8,
'disabled_cmds': set(),
'ip_blacklist': set(),
'ssl_key': default_etp_confdir+"/socket_server.key",
'ssl_cert': default_etp_confdir+"/socket_server.crt",
'ssl_ca_cert': default_etp_confdir+"/socket_server.CA.crt",
'ssl_ca_pkey': default_etp_confdir+"/socket_server.CA.key",
'answers': {
'ok': chr(0)+"OK"+chr(0), # command run
'er': chr(0)+"ER"+chr(1), # execution error
'no': chr(0)+"NO"+chr(2), # not allowed
'cl': chr(0)+"CL"+chr(3), # close connection
'mcr': chr(0)+"MCR"+chr(4), # max connections reached
'eos': chr(0), # end of size,
'noop': chr(0)+"NOOP"+chr(0)
},
},
'install_sources': {
'unknown': 0,
'user': 1,
'automatic_dependency': 2,
},
'pkg_masking_reasons': {
0: _('reason not available'),
1: _('user package.mask'),
2: _('system keywords'),
3: _('user package.unmask'),
4: _('user repo package.keywords (all packages)'),
5: _('user repo package.keywords'),
6: _('user package.keywords'),
7: _('completely masked (by keyword?)'),
8: _('repository general packages.db.mask'),
9: _('repository general packages.db.keywords'),
10: _('user license.mask'),
11: _('user live unmask'),
12: _('user live mask'),
},
'pkg_masking_reference': {
'reason_not_avail': 0,
'user_package_mask': 1,
'system_keyword': 2,
'user_package_unmask': 3,
'user_repo_package_keywords_all': 4,
'user_repo_package_keywords': 5,
'user_package_keywords': 6,
'completely_masked': 7,
'repository_packages_db_mask': 8,
'repository_packages_db_keywords': 9,
'user_license_mask': 10,
'user_live_unmask': 11,
'user_live_mask': 12,
},
'ugc_doctypes': {
'comments': 1,
'bbcode_doc': 2,
'image': 3,
'generic_file': 4,
'youtube_video': 5,
},
'ugc_doctypes_description': {
1: _('Comments'),
2: _('BBcode Documents'),
3: _('Images/Screenshots'),
4: _('Generic Files'),
5: _('YouTube(tm) Videos'),
},
'ugc_doctypes_description_singular': {
1: _('Comment'),
2: _('BBcode Document'),
3: _('Image/Screenshot'),
4: _('Generic File'),
5: _('YouTube(tm) Video'),
},
'ugc_accessfile': default_etp_ugc_confdir+"/access.xml",
'ugc_voterange': range(1, 6),
# handler settings
'handlers': {
# md5sum handler,
'md5sum': "md5sum.php?arch="+etpSys['arch']+"&package=",
},
}
# set current nice level
try:
my_const['current_nice'] = os.nice(0)
except OSError:
pass
etpConst.update(my_const)
def const_set_nice_level(nice_level = 0):
"""
Change current process scheduler "nice" level.
@param nice_level: new valid nice level
@type nice_level: int
@rtype: int
@return: current_nice new nice level
"""
default_nice = etpConst['default_nice']
current_nice = etpConst['current_nice']
delta = current_nice - default_nice
try:
etpConst['current_nice'] = os.nice(delta*-1+nice_level)
except OSError:
pass
return current_nice
def const_extract_cli_repo_params(repostring, branch = None, product = None):
"""
Extract repository information from the provided repository string,
usually contained in the repository settings file, repositories.conf.
@param repostring: valid repository identifier
@type repostring: string
@rtype: tuple (string, dict)
@return: tuple composed by (repository identifier, extracted repository
metadata)
"""
if branch == None:
branch = etpConst['branch']
if product == None:
product = etpConst['product']
reponame = repostring.split("|")[1].strip()
repodesc = repostring.split("|")[2].strip()
repopackages = repostring.split("|")[3].strip()
repodatabase = repostring.split("|")[4].strip()
eapi3_port = int(etpConst['socket_service']['port'])
eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
eapi3_formatcolon = repodatabase.rfind("#")
if eapi3_formatcolon != -1:
try:
ports = repodatabase[eapi3_formatcolon+1:].split(",")
eapi3_port = int(ports[0])
if len(ports) > 1:
eapi3_ssl_port = int(ports[1])
repodatabase = repodatabase[:eapi3_formatcolon]
except (ValueError, IndexError,):
eapi3_port = int(etpConst['socket_service']['port'])
eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
dbformat = etpConst['etpdatabasefileformat']
dbformatcolon = repodatabase.rfind("#")
if dbformatcolon != -1:
if dbformat in etpConst['etpdatabasesupportedcformats']:
try:
dbformat = repodatabase[dbformatcolon+1:]
except (IndexError, ValueError, TypeError,):
pass
repodatabase = repodatabase[:dbformatcolon]
mydata = {}
mydata['repoid'] = reponame
mydata['service_port'] = eapi3_port
mydata['ssl_service_port'] = eapi3_ssl_port
mydata['description'] = repodesc
mydata['packages'] = []
mydata['plain_packages'] = []
mydata['dbpath'] = etpConst['etpdatabaseclientdir'] + "/" + reponame + \
"/" + product + "/" + etpConst['currentarch'] + "/" + branch
mydata['dbcformat'] = dbformat
if not dbformat in etpConst['etpdatabasesupportedcformats']:
mydata['dbcformat'] = etpConst['etpdatabasesupportedcformats'][0]
mydata['plain_database'] = repodatabase
mydata['database'] = repodatabase + "/" + product + "/" + \
reponame + "/database/" + etpConst['currentarch'] + \
"/" + branch
mydata['notice_board'] = mydata['database'] + "/" + \
etpConst['rss-notice-board']
mydata['local_notice_board'] = mydata['dbpath'] + "/" + \
etpConst['rss-notice-board']
mydata['local_notice_board_userdata'] = mydata['dbpath'] + "/" + \
etpConst['rss-notice-board-userdata']
mydata['dbrevision'] = "0"
dbrevision_file = os.path.join(mydata['dbpath'],
etpConst['etpdatabaserevisionfile'])
if os.path.isfile(dbrevision_file) and os.access(dbrevision_file, os.R_OK):
with open(dbrevision_file, "r") as dbrev_f:
mydata['dbrevision'] = dbrev_f.readline().strip()
# setup script paths
mydata['post_branch_hop_script'] = mydata['dbpath'] + "/" + \
etpConst['etp_post_branch_hop_script']
mydata['post_branch_upgrade_script'] = mydata['dbpath'] + "/" + \
etpConst['etp_post_branch_upgrade_script']
# initialize CONFIG_PROTECT
# will be filled the first time the db will be opened
mydata['configprotect'] = None
mydata['configprotectmask'] = None
repopackages = [x.strip() for x in repopackages.split() if x.strip()]
repopackages = [x for x in repopackages if (x.startswith('http://') or \
x.startswith('ftp://') or x.startswith('file://'))]
for repo_package in repopackages:
try:
repo_package = str(repo_package)
except (UnicodeDecodeError,UnicodeEncodeError,):
continue
mydata['plain_packages'].append(repo_package)
mydata['packages'].append(repo_package + "/" + product + "/" + reponame)
return reponame, mydata
def const_read_entropy_release():
"""
Read Entropy release file content and fill etpConst['entropyversion']
@rtype: None
@return: None
"""
# handle Entropy Version
revision_file = "../libraries/revision"
if not os.path.isfile(revision_file):
revision_file = os.path.join(etpConst['installdir'],
'libraries/revision')
if os.path.isfile(revision_file) and \
os.access(revision_file,os.R_OK):
with open(revision_file, "r") as rev_f:
myrev = rev_f.readline().strip()
etpConst['entropyversion'] = myrev
def const_pid_exists(pid):
"""
Determine whether given pid exists.
@param pid: process id
@type pid: int
@return: pid exists? 1; pid does not exist? 0
@rtype: int
"""
try:
os.kill(pid, signal.SIG_DFL)
return 1
except OSError, err:
return err.errno == errno.EPERM
def const_setup_entropy_pid(just_read = False, force_handling = False):
"""
Setup Entropy pid file, if possible and if UID = 0 (root).
If the application is run with --no-pid-handling argument,
this function will have no effect. If just_read is specified,
this function will only try to read the current pid string in
the Entropy pid file (etpConst['pidfile']). If any other entropy
istance is currently owning the contained pid, etpConst['applicationlock']
becomes True.
@param just_read: only read the current pid file, if any and if possible
@type just_read: bool
@param force_handling: force pid handling even if "--no-pid-handling" is
given
@type force_handling: bool
@rtype: bool
@return: if pid lock file has been acquired
"""
if (("--no-pid-handling" in sys.argv) and not force_handling) \
and not just_read:
return False
setup_done = False
# PID creation
pid = os.getpid()
pid_file = etpConst['pidfile']
if os.path.isfile(pid_file) and os.access(pid_file, os.R_OK):
try:
with open(pid_file,"r") as pid_f:
found_pid = str(pid_f.readline().strip())
except (IOError, OSError, UnicodeEncodeError, UnicodeDecodeError,):
found_pid = "0000" # which is always invalid
try:
found_pid = int(found_pid)
except ValueError:
found_pid = 0
if found_pid != pid:
# is found_pid still running ?
if (found_pid != 0) and const_pid_exists(found_pid):
etpConst['applicationlock'] = True
elif (not just_read) and os.access(pid_file, os.W_OK):
try:
with open(pid_file,"w") as pid_f:
pid_f.write(str(pid))
pid_f.flush()
except IOError, err:
if err.errno != 30: # readonly filesystem
raise
try:
const_chmod_entropy_pid()
except OSError:
pass
setup_done = True
elif not just_read:
#if etpConst['uid'] == 0:
if os.access(os.path.dirname(pid_file), os.W_OK):
if os.path.exists(pid_file):
if os.path.islink(pid_file):
os.remove(pid_file)
elif os.path.isdir(pid_file):
import shutil
shutil.rmtree(pid_file)
with open(pid_file, "w") as pid_fw:
try:
fcntl.flock(pid_fw.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
pid_fw.write(str(pid))
pid_fw.flush()
except IOError, err:
# already locked?
if err.errno not in (errno.EACCES, errno.EAGAIN,):
raise
# lock is being acquired by somebody else
# cannot write
return False
try:
const_chmod_entropy_pid()
except OSError:
pass
setup_done = True
return setup_done
def const_remove_entropy_pid():
"""
Remove Entropy pid if function calling pid matches the one stored.
"""
pid = os.getpid()
pid_file = etpConst['pidfile']
if not os.path.lexists(pid_file):
return True # not found, so removed
# open file
try:
with open(pid_file,"r") as pid_f:
found_pid = str(pid_f.readline().strip())
except (IOError, OSError, UnicodeEncodeError, UnicodeDecodeError,):
found_pid = "0000" # which is always invalid
try:
found_pid = int(found_pid)
except ValueError:
found_pid = 0
if (pid != found_pid) and (found_pid != 0):
# cannot remove, i'm not the owner
return False
removed = False
try:
# using os.remove for atomicity
os.remove(pid_file)
removed = True
except OSError, err:
if err.errno not in (errno.ENOENT, errno.EACCES,):
raise
if err.errno == errno.EACCES:
removed = False
else:
removed = True
return removed
def const_secure_config_file(config_file):
"""
Setup entropy file needing strict permissions, no world readable.
@param config_file: valid config file path
@type config_file: string
@rtype: None
@return: None
"""
try:
mygid = const_get_entropy_gid()
except KeyError:
mygid = 0
try:
const_setup_file(config_file, mygid, 0660)
except (OSError, IOError,):
pass
def const_chmod_entropy_pid():
"""
Setup entropy pid file permissions, if possible.
@return: None
"""
try:
mygid = const_get_entropy_gid()
except KeyError:
mygid = 0
const_setup_file(etpConst['pidfile'], mygid, 0664)
def const_create_working_dirs():
"""
Setup Entropy directory structure, as much automagically as possible.
@rtype: None
@return: None
"""
# handle pid file
piddir = os.path.dirname(etpConst['pidfile'])
if not os.path.exists(piddir) and (etpConst['uid'] == 0):
os.makedirs(piddir)
# create tmp dir
#if not os.path.isdir(xpakpath_dir):
# os.makedirs(xpakpath_dir,0775)
# const_setup_file(xpakpath_dir,
# create user if it doesn't exist
gid = None
try:
gid = const_get_entropy_gid()
except KeyError:
if etpConst['uid'] == 0:
# create group
# avoid checking cause it's not mandatory for entropy/equo itself
const_add_entropy_group()
try:
gid = const_get_entropy_gid()
except KeyError:
pass
# Create paths
keys = [x for x in etpConst if isinstance(etpConst[x], basestring)]
for key in keys:
if not etpConst[key] or \
etpConst[key].endswith(".conf") or \
not os.path.isabs(etpConst[key]) or \
etpConst[key].endswith(".cfg") or \
etpConst[key].endswith(".tmp") or \
etpConst[key].find(".db") != -1 or \
etpConst[key].find(".log") != -1 or \
os.path.isdir(etpConst[key]) or \
not key.endswith("dir"):
continue
# allow users to create dirs in custom paths,
# so don't fail here even if we don't have permissions
try:
key_dir = etpConst[key]
d_paths = []
while not os.path.isdir(key_dir):
d_paths.append(key_dir)
key_dir = os.path.dirname(key_dir)
d_paths = sorted(d_paths)
for d_path in d_paths:
os.mkdir(d_path)
const_setup_file(d_path, gid, 0775)
except (OSError, IOError,):
pass
if gid:
etpConst['entropygid'] = gid
if not os.path.isdir(etpConst['entropyworkdir']):
try:
os.makedirs(etpConst['entropyworkdir'])
except OSError:
pass
w_gid = os.stat(etpConst['entropyworkdir'])[stat.ST_GID]
if w_gid != gid:
const_setup_perms(etpConst['entropyworkdir'], gid)
if not os.path.isdir(etpConst['entropyunpackdir']):
try:
os.makedirs(etpConst['entropyunpackdir'])
except OSError:
pass
try:
w_gid = os.stat(etpConst['entropyunpackdir'])[stat.ST_GID]
if w_gid != gid:
if os.path.isdir(etpConst['entropyunpackdir']):
const_setup_perms(etpConst['entropyunpackdir'], gid)
except OSError:
pass
# always setup /var/lib/entropy/client permissions
if not const_islive():
# aufs/unionfs will start to leak otherwise
const_setup_perms(etpConst['etpdatabaseclientdir'], gid)
def const_configure_lock_paths():
"""
Setup Entropy lock file paths.
@rtype: None
@return: None
"""
etpConst['locks'] = {
'using_resources': os.path.join(etpConst['etpdatabaseclientdir'],
'.using_resources'),
}
def const_extract_srv_repo_params(repostring, product = None):
"""
Analyze a server repository string (usually contained in server.conf),
extracting all the parameters.
@param repostring: repository string
@type repostring: string
@keyword product: system product which repository belongs to
@rtype: None
@return: None
"""
if product == None:
product = etpConst['product']
mydata = {}
repoid = repostring.split("|")[1].strip()
repodesc = repostring.split("|")[2].strip()
repouris = repostring.split("|")[3].strip()
repohandlers = repostring.split("|")[4].strip()
service_url = None
eapi3_port = int(etpConst['socket_service']['port'])
eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
if len(repostring.split("|")) > 5:
service_url = repostring.split("|")[5].strip()
eapi3_formatcolon = service_url.rfind("#")
if eapi3_formatcolon != -1:
try:
ports = service_url[eapi3_formatcolon+1:].split(",")
eapi3_port = int(ports[0])
if len(ports) > 1:
eapi3_ssl_port = int(ports[1])
service_url = service_url[:eapi3_formatcolon]
except (ValueError, IndexError,):
eapi3_port = int(etpConst['socket_service']['port'])
eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
mydata = {}
mydata['repoid'] = repoid
mydata['description'] = repodesc
mydata['mirrors'] = []
mydata['community'] = False
mydata['service_url'] = service_url
mydata['service_port'] = eapi3_port
mydata['ssl_service_port'] = eapi3_ssl_port
if repohandlers:
repohandlers = os.path.join(repohandlers, product, repoid, "handlers")
mydata['handler'] = repohandlers
uris = repouris.split()
for uri in uris:
mydata['mirrors'].append(uri)
return repoid, mydata
def const_setup_perms(mydir, gid):
"""
Setup permissions and group id (GID) to a directory, recursively.
@param mydir: valid file path
@type mydir: string
@param gid: valid group id (GID)
@type gid: int
@rtype: None
@return: None
"""
if gid == None:
return
for currentdir, subdirs, files in os.walk(mydir):
try:
cur_gid = os.stat(currentdir)[stat.ST_GID]
if cur_gid != gid:
os.chown(currentdir, -1, gid)
cur_mod = const_get_chmod(currentdir)
if cur_mod != oct(0775):
os.chmod(currentdir, 0775)
except OSError:
pass
for item in files:
item = os.path.join(currentdir, item)
try:
const_setup_file(item, gid, 0664)
except OSError:
pass
def const_setup_file(myfile, gid, chmod):
"""
Setup file permissions and group id (GID).
@param myfile: valid file path
@type myfile: string
@param gid: valid group id (GID)
@type gid: int
@param chmod: permissions
@type chmod: integer representing an octal
@rtype: None
@return: None
"""
cur_gid = os.stat(myfile)[stat.ST_GID]
if cur_gid != gid:
os.chown(myfile, -1, gid)
const_set_chmod(myfile, chmod)
# you need to convert to int
def const_get_chmod(myfile):
"""
This function get the current permissions of the specified
file. If you want to use the returning value with const_set_chmod
you need to convert it back to int.
@param myfile: valid file path
@type myfile: string
@rtype: integer(8) (octal)
@return: octal representing permissions
"""
myst = os.stat(myfile)[stat.ST_MODE]
return oct(myst & 0777)
def const_set_chmod(myfile, chmod):
"""
This function sets specified permissions to a file.
If they differ from the current ones.
@param myfile: valid file path
@type myfile: string
@param chmod: permissions
@type chmod: integer representing an octal
@rtype: None
@return: None
"""
cur_mod = const_get_chmod(myfile)
if cur_mod != oct(chmod):
os.chmod(myfile, chmod)
def const_get_entropy_gid():
"""
This function tries to retrieve the "entropy" user group
GID.
@rtype: None
@return: None
@raise KeyError: when "entropy" system GID is not available
"""
group_file = etpConst['systemroot']+'/etc/group'
if not os.path.isfile(group_file):
raise KeyError
with open(group_file,"r") as group_f:
for line in group_f.readlines():
if line.startswith('%s:' % (etpConst['sysgroup'],)):
try:
gid = int(line.split(":")[2])
except ValueError:
raise KeyError
return gid
raise KeyError
def const_add_entropy_group():
"""
This function looks for an "entropy" user group.
If not available, it tries to create one.
@rtype: None
@return: None
@raise KeyError: if ${ROOT}/etc/group is not found
"""
group_file = etpConst['systemroot']+'/etc/group'
if not os.path.isfile(group_file):
raise KeyError
ids = set()
with open(group_file,"r") as group_f:
for line in group_f.readlines():
if line and line.split(":"):
try:
myid = int(line.split(":")[2])
except ValueError:
pass
ids.add(myid)
if ids:
# starting from 1000, get the first free
new_id = 1000
while 1:
new_id += 1
if new_id not in ids:
break
else:
new_id = 10000
with open(group_file,"aw") as group_fw:
group_fw.seek(0, 2)
app_line = "entropy:x:%s:\n" % (new_id,)
group_fw.write(app_line)
group_fw.flush()
def const_islive():
"""
Live environments (Operating System running off a CD/DVD)
must feature the "cdroot" parameter in kernel /proc/cmdline
Sample code:
>>> from entropy.const import const_islive
>>> const_islive()
False
@rtype: bool
@return: determine wether this is a Live system or not
"""
if "cdroot" in etpConst['cmdline']:
return True
return False
def const_kill_threads():
"""
Entropy threads killer. Even if Python threads cannot
be stopped or killed, TimeScheduled ones can, exporting
the kill() method.
Sample code:
>>> from entropy.const import const_kill_threads
>>> const_kill_threads()
@rtype: None
@return: None
"""
import threading
threads = threading.enumerate()
for running_t in threads:
# do not join current thread
if running_t.getName() == 'MainThread':
continue
if hasattr(running_t,'kill'):
running_t.kill()
running_t.join(120.0) # wait 2 minutes?
def __const_handle_exception(etype, value, t_back):
"""
Our default Python exception handler. It kills
all the threads generated by Entropy before
raising exceptions. Overloads sys.excepthook,
internal function !!
@param etype: exception type
@type etype: exception type
@param value: exception data
@type value: string
@param t_back: traceback object?
@type t_back: Python traceback object
@rtype: default Python exceptions hook
@return: sys.__excepthook__
"""
try:
const_kill_threads()
except (AttributeError, ImportError, TypeError,):
pass
return sys.__excepthook__(etype, value, t_back)
def const_debug_write(identifier, msg):
"""
Entropy debugging output write functions.
@param identifier: debug identifier
@type identifier: string
@param msg: debugging message
@type msg: string
@rtype: None
@return: None
"""
if etpUi['debug']:
sys.stdout.write("%s: %s" % (identifier, msg + "\n"))
# load config
initconfig_entropy_constants(etpSys['rootdir'])