| #!/bin/sh |
| # ---------------------------------------------------------------------- |
| # Copyright (C) 2005-2010 Karl J. Runge <[email protected]> |
| # 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 |
| } |