| OLD | NEW | 
|     1 #!/usr/bin/python |     1 #!/usr/bin/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 341 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   352  |   352  | 
|   353   @staticmethod |   353   @staticmethod | 
|   354   def get_unused_display_number(): |   354   def get_unused_display_number(): | 
|   355     """Return a candidate display number for which there is currently no |   355     """Return a candidate display number for which there is currently no | 
|   356     X Server lock file""" |   356     X Server lock file""" | 
|   357     display = FIRST_X_DISPLAY_NUMBER |   357     display = FIRST_X_DISPLAY_NUMBER | 
|   358     while os.path.exists(X_LOCK_FILE_TEMPLATE % display): |   358     while os.path.exists(X_LOCK_FILE_TEMPLATE % display): | 
|   359       display += 1 |   359       display += 1 | 
|   360     return display |   360     return display | 
|   361  |   361  | 
|   362   def _init_child_env(self): |   362   def _init_child_env(self, keep_env): | 
|   363     # Create clean environment for new session, so it is cleanly separated from |   363     if keep_env: | 
|   364     # the user's console X session. |   364       self.child_env = dict(os.environ) | 
|   365     self.child_env = {} |   365     else: | 
 |   366       # Create clean environment for new session, so it is cleanly separated | 
 |   367       # from the user's console X session. | 
 |   368       self.child_env = {} | 
|   366  |   369  | 
|   367     for key in [ |   370       for key in [ | 
|   368         "HOME", |   371           "HOME", | 
|   369         "LANG", |   372           "LANG", | 
|   370         "LOGNAME", |   373           "LOGNAME", | 
|   371         "PATH", |   374           "PATH", | 
|   372         "SHELL", |   375           "SHELL", | 
|   373         "USER", |   376           "USER", | 
|   374         "USERNAME", |   377           "USERNAME", | 
|   375         LOG_FILE_ENV_VAR]: |   378           LOG_FILE_ENV_VAR]: | 
|   376       if key in os.environ: |   379         if key in os.environ: | 
|   377         self.child_env[key] = os.environ[key] |   380           self.child_env[key] = os.environ[key] | 
 |   381  | 
 |   382       # Initialize the environment from files that would normally be read in a | 
 |   383       # PAM-authenticated session. | 
 |   384       for env_filename in [ | 
 |   385         "/etc/environment", | 
 |   386         "/etc/default/locale", | 
 |   387         os.path.expanduser("~/.pam_environment")]: | 
 |   388         if not os.path.exists(env_filename): | 
 |   389           continue | 
 |   390         try: | 
 |   391           with open(env_filename, "r") as env_file: | 
 |   392             for line in env_file: | 
 |   393               line = line.rstrip("\n") | 
 |   394               # Split at the first "=", leaving any further instances in the | 
 |   395               # value. | 
 |   396               key_value_pair = line.split("=", 1) | 
 |   397               if len(key_value_pair) == 2: | 
 |   398                 key, value = tuple(key_value_pair) | 
 |   399                 # The file stores key=value assignments, but the value may be | 
 |   400                 # quoted, so strip leading & trailing quotes from it. | 
 |   401                 value = value.strip("'\"") | 
 |   402                 self.child_env[key] = value | 
 |   403         except IOError: | 
 |   404           logging.error("Failed to read file: %s" % env_filename) | 
