def start_Xvfb(xvfb_str, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid=None): if not POSIX: raise InitException("starting an Xvfb is not supported on %s" % os.name) if OSX: raise InitException("starting an Xvfb is not supported on MacOS") if not xvfb_str: raise InitException("the 'xvfb' command is not defined") cleanups = [] log = get_vfb_logger() log("start_Xvfb%s", (xvfb_str, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid)) xauthority = get_xauthority_path(display_name, username, uid, gid) os.environ["XAUTHORITY"] = xauthority if not os.path.exists(xauthority): log("creating XAUTHORITY=%s with data=%s", xauthority, xauth_data) try: with open(xauthority, 'wa') as f: if getuid() == 0 and (uid != 0 or gid != 0): os.fchown(f.fileno(), uid, gid) except Exception as e: #trying to continue anyway! log.error("Error trying to create XAUTHORITY file %s:", xauthority) log.error(" %s", e) else: log("found existing XAUTHORITY file '%s'", xauthority) use_display_fd = display_name[0] == 'S' subs = {} def pathexpand(s): return osexpand(s, actual_username=username, uid=uid, gid=gid, subs=subs) subs.update({ "DISPLAY": display_name, "XPRA_LOG_DIR": pathexpand(os.environ.get("XPRA_LOG_DIR")), }) #identify logfile argument if it exists, #as we may have to rename it, or create the directory for it: import shlex xvfb_cmd = shlex.split(xvfb_str) if not xvfb_cmd: raise InitException( "cannot start Xvfb, the command definition is missing!") #make sure all path values are expanded: xvfb_cmd = [pathexpand(s) for s in xvfb_cmd] try: logfile_argindex = xvfb_cmd.index('-logfile') assert logfile_argindex + 1 < len( xvfb_cmd ), "invalid xvfb command string: -logfile should not be last (found at index %i)" % logfile_argindex xorg_log_file = xvfb_cmd[logfile_argindex + 1] except ValueError: xorg_log_file = None tmp_xorg_log_file = None if xorg_log_file: if use_display_fd: #keep track of it so we can rename it later: tmp_xorg_log_file = xorg_log_file #make sure the Xorg log directory exists: xorg_log_dir = os.path.dirname(xorg_log_file) if not os.path.exists(xorg_log_dir): try: log("creating Xorg log dir '%s'", xorg_log_dir) os.mkdir(xorg_log_dir, 0o700) if POSIX and uid != getuid() or gid != getgid(): try: os.lchown(xorg_log_dir, uid, gid) except: pass except OSError as e: raise InitException( "failed to create the Xorg log directory '%s': %s" % (xorg_log_dir, e)) if uinput_uuid: #use uinput: #identify -config xorg.conf argument and replace it with the uinput one: try: config_argindex = xvfb_cmd.index("-config") except ValueError as e: log.warn("Warning: cannot use uinput") log.warn(" '-config' argument not found in the xvfb command") else: assert config_argindex + 1 < len( xvfb_cmd ), "invalid xvfb command string: -config should not be last (found at index %i)" % config_argindex xorg_conf = xvfb_cmd[config_argindex + 1] if xorg_conf.endswith("xorg.conf"): xorg_conf = xorg_conf.replace("xorg.conf", "xorg-uinput.conf") if os.path.exists(xorg_conf): xvfb_cmd[config_argindex + 1] = xorg_conf #create uinput device definition files: #(we have to assume that Xorg is configured to use this path..) xorg_conf_dir = pathexpand(get_Xdummy_confdir()) cleanups = create_xorg_device_configs(xorg_conf_dir, uinput_uuid, uid, gid) xvfb_executable = xvfb_cmd[0] if (xvfb_executable.endswith("Xorg") or xvfb_executable.endswith("Xdummy")) and pixel_depth > 0: xvfb_cmd.append("-depth") xvfb_cmd.append(str(pixel_depth)) xvfb = None try: if use_display_fd: def displayfd_err(msg): raise InitException("%s: %s" % (xvfb_executable, msg)) r_pipe, w_pipe = os.pipe() try: if PYTHON3: os.set_inheritable(w_pipe, True) #@UndefinedVariable xvfb_cmd += ["-displayfd", str(w_pipe)] xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name) def preexec(): setsid() if getuid() == 0 and uid: setuidgid(uid, gid) close_fds([0, 1, 2, r_pipe, w_pipe]) try: xvfb = subprocess.Popen(xvfb_cmd, executable=xvfb_executable, close_fds=False, stdin=subprocess.PIPE, preexec_fn=preexec, cwd=cwd) except OSError as e: log("Popen%s", (xvfb_cmd, xvfb_executable, cwd), exc_info=True) raise InitException( "failed to execute xvfb command %s: %s" % (xvfb_cmd, e)) assert xvfb.poll() is None, "xvfb command failed" # Read the display number from the pipe we gave to Xvfb try: buf = read_displayfd(r_pipe) except Exception as e: log("read_displayfd(%s)", r_pipe, exc_info=True) displayfd_err("failed to read displayfd pipe %s: %s" % (r_pipe, e)) finally: osclose(r_pipe) osclose(w_pipe) n = parse_displayfd(buf, displayfd_err) new_display_name = ":%s" % n log("Using display number provided by %s: %s", xvfb_executable, new_display_name) if tmp_xorg_log_file != None: #ie: ${HOME}/.xpra/Xorg.${DISPLAY}.log -> /home/antoine/.xpra/Xorg.S14700.log f0 = shellsub(tmp_xorg_log_file, subs) subs["DISPLAY"] = new_display_name #ie: ${HOME}/.xpra/Xorg.${DISPLAY}.log -> /home/antoine/.xpra/Xorg.:1.log f1 = shellsub(tmp_xorg_log_file, subs) if f0 != f1: try: os.rename(f0, f1) except Exception as e: log.warn("Warning: failed to rename Xorg log file,") log.warn(" from '%s' to '%s'" % (f0, f1)) log.warn(" %s" % e) display_name = new_display_name else: # use display specified xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name) xvfb_cmd.append(display_name) def preexec(): if getuid() == 0 and (uid != 0 or gid != 0): setuidgid(uid, gid) else: setsid() log("xvfb_cmd=%s", xvfb_cmd) xvfb = subprocess.Popen(xvfb_cmd, executable=xvfb_executable, close_fds=True, stdin=subprocess.PIPE, preexec_fn=preexec) xauth_add(xauthority, display_name, xauth_data, uid, gid) except Exception as e: if xvfb and xvfb.poll() is None: log.error(" stopping vfb process with pid %i", xvfb.pid) xvfb.terminate() raise log("xvfb process=%s", xvfb) log("display_name=%s", display_name) return xvfb, display_name, cleanups
def start_Xvfb(xvfb_str, vfb_geom, pixel_depth, display_name, cwd, uid, gid, username, uinput_uuid=None): if not POSIX: raise InitException("starting an Xvfb is not supported on %s" % os.name) if OSX: raise InitException("starting an Xvfb is not supported on MacOS") if not xvfb_str: raise InitException("the 'xvfb' command is not defined") log = get_vfb_logger() log("start_Xvfb%s", (xvfb_str, vfb_geom, pixel_depth, display_name, cwd, uid, gid, username, uinput_uuid)) use_display_fd = display_name[0]=='S' subs = {} def pathexpand(s): return osexpand(s, actual_username=username, uid=uid, gid=gid, subs=subs) etc_prefix = os.environ.get("XPRA_INSTALL_PREFIX", "") if etc_prefix.endswith("/usr"): etc_prefix = etc_prefix[:-4] subs.update({ "DISPLAY" : display_name, "XPRA_LOG_DIR" : pathexpand(os.environ.get("XPRA_LOG_DIR")), "XORG_CONFIG_PREFIX" : os.environ.get("XORG_CONFIG_PREFIX", etc_prefix), }) #identify logfile argument if it exists, #as we may have to rename it, or create the directory for it: xvfb_cmd = shlex.split(xvfb_str) if not xvfb_cmd: raise InitException("cannot start Xvfb, the command definition is missing!") #make sure all path values are expanded: xvfb_cmd = [pathexpand(s) for s in xvfb_cmd] #try to honour initial geometries if specified: if vfb_geom and xvfb_cmd[0].endswith("Xvfb"): #find the '-screen' arguments: #"-screen 0 8192x4096x24+32" try: no_arg = xvfb_cmd.index("0") except ValueError: no_arg = -1 geom_str = "%sx%s" % ("x".join(str(x) for x in vfb_geom), pixel_depth) if no_arg>0 and xvfb_cmd[no_arg-1]=="-screen" and len(xvfb_cmd)>(no_arg+1): #found an existing "-screen" argument for this screen number, #replace it: xvfb_cmd[no_arg+1] = geom_str else: #append: xvfb_cmd += ["-screen", "0", geom_str] try: logfile_argindex = xvfb_cmd.index('-logfile') if logfile_argindex+1>=len(xvfb_cmd): raise InitException("invalid xvfb command string: -logfile should not be last") xorg_log_file = xvfb_cmd[logfile_argindex+1] except ValueError: xorg_log_file = None tmp_xorg_log_file = None if xorg_log_file: if use_display_fd: #keep track of it so we can rename it later: tmp_xorg_log_file = xorg_log_file #make sure the Xorg log directory exists: xorg_log_dir = os.path.dirname(xorg_log_file) if not os.path.exists(xorg_log_dir): try: log("creating Xorg log dir '%s'", xorg_log_dir) os.mkdir(xorg_log_dir, 0o700) if POSIX and uid!=getuid() or gid!=getgid(): try: os.lchown(xorg_log_dir, uid, gid) except OSError: log("lchown(%s, %i, %i)", xorg_log_dir, uid, gid, exc_info=True) except OSError as e: raise InitException("failed to create the Xorg log directory '%s': %s" % (xorg_log_dir, e)) from None if uinput_uuid: #use uinput: #identify -config xorg.conf argument and replace it with the uinput one: try: config_argindex = xvfb_cmd.index("-config") except ValueError as e: log.warn("Warning: cannot use uinput") log.warn(" '-config' argument not found in the xvfb command") else: if config_argindex+1>=len(xvfb_cmd): raise InitException("invalid xvfb command string: -config should not be last") xorg_conf = xvfb_cmd[config_argindex+1] if xorg_conf.endswith("xorg.conf"): xorg_conf = xorg_conf.replace("xorg.conf", "xorg-uinput.conf") if os.path.exists(xorg_conf): xvfb_cmd[config_argindex+1] = xorg_conf #create uinput device definition files: #(we have to assume that Xorg is configured to use this path..) xorg_conf_dir = pathexpand(get_Xdummy_confdir()) create_xorg_device_configs(xorg_conf_dir, uinput_uuid, uid, gid) xvfb_executable = xvfb_cmd[0] if (xvfb_executable.endswith("Xorg") or xvfb_executable.endswith("Xdummy")) and pixel_depth>0: xvfb_cmd.append("-depth") xvfb_cmd.append(str(pixel_depth)) xvfb = None try: if use_display_fd: def displayfd_err(msg): raise InitException("%s: %s" % (xvfb_executable, msg)) r_pipe, w_pipe = os.pipe() try: os.set_inheritable(w_pipe, True) #@UndefinedVariable xvfb_cmd += ["-displayfd", str(w_pipe)] xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name.lstrip(":")) def preexec(): os.setpgrp() if getuid()==0 and uid: setuidgid(uid, gid) try: xvfb = Popen(xvfb_cmd, executable=xvfb_executable, preexec_fn=preexec, cwd=cwd, pass_fds=(w_pipe,)) except OSError as e: log("Popen%s", (xvfb_cmd, xvfb_executable, cwd), exc_info=True) raise InitException("failed to execute xvfb command %s: %s" % (xvfb_cmd, e)) from None assert xvfb.poll() is None, "xvfb command failed" # Read the display number from the pipe we gave to Xvfb try: buf = read_displayfd(r_pipe) except Exception as e: log("read_displayfd(%s)", r_pipe, exc_info=True) displayfd_err("failed to read displayfd pipe %s: %s" % (r_pipe, e)) finally: osclose(r_pipe) osclose(w_pipe) n = parse_displayfd(buf, displayfd_err) new_display_name = ":%s" % n log("Using display number provided by %s: %s", xvfb_executable, new_display_name) if tmp_xorg_log_file: #ie: ${HOME}/.xpra/Xorg.${DISPLAY}.log -> /home/antoine/.xpra/Xorg.S14700.log f0 = shellsub(tmp_xorg_log_file, subs) subs["DISPLAY"] = new_display_name #ie: ${HOME}/.xpra/Xorg.${DISPLAY}.log -> /home/antoine/.xpra/Xorg.:1.log f1 = shellsub(tmp_xorg_log_file, subs) if f0 != f1: try: os.rename(f0, f1) except Exception as e: log.warn("Warning: failed to rename Xorg log file,") log.warn(" from '%s' to '%s'" % (f0, f1)) log.warn(" %s" % e) display_name = new_display_name else: # use display specified xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name) xvfb_cmd.append(display_name) def preexec(): if getuid()==0 and (uid!=0 or gid!=0): setuidgid(uid, gid) else: os.setsid() log("xvfb_cmd=%s", xvfb_cmd) xvfb = Popen(xvfb_cmd, executable=xvfb_executable, stdin=PIPE, preexec_fn=preexec) except Exception as e: if xvfb and xvfb.poll() is None: log.error(" stopping vfb process with pid %i", xvfb.pid) xvfb.terminate() raise log("xvfb process=%s", xvfb) log("display_name=%s", display_name) return xvfb, display_name