Advertisement
Guest User

Prcise ubiquity-dm

a guest
Jan 4th, 2013
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.38 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. import os
  4. import sys
  5. import subprocess
  6. import time
  7. import signal
  8. import errno
  9. import imp
  10. import grp
  11. import pwd
  12.  
  13. import debconf
  14.  
  15. sys.path.insert(0, '/usr/lib/ubiquity')
  16.  
  17. import ubiquity.frontend
  18. from ubiquity import osextras
  19. from ubiquity import gsettings
  20. from ubiquity.misc import create_bool
  21. from ubiquity.casper import get_casper
  22. from ubiquity.debconfcommunicator import DebconfCommunicator
  23.  
  24. def ck_open_session(uid):
  25. import dbus
  26. bus = dbus.SystemBus ()
  27. manager_obj = bus.get_object ('org.freedesktop.ConsoleKit',
  28. '/org/freedesktop/ConsoleKit/Manager')
  29. manager = dbus.Interface (manager_obj, 'org.freedesktop.ConsoleKit.Manager')
  30. params = dbus.Array ([], signature = "(sv)")
  31. params.append(("unix-user", dbus.Int32(uid)))
  32. params.append(("session-type", dbus.String("")))
  33. params.append(("x11-display", dbus.String(os.environ['DISPLAY'])))
  34. params.append(("x11-display-device", dbus.String('/dev/tty7')))
  35. params.append(("is-local", dbus.Boolean(True)))
  36. cookie = manager.OpenSessionWithParameters(params)
  37. os.environ['XDG_SESSION_COOKIE'] = cookie
  38.  
  39. def set_locale():
  40. db = DebconfCommunicator('ubiquity', cloexec=True)
  41. locale = ''
  42. try:
  43. locale = db.get('debian-installer/locale')
  44. except debconf.DebconfError:
  45. pass
  46. db.shutdown()
  47.  
  48. if not locale:
  49. return
  50.  
  51. default_locale = open('/etc/default/locale', 'w')
  52. print >>default_locale, 'LANG="%s"' % locale
  53. default_locale.close()
  54.  
  55. environment = open('/etc/environment')
  56. environment_lines = environment.readlines()
  57. environment.close()
  58. environment = open('/etc/environment', 'w')
  59. seen_lang = False
  60. for line in environment_lines:
  61. if line.startswith('LANG='):
  62. print >>environment, 'LANG="%s"' % locale
  63. seen_lang = True
  64. else:
  65. print >>environment, line.rstrip('\n')
  66. if not seen_lang:
  67. print >>environment, 'LANG="%s"' % locale
  68. environment.close()
  69.  
  70. locale_gen = open('/etc/locale.gen', 'w')
  71. print >>locale_gen, '%s UTF-8' % locale
  72. locale_gen.close()
  73.  
  74. logfile = open('/var/log/installer/dm', 'a')
  75. subprocess.call(['/usr/sbin/locale-gen', locale],
  76. stdout=logfile, stderr=logfile)
  77. logfile.close()
  78.  
  79. class XStartupError(EnvironmentError):
  80. pass
  81.  
  82. class MissingProgramError(EnvironmentError):
  83. pass
  84.  
  85. class DM:
  86. def __init__(self, vt, display, default_username):
  87. self.vt = vt
  88. self.display = display
  89. self.server_started = False
  90.  
  91. self.username = get_casper('USERNAME', default_username)
  92. try:
  93. self.uid, self.gid = pwd.getpwnam(self.username)[2:4]
  94. except KeyError:
  95. import syslog
  96. syslog.syslog('Could not find %s, falling back to root.' %
  97. self.username)
  98. self.username = 'root'
  99. self.uid, self.gid = 0, 0
  100. os.environ['SUDO_USER'] = self.username
  101. self.homedir = pwd.getpwnam(self.username)[5]
  102. self.uid = int(self.uid)
  103. self.gid = int(self.gid)
  104. self.groups = []
  105. for g in grp.getgrall():
  106. if self.username in g[3] or g[0] == self.username:
  107. self.groups.append(g[2])
  108.  
  109. # Look for a frontend module; we won't actually use it (yet), but
  110. # this lets us find out which window manager etc. to launch. Be
  111. # careful that importing this here will cause the underlying library
  112. # to try to talk to the X server, which won't go well.
  113. frontend_names = ['gtk_ui', 'kde_ui']
  114. self.frontend = None
  115. for f in frontend_names:
  116. try:
  117. imp.find_module(f, ubiquity.frontend.__path__)
  118. self.frontend = f
  119. break
  120. except ImportError:
  121. pass
  122. else:
  123. raise AttributeError('No frontend available; tried %s' %
  124. ', '.join(frontend_names))
  125.  
  126. db = DebconfCommunicator('ubiquity', cloexec=True)
  127. try:
  128. self.force_failsafe = create_bool(db.get('ubiquity/force_failsafe_graphics'))
  129. except debconf.DebconfError:
  130. self.force_failsafe = False
  131. db.shutdown()
  132.  
  133. def sigusr1_handler(self, signum, frame):
  134. self.server_started = True
  135.  
  136. def active_vt(self):
  137. import fcntl
  138. import array
  139.  
  140. console = os.open('/dev/tty0', os.O_RDONLY | os.O_NOCTTY)
  141. try:
  142. VT_GETSTATE = 0x5603
  143. vt_stat = array.array('H', [0, 0, 0])
  144. fcntl.ioctl(console, VT_GETSTATE, vt_stat)
  145. return vt_stat[0]
  146. finally:
  147. os.close(console)
  148.  
  149. def drop_privileges(self):
  150. os.setgroups(self.groups)
  151. os.setgid(self.gid)
  152. os.setuid(self.uid)
  153.  
  154. def server_preexec(self):
  155. signal.signal(signal.SIGUSR1, signal.SIG_IGN)
  156.  
  157. def run_hooks(self, hookdir):
  158. if os.path.isdir(hookdir):
  159. # Exclude hooks containing '.', so that *.dpkg-* et al are avoided.
  160. hooks = [entry for entry in os.listdir(hookdir)
  161. if '.' not in entry]
  162. for hookentry in hooks:
  163. hook = os.path.join(hookdir, hookentry)
  164. with open('/var/log/installer/dm', 'a') as logfile:
  165. subprocess.call(
  166. hook, stdout=logfile, stderr=logfile,
  167. preexec_fn=self.drop_privileges)
  168.  
  169. def run(self, *program):
  170. # extract the program basename to see if we are in oem-config or ubiquity
  171. program_basename = os.path.basename(program[0])
  172.  
  173. null = open('/dev/null', 'w')
  174. try:
  175. os.makedirs('/var/log/installer')
  176. except OSError, e:
  177. # be happy if someone already created the path
  178. if e.errno != errno.EEXIST:
  179. raise
  180. logfile = open('/var/log/installer/dm', 'w')
  181.  
  182. signal.signal(signal.SIGUSR1, self.sigusr1_handler)
  183. signal.signal(signal.SIGTTIN, signal.SIG_IGN)
  184. signal.signal(signal.SIGTTOU, signal.SIG_IGN)
  185.  
  186. servercommand = ['X', '-br', '-ac', '-noreset', '-nolisten', 'tcp']
  187.  
  188. try:
  189. plymouth_running = subprocess.call(['plymouth', '--ping']) == 0
  190. except OSError:
  191. plymouth_running = False
  192. if plymouth_running:
  193. subprocess.call(['plymouth', 'deactivate'])
  194. if subprocess.call(['plymouth', '--has-active-vt']) == 0:
  195. self.vt = 'vt%d' % self.active_vt()
  196. servercommand.append('-nr')
  197. else:
  198. subprocess.call(['plymouth', 'quit'])
  199. plymouth_running = False
  200.  
  201. servercommand.extend([self.vt, self.display])
  202.  
  203. for attempt in ('main', 'fbdev', 'vesa'):
  204. command = list(servercommand)
  205. if attempt == 'main' and self.force_failsafe:
  206. continue
  207. elif attempt != 'main':
  208. # TODO cjwatson 2010-02-11: This is a bodge. The
  209. # duplication is nasty, but fortunately bullet-proof X
  210. # actually turns out not to be very complicated nowadays.
  211. # Most of the complexity is in the fallback session, which I
  212. # haven't attempted to integrate here, so you won't get
  213. # things like interactive reconfiguration. I believe Evan
  214. # is working on doing that, but is blocked on a couple of
  215. # Upstart bugs; once all that's resolved, we should back
  216. # this out.
  217. if attempt == 'fbdev' and not os.path.exists('/dev/fb0'):
  218. continue
  219. xorg_conf_failsafe = '/etc/X11/xorg.conf.failsafe'
  220. command.extend(['-config', xorg_conf_failsafe])
  221. command.extend(['-logfile', '/var/log/Xorg.%s.log' % attempt])
  222.  
  223. xorg_conf_failsafe_file = open(xorg_conf_failsafe, 'w')
  224. print >>xorg_conf_failsafe_file, '''\
  225. Section "Device"
  226. Identifier "Configured Video Device"
  227. Driver "%s"
  228. EndSection
  229.  
  230. Section "Monitor"
  231. Identifier "Configured Monitor"
  232. EndSection
  233.  
  234. Section "Screen"
  235. Identifier "Default Screen"
  236. Monitor "Configured Monitor"
  237. Device "Configured Video Device"
  238. EndSection
  239. ''' % attempt
  240. xorg_conf_failsafe_file.close()
  241.  
  242. server = subprocess.Popen(
  243. command, stdin=null, stdout=logfile, stderr=logfile,
  244. preexec_fn=self.server_preexec)
  245.  
  246. # Really we should select on a pipe or something, but it's not
  247. # worth the effort for now.
  248. try:
  249. timeout = 60
  250. while not self.server_started:
  251. status = server.poll()
  252. if type(status) is int and status != 0:
  253. if plymouth_running:
  254. subprocess.call(['plymouth', 'quit'])
  255. raise XStartupError('X server exited with return code '
  256. + str(status))
  257. if timeout == 0:
  258. if plymouth_running:
  259. subprocess.call(['plymouth', 'quit'])
  260. raise XStartupError('X server failed to start after 60'
  261. ' seconds')
  262. time.sleep(1)
  263. timeout -= 1
  264. if plymouth_running:
  265. subprocess.call(['plymouth', 'quit', '--retain-splash'])
  266. except XStartupError:
  267. if attempt == 'vesa':
  268. raise
  269.  
  270. if self.server_started:
  271. break
  272.  
  273. os.environ['DISPLAY'] = self.display
  274. os.environ['HOME'] = self.homedir
  275. # Give ubiquity a UID and GID that it can drop privileges to.
  276. os.environ['SUDO_UID'] = str(self.uid)
  277. os.environ['SUDO_GID'] = str(self.gid)
  278. os.environ['GVFS_DISABLE_FUSE' ] = '1'
  279.  
  280. ck_open_session(self.uid)
  281.  
  282. # run simple, custom scripts during install time
  283. if program_basename == 'ubiquity':
  284. self.run_hooks('/usr/lib/ubiquity/dm-scripts/install')
  285.  
  286. # run simple, custom scripts during oem-config
  287. if program_basename == 'oem-config-wrapper':
  288. self.run_hooks('/usr/lib/ubiquity/dm-scripts/oem')
  289.  
  290. # Session bus, apparently needed by most interfaces now
  291. if ('DBUS_SESSION_BUS_ADDRESS' not in os.environ and
  292. osextras.find_on_path('dbus-launch')):
  293. dbus_subp = subprocess.Popen(
  294. ['dbus-launch', '--exit-with-session'],
  295. stdin=null, stdout=subprocess.PIPE, stderr=logfile,
  296. preexec_fn=self.drop_privileges)
  297. for line in dbus_subp.stdout:
  298. try:
  299. name, value = line.rstrip('\n').split('=', 1)
  300. os.environ[name] = value
  301. except ValueError:
  302. pass
  303. dbus_subp.stdout.close()
  304. dbus_subp.wait()
  305.  
  306. gconfd_running = False
  307. if (self.frontend == 'gtk_ui' and
  308. osextras.find_on_path('gconftool-2')):
  309. subprocess.call(['gconftool-2', '--spawn'],
  310. stdin=null, stdout=logfile, stderr=logfile,
  311. preexec_fn=self.drop_privileges)
  312. gconfd_running = True
  313.  
  314. extras = []
  315. if self.frontend == 'gtk_ui':
  316. gconf_dir = ('xml:readwrite:%s' %
  317. os.path.expanduser('~%s/.gconf' %
  318. self.username))
  319. accessibility = False
  320. if (osextras.find_on_path('gconftool-2') and
  321. gsettings._gsettings_exists()):
  322. # Set number of workspaces to 1 in metacity
  323. # (still using gconf, GNOME: #621204)
  324. subprocess.call(
  325. ['gconftool-2', '--config-source', gconf_dir,
  326. '--type', 'int', '--set',
  327. '/apps/metacity/general/num_workspaces', '1',],
  328. stdin=null, stdout=logfile, stderr=logfile,
  329. preexec_fn=self.drop_privileges)
  330.  
  331. # Set gsettings keys
  332. gsettings_keys = [
  333. ('org.gnome.desktop.lockdown', 'disable-lock-screen', 'true'),
  334. ('org.gnome.desktop.lockdown', 'disable-user-switching', 'true'),
  335. ]
  336. for gs_schema, gs_key, gs_value in gsettings_keys:
  337. gsettings.set(gs_schema, gs_key, gs_value, self.username)
  338.  
  339. accessibility = gsettings.get('org.gnome.desktop.interface',
  340. 'toolkit-accessibility', self.username)
  341. # Accessibility infrastructure
  342. with open('/proc/cmdline', 'r') as fp:
  343. if (accessibility == True or 'maybe-ubiquity' in fp.readline()):
  344. if os.path.exists('/usr/lib/at-spi2-core/at-spi-bus-launcher'):
  345. extras.append(subprocess.Popen(
  346. ['/usr/lib/at-spi2-core/at-spi-bus-launcher',
  347. '--launch-immediately'],
  348. stdin=null, stdout=logfile, stderr=logfile,
  349. preexec_fn=self.drop_privileges))
  350. os.environ['GTK_MODULES'] = 'gail:atk-bridge'
  351.  
  352. # Set a desktop wallpaper.
  353. with open('/proc/cmdline', 'r') as fp:
  354. for background in ('/usr/share/backgrounds/edubuntu_default.png',
  355. '/usr/share/xfce4/backdrops/macinnis_wallpaper.png',
  356. '/usr/share/xfce4/backdrops/xubuntu-precise-right.png',
  357. '/usr/share/backgrounds/warty-final-ubuntu.png'):
  358. exists = os.access(background, os.R_OK)
  359. if (exists and not 'access=v1' in fp.readline()):
  360. extras.append(subprocess.Popen(['/usr/lib/ubiquity/wallpaper', background],
  361. stdin=null, stdout=logfile, stderr=logfile,
  362. preexec_fn=self.drop_privileges))
  363. break
  364.  
  365. if self.frontend == 'gtk_ui':
  366. if gconfd_running and osextras.find_on_path('metacity'):
  367. wm_cmd = ['metacity', '--sm-disable']
  368. elif osextras.find_on_path('xfwm4'):
  369. wm_cmd = ['xfwm4']
  370. elif osextras.find_on_path('matchbox-window-manager'):
  371. wm_cmd = ['matchbox-window-manager']
  372. elif osextras.find_on_path('openbox-lubuntu'):
  373. wm_cmd = ['openbox-lubuntu']
  374. elif osextras.find_on_path('openbox'):
  375. wm_cmd = ['openbox']
  376. else:
  377. raise MissingProgramError('No window manager found (tried '
  378. 'metacity, xfwm4, matchbox-window-manager, '
  379. 'openbox-lubuntu, openbox)')
  380. wm = subprocess.Popen(wm_cmd,
  381. stdin=null, stdout=logfile, stderr=logfile,
  382. preexec_fn=self.drop_privileges)
  383.  
  384. if os.path.exists('/usr/lib/gnome-settings-daemon/gnome-settings-daemon'):
  385. proc = subprocess.Popen(
  386. ['/usr/lib/gnome-settings-daemon/gnome-settings-daemon'],
  387. stdin=null, stdout=logfile, stderr=logfile,
  388. preexec_fn=self.drop_privileges)
  389. extras.append(proc)
  390.  
  391. if os.path.exists('/usr/bin/xfsettingsd'):
  392. extras.append(subprocess.Popen(
  393. ['xsetroot', '-solid', 'black'],
  394. stdin=null, stdout=logfile, stderr=logfile,
  395. preexec_fn=self.drop_privileges))
  396. extras.append(subprocess.Popen(
  397. ['/usr/bin/xfsettingsd'],
  398. stdin=null, stdout=logfile, stderr=logfile,
  399. preexec_fn=self.drop_privileges))
  400.  
  401. if osextras.find_on_path('lxsession'):
  402. proc = subprocess.Popen(
  403. ['lxsession','-s','Lubuntu', '-e', 'LXDE', '-a'],
  404. stdin=null, stdout=logfile, stderr=logfile,
  405. preexec_fn=self.drop_privileges)
  406. extras.append(proc)
  407.  
  408. if os.path.exists('/usr/lib/ubiquity/panel') and "xfwm4" not in wm_cmd:
  409. if "openbox-lubuntu" not in wm_cmd and "openbox" not in wm_cmd:
  410. extras.append(subprocess.Popen(
  411. ['/usr/lib/ubiquity/panel'],
  412. stdin=null, stdout=logfile, stderr=logfile,
  413. preexec_fn=self.drop_privileges))
  414.  
  415. if osextras.find_on_path('nm-applet'):
  416. extras.append(subprocess.Popen(
  417. ['nm-applet'],
  418. stdin=null, stdout=logfile, stderr=logfile,
  419. preexec_fn=self.drop_privileges))
  420.  
  421. if osextras.find_on_path('ibus-daemon'):
  422. extras.append(subprocess.Popen(
  423. ['ibus-daemon'],
  424. stdin=null, stdout=logfile, stderr=logfile,
  425. preexec_fn=self.drop_privileges))
  426.  
  427. # Simply start bluetooth-applet, ubiquity-bluetooth-agent will
  428. # override it from casper to make sure it also covers the regular
  429. # live session
  430. if osextras.find_on_path('bluetooth-applet'):
  431. extras.append(subprocess.Popen(
  432. ['bluetooth-applet'],
  433. stdin=null, stdout=logfile, stderr=logfile,
  434. preexec_fn=self.drop_privileges))
  435.  
  436. # Accessibility tools
  437. if accessibility == True:
  438. with open('/proc/cmdline', 'r') as fp:
  439. if 'access=m2' in fp.readline():
  440. if osextras.find_on_path('onboard'):
  441. extras.append(subprocess.Popen(['onboard'],
  442. stdin=null, stdout=logfile, stderr=logfile,
  443. preexec_fn=self.drop_privileges))
  444. else:
  445. if osextras.find_on_path('orca'):
  446. time.sleep(15)
  447. extras.append(subprocess.Popen(['orca', '-n'],
  448. stdin=null, stdout=logfile, stderr=logfile,
  449. preexec_fn=self.drop_privileges))
  450. elif self.frontend == 'kde_ui':
  451. # Don't show the background image in v1 accessibility profile.
  452. os.setegid(self.gid)
  453. os.seteuid(self.uid)
  454. path = '/usr/share/wallpapers/kde-default.png'
  455. with open('/proc/cmdline', 'r') as fp:
  456. if (os.access(path, os.R_OK)
  457. and not 'access=v1' in fp.readline()):
  458. # Draw a background image for the install progress window.
  459. from PyQt4.QtCore import Qt
  460. from PyQt4 import QtGui
  461. a = QtGui.QApplication(sys.argv)
  462. root_win = a.desktop()
  463. wallpaper = QtGui.QPixmap(path)
  464. wallpaper = wallpaper.scaled(root_win.width(),
  465. root_win.height(), Qt.KeepAspectRatioByExpanding,
  466. Qt.SmoothTransformation)
  467. palette = QtGui.QPalette()
  468. palette.setBrush(root_win.backgroundRole(),
  469. QtGui.QBrush(wallpaper))
  470. root_win.setPalette(palette)
  471. root_win.setCursor(Qt.ArrowCursor)
  472. a.processEvents()
  473. # Force garbage collection so we don't end up with stray X
  474. # resources when we kill the X server (LP: #556555).
  475. del a
  476. os.seteuid(0)
  477. os.setegid(0)
  478.  
  479. subprocess.call(
  480. ['kwriteconfig', '--file', 'kwinrc', '--group', 'Compositing',
  481. '--key', 'Enabled', 'false'],
  482. stdin=null, stdout=logfile, stderr=logfile,
  483. preexec_fn=self.drop_privileges)
  484. wm = subprocess.Popen('kwin',
  485. stdin=null, stdout=logfile, stderr=logfile,
  486. preexec_fn=self.drop_privileges)
  487.  
  488. greeter = subprocess.Popen(program, stdin=null, stdout=logfile, stderr=logfile)
  489. ret = greeter.wait()
  490.  
  491. reboot = False
  492. if ret != 0:
  493. db = DebconfCommunicator('ubiquity', cloexec=True)
  494. try:
  495. error_cmd = db.get('ubiquity/failure_command')
  496. if error_cmd:
  497. subprocess.call(['sh', '-c', error_cmd])
  498. except debconf.DebconfError:
  499. pass
  500.  
  501. reboot = False
  502. try:
  503. if '--automatic' in program:
  504. reboot = db.get('ubiquity/reboot_on_failure') == 'true'
  505. except debconf.DebconfError:
  506. pass
  507.  
  508. if reboot:
  509. question = 'ubiquity/install_failed_reboot'
  510. else:
  511. question = 'ubiquity/install_failed'
  512. title = ''
  513. message = ''
  514. try:
  515. title = unicode(db.metaget(question, 'description'),
  516. 'utf-8', 'replace')
  517. message = unicode(db.metaget(question, 'extended_description'),
  518. 'utf-8', 'replace')
  519. except debconf.DebconfError:
  520. pass
  521. db.shutdown()
  522.  
  523. if title and message:
  524. if self.frontend == 'gtk_ui':
  525. cmd = ['zenity', '--error', '--title=%s' % title,
  526. '--text=%s' % message]
  527. subprocess.call(cmd)
  528. elif self.frontend == 'kde_ui':
  529. cmd = ['kdialog', '--title=%s' % title,
  530. '--msgbox=%s' % message]
  531. subprocess.call(cmd)
  532. else:
  533. # Not ideal, but if we cannot let the user know what's
  534. # going on, it's best to drop them into a desktop and let
  535. # them figure it out.
  536. reboot = False
  537.  
  538. def kill_if_exists(pid, signum):
  539. try:
  540. os.kill(pid, signum)
  541. except OSError, e:
  542. if e.errno != errno.ESRCH:
  543. raise
  544.  
  545. def sigalrm_handler(signum, frame):
  546. kill_if_exists(wm.pid, signal.SIGKILL)
  547. for extra in extras:
  548. kill_if_exists(extra.pid, signal.SIGKILL)
  549.  
  550. kill_if_exists(wm.pid, signal.SIGTERM)
  551. for extra in extras:
  552. kill_if_exists(extra.pid, signal.SIGTERM)
  553. if gconfd_running:
  554. subprocess.call(['gconftool-2', '--shutdown'],
  555. stdin=null, stdout=logfile, stderr=logfile,
  556. preexec_fn=self.drop_privileges)
  557. signal.signal(signal.SIGALRM, sigalrm_handler)
  558. signal.alarm(1) # low patience with WMs failing to exit on demand
  559. processes = set(extras)
  560. processes.add(wm)
  561. while processes:
  562. done = set()
  563. for process in processes:
  564. try:
  565. process.wait()
  566. done.add(process)
  567. except OSError, e:
  568. if e.errno == errno.EINTR:
  569. continue
  570. raise
  571. processes -= done
  572. signal.alarm(0)
  573.  
  574. # Clear the console so we don't see boot-time messages on switch
  575. try:
  576. vthandle = open('/dev/tty' + self.vt[2:], 'r+')
  577. subprocess.call(['clear'], stdin=vthandle, stdout=vthandle)
  578. except IOError:
  579. pass
  580.  
  581. kill_if_exists(server.pid, signal.SIGTERM)
  582. server.wait()
  583.  
  584. if reboot:
  585. subprocess.Popen(['reboot'])
  586. if ret is not None and ret >= 0:
  587. return ret
  588. else:
  589. return 1
  590.  
  591. if len(sys.argv) < 4:
  592. sys.stderr.write('Usage: %s <vt[1-N]> <:[0-N]> <username> <program> '
  593. '[<arguments>]\n' % sys.argv[0])
  594. sys.exit(1)
  595.  
  596. vt, display, username = sys.argv[1:4]
  597. try:
  598. dm = DM(vt, display, username)
  599. except XStartupError:
  600. sys.exit(1)
  601. ret = dm.run(*sys.argv[4:])
  602. if ret == 0:
  603. set_locale()
  604. sys.exit(ret)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement