You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vncserver 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. #!/usr/bin/env perl
  2. #
  3. # Copyright (C) 2015-2019 Pierre Ossman for Cendio AB
  4. # Copyright (C) 2009-2010 D. R. Commander. All Rights Reserved.
  5. # Copyright (C) 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
  6. # Copyright (C) 2002-2003 Constantin Kaplinsky. All Rights Reserved.
  7. # Copyright (C) 2002-2005 RealVNC Ltd.
  8. # Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
  9. #
  10. # This is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation; either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # This software is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with this software; if not, write to the Free Software
  22. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  23. # USA.
  24. #
  25. #
  26. # vncserver - wrapper script to start an X VNC server.
  27. #
  28. # First make sure we're operating in a sane environment.
  29. $exedir = "";
  30. $slashndx = rindex($0, "/");
  31. if($slashndx>=0) {
  32. $exedir = substr($0, 0, $slashndx+1);
  33. }
  34. &SanityCheck();
  35. #
  36. # Global variables. You may want to configure some of these for
  37. # your site
  38. #
  39. $vncUserDir = "$ENV{HOME}/.vnc";
  40. $vncUserConfig = "$vncUserDir/config";
  41. $vncSystemConfigDir = "/etc/tigervnc";
  42. $vncSystemConfigDefaultsFile = "$vncSystemConfigDir/vncserver-config-defaults";
  43. $vncSystemConfigMandatoryFile = "$vncSystemConfigDir/vncserver-config-mandatory";
  44. $skipxstartup = 0;
  45. $xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
  46. $xstartupFile = $vncUserDir . "/xstartup";
  47. $defaultXStartup
  48. = ("#!/bin/sh\n\n".
  49. "OS=`uname -s`\n".
  50. "if [ \$OS = 'Linux' ]; then\n".
  51. " case \"\$WINDOWMANAGER\" in\n".
  52. " \*gnome\*)\n".
  53. " if [ -e /etc/SuSE-release ]; then\n".
  54. " PATH=\$PATH:/opt/gnome/bin\n".
  55. " export PATH\n".
  56. " fi\n".
  57. " ;;\n".
  58. " esac\n".
  59. "fi\n".
  60. "if [ -x /etc/X11/xinit/xinitrc ]; then\n".
  61. " exec /etc/X11/xinit/xinitrc\n".
  62. "fi\n".
  63. "if [ -f /etc/X11/xinit/xinitrc ]; then\n".
  64. " exec sh /etc/X11/xinit/xinitrc\n".
  65. "fi\n".
  66. "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n".
  67. "xsetroot -solid grey\n".
  68. "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n".
  69. "twm\n");
  70. $defaultConfig
  71. = ("## Supported server options to pass to vncserver upon invocation can be listed\n".
  72. "## in this file. See the following manpages for more: vncserver(1) Xvnc(1).\n".
  73. "## Several common ones are shown below. Uncomment and modify to your liking.\n".
  74. "##\n".
  75. "# securitytypes=vncauth,tlsvnc\n".
  76. "# desktop=sandbox\n".
  77. "# geometry=2000x1200\n".
  78. "# localhost\n".
  79. "# alwaysshared\n");
  80. chop($host = `uname -n`);
  81. if (-d "/etc/X11/fontpath.d") {
  82. $fontPath = "catalogue:/etc/X11/fontpath.d";
  83. }
  84. @fontpaths = ('/usr/share/X11/fonts', '/usr/share/fonts', '/usr/share/fonts/X11/');
  85. if (! -l "/usr/lib/X11") {push(@fontpaths, '/usr/lib/X11/fonts');}
  86. if (! -l "/usr/X11") {push(@fontpaths, '/usr/X11/lib/X11/fonts');}
  87. if (! -l "/usr/X11R6") {push(@fontpaths, '/usr/X11R6/lib/X11/fonts');}
  88. push(@fontpaths, '/usr/share/fonts/default');
  89. @fonttypes = ('misc',
  90. '75dpi',
  91. '100dpi',
  92. 'Speedo',
  93. 'Type1');
  94. foreach $_fpath (@fontpaths) {
  95. foreach $_ftype (@fonttypes) {
  96. if (-f "$_fpath/$_ftype/fonts.dir") {
  97. if (! -l "$_fpath/$_ftype") {
  98. $defFontPath .= "$_fpath/$_ftype,";
  99. }
  100. }
  101. }
  102. }
  103. if ($defFontPath) {
  104. if (substr($defFontPath, -1, 1) == ',') {
  105. chop $defFontPath;
  106. }
  107. }
  108. if ($fontPath eq "") {
  109. $fontPath = $defFontPath;
  110. }
  111. # Check command line options
  112. &ParseOptions("-kill",1,"-help",0,"-h",0,"--help",0,"-list",0,
  113. "-fg",0,"-autokill",0,"-noxstartup",0,"-xstartup",1);
  114. &Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});
  115. &Kill() if ($opt{'-kill'});
  116. &List() if ($opt{'-list'});
  117. if ($opt{'-noxstartup'}) {
  118. $skipxstartup = 1;
  119. }
  120. if ($opt{'-xstartup'}) {
  121. $xstartupFile = $opt{'-xstartup'};
  122. }
  123. # Create the user's vnc directory if necessary.
  124. if (!(-e $vncUserDir)) {
  125. if (!mkdir($vncUserDir,0755)) {
  126. die "$prog: Could not create $vncUserDir.\n";
  127. }
  128. }
  129. # Find display number.
  130. if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
  131. $displayNumber = $1;
  132. shift(@ARGV);
  133. if (!&CheckDisplayNumber($displayNumber)) {
  134. die "A VNC server is already running as :$displayNumber\n";
  135. }
  136. } elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/) && ($ARGV[0] !~ /^\+/)) {
  137. &Usage();
  138. } else {
  139. $displayNumber = &GetDisplayNumber();
  140. }
  141. $vncPort = 5900 + $displayNumber;
  142. $desktopName = "$host:$displayNumber ($ENV{USER})";
  143. my %default_opts;
  144. my %config;
  145. # We set some reasonable defaults. Config file settings
  146. # override these where present.
  147. $default_opts{desktop} = &quotedString($desktopName);
  148. $default_opts{auth} = &quotedString($xauthorityFile);
  149. $default_opts{rfbwait} = 30000;
  150. $default_opts{rfbauth} = "$vncUserDir/passwd";
  151. $default_opts{rfbport} = $vncPort;
  152. $default_opts{fp} = $fontPath if ($fontPath);
  153. $default_opts{pn} = "";
  154. # Load user-overrideable system defaults
  155. LoadConfig($vncSystemConfigDefaultsFile);
  156. # Then the user's settings
  157. LoadConfig($vncUserConfig);
  158. # And then override anything set above if mandatory settings exist.
  159. # WARNING: "Mandatory" is used loosely here! As the man page says,
  160. # there is nothing stopping someone from EASILY subverting the
  161. # settings in $vncSystemConfigMandatoryFile by simply passing
  162. # CLI args to vncserver, which trump config files! To properly
  163. # hard force policy in a non-subvertible way would require major
  164. # development work that touches Xvnc itself.
  165. LoadConfig($vncSystemConfigMandatoryFile, 1);
  166. #
  167. # 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.
  169. #
  170. $securityTypeArgSpecified = 0;
  171. $vncAuthEnabled = 0;
  172. $passwordArgSpecified = 0;
  173. @vncAuthStrings = ("vncauth", "tlsvnc", "x509vnc");
  174. # ...first we check our configuration files' settings
  175. if ($config{'securitytypes'}) {
  176. $securityTypeArgSpecified = 1;
  177. foreach $arg2 (split(',', $config{'securitytypes'})) {
  178. if (grep {$_ eq lc($arg2)} @vncAuthStrings) {
  179. $vncAuthEnabled = 1;
  180. }
  181. }
  182. }
  183. if ($config{'password'} ||
  184. $config{'passwordfile'} ||
  185. $config{'rfbauth'}) {
  186. $passwordArgSpecified = 1;
  187. }
  188. if ((!$securityTypeArgSpecified || $vncAuthEnabled) && !$passwordArgSpecified) {
  189. ($z,$z,$mode) = stat("$vncUserDir/passwd");
  190. if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
  191. warn "\nYou will require a password to access your desktops.\n\n";
  192. system($exedir."vncpasswd -q $vncUserDir/passwd");
  193. if (($? >> 8) != 0) {
  194. exit 1;
  195. }
  196. }
  197. }
  198. $desktopLog = "$vncUserDir/$host:$displayNumber.log";
  199. unlink($desktopLog);
  200. # Make an X server cookie and set up the Xauthority file
  201. # mcookie is a part of util-linux, usually only GNU/Linux systems have it.
  202. $cookie = `mcookie`;
  203. # Fallback for non GNU/Linux OS - use /dev/urandom on systems that have it,
  204. # otherwise use perl's random number generator, seeded with the sum
  205. # of the current time, our PID and part of the encrypted form of the password.
  206. if ($cookie eq "" && open(URANDOM, '<', '/dev/urandom')) {
  207. my $randata;
  208. if (sysread(URANDOM, $randata, 16) == 16) {
  209. $cookie = unpack 'h*', $randata;
  210. }
  211. close(URANDOM);
  212. }
  213. if ($cookie eq "") {
  214. srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
  215. for (1..16) {
  216. $cookie .= sprintf("%02x", int(rand(256)) % 256);
  217. }
  218. }
  219. open(XAUTH, "|xauth -f $xauthorityFile source -");
  220. print XAUTH "add $host:$displayNumber . $cookie\n";
  221. print XAUTH "add $host/unix:$displayNumber . $cookie\n";
  222. close(XAUTH);
  223. # Now start the X VNC Server
  224. # We build up our Xvnc command with options
  225. $cmd = $exedir."Xvnc :$displayNumber";
  226. foreach my $k (sort keys %config) {
  227. $cmd .= " -$k $config{$k}";
  228. delete $default_opts{$k}; # file options take precedence
  229. }
  230. foreach my $k (sort keys %default_opts) {
  231. $cmd .= " -$k $default_opts{$k}";
  232. }
  233. # Run $cmd and record the process ID.
  234. $pidFile = "$vncUserDir/$host:$displayNumber.pid";
  235. system("$cmd & echo \$! >$pidFile");
  236. # Give Xvnc a chance to start up
  237. sleep(3);
  238. if ($fontPath ne $defFontPath) {
  239. unless (kill 0, `cat $pidFile`) {
  240. if ($fpArgSpecified) {
  241. warn "\nWARNING: The first attempt to start Xvnc failed, probably because the font\n";
  242. warn "path you specified using the -fp argument is incorrect. Attempting to\n";
  243. warn "determine an appropriate font path for this system and restart Xvnc using\n";
  244. warn "that font path ...\n";
  245. } else {
  246. warn "\nWARNING: The first attempt to start Xvnc failed, possibly because the font\n";
  247. warn "catalog is not properly configured. Attempting to determine an appropriate\n";
  248. warn "font path for this system and restart Xvnc using that font path ...\n";
  249. }
  250. $cmd =~ s@-fp [^ ]+@@;
  251. $cmd .= " -fp $defFontPath" if ($defFontPath);
  252. system("$cmd & echo \$! >$pidFile");
  253. sleep(3);
  254. }
  255. }
  256. unless (kill 0, `cat $pidFile`) {
  257. warn "Could not start Xvnc.\n\n";
  258. unlink $pidFile;
  259. open(LOG, "<$desktopLog");
  260. while (<LOG>) { print; }
  261. close(LOG);
  262. die "\n";
  263. }
  264. warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
  265. # Create the user's xstartup script if necessary.
  266. if (! $skipxstartup) {
  267. if (!(-e "$xstartupFile")) {
  268. warn "Creating default startup script $xstartupFile\n";
  269. open(XSTARTUP, ">$xstartupFile");
  270. print XSTARTUP $defaultXStartup;
  271. close(XSTARTUP);
  272. chmod 0755, "$xstartupFile";
  273. }
  274. }
  275. # Create the user's config file if necessary.
  276. if (!(-e "$vncUserDir/config")) {
  277. warn "Creating default config $vncUserDir/config\n";
  278. open(VNCUSERCONFIG, ">$vncUserDir/config");
  279. print VNCUSERCONFIG $defaultConfig;
  280. close(VNCUSERCONFIG);
  281. chmod 0644, "$vncUserDir/config";
  282. }
  283. # Run the X startup script.
  284. if (! $skipxstartup) {
  285. warn "Starting applications specified in $xstartupFile\n";
  286. }
  287. warn "Log file is $desktopLog\n\n";
  288. # If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
  289. # TCP (DISPLAY=host:n)
  290. if (-e "/tmp/.X11-unix/X$displayNumber" ||
  291. -e "/usr/spool/sockets/X11/$displayNumber")
  292. {
  293. $ENV{DISPLAY}= ":$displayNumber";
  294. } else {
  295. $ENV{DISPLAY}= "$host:$displayNumber";
  296. }
  297. $ENV{VNCDESKTOP}= $desktopName;
  298. if ($opt{'-fg'}) {
  299. if (! $skipxstartup) {
  300. system("$xstartupFile >> " . &quotedString($desktopLog) . " 2>&1");
  301. }
  302. if (kill 0, `cat $pidFile`) {
  303. $opt{'-kill'} = ':'.$displayNumber;
  304. &Kill();
  305. }
  306. } else {
  307. if ($opt{'-autokill'}) {
  308. if (! $skipxstartup) {
  309. system("($xstartupFile; $0 -kill :$displayNumber) >> "
  310. . &quotedString($desktopLog) . " 2>&1 &");
  311. }
  312. } else {
  313. if (! $skipxstartup) {
  314. system("$xstartupFile >> " . &quotedString($desktopLog)
  315. . " 2>&1 &");
  316. }
  317. }
  318. }
  319. exit;
  320. ###############################################################################
  321. # Functions
  322. ###############################################################################
  323. #
  324. # Populate the global %config hash with settings from a specified
  325. # vncserver configuration file if it exists
  326. #
  327. # Args: 1. file path
  328. # 2. optional boolean flag to enable warning when a previously
  329. # set configuration setting is being overridden
  330. #
  331. sub LoadConfig {
  332. local ($configFile, $warnoverride) = @_;
  333. local ($toggle) = undef;
  334. if (stat($configFile)) {
  335. if (open(IN, $configFile)) {
  336. while (<IN>) {
  337. next if /^#/;
  338. if (my ($k, $v) = /^\s*(\w+)\s*=\s*(.+)$/) {
  339. $k = lc($k); # must normalize key case
  340. if ($warnoverride && $config{$k}) {
  341. print("Warning: $configFile is overriding previously defined '$k' to be '$v'\n");
  342. }
  343. $config{$k} = $v;
  344. } elsif ($_ =~ m/^\s*(\S+)/) {
  345. # We can't reasonably warn on override of toggles (e.g. AlwaysShared)
  346. # because it would get crazy to do so. We'd have to check if the
  347. # current config file being loaded defined the logical opposite setting
  348. # (NeverShared vs. AlwaysShared, etc etc).
  349. $toggle = lc($1); # must normalize key case
  350. $config{$toggle} = $k;
  351. }
  352. }
  353. close(IN);
  354. }
  355. }
  356. }
  357. #
  358. # GetDisplayNumber gets the lowest available display number. A display number
  359. # n is taken if something is listening on the VNC server port (5900+n) or the
  360. # X server port (6000+n).
  361. #
  362. sub GetDisplayNumber
  363. {
  364. foreach $n (1..99) {
  365. if (&CheckDisplayNumber($n)) {
  366. return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
  367. }
  368. }
  369. die "$prog: no free display number on $host.\n";
  370. }
  371. #
  372. # CheckDisplayNumber checks if the given display number is available. A
  373. # display number n is taken if something is listening on the VNC server port
  374. # (5900+n) or the X server port (6000+n).
  375. #
  376. sub CheckDisplayNumber
  377. {
  378. local ($n) = @_;
  379. socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
  380. eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  381. if (!bind(S, pack('S n x12', $AF_INET, 6000 + $n))) {
  382. close(S);
  383. return 0;
  384. }
  385. close(S);
  386. socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
  387. eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  388. if (!bind(S, pack('S n x12', $AF_INET, 5900 + $n))) {
  389. close(S);
  390. return 0;
  391. }
  392. close(S);
  393. if (-e "/tmp/.X$n-lock") {
  394. warn "\nWarning: $host:$n is taken because of /tmp/.X$n-lock\n";
  395. warn "Remove this file if there is no X server $host:$n\n";
  396. return 0;
  397. }
  398. if (-e "/tmp/.X11-unix/X$n") {
  399. warn "\nWarning: $host:$n is taken because of /tmp/.X11-unix/X$n\n";
  400. warn "Remove this file if there is no X server $host:$n\n";
  401. return 0;
  402. }
  403. if (-e "/usr/spool/sockets/X11/$n") {
  404. warn("\nWarning: $host:$n is taken because of ".
  405. "/usr/spool/sockets/X11/$n\n");
  406. warn "Remove this file if there is no X server $host:$n\n";
  407. return 0;
  408. }
  409. return 1;
  410. }
  411. #
  412. # quotedString returns a string which yields the original string when parsed
  413. # by a shell.
  414. #
  415. sub quotedString
  416. {
  417. local ($in) = @_;
  418. $in =~ s/\'/\'\"\'\"\'/g;
  419. return "'$in'";
  420. }
  421. #
  422. # removeSlashes turns slashes into underscores for use as a file name.
  423. #
  424. sub removeSlashes
  425. {
  426. local ($in) = @_;
  427. $in =~ s|/|_|g;
  428. return "$in";
  429. }
  430. #
  431. # Usage
  432. #
  433. sub Usage
  434. {
  435. die("\nusage: $prog [:<number>]\n".
  436. " [-fg]\n".
  437. " [-autokill]\n".
  438. " [-noxstartup]\n".
  439. " [-xstartup <file>]\n".
  440. "\n".
  441. " $prog -kill <X-display>\n\n".
  442. " $prog -list\n\n");
  443. }
  444. #
  445. # List
  446. #
  447. sub List
  448. {
  449. opendir(dir, $vncUserDir);
  450. my @filelist = readdir(dir);
  451. closedir(dir);
  452. print "\nTigerVNC server sessions:\n\n";
  453. print "X DISPLAY #\tPROCESS ID\n";
  454. foreach my $file (@filelist) {
  455. if ($file =~ /$host:(\d+)$\.pid/) {
  456. chop($tmp_pid = `cat $vncUserDir/$file`);
  457. if (kill 0, $tmp_pid) {
  458. print ":".$1."\t\t".`cat $vncUserDir/$file`;
  459. } else {
  460. unlink ($vncUserDir . "/" . $file);
  461. }
  462. }
  463. }
  464. exit;
  465. }
  466. #
  467. # Kill
  468. #
  469. sub Kill
  470. {
  471. $opt{'-kill'} =~ s/(:\d+)\.\d+$/$1/; # e.g. turn :1.0 into :1
  472. if ($opt{'-kill'} =~ /^:\d+$/) {
  473. $pidFile = "$vncUserDir/$host$opt{'-kill'}.pid";
  474. } else {
  475. if ($opt{'-kill'} !~ /^$host:/) {
  476. die "\nCan't tell if $opt{'-kill'} is on $host\n".
  477. "Use -kill :<number> instead\n\n";
  478. }
  479. $pidFile = "$vncUserDir/$opt{'-kill'}.pid";
  480. }
  481. if (! -r $pidFile) {
  482. die "\nCan't find file $pidFile\n".
  483. "You'll have to kill the Xvnc process manually\n\n";
  484. }
  485. $SIG{'HUP'} = 'IGNORE';
  486. chop($pid = `cat $pidFile`);
  487. warn "Killing Xvnc process ID $pid\n";
  488. if (kill 0, $pid) {
  489. system("kill $pid");
  490. sleep(1);
  491. if (kill 0, $pid) {
  492. print "Xvnc seems to be deadlocked. Kill the process manually and then re-run\n";
  493. print " ".$0." -kill ".$opt{'-kill'}."\n";
  494. print "to clean up the socket files.\n";
  495. exit
  496. }
  497. } else {
  498. warn "Xvnc process ID $pid already killed\n";
  499. $opt{'-kill'} =~ s/://;
  500. if (-e "/tmp/.X11-unix/X$opt{'-kill'}") {
  501. print "Xvnc did not appear to shut down cleanly.";
  502. print " Removing /tmp/.X11-unix/X$opt{'-kill'}\n";
  503. unlink "/tmp/.X11-unix/X$opt{'-kill'}";
  504. }
  505. if (-e "/tmp/.X$opt{'-kill'}-lock") {
  506. print "Xvnc did not appear to shut down cleanly.";
  507. print " Removing /tmp/.X$opt{'-kill'}-lock\n";
  508. unlink "/tmp/.X$opt{'-kill'}-lock";
  509. }
  510. }
  511. unlink $pidFile;
  512. exit;
  513. }
  514. #
  515. # ParseOptions takes a list of possible options and a boolean indicating
  516. # whether the option has a value following, and sets up an associative array
  517. # %opt of the values of the options given on the command line. It removes all
  518. # the arguments it uses from @ARGV and returns them in @optArgs.
  519. #
  520. sub ParseOptions
  521. {
  522. local (@optval) = @_;
  523. local ($opt, @opts, %valFollows, @newargs);
  524. while (@optval) {
  525. $opt = shift(@optval);
  526. push(@opts,$opt);
  527. $valFollows{$opt} = shift(@optval);
  528. }
  529. @optArgs = ();
  530. %opt = ();
  531. arg: while (defined($arg = shift(@ARGV))) {
  532. foreach $opt (@opts) {
  533. if ($arg eq $opt) {
  534. push(@optArgs, $arg);
  535. if ($valFollows{$opt}) {
  536. if (@ARGV == 0) {
  537. &Usage();
  538. }
  539. $opt{$opt} = shift(@ARGV);
  540. push(@optArgs, $opt{$opt});
  541. } else {
  542. $opt{$opt} = 1;
  543. }
  544. next arg;
  545. }
  546. }
  547. push(@newargs,$arg);
  548. }
  549. @ARGV = @newargs;
  550. }
  551. # Routine to make sure we're operating in a sane environment.
  552. sub SanityCheck
  553. {
  554. local ($cmd);
  555. # Get the program name
  556. ($prog) = ($0 =~ m|([^/]+)$|);
  557. #
  558. # Check we have all the commands we'll need on the path.
  559. #
  560. cmd:
  561. foreach $cmd ("uname","xauth") {
  562. for (split(/:/,$ENV{PATH})) {
  563. if (-x "$_/$cmd") {
  564. next cmd;
  565. }
  566. }
  567. die "$prog: couldn't find \"$cmd\" on your PATH.\n";
  568. }
  569. if($exedir eq "") {
  570. cmd2:
  571. foreach $cmd ("Xvnc","vncpasswd") {
  572. for (split(/:/,$ENV{PATH})) {
  573. if (-x "$_/$cmd") {
  574. next cmd2;
  575. }
  576. }
  577. die "$prog: couldn't find \"$cmd\" on your PATH.\n";
  578. }
  579. }
  580. else {
  581. cmd3:
  582. foreach $cmd ($exedir."Xvnc",$exedir."vncpasswd") {
  583. for (split(/:/,$ENV{PATH})) {
  584. if (-x "$cmd") {
  585. next cmd3;
  586. }
  587. }
  588. die "$prog: couldn't find \"$cmd\".\n";
  589. }
  590. }
  591. if (!defined($ENV{HOME})) {
  592. die "$prog: The HOME environment variable is not set.\n";
  593. }
  594. #
  595. # Find socket constants. 'use Socket' is a perl5-ism, so we wrap it in an
  596. # eval, and if it fails we try 'require "sys/socket.ph"'. If this fails,
  597. # we just guess at the values. If you find perl moaning here, just
  598. # hard-code the values of AF_INET and SOCK_STREAM. You can find these out
  599. # for your platform by looking in /usr/include/sys/socket.h and related
  600. # files.
  601. #
  602. chop($os = `uname`);
  603. chop($osrev = `uname -r`);
  604. eval 'use Socket';
  605. if ($@) {
  606. eval 'require "sys/socket.ph"';
  607. if ($@) {
  608. if (($os eq "SunOS") && ($osrev !~ /^4/)) {
  609. $AF_INET = 2;
  610. $SOCK_STREAM = 2;
  611. } else {
  612. $AF_INET = 2;
  613. $SOCK_STREAM = 1;
  614. }
  615. } else {
  616. $AF_INET = &AF_INET;
  617. $SOCK_STREAM = &SOCK_STREAM;
  618. }
  619. } else {
  620. $AF_INET = &AF_INET;
  621. $SOCK_STREAM = &SOCK_STREAM;
  622. }
  623. }