Released version 3-2015061300
[notion.git] / test / integration / Xdummy
blob34b3ead5dec061d88f33576072df5d15b05bca23
1 #!/bin/sh
2 # ----------------------------------------------------------------------
3 # Copyright (C) 2005-2011 Karl J. Runge <runge@karlrunge.com>
4 # All rights reserved.
5 #
6 # This file is part of Xdummy.
7 #
8 # Xdummy is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or (at
11 # your option) any later version.
13 # Xdummy is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Xdummy; if not, write to the Free Software
20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
21 # or see <http://www.gnu.org/licenses/>.
22 # ----------------------------------------------------------------------
25 # Xdummy: an LD_PRELOAD hack to run a stock Xorg(1) or XFree86(1) server
26 # with the "dummy" video driver to make it avoid Linux VT switching, etc.
28 # Run "Xdummy -help" for more info.
30 install=""
31 uninstall=""
32 runit=1
33 prconf=""
34 notweak=""
35 root=""
36 nosudo=""
37 xserver=""
38 geom=""
39 nomodelines=""
40 depth=""
41 debug=""
42 strace=""
43 cmdline_config=""
45 PATH=$PATH:/bin:/usr/bin
46 export PATH
48 program=`basename "$0"`
50 help () {
51 ${PAGER:-more} << END
52 $program:
54 A hack to run a stock Xorg(1) or XFree86(1) X server with the "dummy"
55 (RAM-only framebuffer) video driver such that it AVOIDS the Linux VT
56 switching, opening device files in /dev, keyboard and mouse conflicts,
57 and other problems associated with the normal use of "dummy".
59 In other words, it tries to make Xorg/XFree86 with the "dummy"
60 device driver act more like Xvfb(1).
62 The primary motivation for the Xdummy script is to provide a virtual X
63 server for x11vnc but with more features than Xvfb (or Xvnc); however
64 it could be used for other reasons (e.g. better automated testing
65 than with Xvfb.) One nice thing is the dummy server supports RANDR
66 dynamic resizing while Xvfb does not.
68 So, for example, x11vnc+Xdummy terminal services are a little better
69 than x11vnc+Xvfb.
71 To achieve this, while running the real Xserver $program intercepts
72 system and library calls via the LD_PRELOAD method and modifies
73 the behavior to make it work correctly (e.g. avoid the VT stuff.)
74 LD_PRELOAD tricks are usually "clever hacks" and so might not work
75 in all situations or break when something changes.
77 WARNING: Take care in using Xdummy, although it never has it is
78 possible that it could damage hardware. One can use the -prconf
79 option to have it print out the xorg.conf config that it would use
80 and then inspect it carefully before actually using it.
82 This program no longer needs to be run as root as of 12/2009.
83 However, if there are problems for certain situations (usually older
84 servers) it may perform better if run as root (use the -root option.)
85 When running as root remember the previous paragraph and that Xdummy
86 comes without any warranty.
88 gcc/cc and other build tools are required for this script to be able
89 to compile the LD_PRELOAD shared object. Be sure they are installed
90 on the system. See -install and -uninstall described below.
92 Your Linux distribution may not install the dummy driver by default,
93 e.g:
95 /usr/lib/xorg/modules/drivers/dummy_drv.so
97 some have it in a package named xserver-xorg-video-dummy you that
98 need to install.
100 Usage:
102 $program <${program}-args> <Xserver-args>
104 (actually, the arguments can be supplied in any order.)
106 Examples:
108 $program -install
110 $program :1
112 $program -debug :1
114 $program -tmpdir ~/mytmp :1 -nolisten tcp
116 startx example:
118 startx -e bash -- $program :2 -depth 16
120 (if startx needs to be run as root, you can su(1) to a normal
121 user in the bash shell and then launch ~/.xinitrc or ~/.xsession,
122 gnome-session, startkde, startxfce4, etc.)
124 xdm example:
126 xdm -config /usr/local/dummy/xdm-config -nodaemon
128 where the xdm-config file has line:
130 DisplayManager.servers: /usr/local/dummy/Xservers
132 and /usr/local/dummy/Xservers has lines:
134 :1 local /usr/local/dummy/Xdummy :1 -debug
135 :2 local /usr/local/dummy/Xdummy :2 -debug
137 (-debug is optional)
139 gdm/kdm example:
141 TBD.
143 Config file:
145 If the file $program.cfg exists it will be sourced as shell
146 commands. Usually one will set some variables this way.
147 To disable sourcing, supply -nocfg or set XDUMMY_NOCFG=1.
149 Root permission and x11vnc:
151 Update: as of 12/2009 this program no longer must be run as root.
152 So try it as non-root before running it as root and/or the
153 following schemes.
155 In some circumstances X server program may need to be run as root.
156 If so, one could run x11vnc as root with -unixpw (it switches
157 to the user that logs in) and that may be OK, some other ideas:
159 - add this to sudo via visudo:
161 ALL ALL = NOPASSWD: /usr/local/bin/Xdummy
163 - use this little suid wrapper:
165 * xdummy.c
167 cc -o ./xdummy xdummy.c
168 sudo cp ./xdummy /usr/local/bin/xdummy
169 sudo chown root:root /usr/local/bin/xdummy
170 sudo chmod u+s /usr/local/bin/xdummy
173 #include <unistd.h>
174 #include <stdlib.h>
175 #include <sys/types.h>
176 #include <stdio.h>
178 int main (int argc, char *argv[]) {
179 extern char **environ;
180 char str[100];
181 sprintf(str, "XDUMMY_UID=%d", (int) getuid());
182 putenv(str);
183 setuid(0);
184 setgid(0);
185 execv("/usr/local/bin/Xdummy", argv);
186 exit(1);
187 return 1;
191 Options:
193 ${program}-args:
195 -install Compile the LD_PRELOAD shared object and install it
196 next to the $program script file as:
198 $0.so
200 When that file exists it is used as the LD_PRELOAD
201 shared object without recompiling. Otherwise,
202 each time $program is run the LD_PRELOAD shared
203 object is compiled as a file in /tmp (or -tmpdir)
205 If you set the environment variable
206 INTERPOSE_GETUID=1 when building, then when
207 $program is run as an ordinary user, the shared
208 object will interpose getuid() calls and pretend
209 to be root. Otherwise it doesn't pretend to
210 be root.
212 You can also set the CFLAGS environment variable
213 to anything else you want on the compile cmdline.
215 -uninstall Remove the file:
217 $0.so
219 The LD_PRELOAD shared object will then be compiled
220 each time this program is run.
222 The X server is not started under -install, -uninstall, or -prconf.
225 :N The DISPLAY (e.g. :15) is often the first
226 argument. It is passed to the real X server and
227 also used by the Xdummy script as an identifier.
229 -geom geom1[,geom2...] Take the geometry (e.g. 1024x768) or list
230 of geometries and insert them into the Screen
231 section of the tweaked X server config file.
232 Use this to have a different geometry than the
233 one(s) in the system config file.
235 The option -geometry can be used instead of -geom;
236 x11vnc calls Xdummy and Xvfb this way.
238 -nomodelines When you specify -geom/-geometry, $program will
239 create Modelines for each geometry and put them
240 in the Monitor section. If you do not want this
241 then supply -nomodelines.
243 -depth n Use pixel color depth n (e.g. 8, 16, or 24). This
244 makes sure the X config file has a Screen.Display
245 subsection of this depth. Note this option is
246 ALSO passed to the X server.
248 -DEPTH n Same as -depth, except not passed to X server.
250 -tmpdir dir Specify a temporary directory, owned by you and
251 only writable by you. This is used in place of
252 /tmp/Xdummy.\$USER/.. to place the $program.so
253 shared object, tweaked config files, etc.
255 -nonroot Run in non-root mode (working 12/2009, now default)
257 -root Run as root (may still be needed in some
258 environments.) Same as XDUMMY_RUN_AS_ROOT=1.
260 -nosudo Do not try to use sudo(1) when re-running as root,
261 use su(1) instead.
263 -xserver path Specify the path to the Xserver to use. Default
264 is to try "Xorg" first and then "XFree86". If
265 those are not in \$PATH, it tries these locations:
266 /usr/bin/Xorg
267 /usr/X11R6/bin/Xorg
268 /usr/X11R6/bin/XFree86
270 -n Do not run the command to start the X server,
271 just show the command that $program would run.
272 The LD_PRELOAD shared object will be built,
273 if needed. Also note any XDUMMY* environment
274 variables that need to be set.
276 -prconf Print, to stdout, the tweaked Xorg/XFree86
277 config file (-config and -xf86config server
278 options, respectively.) The Xserver is not
279 started.
281 -notweak Do not tweak (modify) the Xorg/XFree86 config file
282 (system or server command line) at all. The -geom
283 and similar config file modifications are ignored.
285 It is up to you to make sure it is a working
286 config file (e.g. "dummy" driver, etc.)
287 Perhaps you want to use a file based on the
288 -prconf output.
290 -nocfg Do not try to source $program.cfg even if it
291 exists. Same as setting XDUMMY_NOCFG=1.
293 -debug Extra debugging output.
295 -strace strace(1) the Xserver process (for troubleshooting.)
296 -ltrace ltrace(1) instead of strace (can be slow.)
298 -h, -help Print out this help.
301 Xserver-args:
303 Most of the Xorg and XFree86 options will work and are simply
304 passed along if you supply them. Important ones that may be
305 supplied if missing:
307 :N X Display number for server to use.
309 vtNN Linux virtual terminal (VT) to use (a VT is currently
310 still used, just not switched to and from.)
312 -config file Driver "dummy" tweaked config file, a
313 -xf86config file number of settings are tweaked besides Driver.
315 If -config/-xf86config is not given, the system one
316 (e.g. /etc/X11/xorg.conf) is used. If the system one cannot be
317 found, a built-in one is used. Any settings in the config file
318 that are not consistent with "dummy" mode will be overwritten
319 (unless -notweak is specified.)
321 Use -config xdummy-builtin to force usage of the builtin config.
323 If "file" is only a basename (e.g. "xorg.dummy.conf") with no /'s,
324 then no tweaking of it is done: the X server will look for that
325 basename via its normal search algorithm. If the found file does
326 not refer to the "dummy" driver, etc, then the X server will fail.
328 You can set the env. var. XDUMMY_EXTRA_SERVER_ARGS to hold some
329 extra Xserver-args too. (Useful for cfg file.)
331 Notes:
333 The Xorg/XFree86 "dummy" driver is currently undocumented. It works
334 well in this mode, but it is evidently not intended for end-users.
335 So it could be removed or broken at any time.
337 If the display Xserver-arg (e.g. :1) is not given, or ":" is given
338 that indicates $program should try to find a free one (based on
339 tcp ports.)
341 If the display virtual terminal, VT, (e.g. vt9) is not given that
342 indicates $program should try to find a free one (or guess a high one.)
344 This program is not completely secure WRT files in /tmp (but it tries
345 to a good degree.) Better is to use the -tmpdir option to supply a
346 directory only writable by you. Even better is to get rid of users
347 on the local machine you do not trust :-)
349 Set XDUMMY_SET_XV=1 to turn on debugging output for this script.
354 warn() {
355 echo "$*" 1>&2
358 if [ "X$XDUMMY_SET_XV" != "X" ]; then
359 set -xv
362 if [ "X$XDUMMY_UID" = "X" ]; then
363 XDUMMY_UID=`id -u`
364 export XDUMMY_UID
366 if [ "X$XDUMMY_UID" = "X0" ]; then
367 if [ "X$SUDO_UID" != "X" ]; then
368 XDUMMY_UID=$SUDO_UID
369 export XDUMMY_UID
373 # check if root=1 first:
375 if [ "X$XDUMMY_RUN_AS_ROOT" = "X1" ]; then
376 root=1
378 for arg in $*
380 if [ "X$arg" = "X-nonroot" ]; then
381 root=""
382 elif [ "X$arg" = "X-root" ]; then
383 root=1
384 elif [ "X$arg" = "X-nocfg" ]; then
385 XDUMMY_NOCFG=1
386 export XDUMMY_NOCFG
388 done
390 if [ "X$XDUMMY_NOCFG" = "X" -a -f "$0.cfg" ]; then
391 . "$0.cfg"
394 # See if it really needs to be run as root:
396 if [ "X$XDUMMY_SU_EXEC" = "X" -a "X$root" = "X1" -a "X`id -u`" != "X0" ]; then
397 # this is to prevent infinite loop in case su/sudo doesn't work:
398 XDUMMY_SU_EXEC=1
399 export XDUMMY_SU_EXEC
401 dosu=1
402 nosudo=""
404 for arg in $*
406 if [ "X$arg" = "X-nonroot" ]; then
407 dosu=""
408 elif [ "X$arg" = "X-nosudo" ]; then
409 nosudo="1"
410 elif [ "X$arg" = "X-help" ]; then
411 dosu=""
412 elif [ "X$arg" = "X-h" ]; then
413 dosu=""
414 elif [ "X$arg" = "X-install" ]; then
415 dosu=""
416 elif [ "X$arg" = "X-uninstall" ]; then
417 dosu=""
418 elif [ "X$arg" = "X-n" ]; then
419 dosu=""
420 elif [ "X$arg" = "X-prconf" ]; then
421 dosu=""
423 done
424 if [ $dosu ]; then
425 # we need to restart it with su/sudo:
426 if type sudo > /dev/null 2>&1; then
428 else
429 nosudo=1
431 if [ "X$nosudo" = "X" ]; then
432 warn "$program: supply the sudo password to restart as root:"
433 if [ "X$XDUMMY_UID" != "X" ]; then
434 exec sudo $0 -uid $XDUMMY_UID "$@"
435 else
436 exec sudo $0 "$@"
438 else
439 warn "$program: supply the root password to restart as root:"
440 if [ "X$XDUMMY_UID" != "X" ]; then
441 exec su -c "$0 -uid $XDUMMY_UID $*"
442 else
443 exec su -c "$0 $*"
446 # DONE:
447 exit
451 # This will hold the X display, e.g. :20
453 disp=""
454 args=""
455 cmdline_config=""
457 # Process Xdummy args:
459 while [ "X$1" != "X" ]
461 if [ "X$1" = "X-config" -o "X$1" = "X-xf86config" ]; then
462 cmdline_config="$2"
464 case $1 in
465 ":"*) disp=$1
467 "-install") install=1; runit=""
469 "-uninstall") uninstall=1; runit=""
471 "-n") runit=""
473 "-no") runit=""
475 "-norun") runit=""
477 "-prconf") prconf=1; runit=""
479 "-notweak") notweak=1
481 "-noconf") notweak=1
483 "-nonroot") root=""
485 "-root") root=1
487 "-nosudo") nosudo=1
489 "-xserver") xserver="$2"; shift
491 "-uid") XDUMMY_UID="$2"; shift
492 export XDUMMY_UID
494 "-geom") geom="$2"; shift
496 "-geometry") geom="$2"; shift
498 "-nomodelines") nomodelines=1
500 "-depth") depth="$2"; args="$args -depth $2";
501 shift
503 "-DEPTH") depth="$2"; shift
505 "-tmpdir") XDUMMY_TMPDIR="$2"; shift
507 "-debug") debug=1
509 "-nocfg") :
511 "-nodebug") debug=""
513 "-strace") strace=1
515 "-ltrace") strace=2
517 "-h") help; exit 0
519 "-help") help; exit 0
521 *) args="$args $1"
523 esac
524 shift
525 done
527 if [ "X$XDUMMY_EXTRA_SERVER_ARGS" != "X" ]; then
528 args="$args $XDUMMY_EXTRA_SERVER_ARGS"
531 # Try to get a username for use in our tmp directory, etc.
533 user=""
534 if [ X`id -u` = "X0" ]; then
535 user=root # this will also be used below for id=0
536 elif [ "X$USER" != "X" ]; then
537 user=$USER
538 elif [ "X$LOGNAME" != "X" ]; then
539 user=$LOGNAME
542 # Keep trying...
544 if [ "X$user" = "X" ]; then
545 user=`whoami 2>/dev/null`
547 if [ "X$user" = "X" ]; then
548 user=`basename "$HOME"`
550 if [ "X$user" = "X" -o "X$user" = "X." ]; then
551 user="u$$"
554 if [ "X$debug" = "X1" -a "X$runit" != "X" ]; then
555 echo ""
556 echo "/usr/bin/env:"
557 env | egrep -v '^(LS_COLORS|TERMCAP)' | sort
558 echo ""
561 # Function to compile the LD_PRELOAD shared object:
563 make_so() {
564 # extract code embedded in this script into a tmp C file:
565 n1=`grep -n '^#code_begin' $0 | head -1 | awk -F: '{print $1}'`
566 n2=`grep -n '^#code_end' $0 | head -1 | awk -F: '{print $1}'`
567 n1=`expr $n1 + 1`
568 dn=`expr $n2 - $n1`
570 tmp=$tdir/Xdummy.$RANDOM$$.c
571 rm -f $tmp
572 if [ -e $tmp -o -h $tmp ]; then
573 warn "$tmp still exists."
574 exit 1
576 touch $tmp || exit 1
577 tail -n +$n1 $0 | head -n $dn > $tmp
579 # compile it to Xdummy.so:
580 if [ -f "$SO" ]; then
581 mv $SO $SO.$$
582 rm -f $SO.$$
584 rm -f $SO
585 touch $SO
586 if [ ! -f "$SO" ]; then
587 SO=$tdir/Xdummy.$user.so
588 warn "warning switching LD_PRELOAD shared object to: $SO"
591 if [ -f "$SO" ]; then
592 mv $SO $SO.$$
593 rm -f $SO.$$
595 rm -f $SO
597 # we assume gcc:
598 if [ "X$INTERPOSE_GETUID" = "X1" ]; then
599 CFLAGS="$CFLAGS -DINTERPOSE_GETUID"
601 echo "$program:" cc -shared -fPIC $CFLAGS -o $SO $tmp
602 cc -shared -fPIC $CFLAGS -o $SO $tmp
603 rc=$?
604 rm -f $tmp
605 if [ $rc != 0 ]; then
606 warn "$program: cannot build $SO"
607 exit 1
609 if [ "X$debug" != "X" -o "X$install" != "X" ]; then
610 warn "$program: created $SO"
611 ls -l "$SO"
615 # Set tdir to tmp dir for make_so():
616 if [ "X$XDUMMY_TMPDIR" != "X" ]; then
617 tdir=$XDUMMY_TMPDIR
618 mkdir -p $tdir
619 else
620 tdir="/tmp"
623 # Handle -install/-uninstall case:
624 SO=$0.so
625 if [ "X$install" != "X" -o "X$uninstall" != "X" ]; then
626 if [ -e "$SO" -o -h "$SO" ]; then
627 warn "$program: removing $SO"
629 if [ -f "$SO" ]; then
630 mv $SO $SO.$$
631 rm -f $SO.$$
633 rm -f $SO
634 if [ -e "$SO" -o -h "$SO" ]; then
635 warn "warning: $SO still exists."
636 exit 1
638 if [ $install ]; then
639 make_so
640 if [ ! -f "$SO" ]; then
641 exit 1
644 exit 0
647 # We need a tmp directory for the .so, tweaked config file, and for
648 # redirecting filenames we cannot create (under -nonroot)
650 tack=""
651 if [ "X$XDUMMY_TMPDIR" = "X" ]; then
652 XDUMMY_TMPDIR="/tmp/Xdummy.$user"
654 # try to tack on a unique subdir (display number or pid)
655 # to allow multiple instances
657 if [ "X$disp" != "X" ]; then
658 t0=$disp
659 else
660 t0=$1
662 tack=`echo "$t0" | sed -e 's/^.*://'`
663 if echo "$tack" | grep '^[0-9][0-9]*$' > /dev/null; then
665 else
666 tack=$$
668 if [ "X$tack" != "X" ]; then
669 XDUMMY_TMPDIR="$XDUMMY_TMPDIR/$tack"
673 tmp=$XDUMMY_TMPDIR
674 if echo "$tmp" | grep '^/tmp' > /dev/null; then
675 if [ "X$tmp" != "X/tmp" -a "X$tmp" != "X/tmp/" ]; then
676 # clean this subdir of /tmp out, otherwise leave it...
677 rm -rf $XDUMMY_TMPDIR
678 if [ -e $XDUMMY_TMPDIR ]; then
679 warn "$XDUMMY_TMPDIR still exists"
680 exit 1
685 mkdir -p $XDUMMY_TMPDIR
686 chmod 700 $XDUMMY_TMPDIR
687 if [ "X$tack" != "X" ]; then
688 chmod 700 `dirname "$XDUMMY_TMPDIR"` 2>/dev/null
691 # See if we can write something there:
693 tfile="$XDUMMY_TMPDIR/test.file"
694 touch $tfile
695 if [ ! -f "$tfile" ]; then
696 XDUMMY_TMPDIR="/tmp/Xdummy.$$.$USER"
697 warn "warning: setting tmpdir to $XDUMMY_TMPDIR ..."
698 rm -rf $XDUMMY_TMPDIR || exit 1
699 mkdir -p $XDUMMY_TMPDIR || exit 1
701 rm -f $tfile
703 export XDUMMY_TMPDIR
705 # Compile the LD_PRELOAD shared object if needed (needs XDUMMY_TMPDIR)
707 if [ ! -f "$SO" ]; then
708 SO="$XDUMMY_TMPDIR/Xdummy.so"
709 make_so
712 # Decide which X server to use:
714 if [ "X$xserver" = "X" ]; then
715 if type Xorg >/dev/null 2>&1; then
716 xserver="Xorg"
717 elif type XFree86 >/dev/null 2>&1; then
718 xserver="XFree86"
719 elif -x /usr/bin/Xorg; then
720 xserver="/usr/bin/Xorg"
721 elif -x /usr/X11R6/bin/Xorg; then
722 xserver="/usr/X11R6/bin/Xorg"
723 elif -x /usr/X11R6/bin/XFree86; then
724 xserver="/usr/X11R6/bin/XFree86"
726 if [ "X$xserver" = "X" ]; then
727 # just let it fail below.
728 xserver="/usr/bin/Xorg"
729 warn "$program: cannot locate a stock Xserver... assuming $xserver"
733 # See if the binary is suid or not readable under -nonroot mode:
735 if [ "X$BASH_VERSION" != "X" ]; then
736 xserver_path=`type -p $xserver 2>/dev/null`
737 else
738 xserver_path=`type $xserver 2>/dev/null | awk '{print $NF}'`
740 if [ -e "$xserver_path" -a "X$root" = "X" -a "X$runit" != "X" ]; then
741 if [ ! -r $xserver_path -o -u $xserver_path -o -g $xserver_path ]; then
742 # XXX not quite correct with rm -rf $XDUMMY_TMPDIR ...
743 # we keep on a filesystem we know root can write to.
744 base=`basename "$xserver_path"`
745 new="/tmp/$base.$user.bin"
746 if [ -e $new ]; then
747 snew=`ls -l $new | awk '{print $5}' | grep '^[0-9][0-9]*$'`
748 sold=`ls -l $xserver_path | awk '{print $5}' | grep '^[0-9][0-9]*$'`
749 if [ "X$snew" != "X" -a "X$sold" != "X" -a "X$sold" != "X$snew" ]; then
750 warn "removing different sized copy:"
751 ls -l $new $xserver_path
752 rm -f $new
755 if [ ! -e $new -o ! -s $new ]; then
756 rm -f $new
757 touch $new || exit 1
758 chmod 700 $new || exit 1
759 if [ ! -r $xserver_path ]; then
760 warn ""
761 warn "NEED TO COPY UNREADABLE $xserver_path to $new as root:"
762 warn ""
763 ls -l $xserver_path 1>&2
764 warn ""
765 warn "This only needs to be done once:"
766 warn " cat $xserver_path > $new"
767 warn ""
768 nos=$nosudo
769 if type sudo > /dev/null 2>&1; then
771 else
772 nos=1
774 if [ "X$nos" = "X1" ]; then
775 warn "Please supply root passwd to 'su -c'"
776 su -c "cat $xserver_path > $new"
777 else
778 warn "Please supply the sudo passwd if asked:"
779 sudo /bin/sh -c "cat $xserver_path > $new"
781 else
782 warn ""
783 warn "COPYING SETUID $xserver_path to $new"
784 warn ""
785 ls -l $xserver_path 1>&2
786 warn ""
787 cat $xserver_path > $new
789 ls -l $new
790 if [ -s $new ]; then
792 else
793 rm -f $new
794 ls -l $new
795 exit 1
797 warn ""
798 warn "Please restart Xdummy now."
799 exit 0
801 if [ ! -O $new ]; then
802 warn "file \"$new\" not owned by us!"
803 ls -l $new
804 exit 1
806 xserver=$new
810 # Work out display:
812 if [ "X$disp" != "X" ]; then
814 elif [ "X$1" != "X" ]; then
815 if echo "$1" | grep '^:[0-9]' > /dev/null; then
816 disp=$1
817 shift
818 elif [ "X$1" = "X:" ]; then
819 # ":" means for us to find one.
820 shift
823 if [ "X$disp" = "X" -o "X$disp" = "X:" ]; then
824 # try to find an open display port:
825 # (tcp outdated...)
826 ports=`netstat -ant | grep LISTEN | awk '{print $4}' | sed -e 's/^.*://'`
828 while [ $n -le 20 ]
830 port=`printf "60%02d" $n`
831 if echo "$ports" | grep "^${port}\$" > /dev/null; then
833 else
834 disp=":$n"
835 warn "$program: auto-selected DISPLAY $disp"
836 break
838 n=`expr $n + 1`
839 done
842 # Work out which vt to use, try to find/guess an open one if necessary.
844 vt=""
845 for arg in $*
847 if echo "$arg" | grep '^vt' > /dev/null; then
848 vt=$arg
849 break
851 done
852 if [ "X$vt" = "X" ]; then
853 if [ "X$user" = "Xroot" ]; then
854 # root can user fuser(1) to see if it is in use:
855 if type fuser >/dev/null 2>&1; then
856 # try /dev/tty17 thru /dev/tty32
857 n=17
858 while [ $n -le 32 ]
860 dev="/dev/tty$n"
861 if fuser $dev >/dev/null 2>&1; then
863 else
864 vt="vt$n"
865 warn "$program: auto-selected VT $vt => $dev"
866 break
868 n=`expr $n + 1`
869 done
872 if [ "X$vt" = "X" ]; then
873 # take a wild guess...
874 vt=vt16
875 warn "$program: selected fallback VT $vt"
877 else
878 vt=""
881 # Decide flavor of Xserver:
883 stype=`basename "$xserver"`
884 if echo "$stype" | grep -i xfree86 > /dev/null; then
885 stype=xfree86
886 else
887 stype=xorg
890 tweak_config() {
891 in="$1"
892 config2="$XDUMMY_TMPDIR/xdummy_modified_xconfig.conf"
893 if [ "X$disp" != "X" ]; then
894 d=`echo "$disp" | sed -e 's,/,,g' -e 's/:/_/g'`
895 config2="$config2$d"
898 # perl script to tweak the config file... add/delete options, etc.
900 env XDUMMY_GEOM=$geom \
901 XDUMMY_DEPTH=$depth \
902 XDUMMY_NOMODELINES=$nomodelines \
903 perl > $config2 < $in -e '
904 $n = 0;
905 $geom = $ENV{XDUMMY_GEOM};
906 $depth = $ENV{XDUMMY_DEPTH};
907 $nomodelines = $ENV{XDUMMY_NOMODELINES};
908 $mode_str = "";
909 $videoram = "240000";
910 $HorizSync = "30.0 - 130.0";
911 $VertRefresh = "50.0 - 250.0";
912 if ($geom ne "") {
913 my $tmp = "";
914 foreach $g (split(/,/, $geom)) {
915 $tmp .= "\"$g\" ";
916 if (!$nomodelines && $g =~ /(\d+)x(\d+)/) {
917 my $w = $1;
918 my $h = $2;
919 $mode_str .= " Modeline \"$g\" ";
920 my $dot = sprintf("%.2f", $w * $h * 70 * 1.e-6);
921 $mode_str .= $dot;
922 $mode_str .= " " . $w;
923 $mode_str .= " " . int(1.02 * $w);
924 $mode_str .= " " . int(1.10 * $w);
925 $mode_str .= " " . int(1.20 * $w);
926 $mode_str .= " " . $h;
927 $mode_str .= " " . int($h + 1);
928 $mode_str .= " " . int($h + 3);
929 $mode_str .= " " . int($h + 20);
930 $mode_str .= "\n";
933 $tmp =~ s/\s*$//;
934 $geom = $tmp;
936 while (<>) {
937 if ($ENV{XDUMMY_NOTWEAK}) {
938 print $_;
939 next;
941 $n++;
942 if (/^\s*#/) {
943 # pass comments straight thru
944 print;
945 next;
947 if (/^\s*Section\s+(\S+)/i) {
948 # start of Section
949 $sect = $1;
950 $sect =~ s/\W//g;
951 $sect =~ y/A-Z/a-z/;
952 $sects{$sect} = 1;
953 print;
954 next;
956 if (/^\s*EndSection/i) {
957 # end of Section
958 if ($sect eq "serverflags") {
959 if (!$got_DontVTSwitch) {
960 print " ##Xdummy:##\n";
961 print " Option \"DontVTSwitch\" \"true\"\n";
963 if (!$got_AllowMouseOpenFail) {
964 print " ##Xdummy:##\n";
965 print " Option \"AllowMouseOpenFail\" \"true\"\n";
967 if (!$got_PciForceNone) {
968 print " ##Xdummy:##\n";
969 print " Option \"PciForceNone\" \"true\"\n";
971 } elsif ($sect eq "device") {
972 if (!$got_Driver) {
973 print " ##Xdummy:##\n";
974 print " Driver \"dummy\"\n";
976 if (!$got_VideoRam) {
977 print " ##Xdummy:##\n";
978 print " VideoRam $videoram\n";
980 } elsif ($sect eq "screen") {
981 if ($depth ne "" && !got_DefaultDepth) {
982 print " ##Xdummy:##\n";
983 print " DefaultDepth $depth\n";
985 if ($got_Monitor eq "") {
986 print " ##Xdummy:##\n";
987 print " Monitor \"Monitor0\"\n";
989 } elsif ($sect eq "monitor") {
990 if (!got_HorizSync) {
991 print " ##Xdummy:##\n";
992 print " HorizSync $HorizSync\n";
994 if (!got_VertRefresh) {
995 print " ##Xdummy:##\n";
996 print " VertRefresh $VertRefresh\n";
998 if (!$nomodelines) {
999 print " ##Xdummy:##\n";
1000 print $mode_str;
1003 $sect = "";
1004 print;
1005 next;
1008 if (/^\s*SubSection\s+(\S+)/i) {
1009 # start of Section
1010 $subsect = $1;
1011 $subsect =~ s/\W//g;
1012 $subsect =~ y/A-Z/a-z/;
1013 $subsects{$subsect} = 1;
1014 if ($sect eq "screen" && $subsect eq "display") {
1015 $got_Modes = 0;
1017 print;
1018 next;
1020 if (/^\s*EndSubSection/i) {
1021 # end of SubSection
1022 if ($sect eq "screen") {
1023 if ($subsect eq "display") {
1024 if ($depth ne "" && !$set_Depth) {
1025 print " ##Xdummy:##\n";
1026 print " Depth\t$depth\n";
1028 if ($geom ne "" && ! $got_Modes) {
1029 print " ##Xdummy:##\n";
1030 print " Modes\t$geom\n";
1034 $subsect = "";
1035 print;
1036 next;
1039 $l = $_;
1040 $l =~ s/#.*$//;
1041 if ($sect eq "serverflags") {
1042 if ($l =~ /^\s*Option.*DontVTSwitch/i) {
1043 $_ =~ s/false/true/ig;
1044 $got_DontVTSwitch = 1;
1046 if ($l =~ /^\s*Option.*AllowMouseOpenFail/i) {
1047 $_ =~ s/false/true/ig;
1048 $got_AllowMouseOpenFail = 1;
1050 if ($l =~ /^\s*Option.*PciForceNone/i) {
1051 $_ =~ s/false/true/ig;
1052 $got_PciForceNone= 1;
1055 if ($sect eq "module") {
1056 if ($l =~ /^\s*Load.*\b(dri|fbdevhw)\b/i) {
1057 $_ = "##Xdummy## $_";
1060 if ($sect eq "monitor") {
1061 if ($l =~ /^\s*HorizSync/i) {
1062 $got_HorizSync = 1;
1064 if ($l =~ /^\s*VertRefresh/i) {
1065 $got_VertRefresh = 1;
1068 if ($sect eq "device") {
1069 if ($l =~ /^(\s*Driver)\b/i) {
1070 $_ = "$1 \"dummy\"\n";
1071 $got_Driver = 1;
1073 if ($l =~ /^\s*VideoRam/i) {
1074 $got_VideoRam= 1;
1077 if ($sect eq "inputdevice") {
1078 if ($l =~ /^\s*Option.*\bDevice\b/i) {
1079 print " ##Xdummy:##\n";
1080 $_ = " Option \"Device\" \"/dev/dilbert$n\"\n";
1083 if ($sect eq "screen") {
1084 if ($l =~ /^\s*DefaultDepth\s+(\d+)/i) {
1085 if ($depth ne "") {
1086 print " ##Xdummy:##\n";
1087 $_ = " DefaultDepth\t$depth\n";
1089 $got_DefaultDepth = 1;
1091 if ($l =~ /^\s*Monitor\s+(\S+)/i) {
1092 $got_Monitor = $1;
1093 $got_Monitor =~ s/"//g;
1095 if ($subsect eq "display") {
1096 if ($geom ne "") {
1097 if ($l =~ /^(\s*Modes)\b/i) {
1098 print " ##Xdummy:##\n";
1099 $_ = "$1 $geom\n";
1100 $got_Modes = 1;
1103 if ($l =~ /^\s*Depth\s+(\d+)/i) {
1104 my $d = $1;
1105 if (!$set_Depth && $depth ne "") {
1106 $set_Depth = 1;
1107 if ($depth != $d) {
1108 print " ##Xdummy:##\n";
1109 $_ = " Depth\t$depth\n";
1115 print;
1117 if ($ENV{XDUMMY_NOTWEAK}) {
1118 exit;
1120 # create any crucial sections that are missing:
1121 if (! exists($sects{serverflags})) {
1122 print "\n##Xdummy:##\n";
1123 print "Section \"ServerFlags\"\n";
1124 print " Option \"DontVTSwitch\" \"true\"\n";
1125 print " Option \"AllowMouseOpenFail\" \"true\"\n";
1126 print " Option \"PciForceNone\" \"true\"\n";
1127 print "EndSection\n";
1129 if (! exists($sects{device})) {
1130 print "\n##Xdummy:##\n";
1131 print "Section \"Device\"\n";
1132 print " Identifier \"Videocard0\"\n";
1133 print " Driver \"dummy\"\n";
1134 print " VideoRam $videoram\n";
1135 print "EndSection\n";
1137 if (! exists($sects{monitor})) {
1138 print "\n##Xdummy:##\n";
1139 print "Section \"Monitor\"\n";
1140 print " Identifier \"Monitor0\"\n";
1141 print " HorizSync $HorizSync\n";
1142 print " VertRefresh $VertRefresh\n";
1143 print "EndSection\n";
1145 if (! exists($sects{screen})) {
1146 print "\n##Xdummy:##\n";
1147 print "Section \"Screen\"\n";
1148 print " Identifier \"Screen0\"\n";
1149 print " Device \"Videocard0\"\n";
1150 if ($got_Monitor ne "") {
1151 print " Monitor \"$got_Monitor\"\n";
1152 } else {
1153 print " Monitor \"Monitor0\"\n";
1155 if ($depth ne "") {
1156 print " DefaultDepth $depth\n";
1157 } else {
1158 print " DefaultDepth 24\n";
1160 print " SubSection \"Display\"\n";
1161 print " Viewport 0 0\n";
1162 print " Depth 24\n";
1163 if ($got_Modes) {
1165 } elsif ($geom ne "") {
1166 print " Modes $geom\n";
1167 } else {
1168 print " Modes \"1280x1024\" \"1024x768\" \"800x600\"\n";
1170 print " EndSubSection\n";
1171 print "EndSection\n";
1176 # Work out config file and tweak it.
1178 if [ "X$cmdline_config" = "X" ]; then
1180 elif [ "X$cmdline_config" = "Xxdummy-builtin" ]; then
1182 elif echo "$cmdline_config" | grep '/' > /dev/null; then
1184 else
1185 # ignore basename only case (let server handle it)
1186 cmdline_config=""
1187 notweak=1
1190 config=$cmdline_config
1192 if [ "X$notweak" = "X1" -a "X$root" = "X" -a -f "$cmdline_config" ]; then
1193 # if not root we need to copy (but not tweak) the specified config.
1194 XDUMMY_NOTWEAK=1
1195 export XDUMMY_NOTWEAK
1196 notweak=""
1199 if [ ! $notweak ]; then
1200 # tweaked config will be put in $config2:
1201 config2=""
1202 if [ "X$config" = "X" ]; then
1203 # use the default one:
1204 if [ "X$stype" = "Xxorg" ]; then
1205 config=/etc/X11/xorg.conf
1206 else
1207 if [ -f "/etc/X11/XF86Config-4" ]; then
1208 config="/etc/X11/XF86Config-4"
1209 else
1210 config="/etc/X11/XF86Config"
1213 if [ ! -f "$config" ]; then
1214 for c in /etc/X11/xorg.conf /etc/X11/XF86Config-4 /etc/X11/XF86Config
1216 if [ -f $c ]; then
1217 config=$c
1218 break
1220 done
1224 if [ "X$config" = "Xxdummy-builtin" ]; then
1225 config=""
1228 if [ ! -f "$config" ]; then
1229 config="$XDUMMY_TMPDIR/xorg.conf"
1230 warn "$program: using minimal built-in xorg.conf settings."
1231 cat > $config <<END
1233 Section "ServerLayout"
1234 Identifier "Layout0"
1235 Screen 0 "Screen0"
1236 InputDevice "Keyboard0" "CoreKeyboard"
1237 InputDevice "Mouse0" "CorePointer"
1238 EndSection
1240 Section "Files"
1241 EndSection
1243 Section "Module"
1244 Load "dbe"
1245 Load "extmod"
1246 Load "freetype"
1247 Load "glx"
1248 EndSection
1250 Section "InputDevice"
1251 Identifier "Mouse0"
1252 Driver "mouse"
1253 Option "Protocol" "auto"
1254 Option "Device" "/dev/psaux"
1255 Option "Emulate3Buttons" "no"
1256 Option "ZAxisMapping" "4 5"
1257 EndSection
1259 Section "InputDevice"
1260 Identifier "Keyboard0"
1261 Driver "kbd"
1262 EndSection
1264 Section "Monitor"
1265 Identifier "Monitor0"
1266 VendorName "Unknown"
1267 ModelName "Unknown"
1268 HorizSync 30.0 - 130.0
1269 VertRefresh 50.0 - 250.0
1270 Option "DPMS"
1271 EndSection
1273 Section "Device"
1274 Identifier "Device0"
1275 Driver "foovideo"
1276 VendorName "foovideo Corporation"
1277 EndSection
1279 Section "Screen"
1280 Identifier "Screen0"
1281 Device "Device0"
1282 Monitor "Monitor0"
1283 DefaultDepth 24
1284 SubSection "Display"
1285 Depth 24
1286 Modes "1280x1024"
1287 EndSubSection
1288 EndSection
1293 if [ -f "$config" ]; then
1294 tweak_config $config
1297 # now we need to get our tweaked config file onto the command line:
1298 if [ "X$cmdline_config" = "X" ]; then
1299 # append to cmdline (FUBAR will be substituted below.)
1300 if [ "X$stype" = "Xxorg" ]; then
1301 args="$args -config FUBAR"
1302 else
1303 args="$args -xf86config FUBAR"
1306 if [ "X$config2" != "X" ]; then
1307 # or modify $args:
1308 c2=$config2
1309 if [ "X$root" = "X" ]; then
1310 # ordinary user cannot use absolute path.
1311 c2=`basename $config2`
1313 args=`echo "$args" | sed \
1314 -e "s,-config *[^ ][^ ]*,-config $c2,g" \
1315 -e "s,-xf86config *[^ ][^ ]*,-xf86config $c2,g"`
1319 if [ $prconf ]; then
1320 warn ""
1321 warn "Printing out the Xorg/XFree86 server config file:"
1322 warn ""
1323 if [ "X$config2" = "X" ]; then
1324 warn "NO CONFIG GENERATED."
1325 exit 1
1326 else
1327 cat "$config2"
1329 exit 0
1332 if [ $debug ]; then
1333 XDUMMY_DEBUG=1
1334 export XDUMMY_DEBUG
1336 if [ $root ]; then
1337 XDUMMY_ROOT=1
1338 export XDUMMY_ROOT
1341 # Finally, run it:
1343 if [ "X$debug" != "X" -o "X$runit" = "X" ]; then
1344 if [ ! $runit ]; then
1345 echo ""
1346 echo "/usr/bin/env:"
1347 env | egrep -v '^(LS_COLORS|TERMCAP)' | sort
1348 echo ""
1349 echo "XDUMMY*:"
1350 env | grep '^XDUMMY' | sort
1351 echo ""
1353 warn ""
1354 warn "The command to run is:"
1355 warn ""
1356 so=$SO
1357 pwd=`pwd`
1358 if echo "$so" | grep '^\./' > /dev/null; then
1359 so=`echo "$so" | sed -e "s,^\.,$pwd,"`
1361 if echo "$so" | grep '/' > /dev/null; then
1363 else
1364 so="$pwd/$so"
1366 warn "env LD_PRELOAD=$so $xserver $disp $args $vt"
1367 warn ""
1368 if [ ! $runit ]; then
1369 exit 0
1373 if [ $strace ]; then
1374 if [ "X$strace" = "X2" ]; then
1375 ltrace -f env LD_PRELOAD=$SO $xserver $disp $args $vt
1376 else
1377 strace -f env LD_PRELOAD=$SO $xserver $disp $args $vt
1379 else
1380 exec env LD_PRELOAD=$SO $xserver $disp $args $vt
1383 exit $?
1385 #########################################################################
1387 code() {
1388 #code_begin
1389 #include <stdio.h>
1390 #define O_ACCMODE 0003
1391 #define O_RDONLY 00
1392 #define O_WRONLY 01
1393 #define O_RDWR 02
1394 #define O_CREAT 0100 /* not fcntl */
1395 #define O_EXCL 0200 /* not fcntl */
1396 #define O_NOCTTY 0400 /* not fcntl */
1397 #define O_TRUNC 01000 /* not fcntl */
1398 #define O_APPEND 02000
1399 #define O_NONBLOCK 04000
1400 #define O_NDELAY O_NONBLOCK
1401 #define O_SYNC 010000
1402 #define O_FSYNC O_SYNC
1403 #define O_ASYNC 020000
1405 #include <unistd.h>
1406 #include <stdlib.h>
1407 #include <string.h>
1409 #include <linux/vt.h>
1410 #include <linux/kd.h>
1412 #define __USE_GNU
1413 #include <dlfcn.h>
1415 static char tmpdir[4096];
1416 static char str1[4096];
1417 static char str2[4096];
1419 static char devs[256][1024];
1420 static int debug = -1;
1421 static int root = -1;
1422 static int changed_uid = 0;
1423 static int saw_fonts = 0;
1424 static int saw_lib_modules = 0;
1426 static time_t start = 0;
1428 void check_debug(void) {
1429 if (debug < 0) {
1430 if (getenv("XDUMMY_DEBUG") != NULL) {
1431 debug = 1;
1432 } else {
1433 debug = 0;
1435 /* prevent other processes using the preload: */
1436 putenv("LD_PRELOAD=");
1439 void check_root(void) {
1440 if (root < 0) {
1441 /* script tells us if we are root */
1442 if (getenv("XDUMMY_ROOT") != NULL) {
1443 root = 1;
1444 } else {
1445 root = 0;
1450 void check_uid(void) {
1451 if (start == 0) {
1452 start = time(NULL);
1453 if (debug) fprintf(stderr, "START: %u\n", (unsigned int) start);
1454 return;
1455 } else if (changed_uid == 0) {
1456 if (saw_fonts || time(NULL) > start + 20) {
1457 if (getenv("XDUMMY_UID")) {
1458 int uid = atoi(getenv("XDUMMY_UID"));
1459 if (debug) fprintf(stderr, "SETREUID: %d saw_fonts=%d\n", uid, saw_fonts);
1460 if (uid >= 0) {
1461 /* this will simply fail in -nonroot mode: */
1462 setreuid(uid, -1);
1465 changed_uid = 1;
1470 #define CHECKIT if (debug < 0) check_debug(); \
1471 if (root < 0) check_root(); \
1472 check_uid();
1474 static void set_tmpdir(void) {
1475 char *s;
1476 static int didset = 0;
1477 if (didset) {
1478 return;
1480 s = getenv("XDUMMY_TMPDIR");
1481 if (! s) {
1482 s = "/tmp";
1484 tmpdir[0] = '\0';
1485 strcat(tmpdir, s);
1486 strcat(tmpdir, "/");
1487 didset = 1;
1490 static char *tmpdir_path(const char *path) {
1491 char *str;
1492 set_tmpdir();
1493 strcpy(str2, path);
1494 str = str2;
1495 while (*str) {
1496 if (*str == '/') {
1497 *str = '_';
1499 str++;
1501 strcpy(str1, tmpdir);
1502 strcat(str1, str2);
1503 return str1;
1506 int open(const char *pathname, int flags, unsigned short mode) {
1507 int fd;
1508 char *store_dev = NULL;
1509 static int (*real_open)(const char *, int , unsigned short) = NULL;
1511 CHECKIT
1512 if (! real_open) {
1513 real_open = (int (*)(const char *, int , unsigned short))
1514 dlsym(RTLD_NEXT, "open");
1517 if (strstr(pathname, "lib/modules/")) {
1518 /* not currently used. */
1519 saw_lib_modules = 1;
1522 if (!root) {
1523 if (strstr(pathname, "/dev/") == pathname) {
1524 store_dev = strdup(pathname);
1526 if (strstr(pathname, "/dev/tty") == pathname && strcmp(pathname, "/dev/tty")) {
1527 pathname = tmpdir_path(pathname);
1528 if (debug) fprintf(stderr, "OPEN: %s -> %s (as FIFO)\n", store_dev, pathname);
1529 /* we make it a FIFO so ioctl on it does not fail */
1530 unlink(pathname);
1531 mkfifo(pathname, 0666);
1532 } else if (0) {
1533 /* we used to handle more /dev files ... */
1534 fd = real_open(pathname, O_WRONLY|O_CREAT, 0777);
1535 close(fd);
1539 fd = real_open(pathname, flags, mode);
1541 if (debug) fprintf(stderr, "OPEN: %s %d %d fd=%d\n", pathname, flags, mode, fd);
1543 if (! root) {
1544 if (store_dev) {
1545 if (fd < 256) {
1546 strcpy(devs[fd], store_dev);
1548 free(store_dev);
1552 return(fd);
1555 int open64(const char *pathname, int flags, unsigned short mode) {
1556 int fd;
1558 CHECKIT
1559 if (debug) fprintf(stderr, "OPEN64: %s %d %d\n", pathname, flags, mode);
1561 fd = open(pathname, flags, mode);
1562 return(fd);
1565 int rename(const char *oldpath, const char *newpath) {
1566 static int (*real_rename)(const char *, const char *) = NULL;
1568 CHECKIT
1569 if (! real_rename) {
1570 real_rename = (int (*)(const char *, const char *))
1571 dlsym(RTLD_NEXT, "rename");
1574 if (debug) fprintf(stderr, "RENAME: %s %s\n", oldpath, newpath);
1576 if (root) {
1577 return(real_rename(oldpath, newpath));
1580 if (strstr(oldpath, "/var/log") == oldpath) {
1581 if (debug) fprintf(stderr, "RENAME: returning 0\n");
1582 return 0;
1584 return(real_rename(oldpath, newpath));
1587 FILE *fopen(const char *pathname, const char *mode) {
1588 static FILE* (*real_fopen)(const char *, const char *) = NULL;
1589 char *str;
1591 if (! saw_fonts) {
1592 if (strstr(pathname, "/fonts/")) {
1593 if (strstr(pathname, "fonts.dir")) {
1594 saw_fonts = 1;
1595 } else if (strstr(pathname, "fonts.alias")) {
1596 saw_fonts = 1;
1601 CHECKIT
1602 if (! real_fopen) {
1603 real_fopen = (FILE* (*)(const char *, const char *))
1604 dlsym(RTLD_NEXT, "fopen");
1607 if (debug) fprintf(stderr, "FOPEN: %s %s\n", pathname, mode);
1609 if (strstr(pathname, "xdummy_modified_xconfig.conf")) {
1610 /* make our config appear to be in /etc/X11, etc. */
1611 char *q = strrchr(pathname, '/');
1612 if (q != NULL && getenv("XDUMMY_TMPDIR") != NULL) {
1613 strcpy(str1, getenv("XDUMMY_TMPDIR"));
1614 strcat(str1, q);
1615 if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str1);
1616 pathname = str1;
1620 if (root) {
1621 return(real_fopen(pathname, mode));
1624 str = (char *) pathname;
1625 if (strstr(pathname, "/var/log") == pathname) {
1626 str = tmpdir_path(pathname);
1627 if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str);
1629 return(real_fopen(str, mode));
1633 #define RETURN0 if (debug) \
1634 {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return 0;
1635 #define RETURN1 if (debug) \
1636 {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return -1;
1638 int ioctl(int fd, int req, void *ptr) {
1639 static int closed_xf86Info_consoleFd = 0;
1640 static int (*real_ioctl)(int, int , void *) = NULL;
1642 CHECKIT
1643 if (! real_ioctl) {
1644 real_ioctl = (int (*)(int, int , void *))
1645 dlsym(RTLD_NEXT, "open");
1647 if (debug) fprintf(stderr, "IOCTL: %d 0x%x %p\n", fd, req, ptr);
1649 /* based on xorg-x11-6.8.1-dualhead.patch */
1650 if (req == VT_GETMODE) {
1651 /* close(xf86Info.consoleFd) */
1652 if (0 && ! closed_xf86Info_consoleFd) {
1653 /* I think better not to close it... */
1654 close(fd);
1655 closed_xf86Info_consoleFd = 1;
1657 RETURN0
1658 } else if (req == VT_SETMODE) {
1659 RETURN0
1660 } else if (req == VT_GETSTATE) {
1661 RETURN0
1662 } else if (req == KDSETMODE) {
1663 RETURN0
1664 } else if (req == KDSETLED) {
1665 RETURN0
1666 } else if (req == KDGKBMODE) {
1667 RETURN0
1668 } else if (req == KDSKBMODE) {
1669 RETURN0
1670 } else if (req == VT_ACTIVATE) {
1671 RETURN0
1672 } else if (req == VT_WAITACTIVE) {
1673 RETURN0
1674 } else if (req == VT_RELDISP) {
1675 if (ptr == (void *) 1) {
1676 RETURN1
1677 } else if (ptr == (void *) VT_ACKACQ) {
1678 RETURN0
1682 return(real_ioctl(fd, req, ptr));
1685 typedef void (*sighandler_t)(int);
1686 #define SIGUSR1 10
1687 #define SIG_DFL ((sighandler_t)0)
1689 sighandler_t signal(int signum, sighandler_t handler) {
1690 static sighandler_t (*real_signal)(int, sighandler_t) = NULL;
1692 CHECKIT
1693 if (! real_signal) {
1694 real_signal = (sighandler_t (*)(int, sighandler_t))
1695 dlsym(RTLD_NEXT, "signal");
1698 if (debug) fprintf(stderr, "SIGNAL: %d %p\n", signum, handler);
1700 if (signum == SIGUSR1) {
1701 if (debug) fprintf(stderr, "SIGNAL: skip SIGUSR1\n");
1702 return SIG_DFL;
1705 return(real_signal(signum, handler));
1708 int close(int fd) {
1709 static int (*real_close)(int) = NULL;
1711 CHECKIT
1712 if (! real_close) {
1713 real_close = (int (*)(int)) dlsym(RTLD_NEXT, "close");
1716 if (debug) fprintf(stderr, "CLOSE: %d\n", fd);
1717 if (!root) {
1718 if (fd < 256) {
1719 devs[fd][0] = '\0';
1722 return(real_close(fd));
1725 struct stat {
1726 int foo;
1729 int stat(const char *path, struct stat *buf) {
1730 static int (*real_stat)(const char *, struct stat *) = NULL;
1732 CHECKIT
1733 if (! real_stat) {
1734 real_stat = (int (*)(const char *, struct stat *))
1735 dlsym(RTLD_NEXT, "stat");
1738 if (debug) fprintf(stderr, "STAT: %s\n", path);
1740 return(real_stat(path, buf));
1743 int stat64(const char *path, struct stat *buf) {
1744 static int (*real_stat64)(const char *, struct stat *) = NULL;
1746 CHECKIT
1747 if (! real_stat64) {
1748 real_stat64 = (int (*)(const char *, struct stat *))
1749 dlsym(RTLD_NEXT, "stat64");
1752 if (debug) fprintf(stderr, "STAT64: %s\n", path);
1754 return(real_stat64(path, buf));
1757 int chown(const char *path, uid_t owner, gid_t group) {
1758 static int (*real_chown)(const char *, uid_t, gid_t) = NULL;
1760 CHECKIT
1761 if (! real_chown) {
1762 real_chown = (int (*)(const char *, uid_t, gid_t))
1763 dlsym(RTLD_NEXT, "chown");
1766 if (root) {
1767 return(real_chown(path, owner, group));
1770 if (debug) fprintf(stderr, "CHOWN: %s %d %d\n", path, owner, group);
1772 if (strstr(path, "/dev") == path) {
1773 if (debug) fprintf(stderr, "CHOWN: return 0\n");
1774 return 0;
1777 return(real_chown(path, owner, group));
1780 extern int *__errno_location (void);
1781 #ifndef ENODEV
1782 #define ENODEV 19
1783 #endif
1785 int ioperm(unsigned long from, unsigned long num, int turn_on) {
1786 static int (*real_ioperm)(unsigned long, unsigned long, int) = NULL;
1788 CHECKIT
1789 if (! real_ioperm) {
1790 real_ioperm = (int (*)(unsigned long, unsigned long, int))
1791 dlsym(RTLD_NEXT, "ioperm");
1793 if (debug) fprintf(stderr, "IOPERM: %d %d %d\n", (int) from, (int) num, turn_on);
1794 if (root) {
1795 return(real_ioperm(from, num, turn_on));
1797 if (from == 0 && num == 1024 && turn_on == 1) {
1798 /* we want xf86EnableIO to fail */
1799 if (debug) fprintf(stderr, "IOPERM: setting ENODEV.\n");
1800 *__errno_location() = ENODEV;
1801 return -1;
1803 return 0;
1806 int iopl(int level) {
1807 static int (*real_iopl)(int) = NULL;
1809 CHECKIT
1810 if (! real_iopl) {
1811 real_iopl = (int (*)(int)) dlsym(RTLD_NEXT, "iopl");
1813 if (debug) fprintf(stderr, "IOPL: %d\n", level);
1814 if (root) {
1815 return(real_iopl(level));
1817 return 0;
1820 #ifdef INTERPOSE_GETUID
1823 * we got things to work w/o pretending to be root.
1824 * so we no longer interpose getuid(), etc.
1827 uid_t getuid(void) {
1828 static uid_t (*real_getuid)(void) = NULL;
1829 CHECKIT
1830 if (! real_getuid) {
1831 real_getuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid");
1833 if (root) {
1834 return(real_getuid());
1836 if (debug) fprintf(stderr, "GETUID: 0\n");
1837 return 0;
1839 uid_t geteuid(void) {
1840 static uid_t (*real_geteuid)(void) = NULL;
1841 CHECKIT
1842 if (! real_geteuid) {
1843 real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid");
1845 if (root) {
1846 return(real_geteuid());
1848 if (debug) fprintf(stderr, "GETEUID: 0\n");
1849 return 0;
1851 uid_t geteuid_kludge1(void) {
1852 static uid_t (*real_geteuid)(void) = NULL;
1853 CHECKIT
1854 if (! real_geteuid) {
1855 real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid");
1857 if (debug) fprintf(stderr, "GETEUID: 0 saw_libmodules=%d\n", saw_lib_modules);
1858 if (root && !saw_lib_modules) {
1859 return(real_geteuid());
1860 } else {
1861 saw_lib_modules = 0;
1862 return 0;
1866 uid_t getuid32(void) {
1867 static uid_t (*real_getuid32)(void) = NULL;
1868 CHECKIT
1869 if (! real_getuid32) {
1870 real_getuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid32");
1872 if (root) {
1873 return(real_getuid32());
1875 if (debug) fprintf(stderr, "GETUID32: 0\n");
1876 return 0;
1878 uid_t geteuid32(void) {
1879 static uid_t (*real_geteuid32)(void) = NULL;
1880 CHECKIT
1881 if (! real_geteuid32) {
1882 real_geteuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid32");
1884 if (root) {
1885 return(real_geteuid32());
1887 if (debug) fprintf(stderr, "GETEUID32: 0\n");
1888 return 0;
1891 gid_t getgid(void) {
1892 static gid_t (*real_getgid)(void) = NULL;
1893 CHECKIT
1894 if (! real_getgid) {
1895 real_getgid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid");
1897 if (root) {
1898 return(real_getgid());
1900 if (debug) fprintf(stderr, "GETGID: 0\n");
1901 return 0;
1903 gid_t getegid(void) {
1904 static gid_t (*real_getegid)(void) = NULL;
1905 CHECKIT
1906 if (! real_getegid) {
1907 real_getegid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid");
1909 if (root) {
1910 return(real_getegid());
1912 if (debug) fprintf(stderr, "GETEGID: 0\n");
1913 return 0;
1915 gid_t getgid32(void) {
1916 static gid_t (*real_getgid32)(void) = NULL;
1917 CHECKIT
1918 if (! real_getgid32) {
1919 real_getgid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid32");
1921 if (root) {
1922 return(real_getgid32());
1924 if (debug) fprintf(stderr, "GETGID32: 0\n");
1925 return 0;
1927 gid_t getegid32(void) {
1928 static gid_t (*real_getegid32)(void) = NULL;
1929 CHECKIT
1930 if (! real_getegid32) {
1931 real_getegid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid32");
1933 if (root) {
1934 return(real_getegid32());
1936 if (debug) fprintf(stderr, "GETEGID32: 0\n");
1937 return 0;
1939 #endif
1941 #if 0
1942 /* maybe we need to interpose on strcmp someday... here is the template */
1943 int strcmp(const char *s1, const char *s2) {
1944 static int (*real_strcmp)(const char *, const char *) = NULL;
1945 CHECKIT
1946 if (! real_strcmp) {
1947 real_strcmp = (int (*)(const char *, const char *)) dlsym(RTLD_NEXT, "strcmp");
1949 if (debug) fprintf(stderr, "STRCMP: '%s' '%s'\n", s1, s2);
1950 return(real_strcmp(s1, s2));
1952 #endif
1954 #code_end