blob: 093d9acd633c906815007502023590ab371aa74b [file] [log] [blame]
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +00001#!/usr/bin/env perl
2#
DRCb9d8e762011-02-09 08:24:58 +00003# Copyright (C) 2009-2010 D. R. Commander. All Rights Reserved.
DRC190854c2009-03-26 18:13:00 +00004# Copyright (C) 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
5# Copyright (C) 2002-2003 Constantin Kaplinsky. All Rights Reserved.
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +00006# Copyright (C) 2002-2005 RealVNC Ltd.
7# Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
8#
9# This is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This software is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this software; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22# USA.
23#
24
25#
26# vncserver - wrapper script to start an X VNC server.
27#
28
29#
30# First make sure we're operating in a sane environment.
31#
32
DRC190854c2009-03-26 18:13:00 +000033$exedir = "";
34$slashndx = rindex($0, "/");
35if($slashndx>=0) {
36 $exedir = substr($0, 0, $slashndx+1);
37}
38
39$vncClasses = "";
40
41$xauth = "xauth";
42
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000043&SanityCheck();
44
45#
46# Global variables. You may want to configure some of these for your site.
47#
48
49$geometry = "1024x768";
DRC9d1c1572009-03-26 18:18:51 +000050#$depth = 16;
DRCe85eba52011-10-04 06:57:19 +000051$vncJavaFiles = (((-d "$vncClasses") && "$vncClasses") ||
52 ((-d "/usr/share/vnc/classes") && "/usr/share/vnc/classes") ||
53 ((-d "/usr/local/vnc/classes") && "/usr/local/vnc/classes"));
54
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000055$vncUserDir = "$ENV{HOME}/.vnc";
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +020056$skipxstartup = 0;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000057$xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
58
59$defaultXStartup
60 = ("#!/bin/sh\n\n".
DRC93248982009-03-26 18:14:38 +000061 "unset SESSION_MANAGER\n".
Adam Tkacc071e492009-05-20 09:01:24 +000062 "unset DBUS_SESSION_BUS_ADDRESS\n".
DRC93248982009-03-26 18:14:38 +000063 "OS=`uname -s`\n".
64 "if [ \$OS = 'Linux' ]; then\n".
65 " case \"\$WINDOWMANAGER\" in\n".
66 " \*gnome\*)\n".
67 " if [ -e /etc/SuSE-release ]; then\n".
68 " PATH=\$PATH:/opt/gnome/bin\n".
69 " export PATH\n".
70 " fi\n".
71 " ;;\n".
72 " esac\n".
73 "fi\n".
74 "if [ -x /etc/X11/xinit/xinitrc ]; then\n".
75 " exec /etc/X11/xinit/xinitrc\n".
76 "fi\n".
77 "if [ -f /etc/X11/xinit/xinitrc ]; then\n".
78 " exec sh /etc/X11/xinit/xinitrc\n".
79 "fi\n".
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000080 "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n".
81 "xsetroot -solid grey\n".
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000082 "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n".
83 "twm &\n");
84
85chop($host = `uname -n`);
86
DRC989dbd12009-04-22 13:23:17 +000087if (-d "/etc/X11/fontpath.d") {
88 $fontPath = "catalogue:/etc/X11/fontpath.d";
89}
DRC36546c12009-04-15 06:47:23 +000090
DRCd6821bf2009-03-26 18:17:49 +000091@fontpaths = ('/usr/share/X11/fonts', '/usr/share/fonts', '/usr/share/fonts/X11/');
92if (! -l "/usr/lib/X11") {push(@fontpaths, '/usr/lib/X11/fonts');}
93if (! -l "/usr/X11") {push(@fontpaths, '/usr/X11/lib/X11/fonts');}
94if (! -l "/usr/X11R6") {push(@fontpaths, '/usr/X11R6/lib/X11/fonts');}
95push(@fontpaths, '/usr/share/fonts/default');
96
97@fonttypes = ('misc',
98 '75dpi',
99 '100dpi',
100 'Speedo',
101 'Type1');
102
103foreach $_fpath (@fontpaths) {
104 foreach $_ftype (@fonttypes) {
105 if (-f "$_fpath/$_ftype/fonts.dir") {
106 if (! -l "$_fpath/$_ftype") {
DRC36546c12009-04-15 06:47:23 +0000107 $defFontPath .= "$_fpath/$_ftype,";
DRCd6821bf2009-03-26 18:17:49 +0000108 }
109 }
110 }
111}
DRCd28792b2010-01-11 20:53:00 +0000112
DRC36546c12009-04-15 06:47:23 +0000113if ($defFontPath) {
114 if (substr($defFontPath, -1, 1) == ',') {
115 chop $defFontPath;
DRCd6821bf2009-03-26 18:17:49 +0000116 }
117}
118
DRCd28792b2010-01-11 20:53:00 +0000119if ($fontPath eq "") {
120 $fontPath = $defFontPath;
121}
122
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000123# Check command line options
124
125&ParseOptions("-geometry",1,"-depth",1,"-pixelformat",1,"-name",1,"-kill",1,
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200126 "-help",0,"-h",0,"--help",0,"-fp",1,"-list",0,"-fg",0,"-autokill",0,"-noxstartup",0);
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000127
128&Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});
129
130&Kill() if ($opt{'-kill'});
131
DRCb9d8e762011-02-09 08:24:58 +0000132&List() if ($opt{'-list'});
133
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000134# Uncomment this line if you want default geometry, depth and pixelformat
135# to match the current X display:
136# &GetXDisplayDefaults();
137
138if ($opt{'-geometry'}) {
139 $geometry = $opt{'-geometry'};
140}
141if ($opt{'-depth'}) {
142 $depth = $opt{'-depth'};
143 $pixelformat = "";
144}
145if ($opt{'-pixelformat'}) {
146 $pixelformat = $opt{'-pixelformat'};
147}
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200148if ($opt{'-noxstartup'}) {
149 $skipxstartup = 1;
150}
DRCeed5d1f2009-03-26 19:16:19 +0000151if ($opt{'-fp'}) {
152 $fontPath = $opt{'-fp'};
DRC36546c12009-04-15 06:47:23 +0000153 $fpArgSpecified = 1;
DRCeed5d1f2009-03-26 19:16:19 +0000154}
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000155
156&CheckGeometryAndDepth();
157
158
159# Create the user's vnc directory if necessary.
160
161if (!(-e $vncUserDir)) {
162 if (!mkdir($vncUserDir,0755)) {
163 die "$prog: Could not create $vncUserDir.\n";
164 }
165}
166
Adam Tkacf586b842011-04-27 11:20:18 +0000167# Check whether VNC authentication is enabled, and if so, prompt the user to
168# create a VNC password if they don't already have one.
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000169
Adam Tkacf586b842011-04-27 11:20:18 +0000170$securityTypeArgSpecified = 0;
171$vncAuthEnabled = 0;
172$passwordArgSpecified = 0;
173
174for ($i = 0; $i < @ARGV; ++$i) {
175 # -SecurityTypes can be followed by a space or "="
176 my @splitargs = split('=', $ARGV[$i]);
177 if (@splitargs <= 1 && $i < @ARGV - 1) {
178 push(@splitargs, $ARGV[$i + 1]);
179 }
180 if (lc(@splitargs[0]) eq "-securitytypes") {
181 if (@splitargs > 1) {
182 $securityTypeArgSpecified = 1;
183 }
184 foreach $arg2 (split(',', @splitargs[1])) {
185 if (lc($arg2) eq "vncauth" || lc($arg2) eq "tlsvnc"
186 || lc($arg2) eq "x509vnc") {
187 $vncAuthEnabled = 1;
188 }
189 }
190 }
191 if ((lc(@splitargs[0]) eq "-password")
192 || (lc(@splitargs[0]) eq "-passwordfile"
193 || (lc(@splitargs[0]) eq "-rfbauth"))) {
194 $passwordArgSpecified = 1;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000195 }
196}
197
Adam Tkacf586b842011-04-27 11:20:18 +0000198if ((!$securityTypeArgSpecified || $vncAuthEnabled) && !$passwordArgSpecified) {
199 ($z,$z,$mode) = stat("$vncUserDir/passwd");
200 if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
201 warn "\nYou will require a password to access your desktops.\n\n";
202 system($exedir."vncpasswd -q $vncUserDir/passwd");
203 if (($? >> 8) != 0) {
204 exit 1;
205 }
206 }
207}
208
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000209# Find display number.
210
211if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
212 $displayNumber = $1;
213 shift(@ARGV);
214 if (!&CheckDisplayNumber($displayNumber)) {
215 die "A VNC server is already running as :$displayNumber\n";
216 }
Adam Tkac39c9d992010-07-21 14:08:38 +0000217} elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/) && ($ARGV[0] !~ /^\+/)) {
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000218 &Usage();
219} else {
220 $displayNumber = &GetDisplayNumber();
221}
222
223$vncPort = 5900 + $displayNumber;
224
225$desktopLog = "$vncUserDir/$host:$displayNumber.log";
226unlink($desktopLog);
227
Adam Tkac6cbd9d12009-11-12 10:39:54 +0000228# Make an X server cookie - use /dev/urandom on systems that have it,
229# otherwise use perl's random number generator, seeded with the sum
230# of the current time, our PID and part of the encrypted form of the password.
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000231
Adam Tkac6cbd9d12009-11-12 10:39:54 +0000232my $cookie = "";
233if (open(URANDOM, '<', '/dev/urandom')) {
234 my $randata;
235 if (sysread(URANDOM, $randata, 16) == 16) {
236 $cookie = unpack 'h*', $randata;
237 }
238 close(URANDOM);
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000239}
Adam Tkac6cbd9d12009-11-12 10:39:54 +0000240if ($cookie eq "") {
241 srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
242 for (1..16) {
243 $cookie .= sprintf("%02x", int(rand(256)) % 256);
244 }
245}
246
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000247system("xauth -f $xauthorityFile add $host:$displayNumber . $cookie");
248system("xauth -f $xauthorityFile add $host/unix:$displayNumber . $cookie");
249
250if ($opt{'-name'}) {
251 $desktopName = $opt{'-name'};
252} else {
253 $desktopName = "$host:$displayNumber ($ENV{USER})";
254}
255
256# Now start the X VNC Server
257
DRC190854c2009-03-26 18:13:00 +0000258$cmd = $exedir."Xvnc :$displayNumber";
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000259$cmd .= " -desktop " . &quotedString($desktopName);
260$cmd .= " -httpd $vncJavaFiles" if ($vncJavaFiles);
261$cmd .= " -auth $xauthorityFile";
262$cmd .= " -geometry $geometry" if ($geometry);
263$cmd .= " -depth $depth" if ($depth);
264$cmd .= " -pixelformat $pixelformat" if ($pixelformat);
265$cmd .= " -rfbwait 30000";
266$cmd .= " -rfbauth $vncUserDir/passwd";
267$cmd .= " -rfbport $vncPort";
DRCd6821bf2009-03-26 18:17:49 +0000268$cmd .= " -fp $fontPath" if ($fontPath);
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000269$cmd .= " -pn";
270
DRCd6821bf2009-03-26 18:17:49 +0000271# Add color database stuff here, e.g.:
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000272#
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000273# $cmd .= " -co /usr/lib/X11/rgb";
274#
275
276foreach $arg (@ARGV) {
277 $cmd .= " " . &quotedString($arg);
278}
279$cmd .= " >> " . &quotedString($desktopLog) . " 2>&1";
280
281# Run $cmd and record the process ID.
282
283$pidFile = "$vncUserDir/$host:$displayNumber.pid";
284system("$cmd & echo \$! >$pidFile");
285
286# Give Xvnc a chance to start up
287
288sleep(3);
DRCd28792b2010-01-11 20:53:00 +0000289if ($fontPath ne $defFontPath) {
290 unless (kill 0, `cat $pidFile`) {
291 if ($fpArgSpecified) {
292 warn "\nWARNING: The first attempt to start Xvnc failed, probably because the font\n";
293 warn "path you specified using the -fp argument is incorrect. Attempting to\n";
294 warn "determine an appropriate font path for this system and restart Xvnc using\n";
295 warn "that font path ...\n";
296 } else {
297 warn "\nWARNING: The first attempt to start Xvnc failed, possibly because the font\n";
298 warn "catalog is not properly configured. Attempting to determine an appropriate\n";
299 warn "font path for this system and restart Xvnc using that font path ...\n";
300 }
301 $cmd =~ s@-fp [^ ]+@@;
302 $cmd .= " -fp $defFontPath" if ($defFontPath);
303 system("$cmd & echo \$! >$pidFile");
304 sleep(3);
DRC36546c12009-04-15 06:47:23 +0000305 }
DRCd6821bf2009-03-26 18:17:49 +0000306}
307unless (kill 0, `cat $pidFile`) {
308 warn "Could not start Xvnc.\n\n";
Michal Srbe6e11f92015-10-02 02:28:26 +0300309 unlink $pidFile;
DRCd6821bf2009-03-26 18:17:49 +0000310 open(LOG, "<$desktopLog");
311 while (<LOG>) { print; }
312 close(LOG);
313 die "\n";
314}
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000315
316warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
317
318# Create the user's xstartup script if necessary.
319
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200320if (! $skipxstartup) {
321 if (!(-e "$vncUserDir/xstartup")) {
322 warn "Creating default startup script $vncUserDir/xstartup\n";
323 open(XSTARTUP, ">$vncUserDir/xstartup");
324 print XSTARTUP $defaultXStartup;
325 close(XSTARTUP);
326 chmod 0755, "$vncUserDir/xstartup";
327 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000328}
329
330# Run the X startup script.
331
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200332if (! $skipxstartup) {
333 warn "Starting applications specified in $vncUserDir/xstartup\n";
334}
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000335warn "Log file is $desktopLog\n\n";
336
337# If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
338# TCP (DISPLAY=host:n)
339
340if (-e "/tmp/.X11-unix/X$displayNumber" ||
341 -e "/usr/spool/sockets/X11/$displayNumber")
342{
343 $ENV{DISPLAY}= ":$displayNumber";
344} else {
345 $ENV{DISPLAY}= "$host:$displayNumber";
346}
347$ENV{VNCDESKTOP}= $desktopName;
348
Pierre Ossmana5b37c02015-07-30 11:04:02 +0200349system($exedir."vncconfig -nowin >> " . &quotedString($desktopLog) . " 2>&1 &");
DRCf6b58402011-10-05 21:28:03 +0000350
DRC8fb11912011-03-03 10:42:14 +0000351if ($opt{'-fg'}) {
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200352 if (! $skipxstartup) {
353 system("$vncUserDir/xstartup >> " . &quotedString($desktopLog) . " 2>&1");
354 }
Adam Tkac38ba8cf2011-04-27 11:28:09 +0000355 if (kill 0, `cat $pidFile`) {
356 $opt{'-kill'} = ':'.$displayNumber;
357 &Kill();
358 }
DRC8fb11912011-03-03 10:42:14 +0000359} else {
Adam Tkac38ba8cf2011-04-27 11:28:09 +0000360 if ($opt{'-autokill'}) {
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200361 if (! $skipxstartup) {
362 system("($vncUserDir/xstartup; $0 -kill :$displayNumber) >> "
363 . &quotedString($desktopLog) . " 2>&1 &");
364 }
Adam Tkac38ba8cf2011-04-27 11:28:09 +0000365 } else {
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200366 if (! $skipxstartup) {
367 system("$vncUserDir/xstartup >> " . &quotedString($desktopLog)
368 . " 2>&1 &");
369 }
Adam Tkac38ba8cf2011-04-27 11:28:09 +0000370 }
DRC8fb11912011-03-03 10:42:14 +0000371}
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000372
373exit;
374
375
376###############################################################################
377#
378# CheckGeometryAndDepth simply makes sure that the geometry and depth values
379# are sensible.
380#
381
382sub CheckGeometryAndDepth
383{
384 if ($geometry =~ /^(\d+)x(\d+)$/) {
385 $width = $1; $height = $2;
386
387 if (($width<1) || ($height<1)) {
388 die "$prog: geometry $geometry is invalid\n";
389 }
390
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000391 $geometry = "${width}x$height";
392 } else {
393 die "$prog: geometry $geometry is invalid\n";
394 }
395
DRCe5b4f752009-03-26 18:23:29 +0000396 if ($depth && (($depth < 8) || ($depth > 32))) {
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000397 die "Depth must be between 8 and 32\n";
398 }
399}
400
401
402#
403# GetDisplayNumber gets the lowest available display number. A display number
404# n is taken if something is listening on the VNC server port (5900+n) or the
405# X server port (6000+n).
406#
407
408sub GetDisplayNumber
409{
410 foreach $n (1..99) {
411 if (&CheckDisplayNumber($n)) {
412 return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
413 }
414 }
415
416 die "$prog: no free display number on $host.\n";
417}
418
419
420#
421# CheckDisplayNumber checks if the given display number is available. A
422# display number n is taken if something is listening on the VNC server port
423# (5900+n) or the X server port (6000+n).
424#
425
426sub CheckDisplayNumber
427{
428 local ($n) = @_;
429
430 socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
431 eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
432 if (!bind(S, pack('S n x12', $AF_INET, 6000 + $n))) {
433 close(S);
434 return 0;
435 }
436 close(S);
437
438 socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
439 eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
440 if (!bind(S, pack('S n x12', $AF_INET, 5900 + $n))) {
441 close(S);
442 return 0;
443 }
444 close(S);
445
446 if (-e "/tmp/.X$n-lock") {
447 warn "\nWarning: $host:$n is taken because of /tmp/.X$n-lock\n";
448 warn "Remove this file if there is no X server $host:$n\n";
449 return 0;
450 }
451
452 if (-e "/tmp/.X11-unix/X$n") {
453 warn "\nWarning: $host:$n is taken because of /tmp/.X11-unix/X$n\n";
454 warn "Remove this file if there is no X server $host:$n\n";
455 return 0;
456 }
457
458 if (-e "/usr/spool/sockets/X11/$n") {
459 warn("\nWarning: $host:$n is taken because of ".
460 "/usr/spool/sockets/X11/$n\n");
461 warn "Remove this file if there is no X server $host:$n\n";
462 return 0;
463 }
464
465 return 1;
466}
467
468
469#
470# GetXDisplayDefaults uses xdpyinfo to find out the geometry, depth and pixel
471# format of the current X display being used. If successful, it sets the
472# options as appropriate so that the X VNC server will use the same settings
473# (minus an allowance for window manager decorations on the geometry). Using
474# the same depth and pixel format means that the VNC server won't have to
475# translate pixels when the desktop is being viewed on this X display (for
476# TrueColor displays anyway).
477#
478
479sub GetXDisplayDefaults
480{
481 local (@lines, @matchlines, $width, $height, $defaultVisualId, $i,
482 $red, $green, $blue);
483
484 $wmDecorationWidth = 4; # a guess at typical size for window manager
485 $wmDecorationHeight = 24; # decoration size
486
487 return if (!defined($ENV{DISPLAY}));
488
489 @lines = `xdpyinfo 2>/dev/null`;
490
491 return if ($? != 0);
492
493 @matchlines = grep(/dimensions/, @lines);
494 if (@matchlines) {
495 ($width, $height) = ($matchlines[0] =~ /(\d+)x(\d+) pixels/);
496
497 $width -= $wmDecorationWidth;
498 $height -= $wmDecorationHeight;
499
500 $geometry = "${width}x$height";
501 }
502
503 @matchlines = grep(/default visual id/, @lines);
504 if (@matchlines) {
505 ($defaultVisualId) = ($matchlines[0] =~ /id:\s+(\S+)/);
506
507 for ($i = 0; $i < @lines; $i++) {
508 if ($lines[$i] =~ /^\s*visual id:\s+$defaultVisualId$/) {
509 if (($lines[$i+1] !~ /TrueColor/) ||
510 ($lines[$i+2] !~ /depth/) ||
511 ($lines[$i+4] !~ /red, green, blue masks/))
512 {
513 return;
514 }
515 last;
516 }
517 }
518
519 return if ($i >= @lines);
520
521 ($depth) = ($lines[$i+2] =~ /depth:\s+(\d+)/);
522 ($red,$green,$blue)
523 = ($lines[$i+4]
524 =~ /masks:\s+0x([0-9a-f]+), 0x([0-9a-f]+), 0x([0-9a-f]+)/);
525
526 $red = hex($red);
527 $green = hex($green);
528 $blue = hex($blue);
529
530 if ($red > $blue) {
531 $red = int(log($red) / log(2)) - int(log($green) / log(2));
532 $green = int(log($green) / log(2)) - int(log($blue) / log(2));
533 $blue = int(log($blue) / log(2)) + 1;
534 $pixelformat = "rgb$red$green$blue";
535 } else {
536 $blue = int(log($blue) / log(2)) - int(log($green) / log(2));
537 $green = int(log($green) / log(2)) - int(log($red) / log(2));
538 $red = int(log($red) / log(2)) + 1;
539 $pixelformat = "bgr$blue$green$red";
540 }
541 }
542}
543
544
545#
546# quotedString returns a string which yields the original string when parsed
547# by a shell.
548#
549
550sub quotedString
551{
552 local ($in) = @_;
553
554 $in =~ s/\'/\'\"\'\"\'/g;
555
556 return "'$in'";
557}
558
559
560#
561# removeSlashes turns slashes into underscores for use as a file name.
562#
563
564sub removeSlashes
565{
566 local ($in) = @_;
567
568 $in =~ s|/|_|g;
569
570 return "$in";
571}
572
573
574#
575# Usage
576#
577
578sub Usage
579{
580 die("\nusage: $prog [:<number>] [-name <desktop-name>] [-depth <depth>]\n".
581 " [-geometry <width>x<height>]\n".
582 " [-pixelformat rgbNNN|bgrNNN]\n".
DRCeed5d1f2009-03-26 19:16:19 +0000583 " [-fp <font-path>]\n".
DRC8fb11912011-03-03 10:42:14 +0000584 " [-fg]\n".
Adam Tkac38ba8cf2011-04-27 11:28:09 +0000585 " [-autokill]\n".
Llorenç Garcia Martinez861cb062015-10-23 13:37:42 +0200586 " [-noxstartup]\n".
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000587 " <Xvnc-options>...\n\n".
DRCb9d8e762011-02-09 08:24:58 +0000588 " $prog -kill <X-display>\n\n".
589 " $prog -list\n\n");
590}
591
592
593#
594# List
595#
596
597sub List
598{
599 opendir(dir, $vncUserDir);
600 my @filelist = readdir(dir);
601 closedir(dir);
DRC075d9fa2011-02-10 04:19:46 +0000602 print "\nTigerVNC server sessions:\n\n";
DRCb9d8e762011-02-09 08:24:58 +0000603 print "X DISPLAY #\tPROCESS ID\n";
604 foreach my $file (@filelist) {
605 if ($file =~ /$host:(\d+)$\.pid/) {
Michal Srbe6e11f92015-10-02 02:28:26 +0300606 chop($tmp_pid = `cat $vncUserDir/$file`);
607 if (kill 0, $tmp_pid) {
608 print ":".$1."\t\t".`cat $vncUserDir/$file`;
609 } else {
610 unlink ($vncUserDir . "/" . $file);
611 }
DRCb9d8e762011-02-09 08:24:58 +0000612 }
613 }
614 exit 1;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000615}
616
617
618#
619# Kill
620#
621
622sub Kill
623{
624 $opt{'-kill'} =~ s/(:\d+)\.\d+$/$1/; # e.g. turn :1.0 into :1
625
626 if ($opt{'-kill'} =~ /^:\d+$/) {
627 $pidFile = "$vncUserDir/$host$opt{'-kill'}.pid";
628 } else {
629 if ($opt{'-kill'} !~ /^$host:/) {
630 die "\nCan't tell if $opt{'-kill'} is on $host\n".
631 "Use -kill :<number> instead\n\n";
632 }
633 $pidFile = "$vncUserDir/$opt{'-kill'}.pid";
634 }
635
636 if (! -r $pidFile) {
637 die "\nCan't find file $pidFile\n".
638 "You'll have to kill the Xvnc process manually\n\n";
639 }
640
641 $SIG{'HUP'} = 'IGNORE';
642 chop($pid = `cat $pidFile`);
643 warn "Killing Xvnc process ID $pid\n";
DRCb9d8e762011-02-09 08:24:58 +0000644
645 if (kill 0, $pid) {
646 system("kill $pid");
647 sleep(1);
648 if (kill 0, $pid) {
649 print "Xvnc seems to be deadlocked. Kill the process manually and then re-run\n";
650 print " ".$0." -kill ".$opt{'-kill'}."\n";
651 print "to clean up the socket files.\n";
652 exit
653 }
654
655 } else {
656 warn "Xvnc process ID $pid already killed\n";
657 $opt{'-kill'} =~ s/://;
658
659 if (-e "/tmp/.X11-unix/X$opt{'-kill'}") {
660 print "Xvnc did not appear to shut down cleanly.";
661 print " Removing /tmp/.X11-unix/X$opt{'-kill'}\n";
662 unlink "/tmp/.X11-unix/X$opt{'-kill'}";
663 }
664 if (-e "/tmp/.X$opt{'-kill'}-lock") {
665 print "Xvnc did not appear to shut down cleanly.";
666 print " Removing /tmp/.X$opt{'-kill'}-lock\n";
667 unlink "/tmp/.X$opt{'-kill'}-lock";
668 }
669 }
670
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000671 unlink $pidFile;
672 exit;
673}
674
675
676#
677# ParseOptions takes a list of possible options and a boolean indicating
678# whether the option has a value following, and sets up an associative array
679# %opt of the values of the options given on the command line. It removes all
680# the arguments it uses from @ARGV and returns them in @optArgs.
681#
682
683sub ParseOptions
684{
685 local (@optval) = @_;
686 local ($opt, @opts, %valFollows, @newargs);
687
688 while (@optval) {
689 $opt = shift(@optval);
690 push(@opts,$opt);
691 $valFollows{$opt} = shift(@optval);
692 }
693
694 @optArgs = ();
695 %opt = ();
696
697 arg: while (defined($arg = shift(@ARGV))) {
698 foreach $opt (@opts) {
699 if ($arg eq $opt) {
700 push(@optArgs, $arg);
701 if ($valFollows{$opt}) {
702 if (@ARGV == 0) {
703 &Usage();
704 }
705 $opt{$opt} = shift(@ARGV);
706 push(@optArgs, $opt{$opt});
707 } else {
708 $opt{$opt} = 1;
709 }
710 next arg;
711 }
712 }
713 push(@newargs,$arg);
714 }
715
716 @ARGV = @newargs;
717}
718
719
720#
721# Routine to make sure we're operating in a sane environment.
722#
723
724sub SanityCheck
725{
726 local ($cmd);
727
728 #
729 # Get the program name
730 #
731
732 ($prog) = ($0 =~ m|([^/]+)$|);
733
734 #
735 # Check we have all the commands we'll need on the path.
736 #
737
738 cmd:
DRC190854c2009-03-26 18:13:00 +0000739 foreach $cmd ("uname") {
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000740 for (split(/:/,$ENV{PATH})) {
741 if (-x "$_/$cmd") {
742 next cmd;
743 }
744 }
745 die "$prog: couldn't find \"$cmd\" on your PATH.\n";
746 }
DRC190854c2009-03-26 18:13:00 +0000747 if (-x "/usr/X11R6/bin/xauth") {
748 $xauth = "/usr/X11R6/bin/xauth";
749 }
750 else {
751 cmd1:
752 foreach $cmd ("xauth") {
753 for (split(/:/,$ENV{PATH})) {
754 if (-x "$_/$cmd") {
755 next cmd1;
756 }
757 }
758 die "$prog: couldn't find \"$cmd\" on your PATH.\n";
759 }
760 }
761
762 if($exedir eq "") {
763 cmd2:
764 foreach $cmd ("Xvnc","vncpasswd") {
765 for (split(/:/,$ENV{PATH})) {
766 if (-x "$_/$cmd") {
767 $vncClasses = "$_/../vnc/classes";
768 next cmd2;
769 }
770 }
771 die "$prog: couldn't find \"$cmd\" on your PATH.\n";
772 }
773 }
774 else {
775 cmd3:
776 foreach $cmd ($exedir."Xvnc",$exedir."vncpasswd") {
777 for (split(/:/,$ENV{PATH})) {
778 if (-x "$cmd") {
779 $vncClasses = $exedir."../vnc/classes";
780 next cmd3;
781 }
782 }
783 die "$prog: couldn't find \"$cmd\".\n";
784 }
785 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000786
787 #
788 # Check the HOME environment variable is set
789 #
790
791 if (!defined($ENV{HOME})) {
792 die "$prog: The HOME environment variable is not set.\n";
793 }
DRC190854c2009-03-26 18:13:00 +0000794# chdir($ENV{HOME});
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000795
796 #
797 # Find socket constants. 'use Socket' is a perl5-ism, so we wrap it in an
798 # eval, and if it fails we try 'require "sys/socket.ph"'. If this fails,
799 # we just guess at the values. If you find perl moaning here, just
800 # hard-code the values of AF_INET and SOCK_STREAM. You can find these out
801 # for your platform by looking in /usr/include/sys/socket.h and related
802 # files.
803 #
804
805 chop($os = `uname`);
806 chop($osrev = `uname -r`);
807
808 eval 'use Socket';
809 if ($@) {
810 eval 'require "sys/socket.ph"';
811 if ($@) {
812 if (($os eq "SunOS") && ($osrev !~ /^4/)) {
813 $AF_INET = 2;
814 $SOCK_STREAM = 2;
815 } else {
816 $AF_INET = 2;
817 $SOCK_STREAM = 1;
818 }
819 } else {
820 $AF_INET = &AF_INET;
821 $SOCK_STREAM = &SOCK_STREAM;
822 }
823 } else {
824 $AF_INET = &AF_INET;
825 $SOCK_STREAM = &SOCK_STREAM;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000826 }
827}