Package entropy :: Module const

Source Code for Module entropy.const

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <[email protected]> 
   5      @contact: [email protected] 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Framework constants module}. 
  10   
  11      This module contains all the Entropy constants used all around 
  12      the "entropy" package. 
  13   
  14      Some of the constants in this module are used as "default" for 
  15      the SystemSettings interface. So, make sure to read the documentation 
  16      of SystemSettings in the "entropy.core" module. 
  17   
  18      Even if possible, etpConst, etpUi, and etpSys objects 
  19      *SHOULD* be I{never ever modified manually}. This freedom could change 
  20      in future, so, if you want to produce a stable code, DON'T do that at all! 
  21   
  22      Basic Entropy constants handling functions are available in this module 
  23      and are all prefixed with "I{const_*}" or "I{initconfig_*}". 
  24      If you are writing a third party application, you should always try 
  25      to avoid to deal directly with functions here unless specified otherwise. 
  26      In fact, usually these here are wrapper in upper-level modules 
  27      (entropy.client, entropy.server, entropy.services). 
  28   
  29   
  30  """ 
  31  import sys 
  32  import os 
  33  import time 
  34  import codecs 
  35   
  36   
  37  import stat 
  38  import errno 
  39  import signal 
  40  import gzip 
  41  import bz2 
  42  import grp 
  43  import pwd 
  44  import tempfile 
  45  import traceback 
  46  import threading 
  47  try: 
  48      import thread 
  49  except ImportError: 
  50      # python 3.x 
  51      import _thread as thread 
  52  from entropy.i18n import _, ENCODING, RAW_ENCODING 
  53   
  54  # Setup debugger hook on SIGUSR1 
55 -def debug_signal(signum, frame):
56 import pdb 57 pdb.set_trace()
58 if os.getuid() == 0: 59 signal.signal(signal.SIGUSR1, debug_signal) 60 61 # Setup thread dump hook on SIGQUIT
62 -def dump_signal(signum, frame, extended=True, stderr=sys.stderr):
63 64 def _std_print_err(msg): 65 stderr.write(msg + '\n') 66 stderr.flush()
67 68 _std_print_err("") 69 _std_print_err("") 70 _std_print_err("---- DUMP START [cut here] ----") 71 thread_count = 0 72 threads_map = dict((x.ident, x) for x in threading.enumerate()) 73 for thread_id, stack in sys._current_frames().items(): 74 thread_count += 1 75 thread_obj = threads_map.get(thread_id, "N/A") 76 _std_print_err("Thread: %s, object: %s" % (thread_id, thread_obj)) 77 78 stack_list = [] 79 _stack = stack 80 while True: 81 stack_list.append(_stack) 82 _stack = _stack.f_back 83 if _stack is None: 84 break 85 86 for filename, lineno, name, line in traceback.extract_stack(stack): 87 _std_print_err("File: '%s', line %d, in %s'" % ( 88 filename, lineno, name,)) 89 if line: 90 _std_print_err(" %s" % (line.rstrip(),)) 91 else: 92 _std_print_err(" ???") 93 94 if not extended: 95 continue 96 97 try: 98 _stack = stack_list.pop() 99 except IndexError: 100 _stack = None 101 if _stack is None: 102 continue 103 104 for key, value in _stack.f_locals.items(): 105 cur_str = "\t%20s = " % key 106 try: 107 cur_str += repr(value) 108 except (AttributeError, NameError, TypeError): 109 cur_str += "<ERROR WHILE PRINTING VALUE>" 110 _std_print_err(cur_str) 111 112 _std_print_err("--") 113 _std_print_err("") 114 _std_print_err("[thread count: %d]" % (thread_count,)) 115 _std_print_err("---- DUMP END [cut here] ----") 116 _std_print_err("") 117 118 _installed_sigquit = False 119 if os.getuid() == 0: 120 _installed_sigquit = True 121 signal.signal(signal.SIGQUIT, dump_signal) 122 123 _uname_m = os.uname()[4] 124 _rootdir = os.getenv("ETP_ROOT", "").rstrip("/") 125 _arch_override_file = os.path.join("/", _rootdir, "etc/entropy/.arch") 126 ETP_ARCH_CONST = None 127 if os.path.isfile(_arch_override_file): 128 try: 129 with codecs.open(_arch_override_file, "r", encoding=ENCODING) \ 130 as arch_f: 131 _arch_const = arch_f.readline().strip() 132 if _arch_const: 133 ETP_ARCH_CONST = _arch_const 134 except (IOError, OSError) as err: 135 const_debug_write("_init_", repr(err)) 136 137 # ETP_ARCH_CONST setup 138 # add more arches here 139 ETP_ARCH_MAP = { 140 ("i386", "i486", "i586", "i686",): "x86", 141 ("x86_64",): "amd64", 142 ("mips", "mips64",): "mips", 143 } 144 145 if ETP_ARCH_CONST is None: 146 for arches, arch in ETP_ARCH_MAP.items(): 147 if _uname_m in arches: 148 ETP_ARCH_CONST = arch 149 break 150 151 _more_keywords = None 152 if _uname_m.startswith("arm"): 153 # ARM is "special", multiple subarches 154 # ahead, better use the full uname value 155 # and account "arm" to etpSys['keywords'] 156 if ETP_ARCH_CONST is None: 157 ETP_ARCH_CONST = _uname_m 158 _more_keywords = set(["arm", "~arm"]) 159 elif ETP_ARCH_CONST is None: 160 ETP_ARCH_CONST = "UNKNOWN" 161 162 etpSys = { 163 'archs': ['alpha', 'amd64', 'amd64-fbsd', 'arm', 'hppa', 'ia64', 'm68k', 164 'mips', 'ppc', 'ppc64', 's390', 'sh', 'sparc', 'sparc-fbsd', 'x86', 165 'x86-fbsd'], 166 'keywords': set([ETP_ARCH_CONST, "~"+ETP_ARCH_CONST]), 167 'api': '3', 168 'arch': ETP_ARCH_CONST, 169 'rootdir': _rootdir, 170 'serverside': False, 171 'unittest': False, 172 } 173 if _more_keywords is not None: 174 etpSys['keywords'] |= _more_keywords 175 176 # debug mode flag, will be triggered by ETP_DEBUG env var. 177 _DEBUG = os.getenv("ETP_DEBUG") is not None 178 179 if _DEBUG and not _installed_sigquit: 180 # install the dump signal function at 181 # SIGQUIT anyway if --debug is enabled 182 signal.signal(signal.SIGQUIT, dump_signal) 183 184 etpConst = {} 185
186 -def initconfig_entropy_constants(rootdir):
187 """ 188 Main constants configurators, this is the only function that you should 189 call from the outside, anytime you want. it will reset all the variables 190 excluding those backed up previously. 191 192 @param rootdir: current root directory, if any, or "" 193 @type rootdir: string 194 @rtype: None 195 @return: None 196 @raise AttributeError: when specified rootdir is not a directory 197 """ 198 if rootdir and not os.path.isdir(rootdir): 199 raise AttributeError("not a valid chroot.") 200 201 # set env ROOT 202 # this way it doesn't need to be set around the code 203 os.environ['ROOT'] = rootdir + os.path.sep 204 205 # save backed up settings 206 if 'backed_up' in etpConst: 207 backed_up_settings = etpConst.pop('backed_up') 208 else: 209 backed_up_settings = {} 210 211 const_default_settings(rootdir) 212 const_read_entropy_release() 213 214 const_create_working_dirs() 215 216 # reflow back settings 217 etpConst.update(backed_up_settings) 218 etpConst['backed_up'] = backed_up_settings.copy() 219 220 # try to set proper permissions for /etc/entropy (at least group) 221 # /etc/entropy should be always writeable by "entropy" group ! 222 # DO NOT FRIGGIN REMOVE 223 const_setup_perms(etpConst['confdir'], etpConst['entropygid'], 224 recursion = False) 225 226 # also setup /var/tmp/entropy if it doesn't exist. 227 # /var/tmp can be mounted on tmpfs 228 if not os.path.isdir(etpConst['entropyunpackdir']): 229 try: 230 const_setup_directory(etpConst['entropyunpackdir']) 231 except (OSError, IOError) as err: 232 sys.stderr.write("WARNING: cannot create %s: %s\n" % ( 233 etpConst['entropyunpackdir'], repr(err),)) 234 235 if sys.excepthook is sys.__excepthook__: 236 sys.excepthook = __const_handle_exception
237
238 -def const_default_settings(rootdir):
239 """ 240 Initialization of all the Entropy base settings. 241 242 @param rootdir: current root directory, if any, or "" 243 @type rootdir: string 244 @rtype: None 245 @return: None 246 """ 247 original_rootdir = rootdir 248 if not rootdir.strip(): 249 rootdir = os.path.sep 250 default_etp_dir = os.getenv( 251 'DEV_ETP_VAR_DIR', 252 os.path.join(rootdir, "var/lib/entropy")) 253 default_etp_dbdir_name = "database" 254 255 default_etp_run_dir = os.getenv( 256 'DEV_ETP_RUN_DIR', 257 os.path.join(rootdir, "run/entropy")) 258 259 default_etp_dbdir = os.path.join( 260 default_etp_dbdir_name, ETP_ARCH_CONST) 261 default_etp_dbfile = "packages.db" 262 default_etp_dbclientfile = "equo.db" 263 default_etp_client_repodir = "client" 264 default_etp_cachesdir = "caches" 265 default_etp_securitydir = "glsa" 266 default_etp_logdir = "logs" 267 268 default_etp_confdir = os.getenv( 269 'DEV_ETP_ETC_DIR', 270 os.path.join(rootdir, "etc/entropy")) 271 default_etp_syslogdir = os.getenv( 272 'DEV_ETP_LOG_DIR', 273 os.path.join(rootdir, "var/log/entropy")) 274 default_etp_vardir = os.getenv( 275 'DEV_ETP_TMP_DIR', 276 os.path.join(rootdir, "var/tmp/entropy")) 277 278 default_etp_tmpcache_dir = os.getenv('DEV_ETP_CACHE_DIR', 279 os.path.join(default_etp_dir, default_etp_cachesdir)) 280 281 etpConst.clear() 282 my_const = { 283 'logging': { 284 'normal_loglevel_id': 1, 285 'verbose_loglevel_id': 2, 286 }, 287 'backed_up': {}, 288 # entropy default installation directory 289 # (excluding Python modules which can be different) 290 'installdir': '/usr/lib/entropy', 291 292 # directory where entropy stores its configuration 293 'confdir': default_etp_confdir, 294 # name of the package sets directory 295 'confsetsdirname': "sets", 296 297 # used by entropy.spm to build pkgs relative URL metadata ("download", 298 # returned by EntropyRepository.retrieveDownloadURL()) 299 'packagesrelativepath_basedir': "packages", 300 'packagesrelativepath_basedir_nonfree': "packages-nonfree", 301 'packagesrelativepath_basedir_restricted': "packages-restricted", 302 'packagesrelativepaths': ("packages", "packages-nonfree", 303 "packages-restricted"), 304 'packagesrelativepath_basename': ETP_ARCH_CONST, 305 'databaserelativepath_basedir': default_etp_dbdir_name, 306 307 'entropyrundir': default_etp_run_dir, # /run/entropy 308 'entropyworkdir': default_etp_dir, # Entropy workdir 309 # new (since 0.99.48) Entropy downloaded packages location 310 # equals to /var/lib/entropy/client/packages containing packages/, 311 # packages-nonfree/, packages-restricted/ etc 312 'entropypackagesworkdir': os.path.join(default_etp_dir, 313 default_etp_client_repodir, "packages"), 314 # Entropy unpack directory 315 'entropyunpackdir': default_etp_vardir, 316 # Entropy packages image directory 317 'entropyimagerelativepath': "image", 318 319 # entropy repository database upload timestamp 320 'etpdatabasetimestampfile': default_etp_dbfile+".timestamp", 321 # entropy repository database owned (in repo) package files 322 'etpdatabasepkglist': default_etp_dbfile+".pkglist", 323 # same for extra_download metadata 324 'etpdatabaseextrapkglist': default_etp_dbfile+".extra_pkglist", 325 # file containing a list of packages that are strictly 326 # required by the repository, thus forced 327 'etpdatabasesytemmaskfile': default_etp_dbfile+".system_mask", 328 'etpdatabasemaskfile': default_etp_dbfile+".mask", 329 'etpdatabasekeywordsfile': default_etp_dbfile+".keywords", 330 'etpdatabaseupdatefile': default_etp_dbfile+".repo_updates", 331 'etpdatabaselicwhitelistfile': default_etp_dbfile+".lic_whitelist", 332 'etpdatabasecriticalfile': default_etp_dbfile+".critical", 333 'etpdatabasemirrorsfile': default_etp_dbfile+".mirrors", 334 'etpdatabasefallbackmirrorsfile': default_etp_dbfile+".fallback_mirrors", 335 'etpdatabasewebservicesfile': default_etp_dbfile+".webservices", 336 337 # per-repository configuration file to list legally sensible pkgs 338 'etpdatabaserestrictedfile': default_etp_dbfile+".restricted", 339 # the local/remote database revision file 340 'etpdatabaserevisionfile': default_etp_dbfile+".revision", 341 # missing dependencies black list file 342 'etpdatabasemissingdepsblfile': default_etp_dbfile + \ 343 ".missing_deps_blacklist", 344 # compressed file that contains all the "meta" 345 # files in a repository dir 346 'etpdatabasemetafilesfile': default_etp_dbfile+".meta", 347 # file that contains a list of the "meta" 348 # files not available in the repository 349 'etpdatabasemetafilesnotfound': default_etp_dbfile+".meta_notfound", 350 # database file checksum 351 'etpdatabasehashfile': default_etp_dbfile+".md5", 352 353 # the remote database lock file 354 'etpdatabaselockfile': default_etp_dbfile+".lock", 355 # the remote database download lock file 356 'etpdatabasedownloadlockfile': default_etp_dbfile+".download.lock", 357 # eapi3 "there are updates" signal file 358 # used to let EAPI3 remote service daemon know about repository updates 359 'etpdatabaseeapi3updates': default_etp_dbfile+".eapi3_updates", 360 # "there are updates" signal file for webinstall packages 361 # can be used to trigger the generation of new webinstall files 362 'etpdatabasewebinstallupdates': default_etp_dbfile+".webinst_updates", 363 # repository GPG public key file 364 'etpdatabasegpgfile': "signature.asc", 365 'etpgpgextension': ".asc", 366 # Entropy Client GPG repositories keyring path 367 'etpclientgpgdir': default_etp_confdir+"/client-gpg-keys", 368 # when this file exists, the database is not synced 369 # anymore with the online one 370 'etpdatabasetaintfile': default_etp_dbfile+".tainted", 371 372 # Entropy sqlite database file default_etp_dir + \ 373 # default_etp_dbdir+"/packages.db" 374 'etpdatabasefile': default_etp_dbfile, 375 # Entropy sqlite database file (gzipped) 376 'etpdatabasefilegzip': default_etp_dbfile+".gz", 377 'etpdatabasefilegziphash': default_etp_dbfile+".gz.md5", 378 # Entropy sqlite database file (bzipped2) 379 'etpdatabasefilebzip2': default_etp_dbfile+".bz2", 380 'etpdatabasefilebzip2hash': default_etp_dbfile+".bz2.md5", 381 382 # Entropy sqlite database file (gzipped) 383 'etpdatabasefilegziplight': default_etp_dbfile+".light.gz", 384 'etpdatabasefilehashgziplight': default_etp_dbfile+".light.gz.md5", 385 # Entropy sqlite database file (bzipped2) 386 'etpdatabasefilebzip2light': default_etp_dbfile+".light.bz2", 387 'etpdatabasefilehashbzip2light': default_etp_dbfile+".light.bz2.md5", 388 389 # Entropy sqlite database dump file (bzipped2) 390 'etpdatabasedumpbzip2': default_etp_dbfile+".dump.bz2", 391 'etpdatabasedumphashfilebz2': default_etp_dbfile+".dump.bz2.md5", 392 # Entropy sqlite database dump file (gzipped) 393 'etpdatabasedumpgzip': default_etp_dbfile+".dump.gz", 394 'etpdatabasedumphashfilegzip': default_etp_dbfile+".dump.gz.md5", 395 396 # Entropy sqlite database dump file 397 'etpdatabasedump': default_etp_dbfile+".dump", 398 399 # Entropy sqlite database dump file (bzipped2) light ver 400 'etpdatabasedumplightbzip2': default_etp_dbfile+".dumplight.bz2", 401 # Entropy sqlite database dump file (gzipped) light ver 402 'etpdatabasedumplightgzip': default_etp_dbfile+".dumplight.gz", 403 # Entropy sqlite database dump file, light ver (no content) 404 'etpdatabasedumplighthashfilebz2': default_etp_dbfile+".dumplight.bz2.md5", 405 'etpdatabasedumplighthashfilegzip': default_etp_dbfile+".dumplight.gz.md5", 406 'etpdatabasedumplight': default_etp_dbfile+".dumplight", 407 # expiration based server-side packages removal 408 409 'etpdatabaseexpbasedpkgsrm': default_etp_dbfile+".fatscope", 410 411 # Entropy default compressed database format 412 'etpdatabasefileformat': "bz2", 413 # Entropy compressed databases format support 414 'etpdatabasesupportedcformats': ["bz2", "gz"], 415 'etpdatabasecompressclasses': { 416 "bz2": (bz2.BZ2File, "unpack_bzip2", "etpdatabasefilebzip2", 417 "etpdatabasedumpbzip2", "etpdatabasedumphashfilebz2", 418 "etpdatabasedumplightbzip2", "etpdatabasedumplighthashfilebz2", 419 "etpdatabasefilebzip2light", "etpdatabasefilehashbzip2light", 420 "etpdatabasefilebzip2hash",), 421 "gz": (gzip.GzipFile, "unpack_gzip", "etpdatabasefilegzip", 422 "etpdatabasedumpgzip", "etpdatabasedumphashfilegzip", 423 "etpdatabasedumplightgzip", "etpdatabasedumplighthashfilegzip", 424 "etpdatabasefilegziplight", "etpdatabasefilehashgziplight", 425 "etpdatabasefilegziphash",) 426 }, 427 # Distribution website URL 428 'distro_website_url': "http://www.sabayon.org", 429 'packages_website_url': "https://packages.sabayon.org", 430 'changelog_filename': "ChangeLog", 431 'changelog_filename_compressed': "ChangeLog.bz2", 432 'changelog_date_format': "%a, %d %b %Y %X +0000", 433 # enable/disable packages RSS feed feature 434 'rss-feed': True, 435 # default name of the RSS feed 436 'rss-name': "packages.rss", 437 # light version of rss-name 438 'rss-light-name': "updates.rss", 439 # default URL to the entropy web interface 440 # (overridden in reagent.conf) 441 'rss-base-url': "http://packages.sabayon.org/", 442 # default URL to the Operating System website 443 # (overridden in reagent.conf) 444 'rss-website-url': "http://www.sabayon.org/", 445 # xml file where will be dumped ServerInterface.rssMessages dictionary 446 'rss-dump-name': "rss_database_actions", 447 'rss-max-entries': 1000, # maximum rss entries 448 'rss-light-max-entries': 300, # max entries for the light version 449 'rss-managing-editor': "[email protected]", # updates submitter 450 # repository RSS-based notice board content 451 'rss-notice-board': "notice.rss", 452 # File containing user data related to repository notice board 453 'rss-notice-board-userdata': "notice.rss.userdata", 454 # default Entropy Client GPG support bit 455 'client_gpg': True, 456 # "or" dependencies support 457 # app-foo/foo;app-foo/abc? 458 'entropyordepsep': ";", 459 'entropyordepquestion': "?", 460 'entropyslotprefix': ":", 461 'entropytagprefix': "#", 462 'packagesetprefix': "@", 463 'entropyrepoprefix': "@", 464 'entropyrepoprefix_alt': "::", 465 'entropyrevisionprefix': "~", 466 'userpackagesetsid': "__user__", 467 'cachedumpext': ".dmp", 468 'packagesext': ".tbz2", 469 # extra download package file extension (mandatory) 470 'packagesextraext': ".tar.bz2", 471 'packagesdebugext': ".debug.tar.bz2", # .tar.bz2 472 'packagesext_webinstall': ".etp", 473 # entropy package files binary delta extension 474 'packagesdeltaext': ".edelta", 475 # entropy package files binary delta subdir 476 'packagesdeltasubdir': "deltas", 477 # Extension of the file that contains the checksum 478 # of its releated package file 479 'packagesmd5fileext': ".md5", 480 'packagessha512fileext': ".sha512", 481 'packagessha256fileext': ".sha256", 482 'packagessha1fileext': ".sha1", 483 # Supported Entropy Client package hashes encodings 484 'packagehashes': ("sha1", "sha256", "sha512", "gpg"), 485 # Used by Entropy client to override some digest checks 486 'packagemtimefileext': ".mtime", 487 # Extension of the file that "contains" expiration mtime 488 'packagesexpirationfileext': ".expired", 489 # Extension of the file that contains package file 490 # information, replacing the real tarballs to save space. 491 'packagesweakfileext': ".weak", 492 # number of days after a package will be removed from mirrors 493 'packagesexpirationdays': 15, 494 # name of the trigger file that would be executed 495 # by equo inside triggerTools 496 'triggername': "trigger", 497 'trigger_sh_interpreter': rootdir+"/usr/sbin/entropy.sh", 498 # entropy hardware hash generator executable 499 'etp_hw_hash_gen': rootdir+"/usr/bin/entropy_hwgen.sh", 500 # entropy client post valid branch migration (equo hop) script name 501 'etp_post_branch_hop_script': default_etp_dbfile+".post_branch.sh", 502 # entropy client post branch upgrade script 503 'etp_post_branch_upgrade_script': default_etp_dbfile+".post_upgrade.sh", 504 # previous branch file container 505 'etp_previous_branch_file': default_etp_confdir+"/.previous_branch", 506 'etp_in_branch_upgrade_file': default_etp_confdir+"/.in_branch_upgrade", 507 # entropy client post repository update script (this is executed 508 # every time) 509 'etp_post_repo_update_script': default_etp_dbfile+".post_update.sh", 510 511 # proxy configuration constants, used system wide 512 'proxy': { 513 'ftp': os.getenv("FTP_PROXY"), 514 'http': os.getenv("HTTP_PROXY"), 515 'rsync': os.getenv("RSYNC_PROXY"), 516 'username': None, 517 'password': None 518 }, 519 # Entropy log level (default: 1 - see entropy.conf for more info) 520 'entropyloglevel': 1, 521 # Entropy Socket Interface log level 522 'socketloglevel': 2, 523 # Log dir where ebuilds store their stuff 524 'logdir': os.path.join(default_etp_dir, default_etp_logdir), 525 526 # Entropy system tools log directory 527 'syslogdir': default_etp_syslogdir, 528 'entropylogfile': os.path.join( 529 default_etp_syslogdir, "entropy.log"), 530 'securitylogfile': os.path.join( 531 default_etp_syslogdir, "security.log"), 532 533 'etpdatabaseclientdir': os.path.join( 534 default_etp_dir, default_etp_client_repodir, 535 default_etp_dbdir), 536 # path to equo.db - client side database file 537 'etpdatabaseclientfilepath': os.path.join( 538 default_etp_dir, default_etp_client_repodir, 539 default_etp_dbdir, default_etp_dbclientfile), 540 # prefix of database backups 541 'dbbackupprefix': 'entropy_backup_', 542 543 # Entropy database API revision 544 'etpapi': etpSys['api'], 545 # Entropy database API currently supported 546 'supportedapis': (1, 2, 3), 547 # contains the current running architecture 548 'currentarch': etpSys['arch'], 549 # Entropy supported Archs 550 'supportedarchs': etpSys['archs'], 551 552 # default choosen branch (overridden by setting in repositories.conf) 553 'branch': "5", 554 # default allowed package keywords 555 'keywords': etpSys['keywords'].copy(), 556 # allow multiple packages in single scope server-side? 557 # this makes possible to have multiple versions of packages 558 # and handle the removal through expiration (using creation date) 559 'expiration_based_scope': False, 560 # our official repository name 561 'defaultserverrepositoryid': None, 562 'officialrepositoryid': "sabayonlinux.org", 563 # tag to append to .tbz2 file before entropy database (must be 32bytes) 564 'databasestarttag': "|ENTROPY:PROJECT:DB:MAGIC:START|", 565 # option to keep a backup of config files after 566 # being overwritten by equo conf update 567 'filesbackup': True, 568 # option to enable Entropy Client splitdebug support 569 'splitdebug': False, 570 # directories where debug symbols are stored 571 'splitdebug_dirs': ("/usr/lib/debug",), 572 # option to enable forced installation of critical updates 573 'forcedupdates': True, 574 # collision protection option, see client.conf for more info 575 'collisionprotect': 1, 576 # this will be used to show the number of updated 577 # files at the end of the processes 578 'configprotectcounter': 0, 579 # default Entropy release version 580 'entropyversion': "1", 581 # default system name (overidden by entropy.conf settings) 582 'systemname': "Sabayon Linux", 583 # Product identificator (standard, professional...) 584 'product': "standard", 585 'systemroot': original_rootdir, # default system root 586 'uid': os.getuid(), # current running UID 587 'entropygid': None, 588 'entropygid_nopriv': None, 589 'sysgroup': "entropy", 590 'sysgroup_nopriv': "entropy-nopriv", 591 'sysuser_nopriv': "entropy-nopriv", 592 'sysuser_nopriv_fallback': "nobody", 593 'defaultumask': 0o22, 594 'storeumask': 0o02, 595 'gentle_nice': 15, 596 'current_nice': 0, 597 'default_nice': 0, 598 # Default download socket timeout for Entropy Client transceivers 599 'default_download_timeout': 30, 600 # Entropy package dependencies type identifiers 601 'dependency_type_ids': { 602 'rdepend_id': 0, # runtime dependencies 603 'pdepend_id': 1, # post dependencies 604 'mdepend_id': 2, # actually, this is entropy-only 605 'bdepend_id': 3, # build dependencies 606 }, 607 'dependency_type_ids_desc': { 608 'rdepend_id': _("Runtime dependency"), 609 'pdepend_id': _("Post dependency"), 610 'mdepend_id': _('Manually added (by staff) dependency'), 611 'bdepend_id': _('Build dependency'), 612 }, 613 614 # entropy client packages download speed limit (in kb/sec) 615 'downloadspeedlimit': None, 616 617 # data storage directory, useful to speed up 618 # entropy client across multiple issued commands 619 'dumpstoragedir': default_etp_tmpcache_dir, 620 # where GLSAs are stored 621 'securitydir': os.path.join( 622 default_etp_dir, default_etp_securitydir), 623 'securityurl': "http://community.sabayon.org/security" 624 "/security-advisories.tar.bz2", 625 626 'safemodeerrors': { 627 'clientdb': 1, 628 }, 629 'safemodereasons': { 630 0: _("All fine"), 631 1: _("Corrupted Client Repository. Please restore a backup."), 632 }, 633 634 'misc_counters': { 635 'forced_atoms_update_ids': { 636 '__idtype__': 1, 637 'kde': 1, 638 }, 639 }, 640 641 'system_settings_plugins_ids': { 642 'client_plugin': "client_plugin", 643 'server_plugin': "server_plugin", 644 'server_plugin_fatscope': "server_plugin_fatscope", 645 'server_plugin_fake_client': "server_plugin_fake_client", 646 }, 647 648 # TODO: remove when Sulfur and PackageKit stopped using it 649 # keep in sync with InstalledPackagesRepository.NAME 650 'clientdbid': "__system__", 651 652 'spmdbid': "spm-db", 653 'spmetprev': 9999, 654 'systemreleasefile': "/etc/sabayon-release", 655 656 'install_sources': { 657 'unknown': 0, 658 'user': 1, 659 'automatic_dependency': 2, 660 }, 661 662 'pkg_masking_reasons': { 663 0: _('reason not available'), 664 1: _('user package.mask'), 665 2: _('system keywords'), 666 3: _('user package.unmask'), 667 4: _('user repo package.keywords (all packages)'), 668 5: _('user repo package.keywords'), 669 6: _('user package.keywords'), 670 7: _('completely masked (by keyword?)'), 671 8: _('repository general packages.db.mask'), 672 9: _('repository general packages.db.keywords'), 673 10: _('user license.mask'), 674 11: _('user live unmask'), 675 12: _('user live mask'), 676 }, 677 'pkg_masking_reference': { 678 'reason_not_avail': 0, 679 'user_package_mask': 1, 680 'system_keyword': 2, 681 'user_package_unmask': 3, 682 'user_repo_package_keywords_all': 4, 683 'user_repo_package_keywords': 5, 684 'user_package_keywords': 6, 685 'completely_masked': 7, 686 'repository_packages_db_mask': 8, 687 'repository_packages_db_keywords': 9, 688 'user_license_mask': 10, 689 'user_live_unmask': 11, 690 'user_live_mask': 12, 691 }, 692 693 # default entropy configuration files encoding 694 'conf_encoding': ENCODING, 695 'conf_raw_encoding': RAW_ENCODING, 696 697 } 698 699 # set current nice level 700 try: 701 my_const['current_nice'] = os.nice(0) 702 except OSError: 703 pass 704 705 etpConst.update(my_const)
706
707 -def const_is_python3():
708 """ 709 Return whether Python3 is interpreting this code. 710 """ 711 return sys.hexversion >= 0x3000000
712
713 -def const_set_nice_level(nice_level = 0):
714 """ 715 Change current process scheduler "nice" level. 716 717 @param nice_level: new valid nice level 718 @type nice_level: int 719 @rtype: int 720 @return: current_nice new nice level 721 """ 722 default_nice = etpConst['default_nice'] 723 current_nice = etpConst['current_nice'] 724 delta = current_nice - default_nice 725 try: 726 etpConst['current_nice'] = os.nice(delta*-1+nice_level) 727 except OSError: 728 pass 729 return current_nice
730
731 -def const_read_entropy_release():
732 """ 733 Read Entropy release file content and fill etpConst['entropyversion'] 734 735 @rtype: None 736 @return: None 737 """ 738 # handle Entropy Version 739 revision_file = "../lib/entropy/revision" 740 if not os.path.isfile(revision_file): 741 revision_file = os.path.join(etpConst['installdir'], 742 'lib/entropy/revision') 743 744 try: 745 with codecs.open(revision_file, "r", encoding=ENCODING) as rev_f: 746 myrev = rev_f.readline().strip() 747 etpConst['entropyversion'] = myrev 748 except (OSError, IOError) as err: 749 if err.errno != errno.ENOENT: 750 raise
751
752 -def const_pid_exists(pid):
753 """ 754 Determine whether given pid exists. 755 756 @param pid: process id 757 @type pid: int 758 @return: pid exists? 1; pid does not exist? 0 759 @rtype: int 760 """ 761 try: 762 os.kill(pid, signal.SIG_DFL) 763 return 1 764 except OverflowError: 765 # pid is invalid int, signed integer is greater than maximum 766 return 0 767 except OSError as err: 768 return err.errno == errno.EPERM
769
770 -def const_secure_config_file(config_file):
771 """ 772 Setup entropy file needing strict permissions, no world readable. 773 774 @param config_file: valid config file path 775 @type config_file: string 776 @rtype: None 777 @return: None 778 """ 779 try: 780 mygid = const_get_entropy_gid() 781 except KeyError: 782 mygid = 0 783 try: 784 const_setup_file(config_file, mygid, 0o660) 785 except (OSError, IOError,): 786 pass
787
788 -def const_drop_privileges(unpriv_uid = None, unpriv_gid = None):
789 """ 790 This function does its best to drop process privileges. If it fails, an 791 exception is raised. You can consider this function security-safe. 792 793 @param unpriv_uid: override default unprivileged uid 794 @type unpriv_uid: int 795 @param unpriv_gid: override default unprivileged gid 796 @type unpriv_gid: int 797 @raise entropy.exceptions.SecurityError: if unprivileged uid/gid cannot 798 be retrieived. 799 @raise ValueError: if program is already running as unprivileged user, 800 but this differs from the usual entropy unprivileged user. 801 @raise OSError: if privileges can't be dropped, the underlying syscall 802 fails. 803 @todo: when Python 2.7, see os.setresuid() 804 """ 805 cur_uid = os.getuid() 806 807 if unpriv_uid is None: 808 unpriv_uid = const_get_lazy_nopriv_uid() 809 if unpriv_gid is None: 810 unpriv_gid = const_get_lazy_nopriv_gid() 811 812 if cur_uid in (unpriv_uid, etpConst['sysuser_nopriv_fallback']): 813 # already unprivileged 814 return 815 elif cur_uid != 0: 816 raise ValueError("already running as another unprivileged user") 817 818 # privileges can be dropped 819 os.setregid(unpriv_gid, 0) 820 os.setreuid(unpriv_uid, 0) # real uid, effective uid 821 822 # make sure 823 if os.getuid() != unpriv_uid: 824 raise OSError("privileges (uid) have not been dropped") 825 if os.getgid() != unpriv_gid: 826 raise OSError("privileges (gid) have not been dropped") 827 828 etpConst['uid'] = unpriv_uid
829
830 -def const_regain_privileges():
831 """ 832 This function should be called if, and only if, a previous 833 const_drop_privileges() has been called. It makes the program able to 834 get back privileges that were dropped previously. 835 836 @raise entropy.exceptions.SecurityError: if unprivileged uid/gid cannot 837 be retrieived. 838 @todo: when Python 2.7, see os.getresuid() 839 """ 840 cur_uid = os.getuid() 841 842 if cur_uid == 0: 843 # already running privileged 844 return 845 846 # privileges can be dropped 847 # set like this, otherwise we won't get back all our privs! 848 os.setreuid(0, 0) # real uid, effective uid 849 os.setregid(0, 0) 850 851 # make sure 852 if os.getuid() != 0: 853 raise OSError("privileges (uid) have not been dropped") 854 if os.getgid() != 0: 855 raise OSError("privileges (gid) have not been dropped") 856 857 etpConst['uid'] = 0
858
859 -def const_setup_run_directory():
860 """ 861 Setup the Entropy /run directory with appropriate permissions. 862 """ 863 const_setup_directory(etpConst['entropyrundir'])
864
865 -def const_create_working_dirs():
866 """ 867 Setup Entropy directory structure, as much automagically as possible. 868 869 @rtype: None 870 @return: None 871 """ 872 # create group if it doesn't exist 873 gid = None 874 try: 875 gid = const_get_entropy_gid() 876 except KeyError: 877 if etpConst['uid'] == 0: 878 _const_add_entropy_group(etpConst['sysgroup']) 879 try: 880 gid = const_get_entropy_gid() 881 except KeyError: 882 pass 883 884 # create unprivileged entropy-nopriv group 885 nopriv_gid = None 886 try: 887 nopriv_gid = const_get_entropy_nopriv_gid() 888 except KeyError: 889 if etpConst['uid'] == 0: 890 _const_add_entropy_group(etpConst['sysgroup_nopriv']) 891 try: 892 nopriv_gid = const_get_entropy_nopriv_gid() 893 except KeyError: 894 pass 895 896 if gid is not None: 897 etpConst['entropygid'] = gid 898 if nopriv_gid is not None: 899 etpConst['entropygid_nopriv'] = nopriv_gid 900 901 try: 902 const_setup_run_directory() 903 except (OSError, IOError): 904 # best effort 905 pass
906
907 -def const_convert_log_level(entropy_log_level):
908 """ 909 Converts Entropy log levels (0, 1, 2) to logging.ERROR, logging.INFO, 910 logging.DEBUG. 911 912 @param entropy_log_level: entropy log level id (0, 1, 2), bogus values are 913 return logging.DEBUG 914 @type entropy_log_level: int 915 @return: logging.{ERROR,INFO,DEBUG} value 916 @rtype: int 917 """ 918 import logging 919 log_map = { 920 0: logging.ERROR, 921 1: logging.INFO, 922 2: logging.DEBUG 923 } 924 return log_map.get(entropy_log_level, logging.INFO)
925
926 -def const_setup_perms(mydir, gid, f_perms = None, recursion = True, uid = -1):
927 """ 928 Setup permissions and group id (GID) to a directory, recursively. 929 930 @param mydir: valid file path 931 @type mydir: string 932 @param gid: valid group id (GID) 933 @type gid: int 934 @keyword f_perms: file permissions in octal type 935 @type f_perms: octal 936 @keyword recursion: set permissions recursively? 937 @type recursion: bool 938 @keyword uid: usually this argument shouldn't be used, but in cae 939 it sets the uid to the file 940 @type uid: int 941 @rtype: None 942 @return: None 943 """ 944 945 if gid == None: 946 return 947 if f_perms is None: 948 f_perms = 0o664 949 950 def do_setup_dir(currentdir): 951 try: 952 cur_gid = os.stat(currentdir)[stat.ST_GID] 953 if cur_gid != gid: 954 os.chown(currentdir, uid, gid) 955 cur_mod = const_get_chmod(currentdir) 956 if cur_mod != oct(0o775): 957 os.chmod(currentdir, 0o775) 958 except OSError: 959 pass
960 961 do_setup_dir(mydir) 962 if recursion: 963 for currentdir, subdirs, files in os.walk(mydir): 964 do_setup_dir(currentdir) 965 for item in files: 966 item = os.path.join(currentdir, item) 967 try: 968 const_setup_file(item, gid, f_perms, uid = uid) 969 except OSError: 970 pass 971
972 -def const_setup_file(myfile, gid, chmod, uid = -1):
973 """ 974 Setup file permissions and group id (GID). 975 976 @param myfile: valid file path 977 @type myfile: string 978 @param gid: valid group id (GID) 979 @type gid: int 980 @param chmod: permissions 981 @type chmod: integer representing an octal 982 @keyword uid: usually this argument shouldn't be used, but in cae 983 it sets the uid to the file 984 @type uid: int 985 """ 986 cur_gid = os.stat(myfile)[stat.ST_GID] 987 if cur_gid != gid: 988 os.chown(myfile, uid, gid) 989 const_set_chmod(myfile, chmod)
990
991 -def const_setup_directory(dirpath):
992 """ 993 Setup Entropy directory, creating it if required, changing 994 ownership and permissions as well. 995 996 @param dirpath: path to entropy directory 997 @type dirpath: string 998 @raise OSError: if permissions are fucked up 999 """ 1000 try: 1001 os.makedirs(dirpath, 0o775) 1002 except OSError as err: 1003 if err.errno != errno.EEXIST: 1004 raise 1005 const_setup_perms(dirpath, etpConst['entropygid'], 1006 recursion=False)
1007
1008 -def const_mkdtemp(dir=None, prefix=None, suffix=None):
1009 """ 1010 mkdtemp() wrapper that creates a temporary directory inside 1011 etpConst['entropyunpackdir'] if dir is None. 1012 1013 @keyword dir: TMPDIR 1014 @type dir: string 1015 @keyword prefix: the mkdtemp prefix argument 1016 @type prefix: string 1017 @keyword suffix: the mkdtemp suffix argument 1018 @type suffix: string 1019 @rtype: string 1020 @return: the temporary directory path 1021 """ 1022 if dir is None: 1023 dir = etpConst['entropyunpackdir'] 1024 # try creating it only if it's our provided dir 1025 try: 1026 os.makedirs(dir) 1027 except OSError as err: 1028 if err.errno != errno.EEXIST: 1029 dir = os.getenv("TMPDIR", "/var/tmp") 1030 1031 if prefix is None: 1032 prefix = "" 1033 if suffix is None: 1034 suffix = "" 1035 return tempfile.mkdtemp(dir=dir, prefix=prefix, suffix=suffix)
1036
1037 -def const_mkstemp(dir=None, prefix=None, suffix=None):
1038 """ 1039 mkstemp() wrapper that creates a temporary file inside 1040 etpConst['entropyunpackdir'] if dir is None. 1041 1042 @keyword dir: TMPDIR 1043 @type dir: string 1044 @keyword prefix: the mkdtemp prefix argument 1045 @type prefix: string 1046 @keyword suffix: the mkdtemp suffix argument 1047 @type suffix: string 1048 @rtype: tuple 1049 @return: the temporary file fd and path tuple 1050 """ 1051 if dir is None: 1052 dir = etpConst['entropyunpackdir'] 1053 # try creating it only if it's our provided dir 1054 try: 1055 os.makedirs(dir) 1056 except OSError as err: 1057 if err.errno != errno.EEXIST: 1058 dir = os.getenv("TMPDIR", "/var/tmp") 1059 1060 if prefix is None: 1061 prefix = "" 1062 if suffix is None: 1063 suffix = "" 1064 return tempfile.mkstemp(dir=dir, prefix=prefix, suffix=suffix)
1065
1066 -def const_get_chmod(myfile):
1067 """ 1068 This function get the current permissions of the specified 1069 file. If you want to use the returning value with const_set_chmod 1070 you need to convert it back to int. 1071 1072 @param myfile: valid file path 1073 @type myfile: string 1074 @rtype: integer(8) (octal) 1075 @return: octal representing permissions 1076 """ 1077 myst = os.stat(myfile)[stat.ST_MODE] 1078 return oct(myst & 0o777)
1079
1080 -def const_set_chmod(myfile, chmod):
1081 """ 1082 This function sets specified permissions to a file. 1083 If they differ from the current ones. 1084 1085 @param myfile: valid file path 1086 @type myfile: string 1087 @param chmod: permissions 1088 @type chmod: integer representing an octal 1089 @rtype: None 1090 @return: None 1091 """ 1092 cur_mod = const_get_chmod(myfile) 1093 if cur_mod != oct(chmod): 1094 os.chmod(myfile, chmod)
1095
1096 -def _const_file_something(path, flags):
1097 """ 1098 Return whether file can be opened and is a regular one. 1099 1100 @param path: path to a file 1101 @type path: string 1102 @param flags: os.open() flags 1103 @type flags: int 1104 @return: True, if file exists and is readable 1105 @rtype: bool 1106 """ 1107 fd = None 1108 try: 1109 fd = os.open(path, flags) 1110 mode = os.fstat(fd).st_mode 1111 if stat.S_ISREG(mode): 1112 # this also handles symlinks to files 1113 # because we don't use O_NOFOLLOW 1114 return True 1115 return False 1116 except (OSError, IOError): 1117 return False 1118 finally: 1119 if fd is not None: 1120 os.close(fd)
1121
1122 -def const_file_readable(path):
1123 """ 1124 Return whether path points to a readable file. 1125 1126 @param path: path to a file 1127 @type path: string 1128 @return: True, if file exists and is readable 1129 @rtype: bool 1130 """ 1131 return _const_file_something(path, os.O_RDONLY)
1132
1133 -def const_file_writable(path):
1134 """ 1135 Return whether path points to a writable file. 1136 1137 @param path: path to a file 1138 @type path: string 1139 @return: True, if file exists and is writable 1140 @rtype: bool 1141 """ 1142 return _const_file_something(path, os.O_APPEND)
1143
1144 -def _const_dir_something(path, flags):
1145 """ 1146 Return whether dir can be opened and is a directory. 1147 1148 @param path: path to a directory 1149 @type path: string 1150 @param flags: os.open() flags 1151 @type flags: int 1152 @return: True, if directory exists and can be opened with 1153 the given flags 1154 @rtype: bool 1155 """ 1156 fd = None 1157 try: 1158 fd = os.open(path, flags) 1159 mode = os.fstat(fd).st_mode 1160 if stat.S_ISDIR(mode): 1161 # this also handles symlinks to files 1162 # because we don't use O_NOFOLLOW 1163 return True 1164 return False 1165 except (OSError, IOError): 1166 return False 1167 finally: 1168 if fd is not None: 1169 os.close(fd)
1170
1171 -def const_dir_readable(dir_path):
1172 """ 1173 Return whether path points to a readable directory. 1174 Readable directory is one that you can read the content. 1175 1176 @param path: path to a directory 1177 @type path: string 1178 @return: True, if directory exists and is readable 1179 @rtype: bool 1180 """ 1181 return _const_dir_something(dir_path, os.O_RDONLY)
1182
1183 -def const_dir_writable(dir_path):
1184 """ 1185 Return whether path points to a writable directory. 1186 1187 @param path: path to a directory 1188 @type path: string 1189 @return: True, if directory exists and is writable 1190 @rtype: bool 1191 """ 1192 return _const_dir_something(dir_path, os.O_APPEND)
1193
1194 -def const_get_entropy_gid():
1195 """ 1196 This function tries to retrieve the "entropy" user group 1197 GID. 1198 1199 @rtype: int 1200 @return: entropy group id 1201 @raise KeyError: when "entropy" system GID is not available 1202 """ 1203 return int(grp.getgrnam(etpConst['sysgroup']).gr_gid)
1204
1205 -def const_get_entropy_nopriv_gid():
1206 """ 1207 This function tries to retrieve the "entropy-nopriv" user group 1208 GID. This is the unprivileged entropy users group. 1209 1210 @rtype: int 1211 @return: entropy-nopriv group id 1212 @raise KeyError: when "entropy-nopriv" system GID is not available 1213 """ 1214 return int(grp.getgrnam(etpConst['sysgroup_nopriv']).gr_gid)
1215
1216 -def const_get_entropy_nopriv_uid():
1217 """ 1218 This function tries to retrieve the "entropy-nopriv" user id (uid). 1219 1220 @rtype: int 1221 @return: entropy-nopriv user id 1222 @raise KeyError: when "entropy-nopriv" system UID is not available 1223 """ 1224 return int(pwd.getpwnam(etpConst['sysuser_nopriv']).pw_uid)
1225
1226 -def const_get_fallback_nopriv_uid():
1227 """ 1228 Fallback function that tries to retrieve the "nobody" user id (uid). 1229 It is used when const_get_entropy_nopriv_uid() fails. 1230 1231 @rtype: int 1232 @return: nobody user id 1233 @raise KeyError: when "nobody" system UID is not available 1234 """ 1235 return int(pwd.getpwnam("nobody").pw_uid)
1236
1237 -def const_get_lazy_nopriv_uid():
1238 """ 1239 This function returns an unprivileged uid by first trying to call 1240 const_get_entropy_nopriv_uid() and then const_get_fallback_nopriv_uid() 1241 1242 @return: uid 1243 @rtype: int 1244 @raise entropy.exceptions.SecurityError: if unprivileged user id is not 1245 available. 1246 """ 1247 unpriv_uid = None 1248 try: 1249 unpriv_uid = const_get_entropy_nopriv_uid() 1250 except KeyError: 1251 # fallback to "nobody" 1252 try: 1253 unpriv_uid = const_get_fallback_nopriv_uid() 1254 except KeyError: 1255 from entropy.exceptions import SecurityError 1256 raise SecurityError("cannot find unprivileged user") 1257 1258 return unpriv_uid
1259
1260 -def const_get_lazy_nopriv_gid():
1261 """ 1262 This function returns an unprivileged gid by first trying to call 1263 const_get_entropy_nopriv_gid() and then const_get_fallback_nopriv_gid() 1264 1265 @return: uid 1266 @rtype: int 1267 @raise entropy.exceptions.SecurityError: if unprivileged group id is not 1268 available. 1269 """ 1270 unpriv_gid = None 1271 try: 1272 unpriv_gid = const_get_entropy_nopriv_gid() 1273 except KeyError: 1274 try: 1275 unpriv_gid = const_get_fallback_nopriv_gid() 1276 except KeyError: 1277 from entropy.exceptions import SecurityError 1278 raise SecurityError("cannot find unprivileged group") 1279 1280 return unpriv_gid
1281
1282 -def const_get_fallback_nopriv_gid():
1283 """ 1284 Fallback function that tries to retrieve the "nogroup" group id (gid). 1285 It is used when const_get_entropy_nopriv_gid() fails. 1286 1287 @rtype: int 1288 @return: nogroup user id 1289 @raise KeyError: when "nogroup" system GID is not available 1290 """ 1291 return grp.getgrnam("nogroup").gr_gid
1292
1293 -def _const_add_entropy_group(group_name):
1294 """ 1295 This function looks for an "entropy" user group. 1296 If not available, it tries to create one. 1297 1298 @rtype: None 1299 @return: None 1300 @raise KeyError: if ${ROOT}/etc/group is not found 1301 """ 1302 group_file = etpConst['systemroot']+'/etc/group' 1303 if not os.path.isfile(group_file): 1304 raise KeyError 1305 ids = set() 1306 1307 with codecs.open(group_file, "r", encoding=ENCODING) \ 1308 as group_f: 1309 for line in group_f.readlines(): 1310 if line and line.split(":"): 1311 try: 1312 myid = int(line.split(":")[2]) 1313 except ValueError: 1314 pass 1315 ids.add(myid) 1316 if ids: 1317 # starting from 1000, get the first free 1318 new_id = 1000 1319 while True: 1320 new_id += 1 1321 if new_id not in ids: 1322 break 1323 else: 1324 new_id = 10000 1325 1326 with codecs.open(group_file, "a", encoding=ENCODING) \ 1327 as group_fw: 1328 group_fw.seek(0, 2) 1329 app_line = "%s:x:%s:\n" % (group_name, new_id,) 1330 group_fw.write(app_line)
1331
1332 -def const_get_stringtype():
1333 """ 1334 Return generic string type for usage in isinstance(). 1335 On Python 2.x, it returns basestring while on Python 3.x it returns 1336 (str, bytes,) 1337 """ 1338 if const_is_python3(): 1339 return (str, bytes,) 1340 else: 1341 return (basestring,)
1342
1343 -def const_isstring(obj):
1344 """ 1345 Return whether obj is a string (unicode or raw). 1346 1347 @param obj: Python object 1348 @type obj: Python object 1349 @return: True, if object is string 1350 @rtype: bool 1351 """ 1352 if const_is_python3(): 1353 return isinstance(obj, (str, bytes)) 1354 else: 1355 return isinstance(obj, basestring)
1356
1357 -def const_isunicode(obj):
1358 """ 1359 Return whether obj is a unicode. 1360 1361 @param obj: Python object 1362 @type obj: Python object 1363 @return: True, if object is unicode 1364 @rtype: bool 1365 """ 1366 if const_is_python3(): 1367 return isinstance(obj, str) 1368 else: 1369 return isinstance(obj, unicode)
1370
1371 -def const_israwstring(obj):
1372 if const_is_python3(): 1373 return isinstance(obj, bytes) 1374 else: 1375 return isinstance(obj, str)
1376
1377 -def const_convert_to_unicode(obj, enctype = RAW_ENCODING):
1378 """ 1379 Convert generic string to unicode format, this function supports both 1380 Python 2.x and Python 3.x unicode bullshit. 1381 1382 @param obj: generic string object 1383 @type obj: string 1384 @return: unicode string object 1385 @rtype: unicode object 1386 """ 1387 1388 # None support 1389 if obj is None: 1390 if const_is_python3(): 1391 return "None" 1392 else: 1393 return unicode("None") 1394 1395 if const_isnumber(obj) or isinstance(obj, float): 1396 if const_is_python3(): 1397 return str(obj) 1398 else: 1399 return unicode(obj) 1400 1401 if isinstance(obj, const_get_buffer()): 1402 if const_is_python3(): 1403 return str(obj.tobytes(), enctype) 1404 else: 1405 return unicode(obj, enctype) 1406 1407 if const_isunicode(obj): 1408 return obj 1409 1410 if hasattr(obj, 'decode'): 1411 return obj.decode(enctype) 1412 1413 if const_is_python3(): 1414 return str(obj, enctype) 1415 else: 1416 return unicode(obj, enctype)
1417
1418 -def const_convert_to_rawstring(obj, from_enctype = RAW_ENCODING):
1419 """ 1420 Convert generic string to raw string (str for Python 2.x or bytes for 1421 Python 3.x). 1422 1423 @param obj: input string 1424 @type obj: string object 1425 @keyword from_enctype: encoding which string is using 1426 @type from_enctype: string 1427 @return: raw string 1428 @rtype: bytes 1429 """ 1430 if obj is None: 1431 return const_convert_to_rawstring("None") 1432 1433 if const_isnumber(obj) or isinstance(obj, float): 1434 if const_is_python3(): 1435 return bytes(str(obj), from_enctype) 1436 return str(obj) 1437 1438 if isinstance(obj, const_get_buffer()): 1439 if const_is_python3(): 1440 return obj.tobytes() 1441 return str(obj) 1442 1443 if not const_isunicode(obj): 1444 return obj 1445 1446 return obj.encode(from_enctype)
1447
1448 -def const_get_buffer():
1449 """ 1450 Return generic buffer object (supporting both Python 2.x and Python 3.x) 1451 """ 1452 if const_is_python3(): 1453 return memoryview 1454 else: 1455 return buffer
1456
1457 -def const_get_int():
1458 """ 1459 Return generic int object (supporting both Python 2.x and Python 3.x). 1460 For Python 2.x a (long, int) tuple is returned. 1461 For Python 3.x a (int,) tuple is returned. 1462 """ 1463 if const_is_python3(): 1464 return (int,) 1465 else: 1466 return (long, int,)
1467
1468 -def const_isfileobj(obj):
1469 """ 1470 Return whether obj is a file object 1471 """ 1472 if const_is_python3(): 1473 import io 1474 return isinstance(obj, io.IOBase) 1475 else: 1476 return isinstance(obj, file)
1477
1478 -def const_isnumber(obj):
1479 """ 1480 Return whether obj is an int, long object. 1481 """ 1482 if const_is_python3(): 1483 return isinstance(obj, int) 1484 else: 1485 return isinstance(obj, (int, long,))
1486
1487 -def const_cmp(a, b):
1488 """ 1489 cmp() is gone in Python 3.x provide our own implementation. 1490 """ 1491 return (a > b) - (a < b)
1492 1493 _CMDLINE = None
1494 -def const_islive():
1495 """ 1496 Live environments (Operating System running off a CD/DVD) 1497 must feature the "cdroot" parameter in kernel /proc/cmdline 1498 1499 Sample code: 1500 >>> from entropy.const import const_islive 1501 >>> const_islive() 1502 False 1503 1504 @rtype: bool 1505 @return: determine wether this is a Live system or not 1506 """ 1507 global _CMDLINE 1508 if _CMDLINE is None: 1509 try: 1510 with codecs.open("/proc/cmdline", "r", encoding=ENCODING) \ 1511 as cmdline_f: 1512 _CMDLINE = cmdline_f.readline().strip().split() 1513 except IOError as err: 1514 if err.errno not in (errno.EPERM, errno.ENOENT): 1515 raise 1516 _CMDLINE = [] 1517 return "cdroot" in _CMDLINE
1518
1519 -def const_kill_threads(wait_seconds = 120.0):
1520 """ 1521 Entropy threads killer. Even if Python threads cannot 1522 be stopped or killed, TimeScheduled ones can, exporting 1523 the kill() method. 1524 1525 Sample code: 1526 >>> from entropy.const import const_kill_threads 1527 >>> const_kill_threads() 1528 1529 @param wait_seconds: number of seconds thread.join() should wait 1530 @type wait_seconds: int 1531 @rtype: None 1532 @return: None 1533 """ 1534 threads = threading.enumerate() 1535 for running_t in threads: 1536 # do not join current thread 1537 if running_t.getName() == 'MainThread': 1538 continue 1539 if hasattr(running_t, 'kill'): 1540 running_t.kill() 1541 if thread.get_ident() == running_t.ident: 1542 # do not try to kill myself 1543 continue 1544 if running_t.daemon: 1545 # will be killed by the VM 1546 continue 1547 running_t.join(wait_seconds) # wait n seconds?
1548
1549 -def __const_handle_exception(etype, value, t_back):
1550 """ 1551 Our default Python exception handler. It kills 1552 all the threads generated by Entropy before 1553 raising exceptions. Overloads sys.excepthook, 1554 internal function !! 1555 1556 @param etype: exception type 1557 @type etype: exception type 1558 @param value: exception data 1559 @type value: string 1560 @param t_back: traceback object? 1561 @type t_back: Python traceback object 1562 @rtype: default Python exceptions hook 1563 @return: sys.__excepthook__ 1564 """ 1565 try: 1566 const_kill_threads() 1567 except (AttributeError, ImportError, TypeError,): 1568 pass 1569 return sys.__excepthook__(etype, value, t_back)
1570
1571 -def const_debug_enabled():
1572 """ 1573 Return whether debug is enabled. 1574 1575 @return: True, if debug is enabled 1576 @rtype: bool 1577 """ 1578 return _DEBUG
1579 1580 _DEBUG_W_LOCK = threading.Lock()
1581 -def const_debug_write(identifier, msg, force = False, stdout=None):
1582 """ 1583 Entropy debugging output write functions. 1584 1585 @param identifier: debug identifier 1586 @type identifier: string 1587 @param msg: debugging message 1588 @type msg: string 1589 @keyword force: force print even if debug mode is off 1590 @type force: bool 1591 @keyword stdout: provide an alternative stdout file object 1592 @type stdout: file object or None 1593 @rtype: None 1594 @return: None 1595 """ 1596 if const_debug_enabled() or force: 1597 if stdout is None: 1598 stdout = sys.stdout 1599 # XXX: hierarchy violation, but hey, we're debugging shit 1600 from entropy.output import brown, purple, teal, darkgreen, darkred 1601 current_thread = threading.current_thread() 1602 th_identifier = "[id:%s, name:%s, daemon:%s, ts:%s] %s" % ( 1603 brown(repr(current_thread.ident)), 1604 purple(repr(current_thread.name)), 1605 teal(repr(current_thread.daemon)), darkgreen(repr(time.time())), 1606 darkred(identifier),) 1607 with _DEBUG_W_LOCK: 1608 if const_is_python3(): 1609 stdout.buffer.write( 1610 const_convert_to_rawstring(th_identifier) + \ 1611 b" " + const_convert_to_rawstring(msg) + b"\n") 1612 else: 1613 stdout.write("%s: %s" % (th_identifier, msg + "\n")) 1614 stdout.flush()
1615
1616 -def const_get_caller():
1617 """ 1618 When called inside a function, return the caller function name. 1619 1620 @return: caller function name 1621 @rtype: string 1622 """ 1623 import inspect 1624 stack = inspect.stack() 1625 try: 1626 func = stack[3][3] 1627 if func != "<module>": 1628 return func 1629 raise IndexError("module wtf?") 1630 except IndexError: 1631 return stack[2][3]
1632
1633 -def const_get_stack():
1634 """ 1635 Return current function stack in form of list of tuples 1636 1637 @return: current function stack 1638 @rtype: list 1639 """ 1640 import inspect 1641 return inspect.stack()
1642
1643 -def const_get_cpus():
1644 """ 1645 Return the number of CPUs/Cores the Operating system exposes 1646 1647 @return: number of CPUs/Cores available 1648 @rtype: int 1649 """ 1650 import multiprocessing 1651 return multiprocessing.cpu_count()
1652 1653 # load config 1654 initconfig_entropy_constants(etpSys['rootdir']) 1655 1656 # Debug Watchdog support. If enabled, a thread dump 1657 # will be pushed to stderr every ETP_DEBUG_WATCHDOG_INTERVAL 1658 # seconds (or 60 seconds if unset). 1659 _debug_watchdog = os.getenv("ETP_DEBUG_WATCHDOG") 1660 if _debug_watchdog is not None: 1661 from threading import Timer 1662 _default_debug_watchdog_interval = 60 1663 _debug_watchdog_interval = os.getenv( 1664 "ETP_DEBUG_WATCHDOG_INTERVAL", 1665 _default_debug_watchdog_interval) 1666 try: 1667 _debug_watchdog_interval = int(_debug_watchdog_interval) 1668 except (ValueError, TypeError): 1669 _debug_watchdog_interval = _default_debug_watchdog_interval 1670 1671 const_debug_write( 1672 __name__, 1673 "DebugWatchdogTimer enabled, interval: %d" % ( 1674 _debug_watchdog_interval,)) 1675
1676 - def _dumper():
1677 dump_signal(None, None) 1678 _setup_timer()
1679
1680 - def _setup_timer():
1681 _timer = Timer(_debug_watchdog_interval, _dumper) 1682 _timer.name = "DebugWatchdogTimer" 1683 _timer.daemon = True 1684 _timer.start()
1685 _setup_timer() 1686