| 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 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 logging.info("Launching X session: %s" % XSESSION_COMMAND) | 281 logging.info("Launching X session: %s" % XSESSION_COMMAND) |
| 282 self.session_proc = subprocess.Popen(XSESSION_COMMAND, | 282 self.session_proc = subprocess.Popen(XSESSION_COMMAND, |
| 283 stdin=open(os.devnull, "r"), | 283 stdin=open(os.devnull, "r"), |
| 284 cwd=HOME_DIR, | 284 cwd=HOME_DIR, |
| 285 env=self.child_env) | 285 env=self.child_env) |
| 286 if not self.session_proc.pid: | 286 if not self.session_proc.pid: |
| 287 raise Exception("Could not start X session") | 287 raise Exception("Could not start X session") |
| 288 | 288 |
| 289 def launch_host(self, host_config): | 289 def launch_host(self, host_config): |
| 290 # Start remoting host | 290 # Start remoting host |
| 291 args = [locate_executable(HOST_BINARY_NAME), | 291 args = [locate_executable(HOST_BINARY_NAME), "--host-config=/dev/stdin"] |
| 292 "--host-config=%s" % (host_config.path)] | 292 self.host_proc = subprocess.Popen(args, env=self.child_env, |
| 293 self.host_proc = subprocess.Popen(args, env=self.child_env) | 293 stdin=subprocess.PIPE) |
| 294 logging.info(args) | 294 logging.info(args) |
| 295 if not self.host_proc.pid: | 295 if not self.host_proc.pid: |
| 296 raise Exception("Could not start Chrome Remote Desktop host") | 296 raise Exception("Could not start Chrome Remote Desktop host") |
| 297 self.host_proc.stdin.write(json.dumps(host_config.data)) |
| 298 self.host_proc.stdin.close() |
| 297 | 299 |
| 298 | 300 |
| 299 class PidFile: | 301 class PidFile: |
| 300 """Class to allow creating and deleting a file which holds the PID of the | 302 """Class to allow creating and deleting a file which holds the PID of the |
| 301 running process. This is used to detect if a process is already running, and | 303 running process. This is used to detect if a process is already running, and |
| 302 inform the user of the PID. On process termination, the PID file is | 304 inform the user of the PID. On process termination, the PID file is |
| 303 deleted. | 305 deleted. |
| 304 | 306 |
| 305 Note that PID files are not truly atomic or reliable, see | 307 Note that PID files are not truly atomic or reliable, see |
| 306 http://mywiki.wooledge.org/ProcessManagement for more discussion on this. | 308 http://mywiki.wooledge.org/ProcessManagement for more discussion on this. |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 logging.error("Unexpected error deleting PID file: " + str(e)) | 510 logging.error("Unexpected error deleting PID file: " + str(e)) |
| 509 | 511 |
| 510 global g_desktops | 512 global g_desktops |
| 511 for desktop in g_desktops: | 513 for desktop in g_desktops: |
| 512 if desktop.x_proc: | 514 if desktop.x_proc: |
| 513 logging.info("Terminating Xvfb") | 515 logging.info("Terminating Xvfb") |
| 514 desktop.x_proc.terminate() | 516 desktop.x_proc.terminate() |
| 515 g_desktops = [] | 517 g_desktops = [] |
| 516 | 518 |
| 517 | 519 |
| 518 def reload_config(): | 520 class SignalHandler: |
| 519 for desktop in g_desktops: | 521 """Reload the config file on SIGHUP. Since we pass the configuration to the |
| 520 if desktop.host_proc: | 522 host processes via stdin, they can't reload it, so terminate them. They will |
| 521 desktop.host_proc.send_signal(signal.SIGHUP) | 523 be relaunched automatically with the new config.""" |
| 522 | 524 |
| 525 def __init__(self, host_config): |
| 526 self.host_config = host_config |
| 523 | 527 |
| 524 def signal_handler(signum, _stackframe): | 528 def __call__(self, signum, _stackframe): |
| 525 if signum == signal.SIGHUP: | 529 if signum == signal.SIGHUP: |
| 526 logging.info("SIGHUP caught, reloading configuration.") | 530 logging.info("SIGHUP caught, restarting host.") |
| 527 reload_config() | 531 self.host_config.load() |
| 528 else: | 532 for desktop in g_desktops: |
| 529 # Exit cleanly so the atexit handler, cleanup(), gets called. | 533 if desktop.host_proc: |
| 530 raise SystemExit | 534 desktop.host_proc.send_signal(signal.SIGTERM) |
| 535 else: |
| 536 # Exit cleanly so the atexit handler, cleanup(), gets called. |
| 537 raise SystemExit |
| 531 | 538 |
| 532 | 539 |
| 533 def relaunch_self(): | 540 def relaunch_self(): |
| 534 cleanup() | 541 cleanup() |
| 535 os.execvp(sys.argv[0], sys.argv) | 542 os.execvp(sys.argv[0], sys.argv) |
| 536 | 543 |
| 537 | 544 |
| 538 def main(): | 545 def main(): |
| 539 DEFAULT_SIZE = "1280x800" | 546 DEFAULT_SIZE = "1280x800" |
| 540 EPILOG = """This script is not intended for use by end-users. To configure | 547 EPILOG = """This script is not intended for use by end-users. To configure |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 return 1 | 642 return 1 |
| 636 | 643 |
| 637 if "--session=ubuntu-2d" in XSESSION_COMMAND: | 644 if "--session=ubuntu-2d" in XSESSION_COMMAND: |
| 638 print >> sys.stderr, ( | 645 print >> sys.stderr, ( |
| 639 "The Unity 2D desktop session will be used.\n" | 646 "The Unity 2D desktop session will be used.\n" |
| 640 "If you encounter problems with this choice of desktop, please install\n" | 647 "If you encounter problems with this choice of desktop, please install\n" |
| 641 "the gnome-session-fallback package, and restart this script.\n") | 648 "the gnome-session-fallback package, and restart this script.\n") |
| 642 | 649 |
| 643 atexit.register(cleanup) | 650 atexit.register(cleanup) |
| 644 | 651 |
| 652 config_filename = os.path.join(CONFIG_DIR, "host#%s.json" % host_hash) |
| 653 host_config = Config(config_filename) |
| 654 |
| 645 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: | 655 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: |
| 646 signal.signal(s, signal_handler) | 656 signal.signal(s, SignalHandler(host_config)) |
| 647 | 657 |
| 648 # Ensure full path to config directory exists. | 658 if (not host_config.load()): |
| 649 if not os.path.exists(CONFIG_DIR): | 659 print >> sys.stderr, "Failed to load " + config_filename |
| 650 os.makedirs(CONFIG_DIR, mode=0700) | 660 return 1 |
| 651 | |
| 652 host_config = Config(os.path.join(CONFIG_DIR, "host#%s.json" % host_hash)) | |
| 653 host_config.load() | |
| 654 | 661 |
| 655 auth = Authentication() | 662 auth = Authentication() |
| 656 auth_config_valid = auth.copy_from(host_config) | 663 auth_config_valid = auth.copy_from(host_config) |
| 657 host = Host() | 664 host = Host() |
| 658 host_config_valid = host.copy_from(host_config) | 665 host_config_valid = host.copy_from(host_config) |
| 659 if not host_config_valid or not auth_config_valid: | 666 if not host_config_valid or not auth_config_valid: |
| 660 logging.error("Failed to load host configuration.") | 667 logging.error("Failed to load host configuration.") |
| 661 return 1 | 668 return 1 |
| 662 | 669 |
| 663 global g_pidfile | 670 global g_pidfile |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 return 0 | 784 return 0 |
| 778 elif os.WEXITSTATUS(status) == 5: | 785 elif os.WEXITSTATUS(status) == 5: |
| 779 logging.info("Host domain is blocked by policy - exiting.") | 786 logging.info("Host domain is blocked by policy - exiting.") |
| 780 os.remove(host.config_file) | 787 os.remove(host.config_file) |
| 781 return 0 | 788 return 0 |
| 782 # Nothing to do for Mac-only status 6 (login screen unsupported) | 789 # Nothing to do for Mac-only status 6 (login screen unsupported) |
| 783 | 790 |
| 784 if __name__ == "__main__": | 791 if __name__ == "__main__": |
| 785 logging.basicConfig(level=logging.DEBUG) | 792 logging.basicConfig(level=logging.DEBUG) |
| 786 sys.exit(main()) | 793 sys.exit(main()) |
| OLD | NEW |