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