Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20966
  • 博文数量: 3
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 40
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-06 14:38
文章分类

全部博文(3)

文章存档

2013年(3)

我的朋友

分类: PERL

2013-03-06 14:58:06

转载请注明出处,谢谢!
http://blog.sina.com.cn/s/blog_5e2308c80101hssf.html

点击(此处)折叠或打开

  1. #!/usr/bin//perl
  2. #
  3. # Copyright (C) 2002-2003 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. # This document is translated and commented by 弦上风.
  23. # 本文档由弦上风注释翻译。
  24. # If you have any questions and good comments, please feel free to tell me.
  25. # 如果你有任何问题或者好的建议,请积极联系我。
  26. # @弦上风
  27. # # # # # # # # # # # # # # # # # # # # # # # # # #

  28. #此脚本用来启动一个X VNC 服务器
  29. # vncserver - wrapper script to start an X VNC server.
  30. #

  31. #首先,保证我们在一个稳定可靠的环境进行操作
  32. # First make sure we're operating in a sane environment.
  33. #
  34. #调用脚本下方的SanityCheck子过程
  35. &SanityCheck();

  36. #全局变量,可以针对自己的site进行自定义配置
  37. # Global variables. You may want to configure some of these for your site.
  38. #
  39. #初始化显示的分辨率,默认分辨率
  40. $geometry = "1024x768";
  41. #颜色深度,默认色深
  42. $depth = 16;

  43. #定义vncJavaFiles的目录
  44. $vncJavaFiles = (((-d "/usr/share/vnc/classes") && "/usr/share/vnc/classes") ||
  45.                  ((-d "/usr/local/vnc/classes") && "/usr/local/vnc/classes"));
  46. #定义用户vnc目录
  47. $vncUserDir = "$ENV{HOME}/.vnc";
  48. #定义X验证文件目录
  49. $xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";

  50. #定义默认的Xstartup启动脚本
  51. $defaultXStartup
  52.     = ("#!/bin/shnn".
  53.        "[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresourcesn".
  54.        "xsetroot -solid greyn".
  55.        "vncconfig -iconic &n".
  56.        "xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &n".
  57.        "twm &n");
  58.     
  59. #获取hostname
  60. chop($host = `uname -n`);

  61. #检查命令行选项
  62. # Check command line options
  63. #分析命令行中的参数
  64. &ParseOptions("-geometry",1,"-depth",1,"-pixelformat",1,"-name",1,"-kill",1,
  65.      "-help",0,"-h",0,"--help",0);

  66. #如果命令行中包括"-help","-h","--help",输出使用帮助
  67. &Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});

  68. #如果命令行中带有"-kill"参数,调用Kill子过程
  69. &Kill() if ($opt{'-kill'});

  70. #如果你想使用默认的分辨率,颜色深度和像素格式来匹配当前的X显示,请去掉下面这行注释
  71. # Uncomment this line if you want default geometry, depth and pixelformat
  72. # to match the current X display:

  73. # &GetXDisplayDefaults();

  74. #读取命令行中的分辨率设置,赋给分辨率全局变量
  75. if ($opt{'-geometry'}) {
  76.     $geometry = $opt{'-geometry'};
  77. }
  78. #读取命令行中的颜色深度设置,赋给颜色深度全局变量
  79. if ($opt{'-depth'}) {
  80.     $depth = $opt{'-depth'};
  81.     $pixelformat = "";
  82. }
  83. #读取命令行中的像素格式设置,赋给像素格式全局变量
  84. if ($opt{'-pixelformat'}) {
  85.     $pixelformat = $opt{'-pixelformat'};
  86. }
  87. #调用检查分辨率和色深的子过程
  88. &CheckGeometryAndDepth();

  89. #如果没有则创建用户的vnc目录
  90. # Create the user's vnc directory if necessary.

  91. #如果不存在用户的vnc目录
  92. if (!(-e $vncUserDir)) {
  93. #如果无法创建用户的vnc目录,退出并输出错误提示信息
  94.     if (!mkdir($vncUserDir,0755)) {
  95.     die "$prog: Could not create $vncUserDir.n";
  96.     }
  97. }
  98.     
  99. #保证用户有密码
  100. # Make sure the user has a password.

  101. #获取passwd文件的权限属性
  102. ($z,$z,$mode) = stat("$vncUserDir/passwd");
  103. #如果不存在passwd文件或者非拥有者对该文件具有可读写权限,提示用户需要设置密码
  104. if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
  105.     warn "nYou will require a password to access your desktops.nn";
  106. #从外部系统执行vncpasswd -q $vncUserDir/passwd命令
  107.     system("vncpasswd -q $vncUserDir/passwd");
  108. #判断外部系统退出状态是否为O,不为0则提示错误退出,0是正常退出状态
  109.     if (($? >> 8) != 0) {
  110.     exit 1;
  111.     }
  112. }

  113. #拿到display号
  114. # Find display number.

  115. #如果剩余的命令参数的数量大于0且第一个参数是以:开头,后面是整数
  116. if ((@ARGV > 0) && ($ARGV[0] =~ /^:(d+)$/)) {
  117. #将$1中的值赋给变量$displayNumber
  118.     $displayNumber = $1;
  119. #从左边弹出一个参数
  120.     shift(@ARGV);
  121. #检查输入的display号是否被占用,若被占用,则退出并输出错误提示信息
  122.     if (!&CheckDisplayNumber($displayNumber)) {
  123.     die "A VNC server is already running as :$displayNumbern";
  124.     }
  125. #如果剩余的命令参数的数量大于0且第一个参数不是-开头,则输出使用说明
  126. } elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/)) {
  127.     &Usage();
  128. #如果以上都不符号,则自动分配display号
  129. } else {
  130.     $displayNumber = &GetDisplayNumber();
  131. }
  132. #将5900加上有效的displaynumber赋给变量vncPort
  133. $vncPort = 5900 + $displayNumber;

  134. #定义用户vnc的log路径
  135. $desktopLog = "$vncUserDir/$host:$displayNumber.log";
  136. #删除之前的vnc log
  137. unlink($desktopLog);

  138. #制作一个X server的cookie,作为种子,当前时间,我们的PID,passwd加密格式的一部分
  139. # Make an X server cookie - use as the seed the sum of the current time, our
  140. # PID and part of the encrypted form of the password. Ideally we'd use
  141. # /dev/urandom, but that's only available on Linux.

  142. #用srand函数生成随机数种子提供给rand函数使用
  143. srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
  144. $cookie = "";
  145. for (1..16) {
  146. #生成32位的随机数作为cookie
  147.     $cookie .= sprintf("%02x", int(rand(256)) % 256);
  148. }
  149.     
  150. #调用外部命令为当前的displayNumber在xauth验证文件添加cookie
  151. system("xauth -f $xauthorityFile add $host:$displayNumber . $cookie");
  152. system("xauth -f $xauthorityFile add $host/unix:$displayNumber . $cookie");

  153. #如果数组%opt中的-name参数有值,则将值赋给变量$desktopName
  154. if ($opt{'-name'}) {
  155.     $desktopName = $opt{'-name'};
  156. #如果没有,则取默认的组合值
  157. } else {
  158.     $desktopName = "$host:$displayNumber ($ENV{USER})";
  159. }

  160. #开始启动X VNC服务器
  161. # Now start the X VNC Server

  162. #将之前得到的所有变量连接起来,形成一条完整的命令
  163. $cmd = "Xvnc :$displayNumber";
  164. $cmd .= " -desktop " . &quotedString($desktopName);
  165. $cmd .= " -httpd $vncJavaFiles" if ($vncJavaFiles);
  166. $cmd .= " -auth $xauthorityFile";
  167. $cmd .= " -geometry $geometry" if ($geometry);
  168. $cmd .= " -depth $depth" if ($depth);
  169. $cmd .= " -pixelformat $pixelformat" if ($pixelformat);
  170. $cmd .= " -rfbwait 30000";
  171. $cmd .= " -rfbauth $vncUserDir/passwd";
  172. $cmd .= " -rfbport $vncPort";
  173. $cmd .= " -pn";

  174. #添加字库和颜色相关
  175. # Add font path and color database stuff here, e.g.:
  176. #
  177. # $cmd .= " -fp /usr/lib/X11/fonts/misc/,/usr/lib/X11/fonts/75dpi/";
  178. # $cmd .= " -co /usr/lib/X11/rgb";
  179. #

  180. #循环取出剩余的命令行参数加到命令的末尾
  181. foreach $arg (@ARGV) {
  182.     $cmd .= " " . &quotedString($arg);
  183. }
  184. #将命令执行结果输出到vnc目录下的log中,包括标准错误输出
  185. $cmd .= " >> " . &quotedString($desktopLog) . " 2>&1";

  186. #运行cmd命令并记录进程ID
  187. # Run $cmd and record the process ID.

  188. #定义进程ID文件路径
  189. $pidFile = "$vncUserDir/$host:$displayNumber.pid";
  190. #执行cmd中的命令并将进程ID写入文件$pidFile
  191. system("$cmd & echo $! >$pidFile");

  192. #启动Xvnc
  193. # Give Xvnc a chance to start up

  194. #等待3秒
  195. sleep(3);
  196. #提示vncserver启动成功
  197. warn "nNew '$desktopName' desktop is $host:$displayNumbernn";

  198. #创建用户的启动脚本
  199. # Create the user's xstartup script if necessary.

  200. #如果用户启动脚本不存在
  201. if (!(-e "$vncUserDir/xstartup")) {
  202. #提示创建默认的启动脚本,存放在vnc用户目录下
  203.     warn "Creating default startup script $vncUserDir/xstartupn";
  204. #以写权限打开用户启动脚本
  205.     open(XSTARTUP, ">$vncUserDir/xstartup");
  206. #将默认启动参数写入启动脚本中
  207.     print XSTARTUP $defaultXStartup;
  208. #关闭脚本文件
  209.     close(XSTARTUP);
  210. #给脚本文件增加755的权限
  211.     chmod 0755, "$vncUserDir/xstartup";
  212. }

  213. #运行用户脚本文件
  214. # Run the X startup script.

  215. #提示按照用户目录下的脚本启动程序
  216. warn "Starting applications specified in $vncUserDir/xstartupn";
  217. #提示log文件存放在用户目录下
  218. warn "Log file is $desktopLognn";

  219. #如果存在unix domain socket,则设置环境变量$DISPLAY=:n,否则使用TCP socket,设置环境变量$DISPLAY=host:n
  220. # If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
  221. # TCP (DISPLAY=host:n)

  222. #如果tmp目录下存在对应的socket文件或者usr的sockets目录下存在对应的文件
  223. if (-e "/tmp/.X11-unix/X$displayNumber" ||
  224.     -e "/usr/spool/sockets/X11/$displayNumber")
  225. {
  226. #设置环境变量DISPLAY=:n
  227.     $ENV{DISPLAY}= ":$displayNumber";
  228. } else {
  229. #否则设置环境变量DISPLAY=host:n
  230.     $ENV{DISPLAY}= "$host:$displayNumber";
  231. }
  232. #设置环境变量$VNCDESKTOP
  233. $ENV{VNCDESKTOP}= $desktopName;

  234. #调用外部命令执行xstartup脚本并将标准输出和错误追加到日志里
  235. system("$vncUserDir/xstartup >> " . "edString($desktopLog) . " 2>&1 &");

  236. exit;


  237. ###############################################################################
  238. #
  239. # CheckGeometryAndDepth simply makes sure that the geometry and depth values
  240. # are sensible.
  241. #简单的检查分辨率和颜色深度

  242. sub CheckGeometryAndDepth
  243. {
  244. #如果分辨率是按照整数x整数格式
  245.     if ($geometry =~ /^(d+)x(d+)$/) {
  246. #取第一个整数作为宽,第二个整数作为高
  247.         $width = $1; $height = $2;
  248. #如果宽和高其中一个小于1,退出并提示错误信息
  249.         if (($width<1) || ($height<1)) {
  250.             die "$prog: geometry $geometry is invalidn";
  251.         }
  252. #保证分辨率的宽是4的倍数
  253.         while (($width % 4)!=0) {
  254.             $width = $width + 1;
  255.         }

  256. #保证分辨率的高是2的倍数
  257.         while (($height % 2)!=0) {
  258.             $height = $height + 1;
  259.         }
  260. #算出分辨率并赋给变量$geometry
  261.         $geometry = "${width}x$height";
  262.     } else {
  263. #如果分辨率格式不对,退出并提示错误
  264.         die "$prog: geometry $geometry is invalidn";
  265.     }
  266. #如果颜色深度不是8到32,退出并提示错误
  267.     if (($depth < 8) || ($depth > 32)) {
  268.         die "Depth must be between 8 and 32n";
  269.     }
  270. }


  271. #从最低有效的display号匹配
  272. # GetDisplayNumber gets the lowest available display number. A display number
  273. # n is taken if something is listening on the VNC server port (5900+n) or the
  274. # X server port (6000+n).
  275. #

  276. sub GetDisplayNumber
  277. {
  278. #检查1到99的display号是否被占用,没被占用就返回该号码,全被占用则退出输出错误提示信息
  279.     foreach $n (1..99) {
  280.     if (&CheckDisplayNumber($n)) {
  281.      return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
  282.     }
  283.     }
  284.     
  285.     die "$prog: no free display number on $host.n";
  286. }


  287. #检查DisplayNumber,判断是否命令行给定的DisplayNumber是可用的。判断给定端口是否被其他程序占用
  288. # CheckDisplayNumber checks if the given display number is available. A
  289. # display number n is taken if something is listening on the VNC server port
  290. # (5900+n) or the X server port (6000+n).
  291. #

  292. sub CheckDisplayNumber
  293. {
  294.     local ($n) = @_;
  295.     
  296. #Perl的函数Socket的格式为:Socket(FILE,Domain,Type,Protocol);
  297. #其中:
  298. #FILE 绑定一个套接字句柄(类似于打开文件的句柄);
  299. #Domain 表示套接字的协议域类型。它可以定义为Internet域,其值为2,也可以定义为UNIX域,如果把这个变量赋值为1表示域的类型为UNIX域。如果这个变量付值为2,则表示定义类型为Internet。我们常用的是的套接字协议族为Internet协议族。
  300. #Type 表示套接字类型,定义为SOCK_STREAM类型,表示的是基于流传输模式的TCP套接字。定义为SOCK_DGRAM类型,表示为基于简单数据传递的UDP套接字。
  301. #Protocol 表示套接字的协议号,这个协议号可以通过Perl内置函数getprotobyname()得到

  302. #打开一个internet域的TCP套接字,如果失败,退出并提示错误信息
  303.     socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!n";
  304. #设置socket选项,并捕获错误信息
  305.     eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  306. #如果绑定失败,关闭套接字,返回0
  307.     if (!bind(S, pack('S n x12', $AF_INET, 6000 + $n))) {
  308.         close(S);
  309.         return 0;
  310.     }
  311.     close(S);

  312. #打开一个internet域的TCP套接字,如果失败,退出并提示错误信息
  313.     socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!n";
  314. #设置socket选项,并捕获错误信息
  315.     eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
  316. #如果绑定失败,关闭套接字,返回0
  317.     if (!bind(S, pack('S n x12', $AF_INET, 5900 + $n))) {
  318.         close(S);
  319.         return 0;
  320.     }
  321.     close(S);

  322. #如果tmp目录下存在-lock,提示警告信息
  323.     if (-e "/tmp/.X$n-lock") {
  324.         warn "nWarning: $host:$n is taken because of /tmp/.X$n-lockn";
  325.         warn "Remove this file if there is no X server $host:$nn";
  326.         return 0;
  327.     }

  328. #如果tmp目录下存在socket文件,提示警告信息
  329.     if (-e "/tmp/.X11-unix/X$n") {
  330.         warn "nWarning: $host:$n is taken because of /tmp/.X11-unix/X$nn";
  331.         warn "Remove this file if there is no X server $host:$nn";
  332.         return 0;
  333.     }

  334. #如果/usr/spool/sockets目录下存在socket文件,提示警告信息
  335.     if (-e "/usr/spool/sockets/X11/$n") {
  336.         warn("nWarning: $host:$n is taken because of ".
  337.              "/usr/spool/sockets/X11/$nn");
  338.         warn "Remove this file if there is no X server $host:$nn";
  339.         return 0;
  340.     }

  341.     return 1;
  342. }


  343. #
  344. # GetXDisplayDefaults uses xdpyinfo to find out the geometry, depth and pixel
  345. # format of the current X display being used. If successful, it sets the
  346. # options as appropriate so that the X VNC server will use the same settings
  347. # (minus an allowance for window manager decorations on the geometry). Using
  348. # the same depth and pixel format means that the VNC server won't have to
  349. # translate pixels when the desktop is being viewed on this X display (for
  350. # TrueColor displays anyway).
  351. #

  352. sub GetXDisplayDefaults
  353. {
  354. #定义本地标量和列表变量
  355.     local (@lines, @matchlines, $width, $height, $defaultVisualId, $i,
  356.      $red, $green, $blue);

  357. #wmDecorationWidth (class WmDecorationWidth)
  358. #For calculating maximum VNC window size. Default 4.
  359. #wmDecorationHeight (class WmDecorationHeight)
  360. #For calculating maximum VNC window size. Default 24.
  361. #不明白这两个变量是用来干嘛的,个人猜测是窗口的边框。decoration是装饰的意思,窗口渲染时,大小必须去掉装饰的长宽
  362.     $wmDecorationWidth = 4;    # a guess at typical size for window manager
  363.     $wmDecorationHeight = 24;    # decoration size

  364. #如果没有定义环境变量DISPLAY,就直接返回
  365.     return if (!defined($ENV{DISPLAY}));
  366. #利用unix下的xdpyinfo工具读取相关的显示信息,赋给数组@lines
  367.     @lines = `xdpyinfo 2>/dev/null`;

  368. #如果上一个外部命令执行错误,则直接返回
  369.     return if ($? != 0);

  370. #找到分辨率,将分辨率赋值给数组
  371.     @matchlines = grep(/dimensions/, @lines);
  372. #如果数组里有值
  373.     if (@matchlines) {
  374. #将数组中字符串通过正则表达式将宽和高取出赋给列表中的两个变量
  375.         ($width, $height) = ($matchlines[0] =~ /(d+)x(d+) pixels/);

  376. #去掉装饰的长宽,个人理解是去掉边框
  377.         $width -= $wmDecorationWidth;
  378.         $height -= $wmDecorationHeight;

  379. #将得到的宽高赋给分辨率变量
  380.         $geometry = "${width}x$height";
  381.     }

  382. #找到默认图像ID
  383.     @matchlines = grep(/default visual id/, @lines);
  384.     if (@matchlines) {
  385. #取出默认图像ID
  386.     ($defaultVisualId) = ($matchlines[0] =~ /id:s+(S+)/);

  387. #遍历数组@lines中所有的元素,查找默认图像ID对应的TrueColor,depth以及RGB
  388.     for ($i = 0; $i < @lines; $i++) {
  389.      if ($lines[$i] =~ /^s*visual id:s+$defaultVisualId$/) {
  390. #如果找不到TrueColor,depth,RGB任何一个,直接返回
  391.             if (($lines[$i+1] !~ /TrueColor/) ||
  392.                 ($lines[$i+2] !~ /depth/) ||
  393.                 ($lines[$i+4] !~ /red, green, blue masks/))
  394.             {
  395.                 return;
  396.             }
  397.             last;
  398.      }
  399.     }
  400. #如果遍历的所有的元素,找不到匹配的元素,直接返回
  401.     return if ($i >= @lines);

  402. #将找到的默认色深赋给变量$depth
  403.     ($depth) = ($lines[$i+2] =~ /depth:s+(d+)/);
  404. #将找到的默认RGB色彩模式值赋给变量
  405.     ($red,$green,$blue)
  406.      = ($lines[$i+4]
  407.      =~ /masks:s+0x([0-9a-f]+), 0x([0-9a-f]+), 0x([0-9a-f]+)/);

  408. #将十六进制转换成十进制
  409.     $red = hex($red);
  410.     $green = hex($green);
  411.     $blue = hex($blue);

  412. #计算红绿蓝然后得出像素格式,不懂图形学,不知道这些公式干嘛的...囧
  413.     if ($red > $blue) {
  414.      $red = int(log($red) / log(2)) - int(log($green) / log(2));
  415.      $green = int(log($green) / log(2)) - int(log($blue) / log(2));
  416.      $blue = int(log($blue) / log(2)) + 1;
  417.      $pixelformat = "rgb$red$green$blue";
  418.     } else {
  419.      $blue = int(log($blue) / log(2)) - int(log($green) / log(2));
  420.      $green = int(log($green) / log(2)) - int(log($red) / log(2));
  421.      $red = int(log($red) / log(2)) + 1;
  422.      $pixelformat = "bgr$blue$green$red";
  423.     }
  424.     }
  425. }


  426. #没明白这个子过程有什么用...把'替换成'"'"',然后再加上'',不明白意图~囧
  427. # quotedString returns a string which yields the original string when parsed
  428. # by a shell.
  429. #

  430. sub quotedString
  431. {
  432.     local ($in) = @_;

  433.     $in =~ s/'/'"'"'/g;

  434.     return "'$in'";
  435. }


  436. #移除斜线号,用下划线取代
  437. # removeSlashes turns slashes into underscores for use as a file name.
  438. #

  439. sub removeSlashes
  440. {
  441.     local ($in) = @_;

  442. #将斜线替换成下划线
  443.     $in =~ s|/|_|g;

  444.     return "$in";
  445. }


  446. #
  447. # Usage
  448. #

  449. #输入格式错误时,提示使用方法
  450. sub Usage
  451. {
  452.     die("nusage: $prog [:] [-name ] [-depth ]n".
  453.     " [-geometry x]n".
  454.     " [-pixelformat rgbNNN|bgrNNN]n".
  455.     " ...nn".
  456.     " $prog -kill nn");
  457. }


  458. #
  459. # Kill
  460. #

  461. sub Kill
  462. {
  463. #转换格式,看句末注释
  464.     $opt{'-kill'} =~ s/(:d+).d+$/$1/; # e.g. turn :1.0 into :1

  465. #如果-kill参数值合法
  466.     if ($opt{'-kill'} =~ /^:d+$/) {
  467. #将对应的pid文件路径赋给变量$pidFile
  468.         $pidFile = "$vncUserDir/$host$opt{'-kill'}.pid";
  469.     } else {
  470. #如果-kill参数值不以$host:开头,退出并提示错误信息
  471.         if ($opt{'-kill'} !~ /^$host:/) {
  472.             die "nCan't tell if $opt{'-kill'} is on $hostn".
  473.             "Use -kill : insteadnn";
  474.         }
  475. #将对应的pid文件路径赋给变量
  476.         $pidFile = "$vncUserDir/$opt{'-kill'}.pid";
  477.     }
  478. #如果pid文件不可读,退出并提示错误信息
  479.     if (! -r $pidFile) {
  480.     die "nCan't find file $pidFilen".
  481.      "You'll have to kill the Xvnc process manuallynn";
  482.     }
  483. #
  484.     $SIG{'HUP'} = 'IGNORE';
  485. #读出pid并去除末尾的回车符
  486.     chop($pid = `cat $pidFile`);
  487. #提示杀死Xvnc进行
  488.     warn "Killing Xvnc process ID $pidn";
  489. #调用外部系统杀死进程
  490.     system("kill $pid");
  491. #删除进程文件
  492.     unlink $pidFile;
  493. #退出
  494.     exit;
  495. }


  496. #
  497. # ParseOptions takes a list of possible options and a boolean indicating
  498. # whether the option has a value following, and sets up an associative array
  499. # %opt of the values of the options given on the command line. It removes all
  500. # the arguments it uses from @ARGV and returns them in @optArgs.
  501. #
  502. #分析选项
  503. sub ParseOptions
  504. {
  505. #将模板里的参数读到数组@optval
  506.     local (@optval) = @_;
  507.     
  508. #定义局部变量$opt,数组@opts,@newargs,哈希表%valFollows
  509.     local ($opt, @opts, %valFollows, @newargs);

  510. #利用while循环取出数组中下标为单数的标量值作为哈希表的键,下标为双数的标量值作为哈希表的值
  511.     while (@optval) {
  512. #从左侧弹出下标为单数的标量值赋给变量$opt
  513.     $opt = shift(@optval);
  514. #将弹出的标量值从右侧弹入数组@opts
  515.     push(@opts,$opt);
  516. #从左侧弹出下标为双数的标量值赋给对应的哈希表的键
  517.     $valFollows{$opt} = shift(@optval);
  518.     }
  519. #定义空的数组和哈希表
  520.     @optArgs = ();
  521.     %opt = ();

  522. #利用while循环读取命令行参数
  523.     arg: while (defined($arg = shift(@ARGV))) {
  524. #利用foreach循环读取数组@opts中的值与命令行中对应的值
  525.         foreach $opt (@opts) {
  526.             if ($arg eq $opt) {
  527. #将命令行中的参数从右侧弹入数组@optArgs
  528.                 push(@optArgs, $arg);
  529. #如果哈希表%valFollows中键的预设值不为0
  530.                 if ($valFollows{$opt}) {
  531. #如果命令行中只输入了一个参数且不带参数值(如果两个参数连在一起,中间没有参数值怎么办?)
  532.                     if (@ARGV == 0) {
  533. #提示使用方法
  534.                         &Usage();
  535.                     }
  536. #将命令行中的参数值赋给哈希表%opt对应的键
  537.                     $opt{$opt} = shift(@ARGV);
  538. #将哈希表中的值存入数组@optArgs中
  539.                     push(@optArgs, $opt{$opt});
  540.                 } else {
  541. #如果哈希表%valFollows中键的预设值为0
  542.                     $opt{$opt} = 1;
  543.                 }
  544. #读取下一个命令行参数
  545.                 next arg;
  546.             }
  547.         }
  548. #将命令行中无法匹配模板的参数存入数组@newargs
  549.         push(@newargs,$arg);
  550.     }
  551. #将没能匹配上的命令行参数重新赋给@ARGV
  552.     @ARGV = @newargs;
  553. }


  554. #例行检查,保证我们在一个可靠的环境中操作
  555. # Routine to make sure we're operating in a sane environment.
  556. #

  557. sub SanityCheck
  558. {
  559.     #定义本地变量,local相当于my
  560.     local ($cmd);

  561.     #下面的正则表达将获取程序的名字
  562.     # Get the program name
  563.     #
  564.     #"=~"叫做绑定操作符,绑定右侧的正则表达式与左侧的$0,默认的右侧正则表达式会与perl默认的变量$_进行匹配。
  565.     #m||,m是perl正则表达式(模式匹配)操作符的缩写match
  566.     ($prog) = ($0 =~ m|([^/]+)$|);

  567.     #检查环境变量PATH中包含我们所需要的命令
  568.     # Check we have all the commands we'll need on the path.
  569.     #

  570.  cmd:
  571.     #foreach循环,每次取括号中的一个参数赋给$cmd
  572.     foreach $cmd ("uname","xauth","Xvnc","vncpasswd") {
  573.     #用split操作符将PATH环境变量通过符号":"拆分开,通过循环取出环境变量赋给$_,判断$_目录中的$cmd是否有可执行权限,$_是perl的默认变量
  574.         for (split(/:/,$ENV{PATH})) {
  575.     #检查当前用户对$cmd命令是否具有可执行的权限
  576.             if (-x "$_/$cmd") {
  577.     #如果找到了第一个可执行的$cmd,就检查下一个$cmd
  578.             next cmd;
  579.             }
  580.         }
  581.     #如果遍历了PATH环境变量,找不到可执行的$cmd,则打印出没找到的$cmd并退出程序
  582.     #函数名:die
  583.     #调用语法:die (message);
  584.     #解说:终止程序并向STDERR输出错误信息。message可以为字符串或列表。如果最后一个参数不包含换行符,则程序文件名和行号也被输出。
  585.         die "$prog: couldn't find "$cmd" on your PATH.n";
  586.     }

  587.     #
  588.     # Check the HOME environment variable is set
  589.     #检查家目录环境变量已经设置好了

  590.     #如果查询发现家目录的环境变量没有定义,则打印出家目录环境变量没设置并退出程序
  591.     if (!defined($ENV{HOME})) {
  592.         die "$prog: The HOME environment variable is not set.n";
  593.     }
  594.     #改变目录到用户的家目录
  595.     chdir($ENV{HOME});

  596.     #
  597.     # Find socket constants. 'use Socket' is a perl5-ism, so we wrap it in an
  598.     # eval, and if it fails we try 'require "sys/socket.ph"'. If this fails,
  599.     # we just guess at the values. If you find perl moaning here, just
  600.     # hard-code the values of AF_INET and SOCK_STREAM. You can find these out
  601.     # for your platform by looking in /usr/include/sys/socket.h and related
  602.     # files.
  603.     #

  604.     #获取操作系统的名字
  605.     chop($os = `uname`);
  606.     #获取操作系统的版本
  607.     chop($osrev = `uname -r`);

  608.     #执行perl目录下的Socket.pm查找AF_INET和SOCK_STREAM
  609.     eval 'use Socket';
  610.     # $@存储 Perl解释器从eval语句返回的错误消息,如果$@有内容的话,就接着查找sys/socket.ph
  611.     if ($@) {
  612.     #检查是否能够找到sys/socket.ph
  613.         eval 'require "sys/socket.ph"';
  614.     #如果$@有内容的话,表示require失败
  615.         if ($@) {
  616.     #通过判断操作系统是SunOS,如果版本是非4的话,hard-code AF_INET=2和SOCK_STREAM=2,如果版本是4的话,hard-code AF_INET=2和SOCK_STREAM=1
  617.             if (($os eq "SunOS") && ($osrev !~ /^4/)) {
  618.                 $AF_INET = 2;
  619.                 $SOCK_STREAM = 2;
  620.             } else {
  621.                 $AF_INET = 2;
  622.                 $SOCK_STREAM = 1;
  623.             }
  624.     #如果require成功的话,就取sys/socket.ph里面的地址组和流套接字的值
  625.         } else {
  626.             $AF_INET = &AF_INET;
  627.             $SOCK_STREAM = &SOCK_STREAM;
  628.         }
  629.     #如果use Socket成功的话,就取Socket.pm里面的地址组和流套接字的值
  630.     } else {
  631.         $AF_INET = &AF_INET;
  632.         $SOCK_STREAM = &SOCK_STREAM;
  633.     }
  634. }

阅读(3155) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~