Advertisement
Guest User

vncserver

a guest
Feb 22nd, 2012
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 14.24 KB | None | 0 0
  1. #!/usr/bin/env perl
  2. #
  3. #  Copyright (C) 2002-2005 RealVNC Ltd.
  4. #  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
  5. #
  6. #  This is free software; you can redistribute it and/or modify
  7. #  it under the terms of the GNU General Public License as published by
  8. #  the Free Software Foundation; either version 2 of the License, or
  9. #  (at your option) any later version.
  10. #
  11. #  This software is distributed in the hope that it will be useful,
  12. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #  GNU General Public License for more details.
  15. #
  16. #  You should have received a copy of the GNU General Public License
  17. #  along with this software; if not, write to the Free Software
  18. #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  19. #  USA.
  20. #
  21.  
  22. #
  23. # vncserver - wrapper script to start an X VNC server.
  24. #
  25.  
  26. #
  27. # First make sure we're operating in a sane environment.
  28. #
  29.  
  30. &SanityCheck();
  31.  
  32. #
  33. # Global variables.  You may want to configure some of these for your site.
  34. #
  35.  
  36. $geometry = "1024x768";
  37. $depth = 16;
  38. $vncJavaFiles = (((-d "/usr/share/vnc/classes") && "/usr/share/vnc/classes") ||
  39.                  ((-d "/usr/local/share/vnc/classes") && "/usr/local/share/vnc/classes"));
  40. $vncUserDir = "$ENV{HOME}/.vnc";
  41. $xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
  42.  
  43. $defaultXStartup
  44.     = ("#!/bin/sh\n\n".
  45.        "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n".
  46.        "xsetroot -solid grey\n".
  47.        "vncconfig -iconic &\n".
  48.        "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n".
  49.        "twm &\n");
  50.  
  51. chop($host = `uname -n`);
  52.  
  53.  
  54. # Check command line options
  55.  
  56. &ParseOptions("-geometry",1,"-depth",1,"-pixelformat",1,"-name",1,"-kill",1,
  57.           "-help",0,"-h",0,"--help",0);
  58.  
  59. &Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});
  60.  
  61. &Kill() if ($opt{'-kill'});
  62.  
  63. # Uncomment this line if you want default geometry, depth and pixelformat
  64. # to match the current X display:
  65. # &GetXDisplayDefaults();
  66.  
  67. if ($opt{'-geometry'}) {
  68.     $geometry = $opt{'-geometry'};
  69. }
  70. if ($opt{'-depth'}) {
  71.     $depth = $opt{'-depth'};
  72.     $pixelformat = "";
  73. }
  74. if ($opt{'-pixelformat'}) {
  75.     $pixelformat = $opt{'-pixelformat'};
  76. }
  77.  
  78. &CheckGeometryAndDepth();
  79.  
  80.  
  81. # Create the user's vnc directory if necessary.
  82.  
  83. if (!(-e $vncUserDir)) {
  84.     if (!mkdir($vncUserDir,0755)) {
  85.     die "$prog: Could not create $vncUserDir.\n";
  86.     }
  87. }
  88.    
  89. # Make sure the user has a password.
  90.  
  91. ($z,$z,$mode) = stat("$vncUserDir/passwd");
  92. if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
  93.     warn "\nYou will require a password to access your desktops.\n\n";
  94.     system("vncpasswd -q $vncUserDir/passwd");
  95.     if (($? >> 8) != 0) {
  96.     exit 1;
  97.     }
  98. }
  99.  
  100. # Find display number.
  101.  
  102. if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
  103.     $displayNumber = $1;
  104.     shift(@ARGV);
  105.     if (!&CheckDisplayNumber($displayNumber)) {
  106.     die "A VNC server is already running as :$displayNumber\n";
  107.     }
  108. } elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/)) {
  109.     &Usage();
  110. } else {
  111.     $displayNumber = &GetDisplayNumber();
  112. }
  113.  
  114. $vncPort = 5900 + $displayNumber;
  115.  
  116. $desktopLog = "$vncUserDir/$host:$displayNumber.log";
  117. unlink($desktopLog);
  118.  
  119. # Make an X server cookie - use as the seed the sum of the current time, our
  120. # PID and part of the encrypted form of the password.  Ideally we'd use
  121. # /dev/urandom, but that's only available on Linux.
  122.  
  123. srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
  124. $cookie = "";
  125. for (1..16) {
  126.     $cookie .= sprintf("%02x", int(rand(256)) % 256);
  127. }
  128.    
  129. system("xauth -f $xauthorityFile add $host:$displayNumber . $cookie");
  130. system("xauth -f $xauthorityFile add $host/unix:$displayNumber . $cookie");
  131.  
  132. if ($opt{'-name'}) {
  133.     $desktopName = $opt{'-name'};
  134. } else {
  135.     $desktopName = "$host:$displayNumber ($ENV{USER})";
  136. }
  137.  
  138. # Now start the X VNC Server
  139.  
  140. $cmd = "Xvnc :$displayNumber";
  141. $cmd .= " -desktop " . &quotedString($desktopName);
  142. $cmd .= " -httpd $vncJavaFiles" if ($vncJavaFiles);
  143. $cmd .= " -auth $xauthorityFile";
  144. $cmd .= " -geometry $geometry" if ($geometry);
  145. $cmd .= " -depth $depth" if ($depth);
  146. $cmd .= " -pixelformat $pixelformat" if ($pixelformat);
  147. $cmd .= " -rfbwait 30000";
  148. $cmd .= " -rfbauth $vncUserDir/passwd";
  149. $cmd .= " -rfbport $vncPort";
  150. $cmd .= " -pn";
  151.  
  152. # Add font path and color database stuff here, e.g.:
  153. #
  154. # $cmd .= " -fp /usr/lib/X11/fonts/misc/,/usr/lib/X11/fonts/75dpi/";
  155. # $cmd .= " -co /usr/lib/X11/rgb";
  156. #
  157. ##$cmd .= " -co /usr/X11R6/lib/X11/rgb";
  158. foreach $arg (@ARGV) {
  159.     $cmd .= " " . &quotedString($arg);
  160. }
  161. $cmd .= " >> " . &quotedString($desktopLog) . " 2>&1";
  162.  
  163. # Run $cmd and record the process ID.
  164.  
  165. $pidFile = "$vncUserDir/$host:$displayNumber.pid";
  166. system("$cmd & echo \$! >$pidFile");
  167.  
  168. # Give Xvnc a chance to start up
  169.  
  170. sleep(3);
  171.  
  172. warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
  173.  
  174. # Create the user's xstartup script if necessary.
  175.  
  176. if (!(-e "$vncUserDir/xstartup")) {
  177.     warn "Creating default startup script $vncUserDir/xstartup\n";
  178.     open(XSTARTUP, ">$vncUserDir/xstartup");
  179.     print XSTARTUP $defaultXStartup;
  180.     close(XSTARTUP);
  181.     chmod 0755, "$vncUserDir/xstartup";
  182. }
  183.  
  184. # Run the X startup script.
  185.  
  186. warn "Starting applications specified in $vncUserDir/xstartup\n";
  187. warn "Log file is $desktopLog\n\n";
  188.  
  189. # If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
  190. # TCP (DISPLAY=host:n)
  191.  
  192. if (-e "/tmp/.X11-unix/X$displayNumber" ||
  193.     -e "/usr/spool/sockets/X11/$displayNumber")
  194. {
  195.     $ENV{DISPLAY}= ":$displayNumber";
  196. } else {
  197.     $ENV{DISPLAY}= "$host:$displayNumber";
  198. }
  199. $ENV{VNCDESKTOP}= $desktopName;
  200.  
  201. system("$vncUserDir/xstartup >> " . &quotedString($desktopLog) . " 2>&1 &");
  202.  
  203. exit;
  204.  
  205.  
  206. ###############################################################################
  207. #
  208. # CheckGeometryAndDepth simply makes sure that the geometry and depth values
  209. # are sensible.
  210. #
  211.  
  212. sub CheckGeometryAndDepth
  213. {
  214.     if ($geometry =~ /^(\d+)x(\d+)$/) {
  215.     $width = $1; $height = $2;
  216.  
  217.     if (($width<1) || ($height<1)) {
  218.         die "$prog: geometry $geometry is invalid\n";
  219.     }
  220.  
  221.     while (($width % 4)!=0) {
  222.         $width = $width + 1;
  223.     }
  224.  
  225.     while (($height % 2)!=0) {
  226.         $height = $height + 1;
  227.     }
  228.  
  229.     $geometry = "${width}x$height";
  230.     } else {
  231.     die "$prog: geometry $geometry is invalid\n";
  232.     }
  233.  
  234.     if (($depth < 8) || ($depth > 32)) {
  235.     die "Depth must be between 8 and 32\n";
  236.     }
  237. }
  238.  
  239.  
  240. #
  241. # GetDisplayNumber gets the lowest available display number.  A display number
  242. # n is taken if something is listening on the VNC server port (5900+n) or the
  243. # X server port (6000+n).
  244. #
  245.  
  246. sub GetDisplayNumber
  247. {
  248.     foreach $n (1..99) {
  249.     if (&CheckDisplayNumber($n)) {
  250.         return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
  251.     }
  252.     }
  253.    
  254.     die "$prog: no free display number on $host.\n";
  255. }
  256.  
  257.  
  258. #
  259. # CheckDisplayNumber checks if the given display number is available.  A
  260. # display number n is taken if something is listening on the VNC server port
  261. # (5900+n) or the X server port (6000+n).
  262. #
  263.  
  264. sub CheckDisplayNumber
  265. {
  266.     local ($n) = @_;
  267.     socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
  268.     eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  269.     if (!bind(S, sockaddr_in(6000 + $n, &INADDR_ANY))) {
  270.         close(S);
  271.         return 0;
  272.     }
  273.     close(S);
  274.     socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
  275.     eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  276.     if (!bind(S, sockaddr_in(5900 + $n, &INADDR_ANY))) {
  277.         close(S);
  278.         return 0;
  279.     }
  280.     close(S);
  281.  
  282.     if (-e "/tmp/.X$n-lock") {
  283.     warn "\nWarning: $host:$n is taken because of /tmp/.X$n-lock\n";
  284.     warn "Remove this file if there is no X server $host:$n\n";
  285.     return 0;
  286.     }
  287.  
  288.     if (-e "/tmp/.X11-unix/X$n") {
  289.     warn "\nWarning: $host:$n is taken because of /tmp/.X11-unix/X$n\n";
  290.     warn "Remove this file if there is no X server $host:$n\n";
  291.     return 0;
  292.     }
  293.  
  294.     if (-e "/usr/spool/sockets/X11/$n") {
  295.     warn("\nWarning: $host:$n is taken because of ".
  296.              "/usr/spool/sockets/X11/$n\n");
  297.     warn "Remove this file if there is no X server $host:$n\n";
  298.     return 0;
  299.     }
  300.  
  301.     return 1;
  302. }
  303.  
  304.  
  305. #
  306. # GetXDisplayDefaults uses xdpyinfo to find out the geometry, depth and pixel
  307. # format of the current X display being used.  If successful, it sets the
  308. # options as appropriate so that the X VNC server will use the same settings
  309. # (minus an allowance for window manager decorations on the geometry).  Using
  310. # the same depth and pixel format means that the VNC server won't have to
  311. # translate pixels when the desktop is being viewed on this X display (for
  312. # TrueColor displays anyway).
  313. #
  314.  
  315. sub GetXDisplayDefaults
  316. {
  317.     local (@lines, @matchlines, $width, $height, $defaultVisualId, $i,
  318.        $red, $green, $blue);
  319.  
  320.     $wmDecorationWidth = 4; # a guess at typical size for window manager
  321.     $wmDecorationHeight = 24;   # decoration size
  322.  
  323.     return if (!defined($ENV{DISPLAY}));
  324.  
  325.     @lines = `xdpyinfo 2>/dev/null`;
  326.  
  327.     return if ($? != 0);
  328.  
  329.     @matchlines = grep(/dimensions/, @lines);
  330.     if (@matchlines) {
  331.     ($width, $height) = ($matchlines[0] =~ /(\d+)x(\d+) pixels/);
  332.  
  333.     $width -= $wmDecorationWidth;
  334.     $height -= $wmDecorationHeight;
  335.  
  336.     $geometry = "${width}x$height";
  337.     }
  338.  
  339.     @matchlines = grep(/default visual id/, @lines);
  340.     if (@matchlines) {
  341.     ($defaultVisualId) = ($matchlines[0] =~ /id:\s+(\S+)/);
  342.  
  343.     for ($i = 0; $i < @lines; $i++) {
  344.         if ($lines[$i] =~ /^\s*visual id:\s+$defaultVisualId$/) {
  345.         if (($lines[$i+1] !~ /TrueColor/) ||
  346.             ($lines[$i+2] !~ /depth/) ||
  347.             ($lines[$i+4] !~ /red, green, blue masks/))
  348.         {
  349.             return;
  350.         }
  351.         last;
  352.         }
  353.     }
  354.  
  355.     return if ($i >= @lines);
  356.  
  357.     ($depth) = ($lines[$i+2] =~ /depth:\s+(\d+)/);
  358.     ($red,$green,$blue)
  359.         = ($lines[$i+4]
  360.            =~ /masks:\s+0x([0-9a-f]+), 0x([0-9a-f]+), 0x([0-9a-f]+)/);
  361.  
  362.     $red = hex($red);
  363.     $green = hex($green);
  364.     $blue = hex($blue);
  365.  
  366.     if ($red > $blue) {
  367.         $red = int(log($red) / log(2)) - int(log($green) / log(2));
  368.         $green = int(log($green) / log(2)) - int(log($blue) / log(2));
  369.         $blue = int(log($blue) / log(2)) + 1;
  370.         $pixelformat = "rgb$red$green$blue";
  371.     } else {
  372.         $blue = int(log($blue) / log(2)) - int(log($green) / log(2));
  373.         $green = int(log($green) / log(2)) - int(log($red) / log(2));
  374.         $red = int(log($red) / log(2)) + 1;
  375.         $pixelformat = "bgr$blue$green$red";
  376.     }
  377.     }
  378. }
  379.  
  380.  
  381. #
  382. # quotedString returns a string which yields the original string when parsed
  383. # by a shell.
  384. #
  385.  
  386. sub quotedString
  387. {
  388.     local ($in) = @_;
  389.  
  390.     $in =~ s/\'/\'\"\'\"\'/g;
  391.  
  392.     return "'$in'";
  393. }
  394.  
  395.  
  396. #
  397. # removeSlashes turns slashes into underscores for use as a file name.
  398. #
  399.  
  400. sub removeSlashes
  401. {
  402.     local ($in) = @_;
  403.  
  404.     $in =~ s|/|_|g;
  405.  
  406.     return "$in";
  407. }
  408.  
  409.  
  410. #
  411. # Usage
  412. #
  413.  
  414. sub Usage
  415. {
  416.     die("\nusage: $prog [:<number>] [-name <desktop-name>] [-depth <depth>]\n".
  417.     "                 [-geometry <width>x<height>]\n".
  418.     "                 [-pixelformat rgbNNN|bgrNNN]\n".
  419.     "                 <Xvnc-options>...\n\n".
  420.     "       $prog -kill <X-display>\n\n");
  421. }
  422.  
  423.  
  424. #
  425. # Kill
  426. #
  427.  
  428. sub Kill
  429. {
  430.     $opt{'-kill'} =~ s/(:\d+)\.\d+$/$1/; # e.g. turn :1.0 into :1
  431.  
  432.     if ($opt{'-kill'} =~ /^:\d+$/) {
  433.     $pidFile = "$vncUserDir/$host$opt{'-kill'}.pid";
  434.     } else {
  435.     if ($opt{'-kill'} !~ /^$host:/) {
  436.         die "\nCan't tell if $opt{'-kill'} is on $host\n".
  437.         "Use -kill :<number> instead\n\n";
  438.     }
  439.     $pidFile = "$vncUserDir/$opt{'-kill'}.pid";
  440.     }
  441.  
  442.     if (! -r $pidFile) {
  443.     die "\nCan't find file $pidFile\n".
  444.         "You'll have to kill the Xvnc process manually\n\n";
  445.     }
  446.  
  447.     $SIG{'HUP'} = 'IGNORE';
  448.     chop($pid = `cat $pidFile`);
  449.     warn "Killing Xvnc process ID $pid\n";
  450.     system("kill $pid");
  451.     unlink $pidFile;
  452.     exit;
  453. }
  454.  
  455.  
  456. #
  457. # ParseOptions takes a list of possible options and a boolean indicating
  458. # whether the option has a value following, and sets up an associative array
  459. # %opt of the values of the options given on the command line. It removes all
  460. # the arguments it uses from @ARGV and returns them in @optArgs.
  461. #
  462.  
  463. sub ParseOptions
  464. {
  465.     local (@optval) = @_;
  466.     local ($opt, @opts, %valFollows, @newargs);
  467.  
  468.     while (@optval) {
  469.     $opt = shift(@optval);
  470.     push(@opts,$opt);
  471.     $valFollows{$opt} = shift(@optval);
  472.     }
  473.  
  474.     @optArgs = ();
  475.     %opt = ();
  476.  
  477.     arg: while (defined($arg = shift(@ARGV))) {
  478.     foreach $opt (@opts) {
  479.         if ($arg eq $opt) {
  480.         push(@optArgs, $arg);
  481.         if ($valFollows{$opt}) {
  482.             if (@ARGV == 0) {
  483.             &Usage();
  484.             }
  485.             $opt{$opt} = shift(@ARGV);
  486.             push(@optArgs, $opt{$opt});
  487.         } else {
  488.             $opt{$opt} = 1;
  489.         }
  490.         next arg;
  491.         }
  492.     }
  493.     push(@newargs,$arg);
  494.     }
  495.  
  496.     @ARGV = @newargs;
  497. }
  498.  
  499.  
  500. #
  501. # Routine to make sure we're operating in a sane environment.
  502. #
  503.  
  504. sub SanityCheck
  505. {
  506.     local ($cmd);
  507.  
  508.     #
  509.     # Get the program name
  510.     #
  511.  
  512.     ($prog) = ($0 =~ m|([^/]+)$|);
  513.  
  514.     #
  515.     # Check we have all the commands we'll need on the path.
  516.     #
  517.  
  518.  cmd:
  519.     foreach $cmd ("uname","xauth","Xvnc","vncpasswd") {
  520.     for (split(/:/,$ENV{PATH})) {
  521.         if (-x "$_/$cmd") {
  522.         next cmd;
  523.         }
  524.     }
  525.     die "$prog: couldn't find \"$cmd\" on your PATH.\n";
  526.     }
  527.  
  528.     #
  529.     # Check the HOME environment variable is set
  530.     #
  531.  
  532.     if (!defined($ENV{HOME})) {
  533.     die "$prog: The HOME environment variable is not set.\n";
  534.     }
  535.     chdir($ENV{HOME});
  536.  
  537.     #
  538.     # Find socket constants. 'use Socket' is a perl5-ism, so we wrap it in an
  539.     # eval, and if it fails we try 'require "sys/socket.ph"'.  If this fails,
  540.     # we just guess at the values.  If you find perl moaning here, just
  541.     # hard-code the values of AF_INET and SOCK_STREAM.  You can find these out
  542.     # for your platform by looking in /usr/include/sys/socket.h and related
  543.     # files.
  544.     #
  545.  
  546.     chop($os = `uname`);
  547.     chop($osrev = `uname -r`);
  548.  
  549.     eval 'use Socket';
  550.     if ($@) {
  551.     eval 'require "sys/socket.ph"';
  552.     if ($@) {
  553.         if (($os eq "SunOS") && ($osrev !~ /^4/)) {
  554.         $AF_INET = 2;
  555.         $SOCK_STREAM = 2;
  556.         } else {
  557.         $AF_INET = 2;
  558.         $SOCK_STREAM = 1;
  559.         }
  560.     } else {
  561.         $AF_INET = &AF_INET;
  562.         $SOCK_STREAM = &SOCK_STREAM;
  563.     }
  564.     } else {
  565.     $AF_INET = &AF_INET;
  566.     $SOCK_STREAM = &SOCK_STREAM;
  567.     }
  568. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement