Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Virtual Me2Me implementation. This script runs and manages the processes | 6 # Virtual Me2Me implementation. This script runs and manages the processes |
| 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop | 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop |
| 8 # session, and Host process. | 8 # session, and Host process. |
| 9 # This script is intended to run continuously as a background daemon | 9 # This script is intended to run continuously as a background daemon |
| 10 # process, running under an ordinary (non-root) user account. | 10 # process, running under an ordinary (non-root) user account. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 import sys | 26 import sys |
| 27 import tempfile | 27 import tempfile |
| 28 import time | 28 import time |
| 29 import urllib2 | 29 import urllib2 |
| 30 import uuid | 30 import uuid |
| 31 | 31 |
| 32 # Local modules | 32 # Local modules |
| 33 import gaia_auth | 33 import gaia_auth |
| 34 import keygen | 34 import keygen |
| 35 | 35 |
| 36 # The X session command is normally determined automatically. To use a | |
|
Wez
2012/07/12 21:18:14
nit: "By default this script will try to determine
Lambros
2012/07/13 00:30:18
Done.
| |
| 37 # specific session instead, set this variable to the executable filename, or a | |
| 38 # list containing the executable and any arguments, for example: | |
| 39 # XSESSION_COMMAND = "/usr/bin/gnome-session-fallback" | |
| 40 # XSESSION_COMMAND = ["/usr/bin/gnome-session", "--session=ubuntu-2d"] | |
| 41 XSESSION_COMMAND = None | |
| 42 | |
| 36 REMOTING_COMMAND = "remoting_me2me_host" | 43 REMOTING_COMMAND = "remoting_me2me_host" |
| 37 | 44 |
| 38 # Command-line switch for passing the config path to remoting_me2me_host. | 45 # Command-line switch for passing the config path to remoting_me2me_host. |
| 39 HOST_CONFIG_SWITCH_NAME = "host-config" | 46 HOST_CONFIG_SWITCH_NAME = "host-config" |
| 40 | 47 |
| 41 # Needs to be an absolute path, since the current working directory is changed | 48 # Needs to be an absolute path, since the current working directory is changed |
| 42 # when this process self-daemonizes. | 49 # when this process self-daemonizes. |
| 43 SCRIPT_PATH = os.path.dirname(sys.argv[0]) | 50 SCRIPT_PATH = os.path.dirname(sys.argv[0]) |
| 44 if SCRIPT_PATH: | 51 if SCRIPT_PATH: |
| 45 SCRIPT_PATH = os.path.abspath(SCRIPT_PATH) | 52 SCRIPT_PATH = os.path.abspath(SCRIPT_PATH) |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 # be started with -noreset otherwise it'll reset as soon as the command | 333 # be started with -noreset otherwise it'll reset as soon as the command |
| 327 # completes, since there are no other X clients running yet. | 334 # completes, since there are no other X clients running yet. |
| 328 proc = subprocess.Popen("setxkbmap -rules evdev", env=self.child_env, | 335 proc = subprocess.Popen("setxkbmap -rules evdev", env=self.child_env, |
| 329 shell=True) | 336 shell=True) |
| 330 pid, retcode = os.waitpid(proc.pid, 0) | 337 pid, retcode = os.waitpid(proc.pid, 0) |
| 331 if retcode != 0: | 338 if retcode != 0: |
| 332 logging.error("Failed to set XKB to 'evdev'") | 339 logging.error("Failed to set XKB to 'evdev'") |
| 333 | 340 |
| 334 def launch_x_session(self): | 341 def launch_x_session(self): |
| 335 # Start desktop session | 342 # Start desktop session |
| 336 # The /dev/null input redirection is necessary to prevent Xsession from | 343 # The /dev/null input redirection is necessary to prevent the X session |
| 337 # reading from stdin. If this code runs as a shell background job in a | 344 # reading from stdin. If this code runs as a shell background job in a |
| 338 # terminal, any reading from stdin causes the job to be suspended. | 345 # terminal, any reading from stdin causes the job to be suspended. |
| 339 # Daemonization would solve this problem by separating the process from the | 346 # Daemonization would solve this problem by separating the process from the |
| 340 # controlling terminal. | 347 # controlling terminal. |
| 341 # | 348 logging.info("Launching X session: %s" % XSESSION_COMMAND) |
| 342 # This assumes that GDM is installed and configured on the system. | 349 self.session_proc = subprocess.Popen(XSESSION_COMMAND, |
| 343 self.session_proc = subprocess.Popen("/etc/gdm/Xsession", | |
| 344 stdin=open(os.devnull, "r"), | 350 stdin=open(os.devnull, "r"), |
| 345 cwd=HOME_DIR, | 351 cwd=HOME_DIR, |
| 346 env=self.child_env) | 352 env=self.child_env) |
| 347 if not self.session_proc.pid: | 353 if not self.session_proc.pid: |
| 348 raise Exception("Could not start X session") | 354 raise Exception("Could not start X session") |
| 349 | 355 |
| 350 def launch_host(self, host): | 356 def launch_host(self, host): |
| 351 # Start remoting host | 357 # Start remoting host |
| 352 args = [locate_executable(REMOTING_COMMAND), | 358 args = [locate_executable(REMOTING_COMMAND), |
| 353 "--%s=%s" % (HOST_CONFIG_SWITCH_NAME, host.config_file)] | 359 "--%s=%s" % (HOST_CONFIG_SWITCH_NAME, host.config_file)] |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 | 438 |
| 433 def delete_file(self): | 439 def delete_file(self): |
| 434 """Delete the PID file if it was created by this instance. | 440 """Delete the PID file if it was created by this instance. |
| 435 | 441 |
| 436 This is called on process termination. | 442 This is called on process termination. |
| 437 """ | 443 """ |
| 438 if self.created: | 444 if self.created: |
| 439 os.remove(self.filename) | 445 os.remove(self.filename) |
| 440 | 446 |
| 441 | 447 |
| 448 def choose_x_session(): | |
| 449 """Finds an appropriate choice of X session command for this system. | |
|
Wez
2012/07/12 21:18:14
nit: "Chooses the most appropriate X session comma
Lambros
2012/07/13 00:30:18
Done.
| |
| 450 | |
| 451 If XSESSION_COMMAND is already set, its value is returned directly. | |
| 452 Otherwise, a session is chosen for this system. | |
| 453 | |
| 454 This may print some information to stderr, so this function is called | |
| 455 before daemonization, and the result is assigned to XSESSION_COMMAND. This | |
| 456 way, any problems or errors can be reported before daemonization occurs. | |
|
Wez
2012/07/12 21:18:14
You print the information to stderr so that it wil
Lambros
2012/07/13 00:30:18
Removed the side-effect.
| |
| 457 | |
| 458 Returns: | |
| 459 A string containing the command to run, or a list of strings containing | |
| 460 the executable program and its arguments, which is suitable for passing as | |
| 461 the first parameter of subprocess.Popen(). If a suitable session cannot | |
| 462 be found, returns None. | |
| 463 """ | |
| 464 if XSESSION_COMMAND is not None: | |
| 465 return XSESSION_COMMAND | |
| 466 | |
| 467 for candidate in [ | |
| 468 "/usr/bin/gnome-session-fallback", | |
| 469 "/etc/gdm/Xsession"]: | |
| 470 if os.path.exists(candidate): | |
| 471 return candidate | |
|
Wez
2012/07/12 21:18:14
You could structure this as a dictionary of {file-
Lambros
2012/07/13 00:30:18
Done, but with a list instead of a dictionary, bec
| |
| 472 | |
| 473 # Unity-2d would normally be the preferred choice on Ubuntu 12.04. At the | |
| 474 # time of writing, this session does not work properly (missing launcher and | |
| 475 # panel), so gnome-session-fallback is used in preference. | |
| 476 # "unity-2d-panel" was chosen here simply because it appears in the TryExec | |
| 477 # line of the session's .desktop file; other choices might be just as good. | |
| 478 if os.path.exists("/usr/bin/unity-2d-panel"): | |
| 479 print >> sys.stderr, ( | |
| 480 "The Unity 2D desktop session will be used.\n" | |
| 481 "If you encounter problems with this choice of desktop, please install\n" | |
| 482 "the gnome-session-fallback package, and restart this script.\n") | |
|
Wez
2012/07/12 21:18:14
It would be cleaner to have the calling code test
Lambros
2012/07/13 00:30:18
Done.
| |
| 483 return ["/usr/bin/gnome-session", "--session=ubuntu-2d"] | |
| 484 | |
| 485 return None | |
| 486 | |
| 487 | |
| 442 def locate_executable(exe_name): | 488 def locate_executable(exe_name): |
| 443 for path in EXE_PATHS_TO_TRY: | 489 for path in EXE_PATHS_TO_TRY: |
| 444 exe_path = os.path.join(SCRIPT_PATH, path, exe_name) | 490 exe_path = os.path.join(SCRIPT_PATH, path, exe_name) |
| 445 if os.path.exists(exe_path): | 491 if os.path.exists(exe_path): |
| 446 return exe_path | 492 return exe_path |
| 447 | 493 |
| 448 raise Exception("Could not locate executable '%s'" % exe_name) | 494 raise Exception("Could not locate executable '%s'" % exe_name) |
| 449 | 495 |
| 450 | 496 |
| 451 def daemonize(log_filename): | 497 def daemonize(log_filename): |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 581 width = int(size_components[0]) | 627 width = int(size_components[0]) |
| 582 height = int(size_components[1]) | 628 height = int(size_components[1]) |
| 583 | 629 |
| 584 # Enforce minimum desktop size, as a sanity-check. The limit of 100 will | 630 # Enforce minimum desktop size, as a sanity-check. The limit of 100 will |
| 585 # detect typos of 2 instead of 3 digits. | 631 # detect typos of 2 instead of 3 digits. |
| 586 if width < 100 or height < 100: | 632 if width < 100 or height < 100: |
| 587 raise ValueError | 633 raise ValueError |
| 588 except ValueError: | 634 except ValueError: |
| 589 parser.error("Width and height should be 100 pixels or greater") | 635 parser.error("Width and height should be 100 pixels or greater") |
| 590 | 636 |
| 637 global XSESSION_COMMAND | |
| 638 XSESSION_COMMAND = choose_x_session() | |
| 639 if XSESSION_COMMAND is None: | |
| 640 print "Unable to choose suitable X session command" | |
| 641 return 1 | |
| 642 | |
| 591 atexit.register(cleanup) | 643 atexit.register(cleanup) |
| 592 | 644 |
| 593 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: | 645 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: |
| 594 signal.signal(s, signal_handler) | 646 signal.signal(s, signal_handler) |
| 595 | 647 |
| 596 # Ensure full path to config directory exists. | 648 # Ensure full path to config directory exists. |
| 597 if not os.path.exists(CONFIG_DIR): | 649 if not os.path.exists(CONFIG_DIR): |
| 598 os.makedirs(CONFIG_DIR, mode=0700) | 650 os.makedirs(CONFIG_DIR, mode=0700) |
| 599 | 651 |
| 600 if options.explicit_config: | 652 if options.explicit_config: |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 759 os.remove(host.config_file) | 811 os.remove(host.config_file) |
| 760 return 0 | 812 return 0 |
| 761 elif os.WEXITSTATUS(status) == 4: | 813 elif os.WEXITSTATUS(status) == 4: |
| 762 logging.info("OAuth credentials are invalid - exiting.") | 814 logging.info("OAuth credentials are invalid - exiting.") |
| 763 os.remove(auth.config_file) | 815 os.remove(auth.config_file) |
| 764 return 0 | 816 return 0 |
| 765 | 817 |
| 766 if __name__ == "__main__": | 818 if __name__ == "__main__": |
| 767 logging.basicConfig(level=logging.DEBUG) | 819 logging.basicConfig(level=logging.DEBUG) |
| 768 sys.exit(main()) | 820 sys.exit(main()) |
| OLD | NEW |