|   378  |   405  | 
|   379     # Ensure that the software-rendering GL drivers are loaded by the desktop |   406     # Ensure that the software-rendering GL drivers are loaded by the desktop | 
|   380     # session, instead of any hardware GL drivers installed on the system. |   407     # session, instead of any hardware GL drivers installed on the system. | 
|   381     self.child_env["LD_LIBRARY_PATH"] = ( |   408     library_path = ( | 
|   382         "/usr/lib/%(arch)s-linux-gnu/mesa:" |   409         "/usr/lib/%(arch)s-linux-gnu/mesa:" | 
|   383         "/usr/lib/%(arch)s-linux-gnu/dri:" |   410         "/usr/lib/%(arch)s-linux-gnu/dri:" | 
|   384         "/usr/lib/%(arch)s-linux-gnu/gallium-pipe" % |   411         "/usr/lib/%(arch)s-linux-gnu/gallium-pipe" % | 
|   385         { "arch": platform.machine() }) |   412         { "arch": platform.machine() }) | 
|   386  |   413  | 
|   387     # Initialize the environment from files that would normally be read in a |   414     if "LD_LIBRARY_PATH" in self.child_env: | 
|   388     # PAM-authenticated session. |   415       library_path += ":" + self.child_env["LD_LIBRARY_PATH"] | 
|   389     for env_filename in [ |   416  | 
|   390       "/etc/environment", |   417     self.child_env["LD_LIBRARY_PATH"] = library_path | 
|   391       "/etc/default/locale", |  | 
|   392       os.path.expanduser("~/.pam_environment")]: |  | 
|   393       if not os.path.exists(env_filename): |  | 
|   394         continue |  | 
|   395       try: |  | 
|   396         with open(env_filename, "r") as env_file: |  | 
|   397           for line in env_file: |  | 
|   398             line = line.rstrip("\n") |  | 
|   399             # Split at the first "=", leaving any further instances in the |  | 
|   400             # value. |  | 
|   401             key_value_pair = line.split("=", 1) |  | 
|   402             if len(key_value_pair) == 2: |  | 
|   403               key, value = tuple(key_value_pair) |  | 
|   404               # The file stores key=value assignments, but the value may be |  | 
|   405               # quoted, so strip leading & trailing quotes from it. |  | 
|   406               value = value.strip("'\"") |  | 
|   407               self.child_env[key] = value |  | 
|   408       except IOError: |  | 
|   409         logging.error("Failed to read file: %s" % env_filename) |  | 
|   410  |   418  | 
|   411   def _setup_pulseaudio(self): |   419   def _setup_pulseaudio(self): | 
|   412     self.pulseaudio_pipe = None |   420     self.pulseaudio_pipe = None | 
|   413  |   421  | 
|   414     # pulseaudio uses UNIX sockets for communication. Length of UNIX socket |   422     # pulseaudio uses UNIX sockets for communication. Length of UNIX socket | 
|   415     # name is limited to 108 characters, so audio will not work properly if |   423     # name is limited to 108 characters, so audio will not work properly if | 
|   416     # the path is too long. To workaround this problem we use only first 10 |   424     # the path is too long. To workaround this problem we use only first 10 | 
|   417     # symbols of the host hash. |   425     # symbols of the host hash. | 
|   418     pulse_path = os.path.join(CONFIG_DIR, |   426     pulse_path = os.path.join(CONFIG_DIR, | 
|   419                               "pulseaudio#%s" % g_host_hash[0:10]) |   427                               "pulseaudio#%s" % g_host_hash[0:10]) | 
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   642       raise Exception("Unable to choose suitable X session command.") |   650       raise Exception("Unable to choose suitable X session command.") | 
|   643  |   651  | 
|   644     logging.info("Launching X session: %s" % xsession_command) |   652     logging.info("Launching X session: %s" % xsession_command) | 
|   645     self.session_proc = subprocess.Popen(xsession_command, |   653     self.session_proc = subprocess.Popen(xsession_command, | 
|   646                                          stdin=open(os.devnull, "r"), |   654                                          stdin=open(os.devnull, "r"), | 
|   647                                          cwd=HOME_DIR, |   655                                          cwd=HOME_DIR, | 
|   648                                          env=self.child_env) |   656                                          env=self.child_env) | 
|   649     if not self.session_proc.pid: |   657     if not self.session_proc.pid: | 
|   650       raise Exception("Could not start X session") |   658       raise Exception("Could not start X session") | 
|   651  |   659  | 
|   652   def launch_session(self, x_args): |   660   def launch_session(self, keep_env, x_args): | 
|   653     self._init_child_env() |   661     self._init_child_env(keep_env) | 
|   654     self._setup_pulseaudio() |   662     self._setup_pulseaudio() | 
|   655     self._setup_gnubby() |   663     self._setup_gnubby() | 
|   656     self._launch_x_server(x_args) |   664     self._launch_x_server(x_args) | 
|   657     self._launch_x_session() |   665     self._launch_x_session() | 
|   658  |   666  | 
|   659   def launch_host(self, host_config): |   667   def launch_host(self, host_config): | 
|   660     # Start remoting host |   668     # Start remoting host | 
|   661     args = [HOST_BINARY_PATH, "--host-config=-"] |   669     args = [HOST_BINARY_PATH, "--host-config=-"] | 
|   662     if self.pulseaudio_pipe: |   670     if self.pulseaudio_pipe: | 
|   663       args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) |   671       args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) | 
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1229   parser.add_option("", "--reload", dest="reload", default=False, |  1237   parser.add_option("", "--reload", dest="reload", default=False, | 
|  1230                     action="store_true", |  1238                     action="store_true", | 
|  1231                     help="Signal currently running host to reload the config.") |  1239                     help="Signal currently running host to reload the config.") | 
|  1232   parser.add_option("", "--add-user", dest="add_user", default=False, |  1240   parser.add_option("", "--add-user", dest="add_user", default=False, | 
|  1233                     action="store_true", |  1241                     action="store_true", | 
|  1234                     help="Add current user to the chrome-remote-desktop group.") |  1242                     help="Add current user to the chrome-remote-desktop group.") | 
|  1235   parser.add_option("", "--add-user-as-root", dest="add_user_as_root", |  1243   parser.add_option("", "--add-user-as-root", dest="add_user_as_root", | 
|  1236                     action="store", metavar="USER", |  1244                     action="store", metavar="USER", | 
|  1237                     help="Adds the specified user to the chrome-remote-desktop " |  1245                     help="Adds the specified user to the chrome-remote-desktop " | 
|  1238                     "group (must be run as root).") |  1246                     "group (must be run as root).") | 
 |  1247   parser.add_option("", "--keep-parent-env", dest="keep_env", default=False, | 
 |  1248                     action="store_true", | 
 |  1249                     help=optparse.SUPPRESS_HELP) | 
