source: ubiquity/trunk/fuentes/ubiquity/misc.py @ 1549

Last change on this file since 1549 was 1549, checked in by daduve, 4 years ago

Updated new files

File size: 26.9 KB
Line 
1# -*- coding: utf-8; Mode: Python; indent-tabs-mode: nil; tab-width: 4 -*-
2
3from collections import namedtuple
4import contextlib
5import grp
6import os
7import pwd
8import re
9import shutil
10import subprocess
11import syslog
12
13from ubiquity import osextras
14
15
16def utf8(s, errors="strict"):
17    """Decode a string as UTF-8 if it isn't already Unicode."""
18    if isinstance(s, str):
19        return s
20    else:
21        return str(s, "utf-8", errors)
22
23
24def is_swap(device):
25    try:
26        with open('/proc/swaps') as fp:
27            for line in fp:
28                if line.startswith(device + ' '):
29                    return True
30    except Exception:
31        pass
32    return False
33
34
35_dropped_privileges = 0
36
37
38def set_groups_for_uid(uid):
39    if uid == os.geteuid() or uid == os.getuid():
40        return
41    user = pwd.getpwuid(uid).pw_name
42    try:
43        os.setgroups([g.gr_gid for g in grp.getgrall() if user in g.gr_mem])
44    except OSError:
45        import traceback
46        for line in traceback.format_exc().split('\n'):
47            syslog.syslog(syslog.LOG_ERR, line)
48
49
50def drop_all_privileges():
51    # gconf needs both the UID and effective UID set.
52    global _dropped_privileges
53    uid = os.environ.get('PKEXEC_UID')
54    gid = None
55    if uid is not None:
56        uid = int(uid)
57        set_groups_for_uid(uid)
58        gid = pwd.getpwuid(uid).pw_gid
59    if gid is not None:
60        gid = int(gid)
61        os.setregid(gid, gid)
62    if uid is not None:
63        uid = int(uid)
64        os.setreuid(uid, uid)
65        os.environ['HOME'] = pwd.getpwuid(uid).pw_dir
66        os.environ['LOGNAME'] = pwd.getpwuid(uid).pw_name
67    _dropped_privileges = None
68
69
70def drop_privileges():
71    global _dropped_privileges
72    assert _dropped_privileges is not None
73    if _dropped_privileges == 0:
74        uid = os.environ.get('PKEXEC_UID')
75        gid = None
76        if uid is not None:
77            uid = int(uid)
78            set_groups_for_uid(uid)
79            gid = pwd.getpwuid(uid).pw_gid
80        if gid is not None:
81            gid = int(gid)
82            os.setegid(gid)
83        if uid is not None:
84            os.seteuid(uid)
85    _dropped_privileges += 1
86
87
88def regain_privileges():
89    global _dropped_privileges
90    assert _dropped_privileges is not None
91    _dropped_privileges -= 1
92    if _dropped_privileges == 0:
93        os.seteuid(0)
94        os.setegid(0)
95        os.setgroups([])
96
97
98def drop_privileges_save():
99    """Drop the real UID/GID as well, and hide them in saved IDs."""
100    # At the moment, we only know how to handle this when effective
101    # privileges were already dropped.
102    assert _dropped_privileges is not None and _dropped_privileges > 0
103    uid = os.environ.get('PKEXEC_UID')
104    gid = None
105    if uid is not None:
106        uid = int(uid)
107        set_groups_for_uid(uid)
108        gid = pwd.getpwuid(uid).pw_gid
109    if gid is not None:
110        gid = int(gid)
111        os.setresgid(gid, gid, 0)
112    if uid is not None:
113        os.setresuid(uid, uid, 0)
114
115
116def regain_privileges_save():
117    """Recover our real UID/GID after calling drop_privileges_save."""
118    assert _dropped_privileges is not None and _dropped_privileges > 0
119    os.setresuid(0, 0, 0)
120    os.setresgid(0, 0, 0)
121    os.setgroups([])
122
123
124@contextlib.contextmanager
125def raised_privileges():
126    """As regain_privileges/drop_privileges, but in context manager style."""
127    regain_privileges()
128    try:
129        yield
130    finally:
131        drop_privileges()
132
133
134def raise_privileges(func):
135    """As raised_privileges, but as a function decorator."""
136    from functools import wraps
137
138    @wraps(func)
139    def helper(*args, **kwargs):
140        with raised_privileges():
141            return func(*args, **kwargs)
142
143    return helper
144
145
146@raise_privileges
147def grub_options():
148    """ Generates a list of suitable targets for grub-installer
149        @return empty list or a list of ['/dev/sda1','Ubuntu Hardy 8.04'] """
150    from ubiquity.parted_server import PartedServer
151
152    l = []
153    try:
154        oslist = {}
155        subp = subprocess.Popen(
156            ['os-prober'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
157            universal_newlines=True)
158        result = subp.communicate()[0].splitlines()
159        for res in result:
160            res = res.split(':')
161            res[0] = re.match(r'[/\w\d]+', res[0]).group()
162            oslist[res[0]] = res[1]
163        p = PartedServer()
164        for disk in p.disks():
165            p.select_disk(disk)
166            with open(p.device_entry('model')) as fp:
167                mod = fp.readline()
168            with open(p.device_entry('device')) as fp:
169                dev = fp.readline()
170            with open(p.device_entry('size')) as fp:
171                size = fp.readline()
172            if dev and mod:
173                if size.isdigit():
174                    size = format_size(int(size))
175                    l.append([dev, '%s (%s)' % (mod, size)])
176                else:
177                    l.append([dev, mod])
178            for part in p.partitions():
179                ostype = ''
180                if part[4] == 'linux-swap':
181                    continue
182                if part[4] == 'free':
183                    continue
184                if os.path.exists(p.part_entry(part[1], 'format')):
185                    # Don't bother looking for an OS type.
186                    pass
187                elif part[5] in oslist.keys():
188                    ostype = oslist[part[5]]
189                l.append([part[5], ostype])
190    except:
191        import traceback
192        for line in traceback.format_exc().split('\n'):
193            syslog.syslog(syslog.LOG_ERR, line)
194    return l
195
196
197@raise_privileges
198def boot_device():
199    from ubiquity.parted_server import PartedServer
200
201    boot = None
202    root = None
203    try:
204        p = PartedServer()
205        for disk in p.disks():
206            p.select_disk(disk)
207            for part in p.partitions():
208                part = part[1]
209                if p.has_part_entry(part, 'mountpoint'):
210                    mp = p.readline_part_entry(part, 'mountpoint')
211                    if mp == '/boot':
212                        boot = disk.replace('=', '/')
213                    elif mp == '/':
214                        root = disk.replace('=', '/')
215    except Exception:
216        import traceback
217        for line in traceback.format_exc().split('\n'):
218            syslog.syslog(syslog.LOG_ERR, line)
219    if boot:
220        return boot
221    return root
222
223
224def is_removable(device):
225    if device is None:
226        return None
227    device = os.path.realpath(device)
228    devpath = None
229    is_partition = False
230    removable_bus = False
231    subp = subprocess.Popen(['udevadm', 'info', '-q', 'property',
232                             '-n', device],
233                            stdout=subprocess.PIPE, universal_newlines=True)
234    for line in subp.communicate()[0].splitlines():
235        line = line.strip()
236        if line.startswith('DEVPATH='):
237            devpath = line[8:]
238        elif line == 'DEVTYPE=partition':
239            is_partition = True
240        elif line == 'ID_BUS=usb' or line == 'ID_BUS=ieee1394':
241            removable_bus = True
242
243    if devpath is not None:
244        if is_partition:
245            devpath = os.path.dirname(devpath)
246        is_removable = removable_bus
247        try:
248            with open('/sys%s/removable' % devpath) as removable:
249                if removable.readline().strip() != '0':
250                    is_removable = True
251        except IOError:
252            pass
253        if is_removable:
254            try:
255                subp = subprocess.Popen(['udevadm', 'info', '-q', 'name',
256                                         '-p', devpath],
257                                        stdout=subprocess.PIPE,
258                                        universal_newlines=True)
259                return ('/dev/%s' %
260                        subp.communicate()[0].splitlines()[0].strip())
261            except Exception:
262                pass
263
264    return None
265
266
267def mount_info(path):
268    """Return filesystem name, type, and ro/rw for a given mountpoint."""
269    fsname = ''
270    fstype = ''
271    writable = ''
272    with open('/proc/mounts') as fp:
273        for line in fp:
274            line = line.split()
275            if line[1] == path:
276                fsname = line[0]
277                fstype = line[2]
278                writable = line[3].split(',')[0]
279    return fsname, fstype, writable
280
281
282def udevadm_info(args):
283    fullargs = ['udevadm', 'info', '-q', 'property']
284    fullargs.extend(args)
285    udevadm = {}
286    subp = subprocess.Popen(
287        fullargs, stdout=subprocess.PIPE, universal_newlines=True)
288    for line in subp.communicate()[0].splitlines():
289        line = line.strip()
290        if '=' not in line:
291            continue
292        name, value = line.split('=', 1)
293        udevadm[name] = value
294    return udevadm
295
296
297def partition_to_disk(partition):
298    """Convert a partition device to its disk device, if any."""
299    udevadm_part = udevadm_info(['-n', partition])
300    if ('DEVPATH' not in udevadm_part or
301            udevadm_part.get('DEVTYPE') != 'partition'):
302        return partition
303
304    disk_syspath = '/sys%s' % udevadm_part['DEVPATH'].rsplit('/', 1)[0]
305    udevadm_disk = udevadm_info(['-p', disk_syspath])
306    return udevadm_disk.get('DEVNAME', partition)
307
308
309def is_boot_device_removable(boot=None):
310    if boot:
311        return is_removable(boot)
312    else:
313        return is_removable(boot_device())
314
315
316def cdrom_mount_info():
317    """Return mount information for /cdrom.
318
319    This is the same as mount_info, except that the partition is converted to
320    its containing disk, and we don't care whether the mount point is
321    writable.
322    """
323    cdsrc, cdfs, _ = mount_info('/cdrom')
324    cdsrc = partition_to_disk(cdsrc)
325    return cdsrc, cdfs
326
327
328@raise_privileges
329def grub_device_map():
330    """Return the contents of the default GRUB device map."""
331    subp = subprocess.Popen(['grub-mkdevicemap', '--no-floppy', '-m', '-'],
332                            stdout=subprocess.PIPE, universal_newlines=True)
333    return subp.communicate()[0].splitlines()
334
335
336def grub_default(boot=None):
337    """Return the default GRUB installation target."""
338
339    # Much of this is intentionally duplicated from grub-installer, so that
340    # we can show the user what device GRUB will be installed to before
341    # grub-installer is run.  Pursuant to that, we intentionally run this in
342    # the installer root as /target might not yet be available.
343
344    bootremovable = is_boot_device_removable(boot=boot)
345    if bootremovable is not None:
346        return bootremovable
347
348    devices = grub_device_map()
349    target = None
350    if devices:
351        try:
352            target = os.path.realpath(devices[0].split('\t')[1])
353        except (IndexError, OSError):
354            pass
355    # last resort
356    if target is None:
357        target = '(hd0)'
358
359    cdsrc, cdfs = cdrom_mount_info()
360    try:
361        # The target is usually under /dev/disk/by-id/, so string equality
362        # is insufficient.
363        same = os.path.samefile(cdsrc, target)
364    except OSError:
365        same = False
366    if ((same or target == '(hd0)') and
367            ((cdfs and cdfs != 'iso9660') or is_removable(cdsrc))):
368        # Installing from removable media other than a CD.  Make sure that
369        # we don't accidentally install GRUB to it.
370        boot = boot_device()
371        try:
372            if boot:
373                target = boot
374            else:
375                # Try the next disk along (which can't also be the CD source).
376                target = os.path.realpath(devices[1].split('\t')[1])
377            target = re.sub(r'(/dev/(cciss|ida)/c[0-9]d[0-9]|/dev/[a-z]+).*',
378                            r'\1', target)
379        except (IndexError, OSError):
380            pass
381
382    return target
383
384
385_os_prober_oslist = {}
386_os_prober_osvers = {}
387_os_prober_called = False
388
389
390def find_in_os_prober(device, with_version=False):
391    """Look for the device name in the output of os-prober.
392
393    Return the friendly name of the device, or the empty string on error.
394    """
395    try:
396        oslist, osvers = os_prober()
397        if device in oslist:
398            ret = oslist[device]
399        elif is_swap(device):
400            ret = 'swap'
401        else:
402            syslog.syslog('Device %s not found in os-prober output' % device)
403            ret = ''
404        ret = utf8(ret, errors='replace')
405        ver = utf8(osvers.get(device, ''), errors='replace')
406        if with_version:
407            return ret, ver
408        else:
409            return ret
410    except (KeyboardInterrupt, SystemExit):
411        pass
412    except:
413        import traceback
414        syslog.syslog(syslog.LOG_ERR, "Error in find_in_os_prober:")
415        for line in traceback.format_exc().split('\n'):
416            syslog.syslog(syslog.LOG_ERR, line)
417    return ''
418
419
420@raise_privileges
421def os_prober():
422    global _os_prober_oslist
423    global _os_prober_osvers
424    global _os_prober_called
425
426    if not _os_prober_called:
427        _os_prober_called = True
428        subp = subprocess.Popen(
429            ['os-prober'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
430            universal_newlines=True)
431        result = subp.communicate()[0].splitlines()
432        for res in result:
433            res = res.split(':')
434            # launchpad bug #1265192, fix os-prober Windows EFI path
435            res[0] = re.match(r'[/\w\d]+', res[0]).group()
436            if res[2] == 'Ubuntu':
437                version = [v for v in re.findall('[0-9.]*', res[1]) if v][0]
438                # Get rid of the superfluous (development version) (11.04)
439                text = re.sub('\s*\(.*\).*', '', res[1])
440                _os_prober_oslist[res[0]] = text
441                _os_prober_osvers[res[0]] = version
442            else:
443                # Get rid of the bootloader indication. It's not relevant here.
444                _os_prober_oslist[res[0]] = res[1].replace(' (loader)', '')
445    return _os_prober_oslist, _os_prober_osvers
446
447
448@raise_privileges
449def remove_os_prober_cache():
450    osextras.unlink_force('/var/lib/ubiquity/os-prober-cache')
451    shutil.rmtree('/var/lib/ubiquity/linux-boot-prober-cache',
452                  ignore_errors=True)
453
454
455def windows_startup_folder(mount_path):
456    locations = [
457        # Windows 8
458        'ProgramData/Microsoft/Windows/Start Menu/Programs/StartUp',
459        # Windows 7
460        'ProgramData/Microsoft/Windows/Start Menu/Programs/Startup',
461        # Windows XP
462        'Documents and Settings/All Users/Start Menu/Programs/Startup',
463        # Windows NT
464        'Winnt/Profiles/All Users/Start Menu/Programs/Startup',
465    ]
466    for location in locations:
467        path = os.path.join(mount_path, location)
468        if os.path.exists(path):
469            return path
470    return ''
471
472
473ReleaseInfo = namedtuple('ReleaseInfo', 'name, version')
474
475
476def get_release():
477    if get_release.release_info is None:
478        try:
479            with open('/cdrom/.disk/info') as fp:
480                line = fp.readline()
481                if line:
482                    line = line.split()
483                    if line[2] == 'LTS':
484                        line[1] += ' LTS'
485                    line[0] = line[0].replace('-', ' ')
486                    get_release.release_info = ReleaseInfo(
487                        name=line[0], version=line[1])
488        except:
489            syslog.syslog(syslog.LOG_ERR, 'Unable to determine the release.')
490
491        if not get_release.release_info:
492            get_release.release_info = ReleaseInfo(name='Ubuntu', version='')
493    return get_release.release_info
494
495get_release.release_info = None
496
497
498def get_release_name():
499    import warnings
500    warnings.warn('get_release_name() is deprecated, '
501                  'use get_release().name instead.',
502                  category=DeprecationWarning)
503
504    if not get_release_name.release_name:
505        try:
506            with open('/cdrom/.disk/info') as fp:
507                line = fp.readline()
508                if line:
509                    line = line.split()
510                    if line[2] == 'LTS':
511                        get_release_name.release_name = ' '.join(line[:3])
512                    else:
513                        get_release_name.release_name = ' '.join(line[:2])
514        except:
515            syslog.syslog(
516                syslog.LOG_ERR,
517                "Unable to determine the distribution name from "
518                "/cdrom/.disk/info")
519        if not get_release_name.release_name:
520            get_release_name.release_name = 'Ubuntu'
521    return get_release_name.release_name
522
523get_release_name.release_name = ''
524
525
526@raise_privileges
527def get_install_medium():
528    if not get_install_medium.medium:
529        try:
530            if os.access('/cdrom', os.W_OK):
531                get_install_medium.medium = 'USB'
532            else:
533                get_install_medium.medium = 'CD'
534        except:
535            syslog.syslog(
536                syslog.LOG_ERR, "Unable to determine install medium.")
537            get_install_medium.medium = 'CD'
538    return get_install_medium.medium
539
540get_install_medium.medium = ''
541
542
543def execute(*args):
544    """runs args* in shell mode. Output status is taken."""
545
546    log_args = ['log-output', '-t', 'ubiquity']
547    log_args.extend(args)
548
549    try:
550        status = subprocess.call(log_args)
551    except IOError as e:
552        syslog.syslog(syslog.LOG_ERR, ' '.join(log_args))
553        syslog.syslog(syslog.LOG_ERR,
554                      "OS error(%s): %s" % (e.errno, e.strerror))
555        return False
556    else:
557        if status != 0:
558            syslog.syslog(syslog.LOG_ERR, ' '.join(log_args))
559            return False
560        syslog.syslog(' '.join(log_args))
561        return True
562
563
564@raise_privileges
565def execute_root(*args):
566    return execute(*args)
567
568
569def format_size(size):
570    """Format a partition size."""
571    if size < 1000:
572        unit = 'B'
573        factor = 1
574    elif size < 1000 * 1000:
575        unit = 'kB'
576        factor = 1000
577    elif size < 1000 * 1000 * 1000:
578        unit = 'MB'
579        factor = 1000 * 1000
580    elif size < 1000 * 1000 * 1000 * 1000:
581        unit = 'GB'
582        factor = 1000 * 1000 * 1000
583    else:
584        unit = 'TB'
585        factor = 1000 * 1000 * 1000 * 1000
586    return '%.1f %s' % (float(size) / factor, unit)
587
588
589def debconf_escape(text):
590    escaped = text.replace('\\', '\\\\').replace('\n', '\\n')
591    return re.sub(r'(\s)', r'\\\1', escaped)
592
593
594def create_bool(text):
595    if text == 'true':
596        return True
597    elif text == 'false':
598        return False
599    else:
600        return text
601
602
603@raise_privileges
604def dmimodel():
605    model = ''
606    kwargs = {}
607    if os.geteuid() != 0:
608        # Silence annoying warnings during the test suite.
609        kwargs['stderr'] = open('/dev/null', 'w')
610    try:
611        proc = subprocess.Popen(
612            ['dmidecode', '--quiet', '--string', 'system-manufacturer'],
613            stdout=subprocess.PIPE, universal_newlines=True, **kwargs)
614        manufacturer = proc.communicate()[0]
615        if not manufacturer:
616            return
617        manufacturer = manufacturer.lower()
618        if 'to be filled' in manufacturer:
619            # Don't bother with products in development.
620            return
621        if 'bochs' in manufacturer or 'vmware' in manufacturer:
622            model = 'virtual machine'
623            # VirtualBox sets an appropriate system-product-name.
624        else:
625            if 'lenovo' in manufacturer or 'ibm' in manufacturer:
626                key = 'system-version'
627            else:
628                key = 'system-product-name'
629            proc = subprocess.Popen(
630                ['dmidecode', '--quiet', '--string', key],
631                stdout=subprocess.PIPE,
632                universal_newlines=True)
633            model = proc.communicate()[0]
634        if 'apple' in manufacturer:
635            # MacBook4,1 - strip the 4,1
636            model = re.sub('[^a-zA-Z\s]', '', model)
637        # Replace each gap of non-alphanumeric characters with a dash.
638        # Ensure the resulting string does not begin or end with a dash.
639        model = re.sub('[^a-zA-Z0-9]+', '-', model).rstrip('-').lstrip('-')
640        if model.lower() == 'not-available':
641            return
642        if model.lower() == "To be filled by O.E.M.".lower():
643            return
644    except Exception:
645        syslog.syslog(syslog.LOG_ERR, 'Unable to determine the model from DMI')
646    finally:
647        if 'stderr' in kwargs:
648            kwargs['stderr'].close()
649    return model
650
651
652def set_indicator_keymaps(lang):
653    import xml.etree.cElementTree as ElementTree
654    from gi.repository import Xkl, GdkX11
655    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
656    # imported; possibly finer-grained than this, but anything using this
657    # will already have imported Gtk anyway ...
658    from gi.repository import Gtk
659    from ubiquity import gsettings
660
661    # pacify pyflakes
662    Gtk
663
664    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
665    lang = lang.split('_')[0]
666    variants = []
667
668    # Map inspired from that of gfxboot-theme-ubuntu that's itself
669    # based on console-setup's. This one has been restricted to
670    # language => keyboard layout not locale => keyboard layout as
671    # we don't actually know the exact locale
672    default_keymap = {
673        'ar': 'ara',
674        'bs': 'ba',
675        'de': 'de',
676        'el': 'gr',
677        'en': 'us',
678        'eo': 'epo',
679        'fr': 'fr_oss',
680        'gu': 'in_guj',
681        'hi': 'in',
682        'hr': 'hr',
683        'hy': 'am',
684        'ka': 'ge',
685        'kn': 'in_kan',
686        'lo': 'la',
687        'ml': 'in_mal',
688        'pa': 'in_guru',
689        'sr': 'rs',
690        'sv': 'se',
691        'ta': 'in_tam',
692        'te': 'in_tel',
693        'zh': 'cn',
694    }
695
696    def item_str(s):
697        '''Convert a zero-terminated byte array to a proper str'''
698        import array
699        s = array.array('B', s).tostring()
700        i = s.find(b'\x00')
701        return s[:i].decode()
702
703    def process_variant(*args):
704        if hasattr(args[2], 'name'):
705            variants.append(
706                '%s\t%s' % (item_str(args[1].name), item_str(args[2].name)))
707        else:
708            variants.append(item_str(args[1].name))
709
710    def restrict_list(variants):
711        new_variants = []
712
713        # Start by looking by an explicit default layout in the keymap
714        if lang in default_keymap:
715            if default_keymap[lang] in variants:
716                variants.remove(default_keymap[lang])
717                new_variants.append(default_keymap[lang])
718            else:
719                tab_keymap = default_keymap[lang].replace('_', '\t')
720                if tab_keymap in variants:
721                    variants.remove(tab_keymap)
722                    new_variants.append(tab_keymap)
723
724        # Prioritize the layout matching the language (if any)
725        if lang in variants:
726            variants.remove(lang)
727            new_variants.append(lang)
728
729        # Uniquify our list (just in case)
730        variants = list(set(variants))
731
732        if len(variants) > 4:
733            # We have a problem, X only supports 4
734
735            # Add as many entry as we can that are layouts without variant
736            country_variants = sorted(
737                entry for entry in variants if '\t' not in entry)
738            for entry in country_variants[:4 - len(new_variants)]:
739                new_variants.append(entry)
740                variants.remove(entry)
741
742            if len(new_variants) < 4:
743                # We can add some more
744                simple_variants = sorted(
745                    entry for entry in variants if '_' not in entry)
746                for entry in simple_variants[:4 - len(new_variants)]:
747                    new_variants.append(entry)
748                    variants.remove(entry)
749
750            if len(new_variants) < 4:
751                # Now just add anything left
752                for entry in variants[:4 - len(new_variants)]:
753                    new_variants.append(entry)
754                    variants.remove(entry)
755        else:
756            new_variants += list(variants)
757
758        # gsettings doesn't understand utf8
759        new_variants = [str(variant) for variant in new_variants]
760
761        return new_variants
762
763    def call_setxkbmap(variants):
764        kb_layouts = []
765        kb_variants = []
766
767        for entry in variants:
768            fields = entry.split('\t')
769            if len(fields) > 1:
770                kb_layouts.append(fields[0])
771                kb_variants.append(fields[1])
772            else:
773                kb_layouts.append(fields[0])
774                kb_variants.append("")
775
776        execute(
777            "setxkbmap", "-layout", ",".join(kb_layouts),
778            "-variant", ",".join(kb_variants))
779
780    iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml')
781    nodes = [element for element in iso_639.findall('iso_639_entry')
782             if element.get('iso_639_1_code') == lang]
783    display = GdkX11.x11_get_default_xdisplay()
784    engine = Xkl.Engine.get_instance(display)
785    if nodes:
786        configreg = Xkl.ConfigRegistry.get_instance(engine)
787        configreg.load(False)
788
789        # Apparently iso_639_2B_code doesn't always work (fails with French)
790        for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'):
791            code = nodes[0].get(prop)
792            if code is not None:
793                configreg.foreach_language_variant(code, process_variant, None)
794                if variants:
795                    restricted_variants = restrict_list(variants)
796                    call_setxkbmap(restricted_variants)
797                    gsettings.set_list(
798                        gsettings_key[0], gsettings_key[1],
799                        restricted_variants)
800                    break
801        else:
802            # Use the system default if no other keymaps can be determined.
803            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])
804
805    engine.lock_group(0)
806
807
808NM = 'org.freedesktop.NetworkManager'
809NM_STATE_CONNECTED_GLOBAL = 70
810
811
812def get_prop(obj, iface, prop):
813    import dbus
814    try:
815        return obj.Get(iface, prop, dbus_interface=dbus.PROPERTIES_IFACE)
816    except dbus.DBusException as e:
817        if e.get_dbus_name() == 'org.freedesktop.DBus.Error.UnknownMethod':
818            return None
819        else:
820            raise
821
822
823def has_connection():
824    import dbus
825    bus = dbus.SystemBus()
826    manager = bus.get_object(NM, '/org/freedesktop/NetworkManager')
827    state = get_prop(manager, NM, 'State')
828    return state == NM_STATE_CONNECTED_GLOBAL
829
830
831def add_connection_watch(func):
832    import dbus
833
834    def connection_cb(state):
835        func(state == NM_STATE_CONNECTED_GLOBAL)
836
837    bus = dbus.SystemBus()
838    bus.add_signal_receiver(connection_cb, 'StateChanged', NM, NM)
839    try:
840        func(has_connection())
841    except dbus.DBusException:
842        # We can't talk to NM, so no idea.  Wild guess: we're connected
843        # using ssh with X forwarding, and are therefore connected.  This
844        # allows us to proceed with a minimum of complaint.
845        func(True)
846
847
848def install_size():
849    if min_install_size:
850        return min_install_size
851
852    # Fallback size to 5 GB
853    size = 5 * 1024 * 1024 * 1024
854
855    # Maximal size to 8 GB
856    max_size = 8 * 1024 * 1024 * 1024
857
858    try:
859        with open('/cdrom/casper/filesystem.size') as fp:
860            size = int(fp.readline())
861    except IOError:
862        pass
863
864    # TODO substitute into the template for the state box.
865    min_disk_size = size * 2  # fudge factor
866
867    # Set minimum size to 8GB if current minimum size is larger
868    # than 8GB and we still have an extra 20% of free space
869    if min_disk_size > max_size and size * 1.2 < max_size:
870        min_disk_size = max_size
871
872    return min_disk_size
873
874min_install_size = None
875
876# vim:ai:et:sts=4:tw=80:sw=4:
Note: See TracBrowser for help on using the repository browser.