9

Desired result on a server without root:

1) Run Xvfb without input devices, or

2) Just get Xvfb to run

Background:

I have two machines both having nearly identical builds of CentOS. One machine has root access and internet and the other is sandboxed (no root access) with no package managers (no yum) and no Xserver. I'm trying to get Xvfb (X virtual frame buffer) running in the target machine for experimenting with headless firefox. When Xvfb is working, I can use xvfb-run.

What I've tried:

I've successfully transferred the Xvfb binary and the user shared libraries using this method (see the comment below the answer). I'm able to run Xvfb like so

Xvfb :1 -nolisten tcp -screen 0 1680x1050x16

but then I get a keymap error (Aside: I'd also like to deal with that temp dir issue as I've set export TMPDIR=~/tmp):

_XSERVTransmkdir: Owner of /tmp/.X11-unix should be set to root
XKB: Failed to compile keymap
Keyboard initialization failed. This could be a missing or incorrect setup of xkeyboard-config.
(EE)
Fatal server error:
(EE) Failed to activate core devices.(EE)

I don't need physical keyboard or mouse support at all. If someone could explain how to run Xvfb without input devices, then we can stop here. I've searched for hours with no success.


How I tried to get xkb working:

My next action was to bring over xkbcomp from the source machine along with the shared libraries. Next I exported the keymap file from the source machine like so:

xkbcomp -xkb $DISPLAY xkbmap

I tried to pass in the xkbdir and xkbmap to run the following with no success

Xvfb :1 -xkbdir ~/X11/xkb -xkbmap xkbmap -nolisten tcp -screen 0 1680x1050x16

because -xkbdir is a valid parameter, whereas -xkbmap is not despite the man page for Xvfb stating:

In addition to the normal server options described in the Xserver(1) manual page, Xvfb accepts the following command line switches:

and the man page for Xserver stating:

−xkbdir directory
    base directory for keyboard layout files. This option is not available for setuid X servers (i.e., when the X server’s real and effective uids are different).
    ...
−xkbmap filename
    loads keyboard description in filename on server startup.

If I just pass in -xkbdir

$ export PATH=~/bin:$PATH; # all copied binaries are here, including xkbcomp
$ Xvfb :1 -xkbdir ~/X11/xkb -nolisten tcp -screen 0 1680x1050x16

then I get

_XSERVTransmkdir: Owner of /tmp/.X11-unix should be set to root
    sh: /usr/bin/xkbcomp: No such file or directory <-- WHY THIS PATH?
    sh: /usr/bin/xkbcomp: No such file or directory
    XKB: Failed to compile keymap
    Keyboard initialization failed. This could be a missing or incorrect setup of xkeyboard-config.
    (EE)
    Fatal server error:
    (EE) Failed to activate core devices.(EE)

This is where I've been stuck for hours. On a machine without root, either

1) How can I run Xvfb without input devices? or

2) How can I just get Xvfb to run?

5
  • Not a solution to your problem, but I just run successfully Xvfb as user under Debian with Xvfb :1 -screen 0 640x480x24 -nolisten tcp on my desktop (of course with another X server as main display). No complaints about xkbd, and the owner of /tmp/.X11-unix is root (because of the first server). So one guess is that you might be missing some necessary files. /usr/bin/xkbcomp is a binary that compiles keymap description files. Those files are in /usr/share/X11/xkb on my system.
    – dirkt
    Oct 8, 2016 at 7:11
  • Doing strings on Xvfb shows %s%sxkbcomp" -w %d %s -xkm "%s" -em1 %s -emp %s -eml %s "%s%s.xkm, so there is some way to set the path (and that path appears to be hardwired). There's also a string /usr/share/X11/xkb.
    – dirkt
    Oct 8, 2016 at 7:16
  • Ah, and you'll need a keymap even if you don't have a physical keyboard, because the keyboard mapping functions are independent from the actual input devices.
    – dirkt
    Oct 8, 2016 at 7:19
  • The directory may be hardwired, see XkbBinDirectory in xkbInit.c. Though there seem to be patches that fix this. It depends on what CentOS does, I guess. The quickest option may be to patch the Xvfb binary with your path.
    – dirkt
    Oct 8, 2016 at 7:31
  • The actual invocation of xkbcomp is in RunXkbComp in ddxLoad.c, and I don't see anything to change that path. So, patch path in the binary, install a fake xkbcomp binary first that shows you the arguments, then install the necessary keymap files.
    – dirkt
    Oct 8, 2016 at 8:02

3 Answers 3

5
+50

Partial answer: How to run Xvfb without xkeycomp.

According to your description, your main problem doesn't seem to be to run Xvfb as non-root (that works quite well on my system), but that as non-root you cannot install auxiliary programs like xkeycomp and their associated data files in the place where Xvfb expects them.

That's difficult to simulate without knowing exactly what is and isn't installed on your sandboxed CentOS environment. But here's how to get rid of the xkeycomp dependency:

