]> git.sur5r.net Git - i3/i3/commitdiff
add Xdummy script to start a headless X11 server
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 25 Jul 2011 13:37:46 +0000 (15:37 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 25 Jul 2011 13:37:46 +0000 (15:37 +0200)
testcases/Xdummy [new file with mode: 0755]

diff --git a/testcases/Xdummy b/testcases/Xdummy
new file mode 100755 (executable)
index 0000000..638a7b3
--- /dev/null
@@ -0,0 +1,1930 @@
+#!/bin/sh
+# ----------------------------------------------------------------------
+#    Copyright (C) 2005-2010 Karl J. Runge <runge@karlrunge.com> 
+#    All rights reserved.
+# 
+# This file is part of Xdummy.
+# 
+# Xdummy is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+# 
+# Xdummy is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with Xdummy; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+# or see <http://www.gnu.org/licenses/>.
+# ----------------------------------------------------------------------
+# 
+# 
+# Xdummy: an LD_PRELOAD hack to run a stock Xorg(1) or XFree86(1) server
+# with the "dummy" video driver to make it avoid Linux VT switching, etc.
+#
+# Run "Xdummy -help" for more info.
+#
+install=""
+uninstall=""
+runit=1
+prconf=""
+notweak=""
+root=""
+nosudo=""
+xserver=""
+geom=""
+nomodelines=""
+depth=""
+debug=""
+strace=""
+cmdline_config=""
+
+PATH=$PATH:/bin:/usr/bin
+export PATH
+
+program=`basename "$0"`
+
+help () {
+       ${PAGER:-more} << END
+$program:
+
+    A hack to run a stock Xorg(1) or XFree86(1) X server with the "dummy"
+    (RAM-only framebuffer) video driver such that it AVOIDS the Linux VT
+    switching, opening device files in /dev, keyboard and mouse conflicts,
+    and other problems associated with the normal use of "dummy".
+
+    In other words, it tries to make Xorg/XFree86 with the "dummy"
+    device driver act more like Xvfb(1).
+
+    The primary motivation for the Xdummy script is to provide a virtual X
+    server for x11vnc but with more features than Xvfb (or Xvnc); however
+    it could be used for other reasons (e.g. better automated testing
+    than with Xvfb.)  One nice thing is the dummy server supports RANDR
+    dynamic resizing while Xvfb does not.
+
+    So, for example, x11vnc+Xdummy terminal services are a little better
+    than x11vnc+Xvfb.
+
+    To achieve this, while running the real Xserver $program intercepts
+    system and library calls via the LD_PRELOAD method and modifies
+    the behavior to make it work correctly (e.g. avoid the VT stuff.)
+    LD_PRELOAD tricks are usually "clever hacks" and so might not work
+    in all situations or break when something changes.
+
+    WARNING: Take care in using Xdummy, although it never has it is
+    possible that it could damage hardware.  One can use the -prconf
+    option to have it print out the xorg.conf config that it would use
+    and then inspect it carefully before actually using it.
+
+    This program no longer needs to be run as root as of 12/2009.
+    However, if there are problems for certain situations (usually older
+    servers) it may perform better if run as root (use the -root option.)
+    When running as root remember the previous paragraph and that Xdummy
+    comes without any warranty.
+
+    gcc/cc and other build tools are required for this script to be able
+    to compile the LD_PRELOAD shared object.  Be sure they are installed
+    on the system.  See -install and -uninstall described below.
+
+    Your Linux distribution may not install the dummy driver by default,
+    e.g:
+
+        /usr/lib/xorg/modules/drivers/dummy_drv.so
+    
+    some have it in a package named xserver-xorg-video-dummy you that
+    need to install.
+
+Usage:
+
+       $program <${program}-args> <Xserver-args>
+
+       (actually, the arguments can be supplied in any order.)
+
+Examples:
+
+       $program -install
+
+       $program :1
+
+       $program -debug :1
+
+       $program -tmpdir ~/mytmp :1 -nolisten tcp
+
+startx example:
+
+       startx -e bash -- $program :2 -depth 16
+
+       (if startx needs to be run as root, you can su(1) to a normal
+       user in the bash shell and then launch ~/.xinitrc or ~/.xsession,
+       gnome-session, startkde, startxfce4, etc.)
+
+xdm example:
+
+       xdm -config /usr/local/dummy/xdm-config -nodaemon
+
+       where the xdm-config file has line:
+
+            DisplayManager.servers:         /usr/local/dummy/Xservers
+
+       and /usr/local/dummy/Xservers has lines:
+
+            :1 local /usr/local/dummy/Xdummy :1 -debug
+            :2 local /usr/local/dummy/Xdummy :2 -debug
+
+        (-debug is optional)
+
+gdm/kdm example:
+
+       TBD.
+
+Root permission and x11vnc:
+
+       Update: as of 12/2009 this program no longer must be run as root.
+       So try it as non-root before running it as root and/or the
+       following schemes.
+
+       In some circumstances X server program may need to be run as root.
+       If so, one could run x11vnc as root with -unixpw (it switches
+       to the user that logs in) and that may be OK, some other ideas:
+
+       - add this to sudo via visudo:
+
+               ALL ALL = NOPASSWD: /usr/local/bin/Xdummy
+
+       - use this little suid wrapper:
+/* 
+ * xdummy.c
+ *
+   cc -o ./xdummy xdummy.c
+   sudo cp ./xdummy /usr/local/bin/xdummy
+   sudo chown root:root /usr/local/bin/xdummy
+   sudo chmod u+s /usr/local/bin/xdummy
+ *
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[]) {
+       extern char **environ;
+       char str[100];
+       sprintf(str, "XDUMMY_UID=%d", (int) getuid());
+       putenv(str);
+       setuid(0);  
+       setgid(0);
+       execv("/usr/local/bin/Xdummy", argv); 
+       exit(1);
+       return 1;
+}
+
+
+Options:
+
+    ${program}-args:
+
+       -install        Compile the LD_PRELOAD shared object and install it
+                       next to the $program script file as:
+
+                         $0.so
+
+                       When that file exists it is used as the LD_PRELOAD
+                       shared object without recompiling.  Otherwise,
+                       each time $program is run the LD_PRELOAD shared
+                       object is compiled as a file in /tmp (or -tmpdir)
+
+                       If you set the environment variable
+                       INTERPOSE_GETUID=1 when building, then when
+                       $program is run as an ordinary user, the shared
+                       object will interpose getuid() calls and pretend
+                       to be root.  Otherwise it doesn't pretend to
+                       be root.
+
+                       You can also set the CFLAGS environment variable
+                       to anything else you want on the compile cmdline.
+
+       -uninstall      Remove the file:
+
+                         $0.so
+
+                       The LD_PRELOAD shared object will then be compiled
+                       each time this program is run.
+
+       The X server is not started under -install, -uninstall, or -prconf.
+
+
+       :N              The DISPLAY (e.g. :15) is often the first
+                       argument.  It is passed to the real X server and
+                       also used by the Xdummy script as an identifier.
+
+       -geom geom1[,geom2...]  Take the geometry (e.g. 1024x768) or list
+                       of geometries and insert them into the Screen
+                       section of the tweaked X server config file.
+                       Use this to have a different geometry than the
+                       one(s) in the system config file.
+
+                       The option -geometry can be used instead of -geom;
+                       x11vnc calls Xdummy and Xvfb this way.
+
+       -nomodelines    When you specify -geom/-geometry, $program will
+                       create Modelines for each geometry and put them
+                       in the Monitor section.  If you do not want this
+                       then supply -nomodelines.
+
+       -depth n        Use pixel color depth n (e.g. 8, 16, or 24). This
+                       makes sure the X config file has a Screen.Display
+                       subsection of this depth.  Note this option is
+                       ALSO passed to the X server.
+
+       -DEPTH n        Same as -depth, except not passed to X server.
+
+       -tmpdir dir     Specify a temporary directory, owned by you and
+                       only writable by you.  This is used in place of
+                       /tmp/Xdummy.\$USER/..  to place the $program.so
+                       shared object, tweaked config files, etc.
+
+       -nonroot        Run in non-root mode (working 12/2009, now default)
+
+       -root           Run as root (may still be needed in some
+                       environments.)  Same as XDUMMY_RUN_AS_ROOT=1.
+
+       -nosudo         Do not try to use sudo(1) when re-running as root,
+                       use su(1) instead.
+
+       -xserver path   Specify the path to the Xserver to use.  Default
+                       is to try "Xorg" first and then "XFree86".  If
+                       those are not in \$PATH, it tries these locations:
+                               /usr/bin/Xorg
+                               /usr/X11R6/bin/Xorg
+                               /usr/X11R6/bin/XFree86
+
+       -n              Do not run the command to start the X server,
+                       just show the command that $program would run.
+                       The LD_PRELOAD shared object will be built,
+                       if needed.  Also note any XDUMMY* environment
+                       variables that need to be set.
+
+       -prconf         Print, to stdout, the tweaked Xorg/XFree86
+                       config file (-config and -xf86config server
+                       options, respectively.)  The Xserver is not
+                       started.
+
+       -notweak        Do not tweak (modify) the Xorg/XFree86 config file
+                       (system or server command line) at all.  The -geom
+                       and similar config file modifications are ignored.
+
+                       It is up to you to make sure it is a working
+                       config file (e.g. "dummy" driver, etc.)
+                       Perhaps you want to use a file based on the
+                       -prconf output.
+
+       -debug          Extra debugging output.
+
+       -strace         strace(1) the Xserver process (for troubleshooting.)
+       -ltrace         ltrace(1) instead of strace (can be slow.)
+
+       -h, -help       Print out this help.
+
+
+    Xserver-args:
+
+       Most of the Xorg and XFree86 options will work and are simply
+       passed along if you supply them.  Important ones that may be
+       supplied if missing:
+
+       :N              X Display number for server to use.
+
+       vtNN            Linux virtual terminal (VT) to use (a VT is currently
+                       still used, just not switched to and from.)
+
+       -config file            Driver "dummy" tweaked config file, a
+       -xf86config file        number of settings are tweaked besides Driver.
+
+       If -config/-xf86config is not given, the system one
+       (e.g. /etc/X11/xorg.conf) is used.  If the system one cannot be
+       found, a built-in one is used.  Any settings in the config file
+       that are not consistent with "dummy" mode will be overwritten
+       (unless -notweak is specified.)
+
+       Use -config xdummy-builtin to force usage of the builtin config.
+
+       If "file" is only a basename (e.g. "xorg.dummy.conf") with no /'s,
+       then no tweaking of it is done: the X server will look for that
+       basename via its normal search algorithm.  If the found file does
+       not refer to the "dummy" driver, etc, then the X server will fail.
+
+Notes:
+
+    The Xorg/XFree86 "dummy" driver is currently undocumented.  It works
+    well in this mode, but it is evidently not intended for end-users.
+    So it could be removed or broken at any time.
+
+    If the display Xserver-arg (e.g. :1) is not given, or ":" is given
+    that indicates $program should try to find a free one (based on
+    tcp ports.)
+
+    If the display virtual terminal, VT, (e.g. vt9) is not given that
+    indicates $program should try to find a free one (or guess a high one.) 
+    
+    This program is not completely secure WRT files in /tmp (but it tries
+    to a good degree.)  Better is to use the -tmpdir option to supply a
+    directory only writable by you.  Even better is to get rid of users
+    on the local machine you do not trust :-)
+
+    Set XDUMMY_SET_XV=1 to turn on debugging output for this script.
+
+END
+}
+
+warn() {
+       echo "$*" 1>&2
+}
+
+if [ "X$XDUMMY_SET_XV" != "X" ]; then
+       set -xv
+fi
+
+if [ "X$XDUMMY_UID" = "X" ]; then
+       XDUMMY_UID=`id -u`
+       export XDUMMY_UID
+fi
+if [ "X$XDUMMY_UID" = "X0" ]; then
+       if [ "X$SUDO_UID" != "X" ]; then
+               XDUMMY_UID=$SUDO_UID
+               export XDUMMY_UID
+       fi
+fi
+
+# check if root=1 first:
+#
+if [ "X$XDUMMY_RUN_AS_ROOT" = "X1" ]; then
+       root=1
+fi
+for arg in $*
+do
+       if [ "X$arg" = "X-nonroot" ]; then
+               root=""
+       elif [ "X$arg" = "X-root" ]; then
+               root=1
+       fi
+done
+
+# See if it really needs to be run as root:
+#
+if [ "X$XDUMMY_SU_EXEC" = "X" -a "X$root" = "X1" -a "X`id -u`" != "X0"  ]; then
+       # this is to prevent infinite loop in case su/sudo doesn't work:
+       XDUMMY_SU_EXEC=1
+       export XDUMMY_SU_EXEC
+
+       dosu=1
+       nosudo=""
+
+       for arg in $*
+       do
+               if [ "X$arg" = "X-nonroot" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-nosudo" ]; then
+                       nosudo="1"
+               elif [ "X$arg" = "X-help" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-h" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-install" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-uninstall" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-n" ]; then
+                       dosu=""
+               elif [ "X$arg" = "X-prconf" ]; then
+                       dosu=""
+               fi
+       done
+       if [ $dosu ]; then
+               # we need to restart it with su/sudo:
+               if type sudo > /dev/null 2>&1; then
+                       :
+               else
+                       nosudo=1
+               fi
+               if [ "X$nosudo" = "X" ]; then
+                       warn "$program: supply the sudo password to restart as root:"
+                       if [ "X$XDUMMY_UID" != "X" ]; then
+                               exec sudo $0 -uid $XDUMMY_UID "$@"
+                       else
+                               exec sudo $0 "$@"
+                       fi
+               else
+                       warn "$program: supply the root password to restart as root:"
+                       if [ "X$XDUMMY_UID" != "X" ]; then
+                               exec su -c "$0 -uid $XDUMMY_UID $*"
+                       else
+                               exec su -c "$0 $*"
+                       fi
+               fi
+               # DONE:
+               exit
+       fi
+fi
+
+# This will hold the X display, e.g. :20
+#
+disp=""
+args=""
+cmdline_config=""
+
+# Process Xdummy args:
+#
+while [ "X$1" != "X" ]
+do
+    if [ "X$1" = "X-config" -o "X$1" = "X-xf86config" ]; then
+       cmdline_config="$2"
+    fi
+    case $1 in 
+       ":"*)   disp=$1
+                ;;
+       "-install") install=1; runit=""
+                ;;
+       "-uninstall") uninstall=1; runit=""
+                ;;
+       "-n")  runit=""
+                ;;
+       "-no") runit=""
+                ;;
+       "-norun") runit=""
+                ;;
+       "-prconf") prconf=1; runit=""
+                ;;
+       "-notweak") notweak=1
+                ;;
+       "-noconf")  notweak=1
+                ;;
+       "-nonroot") root=""
+                ;;
+       "-root")    root=1
+                ;;
+       "-nosudo") nosudo=1
+                ;;
+       "-xserver") xserver="$2"; shift
+                ;;
+       "-uid") XDUMMY_UID="$2"; shift
+               export XDUMMY_UID
+                ;;
+       "-geom")     geom="$2"; shift
+                ;;
+       "-geometry") geom="$2"; shift
+                ;;
+       "-nomodelines") nomodelines=1
+                ;;
+       "-depth") depth="$2"; args="$args -depth $2";
+                 shift
+                ;;
+       "-DEPTH") depth="$2"; shift
+                ;;
+       "-tmpdir") XDUMMY_TMPDIR="$2"; shift
+                ;;
+       "-debug")   debug=1
+                ;;
+       "-nodebug") debug=""
+                ;;
+       "-strace") strace=1
+                ;;
+       "-ltrace") strace=2
+                ;;
+       "-h")    help; exit 0
+                ;;
+       "-help") help; exit 0
+                ;;
+       *)      args="$args $1"
+                ;;
+    esac
+    shift
+done
+
+# Try to get a username for use in our tmp directory, etc.
+#
+user=""
+if [ X`id -u` = "X0"  ]; then
+       user=root       # this will also be used below for id=0
+elif [ "X$USER" != "X" ]; then
+       user=$USER
+elif [ "X$LOGNAME" != "X" ]; then
+       user=$LOGNAME
+fi
+
+# Keep trying...
+#
+if [ "X$user" = "X" ]; then
+       user=`whoami 2>/dev/null`
+fi
+if [ "X$user" = "X" ]; then
+       user=`basename "$HOME"`
+fi
+if [ "X$user" = "X" -o "X$user" = "X." ]; then
+       user="u$$"
+fi
+
+if [ "X$debug" = "X1" -a "X$runit" != "X" ]; then
+       echo ""
+       echo "/usr/bin/env:"
+       env | egrep -v '^(LS_COLORS|TERMCAP)' | sort
+       echo ""
+fi
+
+# Function to compile the LD_PRELOAD shared object:
+#
+make_so() {
+       # extract code embedded in this script into a tmp C file: 
+       n1=`grep -n '^#code_begin' $0 | head -1 | awk -F: '{print $1}'`
+       n2=`grep -n '^#code_end'   $0 | head -1 | awk -F: '{print $1}'`
+       n1=`expr $n1 + 1`
+       dn=`expr $n2 - $n1`
+
+       tmp=$tdir/Xdummy.$RANDOM$$.c
+       rm -f $tmp
+       if [ -e $tmp -o -h $tmp ]; then
+               warn "$tmp still exists."
+               exit 1
+       fi
+       touch $tmp || exit 1
+       tail -n +$n1 $0 | head -n $dn > $tmp
+
+       # compile it to Xdummy.so:
+       if [ -f "$SO" ]; then
+               mv $SO $SO.$$
+               rm -f $SO.$$
+       fi
+       rm -f $SO
+       touch $SO
+       if [ ! -f "$SO" ]; then
+               SO=$tdir/Xdummy.$user.so
+               warn "warning switching LD_PRELOAD shared object to: $SO"
+       fi
+
+       if [ -f "$SO" ]; then
+               mv $SO $SO.$$
+               rm -f $SO.$$
+       fi
+       rm -f $SO
+
+       # we assume gcc:
+       if [ "X$INTERPOSE_GETUID" = "X1" ]; then
+               CFLAGS="$CFLAGS -DINTERPOSE_GETUID"
+       fi
+       echo "$program:" cc -shared -fPIC $CFLAGS -o $SO $tmp
+                         cc -shared -fPIC $CFLAGS -o $SO $tmp
+       rc=$?
+       rm -f $tmp
+       if [ $rc != 0 ]; then
+               warn "$program: cannot build $SO"
+               exit 1
+       fi
+       if [ "X$debug" != "X" -o "X$install" != "X" ]; then
+               warn "$program: created  $SO"
+               ls -l "$SO"
+       fi
+}
+
+# Set tdir to tmp dir for make_so():
+if [ "X$XDUMMY_TMPDIR" != "X" ]; then
+       tdir=$XDUMMY_TMPDIR
+       mkdir -p $tdir
+else
+       tdir="/tmp"
+fi
+
+# Handle -install/-uninstall case:
+SO=$0.so
+if [ "X$install" != "X" -o "X$uninstall" != "X" ]; then
+       if [ -e "$SO" -o -h "$SO" ]; then
+               warn "$program: removing $SO"
+       fi
+       if [ -f "$SO" ]; then
+               mv $SO $SO.$$
+               rm -f $SO.$$
+       fi
+       rm -f $SO
+       if [ -e "$SO" -o -h "$SO" ]; then
+               warn "warning: $SO still exists."
+               exit 1
+       fi
+       if [ $install ]; then
+               make_so
+               if [ ! -f "$SO" ]; then
+                       exit 1
+               fi
+       fi
+       exit 0
+fi
+
+# We need a tmp directory for the .so, tweaked config file, and for
+# redirecting filenames we cannot create (under -nonroot)
+#
+tack=""
+if [ "X$XDUMMY_TMPDIR" = "X" ]; then
+       XDUMMY_TMPDIR="/tmp/Xdummy.$user"
+
+       # try to tack on a unique subdir (display number or pid)
+       # to allow multiple instances
+       #
+       if [ "X$disp" != "X" ]; then
+               t0=$disp
+       else
+               t0=$1
+       fi
+       tack=`echo "$t0" | sed -e 's/^.*://'`
+       if echo "$tack" | grep '^[0-9][0-9]*$' > /dev/null; then
+               :
+       else
+               tack=$$
+       fi
+       if [ "X$tack" != "X" ]; then
+               XDUMMY_TMPDIR="$XDUMMY_TMPDIR/$tack"
+       fi
+fi
+
+tmp=$XDUMMY_TMPDIR
+if echo "$tmp" | grep '^/tmp' > /dev/null; then
+       if [ "X$tmp" != "X/tmp" -a "X$tmp" != "X/tmp/" ]; then
+               # clean this subdir of /tmp out, otherwise leave it...
+               rm -rf $XDUMMY_TMPDIR
+               if [ -e $XDUMMY_TMPDIR ]; then
+                       warn "$XDUMMY_TMPDIR still exists"
+                       exit 1
+               fi
+       fi
+fi
+
+mkdir -p $XDUMMY_TMPDIR
+chmod 700 $XDUMMY_TMPDIR
+if [ "X$tack" != "X" ]; then
+       chmod 700 `dirname "$XDUMMY_TMPDIR"` 2>/dev/null
+fi
+
+# See if we can write something there:
+#
+tfile="$XDUMMY_TMPDIR/test.file"
+touch $tfile
+if [ ! -f "$tfile" ]; then
+       XDUMMY_TMPDIR="/tmp/Xdummy.$$.$USER"
+       warn "warning: setting tmpdir to $XDUMMY_TMPDIR ..."
+       rm -rf $XDUMMY_TMPDIR || exit 1
+       mkdir -p $XDUMMY_TMPDIR || exit 1
+fi
+rm -f $tfile
+
+export XDUMMY_TMPDIR
+
+# Compile the LD_PRELOAD shared object if needed (needs XDUMMY_TMPDIR)
+#
+if [ ! -f "$SO" ]; then
+       SO="$XDUMMY_TMPDIR/Xdummy.so"
+       make_so
+fi
+
+# Decide which X server to use:
+#
+if [ "X$xserver" = "X" ]; then
+       if type Xorg >/dev/null 2>&1; then
+               xserver="Xorg"
+       elif type XFree86 >/dev/null 2>&1; then
+               xserver="XFree86"
+       elif -x /usr/bin/Xorg; then
+               xserver="/usr/bin/Xorg"
+       elif -x /usr/X11R6/bin/Xorg; then
+               xserver="/usr/X11R6/bin/Xorg"
+       elif -x /usr/X11R6/bin/XFree86; then
+               xserver="/usr/X11R6/bin/XFree86"
+       fi
+       if [ "X$xserver" = "X" ]; then
+               # just let it fail below.
+               xserver="/usr/bin/Xorg"
+               warn "$program: cannot locate a stock Xserver... assuming $xserver"
+       fi
+fi
+
+# See if the binary is suid or not readable under -nonroot mode:
+#
+if [ "X$BASH_VERSION" != "X" ]; then
+       xserver_path=`type -p $xserver 2>/dev/null`
+else
+       xserver_path=`type $xserver 2>/dev/null | awk '{print $NF}'`
+fi
+if [ -e "$xserver_path" -a "X$root" = "X" -a "X$runit" != "X" ]; then
+       if [ ! -r $xserver_path -o -u $xserver_path -o -g $xserver_path ]; then
+               # XXX not quite correct with rm -rf $XDUMMY_TMPDIR ...
+               # we keep on a filesystem we know root can write to.
+               base=`basename "$xserver_path"`
+               new="/tmp/$base.$user.bin"
+               if [ -e $new ]; then
+                       snew=`ls -l $new          | awk '{print $5}' | grep '^[0-9][0-9]*$'`
+                       sold=`ls -l $xserver_path | awk '{print $5}' | grep '^[0-9][0-9]*$'`
+                       if [ "X$snew" != "X" -a "X$sold" != "X" -a "X$sold" != "X$snew" ]; then
+                               warn "removing different sized copy:"
+                               ls -l $new $xserver_path
+                               rm -f $new
+                       fi
+               fi
+               if [ ! -e $new -o ! -s $new ]; then
+                       rm -f $new
+                       touch $new || exit 1
+                       chmod 700 $new || exit 1
+                       if [ ! -r $xserver_path ]; then
+                               warn ""
+                               warn "NEED TO COPY UNREADABLE $xserver_path to $new as root:"
+                               warn ""
+                               ls -l $xserver_path 1>&2
+                               warn ""
+                               warn "This only needs to be done once:"
+                               warn "    cat $xserver_path > $new"
+                               warn ""
+                               nos=$nosudo
+                               if type sudo > /dev/null 2>&1; then
+                                       :
+                               else
+                                       nos=1
+                               fi
+                               if [ "X$nos" = "X1" ]; then
+                                       warn "Please supply root passwd to 'su -c'"
+                                       su -c "cat $xserver_path > $new"
+                               else
+                                       warn "Please supply the sudo passwd if asked:"
+                                       sudo /bin/sh -c "cat $xserver_path > $new"
+                               fi
+                       else
+                               warn ""
+                               warn "COPYING SETUID $xserver_path to $new"
+                               warn ""
+                               ls -l $xserver_path 1>&2
+                               warn ""
+                               cat $xserver_path > $new
+                       fi
+                       ls -l $new
+                       if [ -s $new ]; then
+                               :
+                       else
+                               rm -f $new
+                               ls -l $new
+                               exit 1
+                       fi
+                       warn ""
+                       warn "Please restart Xdummy now."
+                       exit 0
+               fi
+               if [ ! -O $new ]; then
+                       warn "file \"$new\" not owned by us!"
+                       ls -l $new
+                       exit 1
+               fi
+               xserver=$new
+       fi 
+fi
+
+# Work out display:
+#
+if [ "X$disp" != "X" ]; then
+       :
+elif [ "X$1" != "X" ]; then
+       if echo "$1" | grep '^:[0-9]' > /dev/null; then
+               disp=$1
+               shift
+       elif [ "X$1" = "X:" ]; then
+               # ":" means for us to find one.
+               shift
+       fi
+fi
+if [ "X$disp" = "X" -o "X$disp" = "X:" ]; then
+       # try to find an open display port:
+       # (tcp outdated...)
+       ports=`netstat -ant | grep LISTEN | awk '{print $4}' | sed -e 's/^.*://'`
+       n=0
+       while [ $n -le 20 ]
+       do
+               port=`printf "60%02d" $n`
+               if echo "$ports" | grep "^${port}\$" > /dev/null; then
+                       :
+               else
+                       disp=":$n"
+                       warn "$program: auto-selected DISPLAY $disp"
+                       break   
+               fi
+               n=`expr $n + 1`
+       done
+fi
+
+# Work out which vt to use, try to find/guess an open one if necessary.
+#
+vt=""
+for arg in $*
+do
+       if echo "$arg" | grep '^vt' > /dev/null; then
+               vt=$arg
+               break
+       fi
+done
+if [ "X$vt" = "X" ]; then
+       if [ "X$user" = "Xroot" ]; then
+               # root can user fuser(1) to see if it is in use:
+               if type fuser >/dev/null 2>&1; then
+                       # try /dev/tty17 thru /dev/tty32
+                       n=17
+                       while [ $n -le 32 ]
+                       do
+                               dev="/dev/tty$n"
+                               if fuser $dev >/dev/null 2>&1; then
+                                       :
+                               else
+                                       vt="vt$n"
+                                       warn "$program: auto-selected VT $vt => $dev"
+                                       break
+                               fi
+                               n=`expr $n + 1`
+                       done
+               fi
+       fi
+       if [ "X$vt" = "X" ]; then
+               # take a wild guess...
+               vt=vt16
+               warn "$program: selected fallback VT $vt"
+       fi
+else
+       vt=""
+fi
+
+# Decide flavor of Xserver:
+#
+stype=`basename "$xserver"`
+if echo "$stype" | grep -i xfree86 > /dev/null; then
+       stype=xfree86
+else
+       stype=xorg
+fi
+
+tweak_config() {
+    in="$1"
+    config2="$XDUMMY_TMPDIR/xdummy_modified_xconfig.conf"
+    if [ "X$disp" != "X" ]; then
+       d=`echo "$disp" | sed -e 's,/,,g' -e 's/:/_/g'`
+       config2="$config2$d"
+    fi
+    
+    # perl script to tweak the config file... add/delete options, etc.
+    #
+    env XDUMMY_GEOM=$geom \
+        XDUMMY_DEPTH=$depth \
+        XDUMMY_NOMODELINES=$nomodelines \
+        perl > $config2 < $in -e '
+    $n = 0;
+    $geom  = $ENV{XDUMMY_GEOM};
+    $depth = $ENV{XDUMMY_DEPTH};
+    $nomodelines = $ENV{XDUMMY_NOMODELINES};
+    $mode_str = "";
+    $videoram = "24000";
+    $HorizSync   = "30.0 - 130.0";
+    $VertRefresh = "50.0 - 250.0";
+    if ($geom ne "") {
+       my $tmp = "";
+       foreach $g (split(/,/, $geom)) {
+               $tmp .= "\"$g\" ";
+               if (!$nomodelines && $g =~ /(\d+)x(\d+)/) {
+                       my $w = $1;
+                       my $h = $2;
+                       $mode_str .= "  Modeline \"$g\" ";
+                       my $dot = sprintf("%.2f", $w * $h * 70 * 1.e-6);
+                       $mode_str .= $dot;
+                       $mode_str .= " " . $w;
+                       $mode_str .= " " . int(1.02 * $w);
+                       $mode_str .= " " . int(1.10 * $w);
+                       $mode_str .= " " . int(1.20 * $w);
+                       $mode_str .= " " . $h;
+                       $mode_str .= " " . int($h + 1);
+                       $mode_str .= " " . int($h + 3);
+                       $mode_str .= " " . int($h + 20);
+                       $mode_str .= "\n";
+               }
+       }
+       $tmp =~ s/\s*$//;
+       $geom = $tmp;
+    }
+    while (<>) {
+       if ($ENV{XDUMMY_NOTWEAK}) {
+               print $_;
+               next;
+       }
+       $n++;
+       if (/^\s*#/) {
+               # pass comments straight thru
+               print;
+               next;
+       }
+       if (/^\s*Section\s+(\S+)/i) {
+               # start of Section
+               $sect = $1;
+               $sect =~ s/\W//g;
+               $sect =~ y/A-Z/a-z/;
+               $sects{$sect} = 1;
+               print;
+               next;
+       }
+       if (/^\s*EndSection/i) {
+               # end of Section
+               if ($sect eq "serverflags") {
+                       if (!$got_DontVTSwitch) {
+                               print "  ##Xdummy:##\n";
+                               print "  Option \"DontVTSwitch\" \"true\"\n";
+                       }
+                       if (!$got_AllowMouseOpenFail) {
+                               print "  ##Xdummy:##\n";
+                               print "  Option \"AllowMouseOpenFail\" \"true\"\n";
+                       }
+                       if (!$got_PciForceNone) {
+                               print "  ##Xdummy:##\n";
+                               print "  Option \"PciForceNone\" \"true\"\n";
+                       }
+               } elsif ($sect eq "device") {
+                       if (!$got_Driver) {
+                               print "  ##Xdummy:##\n";
+                               print "  Driver \"dummy\"\n";
+                       }
+                       if (!$got_VideoRam) {
+                               print "  ##Xdummy:##\n";
+                               print "  VideoRam $videoram\n";
+                       }
+               } elsif ($sect eq "screen") {
+                       if ($depth ne "" && !got_DefaultDepth) {
+                               print "  ##Xdummy:##\n";
+                               print "  DefaultDepth $depth\n";
+                       }
+                       if ($got_Monitor eq "") {
+                               print "  ##Xdummy:##\n";
+                               print "  Monitor \"Monitor0\"\n";
+                       }
+               } elsif ($sect eq "monitor") {
+                       if (!got_HorizSync) {
+                               print "  ##Xdummy:##\n";
+                               print "  HorizSync   $HorizSync\n";
+                       }
+                       if (!got_VertRefresh) {
+                               print "  ##Xdummy:##\n";
+                               print "  VertRefresh $VertRefresh\n";
+                       }
+                       if (!$nomodelines) {
+                               print "  ##Xdummy:##\n";
+                               print $mode_str;
+                       }
+               }
+               $sect = "";
+               print;
+               next;
+       }
+
+       if (/^\s*SubSection\s+(\S+)/i) {
+               # start of Section
+               $subsect = $1;
+               $subsect =~ s/\W//g;
+               $subsect =~ y/A-Z/a-z/;
+               $subsects{$subsect} = 1;
+               if ($sect eq "screen" && $subsect eq "display") {
+                       $got_Modes = 0;
+               }
+               print;
+               next;
+       }
+       if (/^\s*EndSubSection/i) {
+               # end of SubSection
+               if ($sect eq "screen") {
+                       if ($subsect eq "display") {
+                               if ($depth ne "" && !$set_Depth) {
+                                       print "          ##Xdummy:##\n";
+                                       print "          Depth\t$depth\n";
+                               }
+                               if ($geom ne "" && ! $got_Modes) {
+                                       print "          ##Xdummy:##\n";
+                                       print "          Modes\t$geom\n";
+                               }
+                       }
+               }
+               $subsect = "";
+               print;
+               next;
+       }
+
+       $l = $_;
+       $l =~ s/#.*$//;
+       if ($sect eq "serverflags") {
+               if ($l =~ /^\s*Option.*DontVTSwitch/i) {
+                       $_ =~ s/false/true/ig;
+                       $got_DontVTSwitch = 1;
+               }
+               if ($l =~ /^\s*Option.*AllowMouseOpenFail/i) {
+                       $_ =~ s/false/true/ig;
+                       $got_AllowMouseOpenFail = 1;
+               }
+               if ($l =~ /^\s*Option.*PciForceNone/i) {
+                       $_ =~ s/false/true/ig;
+                       $got_PciForceNone= 1;
+               }
+       }
+       if ($sect eq "module") {
+               if ($l =~ /^\s*Load.*\b(dri|fbdevhw)\b/i) {
+                       $_ = "##Xdummy## $_";
+               }
+       }
+       if ($sect eq "monitor") {
+               if ($l =~ /^\s*HorizSync/i) {
+                       $got_HorizSync = 1;
+               }
+               if ($l =~ /^\s*VertRefresh/i) {
+                       $got_VertRefresh = 1;
+               }
+       }
+       if ($sect eq "device") {
+               if ($l =~ /^(\s*Driver)\b/i) {
+                       $_ = "$1 \"dummy\"\n";
+                       $got_Driver = 1;
+               }
+               if ($l =~ /^\s*VideoRam/i) {
+                       $got_VideoRam= 1;
+               }
+       }
+       if ($sect eq "inputdevice") {
+               if ($l =~ /^\s*Option.*\bDevice\b/i) {
+                       print "  ##Xdummy:##\n";
+                       $_ = "  Option \"Device\" \"/dev/dilbert$n\"\n";
+               }
+       }
+       if ($sect eq "screen") {
+               if ($l =~ /^\s*DefaultDepth\s+(\d+)/i) {
+                       if ($depth ne "") {
+                               print "  ##Xdummy:##\n";
+                               $_ = "  DefaultDepth\t$depth\n";
+                       }
+                       $got_DefaultDepth = 1;
+               }
+               if ($l =~ /^\s*Monitor\s+(\S+)/i) {
+                       $got_Monitor = $1;
+                       $got_Monitor =~ s/"//g;
+               }
+               if ($subsect eq "display") {
+                       if ($geom ne "") {
+                               if ($l =~ /^(\s*Modes)\b/i) {
+                                       print "          ##Xdummy:##\n";
+                                       $_ = "$1 $geom\n";
+                                       $got_Modes = 1;
+                               }
+                       }
+                       if ($l =~ /^\s*Depth\s+(\d+)/i) {
+                               my $d = $1;
+                               if (!$set_Depth && $depth ne "") {
+                                       $set_Depth = 1;
+                                       if ($depth != $d) {
+                                               print "          ##Xdummy:##\n";
+                                               $_ =  "          Depth\t$depth\n";
+                                       }
+                               }
+                       }
+               }
+       }
+       print;
+    }
+    if ($ENV{XDUMMY_NOTWEAK}) {
+       exit;
+    }
+    # create any crucial sections that are missing:
+    if (! exists($sects{serverflags})) {
+       print "\n##Xdummy:##\n";
+       print "Section \"ServerFlags\"\n";
+       print "  Option \"DontVTSwitch\" \"true\"\n";
+       print "  Option \"AllowMouseOpenFail\" \"true\"\n";
+       print "  Option \"PciForceNone\" \"true\"\n";
+       print "EndSection\n";
+    }
+    if (! exists($sects{device})) {
+       print "\n##Xdummy:##\n";
+       print "Section \"Device\"\n";
+       print "  Identifier \"Videocard0\"\n";
+       print "  Driver \"dummy\"\n";
+       print "  VideoRam $videoram\n";
+       print "EndSection\n";
+    }
+    if (! exists($sects{monitor})) {
+       print "\n##Xdummy:##\n";
+       print "Section \"Monitor\"\n";
+       print "  Identifier \"Monitor0\"\n";
+       print "  HorizSync   $HorizSync\n";
+       print "  VertRefresh $VertRefresh\n";
+       print "EndSection\n";
+    }
+    if (! exists($sects{screen})) {
+       print "\n##Xdummy:##\n";
+       print "Section \"Screen\"\n";
+       print "  Identifier \"Screen0\"\n";
+       print "  Device \"Videocard0\"\n";
+       if ($got_Monitor ne "") {
+               print "  Monitor \"$got_Monitor\"\n";
+       } else {
+               print "  Monitor \"Monitor0\"\n";
+       }
+       if ($depth ne "") {
+               print "  DefaultDepth $depth\n";
+       } else {
+               print "  DefaultDepth 24\n";
+       }
+       print "  SubSection \"Display\"\n";
+       print "    Viewport 0 0\n";
+       print "    Depth 24\n";
+       if ($got_Modes) {
+               ;
+       } elsif ($geom ne "") {
+               print "    Modes $geom\n";
+       } else {
+               print "    Modes \"1280x1024\" \"1024x768\" \"800x600\"\n";
+       }
+       print "  EndSubSection\n";
+       print "EndSection\n";
+    }
+';
+}
+
+# Work out config file and tweak it.
+#
+if [ "X$cmdline_config" = "X" ]; then
+       :
+elif [ "X$cmdline_config" = "Xxdummy-builtin" ]; then
+       :
+elif echo "$cmdline_config" | grep '/' > /dev/null; then
+       :
+else
+       # ignore basename only case (let server handle it)
+       cmdline_config=""
+       notweak=1
+fi
+
+config=$cmdline_config
+
+if [ "X$notweak" = "X1" -a "X$root" = "X" -a  -f "$cmdline_config" ]; then
+       # if not root we need to copy (but not tweak) the specified config.
+       XDUMMY_NOTWEAK=1
+       export XDUMMY_NOTWEAK
+       notweak=""
+fi
+
+if [ ! $notweak ]; then
+       # tweaked config will be put in $config2:
+       config2=""
+       if [ "X$config" = "X" ]; then
+               # use the default one:
+               if [ "X$stype" = "Xxorg" ]; then
+                       config=/etc/X11/xorg.conf
+               else
+                       if [ -f "/etc/X11/XF86Config-4" ]; then
+                               config="/etc/X11/XF86Config-4"
+                       else
+                               config="/etc/X11/XF86Config"
+                       fi
+               fi
+               if [ ! -f "$config" ]; then
+                       for c in /etc/X11/xorg.conf /etc/X11/XF86Config-4 /etc/X11/XF86Config
+                       do
+                               if [ -f $c ]; then
+                                       config=$c
+                                       break
+                               fi
+                       done
+               fi
+       fi
+
+       if [ "X$config" = "Xxdummy-builtin" ]; then
+               config=""
+       fi
+
+       if [ ! -f "$config" ]; then
+               config="$XDUMMY_TMPDIR/xorg.conf"
+               warn "$program: using minimal built-in xorg.conf settings."
+               cat > $config <<END
+
+Section "ServerLayout"
+    Identifier     "Layout0"
+    Screen      0  "Screen0"
+    InputDevice    "Keyboard0" "CoreKeyboard"
+    InputDevice    "Mouse0" "CorePointer"
+EndSection
+
+Section "Files"
+EndSection
+
+Section "Module"
+    Load           "dbe"
+    Load           "extmod"
+    Load           "freetype"
+    Load           "glx"
+EndSection
+
+Section "InputDevice"
+    Identifier     "Mouse0"
+    Driver         "mouse"
+    Option         "Protocol" "auto"
+    Option         "Device" "/dev/psaux"
+    Option         "Emulate3Buttons" "no"
+    Option         "ZAxisMapping" "4 5"
+EndSection
+
+Section "InputDevice"
+    Identifier     "Keyboard0"
+    Driver         "kbd"
+EndSection
+
+Section "Monitor"
+    Identifier     "Monitor0"
+    VendorName     "Unknown"
+    ModelName      "Unknown"
+    HorizSync       30.0 - 130.0
+    VertRefresh     50.0 - 250.0
+    Option         "DPMS"
+EndSection
+
+Section "Device"
+    Identifier     "Device0"
+    Driver         "foovideo"
+    VendorName     "foovideo Corporation"
+EndSection
+
+Section "Screen"
+    Identifier     "Screen0"
+    Device         "Device0"
+    Monitor        "Monitor0"
+    DefaultDepth    24
+    SubSection     "Display"
+        Depth       24
+        Modes           "1280x1024"
+    EndSubSection
+EndSection
+
+END
+       fi
+
+       if [ -f "$config" ]; then
+               tweak_config $config
+       fi
+
+       # now we need to get our tweaked config file onto the command line:
+       if [ "X$cmdline_config" = "X" ]; then
+               # append to cmdline (FUBAR will be substituted below.)
+               if [ "X$stype" = "Xxorg" ]; then
+                       args="$args -config FUBAR"
+               else
+                       args="$args -xf86config FUBAR"
+               fi
+       fi
+       if [ "X$config2" != "X" ]; then
+               # or modify $args:
+               c2=$config2
+               if [ "X$root" = "X" ]; then
+                       # ordinary user cannot use absolute path.
+                       c2=`basename $config2`
+               fi
+               args=`echo "$args" | sed \
+                       -e "s,-config  *[^ ][^ ]*,-config $c2,g" \
+                       -e "s,-xf86config  *[^ ][^ ]*,-xf86config $c2,g"`
+       fi
+fi
+
+if [ $prconf ]; then
+       warn ""
+       warn "Printing out the Xorg/XFree86 server config file:"
+       warn ""
+       if [ "X$config2" = "X" ]; then
+               warn "NO CONFIG GENERATED."
+               exit 1
+       else
+               cat "$config2"
+       fi
+       exit 0
+fi
+
+if [ $debug ]; then
+       XDUMMY_DEBUG=1
+       export XDUMMY_DEBUG
+fi
+if [ $root ]; then
+       XDUMMY_ROOT=1
+       export XDUMMY_ROOT
+fi
+
+# Finally, run it:
+#
+if [ "X$debug" != "X" -o "X$runit" = "X" ]; then
+       if [ ! $runit ]; then
+               echo ""
+               echo "/usr/bin/env:"
+               env | egrep -v '^(LS_COLORS|TERMCAP)' | sort
+               echo ""
+               echo "XDUMMY*:"
+               env | grep '^XDUMMY' | sort
+               echo ""
+       fi
+       warn ""
+       warn "The command to run is:"
+       warn ""
+       so=$SO
+       pwd=`pwd`
+       if echo "$so" | grep '^\./' > /dev/null; then
+               so=`echo "$so" | sed -e "s,^\.,$pwd,"`
+       fi
+       if echo "$so" | grep '/' > /dev/null; then
+               :
+       else
+               so="$pwd/$so"
+       fi
+       warn "env LD_PRELOAD=$so $xserver $disp $args $vt"
+       warn ""
+       if [ ! $runit ]; then
+               exit 0
+       fi
+fi
+
+if [ $strace ]; then
+       if [ "X$strace" = "X2" ]; then
+               ltrace -f env LD_PRELOAD=$SO $xserver $disp $args $vt
+       else
+               strace -f env LD_PRELOAD=$SO $xserver $disp $args $vt
+       fi
+else
+       exec env LD_PRELOAD=$SO $xserver $disp $args $vt
+fi
+
+exit $?
+
+#########################################################################
+
+code() {
+#code_begin
+#include <stdio.h>
+#define O_ACCMODE          0003
+#define O_RDONLY             00
+#define O_WRONLY             01
+#define O_RDWR               02
+#define O_CREAT            0100 /* not fcntl */
+#define O_EXCL             0200 /* not fcntl */
+#define O_NOCTTY           0400 /* not fcntl */
+#define O_TRUNC           01000 /* not fcntl */
+#define O_APPEND          02000
+#define O_NONBLOCK        04000
+#define O_NDELAY        O_NONBLOCK
+#define O_SYNC           010000
+#define O_FSYNC          O_SYNC
+#define O_ASYNC          020000
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/vt.h>
+#include <linux/kd.h>
+
+#define __USE_GNU
+#include <dlfcn.h>
+
+static char tmpdir[4096];
+static char str1[4096];
+static char str2[4096];
+
+static char devs[256][1024];
+static int debug = -1;
+static int root = -1;
+static int changed_uid = 0;
+static int saw_fonts = 0;
+static int saw_lib_modules = 0;
+
+static time_t start = 0; 
+
+void check_debug(void) {
+       if (debug < 0) {
+               if (getenv("XDUMMY_DEBUG") != NULL) {
+                       debug = 1;
+               } else {
+                       debug = 0;
+               }
+               /* prevent other processes using the preload: */
+               putenv("LD_PRELOAD=");
+       }
+}
+void check_root(void) {
+       if (root < 0) {
+               /* script tells us if we are root */
+               if (getenv("XDUMMY_ROOT") != NULL) {
+                       root = 1;
+               } else {
+                       root = 0;
+               }
+       }
+}
+
+void check_uid(void) {
+       if (start == 0) {
+               start = time(NULL);
+               if (debug) fprintf(stderr, "START: %u\n", (unsigned int) start);
+               return;
+       } else if (changed_uid == 0) {
+               if (saw_fonts || time(NULL) > start + 20) {
+                       if (getenv("XDUMMY_UID")) {
+                               int uid = atoi(getenv("XDUMMY_UID"));
+                               if (debug) fprintf(stderr, "SETREUID: %d saw_fonts=%d\n", uid, saw_fonts);
+                               if (uid >= 0) {
+                                       /* this will simply fail in -nonroot mode: */
+                                       setreuid(uid, -1);
+                               }
+                       }
+                       changed_uid = 1;
+               }
+       }
+}
+
+#define CHECKIT if (debug < 0) check_debug(); \
+               if (root  < 0) check_root(); \
+               check_uid();
+
+static void set_tmpdir(void) {
+       char *s;
+       static int didset = 0;
+       if (didset) {
+               return;
+       }
+       s = getenv("XDUMMY_TMPDIR");
+       if (! s) {
+               s = "/tmp";
+       }
+       tmpdir[0] = '\0';
+       strcat(tmpdir, s);
+       strcat(tmpdir, "/");
+       didset = 1;
+}
+
+static char *tmpdir_path(const char *path) {
+       char *str;
+       set_tmpdir();
+       strcpy(str2, path);
+       str = str2;
+       while (*str) {
+               if (*str == '/') {
+                       *str = '_';
+               }
+               str++;
+       }
+       strcpy(str1, tmpdir);
+       strcat(str1, str2);
+       return str1;
+}
+
+int open(const char *pathname, int flags, unsigned short mode) {
+       int fd;
+       char *store_dev = NULL;
+       static int (*real_open)(const char *, int , unsigned short) = NULL;
+
+       CHECKIT
+       if (! real_open) {
+               real_open = (int (*)(const char *, int , unsigned short))
+                       dlsym(RTLD_NEXT, "open");
+       }
+
+       if (strstr(pathname, "lib/modules/")) {
+               /* not currently used. */
+               saw_lib_modules = 1;
+       }
+
+       if (!root) {
+               if (strstr(pathname, "/dev/") == pathname) {
+                       store_dev = strdup(pathname);
+               }
+               if (strstr(pathname, "/dev/tty") == pathname && strcmp(pathname, "/dev/tty")) {
+                       pathname = tmpdir_path(pathname);
+                       if (debug) fprintf(stderr, "OPEN: %s -> %s (as FIFO)\n", store_dev, pathname);
+                       /* we make it a FIFO so ioctl on it does not fail */
+                       unlink(pathname);
+                       mkfifo(pathname, 0666);
+               } else if (0) {
+                       /* we used to handle more /dev files ... */
+                       fd = real_open(pathname, O_WRONLY|O_CREAT, 0777);
+                       close(fd);
+               }
+       }
+
+       fd = real_open(pathname, flags, mode);
+
+       if (debug) fprintf(stderr, "OPEN: %s %d %d fd=%d\n", pathname, flags, mode, fd);
+
+       if (! root) {
+               if (store_dev) {
+                       if (fd < 256) {
+                               strcpy(devs[fd], store_dev);
+                       }
+                       free(store_dev);
+               }
+       }
+
+       return(fd);
+}
+
+int open64(const char *pathname, int flags, unsigned short mode) {
+       int fd;
+
+       CHECKIT
+       if (debug) fprintf(stderr, "OPEN64: %s %d %d\n", pathname, flags, mode);
+
+       fd = open(pathname, flags, mode);
+       return(fd);
+}
+
+int rename(const char *oldpath, const char *newpath) {
+       static int (*real_rename)(const char *, const char *) = NULL;
+
+       CHECKIT
+       if (! real_rename) {
+               real_rename = (int (*)(const char *, const char *))
+                       dlsym(RTLD_NEXT, "rename");
+       }
+
+       if (debug) fprintf(stderr, "RENAME: %s %s\n", oldpath, newpath);
+
+       if (root) {
+               return(real_rename(oldpath, newpath));
+       }
+
+       if (strstr(oldpath, "/var/log") == oldpath) {
+               if (debug) fprintf(stderr, "RENAME: returning 0\n");
+               return 0;
+       }
+       return(real_rename(oldpath, newpath));
+}
+
+FILE *fopen(const char *pathname, const char *mode) {
+       static FILE* (*real_fopen)(const char *, const char *) = NULL;
+       char *str;
+
+       if (! saw_fonts) {
+               if (strstr(pathname, "/fonts/")) {
+                       if (strstr(pathname, "fonts.dir")) {
+                               saw_fonts = 1;
+                       } else if (strstr(pathname, "fonts.alias")) {
+                               saw_fonts = 1;
+                       }
+               }
+       }
+
+       CHECKIT
+       if (! real_fopen) {
+               real_fopen = (FILE* (*)(const char *, const char *))
+                       dlsym(RTLD_NEXT, "fopen");
+       }
+
+       if (debug) fprintf(stderr, "FOPEN: %s %s\n", pathname, mode);
+
+       if (strstr(pathname, "xdummy_modified_xconfig.conf")) {
+               /* make our config appear to be in /etc/X11, etc. */
+               char *q = strrchr(pathname, '/');
+               if (q != NULL && getenv("XDUMMY_TMPDIR") != NULL) {
+                       strcpy(str1, getenv("XDUMMY_TMPDIR"));
+                       strcat(str1, q);
+                       if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str1);
+                       pathname = str1;
+               }
+       }
+
+       if (root) {
+               return(real_fopen(pathname, mode));
+       }
+
+       str = (char *) pathname;
+       if (strstr(pathname, "/var/log") == pathname) {
+               str = tmpdir_path(pathname);
+               if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str);
+       }
+       return(real_fopen(str, mode));
+}
+
+
+#define RETURN0 if (debug) \
+       {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return 0;
+#define RETURN1 if (debug) \
+       {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return -1;
+
+int ioctl(int fd, int req, void *ptr) {
+       static int closed_xf86Info_consoleFd = 0;
+       static int (*real_ioctl)(int, int , void *) = NULL;
+
+       CHECKIT
+       if (! real_ioctl) {
+               real_ioctl = (int (*)(int, int , void *))
+                       dlsym(RTLD_NEXT, "open");
+       }
+       if (debug) fprintf(stderr, "IOCTL: %d 0x%x %p\n", fd, req, ptr);
+
+       /* based on xorg-x11-6.8.1-dualhead.patch */
+       if (req == VT_GETMODE) {
+               /* close(xf86Info.consoleFd) */
+               if (0 && ! closed_xf86Info_consoleFd) {
+                       /* I think better not to close it... */
+                       close(fd);
+                       closed_xf86Info_consoleFd = 1;
+               }
+               RETURN0
+       } else if (req == VT_SETMODE) {
+               RETURN0
+       } else if (req == VT_GETSTATE) {
+               RETURN0
+       } else if (req == KDSETMODE) {
+               RETURN0
+       } else if (req == KDSETLED) {
+               RETURN0
+       } else if (req == KDGKBMODE) {
+               RETURN0
+       } else if (req == KDSKBMODE) {
+               RETURN0
+       } else if (req == VT_ACTIVATE) {
+               RETURN0
+       } else if (req == VT_WAITACTIVE) {
+               RETURN0
+       } else if (req == VT_RELDISP) {
+               if (ptr == (void *) 1) {
+                       RETURN1
+               } else if (ptr == (void *) VT_ACKACQ) {
+                       RETURN0
+               }
+       }
+
+       return(real_ioctl(fd, req, ptr));
+}
+
+typedef void (*sighandler_t)(int);
+#define SIGUSR1       10
+#define SIG_DFL       ((sighandler_t)0)
+
+sighandler_t signal(int signum, sighandler_t handler) {
+       static sighandler_t (*real_signal)(int, sighandler_t) = NULL;
+
+       CHECKIT
+       if (! real_signal) {
+               real_signal = (sighandler_t (*)(int, sighandler_t))
+                       dlsym(RTLD_NEXT, "signal");
+       }
+
+       if (debug) fprintf(stderr, "SIGNAL: %d %p\n", signum, handler);
+
+       if (signum == SIGUSR1) {
+               if (debug) fprintf(stderr, "SIGNAL: skip SIGUSR1\n");
+               return SIG_DFL;
+       }
+       
+       return(real_signal(signum, handler));
+}
+
+int close(int fd) {
+       static int (*real_close)(int) = NULL;
+
+       CHECKIT
+       if (! real_close) {
+               real_close = (int (*)(int)) dlsym(RTLD_NEXT, "close");
+       }
+
+       if (debug) fprintf(stderr, "CLOSE: %d\n", fd);
+       if (!root) {
+               if (fd < 256) {
+                       devs[fd][0] = '\0';
+               }
+       }
+       return(real_close(fd));
+}
+
+struct stat {
+       int foo;
+};
+
+int stat(const char *path, struct stat *buf) {
+       static int (*real_stat)(const char *, struct stat *) = NULL;
+
+       CHECKIT
+       if (! real_stat) {
+               real_stat = (int (*)(const char *, struct stat *))
+                       dlsym(RTLD_NEXT, "stat");
+       }
+
+       if (debug) fprintf(stderr, "STAT: %s\n", path);
+
+       return(real_stat(path, buf));
+}
+
+int stat64(const char *path, struct stat *buf) {
+       static int (*real_stat64)(const char *, struct stat *) = NULL;
+
+       CHECKIT
+       if (! real_stat64) {
+               real_stat64 = (int (*)(const char *, struct stat *))
+                       dlsym(RTLD_NEXT, "stat64");
+       }
+
+       if (debug) fprintf(stderr, "STAT64: %s\n", path);
+
+       return(real_stat64(path, buf));
+}
+
+int chown(const char *path, uid_t owner, gid_t group) {
+       static int (*real_chown)(const char *, uid_t, gid_t) = NULL;
+
+       CHECKIT
+       if (! real_chown) {
+               real_chown = (int (*)(const char *, uid_t, gid_t))
+                       dlsym(RTLD_NEXT, "chown");
+       }
+
+       if (root) {
+               return(real_chown(path, owner, group));
+       }
+
+       if (debug) fprintf(stderr, "CHOWN: %s %d %d\n", path, owner, group);
+
+       if (strstr(path, "/dev") == path) {
+               if (debug) fprintf(stderr, "CHOWN: return 0\n");
+               return 0;
+       }
+
+       return(real_chown(path, owner, group));
+}
+
+extern int *__errno_location (void);
+#ifndef ENODEV
+#define ENODEV 19
+#endif
+
+int ioperm(unsigned long from, unsigned long num, int turn_on) {
+       static int (*real_ioperm)(unsigned long, unsigned long, int) = NULL;
+
+       CHECKIT
+       if (! real_ioperm) {
+               real_ioperm = (int (*)(unsigned long, unsigned long, int))
+                       dlsym(RTLD_NEXT, "ioperm");
+       }
+       if (debug) fprintf(stderr, "IOPERM: %d %d %d\n", (int) from, (int) num, turn_on);
+       if (root) {
+               return(real_ioperm(from, num, turn_on));
+       }
+       if (from == 0 && num == 1024 && turn_on == 1) {
+               /* we want xf86EnableIO to fail */
+               if (debug) fprintf(stderr, "IOPERM: setting ENODEV.\n");
+               *__errno_location() = ENODEV;
+               return -1;
+       }
+       return 0;
+}
+
+int iopl(int level) {
+       static int (*real_iopl)(int) = NULL;
+
+       CHECKIT
+       if (! real_iopl) {
+               real_iopl = (int (*)(int)) dlsym(RTLD_NEXT, "iopl");
+       }
+       if (debug) fprintf(stderr, "IOPL: %d\n", level);
+       if (root) {
+               return(real_iopl(level));
+       }
+       return 0;
+}
+
+#ifdef INTERPOSE_GETUID 
+
+/*
+ * we got things to work w/o pretending to be root.
+ * so we no longer interpose getuid(), etc.
+ */
+
+uid_t getuid(void) {
+       static uid_t (*real_getuid)(void) = NULL;
+       CHECKIT
+       if (! real_getuid) {
+               real_getuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid");
+       }
+       if (root) {
+               return(real_getuid());
+       }
+       if (debug) fprintf(stderr, "GETUID: 0\n");
+       return 0;
+}
+uid_t geteuid(void) {
+       static uid_t (*real_geteuid)(void) = NULL;
+       CHECKIT
+       if (! real_geteuid) {
+               real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid");
+       }
+       if (root) {
+               return(real_geteuid());
+       }
+       if (debug) fprintf(stderr, "GETEUID: 0\n");
+       return 0;
+}
+uid_t geteuid_kludge1(void) {
+       static uid_t (*real_geteuid)(void) = NULL;
+       CHECKIT
+       if (! real_geteuid) {
+               real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid");
+       }
+       if (debug) fprintf(stderr, "GETEUID: 0 saw_libmodules=%d\n", saw_lib_modules);
+       if (root && !saw_lib_modules) {
+               return(real_geteuid());
+       } else {
+               saw_lib_modules = 0;
+               return 0;
+       }
+}
+
+uid_t getuid32(void) {
+       static uid_t (*real_getuid32)(void) = NULL;
+       CHECKIT
+       if (! real_getuid32) {
+               real_getuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid32");
+       }
+       if (root) {
+               return(real_getuid32());
+       }
+       if (debug) fprintf(stderr, "GETUID32: 0\n");
+       return 0;
+}
+uid_t geteuid32(void) {
+       static uid_t (*real_geteuid32)(void) = NULL;
+       CHECKIT
+       if (! real_geteuid32) {
+               real_geteuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid32");
+       }
+       if (root) {
+               return(real_geteuid32());
+       }
+       if (debug) fprintf(stderr, "GETEUID32: 0\n");
+       return 0;
+}
+
+gid_t getgid(void) {
+       static gid_t (*real_getgid)(void) = NULL;
+       CHECKIT
+       if (! real_getgid) {
+               real_getgid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid");
+       }
+       if (root) {
+               return(real_getgid());
+       }
+       if (debug) fprintf(stderr, "GETGID: 0\n");
+       return 0;
+}
+gid_t getegid(void) {
+       static gid_t (*real_getegid)(void) = NULL;
+       CHECKIT
+       if (! real_getegid) {
+               real_getegid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid");
+       }
+       if (root) {
+               return(real_getegid());
+       }
+       if (debug) fprintf(stderr, "GETEGID: 0\n");
+       return 0;
+}
+gid_t getgid32(void) {
+       static gid_t (*real_getgid32)(void) = NULL;
+       CHECKIT
+       if (! real_getgid32) {
+               real_getgid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid32");
+       }
+       if (root) {
+               return(real_getgid32());
+       }
+       if (debug) fprintf(stderr, "GETGID32: 0\n");
+       return 0;
+}
+gid_t getegid32(void) {
+       static gid_t (*real_getegid32)(void) = NULL;
+       CHECKIT
+       if (! real_getegid32) {
+               real_getegid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid32");
+       }
+       if (root) {
+               return(real_getegid32());
+       }
+       if (debug) fprintf(stderr, "GETEGID32: 0\n");
+       return 0;
+}
+#endif
+
+#if 0
+/* maybe we need to interpose on strcmp someday... here is the template */
+int strcmp(const char *s1, const char *s2) {
+       static int (*real_strcmp)(const char *, const char *) = NULL;
+       CHECKIT
+       if (! real_strcmp) {
+               real_strcmp = (int (*)(const char *, const char *)) dlsym(RTLD_NEXT, "strcmp");
+       }
+       if (debug) fprintf(stderr, "STRCMP: '%s' '%s'\n", s1, s2);
+       return(real_strcmp(s1, s2));
+}
+#endif
+
+#code_end
+}