Added function table to GDI objects for better encapsulation.
[wine.git] / tools / winecheck
bloba669fe1e38a0c4a2cdad183020dcfd30534c58f6
1 #!/usr/bin/perl -w
3 # This program checks the whole Wine environment configuration.
4 # (or that's at least what it's supposed to do once it's finished)
5 # Copyright (C) 2001 Andreas Mohr
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # FIXME:
22 # - implement cmdline arguments e.g. for confirmation keypress
23 # in case of a problem
25 # TODO:
26 # - implement it in a much more systematic way. This is a quick hack for now
27 # (like every Perl program ;-)
28 # And much more so since I'm NOT a Perl hacker
29 # - test/tweak on non-Linux systems
32 use Getopt::Long;
33 use strict;
35 my $hold = 0;
37 my $count_tests = 0;
38 my $count_ok = 0;
39 my $count_suspect = 0;
40 my $count_bad = 0;
41 my $count_critical = 0;
42 my $count_failed = 0;
44 my $is_notchecked = 0;
45 my $is_ok = 1;
46 my $is_suspect = 2;
47 my $is_bad = 3;
48 my $is_critical = 4;
49 my $is_failed = 5;
51 my $factor_suspect = 0.995;
52 my $factor_bad = 0.95;
53 my $factor_critical = 0.85;
54 my $factor_failed = 0.15;
56 my $correctness = 100.0;
58 my $indent = 0;
60 my ($level, $reason, $advice);
62 my $advice_chmod = "If your user account is supposed to be able to access
63 it properly, use chmod as root to fix it (\"man chmod\")";
64 my $advice_fs = "The Filesystem option indicates the filesystem behaviour Wine is supposed to *emulate*, not the filesystem which is there";
66 my $dev_read = 1;
67 my $dev_write = 2;
68 my $dev_open = 4;
70 select(STDERR); $| = 1; # make unbuffered
71 select(STDOUT); $| = 1; # make unbuffered
73 #--------------------------------- main program --------------------------------
74 &Introduction();
75 &Check_BaseFiles();
76 &Check_ConfigFile();
77 &Check_Devices();
78 &Check_Registry();
79 &Check_WindowsFiles();
80 &Print_Score();
82 #------------------------------- support functions -----------------------------
83 sub Do_PrintHeader {
84 my ($str) = @_;
85 my $len = length($str);
86 my $num = int((80 - $len - 2)/2);
87 my $i;
89 print "\n";
90 for ($i = 0; $i < $num; $i++) {
91 print "-";
93 print " ".$str." ";
94 for ($i = 0; $i < $num; $i++) {
95 print "-";
97 if ($len % 2)
99 print "-";
101 print "\n";
104 sub Do_Check {
105 my ($text) = @_;
106 my $test_no;
107 my $indent_str = "";
109 $count_tests++;
110 $test_no = sprintf("%03d", $count_tests);
111 for (my $i = 0; $i < $indent; $i++)
113 $indent_str = $indent_str." ";
115 print sprintf("%.60s", $test_no.".".$indent_str." Checking ".$text."... ");
118 sub Do_PrintResult {
119 my($level, $str, $advice, $skip_score) = @_;
120 my $err;
121 my $key;
123 if ($level == $is_notchecked)
125 $err = "NOT CHECKED";
126 $str = "";
127 $advice = "";
129 elsif ($level == $is_ok)
131 $err = "OK";
132 $str = "";
133 $advice = "";
134 $count_ok++;
136 elsif ($level == $is_suspect)
138 $err = "SUSPICIOUS";
139 $count_suspect++;
140 if (! $skip_score)
142 $correctness *= $factor_suspect;
145 elsif ($level == $is_bad)
147 $err = "BAD";
148 $count_bad++;
149 if (! $skip_score)
151 $correctness *= $factor_bad;
154 elsif ($level == $is_critical)
156 $err = "CRITICAL";
157 $count_critical++;
158 if (! $skip_score)
160 $correctness *= $factor_critical;
163 elsif ($level == $is_failed)
165 $err = "FAILED";
166 $count_failed++;
167 if (! $skip_score)
169 $correctness *= $factor_failed;
172 print $err;
173 if ($str)
175 print " (".$str.")";
177 print ".";
178 if ($hold)
180 print " Press Enter.";
181 $key = getc(STDIN);
183 else
185 print "\n";
187 if ($advice)
189 print "- ADVICE: ".$advice.".\n";
193 #-------------------------------- main functions ------------------------------
194 sub Introduction {
195 print "This script verifies the configuration of the whole Wine environment.\n";
196 print "Note that this is an ALPHA version, and thus it doesn't catch all problems !\n";
197 print "The results of the checks are printed on the right side:\n";
198 print "OK - test passed without problems.\n";
199 print "SUSPICIOUS - potentially problematic. You might want to look into that.\n";
200 print "BAD - This is a problem, and it leads to configuration score penalty.\n";
201 print "CRITICAL - A critical problem which can easily lead to malfunction.\n";
202 print "FAILED - This problem leads to Wine failure almost certainly.\n";
203 print "\nThe result will be printed as a percentage score indicating config completeness.\n";
204 print "\n";
205 if ($hold)
207 my $key;
208 print "Press Enter to continue or Ctrl-C to exit.";
209 $key = getc(STDIN);
213 sub Check_BaseFiles {
214 my $line;
216 Do_PrintHeader("checking Wine base files");
218 $level = $is_ok;
219 Do_Check("for file \"wine\"");
220 $line = `which wine`;
221 if (!$line)
223 $level = $is_failed;
224 $reason = "file not found";
225 $advice = "Make sure the \"wine\" command is in your PATH (echo \$PATH; export PATH=xxx)";
227 Do_PrintResult($level, $reason, $advice);
229 # check for config mess
230 $level = $is_ok;
231 my @output = ();
232 Do_Check("for correct .so lib config (please wait)");
234 # Build list of library directories.
235 # First parse ld.so.conf to find system-wide lib directories.
236 my @dirlist = ();
237 open (LDCONF, "</etc/ld.so.conf");
238 while (<LDCONF>) {
239 s/\#.*//; # eliminate comments
240 chomp;
241 if (-d $_) { push @dirlist, $_; }
243 close (LDCONF);
244 # Next parse LD_LIBRARY_PATH to find user-specific lib dirs.
245 my ($dir);
246 if ($ENV{'LD_LIBRARY_PATH'}) {
247 my (@ld_dirs) = split (/:/, $ENV{'LD_LIBRARY_PATH'});
248 foreach $dir (@ld_dirs) {
249 if (-d $dir) { push @dirlist, $dir; }
253 # Now check for a libwine.so in each directory
254 foreach $dir (@dirlist) {
255 my ($target) = $dir . "/libwine.so";
256 if (-f $target) { push @output, $target; }
258 #print "DEBUG: found libwine: @output\n";
260 if (@output > 1)
262 $level = $is_suspect;
263 my $dirs = "";
264 foreach $line (@output) {
265 chomp $line;
266 $dirs = $dirs." ".$line;
268 $reason = "libwine.so found ".@output." times:".$dirs;
269 $advice = "check whether this is really ok";
271 Do_PrintResult($level, $reason, $advice);
274 sub Do_Config_Drive {
275 my ($drive, $entries, $values) = @_;
276 my $index = 0;
277 my $arg;
278 my $path = "";
279 my $type = "";
280 my $label = "";
281 my $serial = "";
282 my $device = "";
283 my $fs = "";
284 my $unknown = "";
285 my $level;
286 my $my_advice_fat = "If that doesn't help, change mount options in case of VFAT (\"umask\" option)";
288 print "\n>>> Checking drive ".$drive." settings:\n";
289 $reason = "";
290 while (@$entries[$index])
292 $arg = @$values[$index];
293 SWITCH: for (@$entries[$index]) {
294 /^path$/i && do { $path = $arg; last; };
295 /^type$/i && do { $type = $arg; last; };
296 /^label$/i && do { $label = $arg; last; };
297 /^serial$/i && do { $serial = $arg; last; };
298 /^device$/i && do { $device = $arg; last; };
299 /^filesystem$/i && do { $fs = $arg; last; };
300 $unknown = @$entries[$index];
302 $index++;
305 $indent++;
307 my $serious = ($drive =~ /^C$/i) || ($type =~ /^cdrom$/i);
309 ##### check Path #####
310 Do_Check("Path option");
311 $level = $is_ok;
312 $advice = "The syntax of the Path option has to be something like /my/mount/point";
313 if (! $path)
315 $level = $serious ? $is_failed : $is_bad;
316 $reason = "no Path option given in config file";
318 elsif ($path =~ /\\/)
320 $level = $serious ? $is_failed : $is_bad;
321 $reason = "wrong Path format ".$path;
323 elsif ($path =~ /\$\{(.*)\}$/)
325 # get path assigned to environment variable
326 my $envpath = $ENV{$1};
327 if (! $envpath)
329 $level = $serious ? $is_failed : $is_critical;
330 $reason = "Path \"".$path."\" references environment variable \"".$1."\" which is undefined";
331 $advice = "set environment variable before starting Wine or give a \"real\" directory instead";
333 else
335 $path = $envpath;
336 goto PERMCHECK; # hmpf
339 else
341 PERMCHECK:
342 if (!-e $path)
344 $level = $serious ? $is_failed : $is_suspect;
345 $reason = $path." does not exist !";
346 $advice = "create this directory or point Path to a real directory";
348 elsif (!-r $path)
350 $level = $serious ? $is_failed : $is_bad;
351 $reason = $path." is not readable for you";
352 $advice = $advice_chmod.". ".$my_advice_fat;
354 elsif ((! ($type =~ /^cdrom$/i)) && (!-w $path))
356 $level = ($drive =~ /^C$/i) ? $is_failed : $is_suspect;
357 $reason = $path." is not writable for you";
358 $advice = $advice_chmod.". ".$my_advice_fat;
360 else # check permissions of the drive's directories
362 my(@output) = ();
363 push (@output, `find $path 2>&1 1>/dev/null`);
364 foreach my $line (@output) {
365 if ($line =~ /find:\ (.*):\ Permission denied$/)
367 $level = ($drive =~ /^C$/i) ? $is_critical : $is_suspect;
368 $reason = "directory $1 is not accessible for you";
369 $advice = $advice_chmod.". ".$my_advice_fat;
370 last;
375 Do_PrintResult($level, $reason, $advice);
377 ##### check Type #####
378 if ($type)
380 Do_Check("Type option");
381 $level = $is_ok;
382 SWITCH: for ($type) {
383 /^floppy$/i && do { last; };
384 /^hd$/i && do { last; };
385 /^network$/i && do { last; };
386 /^cdrom$/i && do {
387 if (! $device)
389 $level = $is_critical;
390 $reason = "no Device option found -> CD-ROM labels can''t be read";
391 $advice = "add Device option and make sure the device given is accessible by you";
393 last;
395 /^ramdisk$/i && do { last; };
396 if ($type)
398 $level = $is_bad;
399 $reason = "invalid Type setting ".$type;
400 $advice = "use one of \"floppy\", \"hd\", \"network\" or \"cdrom\"";
403 Do_PrintResult($level, $reason, $advice);
406 ##### FIXME: check Label and Serial here #####
408 ##### check Device #####
409 if ($device)
411 my $mode = ($type =~ /^cdrom$/i) ? $dev_read : $dev_read|$dev_write;
412 &Do_CheckDevice("device", $device, 1, $mode);
415 ##### check Filesystem #####
416 if ($fs)
418 Do_Check("Filesystem option");
419 $level = $is_ok;
420 SWITCH: for ($fs) {
421 /^(dos|fat|msdos|unix)$/i && do {
422 $level = $is_bad;
423 $reason = "You probably don't want to use \"".$fs."\". ".$advice_fs;
424 if ($fs =~ /^unix$/i)
426 $advice = "This should almost never be used";
428 else
430 $advice = "only use ".$fs." if you only have a crappy 8.3 filename (i.e.: non-LFN) DOS FAT kernel filesystem driver";
432 last;
434 /^vfat$/i && do { last; };
435 /^win95$/i && do { last; };
436 if ($fs)
438 $level = $is_bad;
439 $reason = "invalid Filesystem setting ".$type;
440 $advice = "use one of \"win95\", \"msdos\" or \"unix\"";
443 Do_PrintResult($level, $reason, $advice);
445 $indent--;
446 if ($reason) {
447 print "--> PROBLEM.\n";
449 else
451 print "--> OK.\n";
455 sub Do_Config_Main {
456 my ($file) = shift;
457 my ($config, $line);
458 my $section = "";
459 my (@entries, @values);
460 LINE: while (<$file>)
462 $line = $_;
463 next LINE if ($line =~ /[\ ]*[;#]/); # skip comments
464 chomp $line;
465 #print "line: ".$line."\n";
466 if ($line =~ /\[(.*)\]/) # end of section/next section ?
468 my $nextsection = $1;
469 my $found = 1;
470 SWITCH: for ($section) {
471 /Drive\ (.)/i && do { &Do_Config_Drive($1, \@entries, \@values); last; };
472 if ($section)
474 $found = 0;
477 $section = $found ? $nextsection : "";
478 @entries = (); @values = ();
479 next LINE;
481 if ($line =~ /^[\ \t]*\"(.*)\"[\ \t]*\=[\ \t]*\"(.*)\"/)
483 push(@entries, $1);
484 push(@values, $2);
489 sub Check_ConfigFile {
490 my $config = "$ENV{'HOME'}/.wine/config";
491 my $indrive = 0;
493 Do_PrintHeader("checking config file");
495 Do_Check("config file access");
496 open(CFGFILE, $config);
497 if (! <CFGFILE>)
499 if (!-e $config) {
500 $reason = $config." does not exist";
501 $advice = "it is ok in case you have ~/.winerc. If you don''t, then you''re in trouble !";
503 elsif (!-r $config) {
504 $reason = $config." not readable";
505 $advice = $advice_chmod;
507 Do_PrintResult($is_failed, $reason, $advice);
508 return;
510 if (!-w $config)
512 Do_PrintResult($is_failed, $config." not writable", "wineserver needs to be able to write to config file. ".$advice_chmod);
514 else
516 Do_PrintResult($is_ok);
518 Do_Config_Main(\*CFGFILE);
519 close(CFGFILE);
522 sub Do_CheckDevice {
523 my($descr, $dev, $output, $mode) = @_;
524 my $level = $is_ok;
525 my $errstr = "";
527 if (! $mode)
529 $mode = $dev_read|$dev_write|$dev_open;
531 ($output != -1) && Do_Check($descr." ".$dev);
533 my $err_level = ($output == 1) ? $is_critical : $is_bad;
535 if (!-e $dev)
537 $level = $err_level;
538 $reason = $dev." does not exist";
539 $advice = "use MAKEDEV script to create it";
540 goto FAILED;
542 if (($mode & $dev_read) && (!-r $dev))
544 $level = $err_level;
545 $reason = $dev." is not readable for you";
546 $advice = $advice_chmod;
547 goto FAILED;
549 if (($mode & $dev_write) && (!-w $dev))
551 $level = $err_level;
552 $reason = $dev." is not writable for you";
553 $advice = $advice_chmod;
554 goto FAILED;
556 if (($mode & $dev_open) && (!open(DEVICE, ">$dev")))
558 $level = $err_level;
559 $reason = "no kernel driver for ".$dev."?";
560 $advice = "module loading problems ? Read /usr/src/linux/Documentation/modules.txt";
561 goto FAILED;
564 FAILED:
565 close(DEVICE);
566 ($output != -1) && Do_PrintResult($level, $reason, $advice);
569 sub Check_Devices {
570 # FIXME: check joystick and scsi devices !
571 my $dev_sound = "/dev/dsp";
572 my $dev_mixer = "/dev/mixer";
573 my $dev_sequencer = "/dev/sequencer";
574 my $dev_mem = "/dev/mem";
576 Do_PrintHeader("checking system devices used by Wine");
577 &Do_CheckDevice("sound device", $dev_sound, 1);
578 &Do_CheckDevice("audio mixer device", $dev_mixer, 1);
579 &Do_CheckDevice("MIDI sequencer device", $dev_sequencer, 0);
582 sub Check_Registry {
583 my(@entries) = ();
584 my $regfile = $ENV{'HOME'}."/.wine/system.reg";
586 Do_PrintHeader("checking registry configuration");
588 Do_Check("availability of winedefault.reg entries");
589 push (@entries, `grep "SHAREDMEMLOCATION" $regfile`);
590 if (@entries)
592 Do_PrintResult($is_ok);
594 else
596 Do_PrintResult($is_critical, "entry \"SHAREDMEMLOCATION\" not found in system.reg registry file", "file winedefault.reg doesn't seem to have been applied using regapi");
598 @entries = ();
600 Do_Check("availability of windows registry entries");
601 # FIXME: use a different key for check if Wine adds this one to its
602 # default registry.
603 push (@entries, `grep "Default Taskbar" $regfile`);
604 if (@entries)
606 Do_PrintResult($is_ok);
608 else
610 Do_PrintResult($is_critical, "entry \"Default Taskbar\" not found", "Windows registry does not seem to be added to Wine, as this typical Windows registry entry does not exist in Wine's registry. This can affect many newer programs. A complete original Windows registry entry set will *not* be available with a no-windows install, of course, so you'll have to live with that.");
612 @entries = ();
615 sub Check_WindowsFiles {
618 sub Print_Score {
619 # my ($score_total, $score_reached, $score_percent);
621 # $score_total = $count_tests * 20;
622 # $score_reached = $count_ok * 20 +
623 # $count_bad * 15 +
624 # $count_critical * 5 +
625 # $count_failed * 0;
626 # $score_percent = $score_reached * 100 / $score_total;
628 print "\n";
629 print $count_tests." tests. ".$count_suspect." suspicious, ".$count_bad." bad, ".$count_critical." critical, ".$count_failed." failed.\n";
630 print sprintf "Wine configuration correctness score: %2.2f%%\n", $correctness;