|  1239   parser.add_option("", "--watch-resolution", dest="watch_resolution", |  1250   parser.add_option("", "--watch-resolution", dest="watch_resolution", | 
|  1240                     type="int", nargs=2, default=False, action="store", |  1251                     type="int", nargs=2, default=False, action="store", | 
|  1241                     help=optparse.SUPPRESS_HELP) |  1252                     help=optparse.SUPPRESS_HELP) | 
|  1242   (options, args) = parser.parse_args() |  1253   (options, args) = parser.parse_args() | 
|  1243  |  1254  | 
|  1244   # Determine the filename of the host configuration and PID files. |  1255   # Determine the filename of the host configuration and PID files. | 
|  1245   if not options.config: |  1256   if not options.config: | 
|  1246     options.config = os.path.join(CONFIG_DIR, "host#%s.json" % g_host_hash) |  1257     options.config = os.path.join(CONFIG_DIR, "host#%s.json" % g_host_hash) | 
|  1247  |  1258  | 
|  1248   # Check for a modal command-line option (start, stop, etc.) |  1259   # Check for a modal command-line option (start, stop, etc.) | 
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1462         logging.info("Relaunching self") |  1473         logging.info("Relaunching self") | 
|  1463         relaunch_self() |  1474         relaunch_self() | 
|  1464       else: |  1475       else: | 
|  1465         # If there is a non-zero |failures| count, restarting the whole script |  1476         # If there is a non-zero |failures| count, restarting the whole script | 
|  1466         # would lose this information, so just launch the session as normal. |  1477         # would lose this information, so just launch the session as normal. | 
|  1467         if x_server_inhibitor.is_inhibited(): |  1478         if x_server_inhibitor.is_inhibited(): | 
|  1468           logging.info("Waiting before launching X server") |  1479           logging.info("Waiting before launching X server") | 
|  1469           relaunch_times.append(x_server_inhibitor.earliest_relaunch_time) |  1480           relaunch_times.append(x_server_inhibitor.earliest_relaunch_time) | 
|  1470         else: |  1481         else: | 
|  1471           logging.info("Launching X server and X session.") |  1482           logging.info("Launching X server and X session.") | 
|  1472           desktop.launch_session(args) |  1483           desktop.launch_session(options.keep_env, args) | 
|  1473           x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, |  1484           x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, | 
|  1474                                             backoff_time) |  1485                                             backoff_time) | 
|  1475           allow_relaunch_self = True |  1486           allow_relaunch_self = True | 
|  1476  |  1487  | 
|  1477     if desktop.host_proc is None: |  1488     if desktop.host_proc is None: | 
|  1478       if host_inhibitor.is_inhibited(): |  1489       if host_inhibitor.is_inhibited(): | 
|  1479         logging.info("Waiting before launching host process") |  1490         logging.info("Waiting before launching host process") | 
|  1480         relaunch_times.append(host_inhibitor.earliest_relaunch_time) |  1491         relaunch_times.append(host_inhibitor.earliest_relaunch_time) | 
|  1481       else: |  1492       else: | 
|  1482         logging.info("Launching host process") |  1493         logging.info("Launching host process") | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1536         else: |  1547         else: | 
|  1537           logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) |  1548           logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) | 
|  1538       elif os.WIFSIGNALED(status): |  1549       elif os.WIFSIGNALED(status): | 
|  1539         logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) |  1550         logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) | 
|  1540  |  1551  | 
|  1541  |  1552  | 
|  1542 if __name__ == "__main__": |  1553 if __name__ == "__main__": | 
|  1543   logging.basicConfig(level=logging.DEBUG, |  1554   logging.basicConfig(level=logging.DEBUG, | 
|  1544                       format="%(asctime)s:%(levelname)s:%(message)s") |  1555                       format="%(asctime)s:%(levelname)s:%(message)s") | 
|  1545   sys.exit(main()) |  1556   sys.exit(main()) | 
| OLD | NEW |