1 rizwank 1.1 #!/usr/bin/perl -w
2 #
3 # TWiki Collaboration Platform, http://TWiki.org/
4 #
5 # Copyright (C) 2000-2004 Peter Thoeny, peter@thoeny.com
6 #
7 # For licensing info read license.txt file in the TWiki root.
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 2
11 # of the License, or (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details, published at
17 # http://www.gnu.org/copyleft/gpl.html
18 #
19 # DESCRIPTION: Test utility to see if CGI is running and enabled
20 # for the bin directory, and check a variety of TWiki, Perl and RCS
21 # setup.
22 rizwank 1.1
23 # NOTE: Testenv should always run on older TWiki versions, as far as
24 # possible - so any dependency on TWiki modules should be carefully
25 # handled and error checked. If a newer feature or subroutine is not
26 # there, it's OK to fail silently and not do the associated tests.
27 # This is more painful to code, but it means that testenv can be downloaded
28 # from CVS and used on older TWiki versions to diagnose problems.
29
30 package TWiki;
31
32 use vars qw( $useLocale $setlibAvail );
33
34
35 my $brokenTWikiCfg;
36
37 BEGIN {
38 # Set default current working directory
39 if( $ENV{"SCRIPT_FILENAME"} && $ENV{"SCRIPT_FILENAME"} =~ /^(.+)\/[^\/]+$/ ) {
40 chdir $1;
41 }
42
43 rizwank 1.1 # Set library paths in @INC, read TWiki.cfg and set locale, at compile time
44 # Try to use setlib.cfg, use default path if missing
45 if ( -r './setlib.cfg' ) {
46 require './setlib.cfg';
47 $setlibAvail = 1;
48 } else {
49 unshift @INC, '../lib';
50 $setlibAvail = 0;
51 }
52
53 # Read the configuration file now in order to set locale;
54 # includes checking for broken syntax etc. Need 'require'
55 # to get the $!/$@ to work.
56 $brokenTWikiCfg = 0;
57 unless( eval 'require "TWiki.cfg" ' ){ # Includes OS detection
58 # Capture the Perl error(s)
59 $brokenTWikiCfg = 1;
60 $brokenTWikiCfgError =
61 ( $! ? "$!\n" : '') . # $! if not readable,
62 ( $@ ? "$@\n" : ''); # $@ if not compileable
63 }
64 rizwank 1.1
65 # Do a dynamic 'use locale' for this script
66 if( $useLocale ) {
67 require locale;
68 import locale ();
69 }
70 }
71
72
73 # use strict; # Recommended for mod_perl, enable for Perl 5.6.1 only
74 # Doesn't work well here, due to 'do "TWiki.cfg"'
75 # use diagnostics; # Debug only
76
77
78 &main();
79
80
81 sub checkBasicModules {
82 # Check whether basic CGI modules exist (some broken installations of
83 # Perl don't have this, even though they are standard modules), and warn user
84 my @basicMods = @_;
85 rizwank 1.1
86 my $modMissing = 0;
87 my $mod;
88 foreach $mod (@basicMods) {
89 eval "use $mod";
90 if ($@) {
91 unless ($modMissing) {
92 print "Content-type: text/html\n\n";
93 print "<html><head><title>Perl Module(s) missing</title></head>\n";
94 print "<body>\n";
95 print "<h1>Perl Module(s) missing</h1>\n";
96 }
97 $modMissing = 1;
98 print "<p><b><font color=\"red\">Warning:</font></b> ";
99 print "Essential module <b>$mod</b> not installed - please check your Perl\n";
100 print "installation, including the setting of <b>\@INC</b>, and re-install Perl if necessary.</p>\n";
101 }
102 }
103 # If any critical modules missing, display @INC and give up
104 if ($modMissing) {
105 print "<p><b>\@INC setting:</b><br /><tt> ";
106 rizwank 1.1 print join "<br />\n", @INC;
107 print "</tt></p>\n";
108 print "</body>\n</html>\n";
109 exit;
110 }
111 }
112
113
114 sub main
115 {
116
117 my $perlverRequired = 5.00503; # Oldest supported version of Perl
118 my $perlverRequiredString = '5.005_03';
119 my $perlverRecommended = '5.6.1';
120 my $ActivePerlRecommendedBuild = 631; # Fixes PERL5SHELL bugs
121
122 # CGI.pm version, on some platforms - actually need CGI 2.93 for mod_perl
123 # 2.0 and CGI 2.90 for Cygwin Perl 5.8.0. See
124 # http://perl.apache.org/products/apache-modules.html#Porting_CPAN_modules_to_mod_perl_2_0_Status
125 my $cgiModVerRecommended = '2.93';
126
127 rizwank 1.1 # Recommended mod_perl version if using mod_perl 2.0 (see Support.RegistryCookerBadFileDescriptor)
128 my $modPerlVersionRecommended = '1.99_12';
129
130 my $rcsverRequired = 5.7;
131
132 my @basicMods = qw( CGI CGI::Carp ); # Required for testenv to work
133
134 my @requiredMods = ( # Required for TWiki
135 @basicMods,
136 'File::Copy',
137 'File::Spec',
138 'FileHandle',
139 );
140
141 # Required on non-Unix platforms (mainly Windows)
142 my @requiredModsNonUnix = (
143 'Digest::SHA1', # For register script
144 'MIME::Base64', # For register script
145 'Net::SMTP', # For registration emails and mailnotify
146 );
147
148 rizwank 1.1 # Optional modules on all platforms
149 my @optionalMods = (
150 'Algorithm::Diff', # For RcsLite (CPAN)
151 'MIME::Base64', # For HTTP Authentication to proxies (CPAN)
152 'POSIX', # For I18N (core module)
153 'Encode', # For I18N conversions (core module in Perl 5.8)
154 'Unicode::MapUTF8', # For I18N conversions (CPAN)
155 'Unicode::Map', # For I18N conversions (CPAN)
156 'Unicode::Map8', # For I18N conversions (CPAN)
157 'Jcode', # For I18N conversions (CPAN)
158 'Digest::MD5', # For MD5 encoded passwords in HtPasswdUser.pm
159 );
160
161
162 open(STDERR,'>&STDOUT'); # redirect errors to browser
163 $| = 1; # no buffering - FIXME: mod_perl issue?
164
165
166 # Check for modules required by this script
167 &checkBasicModules( @basicMods );
168
169 rizwank 1.1 # Load CGI modules (run-time, after checking they are accessible)
170 require CGI;
171 require CGI::Carp;
172 import CGI::Carp qw( fatalsToBrowser );
173
174 my $query = new CGI;
175
176
177 print "Content-type: text/html\n\n";
178 print <<EOM;
179 <html>
180 <head><title>Test TWiki environment</title></head>
181 <body>
182 <h1>Test the environment for TWiki</h1>
183 Please read the <a href="http://TWiki.org/cgi-bin/view/TWiki/TWikiInstallationNotes">TWikiInstallationNotes</a> for more information on TWiki installation.
184 EOM
185
186 # TWiki.cfg was read earlier, in BEGIN block.
187 # Check for broken TWiki.cfg and report any Perl error(s)
188 if ($brokenTWikiCfg) {
189 $brokenTWikiCfgError =~ s!\n!<br />\n!sg; # Format properly
190 rizwank 1.1 print "<h3>TWiki.cfg error</h3>\n";
191 print "<b><font color=\"red\">WARNING:</font></b> ";
192 print "TWiki.cfg is unreadable or has a configuration problem that is causing a Perl error - the following message(s) relate to TWiki.cfg and should help locate the problem.<p />\n";
193 print "$brokenTWikiCfgError\n";
194
195 # EARLY EXIT
196 print "</body>\n</html>";
197 exit;
198 }
199
200 print <<EOM;
201 <h3>Environment variables:</h3>
202 <table>
203 EOM
204 my $key;
205 for $key ( sort keys %ENV ) {
206 print "<tr><th align=\"right\">$key</th><td>$ENV{$key}</td></tr>\n";
207 }
208 print <<EOM;
209 </table>
210 <h3>CGI Setup:</h3>
211 rizwank 1.1 <table>
212 EOM
213
214
215
216 # Make %ENV safer for CGI (should reflect TWiki.pm)
217 my $originalPath = $ENV{'PATH'} || '';
218 if( $safeEnvPath ) {
219 $ENV{'PATH'} = $safeEnvPath;
220 }
221 delete @ENV{ qw( IFS CDPATH ENV BASH_ENV ) };
222
223 # Get Perl version - output looks neater with new variable
224 my $perlvernum = $];
225 my $perlver;
226 if (defined $^V) {
227 $perlver = $^V; # New in Perl 5.6.1, one byte per part
228 $perlver = ord(substr($perlver,0)) . "." . ord(substr($perlver,1))
229 . "." . ord(substr($perlver,2));
230 } else {
231 $perlver = $perlvernum
232 rizwank 1.1 }
233
234
235
236 # Load Config module - used here and elsewhere
237 require Config;
238
239 # Set $detailedOS if not using later versions of TWiki.cfg for BeijingRelease
240 # - this code enables the latest testenv to be used with Dec 2001 and
241 # earlier releases.
242 if ( !defined $detailedOS ) {
243 $detailedOS = $Config::Config{'osname'};
244 # print "$detailedOS<br>";
245 }
246
247 # Detect Perl flavour on Windows, and Cygwin Perl/RCS package versions
248 my $perltype;
249 my $cygwinRcsVerNum;
250 $perlverMsg = $perlver; # Default version message
251 if ($detailedOS eq 'cygwin') {
252 $perltype = 'Cygwin'; # Cygwin Perl only
253 rizwank 1.1 my ($pkg, $pkgName);
254
255 # Get Cygwin perl's package version number
256 $pkgName = 'perl';
257 $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`;
258 if ($?) {
259 $pkg = " [Can't identify package - cygcheck or grep not installed]";
260 $perlverMsg = $perlver . $pkg
261 } else {
262 $pkg = (split ' ', $pkg)[1]; # Package version
263 $perlverMsg = $pkg;
264 }
265
266 # Get Cygwin RCS's package version number
267 $pkgName = 'rcs';
268 $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`;
269 if ($?) {
270 $pkg = " [Can't identify package - cygcheck or grep not installed]";
271 $cygwinRcsVerNum = $pkg;
272 } else {
273 $pkg = (split ' ', $pkg)[1]; # Package version
274 rizwank 1.1 $cygwinRcsVerNum = $pkg;
275 }
276 } elsif ($detailedOS =~ /win/i && $detailedOS !~ /darwin/i ) {
277 # Windows Perl - try ActivePerl-only function: returns number if
278 # successful, otherwise treated as a literal (bareword).
279 my $isActivePerl= eval 'Win32::BuildNumber !~ /Win32/';
280 if( $isActivePerl ) {
281 $perltype = 'ActiveState';
282 $perlverMsg = $perlver . ", build " . Win32::BuildNumber();
283 } else {
284 # Could be SiePerl or some other Win32 port of Perl
285 $perltype = 'SiePerl/Other Win32 Perl';
286 }
287 } else {
288 $perltype = 'generic';
289 }
290
291 # Detect executable name suffix, e.g. .exe on Windows or '' on Unix
292 # Avoid testing for .exe suffixes on Cygwin, since the built-in
293 # grep and ls don't end in '.exe', even though Perl's '_exe' setting
294 # indicates they should.
295 rizwank 1.1 my $exeSuffix='';
296 if ( $Config::Config{'_exe'} and ($OS eq 'WINDOWS' and $perltype ne 'Cygwin') ) {
297 if ( ! $ENV{'INTERIX_ROOT'} ) { #this is set is we are using UnixServicesForWindows (or INTERIX funnily enough) and they don't use .exe either
298 $exeSuffix = $Config::Config{'_exe'};
299 }
300 }
301
302
303 my $thePathInfo = $query->path_info();
304 # my $theRemoteUser = $query->remote_user();
305 my $theTopic = $query->param( 'topic' );
306 my $theUrl = $query->url;
307
308 # Detect whether mod_perl was loaded into Apache
309 my $modPerlLoaded = ( exists $ENV{'SERVER_SOFTWARE'} &&
310 ( $ENV{'SERVER_SOFTWARE'} =~ /mod_perl/ ));
311
312 # Detect whether we are actually running under mod_perl
313 # - test for MOD_PERL alone, which is enough.
314 my $usingModPerl = ( exists $ENV{'MOD_PERL'} );
315
316 rizwank 1.1 # Get the version of mod_perl if it's being used
317 my $modPerlVersion;
318 if ( $usingModPerl ) {
319 $modPerlVersion = eval 'use mod_perl; return $mod_perl::VERSION';
320 }
321
322
323 # OS
324 print "<tr><th align=\"right\">Operating system:</th><td>" . ucfirst(lc($OS));
325 print " ($detailedOS)" if ( $detailedOS ne '' );
326 print "</td></tr>\n";
327
328 # Perl version and type
329 print "<tr><th align=\"right\">Perl version:</th><td>$perlverMsg";
330 print " ($perltype)" if $perltype ne 'generic';
331 print "</td></tr>\n";
332 if ( $perlvernum < $perlverRequired ) {
333 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
334 print "This version of Perl is too old for use with TWiki - upgrade to at least Perl $perlverRequiredString\n";
335 print "and preferably to Perl $perlverRecommended.\n";
336 print "</td></tr>\n";
337 rizwank 1.1 }
338
339 # Perl @INC (lib path)
340 print "<tr><th align=\"right\" valign=\"top\">\@INC library path:</th><td>" .
341 ( join "<br />\n", @INC ) .
342 "</td></tr>\n";
343 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b>\n";
344 print "This is the Perl library path, used to load TWiki modules, ";
345 print "third-party modules used by some plugins, and Perl built-in modules.";
346 print "</td></tr>\n";
347
348
349 # Turn off fatalsToBrowser while checking module loads, to avoid load errors in
350 # browser in some environments.
351 $CGI::Carp::WRAP = $CGI::Carp::WRAP = 0; # Avoid warnings...
352
353 # Add to list of required modules if non-Unix, or MacOS X (detected by
354 # Perl as 'Darwin') - $detailedOS is set in TWiki.cfg.
355 if ( defined $detailedOS and ($detailedOS =~ /darwin/i or $OS ne 'UNIX') ) {
356 push @requiredMods, @requiredModsNonUnix;
357 } else {
358 rizwank 1.1 #these are optional on Unix
359 push @optionalMods, @requiredModsNonUnix;
360 }
361
362 # Check that the TWiki.pm module can be found
363 print "<tr><th align=\"right\">TWiki module in \@INC path:</th><td>";
364 $mod = 'TWiki';
365 eval "use $mod";
366 print "<tr><th></th><td>\n";
367 my $twikiFound = 0;
368 if ($@) {
369 print "<b><font color=\"red\">Warning:</font></b> ";
370 print "'$mod.pm' not found - check path to <code>twiki/lib</code>";
371 print " and edit <code>twiki/bin/setlib.cfg</code> if necessary" if $setlibAvail;
372 print ".\n";
373 print "</td></tr>\n";
374 } else {
375 $twikiFound = 1;
376 my $mod_version = eval '$TWiki::wikiversion';
377 $mod_version ||= 'unknown';
378 print "OK, $mod.pm found (TWiki version: <b>$mod_version</b>)";
379 rizwank 1.1 print "</td></tr>\n";
380 }
381 print "</td></tr>\n";
382
383 # Do locale settings if TWiki.pm was found
384 my $showLocales = 0;
385 if ($twikiFound) {
386 if( eval 'TWiki::setupLocale()' ){ # Not in older TWiki.pm versions
387 # Ignore errors silently
388 $showLocales = 1;
389 }
390 }
391
392
393 # Check that each of the required Perl modules can be loaded, and
394 # print its version number.
395 print "<tr><th align=\"right\">Required Perl modules:</th><td>";
396 foreach $mod (@requiredMods) {
397 eval "use $mod";
398 print "<tr><th></th><td>\n";
399 if ($@) {
400 rizwank 1.1 print "<b><font color=\"red\">Warning:</font></b> ";
401 print "'$mod' not installed - check TWiki documentation to see if this is required.\n";
402 print "</td></tr>\n";
403 } else {
404 my $mod_version;
405 $mod_version = ${"${mod}::VERSION"};
406 print "$mod ($mod_version)";
407
408 # Check for potential CGI.pm module upgrade
409 if( $mod eq 'CGI' and $mod_version < $cgiModVerRecommended ) {
410
411 if ( $perltype eq 'Cygwin' and $perlver eq '5.8.0' ) {
412 # Recommend CGI.pm upgrade if using Cygwin Perl 5.8.0
413 print "<br /><b><font color=\"red\">Warning:</font></b> ";
414 print "CGI.pm version $cgiModVerRecommended or higher is recommended to avoid problems with attachment uploads on Cygwin Perl $perlver.\n";
415
416 } elsif ( $usingModPerl and $modPerlVersion >= 1.99 ) {
417
418 # Recommend CGI.pm upgrade if using mod_perl 2.0, which
419 # is reported as version 1.99 and implies Apache 2.0
420 print "<br /><b><font color=\"red\">Warning:</font></b> ";
421 rizwank 1.1 print "CGI.pm version $cgiModVerRecommended or higher is recommended to avoid problems with mod_perl version $modPerlVersion on Apache 2.0 or higher.\n";
422 }
423 }
424 print "</td></tr>\n";
425 }
426 print "</td></tr>\n";
427 }
428
429 # Check that each of the optional Perl modules can be loaded, and
430 # print its version number.
431 print "<tr><th align=\"right\">Optional Perl modules:</th><td>";
432 foreach $mod (@optionalMods) {
433 eval "use $mod";
434 print "<tr><th></th><td>\n";
435 if ($@) {
436 print "<b><font color=\"green\">Note:</font></b> ";
437 print "Optional module '$mod' not installed - check TWiki documentation to see if your configuration needs this module.\n";
438 print "</td></tr>\n";
439 } else {
440 my $mod_version = $ {"$ {mod}::VERSION"};
441 print "$mod ($mod_version)";
442 rizwank 1.1 print "</td></tr>\n";
443 }
444 print "</td></tr>\n";
445 }
446
447 # All module checks done, OK to enable fatalsToBrowser
448 import CGI::Carp qw( fatalsToBrowser );
449
450
451 # PATH_INFO
452 print "<tr><th align=\"right\">PATH_INFO:<a name=\"PATH_INFO\"></th><td>$thePathInfo</td></tr>\n";
453 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b>\n";
454 print "For a URL such as <b>$theUrl/foo/bar</b>, \n";
455 print "the correct PATH_INFO is <b>/foo/bar</b>, without any prefixed path \n";
456 print "components. <a href=\"$theUrl/foo/bar#PATH_INFO\"><b>Test this now</b></a> \n";
457 print "- particularly if you are using mod_perl, Apache or IIS, or are using a web hosting provider.\n";
458 print "The page resulting from the test link should have a PATH_INFO of <b>/foo/bar</b>.\n";
459 print "</td></tr>\n";
460
461 # mod_perl
462 my $usingModPerlText = $usingModPerl ? "Used" : "Not used";
463 rizwank 1.1 my $modPerlLoadedText = ( $modPerlLoaded ? "loaded" : "not loaded" );
464
465 print "<tr><th align=\"right\">mod_perl:</th><td>$usingModPerlText for this script (mod_perl $modPerlLoadedText into Apache)\n";
466 if ( $modPerlVersion ) {
467 print "- mod_perl version $modPerlVersion\n";
468 }
469 print "</td></tr>\n";
470
471 # Check for a broken version of mod_perl 2.0
472 if ( $usingModPerl and $modPerlVersion >= 1.99
473 and $modPerlVersion eq '1.99_11' ) {
474 # Recommend mod_perl upgrade if using a mod_perl 2.0 version
475 # with PATH_INFO bug (see Support.RegistryCookerBadFileDescriptor)
476 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
477 print "mod_perl version $modPerlVersionRecommended or higher is strongly recommended to avoid 'internal system error' bugs with PATH_INFO when using mod_perl $modPerlVersion and Apache 2.0 or higher.\n";
478 print "</td></tr>\n";
479 }
480
481
482 # Get web server's user and group info
483 my $usr = "";
484 rizwank 1.1 my $grp = "";
485 if( $OS eq 'UNIX' or ($OS eq 'WINDOWS' and $perltype eq 'Cygwin' ) ) {
486 $usr = lc( getpwuid($>) ); # Unix/Cygwin Perl - effective UID
487 foreach( split( " ", $( ) ) {
488 my $onegrp = getgrgid( $_ );
489 $grp .= " " . lc($onegrp);
490 }
491 } else { # ActiveState or other Win32 Perl
492 $usr = lc( getlogin );
493 # Try to use Cygwin's 'id' command - may be on the path, since Cygwin
494 # is probably installed to supply ls, egrep, etc - if it isn't, give up.
495 # Run command without stderr output, to avoid CGI giving error.
496 # Get names of primary and other groups.
497 $grp = lc(qx(sh -c '( id -un ; id -gn) 2>/dev/null' 2>nul ));
498 if ($?) {
499 $grp = "[Can't identify groups - no Cygwin 'id' or 'sh' command on path]";
500 }
501 }
502
503 print "<tr><th align=\"right\">User:</th><td> $usr </td></tr>\n";
504 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
505 rizwank 1.1 print "Your CGI scripts are executing as this user.";
506 print "</td></tr>\n";
507 if( $usr ne "nobody" ) {
508 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
509 print "Since your CGI script is not running as user <tt>nobody</tt>, ";
510 print "you need to change the locks in the *,v RCS files of the TWiki ";
511 print "distribution from <tt>nobody</tt> to <tt>$usr</tt>.\n";
512 print "Otherwise, changes to topics will not be logged by RCS.\n";
513 print "</td></tr>\n";
514 }
515 my $relockCmd = $ENV{'SCRIPT_NAME'};
516 $relockCmd =~ s/\/testenv/\/manage/; # scripts possibly have a suffix
517 $relockCmd .= "?action=relockrcs";
518 print "<tr><th></th><td><b><font color=\"brown\">Fix:</font></b>\n";
519 print "If needed, <a href=\"$relockCmd\">relock</a> ";
520 print "all the rcs files to user <tt>$usr</tt></td></tr>\n";
521
522 print "<tr><th align=\"right\">Group(s):</th><td>";
523 print "$grp";
524 print "</table>\n";
525
526 rizwank 1.1
527
528
529 print "<h3>Test of <tt>TWiki.cfg</tt> Configuration:</h3>\n";
530
531 print "<table>\n";
532
533 print "<tr><th align=\"right\">\$defaultUrlHost:</th><td>$defaultUrlHost</td></tr>\n";
534 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
535 print "This must match the protocol and host part (with optional port number) of ";
536 print "the TWiki URL.";
537 print "</td></tr>\n";
538 my $val = $ENV{"HTTP_HOST"} || '';
539 if( $defaultUrlHost !~ /$val/ ) {
540 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
541 print "This does not match </b>HTTP_HOST</b>";
542 print "</td></tr>\n";
543 }
544
545 # Check Script URL Path against REQUEST_URI
546 print "<tr><th align=\"right\">\$scriptUrlPath:</th><td>$scriptUrlPath</td></tr>\n";
547 rizwank 1.1 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
548 print "This must match the 'cgi-bin' part of the URL used to access the TWiki cgi-bin directory.";
549 print "</td></tr>\n";
550 $val = $ENV{"REQUEST_URI"} || '';
551 if( not $val ) { # REQUEST_URI not set by IIS
552 print "<tr><th></th><td>";
553 print "This web server does not set <b>REQUEST_URI</b>, so it's not
554 possible to check the correctness of this setting.";
555 print "</td></tr>\n";
556 } elsif ( $val !~ /^$scriptUrlPath/ ) {
557 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
558 print "This does not match <b>REQUEST_URI</b>";
559 print "</td></tr>\n";
560 }
561
562 print "<tr><th align=\"right\">\$pubUrlPath:</th><td>$pubUrlPath</td></tr>\n";
563 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
564 print "This must be the URL of the public directory.";
565 print "This is not set correctly if the ";
566 print "$pubUrlPath/wikiHome.gif image below is broken:<br />";
567 print "<img src=\"$pubUrlPath/wikiHome.gif\" />";
568 rizwank 1.1 print "</td></tr>\n";
569
570 print "<tr><th align=\"right\">\$pubDir:</th><td>$pubDir</td></tr>\n";
571 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
572 print "This is the public directory, as seen from the file system. ";
573 print "It must correspond to <b>\$pubUrlPath</b>.";
574 print "</td></tr>\n";
575 if( ! ( -e "$pubDir/wikiHome.gif" ) ) {
576 print "<tr><th></th><td><b><font color=\"red\">Error:</font></b> ";
577 print "Directory does not exist or file <tt>wikiHome.gif</tt> does not exist in this directory.";
578 print "</td></tr>\n";
579 } elsif( ! testFileIsWritable( "$pubDir/testenv.test" ) ) {
580 # directory is not writable
581 print "<tr><th></th><td><b><font color=\"red\">Error:</font></b> ";
582 print "This directory is not writable by <b>$usr</b> user.";
583 print "</td></tr>\n";
584 }
585
586 print "<tr><th align=\"right\">\$templateDir:</th><td>$templateDir</td></tr>\n";
587 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
588 print "This is the TWiki template directory, as seen from the file system. ";
589 rizwank 1.1 print "</td></tr>\n";
590 if( ! ( -e "$templateDir/view.tmpl" ) ) {
591 print "<tr><th></th><td><b><font color=\"red\">Error:</font></b> ";
592 print "Directory does not exist or file <tt>view.tmpl</tt> does not exist in this directory.";
593 print "</td></tr>\n";
594 } elsif( testFileIsWritable( "$templateDir/testenv.test" ) ) {
595 # directory is writable
596 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
597 print "Security issue: This directory should not be writable by the <b>$usr</b> user.";
598 print "</td></tr>\n";
599 }
600
601 print "<tr><th align=\"right\">\$dataDir:</th><td>$dataDir</td></tr>\n";
602 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
603 print "This is the data directory where TWiki stores all topics.";
604 print "</td></tr>\n";
605 if( ! ( -e "$dataDir" ) ) {
606 print "<tr><th></th><td><b><font color=\"red\">Error:</font></b> ";
607 print "Directory does not exist.";
608 print "</td></tr>\n";
609 } elsif( ! testFileIsWritable( "$dataDir/testenv.test" ) ) {
610 rizwank 1.1 # directory is not writable
611 print "<tr><th></th><td><b><font color=\"red\">Error:</font></b> ";
612 print "This directory must be writable by the <b>$usr</b> user.";
613 print "</td></tr>\n";
614 }
615
616 # Check 'sendmail'
617 $val = $mailProgram;
618 $val =~ s/([^\s]*).*/$1/g;
619 # Don't warn on Windows, as Net::SMTP is normally used
620 if( $OS ne 'WINDOWS' && ! ( -e $val ) ) {
621 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
622 print "Mail program <tt>$val</tt> not found. Check the path.";
623 print "</td></tr>\n";
624 }
625
626 print "<tr><th align=\"right\">\$mailProgram:</th><td>$mailProgram</td></tr>\n";
627 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
628 if( $OS ne 'WINDOWS' ) {
629 print "This is the mail program TWiki uses to send mail.";
630 } else {
631 rizwank 1.1 print "This is not typically used on Windows - the Perl Net::SMTP module is used instead.";
632 }
633 print "</td></tr>\n";
634
635
636 # Check RCS directory
637 print "<tr><th align=\"right\">\$rcsDir:</th><td>$rcsDir</td></tr>\n";
638 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
639 print "This is the directory where RCS is located.";
640 print "</td></tr>\n";
641
642 # Check RCS
643 if( ! ( -e "$rcsDir/ci$exeSuffix" ) ) {
644 # RCS not installed
645 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
646 print "RCS program <tt>$rcsDir/ci$exeSuffix</tt> not found. Check \$rcsDir setting in TWiki.cfg. ";
647 print "TWiki will not work (unless you are ";
648 print "using TWiki's built-in RCS implementation, <b>RcsLite</b>).";
649 print "</td></tr>\n";
650
651 } else {
652 rizwank 1.1 # Check RCS version
653 my $rcsVerNum = `$rcsDir/ci$exeSuffix -V`; # May fail due to diff or DLL not on PATH
654 $rcsVerNum = (split(/\s+/, $rcsVerNum))[2] || ""; # Recover from unset variable
655
656 print "<tr><th align=\"right\">RCS Version:</th><td>$rcsVerNum";
657 print " (Cygwin package <tt>rcs-$cygwinRcsVerNum</tt>)" if defined($cygwinRcsVerNum);
658 print "</td></tr>\n";
659 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
660 print "This is the version of RCS which will be used.";
661 print "</td></tr>\n";
662
663 if( $rcsVerNum && $rcsVerNum < $rcsverRequired ) {
664 # RCS too old
665 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
666 print "RCS program is too old, upgrade to version $rcsverRequired or higher.";
667 print "</td></tr>\n";
668 }
669 }
670
671 # Check 'ls'
672 print "<tr><th align=\"right\">\$lsCmd:</th><td>$lsCmd</td></tr>\n";
673 rizwank 1.1 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
674 print "This is the file list program TWiki uses to list topics.";
675 print "</td></tr>\n";
676 $val = $lsCmd . $exeSuffix;
677 $val =~ s/([^\s]*).*/$1/go;
678 if( ! ( -e $val ) ) {
679 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
680 print "List program <tt>$val</tt> not found. Check the path.";
681 print "</td></tr>\n";
682 }
683
684 # Check 'egrep'
685 print "<tr><th align=\"right\">\$egrepCmd:</th><td>$egrepCmd</td></tr>\n";
686 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
687 print "This is a program TWiki uses for search.";
688 print "</td></tr>\n";
689 $val = $egrepCmd . $exeSuffix;
690 $val =~ s/([^\s]*).*/$1/go;
691 if( ! ( -e $val ) ) {
692 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
693 print "Search program <tt>$val</tt> not found. Check the path.";
694 rizwank 1.1 print "</td></tr>\n";
695 }
696
697 # Check 'fgrep'
698 print "<tr><th align=\"right\">\$fgrepCmd:</th><td>$fgrepCmd</td></tr>\n";
699 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
700 print "This is a program TWiki uses for search.";
701 print "</td></tr>\n";
702 $val = $fgrepCmd . $exeSuffix;
703 $val =~ s/([^\s]*).*/$1/go;
704 if( ! ( -e $val ) ) {
705 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
706 print "Search program <tt>$val</tt> not found. Check the path.";
707 print "</td></tr>\n";
708 }
709
710 # Check $safeEnvPath
711 print "<tr><th align=\"right\">\$safeEnvPath:</th><td>$safeEnvPath</td></tr>\n";
712 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
713 print "This is used to initialise the PATH variable, and is used to run the\n";
714 print "'diff' program used by RCS, as well as to run shell programs such as\n";
715 rizwank 1.1 if( $OS eq 'WINDOWS' ) {
716 print "cmd.exe or Cygwin's 'bash'.\n";
717 print "<p>\n";
718 if( $perltype eq 'Cygwin' ) {
719 print "Since you are using Cygwin Perl, 'bash' will be used without any special setup.\n";
720 } elsif( $perltype eq 'ActiveState' ) {
721 print "To use 'bash' with ActiveState Perl, see the PERL5SHELL section below\n";
722 print "- this is recommended\n";
723 print "if Cygwin is installed.\n";
724 }
725 print "</p>\n";
726 } else {
727 print "Bourne shell or 'bash'.";
728 }
729 if( $safeEnvPath eq '' ) {
730 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> \n";
731 print "Security issue: <b>\$safeEnvPath</b> set to empty string. Check TWiki.cfg.\n";
732 print "</td></tr>\n";
733 }
734 print "</td></tr>\n";
735
736 rizwank 1.1
737 # Generate a separate table about specific environment variables
738 print "</table>\n";
739 print "<h3>Path and Shell Environment</h3>\n";
740 print "<table>\n";
741
742 # Check PATH
743
744 print "<tr><th align=\"right\">Original PATH:</th><td>$originalPath</td></tr>\n";
745 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
746 print "This is the PATH value passed in from the web server to this script - it is reset by TWiki scripts to the PATH below, and is provided here for comparison purposes only.\n";
747 print "</td></tr>\n";
748
749 my $currentPath = $ENV{'PATH'} || ''; # As re-set earlier in this routine
750 print "<tr><th align=\"right\">Current PATH:</th><td>$currentPath</td></tr>\n";
751 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
752 print "This is the actual PATH setting that will be used by Perl to run programs.\n";
753 print "It is normally identical to <b>\$safeEnvPath</b>, unless that variable is empty.\n";
754 print "</td></tr>\n";
755
756
757 rizwank 1.1 # Check that diff is found in PATH and is GNU diff - used by various RCS
758 # commands, including ci. Since Windows makes it hard to capture stderr
759 # ('2>&1' works only on Win2000 or higher), and Windows will usually have
760 # GNU diff in any case (installed for TWiki since there's no built-in
761 # diff), we only check for diff on Unix/Linux and Cygwin.
762 if( $OS eq 'UNIX' or ($OS eq 'WINDOWS' and $perltype eq 'Cygwin' ) ) {
763 print "<tr><th align=\"right\">diff:</th>";
764 my $diffOut = `diff 2>&1` || "";
765 my $notFound = ( $? == -1 );
766 if( $notFound ) {
767 print "<td><b><font color=\"red\">Warning:</font></b> ";
768 print "'diff' program was not found on the current PATH.\n";
769 print "</td></tr>";
770 } else {
771 # diff found, check that it's GNU - using '-v' should cause error if not GNU,
772 # since there are no arguments (tested with Solaris diff).
773 $diffOut = `diff -v 2>&1` || "";
774 if( $diffOut !~ /\bGNU\b/ ) {
775 print "<td><b><font color=\"red\">Warning:</font></b> ";
776 print "'diff' program was found on the PATH but is not GNU diff - this may cause problems.\n";
777 print "</td></tr>";
778 rizwank 1.1 } else {
779 print "<td>GNU diff was found on the PATH - this is the recommended diff tool.";
780 print "</td></tr>";
781 }
782 }
783
784 # Final table row applies to all cases
785 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b>\n";
786 print "The 'diff' command is used by RCS to compare files.\n";
787 print "</td></tr>";
788 }
789
790 # PERL5SHELL check for non-Cygwin Perl on Windows only
791 if( $OS eq 'WINDOWS' && $perltype ne 'Cygwin' ) {
792
793 # ActiveState or SiePerl/other
794 # FIXME: Advice in this section should be reviewed and tested by people
795 # using ActivePerl
796 my $perl5shell = $ENV{'PERL5SHELL'} || '';
797 print "</td></tr>\n";
798 print "<tr><th align=\"right\">PERL5SHELL:</th><td>$perl5shell</td></tr>\n";
799 rizwank 1.1 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
800 print "This environment variable is used by ActiveState and other Win32 Perls to run \n";
801 print "commands from TWiki scripts - it determines which shell\n";
802 print "program is used to run commands that use 'pipes'. Examples of shell programs are \n";
803 print "cmd.exe, command.com (aka 'DOS Prompt'), and Cygwin's 'bash'\n";
804 print "(<b>recommended</b> if Cygwin is installed).\n";
805 print "<p>\n";
806 print "To use 'bash' with ActiveState or other Win32 Perls, you should set the \n";
807 print "PERL5SHELL environment variable to something like <tt><b>c:/YOURCYGWINDIR/bin/bash.exe -c</b></tt>.\n";
808 print "This should be set in the System Environment, and ideally set \n";
809 print "directly in the web server (e.g. using the Apache <tt>SetEnv</tt> \n";
810 print "command, followed by an Apache restart). Once this is done, you should re-run <b>testenv</b>\n";
811 print "to check that PERL5SHELL is set properly.\n";
812 if ($perltype eq 'ActiveState' and
813 Win32::BuildNumber() < $ActivePerlRecommendedBuild ) {
814 print "</p>\n";
815 print "<p><b><font color=\"red\">Warning:</font></b> ";
816 print "ActiveState Perl must be upgraded to build <b>$ActivePerlRecommendedBuild</b> if you are going to use PERL5SHELL, which was broken in earlier builds.";
817 }
818 print "</p>\n";
819 print "</td></tr>\n";
820 rizwank 1.1 }
821
822 # User authentication and password handling (only if TWiki::User loaded)
823 if( defined $TWiki::htpasswdFormatFamily ) {
824 print "</table>\n";
825 print "<h3>User Authentication</h3>\n";
826 print "<table>\n";
827
828 $TWiki::htpasswdFormatFamily = $TWiki::htpasswdFormatFamily; # warning fodder
829 $TWiki::htpasswdEncoding = $TWiki::htpasswdEncoding;
830 print "</td></tr>\n";
831 print "<tr><th align=\"right\">htpasswd Format Family:</th><td>$TWiki::htpasswdFormatFamily</td></tr>\n";
832 print "<tr><th align=\"right\">htpasswd Encoding:</th><td>$TWiki::htpasswdEncoding</td></tr>\n";
833 print "<tr><th align=\"right\">htpasswd Filename:</th><td>$TWiki::htpasswdFilename</td></tr>\n" if ( $TWiki::htpasswdFilename );
834 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
835 print " only some combinations of Format, Encoding and Filename are valid, and fewer are tested\n";
836 print "\n";
837 print "</p>\n";
838 print "</td></tr>\n";
839 }
840
841 rizwank 1.1 # Generate a separate table for locale setup
842 if ( $showLocales ) { # Only if TWiki.pm found
843 print "</table>\n";
844 print "<h3>Internationalisation and Locale Setup</h3>\n";
845 print "<table>\n";
846
847 # $useLocale
848 print "<tr><th align=\"right\">\$useLocale:</th><td>$useLocale</td></tr>\n";
849 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
850 print "This TWiki.cfg setting controls whether locales are used by Perl and 'grep'.\n";
851 print "</td></tr>\n";
852
853 if( $OS eq 'WINDOWS' ) {
854 # Warn re known broken locale setup
855 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
856 print "Using Perl on Windows, which may have missing or incorrect locales (in Cygwin or ActiveState Perl, respectively)\n";
857 print "- use of <b>\$useLocale</b> = 0 is recommended unless you know your version of Perl has working locale support.\n";
858 print "</td></tr>\n";
859 }
860
861 # Check for d_setlocale in Config (same as 'perl -V:d_setlocale')
862 rizwank 1.1 eval "use Config";
863 if ( not ( exists $Config{d_setlocale} and $Config{d_setlocale} eq 'define' ) ) {
864 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
865 print "This version of Perl was not compiled with locale support ('d_setlocale' not set in Config.pm)\n";
866 print "- re-compilation of Perl will be required before it can be used to support TWiki internationalisation.\n";
867 print "</td></tr>\n";
868 }
869
870 # $siteLocale
871 print "<tr><th align=\"right\">\$siteLocale:</th><td>$siteLocale</td></tr>\n";
872 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
873 print "This TWiki.cfg parameter sets the site-wide locale - for\n";
874 print "example, <b>de_AT.ISO-8859-1</b> where 'de' is the language code, 'AT' the country code and 'ISO-8859-1' is the character set. Use the <code>locale -a</code> command on your system to determine available locales.\n";
875 print "</td></tr>\n";
876
877 # Try to see if required locale was correctly set earlier
878 my $currentLocale = setlocale(&LC_CTYPE);
879 if ( $currentLocale ne $siteLocale ) {
880 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
881 print "Unable to set locale to '$siteLocale'. The actual locale is '$currentLocale'\n";
882 print "- please test your locale settings. This warning can be ignored\n";
883 rizwank 1.1 print "if you are not planning to use locales (e.g. your site uses English only)\n";
884 print "- or you can set <b>\$siteLocale</b> to <code>C</code>, which should always work.\n";
885 print "</td></tr>\n";
886 }
887
888 # $siteCharset (computed in TWiki::setupLocale from TWiki.cfg settings)
889 if (not defined $siteCharsetOverride ) {
890 $siteCharsetOverride = '';
891 }
892 print "<tr><th align=\"right\">\$siteCharset:</th><td>$siteCharset</td></tr>\n";
893 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
894 print "This value is derived from the site-wide locale setting.\n";
895 print "It may have been overridden by \$siteCharsetOverride (currently '$siteCharsetOverride').\n";
896 print "It is used in TWiki's HTML pages and HTTP headers,\n";
897 print "so it must be acceptable to web browsers even if it is different\n";
898 print "to the locale-derived setting (e.g. 'euc-jp' instead of 'eucjp')\n";
899 print "</td></tr>\n";
900
901 # Warn against UTF-8 for now
902 if ( $siteCharset eq 'utf-8' ) {
903 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
904 rizwank 1.1 print "UTF-8 is not fully supported as the TWiki site character set at present\n";
905 print "- while many features will work, it is recommended to use a non-UTF-8 character set until full support is completed.\n";
906 print "If you are interested in testing TWiki beta releases with improved UTF-8 support and have access to Perl 5.8, see TWiki.org's\n";
907 print "<a href=\"http://twiki.org/cgi-bin/view/Codev/TWikiBetaRelease\">TWikiBetaRelease</a> topic.\n";
908 print "</td></tr>\n";
909
910 # Warn against Perl 5.6 or lower for UTF-8
911 if ( $perlvernum < 5.008 ) {
912 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
913 print "Perl 5.8 is required if you are using TWiki's experimental UTF-8 support\n";
914 print "</td></tr>\n";
915 }
916
917 # Check for 'useperlio' in Config on Perl 5.8 or higher - required
918 # for use of ':utf8' layer.
919 if ( $perlvernum >= 5.008 and
920 not ( exists $Config{useperlio} and $Config{useperlio} eq 'define' ) ) {
921 print "<tr><th></th><td><b><font color=\"red\">Warning:</font></b> ";
922 print "This version of Perl was not compiled to use PerlIO by default ('useperlio' not set in Config.pm, see <i>Perl's Unicode Model</i> in 'perldoc perluniintro')\n";
923 print "- re-compilation of Perl will be required before it can be used to enable TWiki's experimental UTF-8 support.\n";
924 print "</td></tr>\n";
925 rizwank 1.1 }
926 }
927
928 # Locales are off/broken, or using pre-5.6 Perl, so have to
929 # explicitly list the accented characters (but not if using UTF-8)
930 my $perlVerPreferred = 5.006; # 5.6 or higher has [:lower:] etc
931 if ( ( not $useLocale or $perlvernum < $perlVerPreferred
932 or not $localeRegexes )
933 and $siteCharset ne 'utf-8' ) {
934
935 # Can't use locales, so generate upper and lower case character
936 # classes to avoid doing this at run-time in TWiki.
937 my $forUpperNat;
938 my $forLowerNat;
939 if ( $perlvernum < $perlVerPreferred ) {
940
941 # Get strings with the non-ASCII alphabetic characters only, upper and lower case
942 $forUpperNat = join '', grep { lc($_) ne $_ and m/[^A-Z]/ } map { chr($_) } 1..255;
943 $forLowerNat = join '', grep { uc($_) ne $_ and m/[^a-z]/ } map { chr($_) } 1..255;
944 }
945
946 rizwank 1.1 # $upperNational
947 $upperNational = $upperNational; # Warning fodder
948 print "<tr><th align=\"right\">\$upperNational:</th><td>$upperNational</td></tr>\n";
949 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
950 print "This TWiki.cfg parameter is used when <b>\$useLocale</b> is 0, to work around missing or non-working locales.\n";
951 print "It is also used with Perl 5.005 for efficiency reasons - upgrading to Perl 5.6.1 with working locales is recommended, and removes the need for this. \n";
952 print "If required, this parameter should be set to the upper case accented characters you require in your locale.\n";
953 if ( $forUpperNat ) {
954 print "<p>The following upper case accented characters have been found in this locale and should be considered for use in this parameter: <b>$forUpperNat</b></p>\n";
955 }
956 print "</td></tr>\n";
957
958 # $lowerNational
959 $lowerNational = $lowerNational; # Warning fodder
960 print "<tr><th align=\"right\">\$lowerNational:</th><td>$lowerNational</td></tr>\n";
961 print "<tr><th></th><td><b><font color=\"green\">Note:</font></b> ";
962 print "This TWiki.cfg parameter is used whenever <b>\$upperNational</b> is used.\n";
963 print "This parameter should be set to the lower case accented characters you require in your locale.\n";
964 if ( $forLowerNat ) {
965 print "<p>The following lower case accented characters have been found in this locale and should be considered for use in this parameter: <b>$forLowerNat</b></p>\n";
966 }
967 rizwank 1.1 print "</td></tr>\n";
968 }
969 }
970
971 print "</table>\n";
972
973 print <<EOM;
974 </pre>
975 </body>
976 </html>
977 EOM
978 exit;
979
980 }
981
982 # =========================
983 sub testFileIsWritable
984 {
985 my( $name ) = @_;
986 my $txt1 = "test 1 2 3";
987 deleteTestFile( $name );
988 rizwank 1.1 writeTestFile( $name, $txt1 );
989 my $txt2 = readTestFile( $name );
990 deleteTestFile( $name );
991 my $identical = ( $txt2 eq $txt1 );
992 return $identical;
993 }
994
995 # =========================
996 sub readTestFile
997 {
998 my( $name ) = @_;
999 my $data = "";
1000 undef $/; # set to read to EOF
1001 open( IN_FILE, "<$name" ) || return "";
1002 $data = <IN_FILE>;
1003 $/ = "\n";
1004 close( IN_FILE );
1005 return $data;
1006 }
1007
1008 # =========================
1009 rizwank 1.1 sub writeTestFile
1010 {
1011 my( $name, $text ) = @_;
1012 if( open( FILE, ">$name" ) ) {
1013 print FILE $text;
1014 close( FILE);
1015 }
1016 }
1017
1018 # =========================
1019 sub deleteTestFile
1020 {
1021 my( $name ) = @_;
1022 if( -e $name ) {
1023 unlink $name;
1024 }
1025 }
|