- 论坛徽章:
- 0
|
本帖最后由 xiaozi0lei 于 2013-03-05 13:32 编辑
转载请注明出处,谢谢!
http://blog.sina.com.cn/s/blog_5e2308c80101hssf.html
- #!/usr/bin//perl
- #
- # Copyright (C) 2002-2003 RealVNC Ltd.
- # Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
- #
- # This is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This software is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this software; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- # USA.
- #
- # # # # # # # # # # # # # # # # # # # # # # # # # #
- # This document is translated and commented by 弦上风.
- # 本文档由弦上风注释翻译。
- # If you have any questions and good comments, please feel free to tell me.
- # 如果你有任何问题或者好的建议,请积极联系我。
- # @弦上风
- # # # # # # # # # # # # # # # # # # # # # # # # # #
- #此脚本用来启动一个X VNC 服务器
- # vncserver - wrapper script to start an X VNC server.
- #
- #首先,保证我们在一个稳定可靠的环境进行操作
- # First make sure we're operating in a sane environment.
- #
- #调用脚本下方的SanityCheck子过程
- &SanityCheck();
- #全局变量,可以针对自己的site进行自定义配置
- # Global variables. You may want to configure some of these for your site.
- #
- #初始化显示的分辨率,默认分辨率
- $geometry = "1024x768";
- #颜色深度,默认色深
- $depth = 16;
- #定义vncJavaFiles的目录
- $vncJavaFiles = (((-d "/usr/share/vnc/classes") && "/usr/share/vnc/classes") ||
- ((-d "/usr/local/vnc/classes") && "/usr/local/vnc/classes"));
- #定义用户vnc目录
- $vncUserDir = "$ENV{HOME}/.vnc";
- #定义X验证文件目录
- $xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
- #定义默认的Xstartup启动脚本
- $defaultXStartup
- = ("#!/bin/sh\n\n".
- "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n".
- "xsetroot -solid grey\n".
- "vncconfig -iconic &\n".
- "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n".
- "twm &\n");
-
- #获取hostname
- chop($host = `uname -n`);
- #检查命令行选项
- # Check command line options
- #分析命令行中的参数
- &ParseOptions("-geometry",1,"-depth",1,"-pixelformat",1,"-name",1,"-kill",1,
- "-help",0,"-h",0,"--help",0);
- #如果命令行中包括"-help","-h","--help",输出使用帮助
- &Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});
- #如果命令行中带有"-kill"参数,调用Kill子过程
- &Kill() if ($opt{'-kill'});
- #如果你想使用默认的分辨率,颜色深度和像素格式来匹配当前的X显示,请去掉下面这行注释
- # Uncomment this line if you want default geometry, depth and pixelformat
- # to match the current X display:
- # &GetXDisplayDefaults();
- #读取命令行中的分辨率设置,赋给分辨率全局变量
- if ($opt{'-geometry'}) {
- $geometry = $opt{'-geometry'};
- }
- #读取命令行中的颜色深度设置,赋给颜色深度全局变量
- if ($opt{'-depth'}) {
- $depth = $opt{'-depth'};
- $pixelformat = "";
- }
- #读取命令行中的像素格式设置,赋给像素格式全局变量
- if ($opt{'-pixelformat'}) {
- $pixelformat = $opt{'-pixelformat'};
- }
- #调用检查分辨率和色深的子过程
- &CheckGeometryAndDepth();
- #如果没有则创建用户的vnc目录
- # Create the user's vnc directory if necessary.
- #如果不存在用户的vnc目录
- if (!(-e $vncUserDir)) {
- #如果无法创建用户的vnc目录,退出并输出错误提示信息
- if (!mkdir($vncUserDir,0755)) {
- die "$prog: Could not create $vncUserDir.\n";
- }
- }
-
- #保证用户有密码
- # Make sure the user has a password.
- #获取passwd文件的权限属性
- ($z,$z,$mode) = stat("$vncUserDir/passwd");
- #如果不存在passwd文件或者非拥有者对该文件具有可读写权限,提示用户需要设置密码
- if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
- warn "\nYou will require a password to access your desktops.\n\n";
- #从外部系统执行vncpasswd -q $vncUserDir/passwd命令
- system("vncpasswd -q $vncUserDir/passwd");
- #判断外部系统退出状态是否为O,不为0则提示错误退出,0是正常退出状态
- if (($? >> 8) != 0) {
- exit 1;
- }
- }
- #拿到display号
- # Find display number.
- #如果剩余的命令参数的数量大于0且第一个参数是以:开头,后面是整数
- if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
- #将$1中的值赋给变量$displayNumber
- $displayNumber = $1;
- #从左边弹出一个参数
- shift(@ARGV);
- #检查输入的display号是否被占用,若被占用,则退出并输出错误提示信息
- if (!&CheckDisplayNumber($displayNumber)) {
- die "A VNC server is already running as :$displayNumber\n";
- }
- #如果剩余的命令参数的数量大于0且第一个参数不是-开头,则输出使用说明
- } elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/)) {
- &Usage();
- #如果以上都不符号,则自动分配display号
- } else {
- $displayNumber = &GetDisplayNumber();
- }
- #将5900加上有效的displaynumber赋给变量vncPort
- $vncPort = 5900 + $displayNumber;
- #定义用户vnc的log路径
- $desktopLog = "$vncUserDir/$host:$displayNumber.log";
- #删除之前的vnc log
- unlink($desktopLog);
- #制作一个X server的cookie,作为种子,当前时间,我们的PID,passwd加密格式的一部分
- # Make an X server cookie - use as the seed the sum of the current time, our
- # PID and part of the encrypted form of the password. Ideally we'd use
- # /dev/urandom, but that's only available on Linux.
- #用srand函数生成随机数种子提供给rand函数使用
- srand(time+$+unpack("L",`cat $vncUserDir/passwd`));
- $cookie = "";
- for (1..16) {
- #生成32位的随机数作为cookie
- $cookie .= sprintf("%02x", int(rand(256)) % 256);
- }
-
- #调用外部命令为当前的displayNumber在xauth验证文件添加cookie
- system("xauth -f $xauthorityFile add $host:$displayNumber . $cookie");
- system("xauth -f $xauthorityFile add $host/unix:$displayNumber . $cookie");
- #如果数组%opt中的-name参数有值,则将值赋给变量$desktopName
- if ($opt{'-name'}) {
- $desktopName = $opt{'-name'};
- #如果没有,则取默认的组合值
- } else {
- $desktopName = "$host:$displayNumber ($ENV{USER})";
- }
- #开始启动X VNC服务器
- # Now start the X VNC Server
- #将之前得到的所有变量连接起来,形成一条完整的命令
- $cmd = "Xvnc :$displayNumber";
- $cmd .= " -desktop " . "edString($desktopName);
- $cmd .= " -httpd $vncJavaFiles" if ($vncJavaFiles);
- $cmd .= " -auth $xauthorityFile";
- $cmd .= " -geometry $geometry" if ($geometry);
- $cmd .= " -depth $depth" if ($depth);
- $cmd .= " -pixelformat $pixelformat" if ($pixelformat);
- $cmd .= " -rfbwait 30000";
- $cmd .= " -rfbauth $vncUserDir/passwd";
- $cmd .= " -rfbport $vncPort";
- $cmd .= " -pn";
- #添加字库和颜色相关
- # Add font path and color database stuff here, e.g.:
- #
- # $cmd .= " -fp /usr/lib/X11/fonts/misc/,/usr/lib/X11/fonts/75dpi/";
- # $cmd .= " -co /usr/lib/X11/rgb";
- #
- #循环取出剩余的命令行参数加到命令的末尾
- foreach $arg (@ARGV) {
- $cmd .= " " . "edString($arg);
- }
- #将命令执行结果输出到vnc目录下的log中,包括标准错误输出
- $cmd .= " >> " . "edString($desktopLog) . " 2>&1";
- #运行cmd命令并记录进程ID
- # Run $cmd and record the process ID.
- #定义进程ID文件路径
- $pidFile = "$vncUserDir/$host:$displayNumber.pid";
- #执行cmd中的命令并将进程ID写入文件$pidFile
- system("$cmd & echo \$! >$pidFile");
- #启动Xvnc
- # Give Xvnc a chance to start up
- #等待3秒
- sleep(3);
- #提示vncserver启动成功
- warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
- #创建用户的启动脚本
- # Create the user's xstartup script if necessary.
- #如果用户启动脚本不存在
- if (!(-e "$vncUserDir/xstartup")) {
- #提示创建默认的启动脚本,存放在vnc用户目录下
- warn "Creating default startup script $vncUserDir/xstartup\n";
- #以写权限打开用户启动脚本
- open(XSTARTUP, ">$vncUserDir/xstartup");
- #将默认启动参数写入启动脚本中
- print XSTARTUP $defaultXStartup;
- #关闭脚本文件
- close(XSTARTUP);
- #给脚本文件增加755的权限
- chmod 0755, "$vncUserDir/xstartup";
- }
- #运行用户脚本文件
- # Run the X startup script.
- #提示按照用户目录下的脚本启动程序
- warn "Starting applications specified in $vncUserDir/xstartup\n";
- #提示log文件存放在用户目录下
- warn "Log file is $desktopLog\n\n";
- #如果存在unix domain socket,则设置环境变量$DISPLAY=:n,否则使用TCP socket,设置环境变量$DISPLAY=host:n
- # If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
- # TCP (DISPLAY=host:n)
- #如果tmp目录下存在对应的socket文件或者usr的sockets目录下存在对应的文件
- if (-e "/tmp/.X11-unix/X$displayNumber" ||
- -e "/usr/spool/sockets/X11/$displayNumber")
- {
- #设置环境变量DISPLAY=:n
- $ENV{DISPLAY}= ":$displayNumber";
- } else {
- #否则设置环境变量DISPLAY=host:n
- $ENV{DISPLAY}= "$host:$displayNumber";
- }
- #设置环境变量$VNCDESKTOP
- $ENV{VNCDESKTOP}= $desktopName;
- #调用外部命令执行xstartup脚本并将标准输出和错误追加到日志里
- system("$vncUserDir/xstartup >> " . "edString($desktopLog) . " 2>&1 &");
- exit;
- ###############################################################################
- #
- # CheckGeometryAndDepth simply makes sure that the geometry and depth values
- # are sensible.
- #简单的检查分辨率和颜色深度
- sub CheckGeometryAndDepth
- {
- #如果分辨率是按照整数x整数格式
- if ($geometry =~ /^(\d+)x(\d+)$/) {
- #取第一个整数作为宽,第二个整数作为高
- $width = $1; $height = $2;
- #如果宽和高其中一个小于1,退出并提示错误信息
- if (($width<1) || ($height<1)) {
- die "$prog: geometry $geometry is invalid\n";
- }
- #保证分辨率的宽是4的倍数
- while (($width % 4)!=0) {
- $width = $width + 1;
- }
- #保证分辨率的高是2的倍数
- while (($height % 2)!=0) {
- $height = $height + 1;
- }
- #算出分辨率并赋给变量$geometry
- $geometry = "${width}x$height";
- } else {
- #如果分辨率格式不对,退出并提示错误
- die "$prog: geometry $geometry is invalid\n";
- }
- #如果颜色深度不是8到32,退出并提示错误
- if (($depth < 8) || ($depth > 32)) {
- die "Depth must be between 8 and 32\n";
- }
- }
- #从最低有效的display号匹配
- # GetDisplayNumber gets the lowest available display number. A display number
- # n is taken if something is listening on the VNC server port (5900+n) or the
- # X server port (6000+n).
- #
- sub GetDisplayNumber
- {
- #检查1到99的display号是否被占用,没被占用就返回该号码,全被占用则退出输出错误提示信息
- foreach $n (1..99) {
- if (&CheckDisplayNumber($n)) {
- return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
- }
- }
-
- die "$prog: no free display number on $host.\n";
- }
- #检查DisplayNumber,判断是否命令行给定的DisplayNumber是可用的。判断给定端口是否被其他程序占用
- # CheckDisplayNumber checks if the given display number is available. A
- # display number n is taken if something is listening on the VNC server port
- # (5900+n) or the X server port (6000+n).
- #
- sub CheckDisplayNumber
- {
- local ($n) = @_;
-
- #Perl的函数Socket的格式为:Socket(FILE,Domain,Type,Protocol);
- #其中:
- #FILE 绑定一个套接字句柄(类似于打开文件的句柄);
- #Domain 表示套接字的协议域类型。它可以定义为Internet域,其值为2,也可以定义为UNIX域,如果把这个变量赋值为1表示域的类型为UNIX域。如果这个变量付值为2,则表示定义类型为Internet。我们常用的是的套接字协议族为Internet协议族。
- #Type 表示套接字类型,定义为SOCK_STREAM类型,表示的是基于流传输模式的TCP套接字。定义为SOCK_DGRAM类型,表示为基于简单数据传递的UDP套接字。
- #Protocol 表示套接字的协议号,这个协议号可以通过Perl内置函数getprotobyname()得到
- #打开一个internet域的TCP套接字,如果失败,退出并提示错误信息
- socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
- #设置socket选项,并捕获错误信息
- eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
- #如果绑定失败,关闭套接字,返回0
- if (!bind(S, pack('S n x12', $AF_INET, 6000 + $n))) {
- close(S);
- return 0;
- }
- close(S);
- #打开一个internet域的TCP套接字,如果失败,退出并提示错误信息
- socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
- #设置socket选项,并捕获错误信息
- eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
- #如果绑定失败,关闭套接字,返回0
- if (!bind(S, pack('S n x12', $AF_INET, 5900 + $n))) {
- close(S);
- return 0;
- }
- close(S);
- #如果tmp目录下存在-lock,提示警告信息
- if (-e "/tmp/.X$n-lock") {
- warn "\nWarning: $host:$n is taken because of /tmp/.X$n-lock\n";
- warn "Remove this file if there is no X server $host:$n\n";
- return 0;
- }
- #如果tmp目录下存在socket文件,提示警告信息
- if (-e "/tmp/.X11-unix/X$n") {
- warn "\nWarning: $host:$n is taken because of /tmp/.X11-unix/X$n\n";
- warn "Remove this file if there is no X server $host:$n\n";
- return 0;
- }
- #如果/usr/spool/sockets目录下存在socket文件,提示警告信息
- if (-e "/usr/spool/sockets/X11/$n") {
- warn("\nWarning: $host:$n is taken because of ".
- "/usr/spool/sockets/X11/$n\n");
- warn "Remove this file if there is no X server $host:$n\n";
- return 0;
- }
- return 1;
- }
复制代码 |
|