Example #1
0
def select_log_file(log_dir, log_file, display_name):
    """ returns the log file path we should be using given the parameters,
        this may return a temporary logpath if display_name is not available.
    """
    if log_file:
        if os.path.isabs(log_file):
            logpath = log_file
        else:
            logpath = os.path.join(log_dir, log_file)
        v = shellsub(logpath, {"DISPLAY" : display_name})
        if display_name or v==logpath:
            #we have 'display_name', or we just don't need it:
            return v
    if display_name:
        logpath = norm_makepath(log_dir, display_name) + ".log"
    else:
        logpath = os.path.join(log_dir, "tmp_%d.log" % os.getpid())
    return logpath
Example #2
0
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
Example #3
0
def init_client_mmap(mmap_group=None,
                     socket_filename=None,
                     size=128 * 1024 * 1024,
                     filename=None):
    """
        Initializes an mmap area, writes the token in it and returns:
            (success flag, mmap_area, mmap_size, temp_file, mmap_filename)
        The caller must keep hold of temp_file to ensure it does not get deleted!
        This is used by the client.
    """
    def rerr():
        return False, False, None, 0, None, None

    log("init_mmap%s", (mmap_group, socket_filename, size, filename))
    mmap_filename = filename
    mmap_temp_file = None
    delete = True

    def validate_size(size):
        assert size >= 64 * 1024 * 1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit(
            size)
        assert size <= 4 * 1024 * 1024 * 1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit(
            size)

    try:
        import mmap
        unit = max(4096, mmap.PAGESIZE)
        #add 8 bytes for the mmap area control header zone:
        mmap_size = roundup(size + 8, unit)
        if WIN32:
            validate_size(mmap_size)
            if not filename:
                from xpra.net.crypto import get_hex_uuid
                filename = "xpra-%s" % get_hex_uuid()
            mmap_filename = filename
            mmap_area = mmap.mmap(0, mmap_size, filename)
            #not a real file:
            delete = False
            mmap_temp_file = None
        else:
            assert POSIX
            if filename:
                if os.path.exists(filename):
                    fd = os.open(filename, os.O_EXCL | os.O_RDWR)
                    mmap_size = os.path.getsize(mmap_filename)
                    validate_size(mmap_size)
                    #mmap_size = 4*1024*1024    #size restriction needed with ivshmem
                    delete = False
                    log.info("Using existing mmap file '%s': %sMB",
                             mmap_filename, mmap_size // 1024 // 1024)
                else:
                    validate_size(mmap_size)
                    import errno
                    flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
                    try:
                        fd = os.open(filename, flags)
                        mmap_temp_file = None  #os.fdopen(fd, 'w')
                        mmap_filename = filename
                    except OSError as e:
                        if e.errno == errno.EEXIST:
                            log.error(
                                "Error: the mmap file '%s' already exists",
                                filename)
                            return rerr()
                        raise
            else:
                validate_size(mmap_size)
                import tempfile
                from xpra.platform.paths import get_mmap_dir
                mmap_dir = get_mmap_dir()
                subs = os.environ.copy()
                subs.update({
                    "UID": os.getuid(),
                    "GID": os.getgid(),
                    "PID": os.getpid(),
                })
                mmap_dir = shellsub(mmap_dir, subs)
                if mmap_dir and not os.path.exists(mmap_dir):
                    os.mkdir(mmap_dir, 0o700)
                if not mmap_dir or not os.path.exists(mmap_dir):
                    raise Exception("mmap directory %s does not exist!" %
                                    mmap_dir)
                #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures
                #that the file is readable and writable only by the creating user ID
                try:
                    temp = tempfile.NamedTemporaryFile(prefix="xpra.",
                                                       suffix=".mmap",
                                                       dir=mmap_dir)
                except OSError as e:
                    log.error("Error: cannot create mmap file:")
                    log.error(" %s", e)
                    return rerr()
                #keep a reference to it so it does not disappear!
                mmap_temp_file = temp
                mmap_filename = temp.name
                fd = temp.file.fileno()
            #set the group permissions and gid if the mmap-group option is specified
            if mmap_group and type(socket_filename) == str and os.path.exists(
                    socket_filename):
                from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP
                s = os.stat(socket_filename)
                os.fchown(fd, -1, s.st_gid)
                os.fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
            log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd,
                mmap_size)
            os.lseek(fd, mmap_size - 1, os.SEEK_SET)
            assert os.write(fd, b'\x00')
            os.lseek(fd, 0, os.SEEK_SET)
            mmap_area = mmap.mmap(fd, length=mmap_size)
        return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename
    except Exception as e:
        log("failed to setup mmap: %s", e, exc_info=True)
        log.error("Error: mmap setup failed:")
        log.error(" %s", e)
        clean_mmap(mmap_filename)
        return rerr()
