source: ubiquity/trunk/fuentes/bin/ubiquity-dm @ 1475

Last change on this file since 1475 was 1475, checked in by daduve, 3 years ago

Upgrading ubiquity

  • Property svn:executable set to *
File size: 30.2 KB
Line 
1#!/usr/bin/python3
2
3from __future__ import print_function
4
5import errno
6import getpass
7import grp
8import imp
9import os
10import pwd
11import signal
12import subprocess
13import sys
14import sysconfig
15import traceback
16import time
17
18import debconf
19import PAM
20
21sys.path.insert(0, '/usr/lib/ubiquity')
22
23from ubiquity import gsettings, osextras
24from ubiquity.casper import get_casper
25from ubiquity.debconfcommunicator import DebconfCommunicator
26import ubiquity.frontend
27from ubiquity.misc import create_bool, utf8
28
29
30logfile = None
31
32
33def log(msg):
34    print('ubiquity-dm: ' + msg, file=logfile, flush=True)
35
36
37def _pam_conv(auth, query_list, userData):
38    resp = []
39    for query, type in query_list:
40        if type == PAM.PAM_PROMPT_ECHO_ON:
41            val = input(query)
42            resp.append((val, 0))
43        elif type == PAM.PAM_PROMPT_ECHO_OFF:
44            val = getpass.getpass(query)
45            resp.append((val, 0))
46        elif type in (PAM.PAM_PROMPT_ERROR_MSG, PAM.PAM_PROMPT_TEXT_INFO):
47            print(query)
48            resp.append(('', 0))
49        else:
50            return None
51    return resp
52
53
54def set_locale():
55    db = DebconfCommunicator('ubiquity', cloexec=True)
56    locale = ''
57    try:
58        locale = db.get('debian-installer/locale')
59    except debconf.DebconfError:
60        pass
61    db.shutdown()
62
63    if not locale:
64        return
65
66    with open('/etc/default/locale', 'w') as default_locale:
67        print('LANG="%s"' % locale, file=default_locale)
68
69    with open('/etc/environment') as environment:
70        environment_lines = environment.readlines()
71    with open('/etc/environment', 'w') as environment:
72        seen_lang = False
73        for line in environment_lines:
74            if line.startswith('LANG='):
75                print('LANG="%s"' % locale, file=environment)
76                seen_lang = True
77            else:
78                print(line.rstrip('\n'), file=environment)
79        if not seen_lang:
80            print('LANG="%s"' % locale, file=environment)
81
82    with open('/etc/locale.gen', 'w') as locale_gen:
83        print('%s UTF-8' % locale, file=locale_gen)
84
85    subprocess.call(['/usr/sbin/locale-gen', locale],
86                    stdout=logfile, stderr=logfile)
87
88
89def add_ubiquity_kdedir():
90    os.environ['KDEDIRS'] = '/usr/share/ubiquity/qt:' + \
91        os.environ.get('KDEDIRS', '')
92
93
94class XStartupError(EnvironmentError):
95    pass
96
97
98class MissingProgramError(EnvironmentError):
99    pass
100
101
102class DM:
103    def __init__(self, vt, display, default_username):
104        self.auth = PAM.pam()
105        self.vt = vt
106        self.display = display
107        self.server_started = False
108
109        self.username = get_casper('USERNAME', default_username)
110        try:
111            self.uid, self.gid = pwd.getpwnam(self.username)[2:4]
112        except KeyError:
113            import syslog
114            syslog.syslog('Could not find %s, falling back to root.' %
115                          self.username)
116            self.username = 'root'
117            self.uid, self.gid = 0, 0
118        self.homedir = pwd.getpwnam(self.username)[5]
119        self.uid = int(self.uid)
120        self.gid = int(self.gid)
121        self.groups = []
122        for g in grp.getgrall():
123            if self.username in g[3] or g[0] == self.username:
124                self.groups.append(g[2])
125
126        # Look for a frontend module; we won't actually use it (yet), but
127        # this lets us find out which window manager etc. to launch. Be
128        # careful that importing this here will cause the underlying library
129        # to try to talk to the X server, which won't go well.
130        frontend_names = ['gtk_ui', 'kde_ui']
131        self.frontend = None
132        for f in frontend_names:
133            try:
134                imp.find_module(f, ubiquity.frontend.__path__)
135                self.frontend = f
136                break
137            except ImportError:
138                pass
139        else:
140            raise AttributeError('No frontend available; tried %s' %
141                                 ', '.join(frontend_names))
142
143        db = DebconfCommunicator('ubiquity', cloexec=True)
144        try:
145            self.force_failsafe = create_bool(
146                db.get('ubiquity/force_failsafe_graphics'))
147        except debconf.DebconfError:
148            self.force_failsafe = False
149        db.shutdown()
150
151    def sigusr1_handler(self, signum, frame):
152        self.server_started = True
153
154    def active_vt(self):
155        import fcntl
156        import array
157
158        console = os.open('/dev/tty0', os.O_RDONLY | os.O_NOCTTY)
159        try:
160            VT_GETSTATE = 0x5603
161            vt_stat = array.array('H', [0, 0, 0])
162            fcntl.ioctl(console, VT_GETSTATE, vt_stat)
163            return vt_stat[0]
164        finally:
165            os.close(console)
166
167    def drop_privileges(self):
168        os.setgroups(self.groups)
169        os.setgid(self.gid)
170        os.setegid(self.gid)
171        os.setuid(self.uid)
172        os.seteuid(self.uid)
173
174    def server_preexec(self):
175        signal.signal(signal.SIGUSR1, signal.SIG_IGN)
176
177    def run_hooks(self, hookdir):
178        if os.path.isdir(hookdir):
179            # Exclude hooks containing '.', so that *.dpkg-* et al are avoided.
180            hooks = [entry for entry in os.listdir(hookdir)
181                     if '.' not in entry]
182            for hookentry in hooks:
183                hook = os.path.join(hookdir, hookentry)
184                subprocess.call(
185                    hook, stdout=logfile, stderr=logfile,
186                    preexec_fn=self.drop_privileges)
187
188    def pam_open_session(self):
189            self.auth.start('su')
190            self.auth.set_item(PAM.PAM_USER, self.username)
191            self.auth.set_item(PAM.PAM_CONV, _pam_conv)
192            self.auth.putenv('XDG_SESSION_CLASS=greeter')
193            self.auth.putenv('XDG_SEAT=seat0')
194            # at the time pam_open_session is called self.vt is the
195            # correct vt: either the one originally passed as cmd line
196            # arg or as determined by active_vt()
197            #
198            # self.vt is of the form str("vt10")
199            self.auth.putenv('XDG_VTNR=%s' % self.vt[2:])
200            self.auth.authenticate()
201            self.auth.open_session()
202            os.environ.update(
203                [i.split('=', 1) for i in self.auth.getenvlist()])
204
205    def pam_close_session(self):
206        if self.auth:
207            self.auth.close_session()
208            self.auth = None
209
210    def run(self, *program):
211        # Extract the program basename to see if we are in oem-config or
212        # ubiquity.
213        program_basename = os.path.basename(program[0])
214
215        extras = []
216        null = open('/dev/null', 'w')
217        log('starting')
218
219        signal.signal(signal.SIGUSR1, self.sigusr1_handler)
220        signal.signal(signal.SIGTTIN, signal.SIG_IGN)
221        signal.signal(signal.SIGTTOU, signal.SIG_IGN)
222
223        servercommand = ['X', '-br', '-ac', '-noreset', '-nolisten', 'tcp']
224
225        log('plymouth')
226        try:
227            plymouth_running = subprocess.call(['plymouth', '--ping']) == 0
228        except OSError:
229            plymouth_running = False
230        if plymouth_running:
231            subprocess.call(['plymouth', 'deactivate'])
232            if subprocess.call(['plymouth', '--has-active-vt']) == 0:
233                self.vt = 'vt%d' % self.active_vt()
234                servercommand.extend(['-background', 'none'])
235            else:
236                subprocess.call(['plymouth', 'quit'])
237                plymouth_running = False
238
239        servercommand.extend([self.vt, self.display])
240
241        log('start X {}'.format(servercommand))
242        for attempt in ('main', 'fbdev', 'vesa'):
243            command = list(servercommand)
244            if attempt == 'main' and self.force_failsafe:
245                continue
246            elif attempt != 'main':
247                # TODO cjwatson 2010-02-11: This is a bodge.  The
248                # duplication is nasty, but fortunately bullet-proof X
249                # actually turns out not to be very complicated nowadays.
250                # Most of the complexity is in the fallback session, which I
251                # haven't attempted to integrate here, so you won't get
252                # things like interactive reconfiguration.  I believe Evan
253                # is working on doing that, but is blocked on a couple of
254                # Upstart bugs; once all that's resolved, we should back
255                # this out.
256                if attempt == 'fbdev' and not os.path.exists('/dev/fb0'):
257                    continue
258                xorg_conf_failsafe = '/etc/X11/xorg.conf.failsafe'
259                command.extend(['-config', xorg_conf_failsafe])
260                command.extend(['-logfile', '/var/log/Xorg.%s.log' % attempt])
261
262                with open(xorg_conf_failsafe, 'w') as xorg_conf_failsafe_file:
263                    print('''\
264Section "Device"
265\tIdentifier    "Configured Video Device"
266\tDriver                "%s"
267EndSection
268
269Section "Monitor"
270\tIdentifier    "Configured Monitor"
271EndSection
272
273Section "Screen"
274\tIdentifier    "Default Screen"
275\tMonitor               "Configured Monitor"
276\tDevice                "Configured Video Device"
277EndSection
278''' % attempt, file=xorg_conf_failsafe_file)
279
280            server = subprocess.Popen(
281                command, stdin=null, stdout=logfile, stderr=logfile,
282                preexec_fn=self.server_preexec)
283
284            # Really we should select on a pipe or something, but it's not
285            # worth the effort for now.
286            try:
287                timeout = 60
288                while not self.server_started:
289                    status = server.poll()
290                    if type(status) is int and status != 0:
291                        if plymouth_running:
292                            subprocess.call(['plymouth', 'quit'])
293                        raise XStartupError('X server exited with return '
294                                            'code ' + str(status))
295                    if timeout == 0:
296                        if plymouth_running:
297                            subprocess.call(['plymouth', 'quit'])
298                        raise XStartupError('X server failed to start after 60'
299                                            ' seconds')
300                    time.sleep(1)
301                    timeout -= 1
302                if plymouth_running:
303                    subprocess.call(['plymouth', 'quit', '--retain-splash'])
304            except XStartupError:
305                if attempt == 'vesa':
306                    raise
307
308            if self.server_started:
309                break
310
311        log('set vars')
312        os.environ['DISPLAY'] = self.display
313        os.environ['HOME'] = self.homedir
314        # Give ubiquity a UID and GID that it can drop privileges to.
315        os.environ['PKEXEC_UID'] = str(self.uid)
316        os.environ['GVFS_DISABLE_FUSE'] = '1'
317        # Overlay scrollbars are now a gtk module
318        os.environ['GTK_MODULES'] = 'overlay-scrollbar'
319
320        log('pam_open_session')
321        self.pam_open_session()
322
323        # run simple, custom scripts during install time
324        if program_basename == 'ubiquity':
325            log('dm-scripts')
326            self.run_hooks('/usr/lib/ubiquity/dm-scripts/install')
327
328        # run simple, custom scripts during  oem-config
329        if program_basename == 'oem-config-wrapper':
330            log('oem dm-scripts')
331            self.run_hooks('/usr/lib/ubiquity/dm-scripts/oem')
332
333        # Session bus, apparently needed by most interfaces now
334        if ('DBUS_SESSION_BUS_ADDRESS' not in os.environ and
335                osextras.find_on_path('dbus-launch')):
336            log('dbus')
337            dbus_subp = subprocess.Popen(
338                ['dbus-launch', '--exit-with-session'],
339                stdin=null, stdout=subprocess.PIPE, stderr=logfile,
340                preexec_fn=self.drop_privileges, universal_newlines=True)
341            for line in dbus_subp.stdout:
342                try:
343                    name, value = line.rstrip('\n').split('=', 1)
344                    os.environ[name] = value
345                except ValueError:
346                    pass
347            dbus_subp.stdout.close()
348            dbus_subp.wait()
349
350        # dconf writer
351        if os.path.exists("/usr/lib/dconf/dconf-service"):
352            log('dconf-service')
353            extras.append(subprocess.Popen(
354                ['/usr/lib/dconf/dconf-service'],
355                stdin=null, stdout=logfile, stderr=logfile,
356                preexec_fn=self.drop_privileges))
357
358        # Accessibility infrastructure
359        proc_cmdline = []
360        with open('/proc/cmdline', 'r') as fp:
361            proc_cmdline = fp.readline().split()
362
363        log('start frontend {}'.format(self.frontend))
364        if self.frontend == 'gtk_ui':
365            # Set a desktop wallpaper.
366            visual_a11y = 'access=v' in proc_cmdline
367
368            background_image = None
369            for background in (
370                    '/usr/share/xfce4/backdrops/xubuntu-wallpaper.png',
371                    '/usr/share/backgrounds/'
372                    'ubuntustudio/ubuntustudio-default.png',
373                    '/usr/share/lubuntu/wallpapers/'
374                    'lubuntu-default-wallpaper.png'):
375                exists = os.access(background, os.R_OK)
376                if exists:
377                    background_image = background
378                    break
379
380            accessibility = False
381            if gsettings._gsettings_exists():
382                accessibility = gsettings.get(
383                    'org.gnome.desktop.interface', 'toolkit-accessibility',
384                    self.username)
385
386                # Set gsettings keys
387                gsettings_keys = [
388                    ('org.gnome.desktop.lockdown', 'disable-lock-screen',
389                     'true'),
390                    ('org.gnome.desktop.lockdown', 'disable-user-switching',
391                     'true'),
392                    ('org.gnome.settings-daemon.plugins.background', 'active',
393                     'true'),
394                    ('org.gnome.desktop.background', 'draw-background',
395                     'true'),
396                    ('org.gnome.desktop.background', 'show-desktop-icons',
397                     'false'),
398                    ('org.gnome.metacity', 'compositing-manager',
399                     'true'),
400                    ('org.gnome.desktop.wm.preferences', 'num-workspaces',
401                     '1'),
402                ]
403
404                # Setting a wallpaper image, or solid color.
405                if visual_a11y:
406                    gsettings_keys.append(
407                        ('org.gnome.desktop.background', 'picture-options',
408                         'none'))
409                    gsettings_keys.append(
410                        ('org.gnome.desktop.background', 'picture-uri',
411                         "''"))
412
413                if osextras.find_on_path('marco'):
414                    gsettings_keys = [
415                        ('org.mate.lockdown', 'disable-lock-screen',
416                         'true'),
417                        ('org.mate.lockdown', 'disable-user-switching',
418                         'true'),
419                        ('org.mate.SettingsDaemon.plugins.background',
420                         'active', 'true'),
421                        ('org.mate.background', 'draw-background',
422                         'true'),
423                        ('org.mate.background', 'show-desktop-icons',
424                         'false'),
425                        ('org.mate.Marco.general', 'compositing-manager',
426                         'true'),
427                        ('org.mate.Marco.general', 'num-workspaces',
428                         '1'),
429                    ]
430
431                    # Setting a wallpaper image, or solid color.
432                    if visual_a11y:
433                        gsettings_keys.append(
434                            ('org.mate.background', 'picture-options',
435                             'none'))
436                        gsettings_keys.append(
437                            ('org.mate.background', 'picture-filename',
438                             "''"))
439
440                if osextras.find_on_path('gnome-shell'):
441                    gsettings_keys.append(
442                        ('org.gnome.settings-daemon.plugins.background',
443                         'active', 'false'))
444                    gsettings_keys.remove(
445                        ('org.gnome.desktop.wm.preferences', 'num-workspaces',
446                         '1'))
447
448                for gs_schema, gs_key, gs_value in gsettings_keys:
449                    subprocess.call(
450                        ['gsettings', 'set', gs_schema, gs_key, gs_value],
451                        stdin=null, stdout=logfile, stderr=logfile,
452                        preexec_fn=self.drop_privileges)
453
454                usd = '/usr/lib/unity-settings-daemon/unity-settings-daemon'
455                gsd = '/usr/lib/gnome-settings-daemon/gnome-settings-daemon'
456                msd = '/usr/bin/mate-settings-daemon'
457
458                if osextras.find_on_path(usd):
459                    extras.append(subprocess.Popen(
460                        [usd], stdin=null, stdout=logfile, stderr=logfile,
461                        preexec_fn=self.drop_privileges))
462
463                elif osextras.find_on_path(gsd):
464                    extras.append(subprocess.Popen(
465                        [gsd], stdin=null, stdout=logfile, stderr=logfile,
466                        preexec_fn=self.drop_privileges))
467
468                elif osextras.find_on_path(msd):
469                    extras.append(subprocess.Popen(
470                        [msd], stdin=null, stdout=logfile, stderr=logfile,
471                        preexec_fn=self.drop_privileges))
472
473                elif background_image and osextras.find_on_path('feh'):
474                    subprocess.call(
475                        ['feh', '--bg-fill', background_image],
476                        stdin=null, stdout=logfile, stderr=logfile,
477                        preexec_fn=self.drop_privileges)
478
479            if (accessibility or 'maybe-ubiquity' in proc_cmdline or
480                    'only-ubiquity' in proc_cmdline or
481                    program_basename == 'oem-config-wrapper'):
482                launcher = '/usr/lib/at-spi2-core/at-spi-bus-launcher'
483                if os.path.exists(launcher):
484                    extras.append(subprocess.Popen(
485                        [launcher, '--launch-immediately'],
486                        stdin=null, stdout=logfile, stderr=logfile,
487                        preexec_fn=self.drop_privileges))
488                    os.environ['GTK_MODULES'] += os.pathsep + 'gail'
489
490            if osextras.find_on_path('gnome-shell'):
491                wm_cmd = ['gnome-shell', '--sm-disable', '--mode=ubiquity']
492            elif osextras.find_on_path('marco'):
493                wm_cmd = ['marco', '--sm-disable']
494            elif osextras.find_on_path('metacity'):
495                wm_cmd = ['metacity', '--sm-disable']
496            elif osextras.find_on_path('xfwm4'):
497                wm_cmd = ['xfwm4', '--compositor=off', '--sm-client-disable']
498            elif osextras.find_on_path('matchbox-window-manager'):
499                wm_cmd = ['matchbox-window-manager']
500            elif osextras.find_on_path('openbox-lubuntu'):
501                wm_cmd = ['openbox-lubuntu']
502            elif osextras.find_on_path('openbox'):
503                wm_cmd = ['openbox']
504            elif osextras.find_on_path('compiz'):
505                wm_cmd = ['compiz', '--sm-disable', 'decor', 'resize', 'place',
506                          'move']
507            else:
508                raise MissingProgramError(
509                    'No window manager found (tried '
510                    'marco, metacity, xfwm4, matchbox-window-manager, '
511                    'openbox-lubuntu, openbox, compiz)')
512
513            wm = subprocess.Popen(
514                wm_cmd, stdin=null, stdout=logfile, stderr=logfile,
515                preexec_fn=self.drop_privileges)
516
517            if osextras.find_on_path('xfsettingsd'):
518                extras.append(subprocess.Popen(
519                    ['xprop', '-root', '-format', '_NET_NUMBER_OF_DESKTOPS',
520                     '32c', '-set', '_NET_NUMBER_OF_DESKTOPS', '1'],
521                    stdin=null, stdout=logfile, stderr=logfile,
522                    preexec_fn=self.drop_privileges))
523                extras.append(subprocess.Popen(
524                    ['xfsettingsd', '--sm-client-disable'],
525                    stdin=null, stdout=logfile, stderr=logfile,
526                    preexec_fn=self.drop_privileges))
527
528            if osextras.find_on_path('lxsession'):
529                extras.append(subprocess.Popen(
530                    ['lxsession', '-s', 'Lubuntu', '-e', 'LXDE', '-a'],
531                    stdin=null, stdout=logfile, stderr=logfile,
532                    preexec_fn=self.drop_privileges))
533
534            if os.path.exists('/usr/lib/ubiquity/panel'):
535                if ("openbox-lubuntu" not in wm_cmd and
536                        "openbox" not in wm_cmd and
537                        "gnome-shell" not in wm_cmd):
538                    multiarchdir = os.path.split(
539                        sysconfig.get_config_var('multiarchsubdir'))[-1]
540                    indicators = list(filter(os.path.isfile, [
541                        os.path.join('/usr/lib', multiarchdir, i) for i in (
542                            'indicator-application/'
543                            'indicator-application-service',
544                            'indicator-session/indicator-session-service',
545                            'indicator-sound/indicator-sound-service',
546                            'indicator-bluetooth/indicator-bluetooth-service',
547                            'indicator-keyboard/indicator-keyboard-service',
548                            'indicator-keyboard-service',
549                            'indicator-power/indicator-power-service',
550                        )]))
551                    extras.append(subprocess.Popen(
552                        ['/usr/lib/ubiquity/panel'],
553                        stdin=null, stdout=logfile, stderr=logfile,
554                        preexec_fn=self.drop_privileges))
555                    for indicator in indicators:
556                        extras.append(subprocess.Popen(
557                            [indicator],
558                            stdin=null, stdout=logfile, stderr=logfile,
559                            preexec_fn=self.drop_privileges))
560
561            if (osextras.find_on_path('nm-applet') and
562                    "gnome-shell" not in wm_cmd):
563                extras.append(subprocess.Popen(
564                    ['nm-applet'],
565                    stdin=null, stdout=logfile, stderr=logfile,
566                    preexec_fn=self.drop_privileges))
567
568            if osextras.find_on_path('ibus-daemon'):
569                extras.append(subprocess.Popen(
570                    ['ibus-daemon'],
571                    stdin=null, stdout=logfile, stderr=logfile,
572                    preexec_fn=self.drop_privileges))
573
574            # Simply start bluetooth-applet, ubiquity-bluetooth-agent will
575            # override it from casper to make sure it also covers the regular
576            # live session
577            if osextras.find_on_path('bluetooth-applet'):
578                extras.append(subprocess.Popen(
579                    ['bluetooth-applet'],
580                    stdin=null, stdout=logfile, stderr=logfile,
581                    preexec_fn=self.drop_privileges))
582
583            # Accessibility tools
584            if accessibility:
585                # FIXME: launch onboard, when touch screen detected
586                if 'access=m2' in proc_cmdline:
587                    if osextras.find_on_path('onboard'):
588                        extras.append(subprocess.Popen(
589                            ['onboard'],
590                            stdin=null, stdout=logfile, stderr=logfile,
591                            preexec_fn=self.drop_privileges))
592                else:
593                    if osextras.find_on_path('orca'):
594                        time.sleep(15)
595                        extras.append(subprocess.Popen(
596                            ['orca'],
597                            stdin=null, stdout=logfile, stderr=logfile,
598                            preexec_fn=self.drop_privileges))
599        elif self.frontend == 'kde_ui':
600            # Force Qt5 KDE theming to load for kwin and friends.
601            os.environ["QT_QPA_PLATFORMTHEME"] = "kde"
602            if 'access=v1' not in proc_cmdline:
603                log('paint background')
604                path = \
605                    '/usr/share/wallpapers/Next/contents/images/2560x1600.png'
606                extras.append(subprocess.Popen(
607                    ['ubiquity-qtsetbg', path],
608                    stdin=null, stdout=logfile, stderr=logfile,
609                    preexec_fn=self.drop_privileges))
610
611            log("add_ubiquity_kdedir")
612            add_ubiquity_kdedir()
613            log('start kde4breeze')
614            if osextras.find_on_path('kf5-config'):
615                output = subprocess.check_output(
616                    ['kf5-config', '--path', 'lib'],
617                    preexec_fn=self.drop_privileges)
618                output = output.decode()
619                output = output.replace('\n', '')
620                output = output.split(':')[1]
621                breeze = subprocess.Popen(
622                    [output + '/kconf_update_bin/kde4breeze'],
623                    stdin=null, stdout=logfile, stderr=logfile,
624                    preexec_fn=self.drop_privileges)
625                ret = breeze.wait()
626                log('kde4breeze exited with code {}'.format(ret))
627                if ret != 0:
628                    raise
629            else:
630                raise
631            log('start kwin')
632            if osextras.find_on_path('kwin'):
633                wm_cmd = ['kwin']
634            elif osextras.find_on_path('kwin_x11'):
635                wm_cmd = ['kwin_x11']
636            wm = subprocess.Popen(
637                wm_cmd, stdin=null, stdout=logfile, stderr=logfile,
638                preexec_fn=self.drop_privileges)
639
640        log('start greeter')
641        greeter = subprocess.Popen(
642            program, stdin=null, stdout=logfile, stderr=logfile)
643        ret = greeter.wait()
644        log('greeter exited with code {}'.format(ret))
645
646        reboot = False
647        if ret != 0:
648            db = DebconfCommunicator('ubiquity', cloexec=True)
649            try:
650                error_cmd = db.get('ubiquity/failure_command')
651                if error_cmd:
652                    subprocess.call(['sh', '-c', error_cmd])
653            except debconf.DebconfError:
654                pass
655
656            reboot = False
657            try:
658                if '--automatic' in program:
659                    reboot = db.get('ubiquity/reboot_on_failure') == 'true'
660            except debconf.DebconfError:
661                pass
662
663            if reboot:
664                question = 'ubiquity/install_failed_reboot'
665            else:
666                question = 'ubiquity/install_failed'
667            title = ''
668            message = ''
669            try:
670                title = utf8(db.metaget(question, 'description'),
671                             errors='replace')
672                message = utf8(db.metaget(question, 'extended_description'),
673                               errors='replace')
674            except debconf.DebconfError:
675                pass
676            db.shutdown()
677
678            if title and message:
679                if self.frontend == 'gtk_ui':
680                    cmd = ['zenity', '--error', '--title=%s' % title,
681                           '--text=%s' % message]
682                    subprocess.call(cmd)
683                elif self.frontend == 'kde_ui':
684                    cmd = ['kdialog', '--title=%s' % title,
685                           '--msgbox=%s' % message]
686                    subprocess.call(cmd)
687                else:
688                    # Not ideal, but if we cannot let the user know what's
689                    # going on, it's best to drop them into a desktop and let
690                    # them figure it out.
691                    reboot = False
692
693        # Revert gnome-settings to default, for dropping to desktop
694        if self.frontend == 'gtk_ui' and gsettings._gsettings_exists():
695            for gs_schema, gs_key, gs_value in gsettings_keys:
696                subprocess.call(
697                    ['gsettings', 'reset', gs_schema, gs_key],
698                    stdin=null, stdout=logfile, stderr=logfile,
699                    preexec_fn=self.drop_privileges)
700
701        def kill_if_exists(pid, signum):
702            try:
703                os.kill(pid, signum)
704            except OSError as e:
705                if e.errno != errno.ESRCH:
706                    raise
707
708        def sigalrm_handler(signum, frame):
709            kill_if_exists(wm.pid, signal.SIGKILL)
710            for extra in extras:
711                kill_if_exists(extra.pid, signal.SIGKILL)
712
713        kill_if_exists(wm.pid, signal.SIGTERM)
714        for extra in extras:
715            kill_if_exists(extra.pid, signal.SIGTERM)
716        signal.signal(signal.SIGALRM, sigalrm_handler)
717        signal.alarm(1)  # low patience with WMs failing to exit on demand
718        processes = set(extras)
719        processes.add(wm)
720        while processes:
721            done = set()
722            for process in processes:
723                try:
724                    process.wait()
725                    done.add(process)
726                except OSError as e:
727                    if e.errno == errno.EINTR:
728                        continue
729                    raise
730            processes -= done
731        signal.alarm(0)
732
733        # Clear the console so we don't see boot-time messages on switch
734        try:
735            with open('/dev/tty' + self.vt[2:], 'r+') as vthandle:
736                subprocess.call(['clear'], stdin=vthandle, stdout=vthandle)
737        except IOError:
738            pass
739
740        kill_if_exists(server.pid, signal.SIGTERM)
741        server.wait()
742
743        null.close()
744
745        if reboot:
746            subprocess.Popen(['reboot'])
747        if ret is not None and ret >= 0:
748            return ret
749        else:
750            return 1
751
752
753def run(vt, display, username):
754    try:
755        dm = DM(vt, display, username)
756    except XStartupError:
757        log("XStartupError")
758        return 1
759    ret = dm.run(*sys.argv[4:])
760    if ret == 0:
761        log("set_locale")
762        set_locale()
763    dm.pam_close_session()
764    return ret
765
766
767def main():
768    global logfile
769
770    if len(sys.argv) < 4:
771        sys.stderr.write('Usage: %s <vt[1-N]> <:[0-N]> <username> <program> '
772                         '[<arguments>]\n' % sys.argv[0])
773        return 1
774    vt, display, username = sys.argv[1:4]
775
776    try:
777        os.makedirs('/var/log/installer')
778    except OSError as e:
779        # be happy if someone already created the path
780        if e.errno != errno.EEXIST:
781            raise
782    logfile = open('/var/log/installer/dm', 'w')
783    try:
784        ret = run(vt, display, username)
785        log('Exiting with code {}'.format(ret))
786    except Exception:
787        log('Failed with an exception:')
788        log(traceback.format_exc())
789        return 1
790
791if __name__ == '__main__':
792    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.