--- /dev/null
+#!/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
+}