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 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 os.dup2(log_fd, sys.stderr.fileno()) | 627 os.dup2(log_fd, sys.stderr.fileno()) |
628 | 628 |
629 # Close the temporary file-descriptors. | 629 # Close the temporary file-descriptors. |
630 os.close(devnull_fd) | 630 os.close(devnull_fd) |
631 os.close(log_fd) | 631 os.close(log_fd) |
632 | 632 |
633 | 633 |
634 def cleanup(): | 634 def cleanup(): |
635 logging.info("Cleanup.") | 635 logging.info("Cleanup.") |
636 | 636 |
| 637 global g_pidfile |
637 if g_pidfile: | 638 if g_pidfile: |
638 try: | 639 try: |
639 g_pidfile.delete_file() | 640 g_pidfile.delete_file() |
| 641 g_pidfile = None |
640 except Exception, e: | 642 except Exception, e: |
641 logging.error("Unexpected error deleting PID file: " + str(e)) | 643 logging.error("Unexpected error deleting PID file: " + str(e)) |
642 | 644 |
| 645 global g_desktops |
643 for desktop in g_desktops: | 646 for desktop in g_desktops: |
644 if desktop.x_proc: | 647 if desktop.x_proc: |
645 logging.info("Terminating Xvfb") | 648 logging.info("Terminating Xvfb") |
646 desktop.x_proc.terminate() | 649 desktop.x_proc.terminate() |
| 650 g_desktops = [] |
647 | 651 |
648 | 652 |
649 def reload_config(): | 653 def reload_config(): |
650 for desktop in g_desktops: | 654 for desktop in g_desktops: |
651 if desktop.host_proc: | 655 if desktop.host_proc: |
652 # Terminating the Host will cause the main loop to spawn another | 656 # Terminating the Host will cause the main loop to spawn another |
653 # instance, which will read any changes made to the Host config file. | 657 # instance, which will read any changes made to the Host config file. |
654 desktop.host_proc.terminate() | 658 desktop.host_proc.terminate() |
655 | 659 |
656 | 660 |
657 def signal_handler(signum, stackframe): | 661 def signal_handler(signum, stackframe): |
658 if signum == signal.SIGUSR1: | 662 if signum == signal.SIGUSR1: |
659 logging.info("SIGUSR1 caught, reloading configuration.") | 663 logging.info("SIGUSR1 caught, reloading configuration.") |
660 reload_config() | 664 reload_config() |
661 else: | 665 else: |
662 # Exit cleanly so the atexit handler, cleanup(), gets called. | 666 # Exit cleanly so the atexit handler, cleanup(), gets called. |
663 raise SystemExit | 667 raise SystemExit |
664 | 668 |
665 | 669 |
| 670 def relaunch_self(): |
| 671 cleanup() |
| 672 os.execvp(sys.argv[0], sys.argv) |
| 673 |
| 674 |
666 def main(): | 675 def main(): |
667 DEFAULT_SIZE = "1280x800" | 676 DEFAULT_SIZE = "1280x800" |
668 parser = optparse.OptionParser( | 677 parser = optparse.OptionParser( |
669 "Usage: %prog [options] [ -- [ X server options ] ]") | 678 "Usage: %prog [options] [ -- [ X server options ] ]") |
670 parser.add_option("-s", "--size", dest="size", action="append", | 679 parser.add_option("-s", "--size", dest="size", action="append", |
671 help="dimensions of virtual desktop (default: %s). " | 680 help="dimensions of virtual desktop (default: %s). " |
672 "This can be specified multiple times to make multiple " | 681 "This can be specified multiple times to make multiple " |
673 "screen resolutions available (if the Xvfb server " | 682 "screen resolutions available (if the Xvfb server " |
674 "supports this)" % DEFAULT_SIZE) | 683 "supports this)" % DEFAULT_SIZE) |
675 parser.add_option("-f", "--foreground", dest="foreground", default=False, | 684 parser.add_option("-f", "--foreground", dest="foreground", default=False, |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 | 875 |
867 desktop = Desktop(sizes) | 876 desktop = Desktop(sizes) |
868 | 877 |
869 # Remember the time when the last session was launched, in order to enforce | 878 # Remember the time when the last session was launched, in order to enforce |
870 # a minimum time between launches. This avoids spinning in case of a | 879 # a minimum time between launches. This avoids spinning in case of a |
871 # misconfigured system, or other error that prevents a session from starting | 880 # misconfigured system, or other error that prevents a session from starting |
872 # properly. | 881 # properly. |
873 last_launch_time = 0 | 882 last_launch_time = 0 |
874 | 883 |
875 while True: | 884 while True: |
876 # If the session process stops running (e.g. because the user logged out), | 885 # If the session process or X server stops running (e.g. because the user |
877 # the X server should be reset and the session restarted, to provide a | 886 # logged out), kill the other. This will trigger the next conditional block |
878 # completely clean new session. | 887 # as soon as the os.wait() call (below) returns. |
879 if desktop.session_proc is None and desktop.x_proc is not None: | 888 if desktop.session_proc is None and desktop.x_proc is not None: |
880 logging.info("Terminating X server") | 889 logging.info("Terminating X server") |
881 desktop.x_proc.terminate() | 890 desktop.x_proc.terminate() |
| 891 elif desktop.x_proc is None and desktop.session_proc is not None: |
| 892 logging.info("Terminating X session") |
| 893 desktop.session_proc.terminate() |
| 894 elif desktop.x_proc is None and desktop.session_proc is None: |
| 895 # Neither X server nor X session are running. |
| 896 elapsed = time.time() - last_launch_time |
| 897 if elapsed < 60: |
| 898 logging.error("The session lasted less than 1 minute. Waiting " + |
| 899 "before starting new session.") |
| 900 time.sleep(60 - elapsed) |
882 | 901 |
883 if desktop.x_proc is None: | 902 if last_launch_time == 0: |
884 if desktop.session_proc is not None: | 903 # Neither process has been started yet. Do so now. |
885 # The X session would probably die soon if the X server is not | 904 logging.info("Launching X server and X session.") |
886 # running (because of the loss of the X connection). Terminate it | |
887 # anyway, to be sure. | |
888 logging.info("Terminating X session") | |
889 desktop.session_proc.terminate() | |
890 else: | |
891 # Neither X server nor X session are running. | |
892 elapsed = time.time() - last_launch_time | |
893 if elapsed < 60: | |
894 logging.error("The session lasted less than 1 minute. Waiting " + | |
895 "before starting new session.") | |
896 time.sleep(60 - elapsed) | |
897 | |
898 logging.info("Launching X server and X session") | |
899 last_launch_time = time.time() | 905 last_launch_time = time.time() |
900 desktop.launch_x_server(args) | 906 desktop.launch_x_server(args) |
901 desktop.launch_x_session() | 907 desktop.launch_x_session() |
| 908 else: |
| 909 # Both processes have terminated. Since the user's desktop is already |
| 910 # gone at this point, there's no state to lose and now is a good time |
| 911 # to pick up any updates to this script that might have been installed. |
| 912 logging.info("Relaunching self") |
| 913 relaunch_self() |
902 | 914 |
903 if desktop.host_proc is None: | 915 if desktop.host_proc is None: |
904 logging.info("Launching host process") | 916 logging.info("Launching host process") |
905 desktop.launch_host(host_config) | 917 desktop.launch_host(host_config) |
906 | 918 |
907 try: | 919 try: |
908 pid, status = os.wait() | 920 pid, status = os.wait() |
909 except OSError, e: | 921 except OSError, e: |
910 if e.errno == errno.EINTR: | 922 if e.errno == errno.EINTR: |
911 # Retry on EINTR, which can happen if a signal such as SIGUSR1 is | 923 # Retry on EINTR, which can happen if a signal such as SIGUSR1 is |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 return 0 | 967 return 0 |
956 elif os.WEXITSTATUS(status) == 5: | 968 elif os.WEXITSTATUS(status) == 5: |
957 logging.info("Host domain is blocked by policy - exiting.") | 969 logging.info("Host domain is blocked by policy - exiting.") |
958 os.remove(host.config_file) | 970 os.remove(host.config_file) |
959 return 0 | 971 return 0 |
960 # Nothing to do for Mac-only status 6 (login screen unsupported) | 972 # Nothing to do for Mac-only status 6 (login screen unsupported) |
961 | 973 |
962 if __name__ == "__main__": | 974 if __name__ == "__main__": |
963 logging.basicConfig(level=logging.DEBUG) | 975 logging.basicConfig(level=logging.DEBUG) |
964 sys.exit(main()) | 976 sys.exit(main()) |
OLD | NEW |