As using strings on Xvfb shows, the invocation of xkeycomp looks like "%s%sxkbcomp" -w %d %s -xkm "%s" -em1 %s -emp %s -eml %s "%s%s.xkm", and the corresponding source files are xkbInit.c and ddxLoad.c. From a cursory inspection, it looks like the path to xkbcomp is hardwired. But the string is long enough to replace it with a call to a script instead, which shows that Xvfb wants to compile the following description

xkb_keymap "default" {
    xkb_keycodes             { include "evdev+aliases(qwerty)" };
    xkb_types                { include "complete" };
    xkb_compatibility        { include "complete" };
    xkb_symbols              { include "pc+us+inet(evdev)" };
    xkb_geometry             { include "pc(pc105)" };
};

provided from stdin, into the file /tmp/server-1.xkm. So on a machine with X and tools, copy this description to a file, say default.xkb, and compile it

xkbcomp -xkm default.xkb 

to default.xkm. Now patch your copy of Xvfb on the CentOS sandbox by searching for the invocation:

$ grep -FobUa '"%s%sxkbcomp' Xvfb
1648800:"%s%sxkbcomp

and patch it with a call to cp:

echo -n '/bin/cp /home/dirk/tmp/xvfb/default.xkm /tmp/server-1.xkm          ' | dd bs=1 of=Xvfb seek=1648800 conv=notrunc

(of course with your position and your path to default.xkm).

That works fine on my machine, but on your sandboxed CentOS machine it will now probably trigger the next problem. :-)

And the X API decouples the functions to inspect the keyboard mapping from actual input devices, so even if there are no input devices, a keyboard mapping must still be present.

8
  • This is a really good workup. I'm going to run this down and let you know the results shortly.
    – Drakes
    Oct 9, 2016 at 3:35
  • The next problem you will probably run into is that you don't have any X fonts installed (unless firefox doesn't use any X fonts anymore, I never checked).
    – dirkt
    Oct 9, 2016 at 5:28
  • Thank you for your help. You have some clever ideas and I like your way of thinking - very hack3r. I had some trouble with the path lengths, so I ended up compiling Xvfb from source. But again, very clever job here.
    – Drakes
    Oct 13, 2016 at 17:15
  • YW. Didn't want to recommend recompiling Xvfb, it's probably not so easy to set up. :-)
    – dirkt
    Oct 13, 2016 at 17:31
  • Oh it was an absolute PITA. ;)
    – Drakes
    Oct 13, 2016 at 18:01
4

I was successfully able to get Xvfb running without root.

In the end, I downloaded the source code from https://www.x.org/wiki/Releases/Download/, injected environment variables, installed dependencies (yum), and compiled Xvfb and transferred that binary and shared libraries to my sandbox.

Critically, in [sources]/xkb/xkbInit.c I added these lines around line 815:

        if (++i >= argc)
            UseMsg();
        else
            XkbDfltRepeatInterval = (long) atoi(argv[i]);
        return 2;
    }
    /* End original code */


    // Change xkbcomp bin directory with an environment variable
    char *xkbBinDir = getenv("XKB_BINDIR");
    if (xkbBinDir) {
        XkbBinDirectory = Xstrdup(xkbBinDir);
    }

    // Change base xkb directory with an environment variable
    char *xkbBaseDir = getenv("XKBDIR");
    if (xkbBaseDir) {
        XkbBaseDirectory = Xstrdup(xkbBaseDir);
    }


    /* Original code */
    return 0;
}

I can set the environment variables XKB_BINDIR to my xkbcomp binary path (copied to the sandbox), and XKBDIR to where my default.xkm file is.

Again, my successful strategy was to compile Xvfb from source with modifications. For excruciating details and step-by-step instructions, I wrote this up on my site here - https://ericdraken.com/running-xvfb-on-a-shared-host-without-x/


@dirkt had an interesting approach which was to hack the Xvfb binary and do string manipulation. That's appealing as it is quick and somewhat naughty, but it had drawbacks: 1) I can't know what the server number is in advance [1 .. 99], and 2) My paths are too long and would require symlinks. I actually tried a NOP command (:) as the string replacement along with manual copying of the server-N.xkm, except that there are two logic paths to contend with in the source code, one being when the xkm file is cached.

1
  • I followed these instructions and ldd Xvfb showed the binary I built want libGL.so.1 - so I had to built Xvfb from the 1.17 of the source repo instead (git clone git://anongit.freedesktop.org/git/xorg/xserver && git -C xserver checkout server-1.17-branch Jan 5, 2017 at 23:09
2

A similar approach is to use Xdummy, if xserver-xorg-video-dummy is available on your sandboxed system. It uses some dummy drivers and provides an X server that can run without root privileges. You can find some explanations and a sample xorg.conf on xpra website: https://xpra.org/trac/wiki/Xdummy . It needs X to be installed, but doesn't need a running X server.

(Sorry, I've got not enough reputation to post this as a comment)

1
  • Thank you, however I'd like to stay with Xvfb to work with other scripts. This might help someone else though.
    – Drakes
    Oct 13, 2016 at 17:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .