1
2 """
3
4 @author: Fabio Erculiani <lxnay@sabayonlinux.org>
5 @contact: lxnay@sabayonlinux.org
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, etpCache 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 stat
34 import errno
35 import fcntl
36 import signal
37 import gzip
38 import bz2
39 from entropy.i18n import _
40
41
42
43
44 ETP_ARCH_MAP = {
45 ("i386", "i486", "i586", "i686",): "x86",
46 ("x86_64",): "amd64",
47 ("sun4u",): None,
48 ("ppc",): None,
49 }
50 _uname_m = os.uname()[4]
51 ETP_ARCH_CONST = 'UNKNOWN'
52 for arches, arch in list(ETP_ARCH_MAP.items()):
53 if _uname_m in arches:
54 ETP_ARCH_CONST = arch
55
56 etpSys = {
57 'archs': ['alpha', 'amd64', 'amd64-fbsd', 'arm', 'hppa', 'ia64', 'm68k',
58 'mips', 'ppc', 'ppc64', 's390', 'sh', 'sparc', 'sparc-fbsd', 'x86',
59 'x86-fbsd'],
60 'keywords': set([ETP_ARCH_CONST, "~"+ETP_ARCH_CONST]),
61 'api': '3',
62 'arch': ETP_ARCH_CONST,
63 'rootdir': "",
64 'serverside': False,
65 'unittest': False,
66 }
67
68 etpUi = {
69 'debug': False,
70 'quiet': False,
71 'verbose': False,
72 'ask': False,
73 'pretend': False,
74 'mute': False,
75 'nolog': False,
76 'clean': False,
77 'warn': True,
78 }
79 if ("--debug" in sys.argv) or os.getenv("ETP_DEBUG"):
80 etpUi['debug'] = True
81 if os.getenv('ETP_MUTE'):
82 etpUi['mute'] = True
83
84
85 ETP_LOGLEVEL_NORMAL = 1
86 ETP_LOGLEVEL_VERBOSE = 2
87 ETP_LOGPRI_INFO = "[ INFO ]"
88 ETP_LOGPRI_WARNING = "[ WARNING ]"
89 ETP_LOGPRI_ERROR = "[ ERROR ]"
90
91
92 etpCache = {
93
94
95 'configfiles': 'conf/scanfs',
96 'dbMatch': 'match/db',
97 'dbSearch': 'search/db',
98
99 'atomMatch': 'atom_match/atom_match_',
100 'install': 'resume/resume_install',
101 'remove': 'resume/resume_remove',
102 'world': 'resume/resume_world',
103 'world_update': 'world_update/world_cache_',
104 'critical_update': 'critical_update/critical_cache_',
105 'world_available': 'world_available/available_cache_',
106 'check_package_update': 'check_update/package_update_',
107 'advisories': 'security/advisories_cache_',
108 'dep_tree': 'deptree/dep_tree_',
109 'depends_tree': 'depends/depends_tree_',
110 'filter_satisfied_deps': 'depfilter/filter_satisfied_deps_',
111 'library_breakage': 'libs_break/library_breakage_',
112 'repolist': 'repos/repolist',
113 'repository_server': 'reposerver/item',
114 'eapi3_fetch': 'eapi3/segment_',
115 'ugc_votes': 'ugc/ugc_votes',
116 'ugc_downloads': 'ugc/ugc_downloads',
117 'ugc_docs': 'ugc/ugc_docs',
118 'ugc_srv_cache': 'ugc/ugc_srv_cache'
119 }
120
121 etpConst = {}
122
124
125 """
126 Main constants configurators, this is the only function that you should
127 call from the outside, anytime you want. it will reset all the variables
128 excluding those backed up previously.
129
130 @param rootdir: current root directory, if any, or ""
131 @type rootdir: string
132 @rtype: None
133 @return: None
134 @raise AttributeError: when specified rootdir is not a directory
135 """
136
137 if rootdir and not os.path.isdir(rootdir):
138 raise AttributeError("not a valid chroot.")
139
140
141
142 os.environ['ROOT'] = rootdir + os.path.sep
143
144
145 if 'backed_up' in etpConst:
146 backed_up_settings = etpConst.pop('backed_up')
147 else:
148 backed_up_settings = {}
149
150 const_default_settings(rootdir)
151 const_read_entropy_release()
152 const_create_working_dirs()
153 const_setup_entropy_pid()
154 const_configure_lock_paths()
155
156
157 etpConst.update(backed_up_settings)
158 etpConst['backed_up'] = backed_up_settings.copy()
159
160 if sys.excepthook is sys.__excepthook__:
161 sys.excepthook = __const_handle_exception
162
164
165 """
166 Initialization of all the Entropy base settings.
167
168 @param rootdir: current root directory, if any, or ""
169 @type rootdir: string
170 @rtype: None
171 @return: None
172 """
173
174 default_etp_dir = os.getenv('DEV_ETP_VAR_DIR', rootdir+"/var/lib/entropy")
175 default_etp_tmpdir = "/tmp"
176 default_etp_repodir = "/packages/"+ETP_ARCH_CONST
177 default_etp_portdir = rootdir+"/usr/portage"
178 default_etp_distfilesdir = "/distfiles"
179 default_etp_dbdir = "/database/"+ETP_ARCH_CONST
180 default_etp_dbfile = "packages.db"
181 default_etp_dbclientfile = "equo.db"
182 default_etp_client_repodir = "/client"
183 default_etp_triggersdir = "/triggers/"+ETP_ARCH_CONST
184 default_etp_smartappsdir = "/smartapps/"+ETP_ARCH_CONST
185 default_etp_smartpackagesdir = "/smartpackages/"+ETP_ARCH_CONST
186 default_etp_cachesdir = "/caches/"
187 default_etp_securitydir = "/glsa/"
188 default_etp_setsdirname = "sets"
189 default_etp_setsdir = "/%s/" % (default_etp_setsdirname,)
190 default_etp_logdir = default_etp_dir+"/"+"logs"
191 default_etp_confdir = os.getenv('DEV_ETP_ETC_DIR', rootdir+"/etc/entropy")
192 default_etp_packagesdir = default_etp_confdir+"/packages"
193 default_etp_ugc_confdir = default_etp_confdir+"/ugc"
194 default_etp_syslogdir = os.getenv('DEV_ETP_LOG_DIR',
195 rootdir+"/var/log/entropy/")
196 default_etp_vardir = os.getenv('DEV_ETP_TMP_DIR',
197 rootdir+"/var/tmp/entropy")
198
199 cmdline = []
200 cmdline_file = "/proc/cmdline"
201 if os.access(cmdline_file, os.R_OK) and os.path.isfile(cmdline_file):
202 with open(cmdline_file, "r") as cmdline_f:
203 cmdline = cmdline_f.readline().strip().split()
204
205 etpConst.clear()
206 my_const = {
207 'server_repositories': {},
208 'community': {
209 'mode': False,
210 },
211 'cmdline': cmdline,
212 'backed_up': {},
213
214 'installdir': '/usr/lib/entropy',
215
216 'packagestmpdir': default_etp_dir+default_etp_tmpdir,
217
218
219
220
221
222 'packagesbindir': default_etp_dir+default_etp_repodir,
223
224 'smartappsdir': default_etp_dir+default_etp_smartappsdir,
225
226
227 'smartpackagesdir': default_etp_dir+default_etp_smartpackagesdir,
228
229 'triggersdir': default_etp_dir+default_etp_triggersdir,
230
231 'portagetreedir': default_etp_portdir,
232
233 'distfilesdir': default_etp_portdir+default_etp_distfilesdir,
234
235 'confdir': default_etp_confdir,
236
237 'confrepokeysdir': default_etp_confdir + "/rkeys",
238
239 'confpackagesdir': default_etp_packagesdir,
240
241 'confsetsdir': default_etp_packagesdir+default_etp_setsdir,
242
243 'confsetsdirname': default_etp_setsdirname,
244
245 'entropyconf': default_etp_confdir+"/entropy.conf",
246
247 'repositoriesconf': default_etp_confdir+"/repositories.conf",
248
249 'serverconf': default_etp_confdir+"/server.conf",
250
251 'clientconf': default_etp_confdir+"/client.conf",
252
253 'socketconf': default_etp_confdir+"/socket.conf",
254
255 'packagesrelativepath': "packages/"+ETP_ARCH_CONST+"/",
256
257 'entropyworkdir': default_etp_dir,
258
259 'entropyunpackdir': default_etp_vardir,
260
261 'entropyimagerelativepath': "image",
262
263 'entropyxpakrelativepath': "xpak",
264
265 'entropyxpakdatarelativepath': "data",
266
267 'entropyxpakfilename': "metadata.xpak",
268
269
270 'etpdatabasetimestampfile': default_etp_dbfile+".timestamp",
271
272 'etpdatabasepkglist': default_etp_dbfile+".pkglist",
273 'etpdatabaseconflictingtaggedfile': default_etp_dbfile + \
274 ".conflicting_tagged",
275
276
277 'etpdatabasesytemmaskfile': default_etp_dbfile+".system_mask",
278 'etpdatabasemaskfile': default_etp_dbfile+".mask",
279 'etpdatabasekeywordsfile': default_etp_dbfile+".keywords",
280 'etpdatabaseupdatefile': default_etp_dbfile+".repo_updates",
281 'etpdatabaselicwhitelistfile': default_etp_dbfile+".lic_whitelist",
282 'etpdatabasecriticalfile': default_etp_dbfile+".critical",
283
284 'etpdatabaserevisionfile': default_etp_dbfile+".revision",
285
286 'etpdatabasemissingdepsblfile': default_etp_dbfile + \
287 ".missing_deps_blacklist",
288
289
290 'etpdatabasemetafilesfile': default_etp_dbfile+".meta",
291
292
293 'etpdatabasemetafilesnotfound': default_etp_dbfile+".meta_notfound",
294 'etpdatabasehashfile': default_etp_dbfile+".md5",
295
296
297
298 'etpdatabaselockfile': default_etp_dbfile+".lock",
299
300 'etpdatabaseeapi3lockfile': default_etp_dbfile+".eapi3_lock",
301
302 'etpdatabasedownloadlockfile': default_etp_dbfile+".download.lock",
303 'etpdatabasecacertfile': "ca.cert",
304 'etpdatabaseservercertfile': "server.cert",
305
306
307 'etpdatabasetaintfile': default_etp_dbfile+".tainted",
308
309
310
311 'etpdatabasefile': default_etp_dbfile,
312
313 'etpdatabasefilegzip': default_etp_dbfile+".gz",
314
315 'etpdatabasefilebzip2': default_etp_dbfile+".bz2",
316
317
318 'etpdatabasefilegziplight': default_etp_dbfile+".light.gz",
319 'etpdatabasefilehashgziplight': default_etp_dbfile+".light.gz.md5",
320
321 'etpdatabasefilebzip2light': default_etp_dbfile+".light.bz2",
322 'etpdatabasefilehashbzip2light': default_etp_dbfile+".light.bz2.md5",
323
324
325 'etpdatabasedumpbzip2': default_etp_dbfile+".dump.bz2",
326 'etpdatabasedumphashfilebz2': default_etp_dbfile+".dump.bz2.md5",
327
328 'etpdatabasedumpgzip': default_etp_dbfile+".dump.gz",
329 'etpdatabasedumphashfilegzip': default_etp_dbfile+".dump.gz.md5",
330
331
332 'etpdatabasedump': default_etp_dbfile+".dump",
333
334
335 'etpdatabasedumplightbzip2': default_etp_dbfile+".dumplight.bz2",
336
337 'etpdatabasedumplightgzip': default_etp_dbfile+".dumplight.gz",
338
339 'etpdatabasedumplighthashfilebz2': default_etp_dbfile+".dumplight.bz2.md5",
340 'etpdatabasedumplighthashfilegzip': default_etp_dbfile+".dumplight.gz.md5",
341 'etpdatabasedumplight': default_etp_dbfile+".dumplight",
342
343
344 'etpdatabaseexpbasedpkgsrm': default_etp_dbfile+".fatscope",
345
346
347 'etpdatabasefileformat': "bz2",
348
349 'etpdatabasesupportedcformats': ["bz2", "gz"],
350 'etpdatabasecompressclasses': {
351 "bz2": (bz2.BZ2File, "unpack_bzip2", "etpdatabasefilebzip2",
352 "etpdatabasedumpbzip2", "etpdatabasedumphashfilebz2",
353 "etpdatabasedumplightbzip2", "etpdatabasedumplighthashfilebz2",
354 "etpdatabasefilebzip2light", "etpdatabasefilehashbzip2light",),
355 "gz": (gzip.GzipFile, "unpack_gzip", "etpdatabasefilegzip",
356 "etpdatabasedumpgzip", "etpdatabasedumphashfilegzip",
357 "etpdatabasedumplightgzip", "etpdatabasedumplighthashfilegzip",
358 "etpdatabasefilegziplight", "etpdatabasefilehashgziplight",)
359 },
360
361 'rss-feed': True,
362
363 'rss-name': "packages.rss",
364 'rss-light-name': "updates.rss",
365
366
367 'rss-base-url': "http://packages.sabayonlinux.org/",
368
369
370 'rss-website-url': "http://www.sabayonlinux.org/",
371
372 'rss-dump-name': "rss_database_actions",
373 'rss-max-entries': 10000,
374 'rss-light-max-entries': 300,
375 'rss-managing-editor': "lxnay@sabayonlinux.org",
376
377 'rss-notice-board': "notice.rss",
378
379 'rss-notice-board-userdata': "notice.rss.userdata",
380
381 'packagesetprefix': "@",
382 'userpackagesetsid': "__user__",
383 'setsconffilename': "sets.conf",
384 'cachedumpext': ".dmp",
385 'packagesext': ".tbz2",
386 'smartappsext': ".esa",
387
388
389 'packagesmd5fileext': ".md5",
390 'packagessha512fileext': ".sha512",
391 'packagessha256fileext': ".sha256",
392 'packagessha1fileext': ".sha1",
393
394 'packagehashes': ("sha1", "sha256", "sha512"),
395
396 'packagesexpirationfileext': ".expired",
397
398 'packagesexpirationdays': 15,
399
400
401 'triggername': "trigger",
402 'trigger_sh_interpreter': rootdir+"/usr/sbin/entropy.sh",
403
404 'etp_hw_hash_gen': rootdir+"/usr/bin/entropy_hwgen.sh",
405
406 'etp_post_branch_hop_script': default_etp_dbfile+".post_branch.sh",
407
408 'etp_post_branch_upgrade_script': default_etp_dbfile+".post_upgrade.sh",
409
410 'etp_previous_branch_file': default_etp_confdir+"/.previous_branch",
411 'etp_in_branch_upgrade_file': default_etp_confdir+"/.in_branch_upgrade",
412
413
414 'etp_post_repo_update_script': default_etp_dbfile+".post_update.sh",
415
416
417 'proxy': {
418 'ftp': os.getenv("FTP_PROXY"),
419 'http': os.getenv("HTTP_PROXY"),
420 'username': None,
421 'password': None
422 },
423
424 'entropyloglevel': 1,
425
426 'socketloglevel': 2,
427 'spmloglevel': 1,
428
429 'logdir': default_etp_logdir,
430
431 'syslogdir': default_etp_syslogdir,
432 'entropylogfile': default_etp_syslogdir+"entropy.log",
433 'equologfile': default_etp_syslogdir+"equo.log",
434 'spmlogfile': default_etp_syslogdir+"spm.log",
435 'socketlogfile': default_etp_syslogdir+"socket.log",
436
437 'etpdatabaseclientdir': default_etp_dir + default_etp_client_repodir + \
438 default_etp_dbdir,
439
440 'etpdatabaseclientfilepath': default_etp_dir + \
441 default_etp_client_repodir + default_etp_dbdir + "/" + \
442 default_etp_dbclientfile,
443
444
445 'dbnamerepoprefix': "repo_",
446
447 'dbbackupprefix': 'etp_backup_',
448
449
450 'etpapi': etpSys['api'],
451
452 'currentarch': etpSys['arch'],
453
454 'supportedarchs': etpSys['archs'],
455
456
457 'branch': "4",
458
459 'keywords': etpSys['keywords'].copy(),
460
461
462
463 'expiration_based_scope': False,
464
465 'defaultserverrepositoryid': None,
466 'officialrepositoryid': "sabayonlinux.org",
467 'conntestlink': "http://www.sabayonlinux.org",
468
469 'databasestarttag': "|ENTROPY:PROJECT:DB:MAGIC:START|",
470 'pidfile': default_etp_dir+"/entropy.lock",
471 'applicationlock': False,
472
473
474 'filesbackup': True,
475
476 'forcedupdates': True,
477
478 'collisionprotect': 1,
479
480
481 'configprotect': [],
482
483 'configprotectmask': [],
484
485
486 'configprotectskip': [],
487
488 'dbconfigprotect': [],
489
490 'dbconfigprotectmask': [],
491
492
493 'configprotectcounter': 0,
494
495 'entropyversion': "1.0",
496
497 'systemname': "Sabayon Linux",
498
499 'product': "standard",
500 'errorstatus': default_etp_confdir+"/code",
501 'systemroot': rootdir,
502 'uid': os.getuid(),
503 'entropygid': None,
504 'sysgroup': "entropy",
505 'defaultumask': 0o22,
506 'storeumask': 0o02,
507 'gentle_nice': 15,
508 'current_nice': 0,
509 'default_nice': 0,
510
511 'default_download_timeout': 20,
512
513 'dependency_type_ids': {
514 '(r)depend_id': 0,
515 'pdepend_id': 1,
516 'mdepend_id': 2,
517 },
518
519
520 'downloadspeedlimit': None,
521
522
523
524 'dumpstoragedir': default_etp_dir+default_etp_cachesdir,
525
526 'securitydir': default_etp_dir+default_etp_securitydir,
527 'securityurl': "http://community.sabayonlinux.org/security"
528 "/security-advisories.tar.bz2",
529
530 'safemodeerrors': {
531 'clientdb': 1,
532 },
533 'safemodereasons': {
534 0: _("All fine"),
535 1: _("Corrupted Client Repository. Please restore a backup."),
536 },
537
538 'misc_counters': {
539 'forced_atoms_update_ids': {
540 '__idtype__': 1,
541 'kde': 1,
542 },
543 },
544
545 'system_settings_plugins_ids': {
546 'client_plugin': "client_plugin",
547 'server_plugin': "server_plugin",
548 'server_plugin_fatscope': "server_plugin_fatscope",
549 },
550
551 'clientserverrepoid': "__system__",
552 'clientdbid': "client",
553 'serverdbid': "etpdb:",
554 'genericdbid': "generic",
555 'systemreleasefile': "/etc/sabayon-release",
556
557
558
559 'socket_service': {
560 'hostname': "localhost",
561 'port': 1026,
562 'ssl_port': 1027,
563 'timeout': 200,
564 'forked_requests_timeout': 300,
565 'max_command_length': 768000,
566 'threads': 5,
567 'session_ttl': 15,
568 'default_uid': 0,
569 'max_connections': 5,
570 'max_connections_per_host': 15,
571 'max_connections_per_host_barrier': 8,
572 'disabled_cmds': set(),
573 'ip_blacklist': set(),
574 'ssl_key': default_etp_confdir+"/socket_server.key",
575 'ssl_cert': default_etp_confdir+"/socket_server.crt",
576 'ssl_ca_cert': default_etp_confdir+"/socket_server.CA.crt",
577 'ssl_ca_pkey': default_etp_confdir+"/socket_server.CA.key",
578 'answers': {
579
580 'ok': const_convert_to_rawstring(chr(0)+"OK"+chr(0)),
581
582 'er': const_convert_to_rawstring(chr(0)+"ER"+chr(1)),
583
584 'no': const_convert_to_rawstring(chr(0)+"NO"+chr(2)),
585
586 'cl': const_convert_to_rawstring(chr(0)+"CL"+chr(3)),
587
588 'mcr': const_convert_to_rawstring(chr(0)+"MCR"+chr(4)),
589
590 'eos': const_convert_to_rawstring(chr(0)),
591
592 'noop': const_convert_to_rawstring(chr(0)+"NOOP"+chr(0)),
593 },
594 },
595
596 'install_sources': {
597 'unknown': 0,
598 'user': 1,
599 'automatic_dependency': 2,
600 },
601
602 'pkg_masking_reasons': {
603 0: _('reason not available'),
604 1: _('user package.mask'),
605 2: _('system keywords'),
606 3: _('user package.unmask'),
607 4: _('user repo package.keywords (all packages)'),
608 5: _('user repo package.keywords'),
609 6: _('user package.keywords'),
610 7: _('completely masked (by keyword?)'),
611 8: _('repository general packages.db.mask'),
612 9: _('repository general packages.db.keywords'),
613 10: _('user license.mask'),
614 11: _('user live unmask'),
615 12: _('user live mask'),
616 },
617 'pkg_masking_reference': {
618 'reason_not_avail': 0,
619 'user_package_mask': 1,
620 'system_keyword': 2,
621 'user_package_unmask': 3,
622 'user_repo_package_keywords_all': 4,
623 'user_repo_package_keywords': 5,
624 'user_package_keywords': 6,
625 'completely_masked': 7,
626 'repository_packages_db_mask': 8,
627 'repository_packages_db_keywords': 9,
628 'user_license_mask': 10,
629 'user_live_unmask': 11,
630 'user_live_mask': 12,
631 },
632
633 'ugc_doctypes': {
634 'comments': 1,
635 'bbcode_doc': 2,
636 'image': 3,
637 'generic_file': 4,
638 'youtube_video': 5,
639 },
640 'ugc_doctypes_description': {
641 1: _('Comments'),
642 2: _('BBcode Documents'),
643 3: _('Images/Screenshots'),
644 4: _('Generic Files'),
645 5: _('YouTube(tm) Videos'),
646 },
647 'ugc_doctypes_description_singular': {
648 1: _('Comment'),
649 2: _('BBcode Document'),
650 3: _('Image/Screenshot'),
651 4: _('Generic File'),
652 5: _('YouTube(tm) Video'),
653 },
654 'ugc_accessfile': default_etp_ugc_confdir+"/access.xml",
655 'ugc_voterange': list(range(1, 6)),
656
657 }
658
659
660 try:
661 my_const['current_nice'] = os.nice(0)
662 except OSError:
663 pass
664
665 etpConst.update(my_const)
666
668 """
669 Change current process scheduler "nice" level.
670
671 @param nice_level: new valid nice level
672 @type nice_level: int
673 @rtype: int
674 @return: current_nice new nice level
675 """
676 default_nice = etpConst['default_nice']
677 current_nice = etpConst['current_nice']
678 delta = current_nice - default_nice
679 try:
680 etpConst['current_nice'] = os.nice(delta*-1+nice_level)
681 except OSError:
682 pass
683 return current_nice
684
686
687 """
688 Extract repository information from the provided repository string,
689 usually contained in the repository settings file, repositories.conf.
690
691 @param repostring: valid repository identifier
692 @type repostring: string
693 @rtype: tuple (string, dict)
694 @return: tuple composed by (repository identifier, extracted repository
695 metadata)
696 """
697
698 if branch == None:
699 branch = etpConst['branch']
700 if product == None:
701 product = etpConst['product']
702
703 reponame = repostring.split("|")[1].strip()
704 repodesc = repostring.split("|")[2].strip()
705 repopackages = repostring.split("|")[3].strip()
706 repodatabase = repostring.split("|")[4].strip()
707
708 eapi3_uri = None
709 eapi3_port = int(etpConst['socket_service']['port'])
710 eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
711 eapi3_formatcolon = repodatabase.rfind("#")
712
713
714 if eapi3_formatcolon != -1:
715 try:
716 ports = repodatabase[eapi3_formatcolon+1:].split(",")
717 if ports:
718 eapi3_port = int(ports[0])
719 if len(ports) > 1:
720 eapi3_ssl_port = int(ports[1])
721 except (ValueError, IndexError,):
722 eapi3_port = int(etpConst['socket_service']['port'])
723 eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
724 repodatabase = repodatabase[:eapi3_formatcolon]
725
726
727 dbformat = etpConst['etpdatabasefileformat']
728 dbformatcolon = repodatabase.rfind("#")
729 if dbformatcolon != -1:
730 if dbformat in etpConst['etpdatabasesupportedcformats']:
731 try:
732 dbformat = repodatabase[dbformatcolon+1:]
733 except (IndexError, ValueError, TypeError,):
734 pass
735 repodatabase = repodatabase[:dbformatcolon]
736
737
738 eapi3_uricolon = repodatabase.rfind(",")
739 if eapi3_uricolon != -1:
740
741 found_eapi3_uri = repodatabase[eapi3_uricolon+1:]
742 if found_eapi3_uri:
743 eapi3_uri = found_eapi3_uri
744 repodatabase = repodatabase[:eapi3_uricolon]
745
746 mydata = {}
747 mydata['repoid'] = reponame
748 mydata['service_port'] = eapi3_port
749 mydata['ssl_service_port'] = eapi3_ssl_port
750
751 if not repodatabase.endswith("file://") and (eapi3_uri is None):
752 try:
753
754
755 eapi3_uri = repodatabase.split("/")[2]
756 except IndexError:
757 eapi3_uri = None
758 mydata['service_uri'] = eapi3_uri
759 mydata['description'] = repodesc
760 mydata['packages'] = []
761 mydata['plain_packages'] = []
762
763 mydata['dbpath'] = etpConst['etpdatabaseclientdir'] + os.path.sep + \
764 reponame + os.path.sep + product + os.path.sep + \
765 etpConst['currentarch'] + os.path.sep + branch
766
767 mydata['dbcformat'] = dbformat
768 if not dbformat in etpConst['etpdatabasesupportedcformats']:
769 mydata['dbcformat'] = etpConst['etpdatabasesupportedcformats'][0]
770
771 mydata['plain_database'] = repodatabase
772
773 mydata['database'] = repodatabase + os.path.sep + product + os.path.sep + \
774 reponame + "/database/" + etpConst['currentarch'] + \
775 os.path.sep + branch
776
777 mydata['notice_board'] = mydata['database'] + os.path.sep + \
778 etpConst['rss-notice-board']
779
780 mydata['local_notice_board'] = mydata['dbpath'] + os.path.sep + \
781 etpConst['rss-notice-board']
782
783 mydata['local_notice_board_userdata'] = mydata['dbpath'] + os.path.sep + \
784 etpConst['rss-notice-board-userdata']
785
786 mydata['dbrevision'] = "0"
787 dbrevision_file = os.path.join(mydata['dbpath'],
788 etpConst['etpdatabaserevisionfile'])
789 if os.path.isfile(dbrevision_file) and os.access(dbrevision_file, os.R_OK):
790 with open(dbrevision_file, "r") as dbrev_f:
791 mydata['dbrevision'] = dbrev_f.readline().strip()
792
793
794
795 mydata['post_branch_hop_script'] = mydata['dbpath'] + os.path.sep + \
796 etpConst['etp_post_branch_hop_script']
797 mydata['post_branch_upgrade_script'] = mydata['dbpath'] + os.path.sep + \
798 etpConst['etp_post_branch_upgrade_script']
799 mydata['post_repo_update_script'] = mydata['dbpath'] + os.path.sep + \
800 etpConst['etp_post_repo_update_script']
801
802
803
804 mydata['configprotect'] = None
805 mydata['configprotectmask'] = None
806 repopackages = [x.strip() for x in repopackages.split() if x.strip()]
807 repopackages = [x for x in repopackages if (x.startswith('http://') or \
808 x.startswith('ftp://') or x.startswith('file://'))]
809
810 for repo_package in repopackages:
811 try:
812 repo_package = str(repo_package)
813 except (UnicodeDecodeError, UnicodeEncodeError,):
814 continue
815 mydata['plain_packages'].append(repo_package)
816 mydata['packages'].append(
817 repo_package + os.path.sep + product + os.path.sep + reponame)
818
819 return reponame, mydata
820
822 """
823 Read Entropy release file content and fill etpConst['entropyversion']
824
825 @rtype: None
826 @return: None
827 """
828
829 revision_file = "../libraries/revision"
830 if not os.path.isfile(revision_file):
831 revision_file = os.path.join(etpConst['installdir'],
832 'libraries/revision')
833 if os.path.isfile(revision_file) and \
834 os.access(revision_file, os.R_OK):
835
836 with open(revision_file, "r") as rev_f:
837 myrev = rev_f.readline().strip()
838 etpConst['entropyversion'] = myrev
839
841 """
842 Determine whether given pid exists.
843
844 @param pid: process id
845 @type pid: int
846 @return: pid exists? 1; pid does not exist? 0
847 @rtype: int
848 """
849 try:
850 os.kill(pid, signal.SIG_DFL)
851 return 1
852 except OSError as err:
853 return err.errno == errno.EPERM
854
856
857 """
858 Setup Entropy pid file, if possible and if UID = 0 (root).
859 If the application is run with --no-pid-handling argument,
860 this function will have no effect. If just_read is specified,
861 this function will only try to read the current pid string in
862 the Entropy pid file (etpConst['pidfile']). If any other entropy
863 istance is currently owning the contained pid, etpConst['applicationlock']
864 becomes True.
865
866 @param just_read: only read the current pid file, if any and if possible
867 @type just_read: bool
868 @param force_handling: force pid handling even if "--no-pid-handling" is
869 given
870 @type force_handling: bool
871 @rtype: bool
872 @return: if pid lock file has been acquired
873 """
874
875 if (("--no-pid-handling" in sys.argv) and not force_handling) \
876 and not just_read:
877 return False
878
879 setup_done = False
880
881
882 pid = os.getpid()
883 pid_file = etpConst['pidfile']
884 if os.path.isfile(pid_file) and os.access(pid_file, os.R_OK):
885
886 try:
887 with open(pid_file, "r") as pid_f:
888 found_pid = str(pid_f.readline().strip())
889 except (IOError, OSError, UnicodeEncodeError, UnicodeDecodeError,):
890 found_pid = "0000"
891
892 try:
893 found_pid = int(found_pid)
894 except ValueError:
895 found_pid = 0
896
897 if found_pid != pid:
898
899 if (found_pid != 0) and const_pid_exists(found_pid):
900 etpConst['applicationlock'] = True
901 elif (not just_read) and os.access(pid_file, os.W_OK):
902 try:
903 with open(pid_file, "w") as pid_f:
904 pid_f.write(str(pid))
905 pid_f.flush()
906 except IOError as err:
907 if err.errno != 30:
908 raise
909 try:
910 const_chmod_entropy_pid()
911 except OSError:
912 pass
913 setup_done = True
914
915 elif not just_read:
916
917
918 if os.access(os.path.dirname(pid_file), os.W_OK):
919
920 if os.path.exists(pid_file):
921 if os.path.islink(pid_file):
922 os.remove(pid_file)
923 elif os.path.isdir(pid_file):
924 import shutil
925 shutil.rmtree(pid_file)
926
927 with open(pid_file, "w") as pid_fw:
928
929 try:
930 fcntl.flock(pid_fw.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
931 pid_fw.write(str(pid))
932 pid_fw.flush()
933 except IOError as err:
934
935 if err.errno not in (errno.EACCES, errno.EAGAIN,):
936 raise
937
938
939 return False
940
941 try:
942 const_chmod_entropy_pid()
943 except OSError:
944 pass
945 setup_done = True
946
947 return setup_done
948
950 """
951 Remove Entropy pid if function calling pid matches the one stored.
952 """
953 pid = os.getpid()
954 pid_file = etpConst['pidfile']
955 if not os.path.lexists(pid_file):
956 return True
957
958
959 try:
960 with open(pid_file, "r") as pid_f:
961 found_pid = str(pid_f.readline().strip())
962 except (IOError, OSError, UnicodeEncodeError, UnicodeDecodeError,):
963 found_pid = "0000"
964
965 try:
966 found_pid = int(found_pid)
967 except ValueError:
968 found_pid = 0
969
970 if (pid != found_pid) and (found_pid != 0):
971
972 return False
973
974 removed = False
975 try:
976
977 os.remove(pid_file)
978 removed = True
979 except OSError as err:
980 if err.errno not in (errno.ENOENT, errno.EACCES,):
981 raise
982
983 if err.errno == errno.EACCES:
984 removed = False
985 else:
986 removed = True
987
988 return removed
989
991 """
992 Setup entropy file needing strict permissions, no world readable.
993
994 @param config_file: valid config file path
995 @type config_file: string
996 @rtype: None
997 @return: None
998 """
999 try:
1000 mygid = const_get_entropy_gid()
1001 except KeyError:
1002 mygid = 0
1003 try:
1004 const_setup_file(config_file, mygid, 0o660)
1005 except (OSError, IOError,):
1006 pass
1007
1009 """
1010 Setup entropy pid file permissions, if possible.
1011
1012 @return: None
1013 """
1014 try:
1015 mygid = const_get_entropy_gid()
1016 except KeyError:
1017 mygid = 0
1018 const_setup_file(etpConst['pidfile'], mygid, 0o664)
1019
1021
1022 """
1023 Setup Entropy directory structure, as much automagically as possible.
1024
1025 @rtype: None
1026 @return: None
1027 """
1028
1029
1030 piddir = os.path.dirname(etpConst['pidfile'])
1031 if not os.path.exists(piddir) and (etpConst['uid'] == 0):
1032 os.makedirs(piddir)
1033
1034
1035
1036
1037
1038
1039
1040 gid = None
1041 try:
1042 gid = const_get_entropy_gid()
1043 except KeyError:
1044 if etpConst['uid'] == 0:
1045
1046
1047 const_add_entropy_group()
1048 try:
1049 gid = const_get_entropy_gid()
1050 except KeyError:
1051 pass
1052
1053
1054 keys = [x for x in etpConst if const_isstring(etpConst[x])]
1055 for key in keys:
1056
1057 if not etpConst[key] or \
1058 etpConst[key].endswith(".conf") or \
1059 not os.path.isabs(etpConst[key]) or \
1060 etpConst[key].endswith(".cfg") or \
1061 etpConst[key].endswith(".tmp") or \
1062 etpConst[key].find(".db") != -1 or \
1063 etpConst[key].find(".log") != -1 or \
1064 os.path.isdir(etpConst[key]) or \
1065 not key.endswith("dir"):
1066 continue
1067
1068
1069
1070 try:
1071 key_dir = etpConst[key]
1072 d_paths = []
1073 while not os.path.isdir(key_dir):
1074 d_paths.append(key_dir)
1075 key_dir = os.path.dirname(key_dir)
1076 d_paths = sorted(d_paths)
1077 for d_path in d_paths:
1078 os.mkdir(d_path)
1079 const_setup_file(d_path, gid, 0o775)
1080 except (OSError, IOError,):
1081 pass
1082
1083 if gid:
1084 etpConst['entropygid'] = gid
1085 if not os.path.isdir(etpConst['entropyworkdir']):
1086 try:
1087 os.makedirs(etpConst['entropyworkdir'])
1088 except OSError:
1089 pass
1090 w_gid = os.stat(etpConst['entropyworkdir'])[stat.ST_GID]
1091 if w_gid != gid:
1092 const_setup_perms(etpConst['entropyworkdir'], gid)
1093
1094 if not os.path.isdir(etpConst['entropyunpackdir']):
1095 try:
1096 os.makedirs(etpConst['entropyunpackdir'])
1097 except OSError:
1098 pass
1099 try:
1100 w_gid = os.stat(etpConst['entropyunpackdir'])[stat.ST_GID]
1101 if w_gid != gid:
1102 if os.path.isdir(etpConst['entropyunpackdir']):
1103 const_setup_perms(etpConst['entropyunpackdir'], gid)
1104 except OSError:
1105 pass
1106
1107 if not const_islive():
1108
1109 const_setup_perms(etpConst['etpdatabaseclientdir'], gid)
1110
1122
1123
1125 """
1126 Analyze a server repository string (usually contained in server.conf),
1127 extracting all the parameters.
1128
1129 @param repostring: repository string
1130 @type repostring: string
1131 @keyword product: system product which repository belongs to
1132 @rtype: None
1133 @return: None
1134 """
1135
1136 if product == None:
1137 product = etpConst['product']
1138
1139 mydata = {}
1140 repoid = repostring.split("|")[1].strip()
1141 repodesc = repostring.split("|")[2].strip()
1142 repouris = repostring.split("|")[3].strip()
1143
1144 service_url = None
1145 eapi3_port = int(etpConst['socket_service']['port'])
1146 eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
1147 if len(repostring.split("|")) > 4:
1148 service_url = repostring.split("|")[4].strip()
1149
1150 eapi3_formatcolon = service_url.rfind("#")
1151 if eapi3_formatcolon != -1:
1152 try:
1153 ports = service_url[eapi3_formatcolon+1:].split(",")
1154 eapi3_port = int(ports[0])
1155 if len(ports) > 1:
1156 eapi3_ssl_port = int(ports[1])
1157 service_url = service_url[:eapi3_formatcolon]
1158 except (ValueError, IndexError,):
1159 eapi3_port = int(etpConst['socket_service']['port'])
1160 eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
1161
1162 mydata = {}
1163 mydata['repoid'] = repoid
1164 mydata['description'] = repodesc
1165 mydata['mirrors'] = []
1166 mydata['community'] = False
1167 mydata['service_url'] = service_url
1168 mydata['service_port'] = eapi3_port
1169 mydata['ssl_service_port'] = eapi3_ssl_port
1170 uris = repouris.split()
1171 for uri in uris:
1172 mydata['mirrors'].append(uri)
1173
1174 return repoid, mydata
1175
1177 """
1178 Setup permissions and group id (GID) to a directory, recursively.
1179
1180 @param mydir: valid file path
1181 @type mydir: string
1182 @param gid: valid group id (GID)
1183 @type gid: int
1184 @rtype: None
1185 @return: None
1186 """
1187 if gid == None:
1188 return
1189 for currentdir, subdirs, files in os.walk(mydir):
1190 try:
1191 cur_gid = os.stat(currentdir)[stat.ST_GID]
1192 if cur_gid != gid:
1193 os.chown(currentdir, -1, gid)
1194 cur_mod = const_get_chmod(currentdir)
1195 if cur_mod != oct(0o775):
1196 os.chmod(currentdir, 0o775)
1197 except OSError:
1198 pass
1199 for item in files:
1200 item = os.path.join(currentdir, item)
1201 try:
1202 const_setup_file(item, gid, 0o664)
1203 except OSError:
1204 pass
1205
1207 """
1208 Setup file permissions and group id (GID).
1209
1210 @param myfile: valid file path
1211 @type myfile: string
1212 @param gid: valid group id (GID)
1213 @type gid: int
1214 @param chmod: permissions
1215 @type chmod: integer representing an octal
1216 @rtype: None
1217 @return: None
1218 """
1219 cur_gid = os.stat(myfile)[stat.ST_GID]
1220 if cur_gid != gid:
1221 os.chown(myfile, -1, gid)
1222 const_set_chmod(myfile, chmod)
1223
1224
1226 """
1227 This function get the current permissions of the specified
1228 file. If you want to use the returning value with const_set_chmod
1229 you need to convert it back to int.
1230
1231 @param myfile: valid file path
1232 @type myfile: string
1233 @rtype: integer(8) (octal)
1234 @return: octal representing permissions
1235 """
1236 myst = os.stat(myfile)[stat.ST_MODE]
1237 return oct(myst & 0o777)
1238
1240 """
1241 This function sets specified permissions to a file.
1242 If they differ from the current ones.
1243
1244 @param myfile: valid file path
1245 @type myfile: string
1246 @param chmod: permissions
1247 @type chmod: integer representing an octal
1248 @rtype: None
1249 @return: None
1250 """
1251 cur_mod = const_get_chmod(myfile)
1252 if cur_mod != oct(chmod):
1253 os.chmod(myfile, chmod)
1254
1256 """
1257 This function tries to retrieve the "entropy" user group
1258 GID.
1259
1260 @rtype: None
1261 @return: None
1262 @raise KeyError: when "entropy" system GID is not available
1263 """
1264 group_file = etpConst['systemroot']+'/etc/group'
1265 if not os.path.isfile(group_file):
1266 raise KeyError
1267
1268 with open(group_file, "r") as group_f:
1269 for line in group_f.readlines():
1270 if line.startswith('%s:' % (etpConst['sysgroup'],)):
1271 try:
1272 gid = int(line.split(":")[2])
1273 except ValueError:
1274 raise KeyError
1275 return gid
1276 raise KeyError
1277
1279 """
1280 This function looks for an "entropy" user group.
1281 If not available, it tries to create one.
1282
1283 @rtype: None
1284 @return: None
1285 @raise KeyError: if ${ROOT}/etc/group is not found
1286 """
1287 group_file = etpConst['systemroot']+'/etc/group'
1288 if not os.path.isfile(group_file):
1289 raise KeyError
1290 ids = set()
1291
1292 with open(group_file, "r") as group_f:
1293 for line in group_f.readlines():
1294 if line and line.split(":"):
1295 try:
1296 myid = int(line.split(":")[2])
1297 except ValueError:
1298 pass
1299 ids.add(myid)
1300 if ids:
1301
1302 new_id = 1000
1303 while True:
1304 new_id += 1
1305 if new_id not in ids:
1306 break
1307 else:
1308 new_id = 10000
1309
1310 with open(group_file, "a") as group_fw:
1311 group_fw.seek(0, 2)
1312 app_line = "entropy:x:%s:\n" % (new_id,)
1313 group_fw.write(app_line)
1314 group_fw.flush()
1315
1317 """
1318 Return generic string type for usage in isinstance().
1319 On Python 2.x, it returns basestring while on Python 3.x it returns
1320 (str, bytes,)
1321 """
1322 if sys.hexversion >= 0x3000000:
1323 return (str, bytes,)
1324 else:
1325 return (basestring,)
1326
1328 """
1329 Return whether obj is a string (unicode or raw).
1330
1331 @param obj: Python object
1332 @type obj: Python object
1333 @return: True, if object is string
1334 @rtype: bool
1335 """
1336 if sys.hexversion >= 0x3000000:
1337 return isinstance(obj, (str, bytes))
1338 else:
1339 return isinstance(obj, basestring)
1340
1342 """
1343 Return whether obj is a unicode.
1344
1345 @param obj: Python object
1346 @type obj: Python object
1347 @return: True, if object is unicode
1348 @rtype: bool
1349 """
1350 if sys.hexversion >= 0x3000000:
1351 return isinstance(obj, str)
1352 else:
1353 return isinstance(obj, unicode)
1354
1356 if sys.hexversion >= 0x3000000:
1357 return isinstance(obj, bytes)
1358 else:
1359 return isinstance(obj, str)
1360
1362 """
1363 Convert generic string to unicode format, this function supports both
1364 Python 2.x and Python 3.x unicode bullshit.
1365
1366 @param obj: generic string object
1367 @type obj: string
1368 @return: unicode string object
1369 @rtype: unicode object
1370 """
1371
1372
1373 if obj is None:
1374 return const_convert_to_unicode("None")
1375
1376
1377 if isinstance(obj, int):
1378 if sys.hexversion >= 0x3000000:
1379 return str(obj)
1380 else:
1381 return unicode(obj)
1382
1383
1384 if isinstance(obj, const_get_buffer()):
1385 if sys.hexversion >= 0x3000000:
1386 return str(obj.tobytes(), enctype)
1387 else:
1388 return unicode(obj, enctype)
1389
1390
1391 if const_isunicode(obj):
1392 return obj
1393 if hasattr(obj, 'decode'):
1394 return obj.decode(enctype)
1395 else:
1396 if sys.hexversion >= 0x3000000:
1397 return str(obj, enctype)
1398 else:
1399 return unicode(obj, enctype)
1400
1402 """
1403 Convert generic string to raw string (str for Python 2.x or bytes for
1404 Python 3.x).
1405
1406 @param obj: input string
1407 @type obj: string object
1408 @keyword from_enctype: encoding which string is using
1409 @type from_enctype: string
1410 @return: raw string
1411 @rtype: bytes
1412 """
1413 if const_isnumber(obj):
1414 if sys.hexversion >= 0x3000000:
1415 return bytes(str(obj), from_enctype)
1416 else:
1417 return str(obj)
1418 if isinstance(obj, const_get_buffer()):
1419 if sys.hexversion >= 0x3000000:
1420 return obj.tobytes()
1421 else:
1422 return str(obj)
1423 if not const_isunicode(obj):
1424 return obj
1425 return obj.encode(from_enctype)
1426
1428 """
1429 Return generic buffer object (supporting both Python 2.x and Python 3.x)
1430 """
1431 if sys.hexversion >= 0x3000000:
1432 return memoryview
1433 else:
1434 return buffer
1435
1437 """
1438 Return whether obj is a file object
1439 """
1440 if sys.hexversion >= 0x3000000:
1441 import io
1442 return isinstance(obj, io.IOBase)
1443 else:
1444 return isinstance(obj, file)
1445
1447 """
1448 Return whether obj is an int, long object.
1449 """
1450 if sys.hexversion >= 0x3000000:
1451 return isinstance(obj, int)
1452 else:
1453 return isinstance(obj, (int, long,))
1454
1456 """
1457 cmp() is gone in Python 3.x provide our own implementation.
1458 """
1459 return (a > b) - (a < b)
1460
1462 """
1463 Live environments (Operating System running off a CD/DVD)
1464 must feature the "cdroot" parameter in kernel /proc/cmdline
1465
1466 Sample code:
1467 >>> from entropy.const import const_islive
1468 >>> const_islive()
1469 False
1470
1471 @rtype: bool
1472 @return: determine wether this is a Live system or not
1473 """
1474 if "cdroot" in etpConst['cmdline']:
1475 return True
1476 return False
1477
1479 """
1480 Entropy threads killer. Even if Python threads cannot
1481 be stopped or killed, TimeScheduled ones can, exporting
1482 the kill() method.
1483
1484 Sample code:
1485 >>> from entropy.const import const_kill_threads
1486 >>> const_kill_threads()
1487
1488 @rtype: None
1489 @return: None
1490 """
1491 import threading
1492 threads = threading.enumerate()
1493 for running_t in threads:
1494
1495 if running_t.getName() == 'MainThread':
1496 continue
1497 if hasattr(running_t, 'kill'):
1498 running_t.kill()
1499 running_t.join(120.0)
1500
1502 """
1503 Our default Python exception handler. It kills
1504 all the threads generated by Entropy before
1505 raising exceptions. Overloads sys.excepthook,
1506 internal function !!
1507
1508 @param etype: exception type
1509 @type etype: exception type
1510 @param value: exception data
1511 @type value: string
1512 @param t_back: traceback object?
1513 @type t_back: Python traceback object
1514 @rtype: default Python exceptions hook
1515 @return: sys.__excepthook__
1516 """
1517 try:
1518 const_kill_threads()
1519 except (AttributeError, ImportError, TypeError,):
1520 pass
1521 return sys.__excepthook__(etype, value, t_back)
1522
1524 """
1525 Entropy debugging output write functions.
1526
1527 @param identifier: debug identifier
1528 @type identifier: string
1529 @param msg: debugging message
1530 @type msg: string
1531 @rtype: None
1532 @return: None
1533 """
1534 if etpUi['debug']:
1535 if sys.hexversion >= 0x3000000:
1536 sys.stdout.buffer.write(const_convert_to_rawstring(identifier) + \
1537 b" " + const_convert_to_rawstring(msg) + b"\n")
1538 else:
1539 sys.stdout.write("%s: %s" % (identifier, msg + "\n"))
1540 sys.stdout.flush()
1541
1542
1543 initconfig_entropy_constants(etpSys['rootdir'])
1544