1 #!/bin/sh 2 # ---------------------------------------------------------------------- 3 # Copyright (C) 2005-2010 Karl J. Runge <runge (at] 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. 12 # 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. 17 # 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 # ---------------------------------------------------------------------- 23 # 24 # 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. 27 # 28 # Run "Xdummy -help" for more info. 29 # 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="" 44 45 PATH=$PATH:/bin:/usr/bin 46 export PATH 47 48 program=`basename "$0"` 49 50 help () { 51 ${PAGER:-more} << END 52 $program: 53 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". 58 59 In other words, it tries to make Xorg/XFree86 with the "dummy" 60 device driver act more like Xvfb(1). 61 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. 67 68 So, for example, x11vnc+Xdummy terminal services are a little better 69 than x11vnc+Xvfb. 70 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. 76 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. 81 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. 87 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. 91 92 Your Linux distribution may not install the dummy driver by default, 93 e.g: 94 95 /usr/lib/xorg/modules/drivers/dummy_drv.so 96 97 some have it in a package named xserver-xorg-video-dummy you that 98 need to install. 99 100 Usage: 101 102 $program <${program}-args> <Xserver-args> 103 104 (actually, the arguments can be supplied in any order.) 105 106 Examples: 107 108 $program -install 109 110 $program :1 111 112 $program -debug :1 113 114 $program -tmpdir ~/mytmp :1 -nolisten tcp 115 116 startx example: 117 118 startx -e bash -- $program :2 -depth 16 119 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.) 123 124 xdm example: 125 126 xdm -config /usr/local/dummy/xdm-config -nodaemon 127 128 where the xdm-config file has line: 129 130 DisplayManager.servers: /usr/local/dummy/Xservers 131 132 and /usr/local/dummy/Xservers has lines: 133 134 :1 local /usr/local/dummy/Xdummy :1 -debug 135 :2 local /usr/local/dummy/Xdummy :2 -debug 136 137 (-debug is optional) 138 139 gdm/kdm example: 140 141 TBD. 142 143 Root permission and x11vnc: 144 145 Update: as of 12/2009 this program no longer must be run as root. 146 So try it as non-root before running it as root and/or the 147 following schemes. 148 149 In some circumstances X server program may need to be run as root. 150 If so, one could run x11vnc as root with -unixpw (it switches 151 to the user that logs in) and that may be OK, some other ideas: 152 153 - add this to sudo via visudo: 154 155 ALL ALL = NOPASSWD: /usr/local/bin/Xdummy 156 157 - use this little suid wrapper: 158 /* 159 * xdummy.c 160 * 161 cc -o ./xdummy xdummy.c 162 sudo cp ./xdummy /usr/local/bin/xdummy 163 sudo chown root:root /usr/local/bin/xdummy 164 sudo chmod u+s /usr/local/bin/xdummy 165 * 166 */ 167 #include <unistd.h> 168 #include <stdlib.h> 169 #include <sys/types.h> 170 #include <stdio.h> 171 172 int main (int argc, char *argv[]) { 173 extern char **environ; 174 char str[100]; 175 sprintf(str, "XDUMMY_UID=%d", (int) getuid()); 176 putenv(str); 177 setuid(0); 178 setgid(0); 179 execv("/usr/local/bin/Xdummy", argv); 180 exit(1); 181 return 1; 182 } 183 184 185 Options: 186 187 ${program}-args: 188 189 -install Compile the LD_PRELOAD shared object and install it 190 next to the $program script file as: 191 192 $0.so 193 194 When that file exists it is used as the LD_PRELOAD 195 shared object without recompiling. Otherwise, 196 each time $program is run the LD_PRELOAD shared 197 object is compiled as a file in /tmp (or -tmpdir) 198 199 If you set the environment variable 200 INTERPOSE_GETUID=1 when building, then when 201 $program is run as an ordinary user, the shared 202 object will interpose getuid() calls and pretend 203 to be root. Otherwise it doesn't pretend to 204 be root. 205 206 You can also set the CFLAGS environment variable 207 to anything else you want on the compile cmdline. 208 209 -uninstall Remove the file: 210 211 $0.so 212 213 The LD_PRELOAD shared object will then be compiled 214 each time this program is run. 215 216 The X server is not started under -install, -uninstall, or -prconf. 217 218 219 :N The DISPLAY (e.g. :15) is often the first 220 argument. It is passed to the real X server and 221 also used by the Xdummy script as an identifier. 222 223 -geom geom1[,geom2...] Take the geometry (e.g. 1024x768) or list 224 of geometries and insert them into the Screen 225 section of the tweaked X server config file. 226 Use this to have a different geometry than the 227 one(s) in the system config file. 228 229 The option -geometry can be used instead of -geom; 230 x11vnc calls Xdummy and Xvfb this way. 231 232 -nomodelines When you specify -geom/-geometry, $program will 233 create Modelines for each geometry and put them 234 in the Monitor section. If you do not want this 235 then supply -nomodelines. 236 237 -depth n Use pixel color depth n (e.g. 8, 16, or 24). This 238 makes sure the X config file has a Screen.Display 239 subsection of this depth. Note this option is 240 ALSO passed to the X server. 241 242 -DEPTH n Same as -depth, except not passed to X server. 243 244 -tmpdir dir Specify a temporary directory, owned by you and 245 only writable by you. This is used in place of 246 /tmp/Xdummy.\$USER/.. to place the $program.so 247 shared object, tweaked config files, etc. 248 249 -nonroot Run in non-root mode (working 12/2009, now default) 250 251 -root Run as root (may still be needed in some 252 environments.) Same as XDUMMY_RUN_AS_ROOT=1. 253 254 -nosudo Do not try to use sudo(1) when re-running as root, 255 use su(1) instead. 256 257 -xserver path Specify the path to the Xserver to use. Default 258 is to try "Xorg" first and then "XFree86". If 259 those are not in \$PATH, it tries these locations: 260 /usr/bin/Xorg 261 /usr/X11R6/bin/Xorg 262 /usr/X11R6/bin/XFree86 263 264 -n Do not run the command to start the X server, 265 just show the command that $program would run. 266 The LD_PRELOAD shared object will be built, 267 if needed. Also note any XDUMMY* environment 268 variables that need to be set. 269 270 -prconf Print, to stdout, the tweaked Xorg/XFree86 271 config file (-config and -xf86config server 272 options, respectively.) The Xserver is not 273 started. 274 275 -notweak Do not tweak (modify) the Xorg/XFree86 config file 276 (system or server command line) at all. The -geom 277 and similar config file modifications are ignored. 278 279 It is up to you to make sure it is a working 280 config file (e.g. "dummy" driver, etc.) 281 Perhaps you want to use a file based on the 282 -prconf output. 283 284 -debug Extra debugging output. 285 286 -strace strace(1) the Xserver process (for troubleshooting.) 287 -ltrace ltrace(1) instead of strace (can be slow.) 288 289 -h, -help Print out this help. 290 291 292 Xserver-args: 293 294 Most of the Xorg and XFree86 options will work and are simply 295 passed along if you supply them. Important ones that may be 296 supplied if missing: 297 298 :N X Display number for server to use. 299 300 vtNN Linux virtual terminal (VT) to use (a VT is currently 301 still used, just not switched to and from.) 302 303 -config file Driver "dummy" tweaked config file, a 304 -xf86config file number of settings are tweaked besides Driver. 305 306 If -config/-xf86config is not given, the system one 307 (e.g. /etc/X11/xorg.conf) is used. If the system one cannot be 308 found, a built-in one is used. Any settings in the config file 309 that are not consistent with "dummy" mode will be overwritten 310 (unless -notweak is specified.) 311 312 Use -config xdummy-builtin to force usage of the builtin config. 313 314 If "file" is only a basename (e.g. "xorg.dummy.conf") with no /'s, 315 then no tweaking of it is done: the X server will look for that 316 basename via its normal search algorithm. If the found file does 317 not refer to the "dummy" driver, etc, then the X server will fail. 318 319 Notes: 320 321 The Xorg/XFree86 "dummy" driver is currently undocumented. It works 322 well in this mode, but it is evidently not intended for end-users. 323 So it could be removed or broken at any time. 324 325 If the display Xserver-arg (e.g. :1) is not given, or ":" is given 326 that indicates $program should try to find a free one (based on 327 tcp ports.) 328 329 If the display virtual terminal, VT, (e.g. vt9) is not given that 330 indicates $program should try to find a free one (or guess a high one.) 331 332 This program is not completely secure WRT files in /tmp (but it tries 333 to a good degree.) Better is to use the -tmpdir option to supply a 334 directory only writable by you. Even better is to get rid of users 335 on the local machine you do not trust :-) 336 337 Set XDUMMY_SET_XV=1 to turn on debugging output for this script. 338 339 END 340 } 341 342 warn() { 343 echo "$*" 1>&2 344 } 345 346 if [ "X$XDUMMY_SET_XV" != "X" ]; then 347 set -xv 348 fi 349 350 if [ "X$XDUMMY_UID" = "X" ]; then 351 XDUMMY_UID=`id -u` 352 export XDUMMY_UID 353 fi 354 if [ "X$XDUMMY_UID" = "X0" ]; then 355 if [ "X$SUDO_UID" != "X" ]; then 356 XDUMMY_UID=$SUDO_UID 357 export XDUMMY_UID 358 fi 359 fi 360 361 # check if root=1 first: 362 # 363 if [ "X$XDUMMY_RUN_AS_ROOT" = "X1" ]; then 364 root=1 365 fi 366 for arg in $* 367 do 368 if [ "X$arg" = "X-nonroot" ]; then 369 root="" 370 elif [ "X$arg" = "X-root" ]; then 371 root=1 372 fi 373 done 374 375 # See if it really needs to be run as root: 376 # 377 if [ "X$XDUMMY_SU_EXEC" = "X" -a "X$root" = "X1" -a "X`id -u`" != "X0" ]; then 378 # this is to prevent infinite loop in case su/sudo doesn't work: 379 XDUMMY_SU_EXEC=1 380 export XDUMMY_SU_EXEC 381 382 dosu=1 383 nosudo="" 384 385 for arg in $* 386 do 387 if [ "X$arg" = "X-nonroot" ]; then 388 dosu="" 389 elif [ "X$arg" = "X-nosudo" ]; then 390 nosudo="1" 391 elif [ "X$arg" = "X-help" ]; then 392 dosu="" 393 elif [ "X$arg" = "X-h" ]; then 394 dosu="" 395 elif [ "X$arg" = "X-install" ]; then 396 dosu="" 397 elif [ "X$arg" = "X-uninstall" ]; then 398 dosu="" 399 elif [ "X$arg" = "X-n" ]; then 400 dosu="" 401 elif [ "X$arg" = "X-prconf" ]; then 402 dosu="" 403 fi 404 done 405 if [ $dosu ]; then 406 # we need to restart it with su/sudo: 407 if type sudo > /dev/null 2>&1; then 408 : 409 else 410 nosudo=1 411 fi 412 if [ "X$nosudo" = "X" ]; then 413 warn "$program: supply the sudo password to restart as root:" 414 if [ "X$XDUMMY_UID" != "X" ]; then 415 exec sudo $0 -uid $XDUMMY_UID "$@" 416 else 417 exec sudo $0 "$@" 418 fi 419 else 420 warn "$program: supply the root password to restart as root:" 421 if [ "X$XDUMMY_UID" != "X" ]; then 422 exec su -c "$0 -uid $XDUMMY_UID $*" 423 else 424 exec su -c "$0 $*" 425 fi 426 fi 427 # DONE: 428 exit 429 fi 430 fi 431 432 # This will hold the X display, e.g. :20 433 # 434 disp="" 435 args="" 436 cmdline_config="" 437 438 # Process Xdummy args: 439 # 440 while [ "X$1" != "X" ] 441 do 442 if [ "X$1" = "X-config" -o "X$1" = "X-xf86config" ]; then 443 cmdline_config="$2" 444 fi 445 case $1 in 446 ":"*) disp=$1 447 ;; 448 "-install") install=1; runit="" 449 ;; 450 "-uninstall") uninstall=1; runit="" 451 ;; 452 "-n") runit="" 453 ;; 454 "-no") runit="" 455 ;; 456 "-norun") runit="" 457 ;; 458 "-prconf") prconf=1; runit="" 459 ;; 460 "-notweak") notweak=1 461 ;; 462 "-noconf") notweak=1 463 ;; 464 "-nonroot") root="" 465 ;; 466 "-root") root=1 467 ;; 468 "-nosudo") nosudo=1 469 ;; 470 "-xserver") xserver="$2"; shift 471 ;; 472 "-uid") XDUMMY_UID="$2"; shift 473 export XDUMMY_UID 474 ;; 475 "-geom") geom="$2"; shift 476 ;; 477 "-geometry") geom="$2"; shift 478 ;; 479 "-nomodelines") nomodelines=1 480 ;; 481 "-depth") depth="$2"; args="$args -depth $2"; 482 shift 483 ;; 484 "-DEPTH") depth="$2"; shift 485 ;; 486 "-tmpdir") XDUMMY_TMPDIR="$2"; shift 487 ;; 488 "-debug") debug=1 489 ;; 490 "-nodebug") debug="" 491 ;; 492 "-strace") strace=1 493 ;; 494 "-ltrace") strace=2 495 ;; 496 "-h") help; exit 0 497 ;; 498 "-help") help; exit 0 499 ;; 500 *) args="$args $1" 501 ;; 502 esac 503 shift 504 done 505 506 # Try to get a username for use in our tmp directory, etc. 507 # 508 user="" 509 if [ X`id -u` = "X0" ]; then 510 user=root # this will also be used below for id=0 511 elif [ "X$USER" != "X" ]; then 512 user=$USER 513 elif [ "X$LOGNAME" != "X" ]; then 514 user=$LOGNAME 515 fi 516 517 # Keep trying... 518 # 519 if [ "X$user" = "X" ]; then 520 user=`whoami 2>/dev/null` 521 fi 522 if [ "X$user" = "X" ]; then 523 user=`basename "$HOME"` 524 fi 525 if [ "X$user" = "X" -o "X$user" = "X." ]; then 526 user="u$$" 527 fi 528 529 if [ "X$debug" = "X1" -a "X$runit" != "X" ]; then 530 echo "" 531 echo "/usr/bin/env:" 532 env | egrep -v '^(LS_COLORS|TERMCAP)' | sort 533 echo "" 534 fi 535 536 # Function to compile the LD_PRELOAD shared object: 537 # 538 make_so() { 539 # extract code embedded in this script into a tmp C file: 540 n1=`grep -n '^#code_begin' $0 | head -1 | awk -F: '{print $1}'` 541 n2=`grep -n '^#code_end' $0 | head -1 | awk -F: '{print $1}'` 542 n1=`expr $n1 + 1` 543 dn=`expr $n2 - $n1` 544 545 tmp=$tdir/Xdummy.$RANDOM$$.c 546 rm -f $tmp 547 if [ -e $tmp -o -h $tmp ]; then 548 warn "$tmp still exists." 549 exit 1 550 fi 551 touch $tmp || exit 1 552 tail -n +$n1 $0 | head -n $dn > $tmp 553 554 # compile it to Xdummy.so: 555 if [ -f "$SO" ]; then 556 mv $SO $SO.$$ 557 rm -f $SO.$$ 558 fi 559 rm -f $SO 560 touch $SO 561 if [ ! -f "$SO" ]; then 562 SO=$tdir/Xdummy.$user.so 563 warn "warning switching LD_PRELOAD shared object to: $SO" 564 fi 565 566 if [ -f "$SO" ]; then 567 mv $SO $SO.$$ 568 rm -f $SO.$$ 569 fi 570 rm -f $SO 571 572 # we assume gcc: 573 if [ "X$INTERPOSE_GETUID" = "X1" ]; then 574 CFLAGS="$CFLAGS -DINTERPOSE_GETUID" 575 fi 576 echo "$program:" cc -shared -fPIC $CFLAGS -o $SO $tmp 577 cc -shared -fPIC $CFLAGS -o $SO $tmp 578 rc=$? 579 rm -f $tmp 580 if [ $rc != 0 ]; then 581 warn "$program: cannot build $SO" 582 exit 1 583 fi 584 if [ "X$debug" != "X" -o "X$install" != "X" ]; then 585 warn "$program: created $SO" 586 ls -l "$SO" 587 fi 588 } 589 590 # Set tdir to tmp dir for make_so(): 591 if [ "X$XDUMMY_TMPDIR" != "X" ]; then 592 tdir=$XDUMMY_TMPDIR 593 mkdir -p $tdir 594 else 595 tdir="/tmp" 596 fi 597 598 # Handle -install/-uninstall case: 599 SO=$0.so 600 if [ "X$install" != "X" -o "X$uninstall" != "X" ]; then 601 if [ -e "$SO" -o -h "$SO" ]; then 602 warn "$program: removing $SO" 603 fi 604 if [ -f "$SO" ]; then 605 mv $SO $SO.$$ 606 rm -f $SO.$$ 607 fi 608 rm -f $SO 609 if [ -e "$SO" -o -h "$SO" ]; then 610 warn "warning: $SO still exists." 611 exit 1 612 fi 613 if [ $install ]; then 614 make_so 615 if [ ! -f "$SO" ]; then 616 exit 1 617 fi 618 fi 619 exit 0 620 fi 621 622 # We need a tmp directory for the .so, tweaked config file, and for 623 # redirecting filenames we cannot create (under -nonroot) 624 # 625 tack="" 626 if [ "X$XDUMMY_TMPDIR" = "X" ]; then 627 XDUMMY_TMPDIR="/tmp/Xdummy.$user" 628 629 # try to tack on a unique subdir (display number or pid) 630 # to allow multiple instances 631 # 632 if [ "X$disp" != "X" ]; then 633 t0=$disp 634 else 635 t0=$1 636 fi 637 tack=`echo "$t0" | sed -e 's/^.*://'` 638 if echo "$tack" | grep '^[0-9][0-9]*$' > /dev/null; then 639 : 640 else 641 tack=$$ 642 fi 643 if [ "X$tack" != "X" ]; then 644 XDUMMY_TMPDIR="$XDUMMY_TMPDIR/$tack" 645 fi 646 fi 647 648 tmp=$XDUMMY_TMPDIR 649 if echo "$tmp" | grep '^/tmp' > /dev/null; then 650 if [ "X$tmp" != "X/tmp" -a "X$tmp" != "X/tmp/" ]; then 651 # clean this subdir of /tmp out, otherwise leave it... 652 rm -rf $XDUMMY_TMPDIR 653 if [ -e $XDUMMY_TMPDIR ]; then 654 warn "$XDUMMY_TMPDIR still exists" 655 exit 1 656 fi 657 fi 658 fi 659 660 mkdir -p $XDUMMY_TMPDIR 661 chmod 700 $XDUMMY_TMPDIR 662 if [ "X$tack" != "X" ]; then 663 chmod 700 `dirname "$XDUMMY_TMPDIR"` 2>/dev/null 664 fi 665 666 # See if we can write something there: 667 # 668 tfile="$XDUMMY_TMPDIR/test.file" 669 touch $tfile 670 if [ ! -f "$tfile" ]; then 671 XDUMMY_TMPDIR="/tmp/Xdummy.$$.$USER" 672 warn "warning: setting tmpdir to $XDUMMY_TMPDIR ..." 673 rm -rf $XDUMMY_TMPDIR || exit 1 674 mkdir -p $XDUMMY_TMPDIR || exit 1 675 fi 676 rm -f $tfile 677 678 export XDUMMY_TMPDIR 679 680 # Compile the LD_PRELOAD shared object if needed (needs XDUMMY_TMPDIR) 681 # 682 if [ ! -f "$SO" ]; then 683 SO="$XDUMMY_TMPDIR/Xdummy.so" 684 make_so 685 fi 686 687 # Decide which X server to use: 688 # 689 if [ "X$xserver" = "X" ]; then 690 if type Xorg >/dev/null 2>&1; then 691 xserver="Xorg" 692 elif type XFree86 >/dev/null 2>&1; then 693 xserver="XFree86" 694 elif -x /usr/bin/Xorg; then 695 xserver="/usr/bin/Xorg" 696 elif -x /usr/X11R6/bin/Xorg; then 697 xserver="/usr/X11R6/bin/Xorg" 698 elif -x /usr/X11R6/bin/XFree86; then 699 xserver="/usr/X11R6/bin/XFree86" 700 fi 701 if [ "X$xserver" = "X" ]; then 702 # just let it fail below. 703 xserver="/usr/bin/Xorg" 704 warn "$program: cannot locate a stock Xserver... assuming $xserver" 705 fi 706 fi 707 708 # See if the binary is suid or not readable under -nonroot mode: 709 # 710 if [ "X$BASH_VERSION" != "X" ]; then 711 xserver_path=`type -p $xserver 2>/dev/null` 712 else 713 xserver_path=`type $xserver 2>/dev/null | awk '{print $NF}'` 714 fi 715 if [ -e "$xserver_path" -a "X$root" = "X" -a "X$runit" != "X" ]; then 716 if [ ! -r $xserver_path -o -u $xserver_path -o -g $xserver_path ]; then 717 # XXX not quite correct with rm -rf $XDUMMY_TMPDIR ... 718 # we keep on a filesystem we know root can write to. 719 base=`basename "$xserver_path"` 720 new="/tmp/$base.$user.bin" 721 if [ -e $new ]; then 722 snew=`ls -l $new | awk '{print $5}' | grep '^[0-9][0-9]*$'` 723 sold=`ls -l $xserver_path | awk '{print $5}' | grep '^[0-9][0-9]*$'` 724 if [ "X$snew" != "X" -a "X$sold" != "X" -a "X$sold" != "X$snew" ]; then 725 warn "removing different sized copy:" 726 ls -l $new $xserver_path 727 rm -f $new 728 fi 729 fi 730 if [ ! -e $new -o ! -s $new ]; then 731 rm -f $new 732 touch $new || exit 1 733 chmod 700 $new || exit 1 734 if [ ! -r $xserver_path ]; then 735 warn "" 736 warn "NEED TO COPY UNREADABLE $xserver_path to $new as root:" 737 warn "" 738 ls -l $xserver_path 1>&2 739 warn "" 740 warn "This only needs to be done once:" 741 warn " cat $xserver_path > $new" 742 warn "" 743 nos=$nosudo 744 if type sudo > /dev/null 2>&1; then 745 : 746 else 747 nos=1 748 fi 749 if [ "X$nos" = "X1" ]; then 750 warn "Please supply root passwd to 'su -c'" 751 su -c "cat $xserver_path > $new" 752 else 753 warn "Please supply the sudo passwd if asked:" 754 sudo /bin/sh -c "cat $xserver_path > $new" 755 fi 756 else 757 warn "" 758 warn "COPYING SETUID $xserver_path to $new" 759 warn "" 760 ls -l $xserver_path 1>&2 761 warn "" 762 cat $xserver_path > $new 763 fi 764 ls -l $new 765 if [ -s $new ]; then 766 : 767 else 768 rm -f $new 769 ls -l $new 770 exit 1 771 fi 772 warn "" 773 warn "Please restart Xdummy now." 774 exit 0 775 fi 776 if [ ! -O $new ]; then 777 warn "file \"$new\" not owned by us!" 778 ls -l $new 779 exit 1 780 fi 781 xserver=$new 782 fi 783 fi 784 785 # Work out display: 786 # 787 if [ "X$disp" != "X" ]; then 788 : 789 elif [ "X$1" != "X" ]; then 790 if echo "$1" | grep '^:[0-9]' > /dev/null; then 791 disp=$1 792 shift 793 elif [ "X$1" = "X:" ]; then 794 # ":" means for us to find one. 795 shift 796 fi 797 fi 798 if [ "X$disp" = "X" -o "X$disp" = "X:" ]; then 799 # try to find an open display port: 800 # (tcp outdated...) 801 ports=`netstat -ant | grep LISTEN | awk '{print $4}' | sed -e 's/^.*://'` 802 n=0 803 while [ $n -le 20 ] 804 do 805 port=`printf "60%02d" $n` 806 if echo "$ports" | grep "^${port}\$" > /dev/null; then 807 : 808 else 809 disp=":$n" 810 warn "$program: auto-selected DISPLAY $disp" 811 break 812 fi 813 n=`expr $n + 1` 814 done 815 fi 816 817 # Work out which vt to use, try to find/guess an open one if necessary. 818 # 819 vt="" 820 for arg in $* 821 do 822 if echo "$arg" | grep '^vt' > /dev/null; then 823 vt=$arg 824 break 825 fi 826 done 827 if [ "X$vt" = "X" ]; then 828 if [ "X$user" = "Xroot" ]; then 829 # root can user fuser(1) to see if it is in use: 830 if type fuser >/dev/null 2>&1; then 831 # try /dev/tty17 thru /dev/tty32 832 n=17 833 while [ $n -le 32 ] 834 do 835 dev="/dev/tty$n" 836 if fuser $dev >/dev/null 2>&1; then 837 : 838 else 839 vt="vt$n" 840 warn "$program: auto-selected VT $vt => $dev" 841 break 842 fi 843 n=`expr $n + 1` 844 done 845 fi 846 fi 847 if [ "X$vt" = "X" ]; then 848 # take a wild guess... 849 vt=vt16 850 warn "$program: selected fallback VT $vt" 851 fi 852 else 853 vt="" 854 fi 855 856 # Decide flavor of Xserver: 857 # 858 stype=`basename "$xserver"` 859 if echo "$stype" | grep -i xfree86 > /dev/null; then 860 stype=xfree86 861 else 862 stype=xorg 863 fi 864 865 tweak_config() { 866 in="$1" 867 config2="$XDUMMY_TMPDIR/xdummy_modified_xconfig.conf" 868 if [ "X$disp" != "X" ]; then 869 d=`echo "$disp" | sed -e 's,/,,g' -e 's/:/_/g'` 870 config2="$config2$d" 871 fi 872 873 # perl script to tweak the config file... add/delete options, etc. 874 # 875 env XDUMMY_GEOM=$geom \ 876 XDUMMY_DEPTH=$depth \ 877 XDUMMY_NOMODELINES=$nomodelines \ 878 perl > $config2 < $in -e ' 879 $n = 0; 880 $geom = $ENV{XDUMMY_GEOM}; 881 $depth = $ENV{XDUMMY_DEPTH}; 882 $nomodelines = $ENV{XDUMMY_NOMODELINES}; 883 $mode_str = ""; 884 $videoram = "24000"; 885 $HorizSync = "30.0 - 130.0"; 886 $VertRefresh = "50.0 - 250.0"; 887 if ($geom ne "") { 888 my $tmp = ""; 889 foreach $g (split(/,/, $geom)) { 890 $tmp .= "\"$g\" "; 891 if (!$nomodelines && $g =~ /(\d+)x(\d+)/) { 892 my $w = $1; 893 my $h = $2; 894 $mode_str .= " Modeline \"$g\" "; 895 my $dot = sprintf("%.2f", $w * $h * 70 * 1.e-6); 896 $mode_str .= $dot; 897 $mode_str .= " " . $w; 898 $mode_str .= " " . int(1.02 * $w); 899 $mode_str .= " " . int(1.10 * $w); 900 $mode_str .= " " . int(1.20 * $w); 901 $mode_str .= " " . $h; 902 $mode_str .= " " . int($h + 1); 903 $mode_str .= " " . int($h + 3); 904 $mode_str .= " " . int($h + 20); 905 $mode_str .= "\n"; 906 } 907 } 908 $tmp =~ s/\s*$//; 909 $geom = $tmp; 910 } 911 while (<>) { 912 if ($ENV{XDUMMY_NOTWEAK}) { 913 print $_; 914 next; 915 } 916 $n++; 917 if (/^\s*#/) { 918 # pass comments straight thru 919 print; 920 next; 921 } 922 if (/^\s*Section\s+(\S+)/i) { 923 # start of Section 924 $sect = $1; 925 $sect =~ s/\W//g; 926 $sect =~ y/A-Z/a-z/; 927 $sects{$sect} = 1; 928 print; 929 next; 930 } 931 if (/^\s*EndSection/i) { 932 # end of Section 933 if ($sect eq "serverflags") { 934 if (!$got_DontVTSwitch) { 935 print " ##Xdummy:##\n"; 936 print " Option \"DontVTSwitch\" \"true\"\n"; 937 } 938 if (!$got_AllowMouseOpenFail) { 939 print " ##Xdummy:##\n"; 940 print " Option \"AllowMouseOpenFail\" \"true\"\n"; 941 } 942 if (!$got_PciForceNone) { 943 print " ##Xdummy:##\n"; 944 print " Option \"PciForceNone\" \"true\"\n"; 945 } 946 } elsif ($sect eq "device") { 947 if (!$got_Driver) { 948 print " ##Xdummy:##\n"; 949 print " Driver \"dummy\"\n"; 950 } 951 if (!$got_VideoRam) { 952 print " ##Xdummy:##\n"; 953 print " VideoRam $videoram\n"; 954 } 955 } elsif ($sect eq "screen") { 956 if ($depth ne "" && !got_DefaultDepth) { 957 print " ##Xdummy:##\n"; 958 print " DefaultDepth $depth\n"; 959 } 960 if ($got_Monitor eq "") { 961 print " ##Xdummy:##\n"; 962 print " Monitor \"Monitor0\"\n"; 963 } 964 } elsif ($sect eq "monitor") { 965 if (!got_HorizSync) { 966 print " ##Xdummy:##\n"; 967 print " HorizSync $HorizSync\n"; 968 } 969 if (!got_VertRefresh) { 970 print " ##Xdummy:##\n"; 971 print " VertRefresh $VertRefresh\n"; 972 } 973 if (!$nomodelines) { 974 print " ##Xdummy:##\n"; 975 print $mode_str; 976 } 977 } 978 $sect = ""; 979 print; 980 next; 981 } 982 983 if (/^\s*SubSection\s+(\S+)/i) { 984 # start of Section 985 $subsect = $1; 986 $subsect =~ s/\W//g; 987 $subsect =~ y/A-Z/a-z/; 988 $subsects{$subsect} = 1; 989 if ($sect eq "screen" && $subsect eq "display") { 990 $got_Modes = 0; 991 } 992 print; 993 next; 994 } 995 if (/^\s*EndSubSection/i) { 996 # end of SubSection 997 if ($sect eq "screen") { 998 if ($subsect eq "display") { 999 if ($depth ne "" && !$set_Depth) { 1000 print " ##Xdummy:##\n"; 1001 print " Depth\t$depth\n"; 1002 } 1003 if ($geom ne "" && ! $got_Modes) { 1004 print " ##Xdummy:##\n"; 1005 print " Modes\t$geom\n"; 1006 } 1007 } 1008 } 1009 $subsect = ""; 1010 print; 1011 next; 1012 } 1013 1014 $l = $_; 1015 $l =~ s/#.*$//; 1016 if ($sect eq "serverflags") { 1017 if ($l =~ /^\s*Option.*DontVTSwitch/i) { 1018 $_ =~ s/false/true/ig; 1019 $got_DontVTSwitch = 1; 1020 } 1021 if ($l =~ /^\s*Option.*AllowMouseOpenFail/i) { 1022 $_ =~ s/false/true/ig; 1023 $got_AllowMouseOpenFail = 1; 1024 } 1025 if ($l =~ /^\s*Option.*PciForceNone/i) { 1026 $_ =~ s/false/true/ig; 1027 $got_PciForceNone= 1; 1028 } 1029 } 1030 if ($sect eq "module") { 1031 if ($l =~ /^\s*Load.*\b(dri|fbdevhw)\b/i) { 1032 $_ = "##Xdummy## $_"; 1033 } 1034 } 1035 if ($sect eq "monitor") { 1036 if ($l =~ /^\s*HorizSync/i) { 1037 $got_HorizSync = 1; 1038 } 1039 if ($l =~ /^\s*VertRefresh/i) { 1040 $got_VertRefresh = 1; 1041 } 1042 } 1043 if ($sect eq "device") { 1044 if ($l =~ /^(\s*Driver)\b/i) { 1045 $_ = "$1 \"dummy\"\n"; 1046 $got_Driver = 1; 1047 } 1048 if ($l =~ /^\s*VideoRam/i) { 1049 $got_VideoRam= 1; 1050 } 1051 } 1052 if ($sect eq "inputdevice") { 1053 if ($l =~ /^\s*Option.*\bDevice\b/i) { 1054 print " ##Xdummy:##\n"; 1055 $_ = " Option \"Device\" \"/dev/dilbert$n\"\n"; 1056 } 1057 } 1058 if ($sect eq "screen") { 1059 if ($l =~ /^\s*DefaultDepth\s+(\d+)/i) { 1060 if ($depth ne "") { 1061 print " ##Xdummy:##\n"; 1062 $_ = " DefaultDepth\t$depth\n"; 1063 } 1064 $got_DefaultDepth = 1; 1065 } 1066 if ($l =~ /^\s*Monitor\s+(\S+)/i) { 1067 $got_Monitor = $1; 1068 $got_Monitor =~ s/"//g; 1069 } 1070 if ($subsect eq "display") { 1071 if ($geom ne "") { 1072 if ($l =~ /^(\s*Modes)\b/i) { 1073 print " ##Xdummy:##\n"; 1074 $_ = "$1 $geom\n"; 1075 $got_Modes = 1; 1076 } 1077 } 1078 if ($l =~ /^\s*Depth\s+(\d+)/i) { 1079 my $d = $1; 1080 if (!$set_Depth && $depth ne "") { 1081 $set_Depth = 1; 1082 if ($depth != $d) { 1083 print " ##Xdummy:##\n"; 1084 $_ = " Depth\t$depth\n"; 1085 } 1086 } 1087 } 1088 } 1089 } 1090 print; 1091 } 1092 if ($ENV{XDUMMY_NOTWEAK}) { 1093 exit; 1094 } 1095 # create any crucial sections that are missing: 1096 if (! exists($sects{serverflags})) { 1097 print "\n##Xdummy:##\n"; 1098 print "Section \"ServerFlags\"\n"; 1099 print " Option \"DontVTSwitch\" \"true\"\n"; 1100 print " Option \"AllowMouseOpenFail\" \"true\"\n"; 1101 print " Option \"PciForceNone\" \"true\"\n"; 1102 print "EndSection\n"; 1103 } 1104 if (! exists($sects{device})) { 1105 print "\n##Xdummy:##\n"; 1106 print "Section \"Device\"\n"; 1107 print " Identifier \"Videocard0\"\n"; 1108 print " Driver \"dummy\"\n"; 1109 print " VideoRam $videoram\n"; 1110 print "EndSection\n"; 1111 } 1112 if (! exists($sects{monitor})) { 1113 print "\n##Xdummy:##\n"; 1114 print "Section \"Monitor\"\n"; 1115 print " Identifier \"Monitor0\"\n"; 1116 print " HorizSync $HorizSync\n"; 1117 print " VertRefresh $VertRefresh\n"; 1118 print "EndSection\n"; 1119 } 1120 if (! exists($sects{screen})) { 1121 print "\n##Xdummy:##\n"; 1122 print "Section \"Screen\"\n"; 1123 print " Identifier \"Screen0\"\n"; 1124 print " Device \"Videocard0\"\n"; 1125 if ($got_Monitor ne "") { 1126 print " Monitor \"$got_Monitor\"\n"; 1127 } else { 1128 print " Monitor \"Monitor0\"\n"; 1129 } 1130 if ($depth ne "") { 1131 print " DefaultDepth $depth\n"; 1132 } else { 1133 print " DefaultDepth 24\n"; 1134 } 1135 print " SubSection \"Display\"\n"; 1136 print " Viewport 0 0\n"; 1137 print " Depth 24\n"; 1138 if ($got_Modes) { 1139 ; 1140 } elsif ($geom ne "") { 1141 print " Modes $geom\n"; 1142 } else { 1143 print " Modes \"1280x1024\" \"1024x768\" \"800x600\"\n"; 1144 } 1145 print " EndSubSection\n"; 1146 print "EndSection\n"; 1147 } 1148 '; 1149 } 1150 1151 # Work out config file and tweak it. 1152 # 1153 if [ "X$cmdline_config" = "X" ]; then 1154 : 1155 elif [ "X$cmdline_config" = "Xxdummy-builtin" ]; then 1156 : 1157 elif echo "$cmdline_config" | grep '/' > /dev/null; then 1158 : 1159 else 1160 # ignore basename only case (let server handle it) 1161 cmdline_config="" 1162 notweak=1 1163 fi 1164 1165 config=$cmdline_config 1166 1167 if [ "X$notweak" = "X1" -a "X$root" = "X" -a -f "$cmdline_config" ]; then 1168 # if not root we need to copy (but not tweak) the specified config. 1169 XDUMMY_NOTWEAK=1 1170 export XDUMMY_NOTWEAK 1171 notweak="" 1172 fi 1173 1174 if [ ! $notweak ]; then 1175 # tweaked config will be put in $config2: 1176 config2="" 1177 if [ "X$config" = "X" ]; then 1178 # use the default one: 1179 if [ "X$stype" = "Xxorg" ]; then 1180 config=/etc/X11/xorg.conf 1181 else 1182 if [ -f "/etc/X11/XF86Config-4" ]; then 1183 config="/etc/X11/XF86Config-4" 1184 else 1185 config="/etc/X11/XF86Config" 1186 fi 1187 fi 1188 if [ ! -f "$config" ]; then 1189 for c in /etc/X11/xorg.conf /etc/X11/XF86Config-4 /etc/X11/XF86Config 1190 do 1191 if [ -f $c ]; then 1192 config=$c 1193 break 1194 fi 1195 done 1196 fi 1197 fi 1198 1199 if [ "X$config" = "Xxdummy-builtin" ]; then 1200 config="" 1201 fi 1202 1203 if [ ! -f "$config" ]; then 1204 config="$XDUMMY_TMPDIR/xorg.conf" 1205 warn "$program: using minimal built-in xorg.conf settings." 1206 cat > $config <<END 1207 1208 Section "ServerLayout" 1209 Identifier "Layout0" 1210 Screen 0 "Screen0" 1211 InputDevice "Keyboard0" "CoreKeyboard" 1212 InputDevice "Mouse0" "CorePointer" 1213 EndSection 1214 1215 Section "Files" 1216 EndSection 1217 1218 Section "Module" 1219 Load "dbe" 1220 Load "extmod" 1221 Load "freetype" 1222 Load "glx" 1223 EndSection 1224 1225 Section "InputDevice" 1226 Identifier "Mouse0" 1227 Driver "mouse" 1228 Option "Protocol" "auto" 1229 Option "Device" "/dev/psaux" 1230 Option "Emulate3Buttons" "no" 1231 Option "ZAxisMapping" "4 5" 1232 EndSection 1233 1234 Section "InputDevice" 1235 Identifier "Keyboard0" 1236 Driver "kbd" 1237 EndSection 1238 1239 Section "Monitor" 1240 Identifier "Monitor0" 1241 VendorName "Unknown" 1242 ModelName "Unknown" 1243 HorizSync 30.0 - 130.0 1244 VertRefresh 50.0 - 250.0 1245 Option "DPMS" 1246 EndSection 1247 1248 Section "Device" 1249 Identifier "Device0" 1250 Driver "foovideo" 1251 VendorName "foovideo Corporation" 1252 EndSection 1253 1254 Section "Screen" 1255 Identifier "Screen0" 1256 Device "Device0" 1257 Monitor "Monitor0" 1258 DefaultDepth 24 1259 SubSection "Display" 1260 Depth 24 1261 Modes "1280x1024" 1262 EndSubSection 1263 EndSection 1264 1265 END 1266 fi 1267 1268 if [ -f "$config" ]; then 1269 tweak_config $config 1270 fi 1271 1272 # now we need to get our tweaked config file onto the command line: 1273 if [ "X$cmdline_config" = "X" ]; then 1274 # append to cmdline (FUBAR will be substituted below.) 1275 if [ "X$stype" = "Xxorg" ]; then 1276 args="$args -config FUBAR" 1277 else 1278 args="$args -xf86config FUBAR" 1279 fi 1280 fi 1281 if [ "X$config2" != "X" ]; then 1282 # or modify $args: 1283 c2=$config2 1284 if [ "X$root" = "X" ]; then 1285 # ordinary user cannot use absolute path. 1286 c2=`basename $config2` 1287 fi 1288 args=`echo "$args" | sed \ 1289 -e "s,-config *[^ ][^ ]*,-config $c2,g" \ 1290 -e "s,-xf86config *[^ ][^ ]*,-xf86config $c2,g"` 1291 fi 1292 fi 1293 1294 if [ $prconf ]; then 1295 warn "" 1296 warn "Printing out the Xorg/XFree86 server config file:" 1297 warn "" 1298 if [ "X$config2" = "X" ]; then 1299 warn "NO CONFIG GENERATED." 1300 exit 1 1301 else 1302 cat "$config2" 1303 fi 1304 exit 0 1305 fi 1306 1307 if [ $debug ]; then 1308 XDUMMY_DEBUG=1 1309 export XDUMMY_DEBUG 1310 fi 1311 if [ $root ]; then 1312 XDUMMY_ROOT=1 1313 export XDUMMY_ROOT 1314 fi 1315 1316 # Finally, run it: 1317 # 1318 if [ "X$debug" != "X" -o "X$runit" = "X" ]; then 1319 if [ ! $runit ]; then 1320 echo "" 1321 echo "/usr/bin/env:" 1322 env | egrep -v '^(LS_COLORS|TERMCAP)' | sort 1323 echo "" 1324 echo "XDUMMY*:" 1325 env | grep '^XDUMMY' | sort 1326 echo "" 1327 fi 1328 warn "" 1329 warn "The command to run is:" 1330 warn "" 1331 so=$SO 1332 pwd=`pwd` 1333 if echo "$so" | grep '^\./' > /dev/null; then 1334 so=`echo "$so" | sed -e "s,^\.,$pwd,"` 1335 fi 1336 if echo "$so" | grep '/' > /dev/null; then 1337 : 1338 else 1339 so="$pwd/$so" 1340 fi 1341 warn "env LD_PRELOAD=$so $xserver $disp $args $vt" 1342 warn "" 1343 if [ ! $runit ]; then 1344 exit 0 1345 fi 1346 fi 1347 1348 if [ $strace ]; then 1349 if [ "X$strace" = "X2" ]; then 1350 ltrace -f env LD_PRELOAD=$SO $xserver $disp $args $vt 1351 else 1352 strace -f env LD_PRELOAD=$SO $xserver $disp $args $vt 1353 fi 1354 else 1355 exec env LD_PRELOAD=$SO $xserver $disp $args $vt 1356 fi 1357 1358 exit $? 1359 1360 ######################################################################### 1361 1362 code() { 1363 #code_begin 1364 #include <stdio.h> 1365 #define O_ACCMODE 0003 1366 #define O_RDONLY 00 1367 #define O_WRONLY 01 1368 #define O_RDWR 02 1369 #define O_CREAT 0100 /* not fcntl */ 1370 #define O_EXCL 0200 /* not fcntl */ 1371 #define O_NOCTTY 0400 /* not fcntl */ 1372 #define O_TRUNC 01000 /* not fcntl */ 1373 #define O_APPEND 02000 1374 #define O_NONBLOCK 04000 1375 #define O_NDELAY O_NONBLOCK 1376 #define O_SYNC 010000 1377 #define O_FSYNC O_SYNC 1378 #define O_ASYNC 020000 1379 1380 #include <unistd.h> 1381 #include <stdlib.h> 1382 #include <string.h> 1383 1384 #include <linux/vt.h> 1385 #include <linux/kd.h> 1386 1387 #define __USE_GNU 1388 #include <dlfcn.h> 1389 1390 static char tmpdir[4096]; 1391 static char str1[4096]; 1392 static char str2[4096]; 1393 1394 static char devs[256][1024]; 1395 static int debug = -1; 1396 static int root = -1; 1397 static int changed_uid = 0; 1398 static int saw_fonts = 0; 1399 static int saw_lib_modules = 0; 1400 1401 static time_t start = 0; 1402 1403 void check_debug(void) { 1404 if (debug < 0) { 1405 if (getenv("XDUMMY_DEBUG") != NULL) { 1406 debug = 1; 1407 } else { 1408 debug = 0; 1409 } 1410 /* prevent other processes using the preload: */ 1411 putenv("LD_PRELOAD="); 1412 } 1413 } 1414 void check_root(void) { 1415 if (root < 0) { 1416 /* script tells us if we are root */ 1417 if (getenv("XDUMMY_ROOT") != NULL) { 1418 root = 1; 1419 } else { 1420 root = 0; 1421 } 1422 } 1423 } 1424 1425 void check_uid(void) { 1426 if (start == 0) { 1427 start = time(NULL); 1428 if (debug) fprintf(stderr, "START: %u\n", (unsigned int) start); 1429 return; 1430 } else if (changed_uid == 0) { 1431 if (saw_fonts || time(NULL) > start + 20) { 1432 if (getenv("XDUMMY_UID")) { 1433 int uid = atoi(getenv("XDUMMY_UID")); 1434 if (debug) fprintf(stderr, "SETREUID: %d saw_fonts=%d\n", uid, saw_fonts); 1435 if (uid >= 0) { 1436 /* this will simply fail in -nonroot mode: */ 1437 setreuid(uid, -1); 1438 } 1439 } 1440 changed_uid = 1; 1441 } 1442 } 1443 } 1444 1445 #define CHECKIT if (debug < 0) check_debug(); \ 1446 if (root < 0) check_root(); \ 1447 check_uid(); 1448 1449 static void set_tmpdir(void) { 1450 char *s; 1451 static int didset = 0; 1452 if (didset) { 1453 return; 1454 } 1455 s = getenv("XDUMMY_TMPDIR"); 1456 if (! s) { 1457 s = "/tmp"; 1458 } 1459 tmpdir[0] = '\0'; 1460 strcat(tmpdir, s); 1461 strcat(tmpdir, "/"); 1462 didset = 1; 1463 } 1464 1465 static char *tmpdir_path(const char *path) { 1466 char *str; 1467 set_tmpdir(); 1468 strcpy(str2, path); 1469 str = str2; 1470 while (*str) { 1471 if (*str == '/') { 1472 *str = '_'; 1473 } 1474 str++; 1475 } 1476 strcpy(str1, tmpdir); 1477 strcat(str1, str2); 1478 return str1; 1479 } 1480 1481 int open(const char *pathname, int flags, unsigned short mode) { 1482 int fd; 1483 char *store_dev = NULL; 1484 static int (*real_open)(const char *, int , unsigned short) = NULL; 1485 1486 CHECKIT 1487 if (! real_open) { 1488 real_open = (int (*)(const char *, int , unsigned short)) 1489 dlsym(RTLD_NEXT, "open"); 1490 } 1491 1492 if (strstr(pathname, "lib/modules/")) { 1493 /* not currently used. */ 1494 saw_lib_modules = 1; 1495 } 1496 1497 if (!root) { 1498 if (strstr(pathname, "/dev/") == pathname) { 1499 store_dev = strdup(pathname); 1500 } 1501 if (strstr(pathname, "/dev/tty") == pathname && strcmp(pathname, "/dev/tty")) { 1502 pathname = tmpdir_path(pathname); 1503 if (debug) fprintf(stderr, "OPEN: %s -> %s (as FIFO)\n", store_dev, pathname); 1504 /* we make it a FIFO so ioctl on it does not fail */ 1505 unlink(pathname); 1506 mkfifo(pathname, 0666); 1507 } else if (0) { 1508 /* we used to handle more /dev files ... */ 1509 fd = real_open(pathname, O_WRONLY|O_CREAT, 0777); 1510 close(fd); 1511 } 1512 } 1513 1514 fd = real_open(pathname, flags, mode); 1515 1516 if (debug) fprintf(stderr, "OPEN: %s %d %d fd=%d\n", pathname, flags, mode, fd); 1517 1518 if (! root) { 1519 if (store_dev) { 1520 if (fd < 256) { 1521 strcpy(devs[fd], store_dev); 1522 } 1523 free(store_dev); 1524 } 1525 } 1526 1527 return(fd); 1528 } 1529 1530 int open64(const char *pathname, int flags, unsigned short mode) { 1531 int fd; 1532 1533 CHECKIT 1534 if (debug) fprintf(stderr, "OPEN64: %s %d %d\n", pathname, flags, mode); 1535 1536 fd = open(pathname, flags, mode); 1537 return(fd); 1538 } 1539 1540 int rename(const char *oldpath, const char *newpath) { 1541 static int (*real_rename)(const char *, const char *) = NULL; 1542 1543 CHECKIT 1544 if (! real_rename) { 1545 real_rename = (int (*)(const char *, const char *)) 1546 dlsym(RTLD_NEXT, "rename"); 1547 } 1548 1549 if (debug) fprintf(stderr, "RENAME: %s %s\n", oldpath, newpath); 1550 1551 if (root) { 1552 return(real_rename(oldpath, newpath)); 1553 } 1554 1555 if (strstr(oldpath, "/var/log") == oldpath) { 1556 if (debug) fprintf(stderr, "RENAME: returning 0\n"); 1557 return 0; 1558 } 1559 return(real_rename(oldpath, newpath)); 1560 } 1561 1562 FILE *fopen(const char *pathname, const char *mode) { 1563 static FILE* (*real_fopen)(const char *, const char *) = NULL; 1564 char *str; 1565 1566 if (! saw_fonts) { 1567 if (strstr(pathname, "/fonts/")) { 1568 if (strstr(pathname, "fonts.dir")) { 1569 saw_fonts = 1; 1570 } else if (strstr(pathname, "fonts.alias")) { 1571 saw_fonts = 1; 1572 } 1573 } 1574 } 1575 1576 CHECKIT 1577 if (! real_fopen) { 1578 real_fopen = (FILE* (*)(const char *, const char *)) 1579 dlsym(RTLD_NEXT, "fopen"); 1580 } 1581 1582 if (debug) fprintf(stderr, "FOPEN: %s %s\n", pathname, mode); 1583 1584 if (strstr(pathname, "xdummy_modified_xconfig.conf")) { 1585 /* make our config appear to be in /etc/X11, etc. */ 1586 char *q = strrchr(pathname, '/'); 1587 if (q != NULL && getenv("XDUMMY_TMPDIR") != NULL) { 1588 strcpy(str1, getenv("XDUMMY_TMPDIR")); 1589 strcat(str1, q); 1590 if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str1); 1591 pathname = str1; 1592 } 1593 } 1594 1595 if (root) { 1596 return(real_fopen(pathname, mode)); 1597 } 1598 1599 str = (char *) pathname; 1600 if (strstr(pathname, "/var/log") == pathname) { 1601 str = tmpdir_path(pathname); 1602 if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str); 1603 } 1604 return(real_fopen(str, mode)); 1605 } 1606 1607 1608 #define RETURN0 if (debug) \ 1609 {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return 0; 1610 #define RETURN1 if (debug) \ 1611 {fprintf(stderr, "IOCTL: covered %d 0x%x\n", fd, req);} return -1; 1612 1613 int ioctl(int fd, int req, void *ptr) { 1614 static int closed_xf86Info_consoleFd = 0; 1615 static int (*real_ioctl)(int, int , void *) = NULL; 1616 1617 CHECKIT 1618 if (! real_ioctl) { 1619 real_ioctl = (int (*)(int, int , void *)) 1620 dlsym(RTLD_NEXT, "open"); 1621 } 1622 if (debug) fprintf(stderr, "IOCTL: %d 0x%x %p\n", fd, req, ptr); 1623 1624 /* based on xorg-x11-6.8.1-dualhead.patch */ 1625 if (req == VT_GETMODE) { 1626 /* close(xf86Info.consoleFd) */ 1627 if (0 && ! closed_xf86Info_consoleFd) { 1628 /* I think better not to close it... */ 1629 close(fd); 1630 closed_xf86Info_consoleFd = 1; 1631 } 1632 RETURN0 1633 } else if (req == VT_SETMODE) { 1634 RETURN0 1635 } else if (req == VT_GETSTATE) { 1636 RETURN0 1637 } else if (req == KDSETMODE) { 1638 RETURN0 1639 } else if (req == KDSETLED) { 1640 RETURN0 1641 } else if (req == KDGKBMODE) { 1642 RETURN0 1643 } else if (req == KDSKBMODE) { 1644 RETURN0 1645 } else if (req == VT_ACTIVATE) { 1646 RETURN0 1647 } else if (req == VT_WAITACTIVE) { 1648 RETURN0 1649 } else if (req == VT_RELDISP) { 1650 if (ptr == (void *) 1) { 1651 RETURN1 1652 } else if (ptr == (void *) VT_ACKACQ) { 1653 RETURN0 1654 } 1655 } 1656 1657 return(real_ioctl(fd, req, ptr)); 1658 } 1659 1660 typedef void (*sighandler_t)(int); 1661 #define SIGUSR1 10 1662 #define SIG_DFL ((sighandler_t)0) 1663 1664 sighandler_t signal(int signum, sighandler_t handler) { 1665 static sighandler_t (*real_signal)(int, sighandler_t) = NULL; 1666 1667 CHECKIT 1668 if (! real_signal) { 1669 real_signal = (sighandler_t (*)(int, sighandler_t)) 1670 dlsym(RTLD_NEXT, "signal"); 1671 } 1672 1673 if (debug) fprintf(stderr, "SIGNAL: %d %p\n", signum, handler); 1674 1675 if (signum == SIGUSR1) { 1676 if (debug) fprintf(stderr, "SIGNAL: skip SIGUSR1\n"); 1677 return SIG_DFL; 1678 } 1679 1680 return(real_signal(signum, handler)); 1681 } 1682 1683 int close(int fd) { 1684 static int (*real_close)(int) = NULL; 1685 1686 CHECKIT 1687 if (! real_close) { 1688 real_close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); 1689 } 1690 1691 if (debug) fprintf(stderr, "CLOSE: %d\n", fd); 1692 if (!root) { 1693 if (fd < 256) { 1694 devs[fd][0] = '\0'; 1695 } 1696 } 1697 return(real_close(fd)); 1698 } 1699 1700 struct stat { 1701 int foo; 1702 }; 1703 1704 int stat(const char *path, struct stat *buf) { 1705 static int (*real_stat)(const char *, struct stat *) = NULL; 1706 1707 CHECKIT 1708 if (! real_stat) { 1709 real_stat = (int (*)(const char *, struct stat *)) 1710 dlsym(RTLD_NEXT, "stat"); 1711 } 1712 1713 if (debug) fprintf(stderr, "STAT: %s\n", path); 1714 1715 return(real_stat(path, buf)); 1716 } 1717 1718 int stat64(const char *path, struct stat *buf) { 1719 static int (*real_stat64)(const char *, struct stat *) = NULL; 1720 1721 CHECKIT 1722 if (! real_stat64) { 1723 real_stat64 = (int (*)(const char *, struct stat *)) 1724 dlsym(RTLD_NEXT, "stat64"); 1725 } 1726 1727 if (debug) fprintf(stderr, "STAT64: %s\n", path); 1728 1729 return(real_stat64(path, buf)); 1730 } 1731 1732 int chown(const char *path, uid_t owner, gid_t group) { 1733 static int (*real_chown)(const char *, uid_t, gid_t) = NULL; 1734 1735 CHECKIT 1736 if (! real_chown) { 1737 real_chown = (int (*)(const char *, uid_t, gid_t)) 1738 dlsym(RTLD_NEXT, "chown"); 1739 } 1740 1741 if (root) { 1742 return(real_chown(path, owner, group)); 1743 } 1744 1745 if (debug) fprintf(stderr, "CHOWN: %s %d %d\n", path, owner, group); 1746 1747 if (strstr(path, "/dev") == path) { 1748 if (debug) fprintf(stderr, "CHOWN: return 0\n"); 1749 return 0; 1750 } 1751 1752 return(real_chown(path, owner, group)); 1753 } 1754 1755 extern int *__errno_location (void); 1756 #ifndef ENODEV 1757 #define ENODEV 19 1758 #endif 1759 1760 int ioperm(unsigned long from, unsigned long num, int turn_on) { 1761 static int (*real_ioperm)(unsigned long, unsigned long, int) = NULL; 1762 1763 CHECKIT 1764 if (! real_ioperm) { 1765 real_ioperm = (int (*)(unsigned long, unsigned long, int)) 1766 dlsym(RTLD_NEXT, "ioperm"); 1767 } 1768 if (debug) fprintf(stderr, "IOPERM: %d %d %d\n", (int) from, (int) num, turn_on); 1769 if (root) { 1770 return(real_ioperm(from, num, turn_on)); 1771 } 1772 if (from == 0 && num == 1024 && turn_on == 1) { 1773 /* we want xf86EnableIO to fail */ 1774 if (debug) fprintf(stderr, "IOPERM: setting ENODEV.\n"); 1775 *__errno_location() = ENODEV; 1776 return -1; 1777 } 1778 return 0; 1779 } 1780 1781 int iopl(int level) { 1782 static int (*real_iopl)(int) = NULL; 1783 1784 CHECKIT 1785 if (! real_iopl) { 1786 real_iopl = (int (*)(int)) dlsym(RTLD_NEXT, "iopl"); 1787 } 1788 if (debug) fprintf(stderr, "IOPL: %d\n", level); 1789 if (root) { 1790 return(real_iopl(level)); 1791 } 1792 return 0; 1793 } 1794 1795 #ifdef INTERPOSE_GETUID 1796 1797 /* 1798 * we got things to work w/o pretending to be root. 1799 * so we no longer interpose getuid(), etc. 1800 */ 1801 1802 uid_t getuid(void) { 1803 static uid_t (*real_getuid)(void) = NULL; 1804 CHECKIT 1805 if (! real_getuid) { 1806 real_getuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid"); 1807 } 1808 if (root) { 1809 return(real_getuid()); 1810 } 1811 if (debug) fprintf(stderr, "GETUID: 0\n"); 1812 return 0; 1813 } 1814 uid_t geteuid(void) { 1815 static uid_t (*real_geteuid)(void) = NULL; 1816 CHECKIT 1817 if (! real_geteuid) { 1818 real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid"); 1819 } 1820 if (root) { 1821 return(real_geteuid()); 1822 } 1823 if (debug) fprintf(stderr, "GETEUID: 0\n"); 1824 return 0; 1825 } 1826 uid_t geteuid_kludge1(void) { 1827 static uid_t (*real_geteuid)(void) = NULL; 1828 CHECKIT 1829 if (! real_geteuid) { 1830 real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid"); 1831 } 1832 if (debug) fprintf(stderr, "GETEUID: 0 saw_libmodules=%d\n", saw_lib_modules); 1833 if (root && !saw_lib_modules) { 1834 return(real_geteuid()); 1835 } else { 1836 saw_lib_modules = 0; 1837 return 0; 1838 } 1839 } 1840 1841 uid_t getuid32(void) { 1842 static uid_t (*real_getuid32)(void) = NULL; 1843 CHECKIT 1844 if (! real_getuid32) { 1845 real_getuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "getuid32"); 1846 } 1847 if (root) { 1848 return(real_getuid32()); 1849 } 1850 if (debug) fprintf(stderr, "GETUID32: 0\n"); 1851 return 0; 1852 } 1853 uid_t geteuid32(void) { 1854 static uid_t (*real_geteuid32)(void) = NULL; 1855 CHECKIT 1856 if (! real_geteuid32) { 1857 real_geteuid32 = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid32"); 1858 } 1859 if (root) { 1860 return(real_geteuid32()); 1861 } 1862 if (debug) fprintf(stderr, "GETEUID32: 0\n"); 1863 return 0; 1864 } 1865 1866 gid_t getgid(void) { 1867 static gid_t (*real_getgid)(void) = NULL; 1868 CHECKIT 1869 if (! real_getgid) { 1870 real_getgid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid"); 1871 } 1872 if (root) { 1873 return(real_getgid()); 1874 } 1875 if (debug) fprintf(stderr, "GETGID: 0\n"); 1876 return 0; 1877 } 1878 gid_t getegid(void) { 1879 static gid_t (*real_getegid)(void) = NULL; 1880 CHECKIT 1881 if (! real_getegid) { 1882 real_getegid = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid"); 1883 } 1884 if (root) { 1885 return(real_getegid()); 1886 } 1887 if (debug) fprintf(stderr, "GETEGID: 0\n"); 1888 return 0; 1889 } 1890 gid_t getgid32(void) { 1891 static gid_t (*real_getgid32)(void) = NULL; 1892 CHECKIT 1893 if (! real_getgid32) { 1894 real_getgid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getgid32"); 1895 } 1896 if (root) { 1897 return(real_getgid32()); 1898 } 1899 if (debug) fprintf(stderr, "GETGID32: 0\n"); 1900 return 0; 1901 } 1902 gid_t getegid32(void) { 1903 static gid_t (*real_getegid32)(void) = NULL; 1904 CHECKIT 1905 if (! real_getegid32) { 1906 real_getegid32 = (gid_t (*)(void)) dlsym(RTLD_NEXT, "getegid32"); 1907 } 1908 if (root) { 1909 return(real_getegid32()); 1910 } 1911 if (debug) fprintf(stderr, "GETEGID32: 0\n"); 1912 return 0; 1913 } 1914 #endif 1915 1916 #if 0 1917 /* maybe we need to interpose on strcmp someday... here is the template */ 1918 int strcmp(const char *s1, const char *s2) { 1919 static int (*real_strcmp)(const char *, const char *) = NULL; 1920 CHECKIT 1921 if (! real_strcmp) { 1922 real_strcmp = (int (*)(const char *, const char *)) dlsym(RTLD_NEXT, "strcmp"); 1923 } 1924 if (debug) fprintf(stderr, "STRCMP: '%s' '%s'\n", s1, s2); 1925 return(real_strcmp(s1, s2)); 1926 } 1927 #endif 1928 1929 #code_end 1930 } 1931