Example #4
0
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
Example #5
0
def start_Xvfb(xvfb_str, pixel_depth, display_name, cwd, uid, gid, xauth_data):
    if not POSIX:
        raise InitException("starting an Xvfb is not supported on %s" %
                            os.name)
    if not xvfb_str:
        raise InitException("the 'xvfb' command is not defined")

    from xpra.log import Logger
    log = Logger("server", "x11")

    # We need to set up a new server environment
    xauthority = os.environ.get("XAUTHORITY",
                                os.path.expanduser("~/.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)
    use_display_fd = display_name[0] == 'S'

    #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)
    try:
        logfile_argindex = xvfb_cmd.index('-logfile')
    except ValueError:
        logfile_argindex = -1
    assert logfile_argindex + 1 < len(
        xvfb_cmd
    ), "invalid xvfb command string: -logfile should not be last (found at index %i)" % logfile_argindex
    tmp_xorg_log_file = None
    if logfile_argindex > 0:
        if use_display_fd:
            #keep track of it so we can rename it later:
            tmp_xorg_log_file = xvfb_cmd[logfile_argindex + 1]
        #make sure the Xorg log directory exists:
        xorg_log_dir = osexpand(os.path.dirname(xvfb_cmd[logfile_argindex +
                                                         1]))
        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))

    #apply string substitutions:
    subs = {
        "XAUTHORITY": xauthority,
        "USER": os.environ.get("USER", "unknown-user"),
        "UID": os.getuid(),
        "GID": os.getgid(),
        "HOME": os.environ.get("HOME", cwd),
        "DISPLAY": display_name,
        "XPRA_LOG_DIR": os.environ.get("XPRA_LOG_DIR"),
    }
    xvfb_cmd = shellsub(xvfb_str, subs).split()
    log("shellsub(%s, %s)=%s", xvfb_str, subs, xvfb_cmd)

    if not xvfb_cmd:
        raise InitException(
            "cannot start Xvfb, the command definition is missing!")
    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))
    if use_display_fd:
        # 'S' means that we allocate the display automatically
        r_pipe, w_pipe = os.pipe()
        xvfb_cmd += ["-displayfd", str(w_pipe)]
        xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name)

        def preexec():
            setsid()
            if POSIX and getuid() == 0 and uid:
                setuidgid(uid, gid)
            close_fds([0, 1, 2, r_pipe, w_pipe])

        log("xvfb_cmd=%s", xvfb_cmd)
        xvfb = subprocess.Popen(xvfb_cmd,
                                executable=xvfb_executable,
                                close_fds=False,
                                stdin=subprocess.PIPE,
                                preexec_fn=preexec,
                                cwd=cwd)
        # Read the display number from the pipe we gave to Xvfb
        # waiting up to 10 seconds for it to show up
        limit = monotonic_time() + 10
        buf = ""
        import select  #@UnresolvedImport
        while monotonic_time() < limit and len(buf) < 8:
            r, _, _ = select.select([r_pipe], [], [],
                                    max(0, limit - monotonic_time()))
            if r_pipe in r:
                buf += os.read(r_pipe, 8)
                if buf[-1] == '\n':
                    break
        os.close(r_pipe)
        os.close(w_pipe)
        if len(buf) == 0:
            raise InitException(
                "%s did not provide a display number using -displayfd" %
                xvfb_executable)
        if buf[-1] != '\n':
            raise InitException("%s output not terminated by newline: %s" %
                                (xvfb_executable, buf))
        try:
            n = int(buf[:-1])
        except:
            raise InitException("%s display number is not a valid number: %s" %
                                (xvfb_executable, buf[:-1]))
        if n < 0 or n >= 2**16:
            raise InitException("%s provided an invalid display number: %s" %
                                (xvfb_executable, n))
        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:
                    sys.stderr.write(
                        "failed to rename Xorg log file from '%s' to '%s'\n" %
                        (f0, f1))
                    sys.stderr.write(" %s\n" % 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(display_name, xauth_data)
    log("xvfb process=%s", xvfb)
    log("display_name=%s", display_name)
    return xvfb, display_name
Example #6
0
def init_client_mmap(mmap_group=None, socket_filename=None, size=128*1024*1024, filename=None):
    """
        Initializes an mmap area, writes the token in it and returns:
            (success flag, mmap_area, mmap_size, temp_file, mmap_filename)
        The caller must keep hold of temp_file to ensure it does not get deleted!
        This is used by the client.
    """
    def rerr():
        return False, False, None, 0, None, None
    log("init_mmap%s", (mmap_group, socket_filename, size, filename))
    mmap_filename = filename
    mmap_temp_file = None
    delete = True
    def validate_size(size : int):
        assert size>=64*1024*1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit(size)
        assert size<=4*1024*1024*1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit(size)
    try:
        import mmap
        unit = max(4096, mmap.PAGESIZE)
        #add 8 bytes for the mmap area control header zone:
        mmap_size = roundup(size + 8, unit)
        if WIN32:
            validate_size(mmap_size)
            if not filename:
                from xpra.os_util import get_hex_uuid
                filename = "xpra-%s" % get_hex_uuid()
            mmap_filename = filename
            mmap_area = mmap.mmap(0, mmap_size, filename)
            #not a real file:
            delete = False
        else:
            assert POSIX
            if filename:
                if os.path.exists(filename):
                    fd = os.open(filename, os.O_EXCL | os.O_RDWR)
                    mmap_size = os.path.getsize(mmap_filename)
                    validate_size(mmap_size)
                    #mmap_size = 4*1024*1024    #size restriction needed with ivshmem
                    delete = False
                    log.info("Using existing mmap file '%s': %sMB", mmap_filename, mmap_size//1024//1024)
                else:
                    validate_size(mmap_size)
                    flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
                    try:
                        fd = os.open(filename, flags)
                        mmap_temp_file = None   #os.fdopen(fd, 'w')
                        mmap_filename = filename
                    except FileExistsError:
                        log.error("Error: the mmap file '%s' already exists", filename)
                        return rerr()
            else:
                validate_size(mmap_size)
                import tempfile
                from xpra.platform.paths import get_mmap_dir
                mmap_dir = get_mmap_dir()
                subs = os.environ.copy()
                subs.update({
                    "UID"               : os.getuid(),
                    "GID"               : os.getgid(),
                    "PID"               : os.getpid(),
                    })
                mmap_dir = shellsub(mmap_dir, subs)
                if mmap_dir and not os.path.exists(mmap_dir):
                    os.mkdir(mmap_dir, 0o700)
                if not mmap_dir or not os.path.exists(mmap_dir):
                    raise Exception("mmap directory %s does not exist!" % mmap_dir)
                #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures
                #that the file is readable and writable only by the creating user ID
                try:
                    temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir)
                except OSError as e:
                    log.error("Error: cannot create mmap file:")
                    log.error(" %s", e)
                    return rerr()
                #keep a reference to it so it does not disappear!
                mmap_temp_file = temp
                mmap_filename = temp.name
                fd = temp.file.fileno()
            #set the group permissions and gid if the mmap-group option is specified
            mmap_group = (mmap_group or "")
            if POSIX and mmap_group and mmap_group not in FALSE_OPTIONS:
                group_id = None
                if mmap_group=="SOCKET":
                    group_id = get_socket_group(socket_filename)
                elif mmap_group.lower()=="auto":
                    group_id = xpra_group()
                    if not group_id and socket_filename:
                        group_id = get_socket_group(socket_filename)
                elif mmap_group.lower() in TRUE_OPTIONS:
                    log.info("parsing legacy mmap-group value '%s' as 'auto'", mmap_group)
                    log.info(" please update your configuration")
                    group_id = xpra_group() or get_socket_group(socket_filename)
                else:
                    group_id = get_group_id(mmap_group)
                if group_id>0:
                    log("setting mmap file %s to group id=%i", mmap_filename, group_id)
                    try:
                        os.fchown(fd, -1, group_id)
                    except OSError as e:
                        log("fchown(%i, %i, %i) on %s", fd, -1, group_id, mmap_filename, exc_info=True)
                        log.error("Error: failed to change group ownership of mmap file to '%s':", mmap_group)
                        log.error(" %s", e)
                    from stat import S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP
                    os.fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
            log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd, mmap_size)
            os.lseek(fd, mmap_size-1, os.SEEK_SET)
            assert os.write(fd, b'\x00')
            os.lseek(fd, 0, os.SEEK_SET)
            mmap_area = mmap.mmap(fd, length=mmap_size)
        return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename
    except Exception as e:
        log("failed to setup mmap: %s", e, exc_info=True)
        log.error("Error: mmap setup failed:")
        log.error(" %s", e)
        if delete:
            if mmap_temp_file:
                try:
                    mmap_temp_file.close()
                except OSError:
                    log("%s()", mmap_temp_file.close, exc_info=True)
                    log.error(" failed to remove the mmap temp file: %s", e)
            else:
                clean_mmap(mmap_filename)
        return rerr()